crypton 2.0.1 → 2.2.5
raw patch · 555 files changed
This diff is very large; some files are shown as “too large to diff”. Download the raw patch for the complete diff.
Files
- CHANGELOG.md +1024/−1396
- Crypto/Cipher/AES/GCM.hs +256/−0
- Crypto/Cipher/AES/Primitive.hs +379/−11
- Crypto/Cipher/ChaCha.hs +16/−3
- Crypto/Cipher/ChaCha/Poly1305.hs +335/−0
- Crypto/Cipher/ChaChaPoly1305.hs +30/−30
- Crypto/Cipher/RC4.hs +8/−1
- Crypto/Cipher/Salsa.hs +17/−4
- Crypto/Cipher/Twofish/Primitive.hs +5/−6
- Crypto/ConstructHash/MiyaguchiPreneel.hs +2/−3
- Crypto/ECC.hs +1/−12
- Crypto/Error/Types.hs +4/−0
- Crypto/Hash.hs +21/−14
- Crypto/Hash/Algorithms.hs +2/−0
- Crypto/Hash/Skein256.hs +39/−0
- Crypto/Hash/Skein512.hs +39/−0
- Crypto/Hash/Types.hs +20/−0
- Crypto/Internal/ByteArray.hs +47/−0
- Crypto/Internal/Poly1305.hs +37/−0
- Crypto/KEM.hs +121/−0
- Crypto/MAC/Poly1305.hs +13/−17
- Crypto/Number/Basic.hs +6/−1
- Crypto/Number/F2m.hs +3/−4
- Crypto/Number/ModArithmetic.hs +72/−10
- Crypto/Number/ModArithmetic/Pub.hs +158/−0
- Crypto/Number/Serialize/Internal.hs +6/−1
- Crypto/OTP.hs +4/−5
- Crypto/PubKey/Curve25519.hs +15/−10
- Crypto/PubKey/DSA.hs +41/−8
- Crypto/PubKey/ECC/P256.hs +0/−2
- Crypto/PubKey/ECDSA.hs +82/−5
- Crypto/PubKey/ElGamal.hs +48/−10
- Crypto/PubKey/Internal.hs +2/−3
- Crypto/PubKey/MLDSA.hs +656/−0
- Crypto/PubKey/MLKEM.hs +448/−0
- Crypto/PubKey/MaskGenFunction.hs +35/−15
- Crypto/PubKey/RSA/Blinded.hs +29/−0
- Crypto/PubKey/RSA/Blinded/Internal.hs +136/−0
- Crypto/PubKey/RSA/OAEP.hs +40/−12
- Crypto/PubKey/RSA/PKCS15.hs +229/−23
- Crypto/PubKey/RSA/PSS.hs +88/−18
- Crypto/PubKey/RSA/Prim.hs +77/−7
- Crypto/PubKey/RSA/Types.hs +26/−2
- Crypto/PubKey/Rabin/Basic.hs +32/−0
- Crypto/PubKey/Rabin/Modified.hs +34/−4
- Crypto/PubKey/Rabin/OAEP.hs +2/−3
- Crypto/PubKey/Rabin/RW.hs +34/−4
- Crypto/Random.hs +139/−12
- Crypto/Random/Entropy.hs +25/−4
- Crypto/Random/Entropy/Backend.hs +18/−6
- Crypto/Random/Entropy/RDRand.hs +0/−39
- Crypto/Random/Entropy/Source.hs +24/−0
- Crypto/Random/Entropy/SysRandom.hs +50/−0
- Crypto/Random/Entropy/Unix.hs +1/−1
- Crypto/Random/Entropy/Unsafe.hs +8/−6
- Crypto/Random/Entropy/Windows.hs +5/−2
- Crypto/Random/SysDRG.hs +82/−0
- Crypto/Random/Types.hs +19/−1
- Crypto/System/CPU.hs +204/−43
- Crypto/Tutorial.hs +262/−47
- LICENSE +1/−0
- README.md +254/−96
- benchs/Bench.hs +3/−1
- cbits/LICENSE.go +38/−0
- cbits/aes/LICENSE.fusion +29/−0
- cbits/aes/armv8.c +224/−170
- cbits/aes/armv8_impl.c +303/−31
- cbits/aes/block128.h +15/−1
- cbits/aes/gcm_fused_x86.c +1013/−0
- cbits/aes/gcm_fused_x86.h +55/−0
- cbits/aes/gcm_vaes512_x86.c +364/−0
- cbits/aes/gcm_vaes512_x86.h +37/−0
- cbits/aes/gcm_vaes_x86.c +325/−0
- cbits/aes/gcm_vaes_x86.h +35/−0
- cbits/aes/gcm_x86_asm.c +17/−7
- cbits/aes/generic.c +141/−370
- cbits/aes/generic.h +32/−0
- cbits/aes/gf.c +24/−98
- cbits/aes/ppc8.c +287/−0
- cbits/aes/ppc8.h +29/−0
- cbits/aes/x86ni.c +22/−7
- cbits/aes/x86ni_impl.c +60/−1
- cbits/asm/README.md +3/−1
- cbits/asm/aesp8-ppc-linux64le.S +3658/−0
- cbits/asm/aesp8-ppc.pl +3801/−0
- cbits/asm/generate.sh +23/−0
- cbits/asm/ghashp8-ppc-linux64le.S +575/−0
- cbits/asm/ghashp8-ppc.pl +664/−0
- cbits/asm/ppc-xlate.pl +352/−0
- cbits/bearssl/LICENSE +21/−0
- cbits/bearssl/README.md +57/−0
- cbits/bearssl/VERSION +1/−0
- cbits/bearssl/aes_ct64.c +398/−0
- cbits/bearssl/aes_ct64_dec.c +159/−0
- cbits/bearssl/aes_ct64_enc.c +115/−0
- cbits/bearssl/dec32le.c +38/−0
- cbits/bearssl/ghash_ctmul64.c +154/−0
- cbits/bearssl/import.sh +34/−0
- cbits/bearssl/inner.h +92/−0
- cbits/crypton_aes.c +542/−40
- cbits/crypton_aes.h +70/−0
- cbits/crypton_align.h +75/−61
- cbits/crypton_armv8_target.h +52/−0
- cbits/crypton_bignum.h +284/−21
- cbits/crypton_bitfn.h +0/−17
- cbits/crypton_bzero.h +27/−0
- cbits/crypton_chacha.c +14/−13
- cbits/crypton_chacha.h +2/−2
- cbits/crypton_chachapoly.c +156/−0
- cbits/crypton_chachapoly.h +62/−0
- cbits/crypton_cpu.c +418/−3
- cbits/crypton_cpu.h +77/−0
- cbits/crypton_ecc.c +25/−4
- cbits/crypton_ecc_s2n.c +204/−0
- cbits/crypton_ecc_s2n.h +27/−0
- cbits/crypton_ecc_s2n_curves.h +76/−0
- cbits/crypton_f2m.c +6/−2
- cbits/crypton_md4.c +11/−19
- cbits/crypton_md5.c +18/−19
- cbits/crypton_modinv.c +74/−0
- cbits/crypton_modinv.h +22/−0
- cbits/crypton_mont.h +13445/−0
- cbits/crypton_mont.py +173/−0
- cbits/crypton_pbkdf2.c +21/−4
- cbits/crypton_powm.c +558/−27
- cbits/crypton_powm.h +49/−0
- cbits/crypton_powm_ifma.c +187/−0
- cbits/crypton_powm_ifma.h +513/−0
- cbits/crypton_powm_ifma.py +178/−0
- cbits/crypton_rdrand.c +0/−126
- cbits/crypton_ripemd.c +11/−19
- cbits/crypton_salsa.c +5/−5
- cbits/crypton_salsa.h +3/−3
- cbits/crypton_scrypt.c +2/−2
- cbits/crypton_sha1.c +23/−18
- cbits/crypton_sha256.c +38/−24
- cbits/crypton_sha256.h +12/−0
- cbits/crypton_sha3.c +11/−18
- cbits/crypton_sha512.c +20/−18
- cbits/crypton_sha512.h +12/−0
- cbits/crypton_skein256.c +29/−27
- cbits/crypton_skein256.h +3/−3
- cbits/crypton_skein512.c +34/−35
- cbits/crypton_skein512.h +3/−3
- cbits/crypton_sysdrg.c +388/−0
- cbits/crypton_sysrandom.c +119/−0
- cbits/crypton_tiger.c +9/−16
- cbits/crypton_xsalsa.c +6/−6
- cbits/curve25519/x25519.c +88/−0
- cbits/curve25519/x25519.h +16/−0
- cbits/decaf/ed448goldilocks/decaf.c +4/−1
- cbits/decaf/include/word.h +1/−1
- cbits/ed25519/ed25519.c +27/−6
- cbits/ed25519/ed25519_s2n.c +65/−0
- cbits/ed25519/ed25519_s2n.h +14/−0
- cbits/include32/p256/p256.h +2/−16
- cbits/include32/p256/p256_gf.h +95/−85
- cbits/include64/p256/p256.h +2/−16
- cbits/include64/p256/p256_gf.h +94/−85
- cbits/include64/p256/p256_s2n.h +25/−0
- cbits/mldsa/COMMIT +2/−0
- cbits/mldsa/LICENSE +305/−0
- cbits/mldsa/README.md +60/−0
- cbits/mldsa/crypton_mldsa.c +31/−0
- cbits/mldsa/crypton_mldsa.h +79/−0
- cbits/mldsa/crypton_mldsa_asm.S +14/−0
- cbits/mldsa/import.sh +40/−0
- cbits/mldsa/mldsa_native.c +803/−0
- cbits/mldsa/mldsa_native.h +956/−0
- cbits/mldsa/mldsa_native_asm.S +830/−0
- cbits/mldsa/mldsa_native_config.h +855/−0
- cbits/mldsa/src/cbmc.h +233/−0
- cbits/mldsa/src/common.h +301/−0
- cbits/mldsa/src/context.h +152/−0
- cbits/mldsa/src/ct.c +21/−0
- cbits/mldsa/src/ct.h +373/−0
- cbits/mldsa/src/debug.c +75/−0
- cbits/mldsa/src/debug.h +125/−0
- cbits/mldsa/src/fips202/fips202.c +270/−0
- cbits/mldsa/src/fips202/fips202.h +224/−0
- cbits/mldsa/src/fips202/fips202x4.c +187/−0
- cbits/mldsa/src/fips202/fips202x4.h +125/−0
- cbits/mldsa/src/fips202/keccakf1600.c +510/−0
- cbits/mldsa/src/fips202/keccakf1600.h +110/−0
- cbits/mldsa/src/fips202/native/aarch64/auto.h +85/−0
- cbits/mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h +69/−0
- cbits/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_aarch64_asm.S +378/−0
- cbits/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_aarch64_asm.S +207/−0
- cbits/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_aarch64_asm.S +262/−0
- cbits/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.S +1080/−0
- cbits/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.S +990/−0
- cbits/mldsa/src/fips202/native/aarch64/src/keccakf1600_round_constants.c +47/−0
- cbits/mldsa/src/fips202/native/aarch64/x1_scalar.h +27/−0
- cbits/mldsa/src/fips202/native/aarch64/x1_v84a.h +36/−0
- cbits/mldsa/src/fips202/native/aarch64/x2_v84a.h +40/−0
- cbits/mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h +32/−0
- cbits/mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h +37/−0
- cbits/mldsa/src/fips202/native/api.h +129/−0
- cbits/mldsa/src/fips202/native/auto.h +35/−0
- cbits/mldsa/src/fips202/native/x86_64/keccak_f1600_x4_avx2.h +34/−0
- cbits/mldsa/src/fips202/native/x86_64/src/fips202_native_x86_64.h +45/−0
- cbits/mldsa/src/fips202/native/x86_64/src/keccak_f1600_x4_avx2_asm.S +488/−0
- cbits/mldsa/src/fips202/native/x86_64/src/keccakf1600_constants.c +52/−0
- cbits/mldsa/src/native/aarch64/meta.h +314/−0
- cbits/mldsa/src/native/aarch64/src/aarch64_zetas.c +248/−0
- cbits/mldsa/src/native/aarch64/src/arith_native_aarch64.h +367/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_intt_aarch64_asm.S +786/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_ntt_aarch64_asm.S +686/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_pointwise_montgomery_aarch64_asm.S +106/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_poly_caddq_aarch64_asm.S +69/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_poly_chknorm_aarch64_asm.S +76/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_poly_decompose_32_aarch64_asm.S +108/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_poly_decompose_88_aarch64_asm.S +108/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_poly_use_hint_32_aarch64_asm.S +125/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_poly_use_hint_88_aarch64_asm.S +133/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm.S +157/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm.S +173/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm.S +205/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_polyz_unpack_17_aarch64_asm.S +103/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_polyz_unpack_19_aarch64_asm.S +100/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_rej_uniform_aarch64_asm.S +222/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_rej_uniform_eta2_aarch64_asm.S +170/−0
- cbits/mldsa/src/native/aarch64/src/mldsa_rej_uniform_eta4_aarch64_asm.S +163/−0
- cbits/mldsa/src/native/aarch64/src/polyz_unpack_table.c +52/−0
- cbits/mldsa/src/native/aarch64/src/rej_uniform_eta_table.c +547/−0
- cbits/mldsa/src/native/aarch64/src/rej_uniform_table.c +63/−0
- cbits/mldsa/src/native/api.h +617/−0
- cbits/mldsa/src/native/meta.h +24/−0
- cbits/mldsa/src/native/x86_64/meta.h +323/−0
- cbits/mldsa/src/native/x86_64/src/arith_native_x86_64.h +330/−0
- cbits/mldsa/src/native/x86_64/src/consts.c +157/−0
- cbits/mldsa/src/native/x86_64/src/consts.h +27/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_intt_avx2_asm.S +2333/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_ntt_avx2_asm.S +2405/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_nttunpack_avx2_asm.S +254/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_pointwise_acc_l4_avx2_asm.S +173/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_pointwise_acc_l5_avx2_asm.S +189/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_pointwise_acc_l7_avx2_asm.S +221/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_pointwise_avx2_asm.S +158/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_poly_caddq_avx2_asm.S +199/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_poly_chknorm_avx2_asm.S +176/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_poly_decompose_32_avx2_asm.S +490/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_poly_decompose_88_avx2_asm.S +489/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_poly_use_hint_32_avx2_asm.S +123/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_poly_use_hint_88_avx2_asm.S +125/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_polyz_unpack_17_avx2_asm.S +355/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_polyz_unpack_19_avx2_asm.S +355/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_rej_uniform_avx2_asm.S +132/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_rej_uniform_eta2_avx2_asm.S +205/−0
- cbits/mldsa/src/native/x86_64/src/mldsa_rej_uniform_eta4_avx2_asm.S +176/−0
- cbits/mldsa/src/native/x86_64/src/rej_uniform_table.c +161/−0
- cbits/mldsa/src/packing.c +213/−0
- cbits/mldsa/src/packing.h +277/−0
- cbits/mldsa/src/params.h +153/−0
- cbits/mldsa/src/poly.c +1066/−0
- cbits/mldsa/src/poly.h +464/−0
- cbits/mldsa/src/poly_kl.c +910/−0
- cbits/mldsa/src/poly_kl.h +367/−0
- cbits/mldsa/src/polyvec.c +509/−0
- cbits/mldsa/src/polyvec.h +435/−0
- cbits/mldsa/src/polyvec_lazy.c +311/−0
- cbits/mldsa/src/polyvec_lazy.h +652/−0
- cbits/mldsa/src/randombytes.h +26/−0
- cbits/mldsa/src/reduce.h +144/−0
- cbits/mldsa/src/rounding.h +265/−0
- cbits/mldsa/src/sign.c +1720/−0
- cbits/mldsa/src/sign.h +850/−0
- cbits/mldsa/src/symmetric.h +68/−0
- cbits/mldsa/src/sys.h +327/−0
- cbits/mldsa/src/zetas.inc +55/−0
- cbits/mlkem/COMMIT +2/−0
- cbits/mlkem/LICENSE +312/−0
- cbits/mlkem/README.md +59/−0
- cbits/mlkem/crypton_mlkem.c +31/−0
- cbits/mlkem/crypton_mlkem.h +79/−0
- cbits/mlkem/crypton_mlkem_asm.S +14/−0
- cbits/mlkem/import.sh +42/−0
- cbits/mlkem/mlkem_native.c +692/−0
- cbits/mlkem/mlkem_native.h +464/−0
- cbits/mlkem/mlkem_native_asm.S +716/−0
- cbits/mlkem/mlkem_native_config.h +683/−0
- cbits/mlkem/src/cbmc.h +222/−0
- cbits/mlkem/src/common.h +296/−0
- cbits/mlkem/src/compress.c +763/−0
- cbits/mlkem/src/compress.h +613/−0
- cbits/mlkem/src/context.h +51/−0
- cbits/mlkem/src/debug.c +64/−0
- cbits/mlkem/src/debug.h +121/−0
- cbits/mlkem/src/fips202/fips202.c +249/−0
- cbits/mlkem/src/fips202/fips202.h +144/−0
- cbits/mlkem/src/fips202/fips202x4.c +207/−0
- cbits/mlkem/src/fips202/fips202x4.h +81/−0
- cbits/mlkem/src/fips202/keccakf1600.c +499/−0
- cbits/mlkem/src/fips202/keccakf1600.h +98/−0
- cbits/mlkem/src/fips202/native/aarch64/auto.h +78/−0
- cbits/mlkem/src/fips202/native/aarch64/src/fips202_native_aarch64.h +80/−0
- cbits/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_aarch64_asm.S +377/−0
- cbits/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_aarch64_asm.S +206/−0
- cbits/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_aarch64_asm.S +261/−0
- cbits/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.S +1079/−0
- cbits/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.S +989/−0
- cbits/mlkem/src/fips202/native/aarch64/src/keccakf1600_round_constants.c +47/−0
- cbits/mlkem/src/fips202/native/aarch64/x1_scalar.h +26/−0
- cbits/mlkem/src/fips202/native/aarch64/x1_v84a.h +35/−0
- cbits/mlkem/src/fips202/native/aarch64/x2_v84a.h +38/−0
- cbits/mlkem/src/fips202/native/aarch64/x4_v8a_scalar.h +31/−0
- cbits/mlkem/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h +36/−0
- cbits/mlkem/src/fips202/native/api.h +117/−0
- cbits/mlkem/src/fips202/native/auto.h +29/−0
- cbits/mlkem/src/fips202/native/x86_64/keccak_f1600_x4_avx2.h +33/−0
- cbits/mlkem/src/fips202/native/x86_64/src/fips202_native_x86_64.h +44/−0
- cbits/mlkem/src/fips202/native/x86_64/src/keccak_f1600_x4_avx2_asm.S +487/−0
- cbits/mlkem/src/fips202/native/x86_64/src/keccakf1600_constants.c +52/−0
- cbits/mlkem/src/indcpa.c +675/−0
- cbits/mlkem/src/indcpa.h +172/−0
- cbits/mlkem/src/kem.c +474/−0
- cbits/mlkem/src/kem.h +353/−0
- cbits/mlkem/src/native/aarch64/README.md +16/−0
- cbits/mlkem/src/native/aarch64/meta.h +166/−0
- cbits/mlkem/src/native/aarch64/src/aarch64_zetas.c +184/−0
- cbits/mlkem/src/native/aarch64/src/arith_native_aarch64.h +184/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_intt_aarch64_asm.S +635/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_ntt_aarch64_asm.S +565/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_poly_mulcache_compute_aarch64_asm.S +130/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_poly_reduce_aarch64_asm.S +153/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_poly_tobytes_aarch64_asm.S +124/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_poly_tomont_aarch64_asm.S +102/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm.S +264/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm.S +317/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm.S +371/−0
- cbits/mlkem/src/native/aarch64/src/mlkem_rej_uniform_aarch64_asm.S +226/−0
- cbits/mlkem/src/native/aarch64/src/rej_uniform_table.c +543/−0
- cbits/mlkem/src/native/api.h +651/−0
- cbits/mlkem/src/native/meta.h +30/−0
- cbits/mlkem/src/native/x86_64/README.md +4/−0
- cbits/mlkem/src/native/x86_64/meta.h +324/−0
- cbits/mlkem/src/native/x86_64/src/arith_native_x86_64.h +327/−0
- cbits/mlkem/src/native/x86_64/src/compress_consts.c +115/−0
- cbits/mlkem/src/native/x86_64/src/compress_consts.h +53/−0
- cbits/mlkem/src/native/x86_64/src/consts.c +102/−0
- cbits/mlkem/src/native/x86_64/src/consts.h +25/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_intt_avx2_asm.S +743/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_ntt_avx2_asm.S +661/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_nttfrombytes_avx2_asm.S +217/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_ntttobytes_avx2_asm.S +205/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_nttunpack_avx2_asm.S +190/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_poly_compress_d10_avx2_asm.S +413/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_poly_compress_d11_avx2_asm.S +479/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_poly_compress_d4_avx2_asm.S +194/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_poly_compress_d5_avx2_asm.S +251/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_poly_decompress_d10_avx2_asm.S +257/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_poly_decompress_d11_avx2_asm.S +307/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_poly_decompress_d4_avx2_asm.S +209/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_poly_decompress_d5_avx2_asm.S +222/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_poly_mulcache_compute_avx2_asm.S +118/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm.S +536/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm.S +784/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm.S +1032/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_reduce_avx2_asm.S +234/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_rej_uniform_avx2_asm.S +136/−0
- cbits/mlkem/src/native/x86_64/src/mlkem_tomont_avx2_asm.S +172/−0
- cbits/mlkem/src/native/x86_64/src/rej_uniform_table.c +545/−0
- cbits/mlkem/src/params.h +76/−0
- cbits/mlkem/src/poly.c +581/−0
- cbits/mlkem/src/poly.h +296/−0
- cbits/mlkem/src/poly_k.c +522/−0
- cbits/mlkem/src/poly_k.h +622/−0
- cbits/mlkem/src/randombytes.h +52/−0
- cbits/mlkem/src/sampling.c +371/−0
- cbits/mlkem/src/sampling.h +111/−0
- cbits/mlkem/src/symmetric.h +70/−0
- cbits/mlkem/src/sys.h +320/−0
- cbits/mlkem/src/verify.c +20/−0
- cbits/mlkem/src/verify.h +447/−0
- cbits/mlkem/src/zetas.inc +30/−0
- cbits/p256/gen_base_table.py +126/−0
- cbits/p256/p256.c +47/−3
- cbits/p256/p256_base_table.c +841/−0
- cbits/p256/p256_ec.c +714/−151
- cbits/p256/p256_s2n.c +61/−0
- cbits/p256/p256_verify.c +300/−0
- cbits/p256/p256_verify.h +19/−0
- cbits/p256/p256_wnaf_table.c +42/−0
- cbits/s2n/COMMIT +1/−0
- cbits/s2n/LICENSE +222/−0
- cbits/s2n/README.md +184/−0
- cbits/s2n/arm/bignum_deamont_p384.S +151/−0
- cbits/s2n/arm/bignum_demont_p256.S +99/−0
- cbits/s2n/arm/bignum_inv_p521.S +1701/−0
- cbits/s2n/arm/bignum_modinv.S +613/−0
- cbits/s2n/arm/bignum_montifier.S +462/−0
- cbits/s2n/arm/bignum_montinv_p384.S +1493/−0
- cbits/s2n/arm/bignum_montmul_p384.S +891/−0
- cbits/s2n/arm/bignum_montmul_p384_alt.S +345/−0
- cbits/s2n/arm/bignum_montsqr_p384.S +671/−0
- cbits/s2n/arm/bignum_montsqr_p384_alt.S +273/−0
- cbits/s2n/arm/bignum_mul_p521.S +1407/−0
- cbits/s2n/arm/bignum_mul_p521_alt.S +538/−0
- cbits/s2n/arm/bignum_neg_p256.S +72/−0
- cbits/s2n/arm/bignum_sqr_p521.S +1125/−0
- cbits/s2n/arm/bignum_sqr_p521_alt.S too large to diff
- cbits/s2n/arm/bignum_tomont_p256.S too large to diff
- cbits/s2n/arm/bignum_tomont_p384.S too large to diff
- cbits/s2n/arm/curve25519_x25519.S too large to diff
- cbits/s2n/arm/curve25519_x25519_alt.S too large to diff
- cbits/s2n/arm/curve25519_x25519base.S too large to diff
- cbits/s2n/arm/curve25519_x25519base_alt.S too large to diff
- cbits/s2n/arm/edwards25519_encode.S too large to diff
- cbits/s2n/arm/edwards25519_scalarmulbase.S too large to diff
- cbits/s2n/arm/edwards25519_scalarmulbase_alt.S too large to diff
- cbits/s2n/arm/p256_montjadd.S too large to diff
- cbits/s2n/arm/p256_montjadd_alt.S too large to diff
- cbits/s2n/arm/p256_montjdouble.S too large to diff
- cbits/s2n/arm/p256_montjdouble_alt.S too large to diff
- cbits/s2n/arm/p256_montjmixadd.S too large to diff
- cbits/s2n/arm/p256_montjmixadd_alt.S too large to diff
- cbits/s2n/arm/p256_scalarmul.S too large to diff
- cbits/s2n/arm/p256_scalarmul_alt.S too large to diff
- cbits/s2n/arm/p256_scalarmulbase.S too large to diff
- cbits/s2n/arm/p256_scalarmulbase_alt.S too large to diff
- cbits/s2n/arm/p384_montjscalarmul.S too large to diff
- cbits/s2n/arm/p384_montjscalarmul_alt.S too large to diff
- cbits/s2n/arm/p521_jscalarmul.S too large to diff
- cbits/s2n/arm/p521_jscalarmul_alt.S too large to diff
- cbits/s2n/import.sh too large to diff
- cbits/s2n/include/_internal_s2n_bignum_arm.h too large to diff
- cbits/s2n/include/_internal_s2n_bignum_x86_att.h too large to diff
- cbits/s2n/x86_att/_internal_s2n_bignum_x86_att.h too large to diff
- cbits/s2n/x86_att/bignum_deamont_p384.S too large to diff
- cbits/s2n/x86_att/bignum_deamont_p384_alt.S too large to diff
- cbits/s2n/x86_att/bignum_demont_p256.S too large to diff
- cbits/s2n/x86_att/bignum_demont_p256_alt.S too large to diff
- cbits/s2n/x86_att/bignum_emontredc_8n.S too large to diff
- cbits/s2n/x86_att/bignum_inv_p521.S too large to diff
- cbits/s2n/x86_att/bignum_kmul_16_32.S too large to diff
- cbits/s2n/x86_att/bignum_kmul_32_64.S too large to diff
- cbits/s2n/x86_att/bignum_ksqr_16_32.S too large to diff
- cbits/s2n/x86_att/bignum_ksqr_32_64.S too large to diff
- cbits/s2n/x86_att/bignum_modinv.S too large to diff
- cbits/s2n/x86_att/bignum_montifier.S too large to diff
- cbits/s2n/x86_att/bignum_montinv_p384.S too large to diff
- cbits/s2n/x86_att/bignum_montmul_p384.S too large to diff
- cbits/s2n/x86_att/bignum_montmul_p384_alt.S too large to diff
- cbits/s2n/x86_att/bignum_montsqr_p384.S too large to diff
- cbits/s2n/x86_att/bignum_montsqr_p384_alt.S too large to diff
- cbits/s2n/x86_att/bignum_mul.S too large to diff
- cbits/s2n/x86_att/bignum_mul_8_16.S too large to diff
- cbits/s2n/x86_att/bignum_mul_p521.S too large to diff
- cbits/s2n/x86_att/bignum_mul_p521_alt.S too large to diff
- cbits/s2n/x86_att/bignum_neg_p256.S too large to diff
- cbits/s2n/x86_att/bignum_sqr.S too large to diff
- cbits/s2n/x86_att/bignum_sqr_8_16.S too large to diff
- cbits/s2n/x86_att/bignum_sqr_p521.S too large to diff
- cbits/s2n/x86_att/bignum_sqr_p521_alt.S too large to diff
- cbits/s2n/x86_att/bignum_tomont_p256.S too large to diff
- cbits/s2n/x86_att/bignum_tomont_p256_alt.S too large to diff
- cbits/s2n/x86_att/bignum_tomont_p384.S too large to diff
- cbits/s2n/x86_att/bignum_tomont_p384_alt.S too large to diff
- cbits/s2n/x86_att/curve25519_x25519.S too large to diff
- cbits/s2n/x86_att/curve25519_x25519_alt.S too large to diff
- cbits/s2n/x86_att/curve25519_x25519base.S too large to diff
- cbits/s2n/x86_att/curve25519_x25519base_alt.S too large to diff
- cbits/s2n/x86_att/edwards25519_encode.S too large to diff
- cbits/s2n/x86_att/edwards25519_scalarmulbase.S too large to diff
- cbits/s2n/x86_att/edwards25519_scalarmulbase_alt.S too large to diff
- cbits/s2n/x86_att/p256_montjadd.S too large to diff
- cbits/s2n/x86_att/p256_montjadd_alt.S too large to diff
- cbits/s2n/x86_att/p256_montjdouble.S too large to diff
- cbits/s2n/x86_att/p256_montjdouble_alt.S too large to diff
- cbits/s2n/x86_att/p256_montjmixadd.S too large to diff
- cbits/s2n/x86_att/p256_montjmixadd_alt.S too large to diff
- cbits/s2n/x86_att/p256_scalarmul.S too large to diff
- cbits/s2n/x86_att/p256_scalarmul_alt.S too large to diff
- cbits/s2n/x86_att/p256_scalarmulbase.S too large to diff
- cbits/s2n/x86_att/p256_scalarmulbase_alt.S too large to diff
- cbits/s2n/x86_att/p384_montjscalarmul.S too large to diff
- cbits/s2n/x86_att/p384_montjscalarmul_alt.S too large to diff
- cbits/s2n/x86_att/p521_jscalarmul.S too large to diff
- cbits/s2n/x86_att/p521_jscalarmul_alt.S too large to diff
- cbits/sha1_armv8.c too large to diff
- cbits/sha1_x86.c too large to diff
- cbits/sha256_armv8.c too large to diff
- cbits/sha3_armv8.c too large to diff
- cbits/sha512_armv8.c too large to diff
- cbits/tests/bearssl_diff.c too large to diff
- cbits/tests/ct/README too large to diff
- cbits/tests/ct/cpu_stub.c too large to diff
- cbits/tests/ct/ct.h too large to diff
- cbits/tests/ct/ct_aes.c too large to diff
- cbits/tests/ct/ct_aes_armv8.c too large to diff
- cbits/tests/ct/ct_canary.c too large to diff
- cbits/tests/ct/ct_chapoly.c too large to diff
- cbits/tests/ct/ct_decaf.c too large to diff
- cbits/tests/ct/ct_ed25519.c too large to diff
- cbits/tests/ct/ct_mlkem.c too large to diff
- cbits/tests/ct/ct_p256.c too large to diff
- cbits/tests/ct/ct_powm.c too large to diff
- cbits/tests/ct/ct_x25519.c too large to diff
- cbits/tests/ct/known.txt too large to diff
- cbits/tests/ct/run.sh too large to diff
- cbits/tests/endian/README too large to diff
- cbits/tests/endian/endian.c too large to diff
- cbits/tests/endian/run.sh too large to diff
- cbits/tests/endian/vectors.txt too large to diff
- cbits/tests/fuzz/README too large to diff
- cbits/tests/fuzz/corpus/aead-authentic.bin too large to diff
- cbits/tests/fuzz/corpus/ed25519-tampered.bin too large to diff
- cbits/tests/fuzz/corpus/ed25519-valid.bin too large to diff
- cbits/tests/fuzz/corpus/p256-on-curve.bin too large to diff
- cbits/tests/fuzz/fuzz.h too large to diff
- cbits/tests/fuzz/fuzz_aead.c too large to diff
- cbits/tests/fuzz/fuzz_canary.c too large to diff
- cbits/tests/fuzz/fuzz_decaf.c too large to diff
- cbits/tests/fuzz/fuzz_ed25519.c too large to diff
- cbits/tests/fuzz/fuzz_p256.c too large to diff
- cbits/tests/fuzz/run.sh too large to diff
- cbits/tests/fuzz/standalone.c too large to diff
- cbits/tests/perf/floors.txt too large to diff
- cbits/tests/perf/run.sh too large to diff
- cbits/tests/perf/throughput.c too large to diff
- cbits/tests/ppc8_diff.c too large to diff
- cbits/tests/scrub/README too large to diff
- cbits/tests/scrub/known.txt too large to diff
- cbits/tests/scrub/run.sh too large to diff
- cbits/tests/scrub/scrub.c too large to diff
- cbits/tests/sysdrg/run.sh too large to diff
- cbits/tests/sysdrg/sysdrg.c too large to diff
- cbits/tests/width/ed448_width.c too large to diff
- cbits/tests/width/p256_width.c too large to diff
- cbits/tests/width/run.sh too large to diff
- cbits/tests/width/x25519_width.c too large to diff
- crypton.cabal too large to diff
- tests/BlockCipher/AESSpec.hs too large to diff
- tests/ECDSASpec.hs too large to diff
- tests/EntropySpec.hs too large to diff
- tests/HashSpec.hs too large to diff
- tests/KDF/PBKDF2Spec.hs too large to diff
- tests/NumberSpec.hs too large to diff
- tests/PubKey/DSASpec.hs too large to diff
- tests/PubKey/ElGamalSpec.hs too large to diff
- tests/PubKey/MGF1Spec.hs too large to diff
- tests/PubKey/MLDSASpec.hs too large to diff
- tests/PubKey/MLDSAVectors.hs too large to diff
- tests/PubKey/MLKEMSpec.hs too large to diff
- tests/PubKey/MLKEMVectors.hs too large to diff
- tests/PubKey/P256Spec.hs too large to diff
- tests/PubKey/PSSSpec.hs too large to diff
- tests/PubKey/RSASpec.hs too large to diff
- tests/PubKey/RabinSpec.hs too large to diff
- tests/RuntimeSpec.hs too large to diff
- tests/StreamCipher/ChaChaPoly1305Spec.hs too large to diff
- tests/SysDRGSpec.hs too large to diff
- tests/forkprocess/ForkProcess.hs too large to diff
- tests/tutorial/extract.awk too large to diff
- tests/tutorial/run.sh too large to diff
@@ -1,1398 +1,1026 @@ # CHANGELOG for crypton -## 2.0.1--* fix(cpu): stop reading Intel's SDBG bit as AMD's XOP, which crashed SHA-512- and ChaCha20 on Broadwell and later. The vendored assembly dispatches on a- capability word this library fills, and reads bit 11 of its second dword as- XOP -- which is CPUID leaf 0x80000001 ECX bit 11, an AMD extended leaf.- crypton put the raw leaf 1 ECX there, whose bit 11 is SDBG, the silicon- debug interface, which Intel has reported since Broadwell. On such a- processor `sha512-x86_64.S` took `.Lxop_shortcut` and- `chacha-x86_64.S` took `.Lcrypton_chacha20_asm_4xop`, and the first- `vprotq` is an invalid opcode: SIGILL, for SHA-512 and SHA-384, and for- ChaCha20 and so ChaCha20-Poly1305. OpenSSL clears leaf 1's bit 11 before- merging the real flag in; crypton now clears it and leaves it clear, so the- XOP paths are never taken. Nothing is lost -- XOP ran from AMD's Bulldozer- to Excavator and Zen dropped it -- and it is the reason the AVX-512 bits- beside it are cleared as well. Reported by @lucasdicioccio, who- disassembled the trap- [#202](https://github.com/kazu-yamamoto/crypton/issues/202)--## 2.0.0--* fix(docs): export the names the documentation already referred to.- `Crypto.Number.ModArithmetic` throws `CoprimesAssertionError` and- `ModulusAssertionError` from `inverseCoprimes` and `squareRoot`, and said so- in the haddock, without exporting either, so a caller could not name the- exception it was told to expect; `Crypto.PubKey.Rabin.Types.generatePrimes`- takes a `PrimeCondition` in its exported signature and that synonym was not- exported either. All three are now exported- [#195](https://github.com/kazu-yamamoto/crypton/pull/195)--* Breaking change: fix(bcrypt): refuse a cost bcrypt does not have rather than- substituting one. A cost below 4 came back as a cost-10 hash and a cost- above 31 as a cost-31 one, with nothing said either way, so a caller asking- for something bcrypt does not do was answered with something else and had no- way to tell -- `hashPassword 3` and `hashPassword 10` returned the same- thing. Both ends are now reported as `CryptoError_ParameterInvalid`, which- is what every other KDF here already did for a refused parameter.- `hashPassword` can therefore fail where it could not before, so- `tryHashPassword` is added beside it; the salt it generates is always the- right length, so the cost is the only thing it can report- [#59](https://github.com/kazu-yamamoto/crypton/issues/59)--* Breaking change: fix(poly1305): take a checked key, so that initializing- cannot fail. A Poly1305 key is thirty-two bytes and nothing else about it- can be wrong, so `initialize` returning a `CryptoFailable` put an error case- in front of every caller for a length most of them know is right -- and they- answered it with `throwCryptoError`, this library included: the one in- `Crypto.Cipher.ChaChaPoly1305` guarded a `B.take 32`, and `auth` did not- even do that, it called `error`. There is now a `Key` with `key` to build- one, the length is checked there, and `initialize :: Key -> State` and- `auth :: Key -> ba -> Auth` are total. A caller checks once and then- initializes as often as it likes with nothing to handle. `initialize k`- becomes `initialize <$> key k` where the length is unknown, and where it is- known the check moves to where the key is made. `Key` has no `Show`, as- key material should not- [#28](https://github.com/kazu-yamamoto/crypton/issues/28)--* fix(pubkey): stop printing private keys. `Show` is what `print`, a message- built with `error`, an exception and a test framework's failure output all- reach for, so it is the instance a key travels on when nobody meant to send- it anywhere; the library already kept that promise for the secret keys held- in a `ScrubbedBytes`, and the documentation for `ScrubbedBytes` advertises- it, while ten other types printed theirs in full. Those ten --- `RSA.PrivateKey` and `RSA.KeyPair`, `DSA.PrivateKey` and `DSA.KeyPair`,- `ECDSA.PrivateKey` and `ECDSA.KeyPair`, `DH.PrivateNumber`, and the- `PrivateKey` of `Rabin.Basic`, `Rabin.Modified` and `Rabin.RW` -- now render- the public part and `<secret>` for the rest. Nothing else about them- changes: `Read`, `Eq`, `Data`, `Generic` and `NFData` are all still derived.- The new `Crypto.Debug` exports a class `DebugShow` whose `debugShow` returns- exactly what the derived `Show` used to return, for those ten and for the- five `ScrubbedBytes` secret keys as well, which never had a `Show` that- spoke. **Code that serialized a key through `show` has to say `debugShow`- instead**; `read (debugShow k) == k` still holds, but `read` given the- output of `show` will now fail at run time, which the compiler cannot point- at- [#72](https://github.com/kazu-yamamoto/crypton/issues/72)--* deprecate(ecc): the curves over a binary field. They are obsolete, they are- the curves a cofactor makes delicate, and pyca/cryptography deprecated them- for removal in the release that fixed CVE-2026-26007. A `DEPRECATED` pragma- now covers the eighteen `SEC_t*` constructors of `CurveName` and the- eighteen types of the same names in `Crypto.ECC.Simple.Types`; nothing is- removed, so the only effect is a warning where one of them is named, and- they will go in a later major version. The prime curves with a cofactor,- `SEC_p112r2` and `SEC_p128r2`, are not deprecated: the check above covers- them- [#66](https://github.com/kazu-yamamoto/crypton/issues/66)--* fix(ecc): refuse a public point outside the prime-order subgroup. A point- that satisfies the curve equation is not necessarily in the subgroup the- base point generates; the two coincide only where the cofactor is 1. Of the- curves in `CurveName` twenty have a cofactor -- the eighteen binary ones,- and `SEC_p112r2` and `SEC_p128r2`, whose cofactor is 4 -- and on those the- other party could offer a point of small order, at which point the value- that came back depended on our private number only through its residue- modulo that order, and offering it and watching the answer handed them those- bits. This is the flaw pyca/cryptography fixed as CVE-2026-26007; what is- fixed here is the same one, found by following that report.- `Crypto.PubKey.ECC.DH.getShared` and `tryGetShared`, and- `Crypto.ECC.Simple.Prim.pointFromIntegers`, now require the point to be in- the subgroup and report `CryptoError_PointSubgroupInvalid` when it is not.- The check is `isPointInSubgroup`, newly exported from both prim modules:- where the cofactor is 1 it answers without work, and otherwise it multiplies- by the group order and requires the point at infinity, which is what- OpenSSL's `EC_KEY_check_key` does and costs one further scalar- multiplication -- an exchange on an affected curve is about twice the price,- and one on every other curve is unchanged. The typed `Crypto.ECC` interface- offers only cofactor-1 curves and dedicated implementations, so nothing- reaching elliptic curves through it, `tls` among them, was affected--* perf(p256): inline the field arithmetic on AArch64. `felem_mul` and- `felem_square` end in `felem_reduce_degree`, a carry chain the whole width- of the number, and that chain is what their latency is: one product feeding- the next costs 18.1 ns on an Apple M4, while four independent ones cost 11.4- ns each. The curve arithmetic has independent products to offer -- the two- squarings that open a point doubling, the multiplication and the squaring- that close it -- but only if the compiler inlines the reduction instead of- calling it, since a call is a fence. Plain `inline` does not change its- mind; `always_inline` does, and it is worth asking where there are registers- to hold two carry chains at once and not where there are not: 1.23x on an- M4, 1.12x and 1.05x on a Neoverse under clang and gcc, and 0.95x and 0.82x- on x86-64, whose fifteen general-purpose registers are not enough. So it is- gated on the architecture and x86-64 is left byte-identical. ECDH P-256 on- an M4: 69.16 to 56.24 us, against openssl's 24.68, so 0.36 becomes 0.44;- ECDSA P-256 signing and verification move with it. The cost is code, 30 to- 116 kilobytes of it- [#188](https://github.com/kazu-yamamoto/crypton/pull/188)-* perf(number): count bytes from the bit count, not from base 256. `numBytes`- asked GMP how many base-256 digits a number has, and GHC's bignum answers- that by dividing the number down to nothing, one digit at a time, where the- same question in base two is a look at the highest limb. On a 2048-bit- `Integer` that is 1.65 us against 0.01. Every serialization here asks for- the size before it allocates and `i2ospOf` asks twice, so the cost landed on- every RSA, DSA and DH operation leaving the `Integer` world: `i2ospOf_` at- 256 bytes goes from 2.87 to 0.09 us and RSA-2048 verification from 18.4 to- 15.5 us on an M4. Signing moves by a percent; it is two exponentiations and- hardly touches this- [#187](https://github.com/kazu-yamamoto/crypton/pull/187)-* perf(ecc): stop sharing the doublings in the double multiplication.- `pointAddTwoMuls` was Shamir's trick, one pass over the bits of both scalars- at once in `Integer` arithmetic, which is the right trade when the two- multiplications would cost the same. They have not for a while: `pointMul`- goes to C, and over a prime field it multiplies the base point through a- table of its multiples at about a third of the price -- and the base point- is one of the two, since ECDSA verification is the only caller. Doing them- separately and adding: ECDSA P-384 verification 1397 to 698 us on an M4 in- the typed API, 9839 to 738 in the older one, and a curve over a binary field- 641 ms to 2.6. P-256 keeps the double multiplication it has in C- [#186](https://github.com/kazu-yamamoto/crypton/pull/186)-* perf(sha3): take the CRYPTOGAMS Keccak for x86-64 as well. The same module- as [#181](https://github.com/kazu-yamamoto/crypton/pull/181) on the other- architecture, and the reason it was not taken at the time was a measurement- taken on the wrong machine: crypton on Apple silicon against openssl on- x86-64, which said there was nothing to gain. Measured on one machine there- was: SHA3-256 on an EPYC 7763 goes from 109 to 421 MB/s, against openssl's- 426, so 0.26 becomes 0.99- [#184](https://github.com/kazu-yamamoto/crypton/pull/184)-* perf(sha1): take the CRYPTOGAMS SHA-1 for AArch64. The instructions are the- ones [#170](https://github.com/kazu-yamamoto/crypton/pull/170) put in, and- the arrangement is what the module has over them: the message schedule of- the next four rounds runs against the rounds of this one, which is not- something a C function is going to be made to do --- [#179](https://github.com/kazu-yamamoto/crypton/pull/179) tried the one- thing C can do here, handing over a run of blocks, and on this processor it- measured nothing at all. The entry point for processors that have the- instructions is not exported, so the module's own dispatch picks it and the- answer to the runtime question goes into the word that dispatch reads. On- Apple silicon: 3155 to 3379 MB/s at 16 KiB, against openssl's 3350 on the- same machine, so where this was at 0.94 it is now a shade ahead. The- intrinsics stay for the block a message ends with, and for any processor- that has the instructions but is built without the assembly- [#182](https://github.com/kazu-yamamoto/crypton/pull/182)-* perf(sha3): take the CRYPTOGAMS Keccak for AArch64. The instructions are- the ones [#171](https://github.com/kazu-yamamoto/crypton/pull/171) put in --- EOR3, RAX1, XAR and BCAX -- and what this module does with them is take a- run of blocks rather than one at a time, and schedule the round it is in- against the next one. The absorb loop hands over the whole run, which also- drops the alignment trampoline on that path: the assembly reads the message- as bytes. SHA3-256 on Apple silicon: 1002 to 1104 MB/s at 16 KiB, against- openssl's 1058 on the same machine. Only the absorb side is handed over;- the squeeze, which SHAKE uses to produce output, is entangled with this- side's buffer bookkeeping and is not where the time goes- [#181](https://github.com/kazu-yamamoto/crypton/pull/181)-* perf(xts): double the XTS tweak in the integer registers. The tweak- advances by doubling in GF(2^128) once per block, and it was doing that in a- vector register: six operations on the same units that are running the- rounds and the exclusive ors, in a chain where each waits for the one- before. On a processor whose AES is fast that is not a detail -- taking the- doubling out of a diagnostic build, which gives the wrong answer but says- where the time goes, left XTS running at the speed of ECB. It costs three- integer operations instead, and the integer units have nothing else to do- here; what crosses over is one move per block. On x86-64 that also gets- eight values out of a register file with sixteen entries, so the round keys- stay where they were. AES-128-XTS at 16 KiB: 9644 to 18646 MB/s on Apple- silicon and 4504 to 7660 on a Haswell-generation x86-64, against openssl's- 17382 and 6997 on the same machines, so both are now a little ahead where- they were at 0.55 and 0.64. No assembly: the AArch64 module in CRYPTOGAMS- has no XTS, and the x86-64 one's is inside a module this does not otherwise- want- [#180](https://github.com/kazu-yamamoto/crypton/pull/180)-* perf(sha1): hand the SHA-1 block loop a run of blocks rather than one at a- time. A block at a time means the state goes out to memory and comes back- either side of every block, with the two shuffles that put it in the order- the instructions want; against the hundred-odd cycles a block costs with the- SHA extensions that is most of what stood between this and openssl. On an- EPYC 7763: 1364 to 1677 MB/s, against openssl's 1670 on the same machine,- and on a Xeon 8370C 1506 to 1619. On Apple silicon it measures nothing at- all -- that processor hides the cost -- and is kept there only so the two- paths have one shape. The intended file for this was CRYPTOGAMS'- `sha1-x86_64.pl`, which turns out to be the 2006 scalar implementation: no- SSSE3, no AVX, no SHA extensions. Processors without the extensions are- therefore where they were, 664 MB/s against openssl's 791 on a Haswell- [#179](https://github.com/kazu-yamamoto/crypton/pull/179)-* perf(sha2): take the CRYPTOGAMS SHA-256 and SHA-512 for x86-64. One- generator gives both, as on AArch64, and each dispatches on what the- processor has: the SHA extensions, AVX2, AVX, SSSE3 or plain integer code.- That replaces everything written here for x86-64 -- `sha256_x86.c` and- `sha512_x86.c` go -- since it is ahead of all of it either way. At 16 KiB:- on an EPYC 7763, SHA-256 1430 to 1584 MB/s and SHA-512 423 to 769; on a- Haswell-generation part, SHA-256 318 to 379 and SHA-512 488 to 593, where- openssl reports 378 and 589. The block loops hand over the whole run of- blocks rather than one at a time, and the alignment trampoline goes with it.- This also fixes a bug in the capability word- [#176](https://github.com/kazu-yamamoto/crypton/pull/176) added: bit 29 of- leaf 7 EBX is the SHA extensions, not an AVX-512 bit, and was being cleared- along with them -- which cost the SHA-256 assembly two thirds of its speed- on a processor that has them, and which no machine here could have shown,- since none has them- [#178](https://github.com/kazu-yamamoto/crypton/pull/178)-* perf(chacha): take the CRYPTOGAMS ChaCha20 for x86-64 as well. The C here- vectorises from eight blocks up and takes anything shorter one block at a- time, so a message of a few hundred bytes -- a QUIC packet, a small TLS- record -- ran at a fifth of the bulk rate. The module has vector code for- those lengths and is a few per cent ahead in bulk besides: 494 to 1091 MB/s- at 256 bytes, 477 to 701 at 128, and 2201 to 2374 at 16 KiB, which is- openssl's 2389 on the same machine. It is handed everything from one block- up, where the AArch64 module is handed nothing below three, that one's- scalar path measuring level with the C. Keystream generation is still the- C on both, having no input to exclusive-or- [#177](https://github.com/kazu-yamamoto/crypton/pull/177)-* perf(poly1305): take the CRYPTOGAMS Poly1305 for x86-64 as well. The same- module for the other architecture, through the same three functions, so what- this adds is the capability word: where the AArch64 one reads- `crypton_armcap_P`, this one reads `crypton_ia32cap_P`, which is cpuid's own- words in the order OpenSSL keeps them, filled with the bits for anything the- operating system will not preserve cleared. What it brings over the AVX2- written here is a hand-scheduled scalar path, which is what a message of a- few hundred bytes actually uses, and an AVX path for machines with no AVX2:- on a Haswell-generation x86-64, 4298 to 5345 MB/s at 16 KiB and 556 to 1573- at 64 bytes, against the roughly 5270 openssl reaches there. `poly1305_avx2.c`- goes the way the NEON did. The module's AVX-512 paths are not taken: the- generator chooses what to emit from the version of the assembler it is told- about, and it is now told one that predates them, no machine here being able- to run them and an assembler still in use being unable to assemble them.- Pinning that version also makes the checked-in assembly independent of the- host that produced it- [#176](https://github.com/kazu-yamamoto/crypton/pull/176)-* perf(sha256): take the CRYPTOGAMS SHA-256 for AArch64. The instructions are- the ones the intrinsics here already use; what the module does with them is- schedule them across a whole run of blocks rather than one at a time, and- keep the message schedule of the next block moving while the rounds of this- one are still going, which a function that is handed one block and returns- cannot do whatever it is written in. So the block loop hands over the whole- run, which also drops the alignment trampoline on this path -- the assembly- reads the message as bytes and wants neither the alignment nor the copy. On- Apple silicon: 2637 to 3279 MB/s at 16 KiB, against openssl's 3323 on the- same machine, and 1576 to 1966 at 64 bytes. SHA-512, which the same- generator emits, is not taken: 1876 here against openssl's 1880, the- ARMv8.2 instructions for it having gone in with #110- [#175](https://github.com/kazu-yamamoto/crypton/pull/175)-* perf(poly1305): take the CRYPTOGAMS Poly1305 for AArch64. One- multiplication modulo 2^130 - 5 depends on the one before it, so what there- is to win is in how the multiplies and the carries are laid against each- other, and in keeping the accumulator in whichever base costs less: the- module works in base 2^64 while the message is short and switches to base- 2^26 for the four-way vector loop, deciding that for itself. Unlike the- other two it is the whole of the arithmetic rather than a bulk loop bolted- to the side, so the context now holds either the 26-bit limbs the C works in- or the 192 bytes the assembly keeps, as a union, and grows from 84 bytes to- 232. On Apple silicon: 4269 to 8060 MB/s at 16 KiB and 1542 to 4355 at 64- bytes, and ChaCha20-Poly1305 together, which is what this is for, 1416 to- 2284 against openssl's 2180 on the same machine. `poly1305_neon.c`, which- [#169](https://github.com/kazu-yamamoto/crypton/pull/169) added, goes: the- assembly is faster at every length on every target that gets it, and the- scalar C remains for the targets that do not. The tests came first and- found that the chunking property here had been testing nothing -- it used- the all-zero key, whose r is zero, so both sides were the nonce whatever- they did, which is how it came to feed the chunks to `update` in reverse- order and pass- [#174](https://github.com/kazu-yamamoto/crypton/pull/174)-* perf(chacha): take the CRYPTOGAMS ChaCha20 for AArch64. The vector- registers hold four ChaCha states and there is no room for a fifth, so once- four blocks are in flight the only place further parallelism can come from- is the integer side: that module runs a fifth block through the general- registers alongside four in the vector ones, and above 512 bytes two- alongside six. Which register holds which word is the whole of the trick- and C has no way to say it, which is why the intrinsics here sat at about- 0.63 of what openssl gets out of this very file. On Apple silicon, a- message per call: 1911 to 3069 MB/s at 512 bytes, 1913 to 3093 at 4 KiB and- 2056 to 3112 at 64 KiB, against openssl 3.6's 3164 on the same machine,- which is this code. It is handed only the states it fits -- twenty rounds,- a 256-bit key, and as many blocks as the 32-bit counter has room for, since- crypton's counter is 64 bits wide and carries where the assembly wraps --- and nothing below 192 bytes, where its own vector path starts. The tests- came first: the properties here generated one shape of state, so the- 256-bit constants were never exercised by them- [#173](https://github.com/kazu-yamamoto/crypton/pull/173)-* perf(gcm): take the CRYPTOGAMS stitched AES-GCM for x86-64, which is the- first assembly in the package. Counter-mode AES and GHASH do not compete- for the same execution ports, so a loop that interleaves them at- instruction granularity runs both in about the time the rounds alone take;- written in C that interleaving does not survive the compiler, which sinks- every multiply to the end of the group, and the disassembly of what- [#160](https://github.com/kazu-yamamoto/crypton/pull/160) produced says so.- On a Haswell-generation x86-64, a message per call, AES-128-GCM: 2672 to- 3172 MB/s at 1152 bytes, 3394 to 4271 at 4 KiB and 3657 to 5110 at 16 KiB,- where openssl speed on the same machine reports 4896; decryption within a- couple of points of that, and AES-256-GCM 3147 to 4297 at 16 KiB against- openssl's 4206. `cbits/asm` holds the module, the translator it needs and the- generated assembly, one file per object format, so that building needs no- perl; `cbits/asm/README.md` records where it came from and what was done to- it, which is to rename the entry points, a program linking both crypton- and openssl being entitled to object to two definitions of- `aesni_gcm_encrypt`. What the assembly reads is laid out OpenSSL's way and- is built per message in `cbits/aes/gcm_x86_asm.c`, the powers of H being- the ones crypton already has, shifted up a bit. Short messages are not- handed over at all. `cabal-version` is now 3.0, for `asm-sources`- [#172](https://github.com/kazu-yamamoto/crypton/pull/172)-* perf(sha3): use the ARMv8.2 SHA-3 instructions. Keccak was the plain C- everywhere, a round at a time over tables of rotation amounts and lane- positions, at half of what openssl manages on the same machine. EOR3,- RAX1, XAR and BCAX exist for exactly this permutation and take a round from- around a hundred and fifty operations to sixty-six; they come with the- SHA-512 extension the tree already asks for. Rho and pi move one lane of- every row into every other row, so the round cannot be done in place, and- four rounds go in an iteration, which is worth a fifth over one. SHA3-256- 551 to 991 MB/s (openssl 1064), SHAKE128 700 to 1166, Keccak-256 559 to- 944. The body is generated from the definitions in FIPS 202 rather than- copied in, and the script that worked out the rotations and the lane- permutation checked itself against the published digests of the empty- string and of "abc" before emitting any C, which is how a first attempt- with chi reading lanes another row had already overwritten was caught. x86- is untouched: nothing there has instructions for this- [#171](https://github.com/kazu-yamamoto/crypton/pull/171)-* perf(sha1): use the ARMv8 SHA-1 instructions. The AArch64 paths for- SHA-256 and SHA-512 went in with #104 and #110 and x86 got its SHA-1- instructions in [#165](https://github.com/kazu-yamamoto/crypton/pull/165),- but the AArch64 SHA-1 ones were never used -- and they are part of the same- optional feature as the SHA-256 ones, so every processor that has those has- these. SHA1C, SHA1P and SHA1M each do four rounds with one of the three- round functions, SHA1H carries E from one group to the next, and SHA1SU0- and SHA1SU1 do the message schedule between them. On Apple silicon: 1272- to 3180 MB/s, against openssl 3.6's 3350 on the same machine. Checked- against the hardware rather than through an emulation of the instructions,- the machine here having them: the digests agree with the generic- implementation over every message length from 0 to 2000, with each input- split in two updates- [#170](https://github.com/kazu-yamamoto/crypton/pull/170)-* perf(poly1305): four blocks at a time with NEON. AArch64 had only the- scalar loop, whose five 26-bit limbs and 32-bit multiplies are the shape a- 32-bit machine wants. This is the arithmetic of the AVX2 path in NEON,- written as a transliteration of that file rather than a fresh formulation,- since the maths there is already pinned by the known-answer tests; what- differs is the width, AVX2 holding four 64-bit products in a register where- NEON holds two, so each product becomes a pair and the limbs are packed- back into four 32-bit lanes before the next multiply. On Apple silicon:- Poly1305 2783 to 4840 MB/s, and ChaCha20-Poly1305 together 1164 to 1368.- Checked against the scalar implementation over forty keys and every message- length from 0 to 400, with each input split in two updates. Also measured- and left alone: BLAKE2b at 1612 MB/s against openssl's 1378, the reference- C being the faster of the two- [#169](https://github.com/kazu-yamamoto/crypton/pull/169)-* perf(modes): stop the generic cipher modes allocating per byte. Counter- mode with a cipher whose modes are not in C ran at a third of what the same- cipher managed in ECB, and at an eighth for Blowfish, for two reasons- outside the cipher. The counters were built one at a time by `ivAdd`,- which allocates a block and walks the whole width of the counter from the- original for each of them; they are now one buffer filled in place. And- the exclusive or was `Data.ByteArray`'s, which walks a byte at a time- through an IO applicative -- 420 MB of heap for 8 MiB of counter mode,- against 17 MB for the same data through ECB, which is fifty bytes allocated- per byte produced and cost more than the cipher did. There is a- `crypton_memxor` to call instead, a pass of words, which the modes and CMAC- use. The serial modes also took each block as a copy and take shared- slices now. On Apple silicon, counter mode: Camellia-128 79.7 to 285.9- MB/s, Blowfish 60.4 to 282.6, DES 46.2 to 114.9, CAST5 40.2 to 86.6,- Twofish-128 37.4 to 57.6, 3DES 25.2 to 36.3, and CBC and CMAC by a third to- a half as much again. AES is unchanged: its modes are in C and never came- this way- [#168](https://github.com/kazu-yamamoto/crypton/pull/168)-* build: compile the C at -O3, which is what came of looking at P-256 against- openssl. The comparison in the problem list was wrong -- a base point- multiplication here against openssl's ECDH, which is a variable point one --- and measured properly P-256 is 2.8 to 3.3 times slower rather than the 1.27- claimed. The time is in the field arithmetic, five 51-bit limbs in- Montgomery form at 44.4 ns a multiplication, against hand-written assembly- using `mulx`, `adcx` and `adox`; a four-limb saturated Montgomery- multiplication written in C to see what a compiler would give measured 41.3- ns, so that is not the way in. What did move is the optimisation level GHC- passes: a P-256 base point multiplication goes from 71.0 to 59.8 us on x86-64- and 26.0 to 24.3 on Apple silicon, AES-128-GCM from 3455 to 3708 MB/s and- AES-128-OCB from 2187 to 2484, with ChaCha20, Poly1305, SHA-1 and MD5 within- a couple of per cent either way. The masked selections in the curve and- field code compile to no conditional jumps at either level- [#167](https://github.com/kazu-yamamoto/crypton/pull/167)-* refactor(aes): drop the keystream generator nobody can call. `genCTR` and- `genCounter` are exported from a module in `other-modules`, so nothing- outside the library could reach them and nothing inside used them; the only- mention left was a test commented out since the cryptonite days. They were- also the slowest thing in the file, a block at a time through the- single-block entry point at 715 MB/s where counter mode does 5788, and the- three ways of fixing that are each worse than removing them: counter mode- over zeros costs Apple silicon a fifth, counters through ECB costs both, and- a keystream loop written out per key size is eighty lines for an API no- caller can see. Also declares `crypton_aes_encrypt_ctr` and- `crypton_aes_encrypt_c32` in the header, which had them defined and imported- but never declared- [#166](https://github.com/kazu-yamamoto/crypton/pull/166)-* perf(sha1): use the Intel SHA extensions on x86-64. The extension that- carries the SHA-256 instructions carries four for SHA-1 as well, and the same- cpuid bit answers for both, so this is one file and one branch. On an AMD- EPYC 7763: 725.1 to 1363.8 MB/s, against openssl's 1668.2 on the same- machine. 1.9x, where the SHA-256 instructions were worth 4.8x -- SHA-1's- rounds are cheaper to begin with, so there is less for an instruction to- replace. The sequence was checked by replacing the four instructions with C- that follows the SDM and comparing against the generic implementation over- every length from 0 to 1024, which found the same missing schedule step- [#155](https://github.com/kazu-yamamoto/crypton/pull/155) had- [#165](https://github.com/kazu-yamamoto/crypton/pull/165)-* docs(sidechannel): say what the modules that still work in `Integer` keep- from the clock, and fix the two places where something could be done about- it. ElGamal inverted the shared secret with the extended Euclidean- algorithm, whose steps follow the bits it is given -- the modulus is prime,- so Fermat reaches it. Its signing inverts the ephemeral value modulo an even- number, where Fermat does not reach, so `sign` blinds instead: the algorithm- is handed that value times a fresh random unit and the blinder divided out- afterwards. What is left is written down rather than fixed -- the Jacobi- symbols Rabin takes modulo its private primes, and the cost of `Integer`- arithmetic following the size of the numbers -- and `Crypto.Cipher.AES` now- says which implementation a machine gets and that the fallback, being- table-driven, is not constant time- [#164](https://github.com/kazu-yamamoto/crypton/pull/164)-* perf(poly1305): shorten the carry chain and stop the AVX2 loop spilling. The- carries go in pairs, since the two halves of that chain do not depend on each- other; the powers of r are read from memory, there being sixteen registers- and ten of them wanted for the accumulator and the products; and the message- is added limb by limb as the block comes apart rather than five limbs being- formed first. 4203 to 4452 MB/s, and ChaCha20-Poly1305 together from 1412 to- 1488. What is left is the instruction count: 107 per 64 bytes, of which 25- are the multiply- [#163](https://github.com/kazu-yamamoto/crypton/pull/163)-* perf(chacha): combine as the keystream comes out of the registers. All three- vector implementations wrote it to a buffer on the stack and read it back to- exclusive-or it with the input, which is a pass over every byte for something- the registers were already holding. 2128 to 2230 MB/s on x86-64, and nothing- on Apple silicon, where the round trip was free. Measured while doing it:- the AVX2 path already did eight blocks at a time, and what is left of the gap- to openssl in this AEAD is Poly1305 rather than the cipher- [#162](https://github.com/kazu-yamamoto/crypton/pull/162)-* perf(sha): compute the message schedule in vector registers on x86. SHA-512- has no instruction there and SHA-256 has none on a processor older than- Goldmont or Zen, which includes the Ice Lake and Cascade Lake server parts.- The rounds are a chain and stay where they are; the schedule is a quarter of- the work, comes out four words at a time and depends on nothing but the- message, so it goes into the vector registers and runs alongside rounds that- need the general ones. SHA-256 228 to 314 MB/s, SHA-512 354 to 480- [#161](https://github.com/kazu-yamamoto/crypton/pull/161)-* perf(gcm): take the GHASH of the group before, alongside this group's rounds.- Held a group apart the multiply and the rounds run through each other, where- in step neither could start until the other finished. With it, the multiply- called directly rather than through a branch pointer the compiler cannot see- through, and the round keys read from memory rather than spilled: AES-128-GCM- 2797 to 3458 MB/s and AES-256-GCM 2458 to 3053. openssl does 4895 and 4205- on the same machine; the rest of that is instruction-level interleaving,- which does not survive being written in intrinsics- [#160](https://github.com/kazu-yamamoto/crypton/pull/160)-* perf(ocb): drive OCB through the ECB paths a group at a time. It ran one- block at a time through the single-block entry point and so cost four times- what GCM costs, for a mode that does less work than GCM. The offsets have to- be worked out in order but the block cipher calls under them do not depend on- each other, so eight go through ECB together. OCB-128 1130 to 3500 MB/s on- Apple silicon and 694 to 2173 on x86-64, the authenticated data 1141 to 5900- and 692 to 2526. CCM is unchanged and stays that way: what is left there is- CBC-MAC, where each block waits for the one before it- [#159](https://github.com/kazu-yamamoto/crypton/pull/159)-* test(aes): run the XTS vectors, and add OCB and CCM at 192 and 256 bits. The- XTS known-answer tests never ran: the call was commented out and the test it- would have called did not compile, so vectors at both key sizes sat in the- tree unused. XTS is defined only for a 128-bit block, which the general KAT- runner cannot promise, so it gains a counterpart for a cipher that can. OCB- and CCM had vectors at 128 bits only. 2613 examples to 2679- [#158](https://github.com/kazu-yamamoto/crypton/pull/158)-* perf(aes): build the AArch64 key schedule with the instructions rather than- the S-box table. The AArch64 path expanded a key by calling the generic- implementation and then inverting the round keys, so every schedule went- through sixteen lookups at addresses derived from the key -- a small thing- next to the per-block indexing the extensions exist to remove, but a key- schedule is what an attacker most wants out of a cache, and x86 has never- needed the table. AArch64 has no counterpart to AESKEYGENASSIST, but AESE- against a zero key is SubBytes and ShiftRows, and a word given to it in all- four columns comes back as SubWord in each of them. The words stay in- vector registers throughout, which is what makes it free: moving each one to- a general register for the instruction and back cost more than the- instruction did, 87 to 144 ns for an AES-128 schedule, where keeping them in- registers gives 81.4- [#157](https://github.com/kazu-yamamoto/crypton/pull/157)-* perf(aes): AES-192 through the processor's AES instructions. Every 192-bit- slot in the branch table was left at the generic code, on x86 and on AArch64- alike, so a 192-bit key got the table-driven software AES while 128 and 256- got the instructions. It was 164 times slower for counter mode on the x86- machine measured and 62 on Apple silicon, and it was also the only key size- whose data path indexes a table with bytes derived from the key -- a caller- who picks AES-192 over AES-128 for a wider margin was quietly given a weaker- one. Counter mode then GCM, before and after: Apple silicon 152.7 to 9452.0- MB/s and 112.3 to 7049.3, x86-64 40.4 to 6635.1 and 39.9 to 2633.5. Both- implementations were already written once per key size, so this instantiates- them again at twelve rounds; x86 also needed the 192-bit schedule, which- does not fall into 128-bit pieces the way the other two do- [#156](https://github.com/kazu-yamamoto/crypton/pull/156)-* perf(sha256): use the Intel SHA extensions on x86-64, which is what issue- [#31](https://github.com/kazu-yamamoto/crypton/issues/31) reports -- SHA-256- four to eight times slower than sha256sum and openssl, both of which use the- processor's instructions. AArch64 got its instructions in #104 and is at- parity with them; x86 had nothing. SHA256RNDS2 does two rounds at a time and- SHA256MSG1 and SHA256MSG2 help with the message schedule, so a block costs- four groups of sixteen instructions instead of sixty-four rounds of scalar- work. On an AMD EPYC 9V74: 338.3 to 1612.7 MB/s, against openssl's 1783.8 on- the same machine. The extensions arrived with Goldmont and Ice Lake at Intel- and with Zen at AMD, far later than AES-NI, so a processor without them is- ordinary rather than ancient: the code sits behind a target attribute and a- cpuid question, and the plain C stays for everything else- [#155](https://github.com/kazu-yamamoto/crypton/pull/155)-* perf(bcrypt): Blowfish, and the key setup bcrypt wraps it in, in C. bcrypt- is a cost parameter and a promise that the cost is paid, and what pays it is- the Blowfish key schedule; in Haskell that cost about twice what the usual- implementations charge, so a hash of a given length of time had to be asked- for with a lower cost than elsewhere. Cost 8 goes from 25.97 to 9.98 ms,- cost 10 from 102.01 to 39.79, cost 12 from 418.78 to 159.41, `bcrypt_pbkdf`- from 109.76 to 40.38, and Blowfish over 4 KiB from 0.05 to 0.01 -- at cost- 10 that is 39.8 ms against the 52 `htpasswd` takes on the same machine. The- Haskell cipher goes with it, so there is one implementation rather than two,- and nothing exposed changes- [#154](https://github.com/kazu-yamamoto/crypton/pull/154)-* perf(prime): fewer Miller-Rabin rounds for a candidate nobody chose. A- number handed over may have been built to pass, and against that the only- thing to go on is that a round catches three quarters of the composites- there are, so `isProbablyPrime`, `findPrimeFrom` and `findPrimeFromWith`,- which all take their number from the caller, keep their thirty rounds. A- candidate drawn here is the case Damgard, Landrock and Pomerance worked out- and Table 4.4 of the Handbook of Applied Cryptography tabulates:- `generatePrime` and `generateSafePrime` now use twice what it asks for one- chance in 2^80, capped at the thirty they had, which leaves the chance far- under one in 2^100 at every size. With the candidates held fixed,- `generatePrime 1024` goes from 28.5 to 16.9 ms and an RSA-2048 key from 52.9- to 39.2- [#153](https://github.com/kazu-yamamoto/crypton/pull/153)-* fix(rsa): work the private exponent out without the extended Euclidean- algorithm. The modulus is the secret there, so multiplying the value by a- random number hides nothing; what does is that `e` is public. Whatever `d`- is, `e * d = 1 + k * phi` for some `k` under `e`, and reading that modulo- `e` gives `k` as an inverse modulo a number of a handful of bits, which for- a prime `e` is Fermat; `d` is then an exact division. What phi touches is a- remainder and a division, and nothing in either follows it- [#152](https://github.com/kazu-yamamoto/crypton/pull/152)-* perf(f2m): ask aarch64 for its carry-less multiply as well. #148 used PMULL- only where the compiler had been told the machine has the crypto- extensions, which is so on Apple and not on a Linux built for the bare- ARMv8 baseline, though every processor that runs such a build has it. It is- now compiled behind an attribute and the machine asked at run time, through- the auxiliary vector on Linux and Android, elf_aux_info on FreeBSD and a- sysctl on Apple: sect283k1 421.2 to 168.9 us there, sect571r1 2289.2 to- 579.9- [#151](https://github.com/kazu-yamamoto/crypton/pull/151)-* refactor(ecc): one multiplication for both of the curve APIs, and one place- for each buffer's size. Which path a point multiplication takes was written- out twice, and the copy in `Crypto.ECC.Simple.Prim` cannot be reached from- outside the library on a curve over a binary field, so the suite never ran- it; it moves to the internal module both already share, which makes the copy- nobody can call the same code everybody runs. The two buffers for a C call- that still had their size written out separately from the offsets into them- now take both from one list, as the one that was wrong in #141 does -- the- note there records that neither valgrind nor the debug RTS catches that- mistake, both having been tried- [#150](https://github.com/kazu-yamamoto/crypton/pull/150)-* perf(f2m): use the x86 carry-less multiply where the processor has it.- PCLMULQDQ is not part of the x86-64 baseline, so the cpuid the package- already runs for AES-NI reports one more bit and the multiplication that- uses the instruction sits behind an attribute. Measured through Rosetta,- which translates rather than runs it, so the ratio is what to read:- sect283k1 560.4 to 177.5 us, sect571r1 3049.6 to 623.9- [#149](https://github.com/kazu-yamamoto/crypton/pull/149)-* perf(f2m): do the binary field arithmetic in C. The ladder of #142 spent- nearly all its time on one thing -- a carry-less multiplication, which- ordinary arithmetic does not give and which in Haskell was `Integer` shifts- and exclusive ors, about 4 us for a 283-bit multiplication. The field and- the ladder over it are now C, with the processor's instruction where there- is one and four interleaved groups of bits where there is not, folding for- the reduction and Fermat for the inverse. sect163k1 3431 to 67.4 us with- the instruction and 117.3 without, sect283k1 10181 to 157.6 and 386.2,- sect571r1 40469 to 521.6 and 2101.0. It is also constant time, which the- Haskell ladder was not- [#148](https://github.com/kazu-yamamoto/crypton/pull/148)-* perf(bignum): start the doubling for `R^2 mod m` at the highest power of two- under the modulus rather than at one, which for a modulus that fills its- limbs is half the steps. Two to three percent of a curve operation, and- every curve operation and every `expSafe` pays for it once. Folding instead- of Montgomery for the primes shaped `2^k - c` was written and measured- alongside it and is not here: it is slower in this representation, 87.8 ns- against 76.8 for a 521-bit multiplication, because the shift down by `k`- costs more than the reduction pass it replaces when `k` does not land on a- limb boundary- [#147](https://github.com/kazu-yamamoto/crypton/pull/147)-* perf(ecc): keep a table of the multiples of each curve's base point, which- is the point signing and making a key multiply and the only one worth a- table. A multiplication with it is one addition per four bits and no- doublings: secp256k1 211.1 to 59.8 us, secp384r1 519.3 to 144.2, secp521r1- 1047.7 to 283.0, and ECDSA P-384 signing 556.4 to 179.9 on both elliptic- curve APIs, which share the table. A table is built when a curve is first- asked for one -- 2.8 ms for secp256k1, 5.5 for secp384r1, 10.6 for secp521r1- -- and is 221 KB and 456 KB for the last two, so it pays for itself after- about fifteen multiplications- [#146](https://github.com/kazu-yamamoto/crypton/pull/146)-* perf(bignum): take the limbs four and two at a time as well as eight in the- loop every modular multiplication is built out of. Four and six limbs, which- is what most of the curves want, fell entirely to the one-at-a-time tail- before: a field multiplication at six limbs goes from about 58 to 49 ns,- secp384r1 scalar multiplication from 596.7 to 519.3 us and ECDSA P-384- signing from 645.0 to 556.4. Specialising the sizes further, which is what a- generated implementation would do, measures about 4% more and is not here- [#145](https://github.com/kazu-yamamoto/crypton/pull/145)-* fix(rsa): keep the blinding factor out of the extended Euclidean algorithm.- The blinder is a random number and its inverse, and the inverse went through- an algorithm whose steps follow the number handed to it -- the number the- blinding rests on, and unlike the other inverses this one is worked out once- per operation rather than once per key. `n` being composite leaves no- Fermat to fall back on, so the algorithm is handed the factor multiplied by- sixteen fresh random bytes and its answer multiplied by them again, which- leaves the inverse wanted and shows the algorithm nothing to do with it. In- IO, where every draw of randomness goes to the system, `generateBlinder`- goes from 74 to about 120 us and a PKCS#1 v1.5 `signSafer` from 719 to about- 765; under a DRG the caller carries, 24.7 to 24.9- [#144](https://github.com/kazu-yamamoto/crypton/pull/144)-* fix(rsa): work `qinv` out without the extended Euclidean algorithm. Making- a key inverts one prime modulo the other and both of them are the key- itself, so that inverse is now Fermat's little theorem through `expSafe`,- which the other prime being prime allows: 308.6 us against 10.1, on a key- that takes tens of milliseconds to make. Making a key cannot be constant- time -- the search for the primes takes as long as it takes -- but what that- leaks is about the search rather than about the primes it settles on, and- the haddock now says which is which- [#143](https://github.com/kazu-yamamoto/crypton/pull/143)-* perf(ecc): a ladder for the curves over a binary field. These were the last- multiplication whose cost followed the scalar: an affine double-and-add, one- addition for every bit that was set and none for the others, which on- sect283k1 ran from 9665 us for a scalar with two bits set to 17958 for one- with 270. It is now Montgomery's ladder, which carries the multiples of two- consecutive numbers -- their difference being the point is what lets it- carry only their x coordinates -- and spends one addition and one doubling- on every bit whichever way it goes, working the y out at the end from the- two x it is left with, so one division does for the whole multiplication- where the affine code had one per step. The multiplication is now flat, and- quicker: sect163k1 4428 to 3431 us, sect233r1 9304 to 6806, sect283k1 13797- to 10181, sect409k1 30826 to 20584, sect571r1 61931 to 40469. Uniform is- not constant time -- these are `Integer` operations, whose cost follows the- values -- and the point with no x, which is its own negation, keeps the code- that was there- [#142](https://github.com/kazu-yamamoto/crypton/pull/142)-* perf(ecc): multiply points in C on curves over a prime field. P-256 has had- a C implementation all along; every other prime curve -- P-384, P-521,- secp256k1 and the rest -- multiplied points with `Integer` arithmetic, which- cannot be constant time, since what an `Integer` operation costs follows the- value it is given. The C walks four bits of scalar at a time, taking the- multiple to add from a table of sixteen that it reads by touching every- entry and keeping one with a mask, and its addition and doubling are the- complete formulas of Renes, Costello and Batina, which answer for every pair- of points with no case to choose between. A P-384 multiplication goes from- 1557 to 585 us and no longer follows the scalar, ECDSA P-384 signing from- 1700 to 636 us, P-521 from 1942 to 1123. Binary curves are unchanged, and a- point that is not on the curve keeps the answer the Haskell gives it- [#141](https://github.com/kazu-yamamoto/crypton/pull/141)-* fix(ecc): add at every bit in the prime-curve multiplication, which laziness- was skipping. The multiplication adds at every bit, set or not, so that its- cost follows the width of the curve's order rather than the scalar -- but- the addition was a binding only one branch of the following `if` used, so at- a bit that was not set it stayed a thunk and was never worked out. The cost- followed the number of bits set in the scalar, which is the nonce when- signing and the private key in ECDH: on P-384, 765.8 us for a scalar with- two bits set against 1671.5 for one with 383, in a straight line between.- Both copies of the multiplication had it, so both elliptic curve APIs were- affected on every prime curve but P-256- [#140](https://github.com/kazu-yamamoto/crypton/pull/140)-* fix(ecdsa): keep the P-256 signature out of `Integer` arithmetic. The- scalar handed to the C implementation was reduced with `mod`, a division,- whose steps follow the number being divided -- the nonce when signing, the- private key in ECDH. Twice the order is more than 256 bits hold, so a- scalar that fits is brought under the order by one masked subtraction- instead. The second half of a signature, `kInv * (z + r * d)`, was- `Integer` arithmetic as well, and now goes through `scalarAdd` and- `scalarMul`, which on P-256 are the C implementation's fixed-width- arithmetic. What is left on that curve is the conversion between `Integer`- and fixed-width scalars, which is also what it costs: signing goes from 34.1- to 39.3 us, and ECDH and the other curves are unchanged- [#139](https://github.com/kazu-yamamoto/crypton/pull/139)-* fix(dsa,ecdsa): invert the signing nonce without a side channel. Both- inverted it with the extended Euclidean algorithm, whose step count and- branches follow the bits of what it is given -- and a handful of signatures- whose nonces are partly known give the private key away, so the nonce is- worth as much as the key. `Crypto.Number.ModArithmetic.inverseSafe` works- the inverse out with Fermat's little theorem through `expSafe` instead,- falling back on `inverse` when the modulus turns out not to be prime, so- every answer is the one it was. On P-256 the C implementation does it.- Signing costs a little more: ECDSA P-256 30.6 to 34.1 us, ECDSA P-384 678.7- to 703.4, DSA-2048 422.5 to 437.1. Verification inverts a value that- arrives in the signature and is left alone- [#138](https://github.com/kazu-yamamoto/crypton/pull/138)-* perf(number): square, and multiply, faster in `expSafe`. The product and- the Montgomery reduction are now a full product followed by a reduction- rather than interleaved, built out of one loop that takes its limbs eight at- a time, and squaring works out only the products on one side of the diagonal- and doubles their sum. At 2048 bits the constant-time exponentiation goes- from 3.59 to 2.15 ms, which is 1.4x GMP's own rather than 2.4x; RSA-2048- signing goes from 0.80 to 0.63 ms and DH-2048 `getShared` from 2.43 to 1.67- [#137](https://github.com/kazu-yamamoto/crypton/pull/137)-* fix(number): make `expSafe` hide the exponent again. It asked integer-gmp- for `powModSecInteger` and fell back on the ordinary `powModInteger` when- that was missing; since integer-gmp 1.1 it is always missing, so on every- GHC this package supports `expSafe` was the same windowed exponentiation as- `expFast`, table indexed by the exponent's bits, for RSA, DSA, DH, ElGamal- and Rabin alike. It now goes to C: four bits of exponent at a time, the- table of sixteen read by touching every entry and keeping one with a mask,- and a Montgomery multiplication whose final subtraction is masked too. The- exponent's length is still visible, rounded up to a whole 64-bit word, which- is what GMP's own `mpz_powm_sec` lets slip. Hiding the exponent costs 1.6x- at 512 bits and 2.4x at 2048: RSA-2048 signing goes from 0.46 to 0.80 ms and- DH-2048 `getShared` from 1.04 to 2.43- [#136](https://github.com/kazu-yamamoto/crypton/pull/136)-* perf(prime): stop running a Fermat test that Miller-Rabin subsumes. Every- candidate was tested to base 2 before the Miller-Rabin rounds, which begin- with the same base and prove more; the primes it passed paid for it twice- and the composites it caught were nearly all caught by trial division first.- RSA-2048 key generation goes from 55.0 to 32.8 ms- [#135](https://github.com/kazu-yamamoto/crypton/pull/135)-* perf(f2m): reduce the binary field by folding the top back in rather than- taking a step per bit of excess, square a byte at a time through a table of- the patterns a byte spreads into, and take four bits of a multiplier at a- time rather than one. On the 283-bit field, squaring goes from 5440 to 2068- ns and multiplication from 7526 to 4086. A scalar multiplication there is- still affine, so it inverts once per addition, which is where its time now- goes- [#134](https://github.com/kazu-yamamoto/crypton/pull/134)-* perf(ecc): fold instead of dividing in the generic prime-curve arithmetic,- and add the point being multiplied as the affine point it is. These primes- are `2^k - c` with `c` far smaller, so the top half of a product folds back- in with a shift, a multiplication and an addition, where dividing costs four- times as much -- above 256 bits, below which the folding costs more than it- saves. P-521 scalar multiplication goes from 892 to 492 us and P-384 from- 684 to 572- [#133](https://github.com/kazu-yamamoto/crypton/pull/133)-* perf(ecc): route P-256 through the C implementation the library already had.- `Crypto.PubKey.ECDSA` reached `cbits/p256`; `Crypto.PubKey.ECC.*`, the older- and more widely used API, never did. ECDSA signing goes from 590 to 28.7 us,- verification from 726 to 91.4, and `getShared` from 1177 to 96. On P-256- that multiplication is now constant time, where the generic code branches on- the scalar at every bit- [#132](https://github.com/kazu-yamamoto/crypton/pull/132)-* Breaking change: perf(camellia): put Camellia in C, 40 to 321 MiB/s. The- round function ran a byte at a time in Haskell; generating the tables that- take a byte straight to its contribution gained 14%, and the rest was the- language. Input that is not a whole number of blocks now raises, where the- tail of the answer used to be uninitialised memory- [#131](https://github.com/kazu-yamamoto/crypton/pull/131)-* Breaking change: perf(twofish): walk the blocks once and carry them in words- rather than appending each result to what came before and going through lists- per block. 2 MiB goes from 0.14 to 56 MiB/s, and the rate no longer falls as- the message grows. Input that is not a whole number of blocks now raises,- where it used to come back longer than it went in- [#130](https://github.com/kazu-yamamoto/crypton/pull/130)-* perf(modes): cut the message without copying the rest of it in the generic- block cipher modes, which every cipher but AES uses, and hand whole slices to- the cipher in the modes whose blocks do not depend on one another. Camellia- in CBC goes from 1.8 to 22.9 MiB/s at 1 MiB, DES CBC decryption from 0.5 to- 83, and every figure is now flat in the message length where it used to fall- [#129](https://github.com/kazu-yamamoto/crypton/pull/129)-* Breaking change: perf(des): put DES in C. It was carried over lists of- `Bool`, one cons cell per bit, with the key schedule recomputed for every- block: 0.04 MiB/s, and 3DES 0.013, against 105 and 41 for OpenSSL. They are- now 112 and 37. Input that is not a whole number of blocks now raises, where- the tail of the answer used to be uninitialised memory- [#128](https://github.com/kazu-yamamoto/crypton/pull/128)-* perf(cmac): slice the message rather than copying what is left of it once per- block, and chain through CBC, which is what CMAC's chaining is. A MAC over- 4 MiB goes from 0.36 to 1628 MiB/s, which is the speed of AES-CBC itself- [#127](https://github.com/kazu-yamamoto/crypton/pull/127)-* fix(rabin): decode OAEP without early exits, as- `Crypto.PubKey.RSA.OAEP.unpad` has since #91. The difference is not- measurable against the cost of mask generation, and is structural: the scan- across the padding no longer depends on the data- [#126](https://github.com/kazu-yamamoto/crypton/pull/126)-* Breaking change: fix(rabin): refuse a ciphertext or a signature that is not- below the modulus, and a ciphertext carrying a leading zero octet. Squaring- and the square roots that undo it work modulo n, so Basic and Rabin-Williams- decrypted `c + n` to whatever `c` decrypted to, and all three schemes verified- `s + n`, and `-s`, wherever they verified `s`. `Basic.signWith` also refuses a- padding whose first octet is zero, which the signature cannot carry: about one- signature in 256 was one its own `verify` rejected- [#125](https://github.com/kazu-yamamoto/crypton/pull/125)-* fix(prime): derive the Miller-Rabin witnesses from the number being tested and- from a secret drawn once per process. They came from one generator made once- and shared by every call, so the witnesses for one number were the witnesses- for every number, and testing a number again told the caller nothing it had- not already been told. This is the path every GHC since 9.0 takes, integer-gmp- 1.1 having no Miller-Rabin of its own- [#124](https://github.com/kazu-yamamoto/crypton/pull/124)-* docs(elgamal): say what `signWith` requires of its ephemeral value: the range- is 1 to p-2, not the "between 0 and p-1" the haddock claimed, and the value is- a private key that a signature discloses if it is reused or revealed- [#123](https://github.com/kazu-yamamoto/crypton/pull/123)-* Breaking change: fix(afis): give `split` and `merge` one answer for a parameter- they cannot use. They had four between them, including a division by zero for- an expand count of zero and, for a count of one, handing the diffused data back- as though it were the secret- [#122](https://github.com/kazu-yamamoto/crypton/pull/122)-* Breaking change: fix(rsa): refuse a ciphertext or a signature whose integer- representative is not below the modulus, which RFC 8017 requires in sections- 5.1.2 and 5.2.2. `PKCS15.decrypt` and `OAEP.decrypt` decrypted `c + n` to the- same message as `c`, and `PSS.verifyDigest` accepted `s + n` wherever it- accepted `s`- [#121](https://github.com/kazu-yamamoto/crypton/pull/121)-* fix(otp): search the HOTP resynchronization window without early exits. The- time taken read out both where in the window the client's counter was found- and how many of the submitted values were right -- the second of which the- answer itself does not give, being `Nothing` either way. A call now costs one- HMAC per counter in the window plus one per extra value, every time- [#120](https://github.com/kazu-yamamoto/crypton/pull/120)-* Breaking change: fix(kdf): report a refused parameter as a `CryptoError` rather- than as an `ErrorCall` carrying a string, with a `'`-suffixed variant of each- entry point returning `CryptoFailable`. PBKDF2 had no validation at all: a- negative output length reached `memSet` and killed the process with SIGBUS, and- an iteration count of zero returned 32 bytes of zeroes- [#119](https://github.com/kazu-yamamoto/crypton/pull/119)-* perf(xts): take eight blocks at a time on AArch64 and x86-64, and dispatch XTS- decryption through the branch table, which it had never used. AArch64 goes- from 1200 to 7742 MiB/s encrypting and 1166 to 7763 decrypting, x86-64 from- 1220 to 3464 and from 594 to 3461- [#118](https://github.com/kazu-yamamoto/crypton/pull/118)-* perf(poly1305): take four blocks at a time with AVX2 on x86-64, folding the- lanes back together weighted by the powers of r. 1347 to 4137 MiB/s- [#117](https://github.com/kazu-yamamoto/crypton/pull/117)-* perf(ecc): work in Jacobian coordinates in both generic prime-field scalar- multiplications, and say in `Crypto.ECC` which curves branch on a secret- scalar. P-384 and P-521 ECDSA are 2.3x: signing goes from 3.36 to 1.46 ms and- from 5.96 to 2.61 ms. P-256, which has its own C implementation, is unaffected- [#116](https://github.com/kazu-yamamoto/crypton/pull/116)-* Breaking change: fix(padding): bound PKCS#7 padding by the block rather than by- the whole input, which had let a block of sixteen accept a claim of twenty, and- refuse a `ZERO` size of zero rather than dividing by it. What `ZERO` can and- cannot undo is now written down- [#115](https://github.com/kazu-yamamoto/crypton/pull/115)-* perf(gcm): give x86 its own GCM decryption loop. It fell to the generic one,- which calls the block function once per block, and ran at a quarter the speed- of encryption; both directions now take eight blocks at a time and fold their- GHASH into one reduction. AES-256-GCM decryption goes from 561 to 2733 MiB/s- and AES-128 from 667 to 3150- [#114](https://github.com/kazu-yamamoto/crypton/pull/114)-* perf(chacha): take eight blocks at a time with AVX2 where the machine has it,- with the cpuid and XGETBV checks that decide. ChaCha20 on x86-64 goes from- 900 to 2074 MiB/s- [#113](https://github.com/kazu-yamamoto/crypton/pull/113)-* perf(chacha): do four blocks at a time with SSE2 on x86-64, where the cipher- had no vector code at all. ChaCha20 goes from 493 to 900 MiB/s- [#112](https://github.com/kazu-yamamoto/crypton/pull/112)-* perf(chacha): do four blocks at a time with NEON on AArch64. ChaCha20 goes- from 1025 to 1955 MiB/s- [#111](https://github.com/kazu-yamamoto/crypton/pull/111)-* feat(sha512): use the ARMv8.2 SHA-512 instructions on AArch64, which SHA-384- and the truncated SHA-512/t variants share. Hashing 1 MiB goes from 1.53 ms- to 597 us. The extension is optional, so it is asked for at runtime on both- Apple and Linux rather than assumed- [#110](https://github.com/kazu-yamamoto/crypton/pull/110)-* perf(gcm): drive GCM from AArch64 rather than the generic loop, with a group- of eight blocks folding into a single GHASH reduction. AES-128-GCM goes from- 4030 to 8266 MiB/s and AES-256 from 4043 to 7172- [#109](https://github.com/kazu-yamamoto/crypton/pull/109)-* perf(aes): specialise the AArch64 code by key size and interleave eight- blocks, and give CTR its own loop. AES-256 ECB goes from 3886 to 15991- MiB/s, CTR from 2935 to 13567 and CBC decryption from 4366 to 15807- [#108](https://github.com/kazu-yamamoto/crypton/pull/108)--* perf(aes): build the AES-NI paths on Windows, which was missing from the list of- systems that compile them. Windows builds have been doing AES, and GHASH with it,- in the generic C- [#107](https://github.com/kazu-yamamoto/crypton/pull/107)-* fix(armv8): compile the AArch64 sources on a toolchain whose baseline lacks the- crypto extensions. They had not built with GCC on AArch64 Linux since #100; CI now- builds and tests there- [#106](https://github.com/kazu-yamamoto/crypton/pull/106)-* perf(gcm): fold four GHASH blocks into one reduction. AES-256-GCM is 1.6x at 1 KiB- and 2.6x at 64 KiB on Apple silicon, and the x86 paths gain the same structure- [#105](https://github.com/kazu-yamamoto/crypton/pull/105)-* perf(sha256): use the ARMv8 SHA-2 instructions on AArch64. SHA-256 and SHA-224 are- 5.5x- [#104](https://github.com/kazu-yamamoto/crypton/pull/104)-* ci: keep the macOS jobs from queueing behind each other, and supersede a branch's- earlier run- [#103](https://github.com/kazu-yamamoto/crypton/pull/103)-* perf(aes): use PMULL for GHASH on AArch64- [#102](https://github.com/kazu-yamamoto/crypton/pull/102)-* ci: ask cabal where its caches live rather than assuming, and keep the build- products in the cache- [#101](https://github.com/kazu-yamamoto/crypton/pull/101)-* perf(aes): use the ARMv8 cryptographic extensions on AArch64. With the GHASH work- in #102 and #105, AES-256-ECB goes from 121 to 2992 MiB/s and AES-256-GCM from 92 to- 2318 MiB/s on Apple silicon- [#100](https://github.com/kazu-yamamoto/crypton/pull/100)-* build(bench): move the benchmarks from gauge, which is no longer maintained, to- tasty-bench, and let them resolve on a current GHC- [#99](https://github.com/kazu-yamamoto/crypton/pull/99)-* Breaking change: fix(padding): reject a `PKCS7` block size outside 1..255. `pad`- raises and `unpad` returns `Nothing`, where both previously narrowed the size to a- `Word8` and silently agreed on the wrong value- [#98](https://github.com/kazu-yamamoto/crypton/pull/98)-* feat(elgamal): fix `Crypto.PubKey.ElGamal` and expose it- [#97](https://github.com/kazu-yamamoto/crypton/pull/97)-* docs(bcrypt): say that only the first 72 bytes of a password count- [#96](https://github.com/kazu-yamamoto/crypton/pull/96)-* test: move the test suite from tasty to hspec, with hspec-discover. `cabal-version`- is now 2.0- [#95](https://github.com/kazu-yamamoto/crypton/pull/95)--* feat(aead): add `tryAeadSimpleDecrypt`, which takes the tag length as its own argument instead of reading it off the supplied tag- [#94](https://github.com/kazu-yamamoto/crypton/pull/94)-* Breaking change: feat(dh): add `tryGetShared` to `Crypto.PubKey.DH` and `Crypto.PubKey.ECC.DH`, reporting a rejected peer value as `CryptoFailable`; `getShared` is now defined in terms of it and so raises a `CryptoError` rather than an `ErrorCall`- [#93](https://github.com/kazu-yamamoto/crypton/pull/93)-* fix(otp): compare TOTP candidates without an early exit- [#92](https://github.com/kazu-yamamoto/crypton/pull/92)-* fix(rsa): drop the early exits from PKCS#1 v1.5 and OAEP unpadding- [#91](https://github.com/kazu-yamamoto/crypton/pull/91)-* Breaking change: fix(argon2): report invalid options as `CryptoFailed` rather than raising, adding `CryptoError_ParameterInvalid` to `CryptoError`- [#90](https://github.com/kazu-yamamoto/crypton/pull/90)-* Breaking change: fix(dh): validate the peer public number, and size the shared secret from `p` rather than `params_bits`- [#89](https://github.com/kazu-yamamoto/crypton/pull/89)-* fix(dsa): do not crash on values that are not invertible modulo `q`- [#88](https://github.com/kazu-yamamoto/crypton/pull/88)-* Breaking change: fix(ecdh): validate the peer point before the exchange- [#87](https://github.com/kazu-yamamoto/crypton/pull/87)-* Breaking change: fix(pkcs15): reject PKCS#1 v1.5 signatures of the wrong length or out of range- [#86](https://github.com/kazu-yamamoto/crypton/pull/86)-* Breaking change: fix(otp): require a digest long enough for RFC 4226 dynamic truncation, which was reading past the end of the MAC- [#85](https://github.com/kazu-yamamoto/crypton/pull/85)-* fix(ecc): accept zero-x P-256 shared secret- [#84](https://github.com/kazu-yamamoto/crypton/pull/84)-* fix(p256): accept valid edge-case points- [#83](https://github.com/kazu-yamamoto/crypton/pull/83)-* Breaking change: fix(hkdf): enforce output length limit- [#82](https://github.com/kazu-yamamoto/crypton/pull/82)-* Breaking change: fix(ed25519): reject non-canonical signatures- [#81](https://github.com/kazu-yamamoto/crypton/pull/81)-* Support GHC 9.14; `tested-with` now covers 9.10.2, 9.12.4 and 9.14.1- [#74](https://github.com/kazu-yamamoto/crypton/pull/74)--### API changes--* New exports: `Crypto.OTP.minimumDigestSize`, `Crypto.PubKey.DH.tryGetShared`,- `Crypto.PubKey.ECC.DH.tryGetShared`, `Crypto.Cipher.Types.AEAD.tryAeadSimpleDecrypt`,- `Crypto.Number.ModArithmetic.inverseSafe`, `Crypto.PubKey.ECC.Prim.scalarInverse`,- `scalarAdd` and `scalarMul`, `Crypto.PubKey.ECC.P256.scalarReduce`,- and the whole of `Crypto.PubKey.ElGamal`, which was present but not exposed.- The variant of an entry point that reports a refusal rather than raising is- named `try` followed by the name it varies, `tryExpand` beside `expand`. A- trailing apostrophe was the obvious spelling and is what these were called- until shortly before release; it collides too easily, since a caller that- imports one of these modules unqualified and has its own `expand'` or- `split'` no longer compiles, and `tls` did. `Safe` was considered and set- aside: this library already uses that suffix for something else, in- `Crypto.Number.ModArithmetic.expSafe` and `inverseSafe` and in- `Crypto.PubKey.ECC.P256.scalarInvSafe`, where it means the value being- worked on stays out of the timing.- The KDFs gained a variant of each entry point that can refuse its parameters,- returning `CryptoFailable` instead of raising: `Crypto.KDF.Scrypt.tryGenerate`,- `Crypto.KDF.BCrypt.tryBcrypt`, `Crypto.KDF.BCryptPBKDF.tryGenerate` and- `tryHashInternal`, `Crypto.KDF.HKDF.tryExpand`, `Crypto.KDF.PBKDF2.tryGenerate` and- `tryFastPBKDF2_SHA1`, `tryFastPBKDF2_SHA256` and `tryFastPBKDF2_SHA512`, and- `Crypto.Data.AFIS.trySplit` and `tryMerge`. These are additions and break nothing.-* Breaking change: `CryptoError_ParameterInvalid` is added to `CryptoError`. It is- appended, so the `Enum` values of the existing constructors are unchanged, but an- exhaustive `case` without a wildcard will warn. Adding a constructor to an exported- datatype is what requires a major version bump under the PVP, which would have been- 1.2.0; this release goes to 2.0.0. Everything else below changes behaviour rather- than types.-* Breaking change: `getShared` in both DH modules raises a `CryptoError` where it- previously raised an `ErrorCall`, since it is now defined in terms of `tryGetShared`.- The same is now true of `Crypto.KDF.Scrypt.generate`, `Crypto.KDF.BCrypt.bcrypt`,- `Crypto.KDF.BCryptPBKDF.generate` and `hashInternal`, and `Crypto.Data.AFIS.split`- and `merge`, each of which is defined in terms of the variant above.-* Breaking change: input that used to be accepted is now rejected -- a digest shorter- than 20 bytes in `Crypto.OTP.hotp`, a signature of the wrong length or out of range- in `Crypto.PubKey.RSA.PKCS15.verify`, an off-curve peer point or a peer public number- outside `1 < y < p-1` in `getShared`, an output beyond 255 blocks in- `Crypto.KDF.HKDF.expand`, a non-canonical Ed25519 signature, and `Options` the- implementation refuses in `Crypto.KDF.Argon2.hash`.-* Breaking change: a value at or above the modulus is now rejected where it used to be- reduced and accepted -- a ciphertext in `Crypto.PubKey.RSA.PKCS15.decrypt` and- `Crypto.PubKey.RSA.OAEP.decrypt`, a signature in `Crypto.PubKey.RSA.PSS.verify`, and- both, along with a negated signature and a ciphertext with a leading zero octet, in- the three `Crypto.PubKey.Rabin.*` schemes.-* Breaking change: parameters that used to be accepted are now refused -- an iteration- count below one or a negative output length in `Crypto.KDF.PBKDF2`, an expand count- below two or a secret of no bytes in `Crypto.Data.AFIS`, a `PKCS7` claim longer than- the block and a `ZERO` size of zero in `Crypto.Data.Padding`, and a signature padding- whose first octet is zero in `Crypto.PubKey.Rabin.Basic.signWith`.-* Breaking change: DES, 3DES, Twofish and Camellia now raise on input that is not a- whole number of blocks, as AES already did. Before, DES and Camellia returned an- answer whose tail was never written -- uninitialised memory -- and Twofish returned- more than it was given, the missing bytes read as zero.-* Breaking change: `Crypto.Data.Padding.pad` raises on a `PKCS7` block size outside- 1..255, and `unpad` returns `Nothing` for one, where both used to narrow the size to- a `Word8` and hand back something other than what was padded.-* No exported function changed its signature.--## 1.1.5--* fix(aead): reject undersized tags- [#80](https://github.com/kazu-yamamoto/crypton/pull/80)-* fix(aes): refuse a zero-length AES-GCM IV- [#79](https://github.com/kazu-yamamoto/crypton/pull/79)-* fix(p256): prevent crashes when validating valid points- [#78](https://github.com/kazu-yamamoto/crypton/pull/78)-* feat(asn1): add SHA-3 HashAlgorithmASN1 instances for PKCS#1 v1.5- [#77](https://github.com/kazu-yamamoto/crypton/pull/77)-* OCB3 conformance- [#76](https://github.com/kazu-yamamoto/crypton/pull/76)--## 1.1.4--* Generic instance for RSA PublicKey and PrivateKey--## 1.1.3--* Ensure that `pointAdd` in `PubKey.ECC.P256` treats the point at infinity as the additive identity.- [#73](https://github.com/kazu-yamamoto/crypton/pull/73)--## 1.1.2--* Preparing `ram` v0.22.-* Generalizing RSA encrypt/decrypt to manipulate ScrubbedBytes directly.--## 1.1.1--* On iOS, ScrubbedBytes based hashing is used for seedNew. On other- plateforms, entropy is used directly as used to be.- [#71](https://github.com/kazu-yamamoto/crypton/pull/71)--## 1.1.0--* Removing "basement" and "memory".- [#67](https://github.com/kazu-yamamoto/crypton/pull/67)---## 1.0.7--* Stop depending on basement, use upstream dependencies instead-* Stop transitively depending on basement by depending on ram.--## 1.0.6--* Fix test failures on less common 64-bit arches.- [#65](https://github.com/kazu-yamamoto/crypton/pull/65)--## 1.0.5--* Setter/Getter for ChaCha counter.- [#63](https://github.com/kazu-yamamoto/crypton/pull/63)-* Add simple interface to generate full blocks- [#60](https://github.com/kazu-yamamoto/crypton/pull/60)-* Avoid `ghc-prim` dependency.- [#61](https://github.com/kazu-yamamoto/crypton/pull/61)--## 1.0.4--* Ed448.sign: avoid extra re-derive of public key.- [#48](https://github.com/kazu-yamamoto/crypton/pull/48)--## 1.0.3--* Make sign of Ed25519/Ed448 safer. The public key parameter is- ignored and its public key is generated from the secret key- parameter to prevent Double Public Key Signing Function Oracle- Attack.- [#47](https://github.com/kazu-yamamoto/crypton/pull/47)--## 1.0.2--* Deterministic Nonce Generation for ECDSA- [#46](https://github.com/kazu-yamamoto/crypton/pull/46)-* ECDSA Signature Normalization.- [#45](https://github.com/kazu-yamamoto/crypton/pull/45)-* Add Full Test Suite from RFC 6979.- [#44](https://github.com/kazu-yamamoto/crypton/pull/44)-* ECDSA with Public Key Recovery.- [#43](https://github.com/kazu-yamamoto/crypton/pull/43)-* Providing necessary features for HPKE.- [#42](https://github.com/kazu-yamamoto/crypton/pull/42)--## 1.0.1--* Update decaf library.- [#38](https://github.com/kazu-yamamoto/crypton/pull/38)-* Add TypeOperators language extension to EdDSA.hs.- [#36](https://github.com/kazu-yamamoto/crypton/pull/36)--## 1.0.0--* Versions follow the standard version policy.-* Removing pthread stuff.- [#32](https://github.com/kazu-yamamoto/crypton/pull/32)--## 0.34--* Hashing getRandomBytes before using as Seed for ChaChaDRG- [#24](https://github.com/kazu-yamamoto/crypton/pull/24)-* Add support for XChaCha and XChaChaPoly1305- [#18](https://github.com/kazu-yamamoto/crypton/pull/18)-* Strict byteArray of IV c- [#16](https://github.com/kazu-yamamoto/crypton/pull/16)--## 0.33--* Add "crypton_" prefix to the final C symbols.- [#9](https://github.com/kazu-yamamoto/crypton/pull/9)--## 0.32--* All C symbols now have the "crypton_" prefix.- [#7](https://github.com/kazu-yamamoto/crypton/pull/7)- [#8](https://github.com/kazu-yamamoto/crypton/pull/8)--## 0.31--* Crypton is forked from cryptonite with the original authors permission.-* Ignoring exceptons from hClose to read the next entropy- [#1](https://github.com/kazu-yamamoto/crypton/pull/1)-* Enabling the support_pclmuldq flag by default.--## 0.30--* Fix some C symbol blake2b prefix to be cryptonite_ prefix (fix mixing with other C library)-* add hmac-lazy-* Fix compilation with GHC 9.2-* Drop support for GHC8.0, GHC8.2, GHC8.4, GHC8.6--## 0.29--* advance compilation with gmp breakage due to change upstream-* Add native EdDSA support--## 0.28--* Add hash constant time capability-* Prevent possible overflow during hashing by hashing in 4GB chunks--## 0.27--* Optimise AES GCM and CCM-* Optimise P256R1 implementation-* Various AES-NI building improvements-* Add better ECDSA support-* Add XSalsa derive-* Implement square roots for ECC binary curve-* Various tests and benchmarks--## 0.26--* Add Rabin cryptosystem (and variants)-* Add bcrypt_pbkdf key derivation function-* Optimize Blowfish implementation-* Add KMAC (Keccak Message Authentication Code)-* Add ECDSA sign/verify digest APIs-* Hash algorithms with runtime output length-* Update blake2 to latest upstream version-* RSA-PSS with arbitrary key size-* SHAKE with output length not divisible by 8-* Add Read and Data instances for Digest type-* Improve P256 scalar primitives-* Fix hash truncation bug in DSA-* Fix cost parsing for bcrypt-* Fix ECC failures on arm64-* Correction to PKCS#1 v1.5 padding-* Use powModSecInteger when available-* Drop GHC 7.8 and GHC 7.10 support, refer to pkg-guidelines-* Optimise GCM mode-* Add little endian serialization of integer--## 0.25--* Improve digest binary conversion efficiency-* AES CCM support-* Add MonadFailure instance for CryptoFailable-* Various misc improvements on documentation-* Edwards25519 lowlevel arithmetic support-* P256 add point negation-* Improvement in ECC (benchmark, better normalization)-* Blake2 improvements to context size-* Use gauge instead of criterion-* Use haskell-ci for CI scripts-* Improve Digest memory representation to be 2 less Ints and one less boxing- moving from `UArray` to `Block`--## 0.24--* Ed25519: generateSecret & Documentation updates-* Repair tutorial-* RSA: Allow signing digest directly-* IV add: fix overflow behavior-* P256: validate point when decoding-* Compilation fix with deepseq disabled-* Improve Curve448 and use decaf for Ed448-* Compilation flag blake2 sse merged in sse support-* Process unaligned data better in hashes and AES, on architecture needing alignment-* Drop support for ghc 7.6-* Add ability to create random generator Seed from binary data and- loosen constraint on ChaChaDRG seed from ByteArray to ByteArrayAccess.-* Add 3 associated types with the HashAlgorithm class, to get- access to the constant for BlockSize, DigestSize and ContextSize at the type level.- the related function that this replaced will be deprecated in later release, and- eventually removed.--API CHANGES:--* Improve ECDH safety to return failure for bad inputs (e.g. public point in small order subgroup).- To go back to previous behavior you can replace `ecdh` by `ecdhRaw`. It's recommended to- use `ecdh` and handle the error appropriately.-* Users defining their own HashAlgorithm needs to define the- HashBlockSize, HashDigest, HashInternalContextSize associated types--## 0.23--* Digest memory usage improvement by using unpinned memory-* Fix generateBetween to generate within the right bounds-* Add pure Twofish implementation-* Fix memory allocation in P256 when using a temp point-* Consolidate hash benchmark code-* Add Nat-length Blake2 support (GHC > 8.0)-* Update tutorial--## 0.22--* Add Argon2 (Password Hashing Competition winner) hash function-* Update blake2 to latest upstream version-* Add extra blake2 hashing size-* Add faster PBKDF2 functions for SHA1/SHA256/SHA512-* Add SHAKE128 and SHAKE256-* Cleanup prime generation, and add tests-* Add Time-based One Time Password (TOTP) and HMAC-based One Time Password (HOTP)-* Rename Ed448 module name to Curve448, old module name still valid for now--## 0.21--* Drop automated tests with GHC 7.0, GHC 7.4, GHC 7.6. support dropped, but probably still working.-* Improve non-aligned support in C sources, ChaCha and SHA3 now probably work on arch without support for unaligned access. not complete or tested.-* Add another ECC framework that is more flexible, allowing different implementations to work instead of- the existing Pure haskell NIST implementation.-* Add ECIES basic primitives-* Add XSalsa20 stream cipher-* Process partial buffer correctly with Poly1305--## 0.20--* Fixed hash truncation used in ECDSA signature & verification (Olivier Chéron)-* Fix ECDH when scalar and coordinate bit sizes differ (Olivier Chéron)-* Speed up ECDSA verification using Shamir's trick (Olivier Chéron)-* Fix rdrand on windows--## 0.19--* Add tutorial (Yann Esposito)-* Derive Show instance for better interaction with Show pretty printer (Eric Mertens)--## 0.18--* Re-used standard rdrand instructions instead of bytedump of rdrand instruction-* Improvement to F2m, including lots of tests (Andrew Lelechenko)-* Add error check on salt length in bcrypt--## 0.17--* Add Miyaguchi-Preneel construction (Kei Hibino)-* Fix buffer length in scrypt (Luke Taylor)-* build fixes for i686 and arm related to rdrand--## 0.16--* Fix basepoint for Ed448--* Enable 64-bit Curve25519 implementation--## 0.15--* Fix serialization of DH and ECDH--## 0.14--* Reduce size of SHA3 context instead of allocating all-size fit memory. save- up to 72 bytes of memory per context for SHA3-512.-* Add a Seed capability to the main DRG, to be able to debug/reproduce randomized program- where you would want to disable the randomness.-* Add support for Cipher-based Message Authentication Code (CMAC) (Kei Hibino)-* *CHANGE* Change the `SharedKey` for `Crypto.PubKey.DH` and `Crypto.PubKey.ECC.DH`,- from an Integer newtype to a ScrubbedBytes newtype. Prevent mistake where the- bytes representation is generated without the right padding (when needed).-* *CHANGE* Keep The field size in bits, in the `Params` in `Crypto.PubKey.DH`,- moving from 2 elements to 3 elements in the structure.--## 0.13--* *SECURITY* Fix buffer overflow issue in SHA384, copying 16 extra bytes from- the SHA512 context to the destination memory pointer leading to memory- corruption, segfault. (Mikael Bung)--## 0.12--* Fix compilation issue with Ed448 on 32 bits machine.--## 0.11--* Truncate hashing correctly for DSA-* Add support for HKDF (RFC 5869)-* Add support for Ed448-* Extends support for Blake2s to 224 bits version.-* Compilation workaround for old distribution (RHEL 4.1)-* Compilation fix for AIX-* Compilation fix with AESNI and ghci compiling C source in a weird order.-* Fix example compilation, typo, and warning--## 0.10--* Add reference implementation of blake2 for non-SSE2 platform-* Add support\_blake2\_sse flag--## 0.9--* Quiet down unused module imports-* Move Curve25519 over to Crypto.Error instead of using Either String.-* Add documentation for ChaChaPoly1305-* Add missing documentation for various modules-* Add a way to create Poly1305 Auth tag.-* Added support for the BLAKE2 family of hash algorithms-* Fix endianness of incrementNonce function for ChaChaPoly1305--## 0.8--* Add support for ChaChaPoly1305 Nonce Increment (John Galt)-* Move repository to the haskell-crypto organisation--## 0.7--* Add PKCS5 / PKCS7 padding and unpadding methods-* Fix ChaChaPoly1305 Decryption-* Add support for BCrypt (Luke Taylor)--## 0.6--* Add ChaChaPoly1305 AE cipher-* Add instructions in README for building on old OSX-* Fix blocking /dev/random Andrey Sverdlichenko--## 0.5--* Fix all strays exports to all be under the cryptonite prefix.--## 0.4--* Add a System DRG that represent a referentially transparent of evaluated bytes- while using lazy evaluation for future entropy values.--## 0.3--* Allow drgNew to run in any MonadRandom, providing cascading initialization-* Remove Crypto.PubKey.HashDescr in favor of just having the algorithm- specified in PKCS15 RSA function.-* Fix documentation in cipher sub section (Luke Taylor)-* Cleanup AES dead functions (Luke Taylor)-* Fix Show instance of Digest to display without quotes similar to cryptohash-* Use scrubbed bytes instead of bytes for P256 scalar--## 0.2--* Fix P256 compilation and exactness, + add tests-* Add a raw memory number serialization capability (i2osp, os2ip)-* Improve tests for number serialization-* Improve tests for ECC arithmetics-* Add Ord instance for Digest (Nicolas Di Prima)-* Fix entropy compilation on windows 64 bits.--## 0.1--* Initial release+## 2.2.5++**RSA private-key operations check their CRT result.** A fault in one+half of the computation could hand out a signature that reveals a prime of+the key; the result is now raised back to the public exponent first, as+OpenSSL does, at a cost of two or three per cent on signing.++* perf(rsa): verification in C at every RSA size on Apple AArch64+ [#340](https://github.com/kazu-yamamoto/crypton/pull/340)+* perf(rsa): a generated squaring at 48 limbs on AArch64+ [#341](https://github.com/kazu-yamamoto/crypton/pull/341)+* perf(rsa): verification without lists or Integer round trips+ [#342](https://github.com/kazu-yamamoto/crypton/pull/342)+* ci: time out instead of waiting on a stalled package mirror+ [#343](https://github.com/kazu-yamamoto/crypton/pull/343)+* fix(rsa): check the CRT result before letting it out+ [#344](https://github.com/kazu-yamamoto/crypton/pull/344)+* perf(hash): one context for a one-shot hash and for MGF1+ [#345](https://github.com/kazu-yamamoto/crypton/pull/345)+* perf(rsa): RSA-3072's 24-limb square from 8-limb pieces on x86-64+ [#346](https://github.com/kazu-yamamoto/crypton/pull/346)++## 2.2.4++**New module `Crypto.PubKey.RSA.Blinded`.** A `BlindedKey` carries RSA+blinding from one signature or decryption to the next. The existing+`*Safer` functions use it through a small process-wide table, and+verification keeps R^2 per modulus in another.++* perf(rsa): keep the blinding between operations+ [#335](https://github.com/kazu-yamamoto/crypton/pull/335)+* perf(rsa): a generated Montgomery multiplication for AArch64+ [#336](https://github.com/kazu-yamamoto/crypton/pull/336)+* fix: the C warnings CI reports+ [#337](https://github.com/kazu-yamamoto/crypton/pull/337)+* perf(rsa): both CRT halves at once with AVX-512 IFMA+ [#338](https://github.com/kazu-yamamoto/crypton/pull/338)+* perf(rsa): keep R^2 per modulus for verification+ [#339](https://github.com/kazu-yamamoto/crypton/pull/339)++## 2.2.3++**crypton builds on Windows again.** 2.2.2's tarball lacked a header that+only Windows includes, so it built from git but not from Hackage. With+2.2.2, `-f-support_s2n_bignum` works around it.++* bench: RSA-3072 in the tables+ [#331](https://github.com/kazu-yamamoto/crypton/pull/331)+* perf(rsa): a generated Montgomery squaring for AArch64+ [#333](https://github.com/kazu-yamamoto/crypton/pull/333)+* fix: ship the Windows wrapper for s2n-bignum+ [#334](https://github.com/kazu-yamamoto/crypton/pull/334)++## 2.2.2++**crypton builds on an Intel Mac again.** From 2.1.2 onwards, Apple's+assembler rejected one of the vendored RSA assembly files, so the default+configuration did not build on x86-64 macOS. With an older release,+`-f-support_s2n_bignum` works around it.++* doc: the Ed25519 verify step was the AVX2 flag, and the tables move to 2.2.1+ [#318](https://github.com/kazu-yamamoto/crypton/pull/318)+* test: the window the exponentiation walks in, and the macro that hid it+ [#319](https://github.com/kazu-yamamoto/crypton/pull/319)+* perf: the Montgomery constant in assembly, on both architectures+ [#320](https://github.com/kazu-yamamoto/crypton/pull/320)+* perf: verification need not hide an exponent that is public+ [#321](https://github.com/kazu-yamamoto/crypton/pull/321)+* doc: the generic AArch64 routines, measured at last+ [#322](https://github.com/kazu-yamamoto/crypton/pull/322)+* doc: a VM's CPUID is not the hardware: two descriptions that said otherwise+ [#323](https://github.com/kazu-yamamoto/crypton/pull/323)+* test: switches to assume what CPUID hides, for testing only+ [#324](https://github.com/kazu-yamamoto/crypton/pull/324)+* perf: RSA-3072's halves through s2n-bignum on x86-64+ [#325](https://github.com/kazu-yamamoto/crypton/pull/325)+* perf: 3072- and 4096-bit secure exponentiation through s2n-bignum+ [#326](https://github.com/kazu-yamamoto/crypton/pull/326)+* test: the two AES differential tests, in CI+ [#327](https://github.com/kazu-yamamoto/crypton/pull/327)+* perf: s2n-bignum on x86-64 Windows+ [#328](https://github.com/kazu-yamamoto/crypton/pull/328)+* fix: crypton builds on an Intel Mac again+ [#329](https://github.com/kazu-yamamoto/crypton/pull/329)+* ci: link with the Command Line Tools on macOS+ [#330](https://github.com/kazu-yamamoto/crypton/pull/330)++## 2.2.1++**A binary built on one x86-64 machine runs on another again.** Since+2.1.8 the `-mavx2 -mbmi2` written for the ML-KEM and ML-DSA backends have+been compiling every C file in the library -- `cc-options` in a conditional+block belong to the component, not to the block -- so the compiler put AVX2+and BMI2 into ordinary code that has no dispatch and asks nothing at+runtime: Ed25519, Argon2, Curve25519, P-256, Ed448, and the older hashes+among them. A binary built where AVX2 exists then died with `SIGILL` where+it does not, in Ed25519 rather than in anything post-quantum.++The two backends also chose their implementation when the library was+compiled and called it unchecked. They ask the processor now, as everything+else in crypton that uses an instruction beyond the baseline already did,+and fall back to the portable C where the answer is no. AArch64 asks about+the ARMv8.4 Keccak instructions for the same reason.++Nothing in the API changes.++* fix: stop raising the x86-64 baseline for the whole library+ [#317](https://github.com/kazu-yamamoto/crypton/pull/317)+* fix: ask the processor before using the ML-KEM and ML-DSA backends+ [#317](https://github.com/kazu-yamamoto/crypton/pull/317)+* test(ct): link the processor check into the ML-KEM backend build+ [#317](https://github.com/kazu-yamamoto/crypton/pull/317)++## 2.2.0++`ProcessorOption` is no longer a sum of constructors. It is a number with+pattern synonyms for the names it knows, so it has `Ord` now and has lost+`Enum` and `Data`, and a `case` over the names needs a catch-all. `RDRAND`+is gone from it, and with it the `support_rdrand` flag. An AArch64 machine+reports `ARMAES` and `ARMPMULL` where it used to report `AESNI` and `PCLMUL`.++Two more things change under a caller without the type checker saying so:+`MonadRandom IO` draws from a per-thread generator rather than reading the+system on every call, and a missing or failing entropy source raises+`EntropyError` rather than an `ErrorCall` or an `IOException`.++* feat: take entropy from the kernel without a file descriptor+ [#300](https://github.com/kazu-yamamoto/crypton/pull/300)+* feat: a ChaCha20 generator per operating system thread+ [#300](https://github.com/kazu-yamamoto/crypton/pull/300)+* feat: MonadRandom IO goes through the per-thread generator+ [#300](https://github.com/kazu-yamamoto/crypton/pull/300)+* fix: say that the system gave no entropy, rather than error+ [#300](https://github.com/kazu-yamamoto/crypton/pull/300)+* fix: stop using RDRAND at all, since it cannot add anything+ [#300](https://github.com/kazu-yamamoto/crypton/pull/300)+* feat: name every processor feature crypton dispatches on, not three of them+ [#302](https://github.com/kazu-yamamoto/crypton/pull/302)+* fix: an AArch64 machine no longer reports AESNI and PCLMUL+ [#302](https://github.com/kazu-yamamoto/crypton/pull/302)+* chore(rsa): deprecate `sign`, `signSafer` and `verify` in favour of them+ [#305](https://github.com/kazu-yamamoto/crypton/pull/305)+* fix: compute the portable AES and GHASH without a table+ [#308](https://github.com/kazu-yamamoto/crypton/pull/308)+* feat: use the AES instructions on 32-bit ARM+ [#309](https://github.com/kazu-yamamoto/crypton/pull/309)+* test: skip the accelerated constant-time driver where the processor has no instructions+ [#310](https://github.com/kazu-yamamoto/crypton/pull/310)+* feat: use the POWER8 AES and GHASH instructions on ppc64le+ [#311](https://github.com/kazu-yamamoto/crypton/pull/311)+* test: the big-endian harness now asks about AES+ [#312](https://github.com/kazu-yamamoto/crypton/pull/312)+* doc(tutorial): compile the examples, and teach the things people come for+ [#313](https://github.com/kazu-yamamoto/crypton/pull/313)++## 2.1.10++* build: ask the processor for AES-NI on every x86 system, not four of them+ [#307](https://github.com/kazu-yamamoto/crypton/pull/307)+* fix: ask one place which ARMv8 instruction sets the machine has+ [#307](https://github.com/kazu-yamamoto/crypton/pull/307)++## 2.1.9++* feat(rsa): PKCS#1 v1.5 operations that take a digest, and ones that take a DigestInfo+ [#305](https://github.com/kazu-yamamoto/crypton/pull/305)+* feat(dsa): sign and verify over a digest+ [#305](https://github.com/kazu-yamamoto/crypton/pull/305)+* feat(elgamal): sign and verify over a digest+ [#305](https://github.com/kazu-yamamoto/crypton/pull/305)+* feat(rabin): Rabin-Williams and Modified Rabin sign and verify over a digest+ [#305](https://github.com/kazu-yamamoto/crypton/pull/305)++## 2.1.8++* chore: stop hiding foldl' from Prelude+ [#294](https://github.com/kazu-yamamoto/crypton/pull/294)+* chore: ask for hidden visibility only where the format has it+ [#295](https://github.com/kazu-yamamoto/crypton/pull/295)+* feat: ML-KEM and ML-DSA, through mlkem-native and mldsa-native+ [#297](https://github.com/kazu-yamamoto/crypton/pull/297)++## 2.1.7++RSA-PSS verification was accepting an encoding RFC 8017 says to refuse. It+is a conformance fault rather than a forgery: producing such a signature takes+the private key, so a third party holding a valid signature cannot turn it+into one of these.++* chore(p256): drop two declarations nothing defines+ [#292](https://github.com/kazu-yamamoto/crypton/pull/292)+* fix(pss): refuse an encoding with a bit set outside emBits+ [#293](https://github.com/kazu-yamamoto/crypton/pull/293)++## 2.1.6++The `license:` field now says what the tree holds -- `BSD-3-Clause AND MIT+AND ISC` -- and `license-files:` lists all five texts. **Nothing is required+of a user that was not required before**; the field was simply incomplete.++* Carry the MIT notice for the parts that follow fusion, and say what the tree holds+ [#267](https://github.com/kazu-yamamoto/crypton/pull/267)+* fix: two preconditions the Haskell layer did not enforce+ [#288](https://github.com/kazu-yamamoto/crypton/pull/288)+* fix(x86): stop casting a packed block to __m128i *+ [#289](https://github.com/kazu-yamamoto/crypton/pull/289)+* fix(c): say that the digest pointers are never null+ [#290](https://github.com/kazu-yamamoto/crypton/pull/290)+* fix(pbkdf2): refuse a digest larger than its block at compile time+ [#291](https://github.com/kazu-yamamoto/crypton/pull/291)++## 2.1.5++2.1.3 and 2.1.4 cannot be built with GCC 14 or newer. This release is+that fix.++* Watch for a primitive fallen off its fast path+ [#277](https://github.com/kazu-yamamoto/crypton/pull/277)+* The performance tables for 2.1.4+ [#278](https://github.com/kazu-yamamoto/crypton/pull/278)+* The x86-64 table, on the machine the README names+ [#279](https://github.com/kazu-yamamoto/crypton/pull/279)+* perf(armv8): GHASH against a twisted H, a quarter faster+ [#281](https://github.com/kazu-yamamoto/crypton/pull/281)+* ct: run the constant-time harness on AArch64, and put its AES to it+ [#283](https://github.com/kazu-yamamoto/crypton/pull/283)+* Fix crypton_sha1_x86_do_chunk signature+ [#284](https://github.com/kazu-yamamoto/crypton/pull/284)+* ci: build the C with a compiler stricter than this matrix has+ [#285](https://github.com/kazu-yamamoto/crypton/pull/285)++## 2.1.4++2.1.3 could not be built from Hackage in the default configuration, and is+deprecated there. This release is that fix.++* Add p256 header files to cabal extra-source-files+ [#271](https://github.com/kazu-yamamoto/crypton/pull/271)+* Build what is published, not only what is checked out+ [#272](https://github.com/kazu-yamamoto/crypton/pull/272)+* SHA-256 on AArch64 is 5.4x slower in 2.1.3 than in 2.1.2+ [#274](https://github.com/kazu-yamamoto/crypton/pull/274)+* The target attribute spelling gcc before 13 understands+ [#276](https://github.com/kazu-yamamoto/crypton/pull/276)++## 2.1.3++* fix(aead): reject missing and oversized authentication tags+ [#233](https://github.com/kazu-yamamoto/crypton/pull/233)+* fix(chacha): remove redundant Word8 import+ [#234](https://github.com/kazu-yamamoto/crypton/pull/234)+* test(number): cover the two modulus sizes the assembly runs at+ [#235](https://github.com/kazu-yamamoto/crypton/pull/235)+* perf(rsa): swap the buffers instead of copying them back+ [#236](https://github.com/kazu-yamamoto/crypton/pull/236)+* perf(rsa): scan the exponentiation's table four limbs at a time+ [#237](https://github.com/kazu-yamamoto/crypton/pull/237)+* fix(gcm): write the field doubling from its definition+ [#238](https://github.com/kazu-yamamoto/crypton/pull/238)+* doc(gcm): carry the MIT notice for the parts that follow fusion+ [#239](https://github.com/kazu-yamamoto/crypton/pull/239)+* perf(ed25519): the base point multiplication through s2n-bignum+ [#240](https://github.com/kazu-yamamoto/crypton/pull/240)+* perf(gcm): AES-GCM through the 512-bit VAES and VPCLMULQDQ+ [#241](https://github.com/kazu-yamamoto/crypton/pull/241)+* doc: the README said AVX-512 was not used, and it is+ [#242](https://github.com/kazu-yamamoto/crypton/pull/242)+* perf(ecdsa): P-256 verification multiplies both scalars at once+ [#243](https://github.com/kazu-yamamoto/crypton/pull/243)+* perf(rsa): four limbs and two carry chains on AArch64+ [#244](https://github.com/kazu-yamamoto/crypton/pull/244)+* perf(rsa): write out the ragged end of the AArch64 row+ [#245](https://github.com/kazu-yamamoto/crypton/pull/245)+* perf(rsa): build R^2 by squaring, not by doubling+ [#246](https://github.com/kazu-yamamoto/crypton/pull/246)+* perf(rsa): stop clearing the scratch a Montgomery multiply writes over+ [#247](https://github.com/kazu-yamamoto/crypton/pull/247)+* doc(gcm): write down what the AArch64 GHASH is short of+ [#248](https://github.com/kazu-yamamoto/crypton/pull/248)+* security(aes): refuse a nonce of no bytes in Crypto.Cipher.AES.GCM+ [#250](https://github.com/kazu-yamamoto/crypton/pull/250)+* ci: build and test the C the other architectures use+ [#251](https://github.com/kazu-yamamoto/crypton/pull/251)+* perf(p256): five teeth to a comb block, over the signed representation+ [#252](https://github.com/kazu-yamamoto/crypton/pull/252)+* security(cipher): stop truncating message lengths on the way to the C+ [#253](https://github.com/kazu-yamamoto/crypton/pull/253)+* fix(c): two left shifts the standard leaves undefined+ [#254](https://github.com/kazu-yamamoto/crypton/pull/254)+* ci: run the C under the sanitizers+ [#255](https://github.com/kazu-yamamoto/crypton/pull/255)+* fix(c): read words out of a block rather than pointing at it+ [#256](https://github.com/kazu-yamamoto/crypton/pull/256)+* fix(internal): drop an import nothing uses any more+ [#257](https://github.com/kazu-yamamoto/crypton/pull/257)+* fix(c): decide the dispatch table once, not on every key+ [#258](https://github.com/kazu-yamamoto/crypton/pull/258)+* Fix the three cabal flag settings that were broken+ [#259](https://github.com/kazu-yamamoto/crypton/pull/259)+* Run the C that only 32-bit architectures get, and fix what that found+ [#260](https://github.com/kazu-yamamoto/crypton/pull/260)+* Let the last addition of each scalar multiplication be a complete one+ [#261](https://github.com/kazu-yamamoto/crypton/pull/261)+* Ask whether the secrets decide anything+ [#262](https://github.com/kazu-yamamoto/crypton/pull/262)+* Ask a big-endian machine the same questions+ [#263](https://github.com/kazu-yamamoto/crypton/pull/263)+* Ask what the secrets leave behind+ [#264](https://github.com/kazu-yamamoto/crypton/pull/264)+* Stop taking eighteen runner slots to test three things+ [#265](https://github.com/kazu-yamamoto/crypton/pull/265)+* Make the scrubs ones the compiler cannot drop, and finish round ten+ [#266](https://github.com/kazu-yamamoto/crypton/pull/266)+* Feed the parsers bytes nobody chose+ [#268](https://github.com/kazu-yamamoto/crypton/pull/268)++## 2.1.2++* perf(p256): 255 squarings for the field inversion, not 287+ [#223](https://github.com/kazu-yamamoto/crypton/pull/223)+* perf(p256): ECDH through s2n-bignum, 2.7x+ [#224](https://github.com/kazu-yamamoto/crypton/pull/224)+* perf(ecc): P-384 and P-521 through s2n-bignum, 7x and 9x+ [#225](https://github.com/kazu-yamamoto/crypton/pull/225)+* perf(p256): ECDSA signing 2.4x and verification 2.2x+ [#226](https://github.com/kazu-yamamoto/crypton/pull/226)+* perf(rsa): the Montgomery multiplication through s2n-bignum on x86-64+ [#227](https://github.com/kazu-yamamoto/crypton/pull/227)+* perf(ecdsa): invert modulo the order in division steps, not an exponentiation+ [#228](https://github.com/kazu-yamamoto/crypton/pull/228)+* perf(x25519): X25519 through s2n-bignum, and a table for key generation+ [#229](https://github.com/kazu-yamamoto/crypton/pull/229)+* perf(gcm): AES-GCM through VAES and VPCLMULQDQ+ [#230](https://github.com/kazu-yamamoto/crypton/pull/230)+* perf(gcm): compile the wide loop once per key length+ [#231](https://github.com/kazu-yamamoto/crypton/pull/231)++## 2.1.1++* feat(ecdsa): RFC 6979 deterministic nonces for Crypto.PubKey.ECDSA+ [#219](https://github.com/kazu-yamamoto/crypton/pull/219)+* feat(gcm): a decrypt that hands back the tag instead of comparing it+ [#220](https://github.com/kazu-yamamoto/crypton/pull/220)+* feat(chachapoly): ChaCha20-Poly1305 a message at a time+ [#221](https://github.com/kazu-yamamoto/crypton/pull/221)+* docs(rsa): say in the haddock what the optional blinder covers+ [#222](https://github.com/kazu-yamamoto/crypton/pull/222)++## 2.1.0++* fix(cpu): stop reading Intel's SDBG bit as AMD's XOP+ [#204](https://github.com/kazu-yamamoto/crypton/pull/204)+* fix(bench): build the benchmark against the checked ChaCha20-Poly1305 key+ [#205](https://github.com/kazu-yamamoto/crypton/pull/205)+* ci: key the cache on the package version+ [#206](https://github.com/kazu-yamamoto/crypton/pull/206)+* ci: build the benchmarks+ [#207](https://github.com/kazu-yamamoto/crypton/pull/207)+* perf(gcm): a fused AES-GCM for x86-64+ [#208](https://github.com/kazu-yamamoto/crypton/pull/208)+* perf(gcm): a fused AES-GCM for AArch64+ [#209](https://github.com/kazu-yamamoto/crypton/pull/209)+* perf(gcm): build the counter in vector registers+ [#210](https://github.com/kazu-yamamoto/crypton/pull/210)+* perf(gcm): a spare lane for E(K,Y0), and a cheaper short block+ [#211](https://github.com/kazu-yamamoto/crypton/pull/211)+* perf(gcm): unroll the tail pass, and take its blocks from registers+ [#212](https://github.com/kazu-yamamoto/crypton/pull/212)+* perf(gcm): read a short block where it lies+ [#213](https://github.com/kazu-yamamoto/crypton/pull/213)+* perf(gcm): the length block and the counter, in registers+ [#214](https://github.com/kazu-yamamoto/crypton/pull/214)+* perf(gcm): let the one-call interface specialise+ [#215](https://github.com/kazu-yamamoto/crypton/pull/215)+* perf(gcm): decryption takes the fused path too+ [#216](https://github.com/kazu-yamamoto/crypton/pull/216)+* perf(gcm): GHASH takes the ciphertext from the output buffer+ [#217](https://github.com/kazu-yamamoto/crypton/pull/217)+* perf(p256): a signed five-bit window for the variable-point multiply+ [#218](https://github.com/kazu-yamamoto/crypton/pull/218)++## 2.0.1++* feat(hash): Skein with the digest size as a type parameter+ [#197](https://github.com/kazu-yamamoto/crypton/pull/197)+* fix(chachapoly1305): take a checked key, so that initializing cannot fail+ [#198](https://github.com/kazu-yamamoto/crypton/pull/198)+* feat(aes): Crypto.Cipher.AES.GCM, for many short messages under one key+ [#199](https://github.com/kazu-yamamoto/crypton/pull/199)+* build: say which platforms the fallback AES sources are for+ [#200](https://github.com/kazu-yamamoto/crypton/pull/200)+* feat(aes): encryptWithMask, for the QUIC header protection mask+ [#201](https://github.com/kazu-yamamoto/crypton/pull/201)+* fix(cpu): stop reading Intel's SDBG bit as AMD's XOP+ [#203](https://github.com/kazu-yamamoto/crypton/pull/203)++## 2.0.0++**Breaking changes.** Input that used to be accepted is now refused: a value+at or above an RSA or Rabin modulus, a signature of the wrong length or out of+range, a digest too short for HOTP's dynamic truncation, a non-canonical+Ed25519 signature, a PKCS#7 block size outside 1..255, and block cipher input+that is not a whole number of blocks. A refused KDF, Argon2 or bcrypt+parameter is reported as a `CryptoError` rather than raised as an `ErrorCall`,+and `CryptoError_ParameterInvalid` is appended to `CryptoError`;+`tryGetShared` is added beside `getShared`. No exported function changed its+signature.++**Deprecated.** The eighteen curves over a binary field in+`Crypto.ECC.Simple.Types`. They are obsolete, they are the curves whose+cofactor is not 1, and they will go in a later major version. Prefer a prime+curve, or X25519.++* Add GHC 9.14 to CI+ [#74](https://github.com/kazu-yamamoto/crypton/pull/74)+* fix(ed25519): reject non-canonical signatures+ [#81](https://github.com/kazu-yamamoto/crypton/pull/81)+* fix(hkdf): enforce RFC 5869 output limit+ [#82](https://github.com/kazu-yamamoto/crypton/pull/82)+* fix(p256): accept valid edge-case points+ [#83](https://github.com/kazu-yamamoto/crypton/pull/83)+* fix(ecc): accept zero-x P-256 shared secrets+ [#84](https://github.com/kazu-yamamoto/crypton/pull/84)+* fix(otp): require a digest long enough for dynamic truncation+ [#85](https://github.com/kazu-yamamoto/crypton/pull/85)+* fix(pkcs15): reject malformed PKCS#1 v1.5 signatures+ [#86](https://github.com/kazu-yamamoto/crypton/pull/86)+* fix(ecdh): validate the peer point before the exchange+ [#87](https://github.com/kazu-yamamoto/crypton/pull/87)+* fix(dsa): do not crash on non-invertible values+ [#88](https://github.com/kazu-yamamoto/crypton/pull/88)+* fix(dh): validate the peer public number+ [#89](https://github.com/kazu-yamamoto/crypton/pull/89)+* fix(argon2): report invalid options as CryptoFailed+ [#90](https://github.com/kazu-yamamoto/crypton/pull/90)+* fix(rsa): drop the early exits from PKCS#1 v1.5 and OAEP unpadding+ [#91](https://github.com/kazu-yamamoto/crypton/pull/91)+* fix(otp): compare TOTP candidates without an early exit+ [#92](https://github.com/kazu-yamamoto/crypton/pull/92)+* feat(dh): add getShared' reporting rejections as CryptoFailable+ [#93](https://github.com/kazu-yamamoto/crypton/pull/93)+* feat(aead): add aeadSimpleDecrypt' taking the tag length+ [#94](https://github.com/kazu-yamamoto/crypton/pull/94)+* test: move the suite to hspec, with hspec-discover+ [#95](https://github.com/kazu-yamamoto/crypton/pull/95)+* docs(bcrypt): say that only the first 72 bytes of a password count+ [#96](https://github.com/kazu-yamamoto/crypton/pull/96)+* feat(elgamal): fix and expose Crypto.PubKey.ElGamal+ [#97](https://github.com/kazu-yamamoto/crypton/pull/97)+* fix(padding): reject a PKCS7 block size outside 1..255+ [#98](https://github.com/kazu-yamamoto/crypton/pull/98)+* build(bench): move the benchmarks from gauge to tasty-bench+ [#99](https://github.com/kazu-yamamoto/crypton/pull/99)+* feat(aes): use the ARMv8 cryptographic extensions on AArch64+ [#100](https://github.com/kazu-yamamoto/crypton/pull/100)+* ci: stop throwing the cache away, and keep the build products in it+ [#101](https://github.com/kazu-yamamoto/crypton/pull/101)+* feat(aes): use PMULL for GHASH on AArch64+ [#102](https://github.com/kazu-yamamoto/crypton/pull/102)+* ci: cut the macOS queueing and supersede stale branch runs+ [#103](https://github.com/kazu-yamamoto/crypton/pull/103)+* feat(sha256): use the ARMv8 SHA-2 instructions on AArch64+ [#104](https://github.com/kazu-yamamoto/crypton/pull/104)+* perf(gcm): fold four GHASH blocks into one reduction+ [#105](https://github.com/kazu-yamamoto/crypton/pull/105)+* ci: build and test on aarch64 Linux+ [#106](https://github.com/kazu-yamamoto/crypton/pull/106)+* fix(cabal): build the AES-NI paths on Windows too+ [#107](https://github.com/kazu-yamamoto/crypton/pull/107)+* perf(aes): specialise by key size and interleave eight blocks on AArch64+ [#108](https://github.com/kazu-yamamoto/crypton/pull/108)+* perf(gcm): drive GCM from AArch64 rather than the generic loop+ [#109](https://github.com/kazu-yamamoto/crypton/pull/109)+* feat(sha512): use the ARMv8.2 SHA-512 instructions on AArch64+ [#110](https://github.com/kazu-yamamoto/crypton/pull/110)+* perf(chacha): do four blocks at a time with NEON on AArch64+ [#111](https://github.com/kazu-yamamoto/crypton/pull/111)+* perf(chacha): do four blocks at a time with SSE2 on x86-64+ [#112](https://github.com/kazu-yamamoto/crypton/pull/112)+* perf(chacha): take eight blocks with AVX2 where the machine has it+ [#113](https://github.com/kazu-yamamoto/crypton/pull/113)+* perf(gcm): give x86 its own decryption loop, and eight blocks either way+ [#114](https://github.com/kazu-yamamoto/crypton/pull/114)+* fix(padding): bound PKCS7 padding by the block, and check ZERO's size+ [#115](https://github.com/kazu-yamamoto/crypton/pull/115)+* ecc: say which curves branch on a secret scalar, and work in Jacobian coordinates+ [#116](https://github.com/kazu-yamamoto/crypton/pull/116)+* perf(poly1305): take four blocks at a time with AVX2 on x86-64+ [#117](https://github.com/kazu-yamamoto/crypton/pull/117)+* perf(xts): drive XTS eight blocks at a time, and dispatch its decryption+ [#118](https://github.com/kazu-yamamoto/crypton/pull/118)+* Report refused KDF parameters as CryptoError, and fix a PBKDF2 SIGBUS+ [#119](https://github.com/kazu-yamamoto/crypton/pull/119)+* Search the HOTP resynchronization window without early exits+ [#120](https://github.com/kazu-yamamoto/crypton/pull/120)+* Refuse an RSA representative that is not below the modulus+ [#121](https://github.com/kazu-yamamoto/crypton/pull/121)+* Give AFIS one answer for a parameter it cannot use+ [#122](https://github.com/kazu-yamamoto/crypton/pull/122)+* Say what ElGamal's signWith requires of k+ [#123](https://github.com/kazu-yamamoto/crypton/pull/123)+* Draw Miller-Rabin witnesses per number, not once per process+ [#124](https://github.com/kazu-yamamoto/crypton/pull/124)+* Refuse Rabin values that are not below the modulus, and keep the padding that was signed+ [#125](https://github.com/kazu-yamamoto/crypton/pull/125)+* Decode Rabin's OAEP without early exits+ [#126](https://github.com/kazu-yamamoto/crypton/pull/126)+* Make CMAC linear, and chain it through CBC+ [#127](https://github.com/kazu-yamamoto/crypton/pull/127)+* Put DES in C+ [#128](https://github.com/kazu-yamamoto/crypton/pull/128)+* Make the generic block cipher modes linear, and bulk where the blocks allow+ [#129](https://github.com/kazu-yamamoto/crypton/pull/129)+* Walk Twofish's blocks once, and carry them in words+ [#130](https://github.com/kazu-yamamoto/crypton/pull/130)+* Put Camellia in C+ [#131](https://github.com/kazu-yamamoto/crypton/pull/131)+* Route P-256 through the C implementation it already had+ [#132](https://github.com/kazu-yamamoto/crypton/pull/132)+* Fold instead of dividing in the generic curve arithmetic+ [#133](https://github.com/kazu-yamamoto/crypton/pull/133)+* Reduce the binary field by folding, and work a byte and a nibble at a time+ [#134](https://github.com/kazu-yamamoto/crypton/pull/134)+* Stop running a Fermat test Miller-Rabin subsumes+ [#135](https://github.com/kazu-yamamoto/crypton/pull/135)+* Make expSafe hide the exponent again+ [#136](https://github.com/kazu-yamamoto/crypton/pull/136)+* Square, and multiply, faster in expSafe+ [#137](https://github.com/kazu-yamamoto/crypton/pull/137)+* Invert the signing nonce without a side channel+ [#138](https://github.com/kazu-yamamoto/crypton/pull/138)+* Keep the P-256 signature out of Integer arithmetic+ [#139](https://github.com/kazu-yamamoto/crypton/pull/139)+* Add at every bit in the prime-curve multiplication, which laziness was skipping+ [#140](https://github.com/kazu-yamamoto/crypton/pull/140)+* Multiply points in C on curves over a prime field+ [#141](https://github.com/kazu-yamamoto/crypton/pull/141)+* A ladder for the curves over a binary field+ [#142](https://github.com/kazu-yamamoto/crypton/pull/142)+* Work RSA's qinv out without the extended Euclidean algorithm+ [#143](https://github.com/kazu-yamamoto/crypton/pull/143)+* Keep the RSA blinding factor out of the extended algorithm+ [#144](https://github.com/kazu-yamamoto/crypton/pull/144)+* Unroll the inner loop at four and two as well+ [#145](https://github.com/kazu-yamamoto/crypton/pull/145)+* Keep a table for each curve's base point+ [#146](https://github.com/kazu-yamamoto/crypton/pull/146)+* Start R squared at the top of the modulus, and why folding did not pay+ [#147](https://github.com/kazu-yamamoto/crypton/pull/147)+* Do the binary field arithmetic in C+ [#148](https://github.com/kazu-yamamoto/crypton/pull/148)+* Use the x86 carry-less multiply where the processor has it+ [#149](https://github.com/kazu-yamamoto/crypton/pull/149)+* Close the two testing gaps: one multiplication for both APIs, one place for each buffer's size+ [#150](https://github.com/kazu-yamamoto/crypton/pull/150)+* Ask aarch64 for its carry-less multiply as well+ [#151](https://github.com/kazu-yamamoto/crypton/pull/151)+* Work the RSA private exponent out without the extended algorithm+ [#152](https://github.com/kazu-yamamoto/crypton/pull/152)+* Fewer Miller-Rabin rounds for a candidate nobody chose+ [#153](https://github.com/kazu-yamamoto/crypton/pull/153)+* Blowfish, and the key setup bcrypt wraps it in, in C+ [#154](https://github.com/kazu-yamamoto/crypton/pull/154)+* perf(sha256): use the Intel SHA extensions on x86-64+ [#155](https://github.com/kazu-yamamoto/crypton/pull/155)+* perf(aes): AES-192 through the processor's AES instructions+ [#156](https://github.com/kazu-yamamoto/crypton/pull/156)+* perf(aes): build the AArch64 key schedule with AESE, not the S-box table+ [#157](https://github.com/kazu-yamamoto/crypton/pull/157)+* test(aes): run the XTS vectors, and OCB and CCM at 192 and 256 bits+ [#158](https://github.com/kazu-yamamoto/crypton/pull/158)+* perf(ocb): drive OCB through the ECB paths a group at a time+ [#159](https://github.com/kazu-yamamoto/crypton/pull/159)+* perf(gcm): take the GHASH of the group before, alongside this group's rounds+ [#160](https://github.com/kazu-yamamoto/crypton/pull/160)+* perf(sha): compute the message schedule in vector registers on x86+ [#161](https://github.com/kazu-yamamoto/crypton/pull/161)+* perf(chacha): combine as the keystream comes out of the registers+ [#162](https://github.com/kazu-yamamoto/crypton/pull/162)+* perf(poly1305): shorten the carry chain and stop spilling the loop+ [#163](https://github.com/kazu-yamamoto/crypton/pull/163)+* docs(sidechannel): say what the prime-field modules keep from the clock+ [#164](https://github.com/kazu-yamamoto/crypton/pull/164)+* perf(sha1): use the Intel SHA extensions on x86-64+ [#165](https://github.com/kazu-yamamoto/crypton/pull/165)+* refactor(aes): drop the keystream generator nobody can call+ [#166](https://github.com/kazu-yamamoto/crypton/pull/166)+* build: compile the C at -O3+ [#167](https://github.com/kazu-yamamoto/crypton/pull/167)+* perf(modes): stop the generic cipher modes allocating per byte+ [#168](https://github.com/kazu-yamamoto/crypton/pull/168)+* perf(poly1305): four blocks at a time with NEON+ [#169](https://github.com/kazu-yamamoto/crypton/pull/169)+* perf(sha1): use the ARMv8 SHA-1 instructions+ [#170](https://github.com/kazu-yamamoto/crypton/pull/170)+* perf(sha3): use the ARMv8.2 SHA-3 instructions+ [#171](https://github.com/kazu-yamamoto/crypton/pull/171)+* perf(gcm): the CRYPTOGAMS stitched AES-GCM on x86-64+ [#172](https://github.com/kazu-yamamoto/crypton/pull/172)+* perf(chacha): the CRYPTOGAMS ChaCha20 on AArch64+ [#173](https://github.com/kazu-yamamoto/crypton/pull/173)+* perf(poly1305): the CRYPTOGAMS Poly1305 on AArch64+ [#174](https://github.com/kazu-yamamoto/crypton/pull/174)+* perf(sha256): the CRYPTOGAMS SHA-256 on AArch64+ [#175](https://github.com/kazu-yamamoto/crypton/pull/175)+* perf(poly1305): the CRYPTOGAMS Poly1305 on x86-64 too+ [#176](https://github.com/kazu-yamamoto/crypton/pull/176)+* perf(chacha): the CRYPTOGAMS ChaCha20 on x86-64 too+ [#177](https://github.com/kazu-yamamoto/crypton/pull/177)+* perf(sha2): the CRYPTOGAMS SHA-256 and SHA-512 on x86-64+ [#178](https://github.com/kazu-yamamoto/crypton/pull/178)+* perf(sha1): hand the SHA-1 block loop a run of blocks, not one at a time+ [#179](https://github.com/kazu-yamamoto/crypton/pull/179)+* perf(xts): double the tweak in the integer registers+ [#180](https://github.com/kazu-yamamoto/crypton/pull/180)+* perf(sha3): take the CRYPTOGAMS Keccak for AArch64+ [#181](https://github.com/kazu-yamamoto/crypton/pull/181)+* perf(sha1): take the CRYPTOGAMS SHA-1 for AArch64+ [#182](https://github.com/kazu-yamamoto/crypton/pull/182)+* docs: put the performance tables in the README+ [#183](https://github.com/kazu-yamamoto/crypton/pull/183)+* perf(sha3): take the CRYPTOGAMS Keccak for x86-64 as well+ [#184](https://github.com/kazu-yamamoto/crypton/pull/184)+* docs: rebuild the performance tables+ [#185](https://github.com/kazu-yamamoto/crypton/pull/185)+* perf(ecc): stop sharing the doublings in the double multiplication+ [#186](https://github.com/kazu-yamamoto/crypton/pull/186)+* perf(number): count bytes from the bit count, not from base 256+ [#187](https://github.com/kazu-yamamoto/crypton/pull/187)+* perf(p256): inline the field arithmetic on AArch64+ [#188](https://github.com/kazu-yamamoto/crypton/pull/188)+* fix(api): name the reporting variants try..., not with an apostrophe+ [#189](https://github.com/kazu-yamamoto/crypton/pull/189)+* fix(ecc): require a public point to be in the prime-order subgroup+ [#190](https://github.com/kazu-yamamoto/crypton/pull/190)+* fix(pubkey): stop printing private keys, and add Crypto.Debug+ [#191](https://github.com/kazu-yamamoto/crypton/pull/191)+* fix(poly1305): take a checked key, so that initializing cannot fail+ [#192](https://github.com/kazu-yamamoto/crypton/pull/192)+* fix(bcrypt): refuse a cost bcrypt does not have rather than substituting one+ [#194](https://github.com/kazu-yamamoto/crypton/pull/194)+* chore: build without a warning+ [#195](https://github.com/kazu-yamamoto/crypton/pull/195)+* docs: build the documentation without a warning+ [#196](https://github.com/kazu-yamamoto/crypton/pull/196)++## 1.1.5++* fix(aead): reject undersized tags+ [#80](https://github.com/kazu-yamamoto/crypton/pull/80)+* fix(aes): refuse a zero-length AES-GCM IV+ [#79](https://github.com/kazu-yamamoto/crypton/pull/79)+* fix(p256): prevent crashes when validating valid points+ [#78](https://github.com/kazu-yamamoto/crypton/pull/78)+* feat(asn1): add SHA-3 HashAlgorithmASN1 instances for PKCS#1 v1.5+ [#77](https://github.com/kazu-yamamoto/crypton/pull/77)+* OCB3 conformance+ [#76](https://github.com/kazu-yamamoto/crypton/pull/76)++## 1.1.4++* Generic instance for RSA PublicKey and PrivateKey++## 1.1.3++* Ensure that `pointAdd` in `PubKey.ECC.P256` treats the point at infinity as the additive identity.+ [#73](https://github.com/kazu-yamamoto/crypton/pull/73)++## 1.1.2++* Preparing `ram` v0.22.+* Generalizing RSA encrypt/decrypt to manipulate ScrubbedBytes directly.++## 1.1.1++* On iOS, ScrubbedBytes based hashing is used for seedNew. On other+ plateforms, entropy is used directly as used to be.+ [#71](https://github.com/kazu-yamamoto/crypton/pull/71)++## 1.1.0++* Removing "basement" and "memory".+ [#67](https://github.com/kazu-yamamoto/crypton/pull/67)+++## 1.0.7++* Stop depending on basement, use upstream dependencies instead+* Stop transitively depending on basement by depending on ram.++## 1.0.6++* Fix test failures on less common 64-bit arches.+ [#65](https://github.com/kazu-yamamoto/crypton/pull/65)++## 1.0.5++* Setter/Getter for ChaCha counter.+ [#63](https://github.com/kazu-yamamoto/crypton/pull/63)+* Add simple interface to generate full blocks+ [#60](https://github.com/kazu-yamamoto/crypton/pull/60)+* Avoid `ghc-prim` dependency.+ [#61](https://github.com/kazu-yamamoto/crypton/pull/61)++## 1.0.4++* Ed448.sign: avoid extra re-derive of public key.+ [#48](https://github.com/kazu-yamamoto/crypton/pull/48)++## 1.0.3++* Make sign of Ed25519/Ed448 safer. The public key parameter is+ ignored and its public key is generated from the secret key+ parameter to prevent Double Public Key Signing Function Oracle+ Attack.+ [#47](https://github.com/kazu-yamamoto/crypton/pull/47)++## 1.0.2++* Deterministic Nonce Generation for ECDSA+ [#46](https://github.com/kazu-yamamoto/crypton/pull/46)+* ECDSA Signature Normalization.+ [#45](https://github.com/kazu-yamamoto/crypton/pull/45)+* Add Full Test Suite from RFC 6979.+ [#44](https://github.com/kazu-yamamoto/crypton/pull/44)+* ECDSA with Public Key Recovery.+ [#43](https://github.com/kazu-yamamoto/crypton/pull/43)+* Providing necessary features for HPKE.+ [#42](https://github.com/kazu-yamamoto/crypton/pull/42)++## 1.0.1++* Update decaf library.+ [#38](https://github.com/kazu-yamamoto/crypton/pull/38)+* Add TypeOperators language extension to EdDSA.hs.+ [#36](https://github.com/kazu-yamamoto/crypton/pull/36)++## 1.0.0++* Versions follow the standard version policy.+* Removing pthread stuff.+ [#32](https://github.com/kazu-yamamoto/crypton/pull/32)++## 0.34++* Hashing getRandomBytes before using as Seed for ChaChaDRG+ [#24](https://github.com/kazu-yamamoto/crypton/pull/24)+* Add support for XChaCha and XChaChaPoly1305+ [#18](https://github.com/kazu-yamamoto/crypton/pull/18)+* Strict byteArray of IV c+ [#16](https://github.com/kazu-yamamoto/crypton/pull/16)++## 0.33++* Add "crypton_" prefix to the final C symbols.+ [#9](https://github.com/kazu-yamamoto/crypton/pull/9)++## 0.32++* All C symbols now have the "crypton_" prefix.+ [#7](https://github.com/kazu-yamamoto/crypton/pull/7)+ [#8](https://github.com/kazu-yamamoto/crypton/pull/8)++## 0.31++* Crypton is forked from cryptonite with the original authors permission.+* Ignoring exceptons from hClose to read the next entropy+ [#1](https://github.com/kazu-yamamoto/crypton/pull/1)+* Enabling the support_pclmuldq flag by default.++## 0.30++* Fix some C symbol blake2b prefix to be cryptonite_ prefix (fix mixing with other C library)+* add hmac-lazy+* Fix compilation with GHC 9.2+* Drop support for GHC8.0, GHC8.2, GHC8.4, GHC8.6++## 0.29++* advance compilation with gmp breakage due to change upstream+* Add native EdDSA support++## 0.28++* Add hash constant time capability+* Prevent possible overflow during hashing by hashing in 4GB chunks++## 0.27++* Optimise AES GCM and CCM+* Optimise P256R1 implementation+* Various AES-NI building improvements+* Add better ECDSA support+* Add XSalsa derive+* Implement square roots for ECC binary curve+* Various tests and benchmarks++## 0.26++* Add Rabin cryptosystem (and variants)+* Add bcrypt_pbkdf key derivation function+* Optimize Blowfish implementation+* Add KMAC (Keccak Message Authentication Code)+* Add ECDSA sign/verify digest APIs+* Hash algorithms with runtime output length+* Update blake2 to latest upstream version+* RSA-PSS with arbitrary key size+* SHAKE with output length not divisible by 8+* Add Read and Data instances for Digest type+* Improve P256 scalar primitives+* Fix hash truncation bug in DSA+* Fix cost parsing for bcrypt+* Fix ECC failures on arm64+* Correction to PKCS#1 v1.5 padding+* Use powModSecInteger when available+* Drop GHC 7.8 and GHC 7.10 support, refer to pkg-guidelines+* Optimise GCM mode+* Add little endian serialization of integer++## 0.25++* Improve digest binary conversion efficiency+* AES CCM support+* Add MonadFailure instance for CryptoFailable+* Various misc improvements on documentation+* Edwards25519 lowlevel arithmetic support+* P256 add point negation+* Improvement in ECC (benchmark, better normalization)+* Blake2 improvements to context size+* Use gauge instead of criterion+* Use haskell-ci for CI scripts+* Improve Digest memory representation to be 2 less Ints and one less boxing+ moving from `UArray` to `Block`++## 0.24++* Ed25519: generateSecret & Documentation updates+* Repair tutorial+* RSA: Allow signing digest directly+* IV add: fix overflow behavior+* P256: validate point when decoding+* Compilation fix with deepseq disabled+* Improve Curve448 and use decaf for Ed448+* Compilation flag blake2 sse merged in sse support+* Process unaligned data better in hashes and AES, on architecture needing alignment+* Drop support for ghc 7.6+* Add ability to create random generator Seed from binary data and+ loosen constraint on ChaChaDRG seed from ByteArray to ByteArrayAccess.+* Add 3 associated types with the HashAlgorithm class, to get+ access to the constant for BlockSize, DigestSize and ContextSize at the type level.+ the related function that this replaced will be deprecated in later release, and+ eventually removed.++API CHANGES:++* Improve ECDH safety to return failure for bad inputs (e.g. public point in small order subgroup).+ To go back to previous behavior you can replace `ecdh` by `ecdhRaw`. It's recommended to+ use `ecdh` and handle the error appropriately.+* Users defining their own HashAlgorithm needs to define the+ HashBlockSize, HashDigest, HashInternalContextSize associated types++## 0.23++* Digest memory usage improvement by using unpinned memory+* Fix generateBetween to generate within the right bounds+* Add pure Twofish implementation+* Fix memory allocation in P256 when using a temp point+* Consolidate hash benchmark code+* Add Nat-length Blake2 support (GHC > 8.0)+* Update tutorial++## 0.22++* Add Argon2 (Password Hashing Competition winner) hash function+* Update blake2 to latest upstream version+* Add extra blake2 hashing size+* Add faster PBKDF2 functions for SHA1/SHA256/SHA512+* Add SHAKE128 and SHAKE256+* Cleanup prime generation, and add tests+* Add Time-based One Time Password (TOTP) and HMAC-based One Time Password (HOTP)+* Rename Ed448 module name to Curve448, old module name still valid for now++## 0.21++* Drop automated tests with GHC 7.0, GHC 7.4, GHC 7.6. support dropped, but probably still working.+* Improve non-aligned support in C sources, ChaCha and SHA3 now probably work on arch without support for unaligned access. not complete or tested.+* Add another ECC framework that is more flexible, allowing different implementations to work instead of+ the existing Pure haskell NIST implementation.+* Add ECIES basic primitives+* Add XSalsa20 stream cipher+* Process partial buffer correctly with Poly1305++## 0.20++* Fixed hash truncation used in ECDSA signature & verification (Olivier Chéron)+* Fix ECDH when scalar and coordinate bit sizes differ (Olivier Chéron)+* Speed up ECDSA verification using Shamir's trick (Olivier Chéron)+* Fix rdrand on windows++## 0.19++* Add tutorial (Yann Esposito)+* Derive Show instance for better interaction with Show pretty printer (Eric Mertens)++## 0.18++* Re-used standard rdrand instructions instead of bytedump of rdrand instruction+* Improvement to F2m, including lots of tests (Andrew Lelechenko)+* Add error check on salt length in bcrypt++## 0.17++* Add Miyaguchi-Preneel construction (Kei Hibino)+* Fix buffer length in scrypt (Luke Taylor)+* build fixes for i686 and arm related to rdrand++## 0.16++* Fix basepoint for Ed448++* Enable 64-bit Curve25519 implementation++## 0.15++* Fix serialization of DH and ECDH++## 0.14++* Reduce size of SHA3 context instead of allocating all-size fit memory. save+ up to 72 bytes of memory per context for SHA3-512.+* Add a Seed capability to the main DRG, to be able to debug/reproduce randomized program+ where you would want to disable the randomness.+* Add support for Cipher-based Message Authentication Code (CMAC) (Kei Hibino)+* *CHANGE* Change the `SharedKey` for `Crypto.PubKey.DH` and `Crypto.PubKey.ECC.DH`,+ from an Integer newtype to a ScrubbedBytes newtype. Prevent mistake where the+ bytes representation is generated without the right padding (when needed).+* *CHANGE* Keep The field size in bits, in the `Params` in `Crypto.PubKey.DH`,+ moving from 2 elements to 3 elements in the structure.++## 0.13++* *SECURITY* Fix buffer overflow issue in SHA384, copying 16 extra bytes from+ the SHA512 context to the destination memory pointer leading to memory+ corruption, segfault. (Mikael Bung)++## 0.12++* Fix compilation issue with Ed448 on 32 bits machine.++## 0.11++* Truncate hashing correctly for DSA+* Add support for HKDF (RFC 5869)+* Add support for Ed448+* Extends support for Blake2s to 224 bits version.+* Compilation workaround for old distribution (RHEL 4.1)+* Compilation fix for AIX+* Compilation fix with AESNI and ghci compiling C source in a weird order.+* Fix example compilation, typo, and warning++## 0.10++* Add reference implementation of blake2 for non-SSE2 platform+* Add support\_blake2\_sse flag++## 0.9++* Quiet down unused module imports+* Move Curve25519 over to Crypto.Error instead of using Either String.+* Add documentation for ChaChaPoly1305+* Add missing documentation for various modules+* Add a way to create Poly1305 Auth tag.+* Added support for the BLAKE2 family of hash algorithms+* Fix endianness of incrementNonce function for ChaChaPoly1305++## 0.8++* Add support for ChaChaPoly1305 Nonce Increment (John Galt)+* Move repository to the haskell-crypto organisation++## 0.7++* Add PKCS5 / PKCS7 padding and unpadding methods+* Fix ChaChaPoly1305 Decryption+* Add support for BCrypt (Luke Taylor)++## 0.6++* Add ChaChaPoly1305 AE cipher+* Add instructions in README for building on old OSX+* Fix blocking /dev/random Andrey Sverdlichenko++## 0.5++* Fix all strays exports to all be under the cryptonite prefix.++## 0.4++* Add a System DRG that represent a referentially transparent of evaluated bytes+ while using lazy evaluation for future entropy values.++## 0.3++* Allow drgNew to run in any MonadRandom, providing cascading initialization+* Remove Crypto.PubKey.HashDescr in favor of just having the algorithm+ specified in PKCS15 RSA function.+* Fix documentation in cipher sub section (Luke Taylor)+* Cleanup AES dead functions (Luke Taylor)+* Fix Show instance of Digest to display without quotes similar to cryptohash+* Use scrubbed bytes instead of bytes for P256 scalar++## 0.2++* Fix P256 compilation and exactness, + add tests+* Add a raw memory number serialization capability (i2osp, os2ip)+* Improve tests for number serialization+* Improve tests for ECC arithmetics+* Add Ord instance for Digest (Nicolas Di Prima)+* Fix entropy compilation on windows 64 bits.++## 0.1++* Initial release+
@@ -0,0 +1,256 @@+-- |+-- Module : Crypto.Cipher.AES.GCM+-- License : BSD-style+-- Maintainer : Kazu Yamamoto <kazu@iij.ad.jp>+-- Stability : experimental+-- Portability : unknown+--+-- AES-GCM for callers that send many short messages under one key, which is+-- what a datagram transport does.+--+-- The interface in "Crypto.Cipher.Types" builds a state from the key /and/+-- the nonce and then walks it through appending the additional data,+-- encrypting and finalizing, copying the state at each step. For a stream+-- that is nothing next to the encryption. For a QUIC packet it is most of+-- the work: the key schedule and the table of multiples of @H@ depend on the+-- key alone, and rebuilding them for every nonce costs more than encrypting+-- 1440 bytes.+--+-- So here a t'Context' is built from the key once and holds both, and+-- 'encrypt' takes a nonce and a whole message and answers in one call.+--+-- > ctx <- throwCryptoError <$> pure (newContext key)+-- > let packet = encrypt ctx nonce header plaintext 16+--+-- This runs on AES-NI and carry-less multiply, or on the ARMv8 cryptographic+-- extension, and makes no branch and no memory access that depends on the key+-- or on the data. Where the processor has neither, AES falls back to a table+-- driven implementation that is /not/ constant time; see the side channels+-- section of the README, and 'Crypto.System.CPU.processorOptions' for which is+-- in use.+--+-- The result is the ciphertext with the tag after it, which is the shape a+-- packet wants. 'decrypt' takes that shape back, compares the tag itself and+-- answers 'Nothing' when it does not match.+--+-- This computes the same thing as the general interface; the tests hold it to+-- that on the same vectors.+module Crypto.Cipher.AES.GCM (+ Context,+ newContext,+ encrypt,+ decrypt,+ decryptWithTag,++ -- * Header protection+ HeaderKey,+ newHeaderKey,+ encryptWithMask,+) where++import Crypto.Cipher.AES.Primitive (+ AES,+ AESGCMKey,+ gcmFullDecrypt,+ gcmFullDecryptTag,+ gcmFullEncrypt,+ gcmFullEncryptMask,+ gcmKeyInit,+ initAES,+ )+import Crypto.Cipher.Types (AuthTag)+import Crypto.Cipher.Types.AEAD (minimumTagLength)+import Crypto.Error+import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)+import qualified Crypto.Internal.ByteArray as B+import Data.Word (Word8)+import Foreign.Ptr (Ptr)++-- | Everything a key determines: the AES key schedule and the table of+-- multiples of @H@. Build it once and encrypt as many messages under it as+-- the key is good for.+data Context = Context !AES !AESGCMKey++-- | Take a key of 16, 24 or 32 bytes. Any other length is reported as+-- 'CryptoError_KeySizeInvalid'.+newContext :: ByteArrayAccess key => key -> CryptoFailable Context+newContext k = do+ aes <- initAES k+ return $ Context aes (gcmKeyInit aes)++-- | Encrypt one message: the nonce, the additional data that is+-- authenticated but not encrypted, the plaintext, and how many bytes of tag+-- to produce, which GCM allows between 4 and 16. Any other length throws+-- 'CryptoError_AuthenticationTagSizeInvalid', and so does 'decryptWithTag'.+--+-- The answer is the ciphertext followed by the tag.+--+-- A nonce must not be used twice with the same t'Context'. Twelve bytes is+-- the size GCM is defined for and the only one that does not cost a further+-- pass. A nonce of no bytes is refused: it would hand out the key GCM+-- authenticates with, so 'encrypt' and 'decryptWithTag' throw+-- 'CryptoError_IvSizeInvalid' for it, 'decrypt' gives 'Nothing' and+-- 'encryptWithMask' gives 'False'.+{-# INLINABLE encrypt #-}+encrypt+ :: ( ByteArrayAccess nonce+ , ByteArrayAccess aad+ , ByteArrayAccess ba+ , ByteArray output+ )+ => Context+ -> nonce+ -> aad+ -> ba+ -> Int+ -> output+encrypt (Context aes gk) nonce aad input taglen+ | tooLongForC aad input =+ throwCryptoError (CryptoFailed CryptoError_ParameterInvalid)+ | badNonce nonce =+ throwCryptoError (CryptoFailed CryptoError_IvSizeInvalid)+ | badTagLength taglen =+ throwCryptoError (CryptoFailed CryptoError_AuthenticationTagSizeInvalid)+ | otherwise = gcmFullEncrypt aes gk nonce aad input taglen++-- | Decrypt one message, in the shape 'encrypt' produced: the ciphertext with+-- its tag after it. The tag is compared here, every byte of it whatever the+-- answer, and a message whose tag does not match gives 'Nothing' rather than+-- the plaintext.+--+-- 'Nothing' also comes back when the nonce has no bytes, the input is+-- shorter than the tag, or the tag length is outside 4 to 16.+{-# INLINABLE decrypt #-}+decrypt+ :: (ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba)+ => Context+ -> nonce+ -> aad+ -> ba+ -> Int+ -> Maybe ba+decrypt (Context aes gk) nonce aad input taglen+ | tooLongForC aad input = Nothing+ | badNonce nonce || badTagLength taglen || B.length input < taglen = Nothing+ | otherwise = gcmFullDecrypt aes gk nonce aad body tag+ where+ (body, tag) = B.splitAt (B.length input - taglen) input++-- | Decrypt one message, the tag kept apart, and hand back the tag this end+-- computed.+--+-- For a caller whose protocol hands it the tag separately from the+-- ciphertext, so that 'decrypt' -- which wants the two together and compares+-- them itself -- does not fit. Compare the two tags with '=='; the 'Eq'+-- instance of t'AuthTag' is a constant-time comparison, and taking them apart+-- to compare the bytes is how this goes wrong.+--+-- Nothing here says whether the message is authentic. Until the comparison+-- is made and has come out equal, what this returns is not plaintext, it is+-- what the ciphertext turns into, and a caller must not act on it.+{-# INLINABLE decryptWithTag #-}+decryptWithTag+ :: (ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba)+ => Context+ -> nonce+ -> aad+ -> ba+ -> Int+ -> (ba, AuthTag)+decryptWithTag (Context aes gk) nonce aad input taglen+ | tooLongForC aad input =+ throwCryptoError (CryptoFailed CryptoError_ParameterInvalid)+ | badNonce nonce =+ throwCryptoError (CryptoFailed CryptoError_IvSizeInvalid)+ | badTagLength taglen =+ throwCryptoError (CryptoFailed CryptoError_AuthenticationTagSizeInvalid)+ | otherwise = gcmFullDecryptTag aes gk nonce aad input taglen++----------------------------------------------------------------++-- | The key schedule for header protection, which QUIC keeps separately from+-- the one it encrypts with. Built once, like a t'Context'.+newtype HeaderKey = HeaderKey AES++-- | Take a header protection key of 16, 24 or 32 bytes.+newHeaderKey :: ByteArrayAccess key => key -> CryptoFailable HeaderKey+newHeaderKey k = HeaderKey <$> initAES k++-- | Encrypt one message and, from a sample of the ciphertext it just+-- produced, make the header protection mask -- in one call, into two buffers+-- the caller already has.+--+-- QUIC takes its sample from the ciphertext, so the mask cannot be had before+-- the encryption. It can be had before coming back, and with the buffers+-- already there nothing is allocated for either. On an Apple M4 the mask+-- then costs about 0.02 us, where asking for it separately costs 0.11.+--+-- The sealed message wants @length input + taglen@ bytes and the mask+-- sixteen. @sampleOffset@ says where the sixteen bytes of sample begin in+-- the sealed message, counting the tag as part of it.+--+-- 'False' comes back, and nothing is written, when the nonce has no bytes,+-- the sample would not fit, or the tag length is outside 4 to 16.+{-# INLINABLE encryptWithMask #-}+encryptWithMask+ :: (ByteArrayAccess nonce, ByteArrayAccess aad, ByteArrayAccess ba)+ => Context+ -> HeaderKey+ -> nonce+ -> aad+ -> ba+ -> Int+ -- ^ tag length+ -> Int+ -- ^ sample offset+ -> Ptr Word8+ -- ^ where the sealed message goes+ -> Ptr Word8+ -- ^ where the sixteen bytes of mask go+ -> IO Bool+encryptWithMask (Context aes gk) (HeaderKey hp) nonce aad input taglen off outp maskp+ | tooLongForC aad input = return False+ | badNonce nonce = return False+ | off < 0 || badTagLength taglen || off + 16 > B.length input + taglen =+ return False+ | otherwise = do+ gcmFullEncryptMask aes gk hp nonce aad input taglen off outp maskp+ return True++-- | The C behind all four takes its lengths as @uint32_t@, so a message or+-- its additional data from 2^32 bytes up cannot be handed to it: the length+-- would be truncated and most of the buffer left untouched, with nothing to+-- say so. There is no splitting the work here -- the C does the whole+-- message in one call, tag and all -- so such a message is refused.+tooLongForC+ :: (ByteArrayAccess aad, ByteArrayAccess ba) => aad -> ba -> Bool+tooLongForC aad input =+ B.overCLength (B.length aad) || B.overCLength (B.length input)++-- | SP 800-38D 5.2.1.1 asks for at least one byte of IV, and this is why.+--+-- GCM builds its pre-counter block from a nonce that is not twelve bytes as+-- @J0 = GHASH_H(IV || 0^s || [0]_64 || [len(IV)]_64)@. For an empty IV that+-- input is one block of zeros, so @J0@ is zero, and the tag of a message+-- becomes @GHASH_H(A, C) XOR E(K, 0^128)@ -- where @E(K, 0^128)@ is the+-- definition of @H@. The tag of an empty message under an empty nonce is+-- therefore @H@ itself, and any other full tag gives @H@ as the root of a+-- known polynomial.+--+-- @H@ belongs to the key, not to the nonce. An attacker holding it, plus one+-- genuine message under any nonce, has @E(K, J0)@ for that nonce and can make+-- a tag that verifies for data of their own -- under a correct twelve-byte+-- nonce, and for every nonce they have seen. One encryption with an empty+-- nonce and a full tag ends the authenticity of everything under the key.+--+-- 'Crypto.Cipher.AES.Primitive.gcmAeadInit' refuses the empty IV for this+-- reason, and these four have to as well. Only the empty one is refused:+-- SP 800-38D allows every length from one byte up.+badNonce :: ByteArrayAccess nonce => nonce -> Bool+badNonce nonce = B.length nonce == 0++-- | GCM makes a sixteen-byte tag and a shorter one is a prefix of it. Below+-- 'minimumTagLength' it authenticates next to nothing, and past sixteen the+-- C code would read beyond the tag it computed.+badTagLength :: Int -> Bool+badTagLength t = t < minimumTagLength || t > 16
@@ -40,6 +40,12 @@ -- * Incremental GCM gcmMode, gcmInit,+ AESGCMKey,+ gcmKeyInit,+ gcmFullEncrypt,+ gcmFullEncryptMask,+ gcmFullDecrypt,+ gcmFullDecryptTag, gcmAeadInit, -- * Incremental OCB@@ -158,6 +164,14 @@ sizeGCM :: Int sizeGCM = 320 +-- | The size of what a key determines, which is the 320 bytes above and the+-- powers of H the fused path reads: sixteen of them, and sixteen more for+-- the term the Karatsuba multiplication would otherwise work out every time.+-- The same on every platform, so that this is one number rather than one per+-- architecture; the powers are filled only where that path is compiled in.+sizeGCMKey :: Int+sizeGCMKey = 832+ sizeOCB :: Int sizeOCB = 160 @@ -257,6 +271,7 @@ -- ^ ciphertext output encryptCTR ctx iv input | len <= 0 = B.empty+ | B.overCLength len = error tooLongMessage | B.length iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: "@@ -351,6 +366,20 @@ c_aes_encrypt_c32 (castPtr o) k v i (fromIntegral len) len = B.length input +-- | What the AES modes say when a message cannot be given to the C, whose+-- lengths are @uint32_t@. Above that the length is truncated on the way+-- down and most of the buffer is left as it was found, with nothing to say+-- so, which is worse than refusing.+--+-- Unlike the stream ciphers, these cannot be done in pieces: the C is handed+-- the IV and does not hand it back, so a second call would start from the+-- wrong place. ECB, CBC and XTS count blocks rather than bytes, so their+-- limit is sixteen times further out than CTR's.+tooLongMessage :: String+tooLongMessage =+ "AES error: message too long for this implementation, whose C takes its "+ ++ "lengths as uint32_t"+ {-# INLINE doECB #-} doECB :: ByteArray ba@@ -359,6 +388,7 @@ -> ba -> ba doECB f ctx input+ | B.overCLength nbBlocks = error tooLongMessage | len == 0 = B.empty | r /= 0 = error $@@ -382,6 +412,7 @@ -> ba -> ba doCBC f ctx (IV iv) input+ | B.overCLength nbBlocks = error tooLongMessage | len == 0 = B.empty | r /= 0 = error $@@ -405,6 +436,7 @@ -> ba -> ba doXTS f (key1, key2) iv spoint input+ | B.overCLength nbBlocks = error tooLongMessage | len == 0 = B.empty | r /= 0 = error $@@ -429,6 +461,190 @@ c_aes_gcm_init (castPtr gcmStPtr) k v (fromIntegral $ B.length iv) return $ AESGCM sm +-- | How long a message may be and still be handed to an unsafe foreign call.+-- Four kibibytes is about half a microsecond of work, and it takes in a+-- datagram of any size a network will carry.+shortMessage :: Int+shortMessage = 4096++-- | The part of a GCM state the key alone determines: H, which is the key+-- applied to a block of zeroes, and the table of its multiples. That is 256+-- of the 320 bytes of a GCM state, and it is the same for every message sent+-- under one key, so a caller that keeps a key can build this once rather than+-- once for every message.+newtype AESGCMKey = AESGCMKey ScrubbedBytes++-- | Build the key part of a GCM state.+{-# NOINLINE gcmKeyInit #-}+gcmKeyInit :: AES -> AESGCMKey+gcmKeyInit ctx = AESGCMKey $ B.allocAndFreeze sizeGCMKey $ \p ->+ keyToPtr ctx $ \k -> c_aes_gcm_key_init (castPtr p) k++-- | Authenticate and encrypt one message in a single call: the nonce, the+-- additional data, the plaintext and the tag, with no state crossing back+-- into Haskell in between. The result is the ciphertext followed by the tag.+{-# INLINABLE gcmFullEncrypt #-}+gcmFullEncrypt+ :: (ByteArrayAccess iv, ByteArrayAccess aad, ByteArrayAccess ba, ByteArray output)+ => AES -> AESGCMKey -> iv -> aad -> ba -> Int -> output+gcmFullEncrypt ctx (AESGCMKey gk) iv aad input taglen =+ B.allocAndFreeze (B.length input + taglen) $ \out ->+ B.withByteArray gk $ \gkp ->+ keyToPtr ctx $ \k ->+ B.withByteArray iv $ \ivp ->+ B.withByteArray aad $ \aadp ->+ B.withByteArray input $ \inp ->+ call+ out+ (castPtr gkp)+ k+ ivp+ (fromIntegral $ B.length iv)+ aadp+ (fromIntegral $ B.length aad)+ inp+ (fromIntegral $ B.length input)+ (fromIntegral taglen)+ where+ -- An unsafe call keeps a capability for as long as it runs, so it is only+ -- right for work that is over quickly. A message this side of+ -- 'shortMessage' is, and it is the short ones the saving matters for: a+ -- safe call costs about 0.075 us whatever the length, which is a fifth of+ -- a 1440-byte packet and a percent of a 16 KiB record.+ call+ | B.length input <= shortMessage = c_aes_gcm_full_encrypt_unsafe+ | otherwise = c_aes_gcm_full_encrypt++-- | Encrypt, and from a sample of the ciphertext just produced make the+-- header protection mask, into buffers the caller owns. QUIC takes its+-- sample from the ciphertext, so the mask cannot be had before the+-- encryption; it can be had before coming back, and with the buffers already+-- there nothing is allocated for either.+--+-- @sampleoff@ is where the sixteen bytes of sample begin in the output.+{-# INLINABLE gcmFullEncryptMask #-}+gcmFullEncryptMask+ :: (ByteArrayAccess iv, ByteArrayAccess aad, ByteArrayAccess ba)+ => AES+ -> AESGCMKey+ -> AES+ -> iv+ -> aad+ -> ba+ -> Int+ -> Int+ -> Ptr Word8+ -> Ptr Word8+ -> IO ()+gcmFullEncryptMask ctx (AESGCMKey gk) hpctx iv aad input taglen sampleoff outp maskp =+ B.withByteArray gk $ \gkp ->+ keyToPtr ctx $ \k ->+ keyToPtr hpctx $ \hk ->+ B.withByteArray iv $ \ivp ->+ B.withByteArray aad $ \aadp ->+ B.withByteArray input $ \inp ->+ call+ outp+ (castPtr gkp)+ k+ ivp+ (fromIntegral $ B.length iv)+ aadp+ (fromIntegral $ B.length aad)+ inp+ (fromIntegral $ B.length input)+ (fromIntegral taglen)+ hk+ (fromIntegral sampleoff)+ maskp+ where+ call+ | B.length input <= shortMessage = c_aes_gcm_full_encrypt_mask_unsafe+ | otherwise = c_aes_gcm_full_encrypt_mask++-- | The same the other way, with the tag compared here rather than by the+-- caller: 'Nothing' when it does not match, and every byte of it is looked at+-- either way. The ciphertext comes in without its tag, which is given+-- separately.+{-# INLINABLE gcmFullDecrypt #-}+gcmFullDecrypt+ :: ( ByteArrayAccess iv+ , ByteArrayAccess aad+ , ByteArrayAccess ba+ , ByteArrayAccess tag+ , ByteArray output+ )+ => AES -> AESGCMKey -> iv -> aad -> ba -> tag -> Maybe output+gcmFullDecrypt ctx (AESGCMKey gk) iv aad input tag = unsafeDoIO $ do+ (r, out) <- B.allocRet (B.length input) $ \outp ->+ B.withByteArray gk $ \gkp ->+ keyToPtr ctx $ \k ->+ B.withByteArray iv $ \ivp ->+ B.withByteArray aad $ \aadp ->+ B.withByteArray input $ \inp ->+ B.withByteArray tag $ \tagp ->+ call+ outp+ (castPtr gkp)+ k+ ivp+ (fromIntegral $ B.length iv)+ aadp+ (fromIntegral $ B.length aad)+ inp+ (fromIntegral $ B.length input)+ tagp+ (fromIntegral $ B.length tag)+ return $ if r /= 0 then Just out else Nothing+ where+ call+ | B.length input <= shortMessage = c_aes_gcm_full_decrypt_unsafe+ | otherwise = c_aes_gcm_full_decrypt++-- | Decrypt one message and hand back the tag that was computed over it,+-- rather than comparing it here.+--+-- For a caller that holds the expected tag in a form of its own and will+-- compare it itself. Compare the two t'AuthTag's with '==', whose instance+-- for that type is a constant-time comparison; taking them apart and+-- comparing the bytes is how this goes wrong.+--+-- Where the tag simply arrives after the ciphertext, 'gcmFullDecrypt' is the+-- one to use: it compares in C and never puts a tag in the caller's hands.+{-# INLINABLE gcmFullDecryptTag #-}+gcmFullDecryptTag+ :: ( ByteArrayAccess iv+ , ByteArrayAccess aad+ , ByteArrayAccess ba+ , ByteArray output+ )+ => AES -> AESGCMKey -> iv -> aad -> ba -> Int -> (output, AuthTag)+gcmFullDecryptTag ctx (AESGCMKey gk) iv aad input taglen = unsafeDoIO $ do+ (tagbs, out) <- B.allocRet (B.length input) $ \outp ->+ B.alloc taglen $ \tagp ->+ B.withByteArray gk $ \gkp ->+ keyToPtr ctx $ \k ->+ B.withByteArray iv $ \ivp ->+ B.withByteArray aad $ \aadp ->+ B.withByteArray input $ \inp ->+ call+ outp+ tagp+ (castPtr gkp)+ k+ ivp+ (fromIntegral $ B.length iv)+ aadp+ (fromIntegral $ B.length aad)+ inp+ (fromIntegral $ B.length input)+ (fromIntegral taglen)+ return (out, AuthTag $ B.convert (tagbs :: B.Bytes))+ where+ call+ | B.length input <= shortMessage = c_aes_gcm_full_decrypt_tag_unsafe+ | otherwise = c_aes_gcm_full_decrypt_tag+ -- | append data which is only going to be authenticated to the GCM context. -- -- needs to happen after initialization and before appending encryption/decryption data.@@ -439,7 +655,8 @@ doAppend = withNewGCMSt gcmSt $ \gcmStPtr -> withByteArray input $ \i ->- c_aes_gcm_aad gcmStPtr i (fromIntegral $ B.length input)+ B.inCLengths (B.length input) $ \off n ->+ c_aes_gcm_aad gcmStPtr (i `plusPtr` off) (fromIntegral n) -- | append data to encrypt and append to the GCM context --@@ -453,7 +670,13 @@ doEnc gcmStPtr aesPtr = B.alloc len $ \o -> withByteArray input $ \i ->- c_aes_gcm_encrypt (castPtr o) gcmStPtr aesPtr i (fromIntegral len)+ B.inCLengths len $ \off n ->+ c_aes_gcm_encrypt+ (castPtr o `plusPtr` off)+ gcmStPtr+ aesPtr+ (i `plusPtr` off)+ (fromIntegral n) -- | append data to decrypt and append to the GCM context --@@ -467,7 +690,13 @@ doDec gcmStPtr aesPtr = B.alloc len $ \o -> withByteArray input $ \i ->- c_aes_gcm_decrypt (castPtr o) gcmStPtr aesPtr i (fromIntegral len)+ B.inCLengths len $ \off n ->+ c_aes_gcm_decrypt+ (castPtr o `plusPtr` off)+ gcmStPtr+ aesPtr+ (i `plusPtr` off)+ (fromIntegral n) -- | Generate the Tag from GCM context {-# NOINLINE gcmFinish #-}@@ -500,9 +729,11 @@ -- The tag length is expressed in bytes and must be in [0..16]. -- The IV length must be in [1..15] bytes per RFC 7253. {-# NOINLINE ocbInitWithTagLength #-}-ocbInitWithTagLength :: ByteArrayAccess iv => AES -> iv -> Int -> CryptoFailable AESOCB+ocbInitWithTagLength+ :: ByteArrayAccess iv => AES -> iv -> Int -> CryptoFailable AESOCB ocbInitWithTagLength ctx iv taglen- | taglen < 0 || taglen > 16 = CryptoFailed CryptoError_AuthenticationTagSizeInvalid+ | taglen < 0 || taglen > 16 =+ CryptoFailed CryptoError_AuthenticationTagSizeInvalid | ivlen < 1 || ivlen > 15 = CryptoFailed CryptoError_IvSizeInvalid | otherwise = CryptoPassed $ unsafeDoIO $ do sm <- B.alloc sizeOCB $ \ocbStPtr ->@@ -522,7 +753,9 @@ -- need to happen after initialization and before appending encryption/decryption data. {-# NOINLINE ocbAppendAAD #-} ocbAppendAAD :: ByteArrayAccess aad => AES -> AESOCB -> aad -> AESOCB-ocbAppendAAD ctx ocb input = unsafeDoIO (snd `fmap` withOCBKeyAndCopySt ctx ocb doAppend)+ocbAppendAAD ctx ocb input+ | B.overCLength (B.length input) = error tooLongMessage+ | otherwise = unsafeDoIO (snd `fmap` withOCBKeyAndCopySt ctx ocb doAppend) where doAppend ocbStPtr aesPtr = withByteArray input $ \i ->@@ -534,7 +767,9 @@ -- need to happen after AAD appending, or after initialization if no AAD data. {-# NOINLINE ocbAppendEncrypt #-} ocbAppendEncrypt :: ByteArray ba => AES -> AESOCB -> ba -> (ba, AESOCB)-ocbAppendEncrypt ctx ocb input = unsafeDoIO $ withOCBKeyAndCopySt ctx ocb doEnc+ocbAppendEncrypt ctx ocb input+ | B.overCLength (B.length input) = error tooLongMessage+ | otherwise = unsafeDoIO $ withOCBKeyAndCopySt ctx ocb doEnc where len = B.length input doEnc ocbStPtr aesPtr =@@ -548,7 +783,9 @@ -- need to happen after AAD appending, or after initialization if no AAD data. {-# NOINLINE ocbAppendDecrypt #-} ocbAppendDecrypt :: ByteArray ba => AES -> AESOCB -> ba -> (ba, AESOCB)-ocbAppendDecrypt ctx ocb input = unsafeDoIO $ withOCBKeyAndCopySt ctx ocb doDec+ocbAppendDecrypt ctx ocb input+ | B.overCLength (B.length input) = error tooLongMessage+ | otherwise = unsafeDoIO $ withOCBKeyAndCopySt ctx ocb doDec where len = B.length input doDec ocbStPtr aesPtr =@@ -608,7 +845,9 @@ -- needs to happen after initialization and before appending encryption/decryption data. {-# NOINLINE ccmAppendAAD #-} ccmAppendAAD :: ByteArrayAccess aad => AES -> AESCCM -> aad -> AESCCM-ccmAppendAAD ctx ccm input = unsafeDoIO $ snd <$> withCCMKeyAndCopySt ctx ccm doAppend+ccmAppendAAD ctx ccm input+ | B.overCLength (B.length input) = error tooLongMessage+ | otherwise = unsafeDoIO $ snd <$> withCCMKeyAndCopySt ctx ccm doAppend where doAppend ccmStPtr aesPtr = withByteArray input $ \i -> c_aes_ccm_aad ccmStPtr aesPtr i (fromIntegral $ B.length input)@@ -619,7 +858,9 @@ -- needs to happen after AAD appending, or after initialization if no AAD data. {-# NOINLINE ccmEncrypt #-} ccmEncrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)-ccmEncrypt ctx ccm input = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm cbcmacAndIv+ccmEncrypt ctx ccm input+ | B.overCLength (B.length input) = error tooLongMessage+ | otherwise = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm cbcmacAndIv where len = B.length input cbcmacAndIv ccmStPtr aesPtr =@@ -633,7 +874,9 @@ -- needs to happen after AAD appending, or after initialization if no AAD data. {-# NOINLINE ccmDecrypt #-} ccmDecrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)-ccmDecrypt ctx ccm input = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm cbcmacAndIv+ccmDecrypt ctx ccm input+ | B.overCLength (B.length input) = error tooLongMessage+ | otherwise = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm cbcmacAndIv where len = B.length input cbcmacAndIv ccmStPtr aesPtr =@@ -682,6 +925,131 @@ foreign import ccall "crypton_aes.h crypton_aes_encrypt_c32" c_aes_encrypt_c32 :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()++foreign import ccall unsafe "crypton_aes.h crypton_aes_gcm_key_init"+ c_aes_gcm_key_init :: Ptr AESGCM -> Ptr AES -> IO ()++foreign import ccall "crypton_aes.h crypton_aes_gcm_full_encrypt"+ c_aes_gcm_full_encrypt+ :: Ptr Word8+ -> Ptr AESGCM+ -> Ptr AES+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> CUInt+ -> IO ()++foreign import ccall "crypton_aes.h crypton_aes_gcm_full_decrypt"+ c_aes_gcm_full_decrypt+ :: Ptr Word8+ -> Ptr AESGCM+ -> Ptr AES+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO CInt++foreign import ccall "crypton_aes.h crypton_aes_gcm_full_decrypt_tag"+ c_aes_gcm_full_decrypt_tag+ :: Ptr Word8+ -> Ptr Word8+ -> Ptr AESGCM+ -> Ptr AES+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> CUInt+ -> IO ()++foreign import ccall unsafe "crypton_aes.h crypton_aes_gcm_full_decrypt_tag"+ c_aes_gcm_full_decrypt_tag_unsafe+ :: Ptr Word8+ -> Ptr Word8+ -> Ptr AESGCM+ -> Ptr AES+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> CUInt+ -> IO ()++foreign import ccall unsafe "crypton_aes.h crypton_aes_gcm_full_encrypt"+ c_aes_gcm_full_encrypt_unsafe+ :: Ptr Word8+ -> Ptr AESGCM+ -> Ptr AES+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> CUInt+ -> IO ()++foreign import ccall unsafe "crypton_aes.h crypton_aes_gcm_full_decrypt"+ c_aes_gcm_full_decrypt_unsafe+ :: Ptr Word8+ -> Ptr AESGCM+ -> Ptr AES+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO CInt++foreign import ccall "crypton_aes.h crypton_aes_gcm_full_encrypt_mask"+ c_aes_gcm_full_encrypt_mask+ :: Ptr Word8+ -> Ptr AESGCM+ -> Ptr AES+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> CUInt+ -> Ptr AES+ -> CUInt+ -> Ptr Word8+ -> IO ()++foreign import ccall unsafe "crypton_aes.h crypton_aes_gcm_full_encrypt_mask"+ c_aes_gcm_full_encrypt_mask_unsafe+ :: Ptr Word8+ -> Ptr AESGCM+ -> Ptr AES+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> CUInt+ -> Ptr AES+ -> CUInt+ -> Ptr Word8+ -> IO () foreign import ccall "crypton_aes.h crypton_aes_gcm_init" c_aes_gcm_init :: Ptr AESGCM -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
@@ -183,10 +183,19 @@ | B.null src = (B.empty, prevSt) | otherwise = unsafeDoIO $ do (out, st) <- B.copyRet prevStMem $ \ctx ->- B.alloc (B.length src) $ \dstPtr ->+ B.alloc n $ \dstPtr -> B.withByteArray src $ \srcPtr ->- ccrypton_chacha_combine dstPtr ctx srcPtr (fromIntegral $ B.length src)+ -- in pieces the C's uint32_t length can hold; it carries+ -- the state in ctx, so it can simply be called again+ B.inCLengths n $ \off len ->+ ccrypton_chacha_combine+ (dstPtr `plusPtr` off)+ ctx+ (srcPtr `plusPtr` off)+ (fromIntegral len) return (out, State st)+ where+ n = B.length src -- | Generate a number of bytes from the ChaCha output directly generate@@ -201,7 +210,11 @@ | otherwise = unsafeDoIO $ do (out, st) <- B.copyRet prevStMem $ \ctx -> B.alloc len $ \dstPtr ->- ccrypton_chacha_generate dstPtr ctx (fromIntegral len)+ B.inCLengths len $ \off n ->+ ccrypton_chacha_generate+ (dstPtr `plusPtr` off)+ ctx+ (fromIntegral n) return (out, State st) -- | similar to 'generate' but assume certains values
@@ -0,0 +1,335 @@+-- |+-- Module : Crypto.Cipher.ChaCha.Poly1305+-- License : BSD-style+-- Maintainer : Kazu Yamamoto <kazu@iij.ad.jp>+-- Stability : experimental+-- Portability : Good+--+-- ChaCha20-Poly1305 (RFC 8439) a message at a time.+--+-- "Crypto.Cipher.ChaChaPoly1305" takes a message in pieces: a state is+-- started, the additional data appended, the body encrypted and the tag+-- taken, each a step of its own. That is what a protocol wants when the+-- message arrives in pieces, and it is eight foreign calls and the+-- allocations between them when the message was already whole.+--+-- Here the whole message goes in one call.+--+-- The functions are the same shape as "Crypto.Cipher.AES.GCM", so a protocol+-- that offers both ciphers can hold them the same way.+module Crypto.Cipher.ChaCha.Poly1305 (+ Context,+ newContext,+ encrypt,+ decrypt,+ decryptWithTag,+) where++import Crypto.Cipher.Types (AuthTag (..))+import Crypto.Error+import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)+import qualified Crypto.Internal.ByteArray as B+import Crypto.Internal.Compat (unsafeDoIO)+import Crypto.Internal.Imports+import Foreign.C.Types (CInt (..), CUInt (..))+import Foreign.Ptr (Ptr, plusPtr)++-- | A key, checked once.+--+-- ChaCha20-Poly1305 has nothing to precompute from a key: the one-time+-- Poly1305 key comes from the nonce, so it differs for every message. This+-- holds the thirty-two bytes and the knowledge that they are thirty-two, and+-- exists so that the interface is the one "Crypto.Cipher.AES.GCM" has.+newtype Context = Context B.ScrubbedBytes++instance NFData Context where+ rnf (Context k) = k `seq` ()++-- | Take a key of 32 bytes. Any other length is reported as+-- 'CryptoError_KeySizeInvalid'.+newContext :: ByteArrayAccess key => key -> CryptoFailable Context+newContext k+ | B.length k /= 32 = CryptoFailed CryptoError_KeySizeInvalid+ | otherwise = CryptoPassed $ Context (B.convert k)+{-# INLINABLE newContext #-}++-- | Encrypt one message. The result is the ciphertext with the tag after it,+-- which is the shape 'decrypt' expects.+--+-- The nonce is the twelve bytes RFC 8439 defines; any other length gives+-- 'CryptoError_IvSizeInvalid'. RFC 8439 requires a 16-byte tag.+{-# INLINABLE encrypt #-}+encrypt+ :: ( ByteArrayAccess nonce+ , ByteArrayAccess aad+ , ByteArrayAccess ba+ , ByteArray output+ )+ => Context+ -> nonce+ -> aad+ -> ba+ -> Int+ -> CryptoFailable output+encrypt (Context k) nonce aad input taglen+ | tooLongForC aad input = CryptoFailed CryptoError_ParameterInvalid+ | not (validNonce nonce) = CryptoFailed CryptoError_IvSizeInvalid+ | badTag taglen = CryptoFailed CryptoError_AuthenticationTagSizeInvalid+ | otherwise =+ CryptoPassed $+ unsafeDoIO $+ B.alloc (B.length input + taglen) $ \out ->+ B.withByteArray k $ \kp ->+ B.withByteArray nonce $ \np ->+ B.withByteArray aad $ \ap ->+ B.withByteArray input $ \ip ->+ (callE (B.length input))+ out+ (out `plusPtr` B.length input)+ (fromIntegral taglen)+ kp+ np+ (fromIntegral $ B.length nonce)+ ap+ (fromIntegral $ B.length aad)+ ip+ (fromIntegral $ B.length input)++-- | Decrypt one message, in the shape 'encrypt' produced: the ciphertext with+-- its tag after it. The tag is compared here, every byte of it whatever the+-- answer, and a message whose tag does not match gives 'Nothing' rather than+-- the plaintext.+--+-- 'Nothing' also comes back when the input is shorter than the tag, or the+-- nonce is not twelve bytes.+{-# INLINABLE decrypt #-}+decrypt+ :: (ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba)+ => Context+ -> nonce+ -> aad+ -> ba+ -> Int+ -> Maybe ba+decrypt (Context k) nonce aad input taglen+ | tooLongForC aad input = Nothing+ | not (validNonce nonce) = Nothing+ | badTag taglen || B.length input < taglen = Nothing+ | otherwise = unsafeDoIO $ do+ (r, out) <- B.allocRet bodylen $ \outp ->+ B.withByteArray k $ \kp ->+ B.withByteArray nonce $ \np ->+ B.withByteArray aad $ \ap ->+ B.withByteArray body $ \ip ->+ B.withByteArray tag $ \tp ->+ (callD bodylen)+ outp+ tp+ (fromIntegral taglen)+ kp+ np+ (fromIntegral $ B.length nonce)+ ap+ (fromIntegral $ B.length aad)+ ip+ (fromIntegral bodylen)+ return $ if r /= 0 then Just out else Nothing+ where+ bodylen = B.length input - taglen+ (body, tag) = B.splitAt bodylen input++-- | Decrypt one message, the tag kept apart, and hand back the tag this end+-- computed.+--+-- For a caller whose protocol carries the tag separately from the ciphertext,+-- so that 'decrypt' -- which wants the two together and compares them itself+-- -- does not fit. Compare the two tags with '=='; the 'Eq' instance of+-- t'AuthTag' is a constant-time comparison, and taking them apart to compare+-- the bytes is how this goes wrong.+--+-- Nothing here says whether the message is authentic. Until the comparison+-- is made and has come out equal, what this returns is not plaintext, it is+-- what the ciphertext turns into, and a caller must not act on it.+{-# INLINABLE decryptWithTag #-}+decryptWithTag+ :: (ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba)+ => Context+ -> nonce+ -> aad+ -> ba+ -> Int+ -> CryptoFailable (ba, AuthTag)+decryptWithTag (Context k) nonce aad input taglen+ | tooLongForC aad input = CryptoFailed CryptoError_ParameterInvalid+ | not (validNonce nonce) = CryptoFailed CryptoError_IvSizeInvalid+ | badTag taglen = CryptoFailed CryptoError_AuthenticationTagSizeInvalid+ | otherwise = CryptoPassed $ unsafeDoIO $ do+ (tagbs, out) <- B.allocRet (B.length input) $ \outp ->+ B.alloc taglen $ \tagp ->+ B.withByteArray k $ \kp ->+ B.withByteArray nonce $ \np ->+ B.withByteArray aad $ \ap ->+ B.withByteArray input $ \ip ->+ (callT (B.length input))+ outp+ tagp+ (fromIntegral taglen)+ kp+ np+ (fromIntegral $ B.length nonce)+ ap+ (fromIntegral $ B.length aad)+ ip+ (fromIntegral $ B.length input)+ return (out, AuthTag $ B.convert (tagbs :: B.Bytes))++-- | The C takes its lengths as @uint32_t@, so a message or its additional+-- data from 2^32 bytes up cannot be handed to it: the length would be+-- truncated and most of the buffer left untouched, with nothing to say so.+-- The C does the whole message in one call, so there is no splitting it.+tooLongForC+ :: (ByteArrayAccess aad, ByteArrayAccess ba) => aad -> ba -> Bool+tooLongForC aad input =+ B.overCLength (B.length aad) || B.overCLength (B.length input)++-- RFC 8439 is the twelve-byte nonce. ChaCha20 will take eight, but that is+-- the other construction, with a 64-bit block counter, and it is not what+-- this AEAD is defined over -- so it is refused here rather than quietly+-- encrypting under a scheme nobody asked for.+validNonce :: ByteArrayAccess nonce => nonce -> Bool+validNonce n = B.length n == 12++badTag :: Int -> Bool+badTag t = t /= 16++-- | An unsafe call keeps a capability for as long as it runs, so it is only+-- for a message short enough that the run is short. Four kibibytes is what+-- the AES side uses, and it takes in a datagram of any size a network will+-- carry.+shortMessage :: Int+shortMessage = 4096++callE :: Int -> CEncrypt+callE n+ | n <= shortMessage = c_chachapoly_encrypt_unsafe+ | otherwise = c_chachapoly_encrypt++callD :: Int -> CDecrypt+callD n+ | n <= shortMessage = c_chachapoly_decrypt_unsafe+ | otherwise = c_chachapoly_decrypt++callT :: Int -> CEncrypt+callT n+ | n <= shortMessage = c_chachapoly_decrypt_tag_unsafe+ | otherwise = c_chachapoly_decrypt_tag++type CEncrypt =+ Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO ()++type CDecrypt =+ Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO CInt++foreign import ccall "crypton_chachapoly.h crypton_chachapoly_encrypt"+ c_chachapoly_encrypt+ :: Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO ()++foreign import ccall unsafe "crypton_chachapoly.h crypton_chachapoly_encrypt"+ c_chachapoly_encrypt_unsafe+ :: Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO ()++foreign import ccall "crypton_chachapoly.h crypton_chachapoly_decrypt"+ c_chachapoly_decrypt+ :: Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO CInt++foreign import ccall unsafe "crypton_chachapoly.h crypton_chachapoly_decrypt"+ c_chachapoly_decrypt_unsafe+ :: Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO CInt++foreign import ccall "crypton_chachapoly.h crypton_chachapoly_decrypt_tag"+ c_chachapoly_decrypt_tag+ :: Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO ()++foreign import ccall unsafe "crypton_chachapoly.h crypton_chachapoly_decrypt_tag"+ c_chachapoly_decrypt_tag_unsafe+ :: Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> Ptr Word8+ -> CUInt+ -> IO ()
@@ -1,3 +1,5 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+ -- | -- Module : Crypto.Cipher.ChaChaPoly1305 -- License : BSD-style@@ -28,7 +30,7 @@ -- > -> ByteString -- input plaintext to be encrypted -- > -> CryptoFailable ByteString -- ciphertext with a 128-bit tag attached -- >encrypt nonce key header plaintext = do--- > st1 <- C.nonce12 nonce >>= C.initialize key+-- > st1 <- C.initialize <$> C.key key <*> C.nonce12 nonce -- > let -- > st2 = C.finalizeAAD $ C.appendAAD header st1 -- > (out, st3) = C.encrypt plaintext st2@@ -41,6 +43,8 @@ -- * Low level State,+ Key,+ key, Nonce, XNonce, nonce12,@@ -68,6 +72,7 @@ ) import qualified Crypto.Internal.ByteArray as B import Crypto.Internal.Imports+import qualified Crypto.Internal.Poly1305 as PolyKey import qualified Crypto.MAC.Poly1305 as Poly1305 import qualified Data.ByteArray.Pack as P import Data.Memory.Endian@@ -174,44 +179,39 @@ -- -- The key length need to be 256 bits, and the nonce -- procured using either `nonce8` or `nonce12`-initialize- :: ByteArrayAccess key- => key -> Nonce -> CryptoFailable State-initialize key (Nonce8 nonce) = initialize' key nonce-initialize key (Nonce12 nonce) = initialize' key nonce+-- | A ChaCha20Poly1305 key: thirty-two bytes, checked once here rather than+-- at every use, so that 'initialize' and 'initializeX' cannot fail.+newtype Key = Key ScrubbedBytes+ deriving (ByteArrayAccess, Eq, NFData) -initialize'- :: ByteArrayAccess key- => key -> Bytes -> CryptoFailable State-initialize' key nonce- | B.length key /= 32 = CryptoFailed CryptoError_KeySizeInvalid- | otherwise = CryptoPassed $ initFromRootState rootState- where- rootState = ChaCha.initialize 20 key nonce+-- | Take thirty-two bytes for a key. A different length is reported as+-- 'CryptoError_KeySizeInvalid'; nothing else about a key can be wrong.+key :: ByteArrayAccess ba => ba -> CryptoFailable Key+key k+ | B.length k /= 32 = CryptoFailed CryptoError_KeySizeInvalid+ | otherwise = CryptoPassed $ Key $ B.convert k +initialize :: Key -> Nonce -> State+initialize k (Nonce8 nonce) = initialize' k nonce+initialize k (Nonce12 nonce) = initialize' k nonce++initialize' :: Key -> Bytes -> State+initialize' k nonce = initFromRootState (ChaCha.initialize 20 k nonce)+ initFromRootState :: ChaCha.State -> State initFromRootState rootState = State encState polyState 0 0 where (polyKey, encState) = ChaCha.generate rootState 64- -- 64 bytes are generated so the ChaCha state advances a whole block; the- -- first 32 of them are the key, so the length is right by construction- polyState =- Poly1305.initialize $- throwCryptoError $- Poly1305.key (B.take 32 polyKey :: ScrubbedBytes)+ -- 64 bytes are generated so the ChaCha state advances a whole block, and+ -- the first 32 of them are the key, so there is no length left to check+ polyState = Poly1305.initialize (PolyKey.Key (B.take 32 polyKey)) -- | Initialize a new XChaChaPoly1305 State -- -- The key length needs to be 256 bits, and the nonce -- procured using `nonce24`.-initializeX- :: ByteArrayAccess key- => key -> XNonce -> CryptoFailable State-initializeX key (Nonce24 nonce)- | B.length key /= 32 = CryptoFailed CryptoError_KeySizeInvalid- | otherwise = CryptoPassed $ initFromRootState rootState- where- rootState = ChaCha.initializeX 20 key nonce+initializeX :: Key -> XNonce -> State+initializeX k (Nonce24 nonce) = initFromRootState (ChaCha.initializeX 20 k nonce) -- | Append Authenticated Data to the State and return -- the new modified State.@@ -267,8 +267,8 @@ aeadChacha20poly1305Init :: (ByteArrayAccess k, ByteArrayAccess n) => k -> n -> CryptoFailable (AEAD ChaCha20Poly1305)-aeadChacha20poly1305Init key nonce = do- st0 <- nonce12 nonce >>= initialize key+aeadChacha20poly1305Init k nonce = do+ st0 <- initialize <$> key k <*> nonce12 nonce return $ AEAD model st0 where model =
@@ -98,7 +98,14 @@ B.allocRet len $ \outptr -> B.withByteArray clearText $ \clearPtr -> do st <- B.copy prevSt $ \stPtr ->- c_rc4_combine (castPtr stPtr) clearPtr (fromIntegral len) outptr+ -- in pieces the C's uint32_t length can hold; the state it+ -- keeps means it can simply be called again+ B.inCLengths len $ \off n ->+ c_rc4_combine+ (castPtr stPtr)+ (clearPtr `plusPtr` off)+ (fromIntegral n)+ (outptr `plusPtr` off) return $! State st where -- return $! (State st, B.PS outfptr 0 len)
@@ -70,10 +70,19 @@ | B.null src = (B.empty, prevSt) | otherwise = unsafeDoIO $ do (out, st) <- B.copyRet prevStMem $ \ctx ->- B.alloc (B.length src) $ \dstPtr ->- B.withByteArray src $ \srcPtr -> do- ccrypton_salsa_combine dstPtr ctx srcPtr (fromIntegral $ B.length src)+ B.alloc n $ \dstPtr ->+ B.withByteArray src $ \srcPtr ->+ -- in pieces the C's uint32_t length can hold; it carries+ -- the state in ctx, so it can simply be called again+ B.inCLengths n $ \off len ->+ ccrypton_salsa_combine+ (dstPtr `plusPtr` off)+ ctx+ (srcPtr `plusPtr` off)+ (fromIntegral len) return (out, State st)+ where+ n = B.length src -- | Generate a number of bytes from the Salsa output directly generate@@ -88,7 +97,11 @@ | otherwise = unsafeDoIO $ do (out, st) <- B.copyRet prevStMem $ \ctx -> B.alloc len $ \dstPtr ->- ccrypton_salsa_generate dstPtr ctx (fromIntegral len)+ B.inCLengths len $ \off n ->+ ccrypton_salsa_generate+ (dstPtr `plusPtr` off)+ ctx+ (fromIntegral n) return (out, State st) foreign import ccall "crypton_salsa_init"
@@ -15,9 +15,8 @@ import Crypto.Internal.WordArray import Crypto.Internal.Words (Word128 (..)) import Data.Bits-import Data.List (foldl')+import qualified Data.List as L import Data.Word-import Prelude hiding (foldl') -- Based on the Golang referance implementation -- https://github.com/golang/crypto/blob/master/twofish/twofish.go@@ -113,7 +112,7 @@ b' = b `xor` arrayRead32 ks 1 c' = c `xor` arrayRead32 ks 2 d' = d `xor` arrayRead32 ks 3- (!a'', !b'', !c'', !d'') = foldl' shuffle (a', b', c', d') [0 .. 7]+ (!a'', !b'', !c'', !d'') = L.foldl' shuffle (a', b', c', d') [0 .. 7] ts = ( c'' `xor` arrayRead32 ks 4 , d'' `xor` arrayRead32 ks 5@@ -180,7 +179,7 @@ b' = d `xor` arrayRead32 ks 7 c' = a `xor` arrayRead32 ks 4 d' = b `xor` arrayRead32 ks 5- (!a'', !b'', !c'', !d'') = foldl' unshuffle (a', b', c', d') [8, 7 .. 1]+ (!a'', !b'', !c'', !d'') = L.foldl' unshuffle (a', b', c', d') [8, 7 .. 1] ixs = ( a'' `xor` arrayRead32 ks 0 , b'' `xor` arrayRead32 ks 1@@ -284,7 +283,7 @@ ( \wordIndex -> map ( \rsRow ->- foldl'+ L.foldl' ( \acc (!rsVal, !colIndex) -> acc `xor` gfMult rsPolynomial (B.index key $ 8 * wordIndex + colIndex) rsVal )@@ -443,7 +442,7 @@ b' = rotateL b 8 h :: ByteArray ba => [Word8] -> KeyPackage ba -> Int -> Word32-h input keyPackage offset = foldl' xorMdsColMult 0 $ zip [y0f, y1f, y2f, y3f] $ enumFrom Zero+h input keyPackage offset = L.foldl' xorMdsColMult 0 $ zip [y0f, y1f, y2f, y3f] $ enumFrom Zero where key = rawKeyBytes keyPackage [y0, y1, y2, y3] = take 4 input
@@ -15,8 +15,7 @@ MiyaguchiPreneel, ) where -import Data.List (foldl')-import Prelude hiding (foldl')+import qualified Data.List as L import Crypto.Cipher.Types import Crypto.Cipher.Types.Utils (chunk)@@ -41,7 +40,7 @@ -> MiyaguchiPreneel cipher -- ^ output tag compute' g =- MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . pad (ZERO bsz) . B.convert+ MP . L.foldl' (step $ g) (B.replicate bsz 0) . chunks . pad (ZERO bsz) . B.convert where bsz = blockSize (g B.empty {- dummy to get block size -}) -- 'chunk' slices rather than splitting the message, which copied whatever
@@ -49,13 +49,12 @@ import qualified Crypto.ECC.Simple.Prim as Simple import qualified Crypto.ECC.Simple.Types as Simple import Crypto.Error+import Crypto.KEM (SharedSecret (..)) import Crypto.Internal.ByteArray ( ByteArray, ByteArrayAccess,- ScrubbedBytes, ) import qualified Crypto.Internal.ByteArray as B-import Crypto.Internal.Imports import Crypto.Number.Basic (numBits) import Crypto.Number.Serialize (i2ospOf_, os2ip) import qualified Crypto.Number.Serialize.LE as LE@@ -74,16 +73,6 @@ { keypairGetPublic :: !(Point curve) , keypairGetPrivate :: !(Scalar curve) }---- | Secret shared via key exchange-newtype SharedSecret = SharedSecret ScrubbedBytes- deriving (Eq, ByteArrayAccess, NFData)--instance Semigroup SharedSecret where- SharedSecret x <> SharedSecret y = SharedSecret (x <> y)--instance Monoid SharedSecret where- mempty = SharedSecret mempty class EllipticCurve curve where -- | Point on an Elliptic Curve
@@ -57,6 +57,10 @@ -- the base point generates, so multiplying it would answer modulo a -- small order. Appended for the same reason as the constructor above. CryptoError_PointSubgroupInvalid+ | -- | A public key is the right length but is not a well-formed encoding+ -- of one, so no honest party produced it. Appended for the same+ -- reason as the two constructors above.+ CryptoError_PublicKeyStructureInvalid deriving (Show, Eq, Enum, Data) instance E.Exception CryptoError
@@ -53,12 +53,20 @@ import qualified Crypto.Internal.ByteArray as B import qualified Data.ByteString.Lazy as L import Data.Int (Int32)+import Data.Word (Word8)+import Foreign.Marshal.Alloc (allocaBytes) import qualified Foreign.Marshal.Utils as FMU import Foreign.Ptr (Ptr, castPtr, plusPtr) -- | Hash a strict bytestring into a digest.-hash :: (ByteArrayAccess ba, HashAlgorithm a) => ba -> Digest a-hash bs = hashFinalize $ hashUpdate hashInit bs+hash :: forall ba a. (ByteArrayAccess ba, HashAlgorithm a) => ba -> Digest a+hash bs = Digest $+ allocAndFreezePrim (hashDigestSize (undefined :: a)) $ \(dig :: Ptr (Digest a)) ->+ -- one context, used in place: the pure steps would copy it three times+ allocaBytes (hashInternalContextSize (undefined :: a)) $ \(ctx :: Ptr (Context a)) -> do+ hashInternalInit ctx+ B.withByteArray bs (updateBlocks ctx (B.length bs))+ hashInternalFinalize ctx dig -- | Hash the first N bytes of a bytestring, with code path independent from N. hashPrefix@@ -92,20 +100,19 @@ hashUpdates c l | null ls = c | otherwise = Context $ B.copyAndFreeze c $ \(ctx :: Ptr (Context a)) ->- mapM_ (\b -> B.withByteArray b (processBlocks ctx (B.length b))) ls+ mapM_ (\b -> B.withByteArray b (updateBlocks ctx (B.length b))) ls where ls = filter (not . B.null) l- -- process the data in 2GB chunks to fit in uint32_t and Int on 32 bit systems- processBlocks ctx bytesLeft dataPtr- | bytesLeft == 0 = return ()- | otherwise = do- hashInternalUpdate ctx dataPtr (fromIntegral actuallyProcessed)- processBlocks- ctx- (bytesLeft - actuallyProcessed)- (dataPtr `plusPtr` actuallyProcessed)- where- actuallyProcessed = min bytesLeft (fromIntegral (maxBound :: Int32))++-- | Process the data in 2GB chunks to fit in uint32_t and Int on 32 bit systems+updateBlocks :: HashAlgorithm a => Ptr (Context a) -> Int -> Ptr Word8 -> IO ()+updateBlocks ctx bytesLeft dataPtr+ | bytesLeft == 0 = return ()+ | otherwise = do+ hashInternalUpdate ctx dataPtr (fromIntegral actuallyProcessed)+ updateBlocks ctx (bytesLeft - actuallyProcessed) (dataPtr `plusPtr` actuallyProcessed)+ where+ actuallyProcessed = min bytesLeft (fromIntegral (maxBound :: Int32)) -- | Finalize a context and return a digest. hashFinalize
@@ -48,8 +48,10 @@ Blake2bp (..), Blake2s (..), Blake2sp (..),+ Skein256 (..), Skein256_224 (..), Skein256_256 (..),+ Skein512 (..), Skein512_224 (..), Skein512_256 (..), Skein512_384 (..),
@@ -1,7 +1,11 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} -- | -- Module : Crypto.Hash.Skein256@@ -13,14 +17,17 @@ -- Module containing the binding functions to work with the -- Skein256 cryptographic hash. module Crypto.Hash.Skein256 (+ Skein256 (..), Skein256_224 (..), Skein256_256 (..), ) where import Crypto.Hash.Types+import Crypto.Internal.Nat import Data.Data import Data.Word (Word32, Word8) import Foreign.Ptr (Ptr)+import GHC.TypeLits (KnownNat, Nat, type (+)) -- | Skein256 (224 bits) cryptographic hash algorithm data Skein256_224 = Skein256_224@@ -51,6 +58,38 @@ hashInternalInit p = c_skein256_init p 256 hashInternalUpdate = c_skein256_update hashInternalFinalize p = c_skein256_finalize p 256++-- | Skein256 with the digest size given as a type parameter of kind 'Nat',+-- in bits. @t'Skein256' 256@ is @t'Skein256_256'@; the sizes with a type of+-- their own+-- above are there for their names, and this one also takes the sizes that+-- have none.+--+-- A size that is not a whole number of bytes is rounded up to the next one,+-- as the implementation underneath does.+--+-- The output is produced in counter mode, a block of it per Threefish call,+-- so one large digest is a good deal cheaper than the same number of bytes+-- taken from repeated small ones: on an Apple M4, 512 KiB arrives at 947 MB/s+-- in one digest against 172 MB/s as 8192 separate @t'Skein256_256'@ ones.+--+-- Note the digest size goes into the configuration block, so it changes the+-- value the message is hashed from: a longer digest is /not/ an extension of+-- a shorter one. That is the opposite of how t'Crypto.Hash.SHAKE.SHAKE128'+-- behaves.+data Skein256 (bitlen :: Nat) = Skein256+ deriving (Show, Data)++instance KnownNat bitlen => HashAlgorithm (Skein256 bitlen) where+ type HashBlockSize (Skein256 bitlen) = 32+ type HashDigestSize (Skein256 bitlen) = Div8 (bitlen + 7)+ type HashInternalContextSize (Skein256 bitlen) = 96+ hashBlockSize _ = 32+ hashDigestSize _ = byteLen (Proxy :: Proxy bitlen)+ hashInternalContextSize _ = 96+ hashInternalInit p = c_skein256_init p (integralNatVal (Proxy :: Proxy bitlen))+ hashInternalUpdate = c_skein256_update+ hashInternalFinalize p = c_skein256_finalize p (integralNatVal (Proxy :: Proxy bitlen)) foreign import ccall unsafe "crypton_skein256_init" c_skein256_init :: Ptr (Context a) -> Word32 -> IO ()
@@ -1,7 +1,11 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} -- | -- Module : Crypto.Hash.Skein512@@ -13,6 +17,7 @@ -- Module containing the binding functions to work with the -- Skein512 cryptographic hash. module Crypto.Hash.Skein512 (+ Skein512 (..), Skein512_224 (..), Skein512_256 (..), Skein512_384 (..),@@ -20,9 +25,11 @@ ) where import Crypto.Hash.Types+import Crypto.Internal.Nat import Data.Data import Data.Word (Word32, Word8) import Foreign.Ptr (Ptr)+import GHC.TypeLits (KnownNat, Nat, type (+)) -- | Skein512 (224 bits) cryptographic hash algorithm data Skein512_224 = Skein512_224@@ -83,6 +90,38 @@ hashInternalInit p = c_skein512_init p 512 hashInternalUpdate = c_skein512_update hashInternalFinalize p = c_skein512_finalize p 512++-- | Skein512 with the digest size given as a type parameter of kind 'Nat',+-- in bits. @t'Skein512' 512@ is @t'Skein512_512'@; the sizes with a type of+-- their own+-- above are there for their names, and this one also takes the sizes that+-- have none.+--+-- A size that is not a whole number of bytes is rounded up to the next one,+-- as the implementation underneath does.+--+-- The output is produced in counter mode, a block of it per Threefish call,+-- so one large digest is a good deal cheaper than the same number of bytes+-- taken from repeated small ones: on an Apple M4, 512 KiB arrives at 947 MB/s+-- in one digest against 172 MB/s as 8192 separate @t'Skein512_512'@ ones.+--+-- Note the digest size goes into the configuration block, so it changes the+-- value the message is hashed from: a longer digest is /not/ an extension of+-- a shorter one. That is the opposite of how t'Crypto.Hash.SHAKE.SHAKE128'+-- behaves.+data Skein512 (bitlen :: Nat) = Skein512+ deriving (Show, Data)++instance KnownNat bitlen => HashAlgorithm (Skein512 bitlen) where+ type HashBlockSize (Skein512 bitlen) = 64+ type HashDigestSize (Skein512 bitlen) = Div8 (bitlen + 7)+ type HashInternalContextSize (Skein512 bitlen) = 160+ hashBlockSize _ = 64+ hashDigestSize _ = byteLen (Proxy :: Proxy bitlen)+ hashInternalContextSize _ = 160+ hashInternalInit p = c_skein512_init p (integralNatVal (Proxy :: Proxy bitlen))+ hashInternalUpdate = c_skein512_update+ hashInternalFinalize p = c_skein512_finalize p (integralNatVal (Proxy :: Proxy bitlen)) foreign import ccall unsafe "crypton_skein512_init" c_skein512_init :: Ptr (Context a) -> Word32 -> IO ()
@@ -103,6 +103,26 @@ -- layout is architecture dependent, may contain uninitialized data fragments, -- and change in future versions. The bytearray should not be used as input to -- cryptographic algorithms.+--+-- __A context is not erased when it is finished with.__ A hash algorithm+-- buffers its input a block at a time, and finalizing does not clear what is+-- left there. How much survives depends on where the message ended relative+-- to the block: with SHA-256, a 32-byte message is still in the context in+-- full afterwards, and a 100-byte one leaves its last 36 bytes.+-- @hashFinalize@ works on a copy, so the caller's own context keeps what it+-- had as well. Nothing clears either of them: this is 'Bytes' rather than+-- @ScrubbedBytes@, and the C clears nothing. They go to the garbage+-- collector as they are, and a core file, a crash dump or a swapped page can+-- carry them away afterwards.+--+-- That is a deliberate trade rather than an oversight, and there is no way+-- to ask for the other side of it: no operation here clears a context.+-- Scrubbing them all was measured at about 70% of a 32-byte hash and a third+-- of an incremental one, because the allocation is most of the work when the+-- message is short -- and short hashes are the common case, in HMAC, in+-- HKDF, and anywhere a key or an identifier is hashed. A 64 KB hash does+-- not notice it. Anything that must not be left in memory this way is+-- better not hashed through this interface at all. newtype Context a = Context Bytes deriving (ByteArrayAccess, NFData)
@@ -14,6 +14,8 @@ module Data.ByteArray.Mapping, module Data.ByteArray.Encoding, constAllZero,+ overCLength,+ inCLengths, allocAndFreezePrimIO, allocAndFreezePrim, bxor,@@ -30,6 +32,51 @@ import Foreign.Storable (peekByteOff) import Crypto.Internal.Compat (unsafeDoIO)++-- | Whether a length is too large to reach the C, which takes its lengths as+-- @uint32_t@.+--+-- From 2^32 up the value is truncated on the way down, and the C then works+-- on the low bits of it and leaves the rest of the buffer as it found it --+-- which for a fresh allocation is zeros. What comes back is as long as the+-- caller asked for, with nothing to say that most of it was never written:+-- a 4 GiB message through Crypto.Cipher.ChaCha.combine came back with 2^32+-- bytes of zeros where the ciphertext should have been.+--+-- Every place that hands a caller's length to the C either turns it away+-- with this or cuts the work into pieces small enough to pass.+--+-- The round trip through 'Word32' rather than a comparison against 2^32,+-- which a 32-bit 'Int' cannot hold. There every non-negative 'Int' passes,+-- which is the right answer: there is no such buffer to be had.+overCLength :: Int -> Bool+overCLength n = fromIntegral (fromIntegral n :: Word32) /= n++-- | Walk a length in pieces small enough to reach the C, calling the action+-- with the offset and the size of each.+--+-- The same 2 GiB step "Crypto.Hash" has always taken, and for the same+-- reason: the C takes its lengths as @uint32_t@, and a 32-bit 'Int' cannot+-- hold a whole one either. This is for the C that keeps its state in a+-- context and can simply be called again -- the stream ciphers, the MACs --+-- where a long message can be enciphered in pieces rather than refused.+inCLengths :: Int -> (Int -> Int -> IO ()) -> IO ()+inCLengths total f = go 0+ where+ go !off+ | off >= total = return ()+ | otherwise = f off n >> go (off + n)+ where+ !n = min (total - off) cChunk++-- | The step 'inCLengths' takes: the largest multiple of 64 that a signed+-- 32-bit integer holds.+--+-- Under 2^31 because a 32-bit 'Int' cannot hold more, and a+-- multiple of 64 because some of the C this feeds -- the AEAD modes -- will+-- take a piece that is not a whole number of blocks only as the last one.+cChunk :: Int+cChunk = 0x7fffffc0 -- | Allocate a pinned 'Prim.ByteArray' of the given size, populate it via a -- 'Ptr', then freeze and return it. The pointer must not be retained after
@@ -0,0 +1,37 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- |+-- Module : Crypto.Internal.Poly1305+-- License : BSD-style+-- Maintainer : Kazu Yamamoto <kazu@iij.ad.jp>+-- Stability : experimental+-- Portability : unknown+--+-- The Poly1305 key with its constructor, for the modules here that build one+-- from bytes whose length they already know. "Crypto.MAC.Poly1305" exports+-- the type without the constructor, so that outside this library a key can+-- only be made by 'key', which checks.+module Crypto.Internal.Poly1305 (+ Key (..),+ key,+) where++import Crypto.Error+import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes)+import qualified Crypto.Internal.ByteArray as B+import Crypto.Internal.DeepSeq++-- | A Poly1305 key: thirty-two bytes, and the length is checked here rather+-- than at every use. 'Crypto.MAC.Poly1305.initialize' and+-- 'Crypto.MAC.Poly1305.auth' take one of these and cannot fail, so a caller+-- that holds a key does not carry an error case for a length it already knows+-- is right.+newtype Key = Key ScrubbedBytes+ deriving (ByteArrayAccess, Eq, NFData)++-- | Take thirty-two bytes for a key. A different length is reported as+-- 'CryptoError_MacKeyInvalid'; nothing else about a key can be wrong.+key :: ByteArrayAccess ba => ba -> CryptoFailable Key+key k+ | B.length k /= 32 = CryptoFailed CryptoError_MacKeyInvalid+ | otherwise = CryptoPassed $ Key $ B.convert k
@@ -0,0 +1,121 @@+-- |+-- Module : Crypto.KEM+-- License : BSD-style+-- Maintainer : Kazu Yamamoto <kazu@iij.ad.jp>+-- Stability : experimental+-- Portability : unknown+--+-- Key encapsulation: one side publishes a key, the other draws a secret and+-- returns something only the first side can turn back into it.+--+-- The shape is not ML-KEM's alone, which is why this is a class in a module+-- of its own rather than part of any one algorithm: 'Crypto.PubKey.MLKEM'+-- is one instance of it, and a caller that does not care which it has can+-- be written against this.+--+-- A bare Diffie-Hellman exchange is deliberately __not__ an instance, even+-- though the shapes line up. The KEM a Diffie-Hellman group gives is+-- DHKEM, of RFC 9180 section 4.1, and that is not the raw exchange: its+-- shared secret is the exchange's output run through HKDF with the+-- ephemeral and the recipient public keys as context, under labels that+-- name the ciphersuite. The binding to those two keys, and the separation+-- between suites, are what the KEM security argument rests on; the raw+-- value has neither. A protocol can supply the binding at its own level --+-- TLS 1.3 does, in the key schedule -- but then the binding belongs to the+-- protocol, not to this class, and offering the raw exchange here would+-- invite its use somewhere that supplies nothing.+--+-- DHKEM proper is an instance, and it is not here either: the labels it+-- derives under carry the HPKE ciphersuite identifier, which is an IANA+-- registry value rather than anything a primitive knows, so the instances+-- live beside the registry in the @hpke@ package.+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies #-}++module Crypto.KEM (+ KEM (..),+ SharedSecret (..),+) where++import Data.Kind (Type)++import Crypto.Error (CryptoFailable)+import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes)+import Crypto.Internal.Imports+import Crypto.Random (MonadRandom)++-- | Secret shared via key exchange.+newtype SharedSecret = SharedSecret ScrubbedBytes+ deriving (Eq, ByteArrayAccess, NFData)++instance Show SharedSecret where+ show _ = "SharedSecret <redacted>"++instance Semigroup SharedSecret where+ SharedSecret x <> SharedSecret y = SharedSecret (x <> y)++instance Monoid SharedSecret where+ mempty = SharedSecret mempty++-- | A key encapsulation mechanism.+--+-- The three values are named for what they do rather than for what they are+-- in any one algorithm. In ML-KEM the encapsulation key and the ciphertext+-- are what the names say; in a Diffie-Hellman exchange both are public+-- values of the group, and the \"ciphertext\" is the ephemeral one the+-- encapsulating side generates. Keeping them apart in the types is what+-- stops one being passed where the other belongs, which they are not+-- interchangeable for even where they have the same representation.+class KEM kem where+ -- | What the encapsulating side is given.+ type EncapsulationKey kem :: Type++ -- | What the decapsulating side keeps.+ type DecapsulationKey kem :: Type++ -- | What travels back, and is decapsulated.+ type Ciphertext kem :: Type++ -- | The randomness 'encapsulate' draws, for the instances that let a+ -- caller supply it. In ML-KEM it is @m@ of FIPS 203, a string of+ -- bytes; in DHKEM it is the ephemeral secret key, a scalar of the+ -- group. Both are secret, and both determine the shared secret+ -- completely.+ type Coins kem :: Type++ -- | Generate a key pair for the decapsulating side.+ generateKeyPair+ :: MonadRandom m+ => proxy kem -> m (EncapsulationKey kem, DecapsulationKey kem)++ -- | Draw a secret and encapsulate it against the key.+ --+ -- This can fail, and does for some instances: a Diffie-Hellman exchange+ -- refuses a peer value that would make the secret degenerate, where+ -- ML-KEM has nothing to refuse.+ encapsulate+ :: MonadRandom m+ => proxy kem+ -> EncapsulationKey kem+ -> m (CryptoFailable (Ciphertext kem, SharedSecret))++ -- | Encapsulate with the randomness supplied rather than drawn.+ --+ -- The secret this produces is a deterministic function of the key and+ -- these coins, so they must come from a source no other party can+ -- predict or repeat, and must not be used twice. 'encapsulate' is the+ -- entry point for ordinary use; this one is for test vectors, and for a+ -- protocol that has to name the ephemeral value it used -- HPKE lets a+ -- sender supply its own, and the RFC 9180 vectors are written that way.+ encapsulateWith+ :: proxy kem+ -> EncapsulationKey kem+ -> Coins kem+ -> CryptoFailable (Ciphertext kem, SharedSecret)++ -- | Recover the secret.+ decapsulate+ :: proxy kem+ -> DecapsulationKey kem+ -> Ciphertext kem+ -> CryptoFailable SharedSecret
@@ -35,6 +35,7 @@ ) import qualified Crypto.Internal.ByteArray as B import Crypto.Internal.DeepSeq+import Crypto.Internal.Poly1305 (Key (..), key) import Data.Word import Foreign.C.Types import Foreign.Ptr@@ -48,20 +49,6 @@ newtype State = State ScrubbedBytes deriving (ByteArrayAccess) --- | A Poly1305 key: thirty-two bytes, and the length is checked here rather--- than at every use. 'initialize' and 'auth' take one of these and cannot--- fail, so a caller that holds a key does not carry an error case for a--- length it already knows is right.-newtype Key = Key ScrubbedBytes- deriving (ByteArrayAccess, Eq, NFData)---- | Take thirty-two bytes for a key. A different length is reported as--- 'CryptoError_MacKeyInvalid'; nothing else about a key can be wrong.-key :: ByteArrayAccess ba => ba -> CryptoFailable Key-key k- | B.length k /= 32 = CryptoFailed CryptoError_MacKeyInvalid- | otherwise = CryptoPassed $ Key $ B.convert k- -- | Poly1305 State. use State instead of Ctx type Ctx = State @@ -105,7 +92,10 @@ update :: ByteArrayAccess ba => State -> ba -> State update (State prevCtx) d = State $ B.copyAndFreeze prevCtx $ \ctxPtr -> B.withByteArray d $ \dataPtr ->- c_poly1305_update (castPtr ctxPtr) dataPtr (fromIntegral $ B.length d)+ -- in pieces the C's uint32_t length can hold; the context carries+ -- across, so it can simply be called again+ B.inCLengths (B.length d) $ \off n ->+ c_poly1305_update (castPtr ctxPtr) (dataPtr `plusPtr` off) (fromIntegral n) {-# NOINLINE update #-} -- | updates a context with multiples bytestring@@ -114,7 +104,9 @@ where loop [] _ = return () loop (x : xs) ctxPtr = do- B.withByteArray x $ \dataPtr -> c_poly1305_update ctxPtr dataPtr (fromIntegral $ B.length x)+ B.withByteArray x $ \dataPtr ->+ B.inCLengths (B.length x) $ \off n ->+ c_poly1305_update ctxPtr (dataPtr `plusPtr` off) (fromIntegral n) loop xs ctxPtr {-# NOINLINE updates #-} @@ -137,5 +129,9 @@ B.withByteArray k $ \keyPtr -> do c_poly1305_init (castPtr ctxPtr) keyPtr B.withByteArray d $ \dataPtr ->- c_poly1305_update (castPtr ctxPtr) dataPtr (fromIntegral $ B.length d)+ B.inCLengths (B.length d) $ \off n ->+ c_poly1305_update+ (castPtr ctxPtr)+ (dataPtr `plusPtr` off)+ (fromIntegral n) c_poly1305_finalize dst (castPtr ctxPtr)
@@ -85,7 +85,12 @@ -- | Compute the number of bits for an integer numBits :: Integer -> Int-numBits n = gmpSizeInBits n `onGmpUnsupported` (if n == 0 then 1 else computeBits 0 n)+-- GMP sizes the magnitude and calls zero zero bits, and every caller here --+-- 'numBytes' above all -- is written against that. The fallback used to+-- answer 1 for zero, and to divide a negative number by 256 forever, because+-- the quotient never reaches zero.+numBits n =+ gmpSizeInBits n `onGmpUnsupported` (if n == 0 then 0 else computeBits 0 (abs n)) where computeBits !acc i | q == 0 =
@@ -36,9 +36,8 @@ (.&.), (.|.), )-import Data.List (foldl')+import qualified Data.List as L import Data.Word (Word32)-import Prelude hiding (foldl') -- | Binary Polynomial represented by an integer type BinaryPolynomial = Integer@@ -89,7 +88,7 @@ | otherwise = fold es- (foldl' (\acc e -> acc `xor` (hi `shiftL` e)) (n .&. mask) es)+ (L.foldl' (\acc e -> acc `xor` (hi `shiftL` e)) (n .&. mask) es) where hi = n `shiftR` lfx {-# INLINE modF2m #-}@@ -211,7 +210,7 @@ where spread :: Int -> Word32 spread b =- foldl' (\acc i -> if testBit b i then setBit acc (2 * i) else acc) 0 [0 .. 7]+ L.foldl' (\acc i -> if testBit b i then setBit acc (2 * i) else acc) 0 [0 .. 7] {-# NOINLINE spreadTable #-} {-# INLINE squareF2m' #-}
@@ -43,6 +43,7 @@ import Crypto.Internal.Compat (unsafeDoIO) import Crypto.Number.Basic import Crypto.Number.Compat+import Crypto.Number.ModArithmetic.Pub (expPub) import qualified Crypto.Number.Serialize.Internal as Internal import Data.Memory.PtrMethods (memSet) import Data.Word (Word32, Word8)@@ -141,6 +142,7 @@ -- what GMP's own secure exponentiation lets slip !eLen = 8 * ((numBytes e + 7) `div` 8) + foreign import ccall safe "crypton_powm_sec" c_powm_sec :: Ptr Word8@@ -158,6 +160,14 @@ -- -- Use this function when all the parameters are public, -- otherwise 'expSafe' should be preferred.+--+-- A short exponent on an odd modulus -- RSA verification, where the exponent+-- is 65537 and comes out of the public key -- is walked a bit at a time in+-- C, squaring at each step and multiplying where a bit is set, which reads+-- the exponent and branches on it and is why this is not 'expSafe'. That+-- path is taken only where it is the faster of the two, which the C decides;+-- everywhere else, and for every longer exponent, this is GMP's windowed+-- exponentiation as it has always been. expFast :: Integer -- ^ base@@ -167,13 +177,29 @@ -- ^ modulo -> Integer -- ^ result-expFast b e m = gmpPowModInteger b e m `onGmpUnsupported` exponentiation b e m+expFast b e m+ | odd m && m > 1 && e > 0 = case expPub (b `mod` m) e m of+ Just r -> r+ Nothing -> slow+ | otherwise = slow+ where+ slow = gmpPowModInteger b e m `onGmpUnsupported` exponentiation b e m -- | @exponentiation@ computes modular exponentiation as /b^e mod m/ -- using repetitive squaring.+--+-- The corner cases are held to what GMP answers, since that is what this+-- computes on every build that has it: a modulus of one is zero whatever+-- else is asked, and a negative exponent is a request for the inverse of+-- the base raised to its magnitude, which is zero when no inverse exists.+-- Read literally, the recursion below walked a negative exponent from -1 to+-- -2 and back for as long as the stack held. exponentiation :: Integer -> Integer -> Integer -> Integer exponentiation b e m- | b == 1 = b+ | m == 1 = 0+ | e < 0 =+ maybe 0 (\bInv -> exponentiation bInv (negate e) m) (inverse (b `mod` m) m)+ | b == 1 = 1 | e == 0 = 1 | e == 1 = b `mod` m | even e =@@ -240,20 +266,56 @@ -- bits it is given, and a nonce inverted that way has been taken apart before -- by watching the steps go by. ----- The moduli this is for -- the order of a group -- are prime, so the inverse--- comes from 'inverseFermat' instead. When the modulus is not prime, that--- answer is not an inverse, and the result is checked and 'inverse' asked--- instead, so this agrees with 'inverse' on every input. That fallback is--- reached only by parameters that are already broken.+-- The answer comes from a fixed number of division steps where the assembly+-- for them is built, and from 'inverseFermat' where it is not. Either way it+-- is checked here by multiplying out: neither one says when the number has no+-- inverse -- the first returns something that is not one and the second+-- returns something that is not one either -- so the check is what makes this+-- agree with 'inverse' on every input, and 'inverse' is asked when it fails.+-- That fallback is reached only by parameters that are already broken. ----- It costs what an exponentiation costs: around thirty times an 'inverse'--- for a 256-bit modulus.+-- The division steps cost about a twentieth of the exponentiation: on an+-- Apple M4, inverting modulo the P-256 group order is 0.80 microseconds+-- against 6.02, and modulo the P-521 one 2.05 against 63.2. inverseSafe :: Integer -> Integer -> Maybe Integer inverseSafe g m | m > 1 && (g * r) `mod` m == 1 = Just r | otherwise = inverse g m where- r = inverseFermat g m+ r = case inverseSec g m of+ Just v -> v+ Nothing -> inverseFermat g m++-- | The inverse in a fixed number of division steps, from the vendored+-- assembly. 'Nothing' when that is not built, when the modulus is even --+-- where the routine answers without saying it cannot -- or when the numbers+-- are larger than it keeps room for. The answer is not checked here; the+-- caller does that.+inverseSec :: Integer -> Integer -> Maybe Integer+inverseSec g m+ | m <= 1 || even m || g < 0 = Nothing+ | otherwise = unsafeDoIO $+ allocaBytes (3 * mLen) $ \out -> do+ let gp = out `plusPtr` mLen+ mp = gp `plusPtr` mLen+ _ <- Internal.i2ospOf (g `mod` m) gp mLen+ _ <- Internal.i2ospOf m mp mLen+ r <- c_modinv_sec out gp mp (fromIntegral mLen)+ if r == 0+ then do+ !v <- Internal.os2ip out mLen+ return (Just v)+ else return Nothing+ where+ !mLen = numBytes m++foreign import ccall unsafe "crypton_modinv_sec"+ c_modinv_sec+ :: Ptr Word8+ -> Ptr Word8+ -> Ptr Word8+ -> Word32+ -> IO CInt -- | Raised when the assumption about the modulus is invalid. data ModulusAssertionError = ModulusAssertionError
@@ -0,0 +1,158 @@+{-# LANGUAGE BangPatterns #-}++-- |+-- Module : Crypto.Number.ModArithmetic.Pub+-- License : BSD-style+-- Stability : experimental+-- Portability : Good+--+-- The C exponentiation for an exponent that is not a secret, and the R^2+-- it keeps per modulus. Internal: 'expPub' is behind 'expFast', and+-- 'expPubBytes' behind RSA's public-key operation.+module Crypto.Number.ModArithmetic.Pub (+ expPub,+ expPubBytes,+) where++import Crypto.Internal.ByteArray (+ ByteArray,+ ByteArrayAccess,+ Bytes,+ allocRet,+ withByteArray,+ )+import qualified Crypto.Internal.ByteArray as B+import Crypto.Internal.Compat (unsafeDoIO)+import Crypto.Number.Basic+import qualified Crypto.Number.Serialize.Internal as Internal+import Data.IORef (IORef, atomicModifyIORef', newIORef)+import Data.Word (Word32, Word8)+import Foreign.C.Types (CInt (..))+import Foreign.Marshal.Alloc (allocaBytes)+import Foreign.Ptr (Ptr, plusPtr)+import System.IO.Unsafe (unsafePerformIO)++-- | The windowless exponentiation in C, for an exponent that is not a+-- secret. 'Nothing' when the C declines, which it does on every machine+-- where what the caller already has is faster -- so this is an+-- optimisation and never the only path. The base has to be reduced and+-- the exponent positive, which the caller sees to.+expPub :: Integer -> Integer -> Integer -> Maybe Integer+expPub b e m = unsafeDoIO $ do+ known <- r2For m+ case known of+ Nothing -> return Nothing+ Just (r2, modu) ->+ allocaBytes (sum widths) $ \start -> case scanl plusPtr start widths of+ (out : base : expo : _) -> do+ _ <- Internal.i2ospOf b base mLen+ _ <- Internal.i2ospOf e expo eLen+ r <- withByteArray modu $ \pm -> withByteArray r2 $ \pr2 ->+ c_powm_pub_r2+ out+ base+ (fromIntegral mLen)+ expo+ (fromIntegral eLen)+ pm+ (fromIntegral mLen)+ pr2+ if r == 0+ then do+ !v <- Internal.os2ip out mLen+ return (Just v)+ else return Nothing+ _ -> return Nothing+ where+ !mLen = numBytes m+ !eLen = numBytes e+ widths = [mLen, mLen, eLen]++-- | The same with the base and the answer as big-endian bytes, as long as+-- the modulus: what RSA verification has in hand, so neither goes through+-- an 'Integer'. 'Nothing' also when the base is not below the modulus.+expPubBytes+ :: (ByteArrayAccess bi, ByteArray bo) => Integer -> Integer -> bi -> Maybe bo+expPubBytes e m b+ | e <= 0 || m <= 1 || even m || B.length b /= mLen = Nothing+ | otherwise = unsafeDoIO $ do+ known <- r2For m+ case known of+ Nothing -> return Nothing+ Just (r2, modu)+ | not (below b modu) -> return Nothing+ | otherwise -> allocaBytes eLen $ \expo -> do+ _ <- Internal.i2ospOf e expo eLen+ (r, out) <- allocRet mLen $ \pout ->+ withByteArray b $ \pb -> withByteArray modu $ \pm ->+ withByteArray r2 $ \pr2 ->+ c_powm_pub_r2+ pout+ pb+ (fromIntegral mLen)+ expo+ (fromIntegral eLen)+ pm+ (fromIntegral mLen)+ pr2+ return (if r == 0 then Just out else Nothing)+ where+ !mLen = numBytes m+ !eLen = numBytes e++-- big-endian numbers of one length: the first byte that differs decides+below :: (ByteArrayAccess a, ByteArrayAccess b) => a -> b -> Bool+below x y = go 0+ where+ n = B.length x+ go i+ | i >= n = False+ | otherwise = case compare (B.index x i) (B.index y i) of+ EQ -> go (i + 1)+ o -> o == LT++-- | R^2 mod m for the public path, and m in bytes, kept for the last few+-- moduli, since a program verifies under the same keys again and again.+-- 'Nothing' is kept too: it means the C declines this modulus, which is+-- then not asked again.+r2For :: Integer -> IO (Maybe (Bytes, Bytes))+r2For m = do+ found <- atomicModifyIORef' r2Table $ \ks -> case break ((== m) . fst) ks of+ (before, hit : after) -> (hit : before ++ after, Just (snd hit))+ _ -> (ks, Nothing)+ case found of+ Just r2 -> return r2+ Nothing -> do+ let mLen = numBytes m+ (r2, modu) <- allocRet mLen $ \modu -> do+ _ <- Internal.i2ospOf m modu mLen+ (r, out) <- allocRet mLen $ \pout -> c_powm_r2 pout modu (fromIntegral mLen)+ return (if r == 0 then Just out else Nothing)+ let kept = fmap (\x -> (x, modu)) r2+ atomicModifyIORef' r2Table $ \ks -> (take r2TableSize ((m, kept) : ks), ())+ return kept++r2TableSize :: Int+r2TableSize = 8++r2Table :: IORef [(Integer, Maybe (Bytes, Bytes))]+r2Table = unsafePerformIO (newIORef [])+{-# NOINLINE r2Table #-}++-- safe, as the secure one is: the call is tens of microseconds at RSA+-- sizes, and the hundred nanoseconds this costs over an unsafe call is+-- nothing beside holding a capability for that long in a server+foreign import ccall safe "crypton_powm_pub_r2"+ c_powm_pub_r2+ :: Ptr Word8+ -> Ptr Word8+ -> Word32+ -> Ptr Word8+ -> Word32+ -> Ptr Word8+ -> Word32+ -> Ptr Word8+ -> IO CInt++foreign import ccall unsafe "crypton_powm_r2"+ c_powm_r2 :: Ptr Word8 -> Ptr Word8 -> Word32 -> IO CInt
@@ -53,7 +53,12 @@ !padSz = ptrSz - sz fillPtr :: Ptr Word8 -> Int -> Integer -> IO ()-fillPtr p sz m = gmpExportInteger m p `onGmpUnsupported` export (sz - 1) m+fillPtr p sz m+ -- zero is no bytes wide, and the callers above have already written the+ -- room out as zeros. Without this the loop below starts at offset -1,+ -- never meets the 0 it stops at, and walks backwards out of the buffer.+ | sz <= 0 = return ()+ | otherwise = gmpExportInteger m p `onGmpUnsupported` export (sz - 1) m where export ofs i | ofs == 0 = pokeByteOff p ofs (fromIntegral i :: Word8)
@@ -49,9 +49,8 @@ import Crypto.MAC.HMAC import Data.Bits (complement, shiftL, shiftR, xor, (.&.), (.|.)) import Data.ByteArray.Mapping (fromW64BE)-import Data.List (foldl')+import qualified Data.List as L import Data.Word-import Prelude hiding (foldl') -- | A one-time password which is a sequence of 4 to 9 digits. type OTP = Word32@@ -150,7 +149,7 @@ range = map (hotp h d k) [c .. c + fromIntegral s] -- the offset of the first match, accumulated without stopping there- (matched, offset) = foldl' pick (0, 0) (zip [0 ..] range)+ (matched, offset) = L.foldl' pick (0, 0) (zip [0 ..] range) pick (!m, !off) (i, candidate) = (m .|. hit, off .|. (hit .&. i)) where -- zero once something has matched, so only the first match counts@@ -162,7 +161,7 @@ -- the counters continue past the window, and wrap where the old -- 'checkExtraOtps' wrapped extrasMatched =- foldl' step (complement 0) (zip (iterate (+ 1) afterFirst) extras)+ L.foldl' step (complement 0) (zip (iterate (+ 1) afterFirst) extras) step acc (ctr, p) = acc .&. eqMask (hotp h d k ctr) p -- | All ones when the two values are equal, zero otherwise, without branching@@ -250,7 +249,7 @@ -- every candidate is compared, and none of the comparisons stops early, so -- neither which step matched nor how far a mismatch got is visible in how -- long this takes- matched = foldl' step 0 (map (hotp h d k) (range window []))+ matched = L.foldl' step 0 (map (hotp h d k) (range window [])) step acc candidate = acc .|. eqMask candidate otp timeToCounter :: Word64 -> Word64 -> Word16 -> Word64
@@ -1,5 +1,4 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MagicHash #-} {-# LANGUAGE ScopedTypeVariables #-} -- |@@ -31,7 +30,6 @@ import Data.Word import Foreign.Ptr import Foreign.Storable-import GHC.Ptr import Crypto.Error import Crypto.Internal.ByteArray (@@ -114,20 +112,19 @@ $ \result -> withByteArray sec $ \psec -> withByteArray pub $ \ppub ->- ccrypton_curve25519 result psec ppub+ ccrypton_x25519 result psec ppub {-# NOINLINE dh #-} -- | Create a public key from a secret key+-- The base point does not go in: where the assembly is built there is a table+-- for this, and it is four to five times less work than multiplying the point+-- 9 the general way. toPublic :: SecretKey -> PublicKey toPublic (SecretKey sec) = PublicKey <$> B.allocAndFreeze 32 $ \result -> withByteArray sec $ \psec ->- ccrypton_curve25519 result psec basePoint- where- basePoint =- Ptr- "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#+ ccrypton_x25519_base result psec {-# NOINLINE toPublic #-} -- | Generate a secret key.@@ -142,12 +139,20 @@ modifyByte :: Ptr Word8 -> Int -> (Word8 -> Word8) -> IO () modifyByte p n f = peekByteOff p n >>= pokeByteOff p n . f -foreign import ccall "crypton_curve25519_donna"- ccrypton_curve25519+foreign import ccall "crypton_x25519"+ ccrypton_x25519 :: Ptr Word8 -- ^ public -> Ptr Word8 -- ^ secret -> Ptr Word8 -- ^ basepoint+ -> IO ()++foreign import ccall "crypton_x25519_base"+ ccrypton_x25519_base+ :: Ptr Word8+ -- ^ public+ -> Ptr Word8+ -- ^ secret -> IO ()
@@ -41,9 +41,12 @@ -- * Signature primitive sign, signWith,+ signDigest,+ signDigestWith, -- * Verification primitive verify,+ verifyDigest, -- * Key pair KeyPair (..),@@ -59,7 +62,7 @@ import Crypto.Internal.Imports import Crypto.Number.Generate import Crypto.Number.ModArithmetic (expFast, expSafe, inverse, inverseSafe)-import Crypto.PubKey.Internal (dsaTruncHash)+import Crypto.PubKey.Internal (dsaTruncHashDigest) import Crypto.Random.Types -- | DSA Public Number, usually embedded in DSA Public Key@@ -194,14 +197,31 @@ -> msg -- ^ message to sign -> Maybe Signature-signWith k pk hashAlg msg = do+signWith k pk hashAlg msg = signDigestWith k pk (hashWith hashAlg msg)++-- | Sign a digest using the private key and an explicit k number.+--+-- The digest's type says which algorithm made it, so this needs nothing else+-- to name one. 'signWith' takes a @hash@ value and never reads it -- it is+-- there to fix the type -- which leaves a caller that is itself polymorphic+-- in the algorithm with nothing to pass.+signDigestWith+ :: HashAlgorithm hash+ => Integer+ -- ^ k random number+ -> PrivateKey+ -- ^ private key+ -> Digest hash+ -- ^ digest of the message to sign+ -> Maybe Signature+signDigestWith k pk digest = do -- k comes from the caller and is only invertible when it is coprime with -- q, which the caller cannot check without knowing q is prime. It is also -- a secret worth as much as the private key, so it is inverted without -- the extended Euclidean algorithm, whose steps follow the bits of what -- it is given kInv <- inverseSafe k q- let hm = dsaTruncHash hashAlg msg q+ let hm = dsaTruncHashDigest digest q r = expSafe g k p `mod` q s = (kInv * (hm + x * r)) `mod` q if r == 0 || s == 0 then Nothing else Just $ Signature r s@@ -214,10 +234,17 @@ sign :: (ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m) => PrivateKey -> hash -> msg -> m Signature-sign pk hashAlg msg = do+sign pk hashAlg msg = signDigest pk (hashWith hashAlg msg)++-- | Sign a digest using the private key. See 'signDigestWith' for why a+-- digest rather than a @hash@ value.+signDigest+ :: (HashAlgorithm hash, MonadRandom m)+ => PrivateKey -> Digest hash -> m Signature+signDigest pk digest = do k <- generateMax q- case signWith k pk hashAlg msg of- Nothing -> sign pk hashAlg msg+ case signDigestWith k pk digest of+ Nothing -> signDigest pk digest Just sig -> return sig where (Params _ _ q) = private_params pk@@ -226,7 +253,13 @@ verify :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> PublicKey -> Signature -> msg -> Bool-verify hashAlg pk (Signature r s) m+verify hashAlg pk sig m = verifyDigest pk sig (hashWith hashAlg m)++-- | Verify a signature over a digest. See 'signDigestWith' for why a digest+-- rather than a @hash@ value.+verifyDigest+ :: HashAlgorithm hash => PublicKey -> Signature -> Digest hash -> Bool+verifyDigest pk (Signature r s) digest -- Reject the signature if either 0 < r < q or 0 < s < q is not satisfied. | r <= 0 || r >= q || s <= 0 || s >= q = False -- s is invertible for every 0 < s < q when q is prime, but the parameters@@ -235,7 +268,7 @@ where (Params p g q) = public_params pk y = public_y pk- hm = dsaTruncHash hashAlg m q+ hm = dsaTruncHashDigest digest q v = do w <- inverse s q let u1 = (hm * w) `mod` q
@@ -413,8 +413,6 @@ foreign import ccall "crypton_p256e_scalar_invert" ccrypton_p256e_scalar_invert :: Ptr P256Scalar -> Ptr P256Scalar -> IO () --- foreign import ccall "crypton_p256_modinv"--- ccrypton_p256_modinv :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO () foreign import ccall "crypton_p256_modinv_vartime" ccrypton_p256_modinv_vartime :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
@@ -48,6 +48,11 @@ signDigest, verify, verifyDigest,++ -- * Deterministic nonces+ deterministicNonce,+ signDeterministic,+ signDigestDeterministic, ) where import Control.Monad@@ -58,8 +63,10 @@ import Crypto.Hash import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess) import Crypto.Internal.Imports-import Crypto.Number.ModArithmetic (inverseFermat)+import Crypto.Number.Generate (generatePrefix)+import Crypto.Number.ModArithmetic (inverseSafe) import qualified Crypto.PubKey.ECC.P256 as P256+import Crypto.Random.HmacDRG (initial, update) import Crypto.Random.Types import Data.Bits@@ -257,6 +264,75 @@ verify prx hashAlg q sig msg = verifyDigest prx q sig (hashWith hashAlg msg) -- | Truncate a digest based on curve order size.+-- | Deterministic nonce generation according to RFC 6979.+--+-- The nonce is derived from the private key and the message alone, so a+-- signature made this way needs no random number generator and cannot be the+-- one that repeats a nonce -- which, for ECDSA, hands over the private key.+--+-- The hash used to seed the generator is given separately from the one the+-- message was digested with, as RFC 6979 allows.+--+-- The last argument is what to do with a candidate nonce. It may answer+-- 'Nothing', in which case another candidate is drawn, which is what+-- 'signDigestDeterministic' does for the r or s that comes out zero:+--+-- > deterministicNonce prx SHA256 priv digest (\k -> signDigestWith prx k priv digest)+deterministicNonce+ :: (EllipticCurveECDSA curve, HashAlgorithm hashDRG, HashAlgorithm hashDigest)+ => proxy curve+ -> hashDRG+ -> PrivateKey curve+ -> Digest hashDigest+ -> (Scalar curve -> Maybe a)+ -> a+deterministicNonce prx alg d digest go = fst $ withDRG state run+ where+ state = update seed $ initial alg+ -- RFC 6979 section 3.2 step d: int2octets(x) || bits2octets(h1). The+ -- second is the truncated digest taken modulo the order, which is what+ -- scalarAdd with zero does, its contract being to reduce there.+ seed =+ B.append (encodeScalar prx d) (encodeScalar prx z)+ :: B.ScrubbedBytes+ z = scalarAdd prx (tHashDigest prx digest) zeroScalar+ zeroScalar = throwCryptoError $ scalarFromInteger prx 0+ run = do+ k <- generatePrefix (curveOrderBits prx)+ case scalarFromInteger prx k of+ CryptoPassed s+ | scalarIsValid prx s -> maybe run pure (go s)+ _ -> run++-- | Sign a digest with a nonce derived from the private key and the digest,+-- as RFC 6979 says, rather than from a random number generator.+signDigestDeterministic+ :: (EllipticCurveECDSA curve, HashAlgorithm hashDRG, HashAlgorithm hashDigest)+ => proxy curve+ -> hashDRG+ -> PrivateKey curve+ -> Digest hashDigest+ -> Signature curve+signDigestDeterministic prx alg d digest =+ deterministicNonce prx alg d digest $ \k -> signDigestWith prx k d digest++-- | Sign a message with a nonce derived from the private key and the message,+-- as RFC 6979 says, rather than from a random number generator.+signDeterministic+ :: ( EllipticCurveECDSA curve+ , HashAlgorithm hashDRG+ , HashAlgorithm hash+ , ByteArrayAccess msg+ )+ => proxy curve+ -> hashDRG+ -> PrivateKey curve+ -> hash+ -> msg+ -> Signature curve+signDeterministic prx alg d hashAlg msg =+ signDigestDeterministic prx alg d (hashWith hashAlg msg)+ tHashDigest :: (EllipticCurveECDSA curve, HashAlgorithm hash) => proxy curve -> Digest hash -> Scalar curve@@ -296,15 +372,16 @@ => Simple.Scalar curve -> Bool ecScalarIsZero (Simple.Scalar a) = a == 0 +-- | 'inverseSafe' is the one that takes a fixed number of division steps+-- where the assembly for them is built, and checks whatever it gets by+-- multiplying out. It answers 'Nothing' exactly where the exponentiation+-- this used to do answered zero. ecScalarInv :: Simple.Curve c => proxy c -> Simple.Scalar c -> Maybe (Simple.Scalar c)-ecScalarInv prx (Simple.Scalar s)- | i == 0 = Nothing- | otherwise = Just $ Simple.Scalar i+ecScalarInv prx (Simple.Scalar s) = Simple.Scalar <$> inverseSafe s n where n = Simple.curveEccN $ Simple.curveParameters prx- i = inverseFermat s n ecPointX :: Simple.Curve c
@@ -57,10 +57,13 @@ -- * Signature primitives signWith,+ signDigestWith, sign,+ signDigest, -- * Verification primitives verify,+ verifyDigest, ) where import Crypto.Error@@ -194,8 +197,28 @@ -> msg -- ^ message to sign -> Maybe Signature-signWith = signWithBlinder 1+signWith k params priv hashAlg msg =+ signDigestWith k params priv (hashWith hashAlg msg) +-- | Sign a digest with an explicit ephemeral value.+--+-- The digest's type says which algorithm made it, so this needs nothing else+-- to name one. 'signWith' takes a @hash@ value and never reads it -- it is+-- there to fix the type -- which leaves a caller that is itself polymorphic+-- in the algorithm with nothing to pass.+signDigestWith+ :: HashAlgorithm hash+ => Integer+ -- ^ ephemeral value k, in [1, p-2] and coprime with p-1+ -> Params+ -- ^ DH params (p,g)+ -> PrivateNumber+ -- ^ DH private key+ -> Digest hash+ -- ^ digest of the message to sign+ -> Maybe Signature+signDigestWith = signWithBlinder 1+ -- | The same with a blinder for the inversion of @k@. -- -- @k@ is inverted modulo @p-1@, which is even, so Fermat's little theorem@@ -210,15 +233,15 @@ -- When @b@ shares a factor with @p-1@ the algorithm reports it the same way -- it reports one in @k@, and the answer is the same: draw again. signWithBlinder- :: (ByteArrayAccess msg, HashAlgorithm hash)- => Integer -> Integer -> Params -> PrivateNumber -> hash -> msg -> Maybe Signature-signWithBlinder b k (Params p g _) (PrivateNumber x) hashAlg msg+ :: HashAlgorithm hash+ => Integer -> Integer -> Params -> PrivateNumber -> Digest hash -> Maybe Signature+signWithBlinder b k (Params p g _) (PrivateNumber x) digest | k <= 0 || k >= p - 1 || b <= 0 || d > 1 = Nothing | s == 0 = Nothing | otherwise = Just $ Signature r s where r = expSafe g k p- h = os2ip $ hashWith hashAlg msg+ h = os2ip digest s = ((h - x * r) * kInv) `mod` (p - 1) kInv = (kbInv * b) `mod` (p - 1) (kbInv, _, d) = gcde ((k * b) `mod` (p - 1)) (p - 1)@@ -239,13 +262,20 @@ -> msg -- ^ message to sign -> m Signature-sign params@(Params p _ _) priv hashAlg msg = do+sign params priv hashAlg msg = signDigest params priv (hashWith hashAlg msg)++-- | Sign a digest, drawing the ephemeral value. See 'signDigestWith' for+-- why a digest rather than a @hash@ value.+signDigest+ :: (HashAlgorithm hash, MonadRandom m)+ => Params -> PrivateNumber -> Digest hash -> m Signature+signDigest params@(Params p _ _) priv digest = do k <- generateMax (p - 1) -- and a blinder for the inversion of k, which is the one step here that -- the extended Euclidean algorithm has to do b <- generateMax (p - 1)- case signWithBlinder b k params priv hashAlg msg of- Nothing -> sign params priv hashAlg msg+ case signWithBlinder b k params priv digest of+ Nothing -> signDigest params priv digest Just sig -> return sig -- | verify a signature@@ -257,10 +287,18 @@ -> msg -> Signature -> Bool-verify (Params p g _) (PublicNumber y) hashAlg msg (Signature r s)+verify params pub hashAlg msg sig =+ verifyDigest params pub (hashWith hashAlg msg) sig++-- | Verify a signature over a digest. See 'signDigestWith' for why a digest+-- rather than a @hash@ value.+verifyDigest+ :: HashAlgorithm hash+ => Params -> PublicNumber -> Digest hash -> Signature -> Bool+verifyDigest (Params p g _) (PublicNumber y) digest (Signature r s) | or [r <= 0, r >= p, s <= 0, s >= (p - 1)] = False | otherwise = lhs == rhs where- h = os2ip $ hashWith hashAlg msg+ h = os2ip digest lhs = expFast g h p rhs = (expFast y r p * expFast r s p) `mod` p
@@ -12,8 +12,7 @@ ) where import Data.Bits (shiftR)-import Data.List (foldl')-import Prelude hiding (foldl')+import qualified Data.List as L import Crypto.Hash import Crypto.Internal.ByteArray (ByteArrayAccess)@@ -22,7 +21,7 @@ -- | This is a strict version of and and' :: [Bool] -> Bool-and' l = foldl' (&&!) True l+and' l = L.foldl' (&&!) True l -- | This is a strict version of &&. (&&!) :: Bool -> Bool -> Bool
@@ -0,0 +1,656 @@+-- |+-- Module : Crypto.PubKey.MLDSA+-- License : BSD-style+-- Maintainer : Kazu Yamamoto <kazu@iij.ad.jp>+-- Stability : experimental+-- Portability : unknown+--+-- ML-DSA, the Module-Lattice-Based Digital Signature Algorithm of+-- <https://csrc.nist.gov/pubs/fips/204/final FIPS 204>, in all three+-- parameter sets.+--+-- > (vk, sk) <- generateKeyPair MLDSA65+-- > sig <- sign sk emptyContext message+-- > verify vk emptyContext message sig+--+-- What 'generateKeyPair' and 'sign' draw their randomness from is the+-- 'Crypto.Random.MonadRandom' instance in use. Its documentation says what+-- an instance of your own has to be.+--+-- The parameter set is a type, so an ML-DSA-65 key cannot be passed where+-- an ML-DSA-87 one is expected. The three are fixed by FIPS 204 and the+-- class has no other instances.+--+-- This is pure ML-DSA: the message goes in whole. The pre-hash variant+-- (HashML-DSA) is a different algorithm with a different domain separator+-- and is not offered here.+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Crypto.PubKey.MLDSA (+ -- * Parameter sets+ MLDSA44 (..),+ MLDSA65 (..),+ MLDSA87 (..),+ MLDSA (verificationKeySize, signingKeySize, signatureSize),++ -- * Keys and signatures+ VerificationKey,+ SigningKey,+ Signature,++ -- * Smart constructors+ verificationKey,+ signingKey,+ signature,++ -- * Generating a key pair+ generateKeyPair,+ generateKeyPairAndSeed,+ keyPairFromSeed,+ toPublic,++ -- * The context string+ Context,+ context,+ emptyContext,++ -- * The message representative+ Mu,+ mu,+ messageRepresentative,++ -- ** A message that does not arrive in one piece+ MuContext,+ muInit,+ muUpdate,+ muUpdates,+ muFinalize,++ -- * Signing and verifying+ sign,+ signWith,+ signDeterministic,+ verify,++ -- * Signing and verifying a message representative+ signExternalMu,+ signExternalMuWith,+ signExternalMuDeterministic,+ verifyExternalMu,++ -- * Sizes+ seedSize,+ signingRandomnessSize,+ maxContextLength,+ muSize,+) where++import Data.Proxy (Proxy (..))+import Foreign.C.Types (CInt (..), CSize (..))+import Foreign.Ptr (Ptr, nullPtr)++import Crypto.Debug (DebugShow (..), debugShowBytes)+import Crypto.Hash (Digest, hash, hashFinalize, hashInit, hashUpdate, hashUpdates)+import qualified Crypto.Hash as Hash (Context)+import Crypto.Hash.Algorithms (SHAKE256 (..))+import Crypto.Error+import Crypto.Internal.ByteArray (+ ByteArrayAccess,+ Bytes,+ ScrubbedBytes,+ withByteArray,+ )+import qualified Crypto.Internal.ByteArray as B+import Crypto.Internal.Compat (unsafeDoIO)+import Crypto.Internal.Imports+import Crypto.Random (MonadRandom, getRandomBytes)++-- | ML-DSA-44.+data MLDSA44 = MLDSA44 deriving (Show, Eq)++-- | ML-DSA-65.+data MLDSA65 = MLDSA65 deriving (Show, Eq)++-- | ML-DSA-87.+data MLDSA87 = MLDSA87 deriving (Show, Eq)++-- | The three parameter sets of FIPS 204.+--+-- Named for the algorithm rather than \"DSA\", which is a different one that+-- crypton also has, in "Crypto.PubKey.DSA". It is the three sets FIPS 204+-- defines, closed, carrying their sizes and the calls into the+-- implementation; only the sizes are exported.+class MLDSA p where+ -- | Size in bytes of a 'VerificationKey' of this parameter set.+ verificationKeySize :: proxy p -> Int++ -- | Size in bytes of a 'SigningKey' of this parameter set.+ signingKeySize :: proxy p -> Int++ -- | Size in bytes of a 'Signature' of this parameter set.+ signatureSize :: proxy p -> Int++ c_keypair :: proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+ c_sign+ :: proxy p+ -> Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> CSize+ -> Ptr Word8 -> Ptr Word8 -> CInt -> IO CInt+ c_verify+ :: proxy p+ -> Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> CSize+ -> Ptr Word8 -> CInt -> IO CInt+ c_pkFromSk :: proxy p -> Ptr Word8 -> Ptr Word8 -> IO CInt++-- | A public verification key.+newtype VerificationKey p = VerificationKey Bytes+ deriving (Show, Eq, ByteArrayAccess, NFData)++-- | A private signing key.+newtype SigningKey p = SigningKey ScrubbedBytes+ deriving (Eq, ByteArrayAccess, NFData)++instance Show (SigningKey p) where+ show _ = "SigningKey <redacted>"++instance DebugShow (SigningKey p) where+ debugShow = debugShowBytes "SigningKey"++-- | A signature.+newtype Signature p = Signature Bytes+ deriving (Show, Eq, ByteArrayAccess, NFData)++-- | The context string a signature is bound to, at most+-- 'maxContextLength' bytes.+--+-- FIPS 204 mixes it into what is signed, so a signature made under one+-- context does not verify under another. Two uses of one key that don't+-- agree on a context string cannot be made to accept each other's+-- signatures. Use 'emptyContext' where there is nothing to separate -- TLS,+-- for one, signs with an empty context.+newtype Context = Context Bytes+ deriving (Show, Eq, ByteArrayAccess, NFData)++-- | The context string of length zero, which is what to sign under when+-- there is nothing to separate.+--+-- It is a context and not the absence of one: 'sign' always takes one, and+-- what this separates from is every non-empty context there is.+emptyContext :: Context+emptyContext = Context B.empty++-- | Try to build a context string.+context :: ByteArrayAccess ba => ba -> CryptoFailable Context+context bs+ | B.length bs <= maxContextLength =+ CryptoPassed $ Context $ B.copyAndFreeze bs (\_ -> return ())+ | otherwise = CryptoFailed CryptoError_ParameterInvalid++-- | The longest context string FIPS 204 allows, which is 255 bytes because+-- its length is encoded in one byte.+maxContextLength :: Int+maxContextLength = 255++-- | The message representative, @mu@ in FIPS 204: a 64-byte commitment to+-- the verification key, the context string and the message, and the only+-- part of them that signing and verification actually read.+--+-- Signing it directly is the "external mu" interface. It is for a caller+-- that has the representative without having the message in one piece: a+-- message arriving as a stream, or hashed on another machine, or by a+-- device that holds the key and is handed only this. TLS does not need it.+newtype Mu = Mu Bytes+ deriving (Show, Eq, ByteArrayAccess, NFData)++-- | Size in bytes of a 'Mu'.+muSize :: Int+muSize = 64++-- | Try to read a message representative.+mu :: ByteArrayAccess ba => ba -> CryptoFailable Mu+mu bs+ | B.length bs == muSize = CryptoPassed $ Mu $ B.copyAndFreeze bs (\_ -> return ())+ | otherwise = CryptoFailed CryptoError_ParameterInvalid++-- | Compute the message representative, for a caller that wants to make it+-- here and sign it later, or sign it elsewhere.+--+-- @'signExternalMuDeterministic' sk ('messageRepresentative' ('toPublic' sk) ctx msg)@+-- and @'signDeterministic' sk ctx msg@ are the same signature.+messageRepresentative+ :: (MLDSA p, ByteArrayAccess msg)+ => VerificationKey p -> Context -> msg -> Mu+messageRepresentative vk ctx msg = muFinalize (muUpdate (muInit vk ctx) msg)++-- | A 'Mu' being computed, with the message going in a piece at a time.+--+-- The name is not 'Context': that is ML-DSA's context string, which this+-- is built from and is not.+newtype MuContext = MuContext (Hash.Context (SHAKE256 512))++-- | Begin a message representative. The key and the context string are+-- what it is bound to, and they are all that is needed before the message.+--+-- > muFinalize (muUpdates (muInit vk ctx) chunks)+--+-- is 'messageRepresentative' of the chunks joined, so a message too large+-- to hold at once never has to be.+muInit :: MLDSA p => VerificationKey p -> Context -> MuContext+muInit vk ctx =+ -- FIPS 204: tr <- H(pk, 64) at key generation, and mu <- H(tr || M', 64)+ -- when signing, with M' the domain-separated message. Everything up to+ -- the message itself is absorbed here.+ MuContext $ hashUpdates hashInit [tr, domainPrefix ctx]+ where+ tr = B.convert (shake64 (B.convert vk :: Bytes)) :: Bytes++-- | Absorb a piece of the message.+muUpdate :: ByteArrayAccess msg => MuContext -> msg -> MuContext+muUpdate (MuContext c) msg = MuContext (hashUpdate c msg)++-- | Absorb several pieces, which is 'muUpdate' one after the other.+muUpdates :: ByteArrayAccess msg => MuContext -> [msg] -> MuContext+muUpdates (MuContext c) msgs = MuContext (hashUpdates c msgs)++-- | The message representative of everything absorbed so far.+muFinalize :: MuContext -> Mu+muFinalize (MuContext c) = Mu (B.convert (hashFinalize c :: Digest (SHAKE256 512)))++shake64 :: ByteArrayAccess ba => ba -> Digest (SHAKE256 512)+shake64 = hash++-- | Size in bytes of the seed 'keyPairFromSeed' takes, @xi@ in FIPS 204.+seedSize :: Int+seedSize = 32++-- | Size in bytes of the randomness 'signWith' takes.+signingRandomnessSize :: Int+signingRandomnessSize = 32++-- | Try to read a verification key. Only the length is checked: a+-- verification key is a packed encoding with no redundancy to test, and one+-- that is not a real key simply verifies nothing.+verificationKey+ :: forall p ba+ . (MLDSA p, ByteArrayAccess ba)+ => ba -> CryptoFailable (VerificationKey p)+verificationKey bs+ | B.length bs == verificationKeySize (Proxy :: Proxy p) =+ CryptoPassed $ VerificationKey $ B.copyAndFreeze bs (\_ -> return ())+ | otherwise = CryptoFailed CryptoError_PublicKeySizeInvalid++-- | Try to read a signing key.+--+-- Beyond the length this runs the validity checks of the implementation:+-- the secret polynomials must have coefficients in range, and the+-- commitment and the public-key hash the key carries must match what is+-- recomputed from the rest of it. A key that fails has been damaged or was+-- never a key, and signing with it would produce signatures nothing+-- verifies.+signingKey+ :: forall p ba+ . (MLDSA p, ByteArrayAccess ba)+ => ba -> CryptoFailable (SigningKey p)+signingKey bs+ | B.length bs /= signingKeySize p = CryptoFailed CryptoError_SecretKeySizeInvalid+ | otherwise = unsafeDoIO $ do+ (r, _ :: Bytes) <- B.allocRet (verificationKeySize p) $ \ppk ->+ withByteArray bs $ \psk -> c_pkFromSk p ppk psk+ return $+ if r == 0+ then CryptoPassed $ SigningKey $ B.copyAndFreeze bs (\_ -> return ())+ else CryptoFailed CryptoError_SecretKeyStructureInvalid+ where+ p = Proxy :: Proxy p+{-# NOINLINE signingKey #-}++-- | Try to read a signature. Only the length is checked; whether it is a+-- signature of anything is what 'verify' answers.+signature+ :: forall p ba+ . (MLDSA p, ByteArrayAccess ba)+ => ba -> CryptoFailable (Signature p)+signature bs+ | B.length bs == signatureSize (Proxy :: Proxy p) =+ CryptoPassed $ Signature $ B.copyAndFreeze bs (\_ -> return ())+ | otherwise = CryptoFailed CryptoError_ParameterInvalid++-- | Recover the verification key a signing key was made with.+toPublic :: forall p. MLDSA p => SigningKey p -> VerificationKey p+toPublic sk = VerificationKey $ unsafeDoIO $ do+ (_ :: CInt, pk) <- B.allocRet (verificationKeySize p) $ \ppk ->+ withByteArray sk $ \psk -> c_pkFromSk p ppk psk+ return pk+ where+ p = Proxy :: Proxy p+{-# NOINLINE toPublic #-}++-- | Generate a key pair.+--+-- The seed it is derived from is drawn here and thrown away. Use+-- 'generateKeyPairAndSeed' where it has to be kept.+generateKeyPair+ :: forall p proxy m+ . (MLDSA p, MonadRandom m)+ => proxy p -> m (VerificationKey p, SigningKey p)+generateKeyPair p = do+ (vk, sk, _) <- generateKeyPairAndSeed p+ return (vk, sk)++-- | Generate a key pair and hand back the seed it was derived from, @xi@+-- in FIPS 204.+--+-- A 'SigningKey' is the expanded key and nothing else, so the seed cannot+-- be recovered from a pair afterwards. An application that has to write+-- the key out in a form that keeps the seed -- RFC 9881 lets an ML-DSA+-- private key be the seed, the expanded key, or both -- has to generate it+-- here:+--+-- > (vk, sk, seed) <- generateKeyPairAndSeed MLDSA65+--+-- The seed is as secret as the signing key: 'keyPairFromSeed' turns it+-- back into the same pair.+generateKeyPairAndSeed+ :: forall p proxy m+ . (MLDSA p, MonadRandom m)+ => proxy p -> m (VerificationKey p, SigningKey p, ScrubbedBytes)+generateKeyPairAndSeed p = do+ seed <- getRandomBytes seedSize :: m ScrubbedBytes+ case keyPairFromSeed p seed of+ CryptoPassed (vk, sk) -> return (vk, sk, seed)+ CryptoFailed e ->+ error ("Crypto.PubKey.MLDSA.generateKeyPairAndSeed: " ++ show e)++-- | Derive a key pair from a seed, @xi@ in FIPS 204, which must be+-- 'seedSize' bytes.+keyPairFromSeed+ :: forall p proxy ba+ . (MLDSA p, ByteArrayAccess ba)+ => proxy p -> ba -> CryptoFailable (VerificationKey p, SigningKey p)+keyPairFromSeed p seed+ | B.length seed /= seedSize = CryptoFailed CryptoError_SeedSizeInvalid+ | otherwise = unsafeDoIO $ do+ -- Not zeroed, and does not need to be: the C writes the whole+ -- buffer, and on a non-zero return the result is discarded without+ -- being read. Anything that is *read* before being written has to+ -- use B.zero instead -- see signInternal in Crypto.PubKey.MLDSA.+ sk <- B.alloc (signingKeySize p) (\_ -> return ()) :: IO ScrubbedBytes+ (r, vk) <- B.allocRet (verificationKeySize p) $ \pvk ->+ withByteArray sk $ \psk ->+ withByteArray seed $ \pseed ->+ c_keypair p pvk psk pseed+ return $+ if r == 0+ then CryptoPassed (VerificationKey vk, SigningKey sk)+ else CryptoFailed CryptoError_ParameterInvalid+{-# NOINLINE keyPairFromSeed #-}++-- | Sign a message.+--+-- This is the hedged signing FIPS 204 recommends: fresh randomness goes in+-- alongside the key and the message, so two signatures of one message+-- differ and a fault in one reveals less. Verification does not care which+-- of the three entry points made the signature.+sign+ :: forall p m msg+ . (MLDSA p, MonadRandom m, ByteArrayAccess msg)+ => SigningKey p -> Context -> msg -> m (Signature p)+sign sk ctx msg = do+ rnd <- getRandomBytes signingRandomnessSize :: m ScrubbedBytes+ case signWith sk ctx msg rnd of+ CryptoPassed s -> return s+ CryptoFailed e -> error ("Crypto.PubKey.MLDSA.sign: " ++ show e)++-- | Sign with the randomness supplied, which must be+-- 'signingRandomnessSize' bytes.+--+-- For test vectors, and for callers who draw their own randomness. Ordinary+-- use wants 'sign'.+signWith+ :: forall p msg rnd+ . (MLDSA p, ByteArrayAccess msg, ByteArrayAccess rnd)+ => SigningKey p -> Context -> msg -> rnd -> CryptoFailable (Signature p)+signWith sk ctx msg rnd+ | B.length rnd /= signingRandomnessSize = CryptoFailed CryptoError_SeedSizeInvalid+ | otherwise = signInternal sk ctx msg (Just rnd)++-- | Sign deterministically, as FIPS 204 section 3.4 allows: the randomness+-- is replaced by zeroes, so one key and one message always give one+-- signature.+--+-- This is what test vectors are written against, and what to use where the+-- signature must be reproducible. It gives up what hedging buys, so where+-- there is a usable random source 'sign' is the better default.+signDeterministic+ :: forall p msg+ . (MLDSA p, ByteArrayAccess msg)+ => SigningKey p -> Context -> msg -> Signature p+signDeterministic sk ctx msg =+ case signInternal sk ctx msg (Nothing :: Maybe Bytes) of+ CryptoPassed s -> s+ CryptoFailed e -> error ("Crypto.PubKey.MLDSA.signDeterministic: " ++ show e)++signInternal+ :: forall p msg rnd+ . (MLDSA p, ByteArrayAccess msg, ByteArrayAccess rnd)+ => SigningKey p -> Context -> msg -> Maybe rnd -> CryptoFailable (Signature p)+signInternal sk ctx msg mrnd = unsafeDoIO $ do+ -- B.zero, not B.alloc with an empty action: alloc hands back whatever+ -- was in the memory. That made signDeterministic sign with the last+ -- caller's bytes and produce a different signature every time, which the+ -- ACVP vectors caught only once the whole suite ran and the allocator+ -- stopped handing out fresh zeroed pages.+ let zeroes = B.zero signingRandomnessSize :: ScrubbedBytes+ withRnd f = case mrnd of+ Just r -> withByteArray r f+ Nothing -> withByteArray zeroes f+ (r, sig) <- B.allocRet (signatureSize p) $ \psig ->+ withByteArray msg $ \pmsg ->+ withByteArray pre $ \ppre ->+ withRnd $ \prnd ->+ withByteArray sk $ \psk ->+ c_sign+ p+ psig+ pmsg+ (fromIntegral (B.length msg))+ ppre+ (fromIntegral (B.length pre))+ prnd+ psk+ 0+ return $+ if r == 0+ then CryptoPassed (Signature sig)+ else CryptoFailed CryptoError_ParameterInvalid+ where+ p = Proxy :: Proxy p+ pre = domainPrefix ctx+{-# NOINLINE signInternal #-}++-- | Sign a message representative, drawing the randomness.+--+-- The context string is already inside the representative, which is why+-- this does not take one.+signExternalMu+ :: forall p m+ . (MLDSA p, MonadRandom m)+ => SigningKey p -> Mu -> m (Signature p)+signExternalMu sk m = do+ rnd <- getRandomBytes signingRandomnessSize :: m ScrubbedBytes+ case signExternalMuWith sk m rnd of+ CryptoPassed s -> return s+ CryptoFailed e -> error ("Crypto.PubKey.MLDSA.signExternalMu: " ++ show e)++-- | Sign a message representative with the randomness supplied.+signExternalMuWith+ :: (MLDSA p, ByteArrayAccess rnd)+ => SigningKey p -> Mu -> rnd -> CryptoFailable (Signature p)+signExternalMuWith sk m rnd+ | B.length rnd /= signingRandomnessSize = CryptoFailed CryptoError_SeedSizeInvalid+ | otherwise = signMu sk m (Just rnd)++-- | Sign a message representative deterministically.+signExternalMuDeterministic+ :: MLDSA p => SigningKey p -> Mu -> Signature p+signExternalMuDeterministic sk m =+ case signMu sk m (Nothing :: Maybe Bytes) of+ CryptoPassed s -> s+ CryptoFailed e ->+ error ("Crypto.PubKey.MLDSA.signExternalMuDeterministic: " ++ show e)++-- | Verify a signature of a message representative.+verifyExternalMu+ :: forall p. MLDSA p => VerificationKey p -> Mu -> Signature p -> Bool+verifyExternalMu vk m sig+ | B.length sig /= signatureSize p = False+ | otherwise = unsafeDoIO $+ withByteArray sig $ \psig ->+ withByteArray m $ \pmu ->+ withByteArray vk $ \pvk -> do+ r <-+ c_verify+ p+ psig+ pmu+ (fromIntegral muSize)+ nullPtr+ 0+ pvk+ 1+ return (r == 0)+ where+ p = Proxy :: Proxy p+{-# NOINLINE verifyExternalMu #-}++-- The external-mu entry points are the ordinary ones with the last argument+-- set: the representative goes in where the message would, there is no+-- domain separation prefix to prepend because it is already inside, and the+-- implementation is told so.+signMu+ :: forall p rnd+ . (MLDSA p, ByteArrayAccess rnd)+ => SigningKey p -> Mu -> Maybe rnd -> CryptoFailable (Signature p)+signMu sk m mrnd = unsafeDoIO $ do+ let zeroes = B.zero signingRandomnessSize :: ScrubbedBytes+ withRnd f = case mrnd of+ Just r -> withByteArray r f+ Nothing -> withByteArray zeroes f+ (r, sig) <- B.allocRet (signatureSize p) $ \psig ->+ withByteArray m $ \pmu ->+ withRnd $ \prnd ->+ withByteArray sk $ \psk ->+ c_sign p psig pmu (fromIntegral muSize) nullPtr 0 prnd psk 1+ return $+ if r == 0+ then CryptoPassed (Signature sig)+ else CryptoFailed CryptoError_ParameterInvalid+ where+ p = Proxy :: Proxy p+{-# NOINLINE signMu #-}++-- | Verify a signature.+--+-- The context must be the one it was signed under; anything else is a+-- rejection, which is what the context is for.+verify+ :: forall p msg+ . (MLDSA p, ByteArrayAccess msg)+ => VerificationKey p -> Context -> msg -> Signature p -> Bool+verify vk ctx msg sig+ | B.length sig /= signatureSize p = False+ | otherwise = unsafeDoIO $+ withByteArray sig $ \psig ->+ withByteArray msg $ \pmsg ->+ withByteArray pre $ \ppre ->+ withByteArray vk $ \pvk -> do+ r <-+ c_verify+ p+ psig+ pmsg+ (fromIntegral (B.length msg))+ ppre+ (fromIntegral (B.length pre))+ pvk+ 0+ return (r == 0)+ where+ p = Proxy :: Proxy p+ pre = domainPrefix ctx+{-# NOINLINE verify #-}++-- | The domain separation prefix of FIPS 204 for pure ML-DSA, which is a+-- zero byte, the context's length and the context itself. It is built here+-- rather than taken from the implementation because it is three bytes of+-- concatenation and doing it here keeps one fewer foreign call.+domainPrefix :: Context -> Bytes+domainPrefix (Context ctx) =+ B.concat [B.pack [0, fromIntegral (B.length ctx)] :: Bytes, B.convert ctx]++instance MLDSA MLDSA44 where+ verificationKeySize _ = 1312+ signingKeySize _ = 2560+ signatureSize _ = 2420+ c_keypair _ = c_mldsa44_keypair+ c_sign _ = c_mldsa44_sign+ c_verify _ = c_mldsa44_verify+ c_pkFromSk _ = c_mldsa44_pk_from_sk++instance MLDSA MLDSA65 where+ verificationKeySize _ = 1952+ signingKeySize _ = 4032+ signatureSize _ = 3309+ c_keypair _ = c_mldsa65_keypair+ c_sign _ = c_mldsa65_sign+ c_verify _ = c_mldsa65_verify+ c_pkFromSk _ = c_mldsa65_pk_from_sk++instance MLDSA MLDSA87 where+ verificationKeySize _ = 2592+ signingKeySize _ = 4896+ signatureSize _ = 4627+ c_keypair _ = c_mldsa87_keypair+ c_sign _ = c_mldsa87_sign+ c_verify _ = c_mldsa87_verify+ c_pkFromSk _ = c_mldsa87_pk_from_sk++foreign import ccall unsafe "crypton_mldsa44_keypair_internal"+ c_mldsa44_keypair :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mldsa44_signature_internal"+ c_mldsa44_sign+ :: Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> CSize+ -> Ptr Word8 -> Ptr Word8 -> CInt -> IO CInt+foreign import ccall unsafe "crypton_mldsa44_verify_internal"+ c_mldsa44_verify+ :: Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> CSize+ -> Ptr Word8 -> CInt -> IO CInt+foreign import ccall unsafe "crypton_mldsa44_pk_from_sk"+ c_mldsa44_pk_from_sk :: Ptr Word8 -> Ptr Word8 -> IO CInt++foreign import ccall unsafe "crypton_mldsa65_keypair_internal"+ c_mldsa65_keypair :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mldsa65_signature_internal"+ c_mldsa65_sign+ :: Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> CSize+ -> Ptr Word8 -> Ptr Word8 -> CInt -> IO CInt+foreign import ccall unsafe "crypton_mldsa65_verify_internal"+ c_mldsa65_verify+ :: Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> CSize+ -> Ptr Word8 -> CInt -> IO CInt+foreign import ccall unsafe "crypton_mldsa65_pk_from_sk"+ c_mldsa65_pk_from_sk :: Ptr Word8 -> Ptr Word8 -> IO CInt++foreign import ccall unsafe "crypton_mldsa87_keypair_internal"+ c_mldsa87_keypair :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mldsa87_signature_internal"+ c_mldsa87_sign+ :: Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> CSize+ -> Ptr Word8 -> Ptr Word8 -> CInt -> IO CInt+foreign import ccall unsafe "crypton_mldsa87_verify_internal"+ c_mldsa87_verify+ :: Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> CSize+ -> Ptr Word8 -> CInt -> IO CInt+foreign import ccall unsafe "crypton_mldsa87_pk_from_sk"+ c_mldsa87_pk_from_sk :: Ptr Word8 -> Ptr Word8 -> IO CInt
@@ -0,0 +1,448 @@+-- |+-- Module : Crypto.PubKey.MLKEM+-- License : BSD-style+-- Maintainer : Kazu Yamamoto <kazu@iij.ad.jp>+-- Stability : experimental+-- Portability : unknown+--+-- ML-KEM, the Module-Lattice-Based Key-Encapsulation Mechanism of+-- <https://csrc.nist.gov/pubs/fips/203/final FIPS 203>, in all three+-- parameter sets.+--+-- A key encapsulation mechanism is not a Diffie-Hellman: there is no shared+-- secret to be computed from two key pairs. One side publishes an+-- 'EncapsulationKey'; the other calls 'encapsulate' on it, which draws a+-- fresh secret and returns it along with a 'Ciphertext' that only the holder+-- of the matching 'DecapsulationKey' can turn back into that secret.+--+-- > (ek, dk) <- generateKeyPair MLKEM768 -- the receiver+-- > (ct, ss) <- encapsulate ek -- the sender+-- > let ss' = decapsulate dk ct -- the receiver, again+-- > ss == ss'+--+-- What 'generateKeyPair' and 'encapsulate' draw their randomness from is+-- the 'Crypto.Random.MonadRandom' instance in use. Its documentation says+-- what an instance of your own has to be.+--+-- The parameter set is a type, so an ML-KEM-768 key cannot be passed where+-- an ML-KEM-1024 one is expected. The three are fixed by FIPS 203 and the+-- class has no other instances.+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Crypto.PubKey.MLKEM (+ -- * Parameter sets+ MLKEM512 (..),+ MLKEM768 (..),+ MLKEM1024 (..),+ MLKEM (encapsulationKeySize, decapsulationKeySize, ciphertextSize),++ -- * Keys, ciphertexts and shared secrets+ --+ -- | These are the associated types of 'KEM', re-exported so that a+ -- caller of this module alone has them.+ KEM (..),+ SharedSecret (..),++ -- * Smart constructors+ encapsulationKey,+ decapsulationKey,+ ciphertext,++ -- * What ML-KEM has beyond the class+ generateKeyPairAndSeed,+ keyPairFromSeed,++ -- * Sizes+ seedSize,+ encapsulationCoinsSize,+ sharedSecretSize,+) where++import Data.Proxy (Proxy (..))+import Foreign.C.Types (CInt (..))+import Foreign.Ptr (Ptr)++import Crypto.Debug (DebugShow (..), debugShowBytes)+import Crypto.Error+import Crypto.KEM+import Crypto.Internal.ByteArray (+ ByteArrayAccess,+ Bytes,+ ScrubbedBytes,+ withByteArray,+ )+import qualified Crypto.Internal.ByteArray as B+import Crypto.Internal.Compat (unsafeDoIO)+import Crypto.Internal.Imports+import Crypto.Random (MonadRandom, getRandomBytes)++-- | ML-KEM-512.+data MLKEM512 = MLKEM512 deriving (Show, Eq)++-- | ML-KEM-768. This is the set TLS uses, on its own and as the+-- lattice half of the hybrid groups.+data MLKEM768 = MLKEM768 deriving (Show, Eq)++-- | ML-KEM-1024.+data MLKEM1024 = MLKEM1024 deriving (Show, Eq)++-- | The three parameter sets of FIPS 203.+--+-- This is not an abstract KEM interface and does not try to be: it is the+-- three sets FIPS 203 defines, closed, carrying their sizes and the calls+-- into the implementation. Only the sizes are exported. If crypton grows+-- a second KEM and an interface common to both is wanted, that belongs in+-- a module of its own, with this as one of its instances.+class+ ( KEM p+ , EncapsulationKey p ~ MLKEMEncapsulationKey p+ , DecapsulationKey p ~ MLKEMDecapsulationKey p+ , Ciphertext p ~ MLKEMCiphertext p+ , Coins p ~ ScrubbedBytes+ ) =>+ MLKEM p+ where+ -- | Size in bytes of an 'EncapsulationKey' of this parameter set.+ encapsulationKeySize :: proxy p -> Int++ -- | Size in bytes of a 'DecapsulationKey' of this parameter set.+ decapsulationKeySize :: proxy p -> Int++ -- | Size in bytes of a 'Ciphertext' of this parameter set.+ ciphertextSize :: proxy p -> Int++ c_keypair :: proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+ c_enc :: proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+ c_dec :: proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+ c_checkPk :: proxy p -> Ptr Word8 -> IO CInt+ c_checkSk :: proxy p -> Ptr Word8 -> IO CInt++-- | A public encapsulation key, @ek@ in FIPS 203.+newtype MLKEMEncapsulationKey p = MLKEMEncapsulationKey Bytes+ deriving (Show, Eq, ByteArrayAccess, NFData)++-- | A private decapsulation key, @dk@ in FIPS 203. It embeds the matching+-- encapsulation key, which is why it is the larger of the two.+newtype MLKEMDecapsulationKey p = MLKEMDecapsulationKey ScrubbedBytes+ deriving (Eq, ByteArrayAccess, NFData)++instance Show (MLKEMDecapsulationKey p) where+ show _ = "DecapsulationKey <redacted>"++instance DebugShow (MLKEMDecapsulationKey p) where+ debugShow = debugShowBytes "DecapsulationKey"++-- | The value 'encapsulate' produces and 'decapsulate' consumes.+newtype MLKEMCiphertext p = MLKEMCiphertext Bytes+ deriving (Show, Eq, ByteArrayAccess, NFData)++-- | Size in bytes of the seed 'keyPairFromSeed' takes, which is @d@ and @z@+-- of FIPS 203 one after the other.+seedSize :: Int+seedSize = 64++-- | Size in bytes of the randomness 'encapsulateWith' takes, @m@ in+-- FIPS 203.+encapsulationCoinsSize :: Int+encapsulationCoinsSize = 32++-- | Size in bytes of a 'SharedSecret'.+sharedSecretSize :: Int+sharedSecretSize = 32++-- | Try to read an encapsulation key.+--+-- Beyond the length this runs the check of FIPS 203 section 7.2: the key+-- must be the encoding of coefficients that are all in range, which is to+-- say it must survive a decode and re-encode unchanged. A key that fails+-- it is not one any honest party produced.+encapsulationKey+ :: forall p ba+ . (MLKEM p, ByteArrayAccess ba)+ => ba -> CryptoFailable (EncapsulationKey p)+encapsulationKey bs+ | B.length bs /= encapsulationKeySize p = CryptoFailed CryptoError_PublicKeySizeInvalid+ | otherwise = unsafeDoIO $ withByteArray bs $ \inp -> do+ r <- c_checkPk p inp+ return $+ if r == 0+ then CryptoPassed $ MLKEMEncapsulationKey $ B.copyAndFreeze bs (\_ -> return ())+ else CryptoFailed CryptoError_PublicKeyStructureInvalid+ where+ p = Proxy :: Proxy p+{-# NOINLINE encapsulationKey #-}++-- | Try to read a decapsulation key.+--+-- Beyond the length this runs the check of FIPS 203 section 7.3: the hash+-- of the encapsulation key the private key embeds must match the copy of+-- that hash it also embeds. The two disagreeing means the key was not+-- produced as a pair, and decapsulating with it would silently answer with+-- the implicit rejection every time.+decapsulationKey+ :: forall p ba+ . (MLKEM p, ByteArrayAccess ba)+ => ba -> CryptoFailable (DecapsulationKey p)+decapsulationKey bs+ | B.length bs /= decapsulationKeySize p = CryptoFailed CryptoError_SecretKeySizeInvalid+ | otherwise = unsafeDoIO $ withByteArray bs $ \inp -> do+ r <- c_checkSk p inp+ return $+ if r == 0+ then CryptoPassed $ MLKEMDecapsulationKey $ B.copyAndFreeze bs (\_ -> return ())+ else CryptoFailed CryptoError_SecretKeyStructureInvalid+ where+ p = Proxy :: Proxy p+{-# NOINLINE decapsulationKey #-}++-- | Try to read a ciphertext. Only the length is checked; every string of+-- the right length is a ciphertext that 'decapsulate' will answer.+ciphertext+ :: forall p ba+ . (MLKEM p, ByteArrayAccess ba)+ => ba -> CryptoFailable (Ciphertext p)+ciphertext bs+ | B.length bs == ciphertextSize (Proxy :: Proxy p) =+ CryptoPassed $ MLKEMCiphertext $ B.copyAndFreeze bs (\_ -> return ())+ | otherwise = CryptoFailed CryptoError_PointSizeInvalid++-- | Generate a key pair.+--+-- The seed it is derived from is drawn here and thrown away. Use+-- 'generateKeyPairAndSeed' where it has to be kept.+mlkemGenerateKeyPair+ :: forall p proxy m+ . (MLKEM p, MonadRandom m)+ => proxy p -> m (MLKEMEncapsulationKey p, DecapsulationKey p)+mlkemGenerateKeyPair p = do+ (ek, dk, _) <- generateKeyPairAndSeed p+ return (ek, dk)++-- | Generate a key pair and hand back the seed it was derived from, @d@+-- and @z@ of FIPS 203 one after the other.+--+-- A 'DecapsulationKey' is the expanded key and nothing else, so the seed+-- cannot be recovered from a pair afterwards. An application that has to+-- write the key out in a form that keeps the seed has to generate it here:+--+-- > (ek, dk, seed) <- generateKeyPairAndSeed MLKEM768+--+-- The seed is as secret as the decapsulation key: 'keyPairFromSeed' turns+-- it back into the same pair.+generateKeyPairAndSeed+ :: forall p proxy m+ . (MLKEM p, MonadRandom m)+ => proxy p+ -> m (MLKEMEncapsulationKey p, DecapsulationKey p, ScrubbedBytes)+generateKeyPairAndSeed p = do+ seed <- getRandomBytes seedSize :: m ScrubbedBytes+ case keyPairFromSeed p seed of+ CryptoPassed (ek, dk) -> return (ek, dk, seed)+ CryptoFailed e ->+ error ("Crypto.PubKey.MLKEM.generateKeyPairAndSeed: " ++ show e)++-- | Derive a key pair from a seed, which is @d@ and @z@ of FIPS 203 one+-- after the other and must be 'seedSize' bytes.+--+-- This is the entry point to use when the seed comes from somewhere+-- particular -- a test vector, or a store that keeps seeds rather than+-- expanded keys. For an ordinary key, 'generateKeyPair' draws the seed+-- itself.+keyPairFromSeed+ :: forall p proxy ba+ . (MLKEM p, ByteArrayAccess ba)+ => proxy p+ -> ba+ -> CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p)+keyPairFromSeed p seed+ | B.length seed /= seedSize = CryptoFailed CryptoError_SeedSizeInvalid+ | otherwise = unsafeDoIO $ do+ -- Not zeroed, and does not need to be: the C writes the whole+ -- buffer, and on a non-zero return the result is discarded without+ -- being read. Anything that is *read* before being written has to+ -- use B.zero instead -- see signInternal in Crypto.PubKey.MLDSA.+ dk <- B.alloc (decapsulationKeySize p) (\_ -> return ()) :: IO ScrubbedBytes+ (r, ek) <- B.allocRet (encapsulationKeySize p) $ \pek ->+ withByteArray dk $ \pdk ->+ withByteArray seed $ \pseed ->+ c_keypair p pek pdk pseed+ return $+ if r == 0+ then CryptoPassed (MLKEMEncapsulationKey ek, MLKEMDecapsulationKey dk)+ else CryptoFailed CryptoError_ParameterInvalid+{-# NOINLINE keyPairFromSeed #-}++-- | Encapsulate against a public key, drawing the randomness.+mlkemEncapsulate+ :: forall p m+ . (MLKEM p, MonadRandom m)+ => MLKEMEncapsulationKey p+ -> m (CryptoFailable (Ciphertext p, SharedSecret))+mlkemEncapsulate ek = do+ coins <- getRandomBytes encapsulationCoinsSize :: m ScrubbedBytes+ return (mlkemEncapsulateWith ek coins)++-- The class's 'encapsulateWith' for ML-KEM, where the coins are @m@ of+-- FIPS 203 and must be 'encapsulationCoinsSize' bytes.+mlkemEncapsulateWith+ :: forall p+ . MLKEM p+ => MLKEMEncapsulationKey p+ -> ScrubbedBytes+ -> CryptoFailable (Ciphertext p, SharedSecret)+mlkemEncapsulateWith ek coins+ | B.length coins /= encapsulationCoinsSize = CryptoFailed CryptoError_SeedSizeInvalid+ | otherwise = unsafeDoIO $ do+ ss <- B.alloc sharedSecretSize (\_ -> return ()) :: IO ScrubbedBytes+ (r, ct) <- B.allocRet (ciphertextSize p) $ \pct ->+ withByteArray ss $ \pss ->+ withByteArray ek $ \pek ->+ withByteArray coins $ \pcoins ->+ c_enc p pct pss pek pcoins+ return $+ if r == 0+ then CryptoPassed (MLKEMCiphertext ct, SharedSecret ss)+ else CryptoFailed CryptoError_ParameterInvalid+ where+ p = Proxy :: Proxy p+{-# NOINLINE mlkemEncapsulateWith #-}++-- | Recover the shared secret from a ciphertext.+--+-- A ciphertext that was not produced by encapsulating against the matching+-- key is not an error. ML-KEM rejects implicitly: it yields a secret+-- derived from the private key and the ciphertext, and the caller cannot+-- tell that case from the other one, which is the point -- telling them+-- apart is what a chosen-ciphertext attack needs. A ciphertext that does+-- not belong here shows up later, as the two sides failing to agree on+-- anything.+--+-- The checks FIPS 203 does require are at the point where bytes become a+-- value of these types, which is where they can be reported:+--+-- * The ciphertext type check of section 7.3 is its length, and+-- 'ciphertext' is the only way to build a 'Ciphertext' from bytes. There+-- is nothing else to check: a ciphertext's coefficients are compressed to+-- fewer than twelve bits, so every bit pattern decodes to a value in+-- range.+-- * The hash check of section 7.3 is on the decapsulation key, and+-- 'decapsulationKey' runs it; a key from 'generateKeyPair' or+-- 'keyPairFromSeed' satisfies it by construction.+--+-- So the result is 'CryptoPassed' for every key and ciphertext this module+-- can produce. It is 'CryptoFailable' rather than a bare 'SharedSecret'+-- because the implementation checks the key again on its way through, and+-- what it finds is better reported than turned into an exception.+mlkemDecapsulate+ :: forall p+ . MLKEM p+ => DecapsulationKey p -> Ciphertext p -> CryptoFailable SharedSecret+mlkemDecapsulate dk ct = unsafeDoIO $ do+ (r, ss) <- B.allocRet sharedSecretSize $ \pss ->+ withByteArray ct $ \pct ->+ withByteArray dk $ \pdk ->+ c_dec (Proxy :: Proxy p) pss pct pdk+ return $+ if r == (0 :: CInt)+ then CryptoPassed (SharedSecret ss)+ else CryptoFailed CryptoError_SecretKeyStructureInvalid+{-# NOINLINE mlkemDecapsulate #-}++-- The class's view of the three sets. The operations are the ones above;+-- only the shape of the arguments differs, because the class takes the+-- mechanism as a proxy.+instance KEM MLKEM512 where+ type EncapsulationKey MLKEM512 = MLKEMEncapsulationKey MLKEM512+ type DecapsulationKey MLKEM512 = MLKEMDecapsulationKey MLKEM512+ type Ciphertext MLKEM512 = MLKEMCiphertext MLKEM512+ type Coins MLKEM512 = ScrubbedBytes+ generateKeyPair = mlkemGenerateKeyPair+ encapsulate _ = mlkemEncapsulate+ encapsulateWith _ = mlkemEncapsulateWith+ decapsulate _ = mlkemDecapsulate++instance KEM MLKEM768 where+ type EncapsulationKey MLKEM768 = MLKEMEncapsulationKey MLKEM768+ type DecapsulationKey MLKEM768 = MLKEMDecapsulationKey MLKEM768+ type Ciphertext MLKEM768 = MLKEMCiphertext MLKEM768+ type Coins MLKEM768 = ScrubbedBytes+ generateKeyPair = mlkemGenerateKeyPair+ encapsulate _ = mlkemEncapsulate+ encapsulateWith _ = mlkemEncapsulateWith+ decapsulate _ = mlkemDecapsulate++instance KEM MLKEM1024 where+ type EncapsulationKey MLKEM1024 = MLKEMEncapsulationKey MLKEM1024+ type DecapsulationKey MLKEM1024 = MLKEMDecapsulationKey MLKEM1024+ type Ciphertext MLKEM1024 = MLKEMCiphertext MLKEM1024+ type Coins MLKEM1024 = ScrubbedBytes+ generateKeyPair = mlkemGenerateKeyPair+ encapsulate _ = mlkemEncapsulate+ encapsulateWith _ = mlkemEncapsulateWith+ decapsulate _ = mlkemDecapsulate++instance MLKEM MLKEM512 where+ encapsulationKeySize _ = 800+ decapsulationKeySize _ = 1632+ ciphertextSize _ = 768+ c_keypair _ = c_mlkem512_keypair+ c_enc _ = c_mlkem512_enc+ c_dec _ = c_mlkem512_dec+ c_checkPk _ = c_mlkem512_check_pk+ c_checkSk _ = c_mlkem512_check_sk++instance MLKEM MLKEM768 where+ encapsulationKeySize _ = 1184+ decapsulationKeySize _ = 2400+ ciphertextSize _ = 1088+ c_keypair _ = c_mlkem768_keypair+ c_enc _ = c_mlkem768_enc+ c_dec _ = c_mlkem768_dec+ c_checkPk _ = c_mlkem768_check_pk+ c_checkSk _ = c_mlkem768_check_sk++instance MLKEM MLKEM1024 where+ encapsulationKeySize _ = 1568+ decapsulationKeySize _ = 3168+ ciphertextSize _ = 1568+ c_keypair _ = c_mlkem1024_keypair+ c_enc _ = c_mlkem1024_enc+ c_dec _ = c_mlkem1024_dec+ c_checkPk _ = c_mlkem1024_check_pk+ c_checkSk _ = c_mlkem1024_check_sk++foreign import ccall unsafe "crypton_mlkem512_keypair_derand"+ c_mlkem512_keypair :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem512_enc_derand"+ c_mlkem512_enc :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem512_dec"+ c_mlkem512_dec :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem512_check_pk"+ c_mlkem512_check_pk :: Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem512_check_sk"+ c_mlkem512_check_sk :: Ptr Word8 -> IO CInt++foreign import ccall unsafe "crypton_mlkem768_keypair_derand"+ c_mlkem768_keypair :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem768_enc_derand"+ c_mlkem768_enc :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem768_dec"+ c_mlkem768_dec :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem768_check_pk"+ c_mlkem768_check_pk :: Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem768_check_sk"+ c_mlkem768_check_sk :: Ptr Word8 -> IO CInt++foreign import ccall unsafe "crypton_mlkem1024_keypair_derand"+ c_mlkem1024_keypair :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem1024_enc_derand"+ c_mlkem1024_enc :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem1024_dec"+ c_mlkem1024_dec :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem1024_check_pk"+ c_mlkem1024_check_pk :: Ptr Word8 -> IO CInt+foreign import ccall unsafe "crypton_mlkem1024_check_sk"+ c_mlkem1024_check_sk :: Ptr Word8 -> IO CInt
@@ -1,4 +1,4 @@-{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ScopedTypeVariables #-} -- | -- Module : Crypto.PubKey.MaskGenFunction@@ -11,10 +11,17 @@ mgf1, ) where -import Crypto.Hash-import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess, Bytes)+import Control.Monad (forM_)+import Crypto.Hash (Context, Digest)+import Crypto.Hash.IO (HashAlgorithm (..))+import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess) import qualified Crypto.Internal.ByteArray as B-import Crypto.Number.Serialize (i2ospOf_)+import Data.Bits (shiftR)+import Data.Word (Word8)+import Foreign.Marshal.Alloc (allocaBytes)+import Foreign.Marshal.Utils (copyBytes)+import Foreign.Ptr (Ptr, castPtr, plusPtr)+import Foreign.Storable (pokeByteOff) -- | Represent a mask generation algorithm type MaskGenAlgorithm seed output =@@ -26,20 +33,33 @@ -- | Mask generation algorithm MGF1 mgf1- :: (ByteArrayAccess seed, ByteArray output, HashAlgorithm hashAlg)+ :: forall seed output hashAlg+ . (ByteArrayAccess seed, ByteArray output, HashAlgorithm hashAlg) => hashAlg -> seed -> Int -> output-mgf1 hashAlg seed len =- let !seededCtx = hashUpdate (hashInitWith hashAlg) seed- in B.take len $- B.concat $- map (hashCounter seededCtx) [0 .. fromIntegral (maxCounter - 1)]+mgf1 hashAlg seed len+ | len <= 0 = B.empty+ | otherwise = B.allocAndFreeze len $ \out ->+ -- the seeded context is kept, and copied for each block rather than+ -- rebuilt; each block's digest is written straight into the output+ allocaBytes ctxSize $ \(seeded :: Ptr (Context hashAlg)) ->+ allocaBytes ctxSize $ \(ctx :: Ptr (Context hashAlg)) ->+ allocaBytes digestLen $ \(dig :: Ptr (Digest hashAlg)) ->+ allocaBytes 4 $ \(cnt :: Ptr Word8) -> do+ hashInternalInit seeded+ B.withByteArray seed $ \p ->+ hashInternalUpdate seeded p (fromIntegral (B.length seed))+ forM_ [0 .. maxCounter - 1] $ \i -> do+ copyBytes ctx seeded ctxSize+ forM_ [0 .. 3] $ \k ->+ pokeByteOff cnt k (fromIntegral (i `shiftR` (8 * (3 - k))) :: Word8)+ hashInternalUpdate ctx cnt 4+ hashInternalFinalize ctx dig+ let off = i * digestLen+ copyBytes (out `plusPtr` off) (castPtr dig) (min digestLen (len - off)) where+ ctxSize = hashInternalContextSize hashAlg digestLen = hashDigestSize hashAlg- (chunks, left) = len `divMod` digestLen- maxCounter = if left > 0 then chunks + 1 else chunks-- hashCounter :: HashAlgorithm a => Context a -> Integer -> Digest a- hashCounter ctx counter = hashFinalize $ hashUpdate ctx (i2ospOf_ 4 counter :: Bytes)+ maxCounter = (len + digestLen - 1) `div` digestLen
@@ -0,0 +1,29 @@+-- |+-- Module : Crypto.PubKey.RSA.Blinded+-- License : BSD-style+-- Stability : experimental+-- Portability : Good+--+-- An RSA private key that keeps its blinding between operations.+--+-- Blinding hides the private-key operation's input from timing: it is+-- multiplied by @r^e@ for a random @r@ first, and the result by @r^-1@+-- after. Drawing a new @r@ costs a modular inverse and an exponentiation,+-- about a tenth of an RSA-2048 signature. A t'BlindedKey' draws one and+-- squares the pair for each use after it, which is what OpenSSL does, and+-- draws a new one every 32 uses, from the 'Crypto.Random.Types.MonadRandom'+-- the operation runs in.+--+-- The key is threaded through the operations as a hash context is: each+-- function in "Crypto.PubKey.RSA.PKCS15", "Crypto.PubKey.RSA.PSS" and+-- "Crypto.PubKey.RSA.OAEP" whose name ends in @Blinded@ returns the key for+-- the next one. The @Safer@ functions there keep a t'BlindedKey' per key+-- themselves, for the last few keys used, so they get the same saving+-- without one being passed.+module Crypto.PubKey.RSA.Blinded (+ BlindedKey,+ blindedKey,+ blindedPrivateKey,+) where++import Crypto.PubKey.RSA.Blinded.Internal
@@ -0,0 +1,136 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-cse -fno-full-laziness #-}++-- |+-- Module : Crypto.PubKey.RSA.Blinded.Internal+-- License : BSD-style+-- Stability : experimental+-- Portability : Good+--+-- A private key with a blinding pair that is reused by squaring, as OpenSSL+-- does, rather than generated afresh for every operation. The key is a value+-- threaded through the operations, as a hash 'Crypto.Hash.Context' is.+module Crypto.PubKey.RSA.Blinded.Internal (+ BlindedKey (..),+ blindedKey,+ dpBlinded,+ Draw,+ drawFor,+ withBlindingFor,+ dpWithPair,+) where++import Data.IORef+import System.IO.Unsafe (unsafePerformIO)++import Crypto.Internal.ByteArray (ByteArray, ScrubbedBytes)+import Crypto.Number.Generate (generateMax)+import Crypto.Number.ModArithmetic (expFast, inverseCoprimes)+import Crypto.Number.Serialize (i2ospOf_, os2ip)+import Crypto.PubKey.RSA.Prim (dp)+import Crypto.PubKey.RSA.Types+import Crypto.Random.Types++-- | A private key together with the blinding its next operation uses.+--+-- Each operation multiplies the input by @r^e@ and the output by @r^-1@, and+-- returns the key with both squared for the next one, so a pair costs two+-- multiplications after the first. A new @r@ is drawn every 32 operations.+-- Use the key an operation returns: handing the same one to two operations+-- gives both the same pair.+data BlindedKey = BlindedKey+ { blindedPrivateKey :: PrivateKey+ -- ^ the key it was made from+ , blindedPair :: Pair+ }++-- | @r^e@ and @r^-1@ modulo n, and how many more uses they have after this.+data Pair = Pair !Int !Integer !Integer | Spent++-- | Uses of one @r@ before another is drawn, OpenSSL's number.+refresh :: Int+refresh = 32++-- | A t'BlindedKey' for a private key. The first pair is drawn when it is+-- first used.+blindedKey :: PrivateKey -> BlindedKey+blindedKey pk = BlindedKey pk Spent++-- | The random numbers a new pair is made from: drawing them is cheap, and+-- making the pair, an inverse and an exponentiation, is done only if needed.+data Draw = Draw !Integer !Integer++-- | Draw for a key, as 'Crypto.PubKey.RSA.generateBlinder' does.+drawFor :: forall m. MonadRandom m => PrivateKey -> m Draw+drawFor pk = do+ r <- generateMax (private_n pk)+ u <- os2ip <$> (getRandomBytes 16 :: m ScrubbedBytes)+ return (Draw r u)++-- | @r^e@ and @r^-1@. The inverse is taken of @r*u@ and multiplied by @u@,+-- so the extended Euclidean algorithm never sees @r@, as in+-- 'Crypto.PubKey.RSA.generateBlinder'.+makePair :: PrivateKey -> Draw -> (Integer, Integer)+makePair pk (Draw r u) =+ (expFast r (private_e pk) n, (inverseCoprimes ((r * u) `mod` n) n * u) `mod` n)+ where+ n = private_n pk++-- | The pair for this operation, and the key holding the next one. The+-- draw is used only when a new pair is due.+takePair :: Draw -> BlindedKey -> ((Integer, Integer), BlindedKey)+takePair d (BlindedKey pk pair) = case pair of+ Pair k a ai -> ((a, ai), BlindedKey pk (next k a ai))+ Spent -> case makePair pk d of+ (a, ai) -> ((a, ai), BlindedKey pk (next refresh a ai))+ where+ n = private_n pk+ next k a ai+ | k > 1 = Pair (k - 1) ((a * a) `mod` n) ((ai * ai) `mod` n)+ | otherwise = Spent++-- | The decryption primitive, blinded with a given pair.+dpWithPair :: ByteArray ba => (Integer, Integer) -> PrivateKey -> ba -> ba+dpWithPair (a, ai) pk c = i2ospOf_ k ((ai * os2ip m) `mod` n)+ where+ n = private_n pk+ k = private_size pk+ m = dp Nothing pk (i2ospOf_ k ((a * os2ip c) `mod` n) `asTypeOf` c)++-- | The decryption primitive, blinded with the key's pair, and the key for+-- the next operation. Randomness is drawn only when a new pair is due.+dpBlinded+ :: (MonadRandom m, ByteArray ba) => BlindedKey -> ba -> m (ba, BlindedKey)+dpBlinded bk c = do+ d <- case blindedPair bk of+ Pair {} -> return (Draw 0 0)+ Spent -> drawFor (blindedPrivateKey bk)+ let (pair, bk') = takePair d bk+ return (dpWithPair pair (blindedPrivateKey bk) c, bk')++-- | Run an operation with the pair kept for a key, for the functions that+-- take a bare t'PrivateKey'. One t'BlindedKey' is kept per public key, for+-- the last few keys used; taking its pair and leaving the next is atomic, so+-- no two operations get the same pair. The caller draws every time, since+-- whether a new pair is due is known only in here.+withBlindingFor :: PrivateKey -> Draw -> ((Integer, Integer) -> a) -> a+withBlindingFor pk d f = unsafePerformIO $ do+ pair <- atomicModifyIORef' table step+ return (f pair)+ where+ pub = private_pub pk+ step ks = case break ((== pub) . private_pub . blindedPrivateKey) ks of+ (before, bk : after) -> found bk (before ++ after)+ _ -> found (blindedKey pk) ks+ found bk rest = case takePair d bk of+ (pair@(!_, !_), bk') -> (take tableSize (bk' : rest), pair)+{-# NOINLINE withBlindingFor #-}++-- | How many keys 'withBlindingFor' remembers.+tableSize :: Int+tableSize = 4++table :: IORef [BlindedKey]+table = unsafePerformIO (newIORef [])+{-# NOINLINE table #-}
@@ -18,22 +18,22 @@ -- * OAEP decryption decrypt, decryptSafer,+ decryptBlinded, ) where import Crypto.Hash import Crypto.Number.Serialize (os2ip) import Crypto.PubKey.Internal (and') import Crypto.PubKey.MaskGenFunction-import Crypto.PubKey.RSA (generateBlinder)+import Crypto.PubKey.RSA.Blinded.Internal import Crypto.PubKey.RSA.Prim import Crypto.PubKey.RSA.Types import Crypto.Random.Types import Data.Bits (complement, shiftR, xor, (.&.), (.|.)) import Data.ByteString (ByteString) import qualified Data.ByteString as B-import Data.List (foldl')+import qualified Data.List as L import Data.Word (Word32)-import Prelude hiding (foldl') import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess) import qualified Crypto.Internal.ByteArray as B (constEq, convert)@@ -156,7 +156,7 @@ -- is zero; all of them are looked at either way oneIndex = fst $- foldl'+ L.foldl' step (fromIntegral (B.length db1) :: Word32, 1 :: Word32) (zip [0 ..] (B.unpack db1))@@ -181,10 +181,9 @@ -- | Decrypt a ciphertext using OAEP ----- When the signature is not in a context where an attacker could gain--- information from the timing of the operation, the blinder can be set to None.------ If unsure always set a blinder or use decryptSafer+-- The blinder is optional and 'Nothing' is accepted, but see t'Blinder' for+-- what it covers and when leaving it out is a decision rather than a default.+-- 'decryptSafer' generates one for you. -- -- Following RFC 8017, the ciphertext is rejected unless it is exactly as long -- as the modulus (section 7.1.2, step 1) and its integer representative is@@ -214,7 +213,8 @@ k = private_size pk hashLen = hashDigestSize (oaepHash oaep) --- | Decrypt a ciphertext using OAEP and by automatically generating a blinder.+-- | Decrypt a ciphertext using OAEP, blinded with the pair kept for this key;+-- see "Crypto.PubKey.RSA.Blinded". decryptSafer :: (HashAlgorithm hash, MonadRandom m) => OAEPParams hash ByteString ByteString@@ -224,6 +224,34 @@ -> ByteString -- ^ Cipher text -> m (Either Error ByteString)-decryptSafer oaep pk cipher = do- blinder <- generateBlinder (private_n pk)- return (decrypt (Just blinder) oaep pk cipher)+decryptSafer oaep pk cipher+ | B.length cipher /= k = return (Left MessageSizeIncorrect)+ | os2ip cipher >= private_n pk = return (Left MessageSizeIncorrect)+ | k < 2 * hashLen + 2 = return (Left InvalidParameters)+ | otherwise = do+ d <- drawFor pk+ return $ withBlindingFor pk d $ \pair -> unpad oaep k (dpWithPair pair pk cipher)+ where+ k = private_size pk+ hashLen = hashDigestSize (oaepHash oaep)++-- | 'decrypt' with the blinding a t'BlindedKey' keeps, and the key for the+-- next operation.+decryptBlinded+ :: (HashAlgorithm hash, MonadRandom m)+ => OAEPParams hash ByteString ByteString+ -> BlindedKey+ -> ByteString+ -- ^ Cipher text+ -> m (Either Error ByteString, BlindedKey)+decryptBlinded oaep bk cipher+ | B.length cipher /= k = return (Left MessageSizeIncorrect, bk)+ | os2ip cipher >= private_n pk = return (Left MessageSizeIncorrect, bk)+ | k < 2 * hashLen + 2 = return (Left InvalidParameters, bk)+ | otherwise = do+ (m, bk') <- dpBlinded bk cipher+ return (unpad oaep k m, bk')+ where+ pk = blindedPrivateKey bk+ k = private_size pk+ hashLen = hashDigestSize (oaepHash oaep)
@@ -15,10 +15,21 @@ decryptSafer, sign, signSafer,+ signDigest,+ signSaferDigest,+ signDigestInfo,+ signSaferDigestInfo, + -- * Private key operations with a kept blinding+ decryptBlinded,+ signDigestBlinded,+ signDigestInfoBlinded,+ -- * Public key operations encrypt, verify,+ verifyDigest,+ verifyDigestInfo, -- * Hash ASN1 description HashAlgorithmASN1,@@ -27,7 +38,7 @@ import Crypto.Hash import Crypto.Number.Serialize (os2ip) import Crypto.PubKey.Internal (and')-import Crypto.PubKey.RSA (generateBlinder)+import Crypto.PubKey.RSA.Blinded.Internal import Crypto.PubKey.RSA.Prim import Crypto.PubKey.RSA.Types import Crypto.Random.Types@@ -38,8 +49,7 @@ import Crypto.Internal.ByteArray (ByteArray, Bytes) import qualified Crypto.Internal.ByteArray as B-import Data.List (foldl')-import Prelude hiding (foldl')+import qualified Data.List as L -- | A specialized class for hash algorithm that can product -- a ASN1 wrapped description the algorithm plus the content@@ -405,10 +415,10 @@ :: ByteArray signature => Int -> signature -> Either Error signature padSignature klen signature | klen < siglen + 11 = Left SignatureTooLong- | otherwise = Right (B.pack padding `B.append` signature)+ | otherwise =+ Right (B.concat [B.pack [0, 1], B.replicate (klen - siglen - 3) 0xff, B.pack [0], signature]) where siglen = B.length signature- padding = 0 : 1 : (replicate (klen - siglen - 3) 0xff ++ [0]) -- | Try to remove a standard PKCS1.5 encryption padding. --@@ -431,7 +441,7 @@ -- index of the first zero octet in ps0m, counted from the start of packed, -- or len when there is none; every octet is looked at either way- zeroIndex = fst $ foldl' step (fromIntegral len :: Word32, 1 :: Word32) indexed+ zeroIndex = fst $ L.foldl' step (fromIntegral len :: Word32, 1 :: Word32) indexed indexed = zip [2 ..] (B.unpack ps0m) step (idx, unseen) (i, b) = (select found i idx, unseen .&. complement found) where@@ -453,10 +463,9 @@ -- | decrypt message using the private key. ----- When the decryption is not in a context where an attacker could gain--- information from the timing of the operation, the blinder can be set to None.------ If unsure always set a blinder or use decryptSafer+-- The blinder is optional and 'Nothing' is accepted, but see t'Blinder' for+-- what it covers and when leaving it out is a decision rather than a default.+-- 'decryptSafer' generates one for you. -- -- The message is returned un-padded. --@@ -482,7 +491,8 @@ -- "convert" must be apply to "c". | otherwise = unpad $ dp blinder pk $ B.convert c --- | decrypt message using the private key and by automatically generating a blinder.+-- | decrypt message using the private key, blinded with the pair kept for+-- this key; see "Crypto.PubKey.RSA.Blinded". decryptSafer :: (MonadRandom m, ByteArray ba) => PrivateKey@@ -490,10 +500,30 @@ -> ByteString -- ^ cipher text -> m (Either Error ba)-decryptSafer pk b = do- blinder <- generateBlinder (private_n pk)- return (decrypt (Just blinder) pk b)+decryptSafer pk b+ | B.length b /= private_size pk = return (Left MessageSizeIncorrect)+ | os2ip b >= private_n pk = return (Left MessageSizeIncorrect)+ | otherwise = do+ d <- drawFor pk+ return $ withBlindingFor pk d $ \pair -> unpad (dpWithPair pair pk (B.convert b)) +-- | 'decrypt' with the blinding a t'BlindedKey' keeps, and the key for the+-- next operation.+decryptBlinded+ :: (MonadRandom m, ByteArray ba)+ => BlindedKey+ -> ByteString+ -- ^ cipher text+ -> m (Either Error ba, BlindedKey)+decryptBlinded bk c+ | B.length c /= private_size pk = return (Left MessageSizeIncorrect, bk)+ | os2ip c >= private_n pk = return (Left MessageSizeIncorrect, bk)+ | otherwise = do+ (m, bk') <- dpBlinded bk (B.convert c)+ return (unpad m, bk')+ where+ pk = blindedPrivateKey bk+ -- | encrypt a bytestring using the public key. -- -- The message needs to be smaller than the key size - 11.@@ -508,10 +538,15 @@ -- | sign message using private key, a hash and its ASN1 description ----- When the signature is not in a context where an attacker could gain--- information from the timing of the operation, the blinder can be set to None.+-- __Deprecated.__ Use 'signDigest', or 'signDigestInfo' where this would+-- have been given 'Nothing'. The @Maybe hashAlg@ argument says both \"hash+-- it with this\" and \"do not hash it\", and down the first path the value+-- inside the 'Just' is never read: it is there to fix the type, which+-- leaves a caller that has only a type with nothing to pass. ----- If unsure always set a blinder or use signSafer+-- The blinder is optional and 'Nothing' is accepted, but see t'Blinder' for+-- what it covers and when leaving it out is a decision rather than a default.+-- 'signSafer' generates one for you. sign :: HashAlgorithmASN1 hashAlg => Maybe Blinder@@ -524,8 +559,15 @@ -- ^ message to sign -> Either Error ByteString sign blinder hashDescr pk m = dp blinder pk `fmap` makeSignature hashDescr (private_size pk) m+{-# DEPRECATED+ sign+ "Use signDigest, or signDigestInfo when the message is already a DigestInfo"+ #-} --- | sign message using the private key and by automatically generating a blinder.+-- | sign message using the private key, blinded with the pair kept for this+-- key; see "Crypto.PubKey.RSA.Blinded".+--+-- __Deprecated.__ Use 'signSaferDigest', or 'signSaferDigestInfo'. signSafer :: (HashAlgorithmASN1 hashAlg, MonadRandom m) => Maybe hashAlg@@ -536,11 +578,18 @@ -- ^ message to sign -> m (Either Error ByteString) signSafer hashAlg pk m = do- blinder <- generateBlinder (private_n pk)- return (sign (Just blinder) hashAlg pk m)+ d <- drawFor pk+ return $ signWithBlindingFor pk d (makeSignature hashAlg (private_size pk) m)+{-# DEPRECATED+ signSafer+ "Use signSaferDigest, or signSaferDigestInfo when the message is already a DigestInfo"+ #-} -- | verify message with the signed message --+-- __Deprecated.__ Use 'verifyDigest', or 'verifyDigestInfo' where this+-- would have been given 'Nothing'.+-- -- Following RFC 8017, the signature is rejected unless it is exactly as long -- as the modulus (section 8.2.2, step 1) and its integer representative is -- below the modulus (section 5.2.2, step 1). Verification works by@@ -557,13 +606,170 @@ -> ByteString -- ^ Signature -> Bool-verify hashAlg pk m sm+verify hashAlg pk m sm =+ verifyEncoded pk (makeSignature hashAlg (public_size pk) m) sm+{-# DEPRECATED+ verify+ "Use verifyDigest, or verifyDigestInfo when the message is already a DigestInfo"+ #-}++-- | The two checks of RFC 8017 and the comparison, shared by the three+-- verification entry points. The expected encoding is a thunk and is+-- forced only once the checks have passed, as it was when this was written+-- out inside 'verify'.+verifyEncoded+ :: PublicKey+ -> Either Error ByteString+ -- ^ the encoding a signature of this message would have+ -> ByteString+ -- ^ signature+ -> Bool+verifyEncoded pk expected sm | B.length sm /= public_size pk = False | os2ip sm >= public_n pk = False | otherwise =- case makeSignature hashAlg (public_size pk) m of+ case expected of Left _ -> False- Right s -> s == (ep pk sm)+ Right s -> s == ep pk sm++-- | Sign a digest.+--+-- The digest's type says which algorithm made it, so this needs nothing+-- else to name one: the ASN.1 DigestInfo prefix comes from the+-- 'HashAlgorithmASN1' instance that type selects. 'sign' takes @Maybe+-- hashAlg@ and never reads the value inside the @Just@ -- it is there only+-- to fix the type -- which is no burden when the caller has a value and+-- leaves nothing to pass when the caller is itself polymorphic in the+-- algorithm.+--+-- > signDigest blinder key (hashWith SHA256 message)+--+-- The blinder is optional and 'Nothing' is accepted, but see t'Blinder' for+-- what it covers and when leaving it out is a decision rather than a+-- default. 'signSaferDigest' generates one for you.+signDigest+ :: HashAlgorithmASN1 hashAlg+ => Maybe Blinder+ -- ^ optional blinder+ -> PrivateKey+ -- ^ private key+ -> Digest hashAlg+ -- ^ digest of the message to sign+ -> Either Error ByteString+signDigest blinder pk digest =+ dp blinder pk `fmap` padSignature (private_size pk) (hashDigestASN1 digest)++-- | 'signDigest' blinded with the pair kept for this key, as 'signSafer' is+-- to 'sign'; see "Crypto.PubKey.RSA.Blinded".+signSaferDigest+ :: (HashAlgorithmASN1 hashAlg, MonadRandom m)+ => PrivateKey+ -- ^ private key+ -> Digest hashAlg+ -- ^ digest of the message to sign+ -> m (Either Error ByteString)+signSaferDigest pk digest = do+ d <- drawFor pk+ return $+ signWithBlindingFor pk d (padSignature (private_size pk) (hashDigestASN1 digest))++-- | 'signDigest' with the blinding a t'BlindedKey' keeps, and the key for the+-- next operation.+signDigestBlinded+ :: (HashAlgorithmASN1 hashAlg, MonadRandom m)+ => BlindedKey+ -> Digest hashAlg+ -- ^ digest of the message to sign+ -> m (Either Error ByteString, BlindedKey)+signDigestBlinded bk digest =+ signBlindedEncoded bk $+ padSignature (private_size (blindedPrivateKey bk)) (hashDigestASN1 digest)++-- | Sign something that is already a DigestInfo, the ASN.1 structure+-- naming a hash algorithm and carrying a digest under it.+--+-- This is what @'sign' blinder 'Nothing'@ does. It needs no+-- 'HashAlgorithmASN1' constraint, because nothing here hashes or encodes:+-- the caller has done both. @'sign' blinder 'Nothing'@ carries the+-- constraint anyway, and since the type variable then appears nowhere else+-- the caller has to name an algorithm that is never used --+-- @'sign' blinder ('Nothing' :: 'Maybe' 'Crypto.Hash.SHA256')@ -- to say+-- which one it is not using.+signDigestInfo+ :: Maybe Blinder+ -- ^ optional blinder+ -> PrivateKey+ -- ^ private key+ -> ByteString+ -- ^ a DigestInfo, encoded+ -> Either Error ByteString+signDigestInfo blinder pk di =+ dp blinder pk `fmap` padSignature (private_size pk) di++-- | 'signDigestInfo' blinded with the pair kept for this key.+signSaferDigestInfo+ :: MonadRandom m+ => PrivateKey+ -- ^ private key+ -> ByteString+ -- ^ a DigestInfo, encoded+ -> m (Either Error ByteString)+signSaferDigestInfo pk di = do+ d <- drawFor pk+ return $ signWithBlindingFor pk d (padSignature (private_size pk) di)++-- | 'signDigestInfo' with the blinding a t'BlindedKey' keeps, and the key for+-- the next operation.+signDigestInfoBlinded+ :: MonadRandom m+ => BlindedKey+ -> ByteString+ -- ^ a DigestInfo, encoded+ -> m (Either Error ByteString, BlindedKey)+signDigestInfoBlinded bk di =+ signBlindedEncoded bk $ padSignature (private_size (blindedPrivateKey bk)) di++-- | The private-key operation on an encoded signature, if there is one; the+-- key is used up only if there is.+signBlindedEncoded+ :: MonadRandom m+ => BlindedKey+ -> Either Error ByteString+ -> m (Either Error ByteString, BlindedKey)+signBlindedEncoded bk (Left err) = return (Left err, bk)+signBlindedEncoded bk (Right em) = do+ (s, bk') <- dpBlinded bk em+ return (Right s, bk')++-- | The same, with the pair the @Safer@ functions keep for this key.+signWithBlindingFor+ :: PrivateKey -> Draw -> Either Error ByteString -> Either Error ByteString+signWithBlindingFor _ _ (Left err) = Left err+signWithBlindingFor pk d (Right em) = Right (withBlindingFor pk d (\pair -> dpWithPair pair pk em))++-- | Verify a signature over a digest. The checks are 'verify's.+verifyDigest+ :: HashAlgorithmASN1 hashAlg+ => PublicKey+ -> Digest hashAlg+ -- ^ digest of the message+ -> ByteString+ -- ^ signature+ -> Bool+verifyDigest pk digest sm =+ verifyEncoded pk (padSignature (public_size pk) (hashDigestASN1 digest)) sm++-- | Verify a signature over something that is already a DigestInfo, which+-- is what @'verify' 'Nothing'@ does.+verifyDigestInfo+ :: PublicKey+ -> ByteString+ -- ^ a DigestInfo, encoded+ -> ByteString+ -- ^ signature+ -> Bool+verifyDigestInfo pk di sm =+ verifyEncoded pk (padSignature (public_size pk) di) sm -- | make signature digest, used in 'sign' and 'verify' makeSignature
@@ -16,6 +16,8 @@ signDigest, signSafer, signDigestSafer,+ signBlinded,+ signDigestBlinded, verify, verifyDigest, ) where@@ -24,15 +26,15 @@ import Crypto.Number.Basic (numBits) import Crypto.Number.Serialize (os2ip) import Crypto.PubKey.MaskGenFunction-import Crypto.PubKey.RSA (generateBlinder)+import Crypto.PubKey.RSA.Blinded.Internal import Crypto.PubKey.RSA.Prim import Crypto.PubKey.RSA.Types import Crypto.Random.Types-import Data.Bits (shiftR, xor, (.&.))+import Data.Bits (complement, shiftR, (.&.)) import Data.Word import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)-import qualified Crypto.Internal.ByteArray as B (convert, eq)+import qualified Crypto.Internal.ByteArray as B (bxor, convert, eq) import Data.ByteString (ByteString) import qualified Data.ByteString as B@@ -69,6 +71,9 @@ -- | Sign using the PSS parameters and the salt explicitely passed as parameters. -- -- the function ignore SaltLength from the PSS Parameters+--+-- See t'Blinder' for what the optional blinder covers and when leaving it out+-- is a decision rather than a default. 'signSafer' generates one for you. signDigestWithSalt :: HashAlgorithm hash => ByteString@@ -82,9 +87,20 @@ -> Digest hash -- ^ Message digest -> Either Error ByteString-signDigestWithSalt salt blinder params pk digest+signDigestWithSalt salt blinder params pk digest =+ dp blinder pk <$> encodeDigest salt params pk digest++-- | The encoded message the private-key operation is applied to.+encodeDigest+ :: HashAlgorithm hash+ => ByteString+ -> PSSParams hash ByteString ByteString+ -> PrivateKey+ -> Digest hash+ -> Either Error ByteString+encodeDigest salt params pk digest | emLen < hashLen + saltLen + 2 = Left InvalidParameters- | otherwise = Right $ dp blinder pk em+ | otherwise = Right em where k = private_size pk emLen = if emTruncate pubBits then k - 1 else k@@ -97,12 +113,15 @@ h = B.convert $ hashWith (pssHash params) m' db = B.concat [B.replicate (dbLen - saltLen - 1) 0, B.singleton 1, salt] dbmask = pssMaskGenAlg params h dbLen- maskedDB = B.pack $ normalizeToKeySize pubBits $ B.zipWith xor db dbmask+ maskedDB = normalizeToKeySize pubBits (B.bxor db dbmask :: ByteString) em = B.concat [maskedDB, h, B.singleton (pssTrailerField params)] -- | Sign using the PSS parameters and the salt explicitely passed as parameters. -- -- the function ignore SaltLength from the PSS Parameters+--+-- See t'Blinder' for what the optional blinder covers and when leaving it out+-- is a decision rather than a default. 'signSafer' generates one for you. signWithSalt :: HashAlgorithm hash => ByteString@@ -121,6 +140,9 @@ mHash = hashWith (pssHash params) m -- | Sign using the PSS Parameters+--+-- See t'Blinder' for what the optional blinder covers and when leaving it out+-- is a decision rather than a default. 'signSafer' generates one for you. sign :: (HashAlgorithm hash, MonadRandom m) => Maybe Blinder@@ -137,6 +159,9 @@ return (signWithSalt salt blinder params pk m) -- | Sign using the PSS Parameters+--+-- See t'Blinder' for what the optional blinder covers and when leaving it out+-- is a decision rather than a default. 'signSafer' generates one for you. signDigest :: (HashAlgorithm hash, MonadRandom m) => Maybe Blinder@@ -152,7 +177,8 @@ salt <- getRandomBytes (pssSaltLength params) return (signDigestWithSalt salt blinder params pk digest) --- | Sign using the PSS Parameters and an automatically generated blinder.+-- | Sign using the PSS Parameters, blinded with the pair kept for this key;+-- see "Crypto.PubKey.RSA.Blinded". signSafer :: (HashAlgorithm hash, MonadRandom m) => PSSParams hash ByteString ByteString@@ -162,11 +188,10 @@ -> ByteString -- ^ message to sign -> m (Either Error ByteString)-signSafer params pk m = do- blinder <- generateBlinder (private_n pk)- sign (Just blinder) params pk m+signSafer params pk m = signDigestSafer params pk (hashWith (pssHash params) m) --- | Sign using the PSS Parameters and an automatically generated blinder.+-- | Sign using the PSS Parameters, blinded with the pair kept for this key;+-- see "Crypto.PubKey.RSA.Blinded". signDigestSafer :: (HashAlgorithm hash, MonadRandom m) => PSSParams hash ByteString ByteString@@ -177,9 +202,40 @@ -- ^ message digst -> m (Either Error ByteString) signDigestSafer params pk digest = do- blinder <- generateBlinder (private_n pk)- signDigest (Just blinder) params pk digest+ salt <- getRandomBytes (pssSaltLength params)+ d <- drawFor pk+ return $ case encodeDigest salt params pk digest of+ Left err -> Left err+ Right em -> Right (withBlindingFor pk d (\pair -> dpWithPair pair pk em)) +-- | 'signSafer' with the blinding a t'BlindedKey' keeps, and the key for the+-- next operation.+signBlinded+ :: (HashAlgorithm hash, MonadRandom m)+ => PSSParams hash ByteString ByteString+ -> BlindedKey+ -> ByteString+ -- ^ message to sign+ -> m (Either Error ByteString, BlindedKey)+signBlinded params bk m = signDigestBlinded params bk (hashWith (pssHash params) m)++-- | 'signDigestSafer' with the blinding a t'BlindedKey' keeps, and the key+-- for the next operation.+signDigestBlinded+ :: (HashAlgorithm hash, MonadRandom m)+ => PSSParams hash ByteString ByteString+ -> BlindedKey+ -> Digest hash+ -- ^ message digest+ -> m (Either Error ByteString, BlindedKey)+signDigestBlinded params bk digest = do+ salt <- getRandomBytes (pssSaltLength params)+ case encodeDigest salt params (blindedPrivateKey bk) digest of+ Left err -> return (Left err, bk)+ Right em -> do+ (s, bk') <- dpBlinded bk em+ return (Right s, bk')+ -- | Verify a signature using the PSS Parameters verify :: HashAlgorithm hash@@ -221,6 +277,7 @@ | B.length s /= k = False | os2ip s >= public_n pk = False | B.any (/= 0) pre = False+ | B.any (\x -> x .&. topBits /= 0) (B.take 1 maskedDB) = False | B.last em /= pssTrailerField params = False | B.any (/= 0) ps0 = False | b1 /= B.singleton 1 = False@@ -234,12 +291,19 @@ emLen = if emTruncate pubBits then k - 1 else k dbLen = emLen - hashLen - 1 pubBits = numBits (public_n pk)+ -- RFC 8017 9.1.2 step 6: the leftmost 8*emLen - emBits bits of the+ -- leftmost octet of maskedDB have to be zero already. Step 9 clears+ -- them in DB, which is what normalizeToKeySize does below, and clearing+ -- is not checking: without this an encoding with the top bit set -- one+ -- the standard calls inconsistent -- verifies as though it were sound,+ -- because the bit that made it wrong is thrown away before it is read.+ topBits = complement (normalizeMask pubBits) -- unmarshall fields (pre, em) = B.splitAt (k - emLen) (ep pk s) -- drop 0..1 byte maskedDB = B.take dbLen em h = B.take hashLen $ B.drop (B.length maskedDB) em dbmask = pssMaskGenAlg params h dbLen- db = B.pack $ normalizeToKeySize pubBits $ B.zipWith xor maskedDB dbmask+ db = normalizeToKeySize pubBits (B.bxor maskedDB dbmask :: ByteString) (ps0, z) = B.break (== 1) db (b1, salt) = B.splitAt 1 z m' = B.concat [B.replicate 8 0, mHash, salt]@@ -249,9 +313,15 @@ emTruncate :: Int -> Bool emTruncate bits = ((bits - 1) .&. 0x7) == 0 -normalizeToKeySize :: Int -> [Word8] -> [Word8]-normalizeToKeySize _ [] = [] -- very unlikely-normalizeToKeySize bits (x : xs) = x .&. mask : xs+normalizeToKeySize :: Int -> ByteString -> ByteString+normalizeToKeySize bits x = case B.uncons x of+ Nothing -> x -- very unlikely+ Just (h, t) -> B.cons (h .&. normalizeMask bits) t++-- | The bits of the leftmost octet that belong to the encoding: the low+-- @emBits `mod` 8@ of them, or all eight when that is zero. Its complement+-- is the bits RFC 8017 requires to be zero.+normalizeMask :: Int -> Word8+normalizeMask bits = if sh > 0 then 0xff `shiftR` (8 - sh) else 0xff where- mask = if sh > 0 then 0xff `shiftR` (8 - sh) else 0xff sh = (bits - 1) .&. 0x7
@@ -1,3 +1,5 @@+{-# LANGUAGE BangPatterns #-}+ -- | -- Module : Crypto.PubKey.RSA.Prim -- License : BSD-style@@ -12,9 +14,19 @@ ep, ) where +import Data.Memory.PtrMethods (memSet)+import Data.Word (Word32, Word8)+import Foreign.C.Types (CInt (..))+import Foreign.Marshal.Alloc (allocaBytes)+import Foreign.Ptr (Ptr, plusPtr)+ import Crypto.Internal.ByteArray (ByteArray)+import Crypto.Internal.Compat (unsafeDoIO)+import Crypto.Number.Basic (numBytes) import Crypto.Number.ModArithmetic (expFast, expSafe)+import Crypto.Number.ModArithmetic.Pub (expPubBytes) import Crypto.Number.Serialize (i2ospOf_, os2ip)+import qualified Crypto.Number.Serialize.Internal as Internal import Crypto.PubKey.RSA.Types {- dpSlow computes the decrypted message not using any precomputed cache value.@@ -29,22 +41,78 @@ dpFast (Blinder r rm1) pk c = i2ospOf_ (private_size pk)- (multiplication rm1 (m2 + h * (private_q pk)) (private_n pk))+ (multiplication rm1 (crtChecked pk iC (m2 + h * (private_q pk))) (private_n pk)) where re = expFast r (public_e $ private_pub pk) (private_n pk) iC = multiplication re (os2ip c) (private_n pk)- m1 = expSafe iC (private_dP pk) (private_p pk)- m2 = expSafe iC (private_dQ pk) (private_q pk)+ (m1, m2) = crtHalves iC pk h = ((private_qinv pk) * (m1 - m2)) `mod` (private_p pk) dpFastNoBlinder :: ByteArray ba => PrivateKey -> ba -> ba-dpFastNoBlinder pk c = i2ospOf_ (private_size pk) (m2 + h * (private_q pk))+dpFastNoBlinder pk c = i2ospOf_ (private_size pk) (crtChecked pk iC (m2 + h * (private_q pk))) where iC = os2ip c- m1 = expSafe iC (private_dP pk) (private_p pk)- m2 = expSafe iC (private_dQ pk) (private_q pk)+ (m1, m2) = crtHalves iC pk h = ((private_qinv pk) * (m1 - m2)) `mod` (private_p pk) +-- | The CRT answer m for c, raised back to e before it is let out: a fault+-- in one half gives an m whose gcd with n is the other prime (Boneh, DeMillo+-- and Lipton). On a mismatch it is computed again without CRT, as OpenSSL does.+crtChecked :: PrivateKey -> Integer -> Integer -> Integer+crtChecked pk c m+ | expFast m (public_e (private_pub pk)) n == c `mod` n = m+ | private_d pk > 0 = expSafe c (private_d pk) n+ | otherwise = m+ where+ n = private_n pk++-- | c^dP mod p and c^dQ mod q, the halves of the private-key operation: both+-- at once where the C can (AVX-512 IFMA, and the sizes of RSA-2048, -3072 and+-- -4096), one after the other where it declines.+crtHalves :: Integer -> PrivateKey -> (Integer, Integer)+crtHalves c pk = case expSafeX2 (c `mod` p) dP p (c `mod` q) dQ q of+ Just r -> r+ Nothing -> (expSafe c dP p, expSafe c dQ q)+ where+ p = private_p pk+ q = private_q pk+ dP = private_dP pk+ dQ = private_dQ pk++-- | Two secure exponentiations in one call. The bases are reduced already+-- and the moduli are the same length; both exponents go in at that length,+-- so the length the C sees is the modulus', as 'expSafe' pads to whole words.+expSafeX2 :: Integer -> Integer -> Integer -> Integer -> Integer -> Integer -> Maybe (Integer, Integer)+expSafeX2 b1 e1 m1 b2 e2 m2+ | numBytes m2 /= len || not (odd m1 && odd m2) = Nothing+ | e1 < 0 || e2 < 0 || numBytes e1 > len || numBytes e2 > len = Nothing+ | otherwise = unsafeDoIO $+ allocaBytes (8 * len) $ \start -> case take 8 (iterate (`plusPtr` len) start) of+ [o1, pb1, pe1, pm1, o2, pb2, pe2, pm2] -> do+ mapM_+ (\(v, ptr) -> Internal.i2ospOf v ptr len)+ [(b1, pb1), (e1, pe1), (m1, pm1), (b2, pb2), (e2, pe2), (m2, pm2)]+ r <- c_powm_sec_x2 o1 pb1 l pe1 l pm1 l o2 pb2 l pe2 l pm2 l+ -- the exponents are the caller's secrets+ memSet pe1 0 len+ memSet pe2 0 len+ if r /= 0+ then return Nothing+ else do+ !v1 <- Internal.os2ip o1 len+ !v2 <- Internal.os2ip o2 len+ return (Just (v1, v2))+ _ -> return Nothing+ where+ !len = numBytes m1+ l = fromIntegral len :: Word32++foreign import ccall safe "crypton_powm_sec_x2"+ c_powm_sec_x2+ :: Ptr Word8 -> Ptr Word8 -> Word32 -> Ptr Word8 -> Word32 -> Ptr Word8 -> Word32+ -> Ptr Word8 -> Ptr Word8 -> Word32 -> Ptr Word8 -> Word32 -> Ptr Word8 -> Word32+ -> IO CInt+ -- | Compute the RSA decrypt primitive. -- if the p and q numbers are available, then dpFast is used -- otherwise, we use dpSlow which only need d and n.@@ -56,7 +124,9 @@ -- | Compute the RSA encrypt primitive ep :: ByteArray ba => PublicKey -> ba -> ba-ep pk m = i2ospOf_ (public_size pk) $ expFast (os2ip m) (public_e pk) (public_n pk)+ep pk m = case expPubBytes (public_e pk) (public_n pk) m of+ Just r -> r+ Nothing -> i2ospOf_ (public_size pk) $ expFast (os2ip m) (public_e pk) (public_n pk) -- | multiply 2 integers in Zm only performing the modulo operation if necessary multiplication :: Integer -> Integer -> Integer -> Integer
@@ -27,8 +27,32 @@ import GHC.Generics --- | Blinder which is used to obfuscate the timing--- of the decryption primitive (used by decryption and signing).+-- | A blinder, which keeps the timing of the private key operation from+-- saying anything about the number it was given.+--+-- The private exponent is not what is at risk. 'Crypto.Number.ModArithmetic.expSafe',+-- which the exponentiation goes through, keeps the /value/ of an exponent out+-- of the work it does.+--+-- What a blinder covers is the other side. Without one, the operation runs+-- on the ciphertext as it arrived, so how long it takes depends on a number+-- an attacker may have chosen and can vary -- which is what a remote timing+-- attack on RSA needs. With one, the input is multiplied by a random value+-- first and that value divided out afterwards, so the timing carries nothing+-- an attacker can steer.+--+-- Every private key operation here takes a @'Maybe' t'Blinder'@. The+-- @Safer@ form of each -- 'Crypto.PubKey.RSA.PKCS15.decryptSafer',+-- 'Crypto.PubKey.RSA.PKCS15.signSafer' and their kind -- generates one and is+-- the one to reach for. Pass 'Nothing' only where the input is not attacker+-- controlled and you have decided that it is not.+--+-- A blinder costs one more exponentiation, by the public exponent, which is+-- the cheap direction: measured on an Apple M4, PKCS#1 v1.5 signing goes from+-- about 601 to about 620 microseconds.+--+-- Use a blinder once. 'Crypto.PubKey.RSA.generateBlinder' makes a fresh one;+-- carrying one across operations is not what it is for. data Blinder = Blinder !Integer !Integer deriving (Show, Eq)
@@ -25,6 +25,38 @@ -- -- Around all of that is 'Integer' arithmetic, whose cost follows the size of -- the numbers; see "Crypto.PubKey.DSA" for that note at more length.+--+-- == The hash algorithm is passed as a value, and that is not going to change+--+-- 'sign', 'signWith' and 'verify' take a @hash@ argument whose value they+-- never read. Every 'Crypto.Hash.HashAlgorithm' instance is a nullary+-- constructor, and the algorithm comes from the type; the value is there to+-- carry the type and nothing else. A caller holding a value loses nothing+-- by it, and a caller that is itself polymorphic in the algorithm has no+-- value to pass.+--+-- Elsewhere in crypton that is answered by taking a+-- 'Crypto.Hash.Digest' instead: the digest carries the algorithm in its+-- type and the bytes in its value, so nothing is passed only to name a+-- type. "Crypto.PubKey.RSA.PKCS15", "Crypto.PubKey.DSA",+-- "Crypto.PubKey.ElGamal", "Crypto.PubKey.Rabin.RW" and+-- "Crypto.PubKey.Rabin.Modified" all do that.+--+-- This module cannot. What is hashed here is not the message:+--+-- > h = os2ip $ hashWith hashAlg $ B.append padding m+--+-- and the padding is not the caller's either. 'sign' searches for one,+-- drawing eight bytes at a time until the first octet is non-zero and the+-- Jacobi symbols of the hash modulo each private prime are both 1. Which+-- bytes get hashed is therefore decided inside the signing operation, after+-- the caller has handed over the message, so there is no digest for a+-- caller to compute in advance.+--+-- A proxy argument would work where a digest cannot. It is deliberately+-- not added: it would be the one exception to a rule the rest of the+-- library now follows, and this module has no callers asking for it. See+-- the survey in <https://github.com/kazu-yamamoto/crypton/issues/304>. module Crypto.PubKey.Rabin.Basic ( PublicKey (..), PrivateKey (..),
@@ -17,7 +17,9 @@ PrivateKey (..), generate, sign,+ signDigest, verify,+ verifyDigest, ) where import Crypto.Debug (DebugShow (..))@@ -109,10 +111,25 @@ -> ByteString -- ^ message to sign -> Either Error Integer-sign pk hashAlg m =+sign pk hashAlg m = signDigest pk (hashWith hashAlg m)++-- | Sign a digest using the private key.+--+-- The digest's type says which algorithm made it, so this needs nothing else+-- to name one. 'sign' takes a @hash@ value and never reads it -- it is there+-- to fix the type -- which leaves a caller that is itself polymorphic in the+-- algorithm with nothing to pass.+signDigest+ :: HashAlgorithm hash+ => PrivateKey+ -- ^ private key+ -> Digest hash+ -- ^ digest of the message to sign+ -> Either Error Integer+signDigest pk digest = let d = private_d pk n = public_n $ private_pub pk- h = os2ip $ hashWith hashAlg m+ h = os2ip digest limit = (n - 6) `div` 16 in if h > limit then Left MessageTooLong@@ -135,14 +152,27 @@ -> Integer -- ^ signature -> Bool-verify pk hashAlg m s+verify pk hashAlg m s = verifyDigest pk (hashWith hashAlg m) s++-- | Verify a signature over a digest. See 'signDigest' for why a digest+-- rather than a @hash@ value.+verifyDigest+ :: HashAlgorithm hash+ => PublicKey+ -- ^ public key+ -> Digest hash+ -- ^ digest of the message+ -> Integer+ -- ^ signature+ -> Bool+verifyDigest pk digest s -- squaring works modulo n, so s + n and -s would verify wherever s does | s < 0 || s >= n = False | otherwise = go where n = public_n pk go =- let h = os2ip $ hashWith hashAlg m+ let h = os2ip digest s' = expSafe s 2 n s'' = case s' `mod` 8 of 6 -> s'
@@ -17,9 +17,8 @@ import Data.Bits (complement, shiftR, xor, (.&.), (.|.)) import Data.ByteString (ByteString) import qualified Data.ByteString as B-import Data.List (foldl')+import qualified Data.List as L import Data.Word (Word32)-import Prelude hiding (foldl') import Crypto.Hash import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)@@ -127,7 +126,7 @@ -- is zero; all of them are looked at either way oneIndex = fst $- foldl'+ L.foldl' step (fromIntegral (B.length db1) :: Word32, 1 :: Word32) (zip [0 ..] (B.unpack db1))
@@ -21,7 +21,9 @@ encryptWithSeed, decrypt, sign,+ signDigest, verify,+ verifyDigest, ) where import Crypto.Debug (DebugShow (..))@@ -181,11 +183,26 @@ -> ByteString -- ^ message to sign -> Either Error Integer-sign pk hashAlg m =+sign pk hashAlg m = signDigest pk (hashWith hashAlg m)++-- | Sign a digest using the private key.+--+-- The digest's type says which algorithm made it, so this needs nothing else+-- to name one. 'sign' takes a @hash@ value and never reads it -- it is there+-- to fix the type -- which leaves a caller that is itself polymorphic in the+-- algorithm with nothing to pass.+signDigest+ :: HashAlgorithm hash+ => PrivateKey+ -- ^ private key+ -> Digest hash+ -- ^ digest of the message to sign+ -> Either Error Integer+signDigest pk digest = let d = private_d pk n = public_n $ private_pub pk in do- m' <- ep1 n $ os2ip $ hashWith hashAlg m+ m' <- ep1 n $ os2ip digest return $ dp1 d n m' -- | Verify signature using hash algorithm and public key.@@ -200,11 +217,24 @@ -> Integer -- ^ signature -> Bool-verify pk hashAlg m s+verify pk hashAlg m s = verifyDigest pk (hashWith hashAlg m) s++-- | Verify a signature over a digest. See 'signDigest' for why a digest+-- rather than a @hash@ value.+verifyDigest+ :: HashAlgorithm hash+ => PublicKey+ -- ^ public key+ -> Digest hash+ -- ^ digest of the message+ -> Integer+ -- ^ signature+ -> Bool+verifyDigest pk digest s -- squaring works modulo n, so s + n and -s would verify wherever s does | s < 0 || s >= n = False | otherwise =- let h = os2ip $ hashWith hashAlg m+ let h = os2ip digest h' = dp2 n $ ep2 n s in h' == h where
@@ -7,35 +7,159 @@ -- Maintainer : Vincent Hanquez <vincent@snarc.org> -- Stability : stable -- Portability : good+--+-- Random bytes, drawn either from the system or from a generator whose+-- seed you hold.+--+-- == Drawing from the system+--+-- 'getRandomBytes' in 'IO' is the ordinary way to get bytes nobody can+-- predict. The length is in bytes and the type is any 'ByteArray', so the+-- result is usually pinned down by where it goes:+--+-- > import Crypto.Random (getRandomBytes)+-- > import Data.ByteString (ByteString)+-- >+-- > nonce <- getRandomBytes 12 :: IO ByteString+--+-- Everything in this library that needs randomness takes it the same way,+-- through a @MonadRandom m =>@ constraint, so running it in 'IO' is the+-- whole of choosing this source:+--+-- > import qualified Crypto.PubKey.RSA as RSA+-- >+-- > (pub, priv) <- RSA.generate 256 0x10001+--+-- Where the operating system offers @getrandom(2)@ or @getentropy(3)@ the+-- bytes come from a ChaCha20 generator belonging to the operating system+-- thread the call runs on, seeded from the system and reseeded as it goes;+-- see "Crypto.Random.SysDRG" for what that is and what it is not. Where+-- it does not -- Windows, for now -- they come from the system on every+-- call, as they always did. Either way the caller writes the same line.+--+-- Any Haskell thread may draw, and none has to say which generator it+-- wants:+--+-- > import Control.Concurrent (forkIO)+-- >+-- > mapM_ (\_ -> forkIO (getRandomBytes 32 >>= use)) [1 .. 64 :: Int]+--+-- The generator belongs to the operating system thread that happens to be+-- carrying the Haskell thread when the call is made, and is found through+-- that thread's own storage rather than by anything the caller passes. A+-- @forkIO@ thread moves between capabilities, so two draws from one Haskell+-- thread may be answered by two generators; they are seeded independently+-- of each other, so it makes no difference which one answers.+--+-- == Drawing from a generator you hold+--+-- A generator of your own is the way to draw many times from one seed.+-- The system is asked once, when the generator is made, and not again.+-- That is how @tls@ does a connection: 'seedNew' when it opens, and+-- everything the handshake needs afterwards from the generator, whose+-- state the connection carries from one draw to the next.+--+-- > import Crypto.Random (ChaChaDRG, drgNewSeed, seedNew, withDRG)+-- >+-- > data Connection = Connection { connRNG :: ChaChaDRG }+-- >+-- > newConnection :: IO Connection+-- > newConnection = do+-- > seed <- seedNew -- the only draw from the system+-- > return (Connection (drgNewSeed seed))+-- >+-- > -- every later draw advances the connection's own generator+-- > connRandom :: Int -> Connection -> (ByteString, Connection)+-- > connRandom n conn =+-- > let (bytes, rng') = withDRG (connRNG conn) (getRandomBytes n)+-- > in (bytes, conn{connRNG = rng'})+--+-- Inside 'withDRG' the same 'getRandomBytes' resolves to the instance for+-- 'MonadPseudoRandom' rather than the one for 'IO', so it touches neither+-- the system nor the per-thread generator: it advances the generator it was+-- given and hands it back. Keep that generator and the bytes are+-- reproducible from the seed, which is what makes a test repeatable -- and+-- what makes a generator unfit for keys unless its seed came from the+-- system.+--+-- 'drgNew' is 'seedNew' and 'drgNewSeed' in one step; 'drgNewTest' takes+-- four numbers instead of a seed, for a test that must give the same answer+-- twice.+--+-- == Drawing from a monad stacked on IO+--+-- There are two instances, one for 'IO' and one for 'MonadPseudoRandom',+-- and none for the transformers, so a @ReaderT env IO@ or a @StateT s IO@+-- reaches the system through 'liftIO':+--+-- > import Control.Monad.IO.Class (liftIO)+-- > import Control.Monad.Trans.Reader (ReaderT)+-- >+-- > newKey :: ReaderT env IO ByteString+-- > newKey = liftIO (getRandomBytes 32)+--+-- What that draws is what the first section describes, no more and no less:+-- the 'IO' instance, the generator of the operating system thread the call+-- lands on, seeded from the system and reseeded as it goes. 'liftIO' says+-- which monad the draw happens in and nothing about where the bytes come+-- from.+--+-- Writing an instance for the stack instead would make the choice invisible+-- at the call site, and the class cannot tell a strong source from a weak+-- one -- see 'MonadRandom'.+--+-- == When the system will not give any+--+-- Drawing randomness is the one thing here with nothing to fall back on,+-- so the failure is an exception rather than a value: there is no sensible+-- 'Maybe' to return and no partial answer worth having. Since 2.2 it is an+-- 'EntropyError' and not a @Control.Exception.ErrorCall@ or an+-- @Control.Exception.IOException@, which is worth knowing if you were+-- catching one of those:+--+-- > import Control.Exception (catch)+-- > import Crypto.Random (EntropyError (..), getRandomBytes)+-- >+-- > key <- getRandomBytes 32 `catch` \e -> case e of+-- > NoEntropySource -> fail "this system offers no randomness at all"+-- > EntropyShort w g -> fail (show w ++ " bytes wanted, " ++ show g ++ " arrived")+-- > EntropySourceLost s -> fail ("the source " ++ s ++ " went away")+--+-- Catching it at all is a decision rather than a default. A program that+-- cannot get randomness cannot make a key, and stopping is usually the+-- honest thing; the reason to catch is to say so in the program's own+-- terms rather than in crypton's. module Crypto.Random (- -- * Deterministic instances- ChaChaDRG,- SystemDRG,- Seed,+ -- * Drawing from the system+ MonadRandom (..), - -- * Seed+ -- * Drawing from a generator you hold+ Seed, seedNew, seedFromInteger, seedToInteger, seedFromBinary,-- -- * Deterministic Random class- getSystemDRG,- drgNew, drgNewSeed,+ drgNew, drgNewTest, withDRG, withRandomBytes,+ MonadPseudoRandom, DRG (..), - -- * Random abstraction- MonadRandom (..),- MonadPseudoRandom,+ -- * The generators+ ChaChaDRG,+ SystemDRG,+ getSystemDRG,++ -- * When the system will not give any+ EntropyError (..), ) where import Crypto.Error import Crypto.Internal.Imports import Crypto.Random.ChaChaDRG+import Crypto.Random.Entropy (EntropyError (..)) import Crypto.Random.SystemDRG import Crypto.Random.Types import Data.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes)@@ -50,6 +174,9 @@ import Foreign.Ptr (Ptr, castPtr) #endif +-- | The material a deterministic generator is built from. Two generators+-- made from one seed produce the same bytes, which is what 'drgNewSeed' is+-- for and why a seed kept anywhere is as good as the keys drawn from it. newtype Seed = Seed ScrubbedBytes deriving (ByteArrayAccess)
@@ -6,16 +6,37 @@ -- Portability : Good module Crypto.Random.Entropy ( getEntropy,+ EntropyError (..), ) where import Crypto.Internal.ByteArray (ByteArray) import qualified Crypto.Internal.ByteArray as B-import Data.Maybe (catMaybes)+import System.IO.Unsafe (unsafeInterleaveIO, unsafePerformIO) import Crypto.Random.Entropy.Unsafe +-- | The backends this system has, worked out once and no further than+-- needed.+--+-- Opening one is not free: for a device file it means opening and closing+-- @\/dev\/random@ or @\/dev\/urandom@ just to learn that it is there. This+-- used to be done on every call, and for the whole list before any backend+-- was asked for a byte, so a program paid for both devices even when the+-- first backend answered everything.+--+-- Once, now, and lazily: 'replenish' stops as soon as the buffer is full,+-- which leaves the tail of this list unforced, so a system where the first+-- backend answers never opens a device at all.+{-# NOINLINE openedBackends #-}+openedBackends :: [EntropyBackend]+openedBackends = unsafePerformIO (openAsNeeded supportedBackends)+ where+ openAsNeeded [] = return []+ openAsNeeded (o : os) = do+ m <- o+ rest <- unsafeInterleaveIO (openAsNeeded os)+ return $ maybe rest (: rest) m+ -- | Get some entropy from the system source of entropy getEntropy :: ByteArray byteArray => Int -> IO byteArray-getEntropy n = do- backends <- catMaybes `fmap` sequence supportedBackends- B.alloc n (replenish n backends)+getEntropy n = B.alloc n (replenish n openedBackends)
@@ -11,27 +11,39 @@ ( EntropyBackend , supportedBackends , gatherBackend+ , EntropyError(..) ) where import Foreign.Ptr import Data.Proxy import Data.Word (Word8) import Crypto.Random.Entropy.Source-#ifdef SUPPORT_RDRAND-import Crypto.Random.Entropy.RDRand-#endif #ifdef WINDOWS import Crypto.Random.Entropy.Windows #else+import Crypto.Random.Entropy.SysRandom import Crypto.Random.Entropy.Unix #endif --- | All supported backends +-- | All supported backends, best first.+--+-- The system call comes before everything else: it is the kernel's own+-- generator, it needs no descriptor, and it is what the rest of the world+-- reaches for now. The device files are what is left when the system has+-- no such call.+--+-- RDRAND is deliberately not here, though it used to be first on x86. A+-- list like this one is a list of alternatives, and whichever answers+-- first decides the bytes on its own -- which is the one thing #298 says+-- RDRAND should not do. Nor does it contribute anywhere else: every+-- system this builds for already feeds the instruction into the pool the+-- call above draws from, so asking it again adds nothing. See the note in+-- @cbits\/crypton_sysdrg.c@. supportedBackends :: [IO (Maybe EntropyBackend)] supportedBackends = [-#ifdef SUPPORT_RDRAND- openBackend (Proxy :: Proxy RDRand),+#ifndef WINDOWS+ openBackend (Proxy :: Proxy SysRandom), #endif #ifdef WINDOWS openBackend (Proxy :: Proxy WinCryptoAPI)
@@ -1,39 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface #-}---- |--- Module : Crypto.Random.Entropy.RDRand--- License : BSD-style--- Maintainer : Vincent Hanquez <vincent@snarc.org>--- Stability : experimental--- Portability : Good-module Crypto.Random.Entropy.RDRand (- RDRand,-) where--import Crypto.Random.Entropy.Source-import Data.Word (Word8)-import Foreign.C.Types-import Foreign.Ptr--foreign import ccall unsafe "crypton_cpu_has_rdrand"- c_cpu_has_rdrand :: IO CInt--foreign import ccall unsafe "crypton_get_rand_bytes"- c_get_rand_bytes :: Ptr Word8 -> CInt -> IO CInt---- | Fake handle to Intel RDRand entropy CPU instruction-data RDRand = RDRand--instance EntropySource RDRand where- entropyOpen = rdrandGrab- entropyGather _ = rdrandGetBytes- entropyClose _ = return ()--rdrandGrab :: IO (Maybe RDRand)-rdrandGrab = supported `fmap` c_cpu_has_rdrand- where- supported 0 = Nothing- supported _ = Just RDRand--rdrandGetBytes :: Ptr Word8 -> Int -> IO Int-rdrandGetBytes ptr sz = fromIntegral `fmap` c_get_rand_bytes ptr (fromIntegral sz)
@@ -6,8 +6,32 @@ -- Portability : Good module Crypto.Random.Entropy.Source where +import Control.Exception (Exception) import Data.Word (Word8) import Foreign.Ptr++-- | The system would not give the entropy it was asked for.+--+-- This is the one failure in the library with nothing to fall back on and+-- nothing sensible to return: a key drawn from bytes that are not random+-- is worse than no key. It used to be reported with 'error' and 'fail',+-- which left a caller no way to tell it from a bug in the library, and no+-- way to say anything useful about it.+data EntropyError+ = -- | The system offers no source of entropy at all. On Unix that+ -- means no @getrandom(2)@, no @getentropy(3)@ and no @\/dev@ to read+ -- from; a container built from nothing would look like this.+ NoEntropySource+ | -- | The sources between them gave fewer bytes than were asked for,+ -- three times over. The two numbers are how many were wanted and+ -- how many arrived.+ EntropyShort Int Int+ | -- | A source that could be opened once could not be opened again.+ -- The string names it.+ EntropySourceLost String+ deriving (Show, Eq)++instance Exception EntropyError -- | A handle to an entropy maker, either a system capability -- or a hardware generator.
@@ -0,0 +1,50 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module : Crypto.Random.Entropy.SysRandom+-- License : BSD-style+-- Maintainer : Kazu Yamamoto <kazu@iij.ad.jp>+-- Stability : experimental+-- Portability : Unix+--+-- The kernel's own generator, reached without a file descriptor:+-- @getrandom(2)@ on Linux and FreeBSD, @getentropy(3)@ where that is what+-- the system has.+--+-- This is the source to prefer over reading @\/dev\/urandom@. It needs no+-- path and no descriptor, so it still answers where @\/dev@ is not mounted+-- or not populated, and it cannot be defeated by a full descriptor table.+module Crypto.Random.Entropy.SysRandom (+ SysRandom,+) where++import Crypto.Random.Entropy.Source+import Data.Word (Word8)+import Foreign.C.Types+import Foreign.Ptr++-- Both are @safe@ rather than @unsafe@: at early boot, before the kernel+-- pool is initialised, these calls block, and an unsafe call that blocks+-- holds the capability it runs on.+foreign import ccall safe "crypton_sysrandom_available"+ c_sysrandom_available :: IO CInt++foreign import ccall safe "crypton_sysrandom_bytes"+ c_sysrandom_bytes :: Ptr Word8 -> CInt -> IO CInt++-- | The system call, where there is one.+data SysRandom = SysRandom++instance EntropySource SysRandom where+ -- Asked at run time and not only at compile time: a binary built where+ -- the header declares the call can still run on a kernel that answers+ -- ENOSYS.+ entropyOpen = available `fmap` c_sysrandom_available+ where+ available 0 = Nothing+ available _ = Just SysRandom++ entropyGather _ ptr n =+ fromIntegral `fmap` c_sysrandom_bytes ptr (fromIntegral n)++ entropyClose _ = return ()
@@ -61,7 +61,7 @@ withDev filepath f = openDev filepath >>= \h -> case h of- Nothing -> error ("device " ++ filepath ++ " cannot be grabbed")+ Nothing -> E.throwIO (EntropySourceLost filepath) Just fd -> f fd `E.finally` closeDev fd closeDev :: H -> IO ()
@@ -9,25 +9,27 @@ module Crypto.Random.Entropy.Backend, ) where +import Control.Exception (throwIO)+ import Crypto.Random.Entropy.Backend import Data.Word (Word8) import Foreign.Ptr (Ptr, plusPtr) -- | Refill the entropy in a buffer ----- Call each entropy backend in turn until the buffer has--- been replenished.+-- Call each entropy backend in turn until the buffer has been replenished. ----- If the buffer cannot be refill after 3 loopings, this will raise--- an User Error exception+-- Throws 'EntropyError': 'NoEntropySource' when there is no backend at all,+-- and 'EntropyShort' when three passes over the backends still leave the+-- buffer unfilled. replenish :: Int -> [EntropyBackend] -> Ptr Word8 -> IO ()-replenish _ [] _ = fail "crypton: random: cannot get any source of entropy on this system"+replenish _ [] _ = throwIO NoEntropySource replenish poolSize backends ptr = loop 0 backends ptr poolSize where loop :: Int -> [EntropyBackend] -> Ptr Word8 -> Int -> IO () loop _ _ _ 0 = return () loop retry [] p n- | retry == 3 = error "crypton: random: cannot fully replenish"+ | retry == 3 = throwIO $ EntropyShort poolSize (poolSize - n) | otherwise = loop (retry + 1) backends p n loop retry (b : bs) p n = do r <- gatherBackend b p n
@@ -23,6 +23,7 @@ import Foreign.Storable (peek) import System.Win32.Types (getLastError) +import Control.Exception (throwIO) import Crypto.Random.Entropy.Source @@ -38,7 +39,8 @@ case mctx of Nothing -> do lastError <- getLastError- fail $ "cannot re-grab win crypto api: error " ++ show lastError+ throwIO $ EntropySourceLost+ ("the Windows crypto API: error " ++ show lastError) Just ctx -> do r <- cryptGenRandom ctx ptr n cryptReleaseCtx ctx@@ -100,4 +102,5 @@ then return () else do lastError <- getLastError- fail $ "cryptReleaseCtx: error " ++ show lastError+ throwIO $ EntropySourceLost+ ("cryptReleaseCtx: error " ++ show lastError)
@@ -0,0 +1,82 @@+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module : Crypto.Random.SysDRG+-- License : BSD-style+-- Maintainer : Kazu Yamamoto <kazu@iij.ad.jp>+-- Stability : experimental+-- Portability : Unix, Windows+--+-- The generator behind the 'Crypto.Random.MonadRandom' instance for 'IO'.+--+-- A ChaCha20 generator per operating system thread, seeded from a+-- process-wide generator, seeded in turn from the system entropy pool.+-- The state and the reseeding live in+-- @cbits\/crypton_sysdrg.c@, because a @forkIO@ thread is not an operating+-- system thread -- it moves between capabilities -- so state held against+-- one would be shared by threads running at the same time.+--+-- == What it is, and what it is not+--+-- It is not a DRBG of NIST SP 800-90A. That standard names three --+-- @Hash_DRBG@, @HMAC_DRBG@ and @CTR_DRBG@ -- and none of them is built on a+-- stream cipher. The name here is the older and looser sense of the word.+--+-- What it is is the shape @arc4random@ on OpenBSD and @get_random_bytes@ in+-- the Linux kernel both have, and the one asked for in+-- <https://github.com/kazu-yamamoto/crypton/issues/298>. That shape is+-- common; it is not specified anywhere, so the parts a standard would have+-- fixed were chosen here instead:+--+-- * ChaCha20, rather than AES in counter mode.+-- * SHA-512 over the system's bytes, rather than a derivation function a+-- standard would have named.+-- * A mebibyte per thread, and a mebibyte of issued seed for the process+-- generator, as the points at which to reseed. Those numbers are a+-- choice, not a result.+--+-- The pieces underneath are specified: ChaCha20 is RFC 8439, SHA-512 is+-- FIPS 180-4. The way they are put together is not.+--+-- == What a compromised state gives away+--+-- Each draw ends by taking the next forty bytes of keystream as the key and+-- nonce and dropping the ones that made the output, so a state read after a+-- draw is not the state that produced it. ChaCha20 does not run backwards+-- and the key that would be needed is gone, which is backtracking+-- resistance in the terms of SP 800-90A. Without it, a key stands until+-- the next reseed and anyone holding the state can wind the counter back+-- over everything issued since -- a mebibyte of output that was meant to be+-- secret. It is what @arc4random@ does, and for the same reason.+--+-- Prediction resistance is what the reseeding gives. A reseed draws from+-- the system again, so a state that has been read does not determine what+-- comes after one.+module Crypto.Random.SysDRG (+ sysDRGBytes,+) where++import Data.Word (Word8)+import Foreign.C.Types (CInt (..))+import Foreign.Ptr (Ptr)++import Crypto.Internal.ByteArray (ByteArray)+import qualified Crypto.Internal.ByteArray as B++-- Safe, not unsafe: seeding can reach a getrandom(2) that blocks until the+-- kernel pool is ready, and an unsafe call that blocks holds the capability+-- it runs on.+foreign import ccall safe "crypton_sysdrg_bytes"+ c_sysdrg_bytes :: Ptr Word8 -> CInt -> IO CInt++-- | Draw bytes, or 'Nothing' if the generator cannot be seeded.+--+-- It cannot be seeded where the system has no @getrandom(2)@ or+-- @getentropy(3)@; the caller falls back to+-- 'Crypto.Random.Entropy.getEntropy' there, which is the path this system+-- had before the generator existed.+sysDRGBytes :: ByteArray byteArray => Int -> IO (Maybe byteArray)+sysDRGBytes n = do+ (got, out) <- B.allocRet n $ \ptr ->+ fromIntegral `fmap` c_sysdrg_bytes ptr (fromIntegral n)+ return $ if got == n then Just out else Nothing
@@ -13,8 +13,21 @@ import Crypto.Internal.ByteArray import Crypto.Random.Entropy+import Crypto.Random.SysDRG (sysDRGBytes) -- | A monad constraint that allows to generate random bytes+--+-- Everything in this library that draws a key, a nonce or a signature's+-- randomness draws it through this class, and cannot tell a strong source+-- from a weak one. The two instances below are the ones to reach for:+-- @IO@ reads the system entropy source, and @MonadPseudoRandom@ runs a+-- 'DRG' seeded from it.+--+-- An instance of your own is held to the same standard. A generator that+-- another party can predict, or that repeats, yields keys and signatures+-- that give away what they are meant to keep -- so the deliberately+-- repeatable instance that makes a test reproducible is not one to ship+-- with. class Monad m => MonadRandom m where getRandomBytes :: ByteArray byteArray => Int -> m byteArray @@ -23,8 +36,13 @@ -- | Generate N bytes of randomness from a DRG randomBytesGenerate :: ByteArray byteArray => Int -> gen -> (byteArray, gen) +-- | Through the generator of 'Crypto.Random.SysDRG': a ChaCha20 generator+-- per operating system thread, reseeded from the system. Where that+-- cannot be seeded -- a system with no @getrandom(2)@ or @getentropy(3)@,+-- which includes Windows for now -- this is the system entropy source+-- directly, as it was before the generator existed. instance MonadRandom IO where- getRandomBytes = getEntropy+ getRandomBytes n = sysDRGBytes n >>= maybe (getEntropy n) return -- | A simple Monad class very similar to a State Monad -- with the state being a DRG.
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE PatternSynonyms #-} -- | -- Module : Crypto.System.CPU@@ -11,57 +11,218 @@ -- -- Gives information about crypton runtime environment. module Crypto.System.CPU (- ProcessorOption (..),+ -- The names are bundled with the type rather than listed as+ -- `pattern' exports, so an importer writes ProcessorOption (..), or+ -- names the ones it wants, as it would for a type with constructors.+ ProcessorOption (+ -- x86+ AESNI,+ PCLMUL,+ SSSE3,+ AVX,+ AVX2,+ SHANI,+ MOVBE,+ ADX,+ VAES,+ VAES512,+ AVX512IFMA,+ -- AArch64+ NEON,+ ARMAES,+ ARMPMULL,+ ARMSHA1,+ ARMSHA2,+ ARMSHA512,+ -- PowerISA+ PPCAES,+ PPCVPMSUM+ ), processorOptions,-) where -import Data.Data-import Data.List (findIndices)-#ifdef SUPPORT_RDRAND-import Data.Maybe (isJust)-#endif-import Data.Word (Word8)-import Foreign.Ptr-import Foreign.Storable+ -- * Questions that do not name an architecture+ hasAESAcceleration,+ hasGHASHAcceleration,+) where +import Control.Monad (filterM)+import Data.List (sort)+import Data.Word (Word16)+import Foreign.C.Types (CInt (..), CUInt (..)) import Crypto.Internal.Compat -#ifdef SUPPORT_RDRAND-import Crypto.Random.Entropy.RDRand-import Crypto.Random.Entropy.Source-#endif+-- | A processor feature crypton looked for, and dispatches on where it+-- finds it.+--+-- This is a number with names rather than a sum of constructors, and the+-- names are pattern synonyms with no @COMPLETE@ pragma, so a @case@ over+-- them needs a catch-all and a feature named in a later release breaks+-- nothing that compiled against this one. The same reason 'Show' is+-- written out below: a program built against an older crypton still says+-- something useful about a value from a newer one.+--+-- The names are the processor's, not the operation's. 'AESNI' is x86's+-- and 'ARMAES' is AArch64's, and a machine reports only the ones it has;+-- ask 'hasAESAcceleration' if the question is whether AES is fast here.+--+-- They are bundled with the type in the export list, so @ProcessorOption+-- (..)@ brings in all of them and naming one brings in that one, as for a+-- type with constructors. The constructor underneath is not exported:+-- these values say what the processor was found to have, and a caller has+-- nothing to build.+newtype ProcessorOption = ProcessorOption Word16+ deriving (Eq, Ord) --- | CPU options impacting cryptography implementation and library performance.-data ProcessorOption- = -- | Support for AES instructions, with flag @support_aesni@- AESNI- | -- | Support for CLMUL instructions, with flag @support_pclmuldq@- PCLMUL- | -- | Support for RDRAND instruction, with flag @support_rdrand@- RDRAND- deriving (Show, Eq, Enum, Data)+-- | Support for AES instructions, with flag @support_aesni@.+pattern AESNI :: ProcessorOption+pattern AESNI = ProcessorOption 0 --- | Options which have been enabled at compile time and are supported by the--- current CPU.+-- | Support for CLMUL instructions, with flag @support_pclmuldq@.+pattern PCLMUL :: ProcessorOption+pattern PCLMUL = ProcessorOption 1++-- | Supplemental SSE3.+pattern SSSE3 :: ProcessorOption+pattern SSSE3 = ProcessorOption 3++-- | AVX, and an operating system that saves its registers.+pattern AVX :: ProcessorOption+pattern AVX = ProcessorOption 4++-- | AVX2, and an operating system that saves its registers.+pattern AVX2 :: ProcessorOption+pattern AVX2 = ProcessorOption 5++-- | The SHA extensions, @sha1rnds4@ and @sha256rnds2@ and their neighbours.+pattern SHANI :: ProcessorOption+pattern SHANI = ProcessorOption 6++-- | The byte-swapping load.+pattern MOVBE :: ProcessorOption+pattern MOVBE = ProcessorOption 7++-- | @MULX@, @ADCX@ and @ADOX@: the two independent carry chains.+pattern ADX :: ProcessorOption+pattern ADX = ProcessorOption 8++-- | The AES and carry-less multiply instructions in their 256-bit form.+pattern VAES :: ProcessorOption+pattern VAES = ProcessorOption 9++-- | The same pair in their 512-bit form.+pattern VAES512 :: ProcessorOption+pattern VAES512 = ProcessorOption 10++-- | The AVX-512 52-bit integer multiply-adds, with AVX-512 F and VL, and the+-- operating system saving their state: RSA's private-key operation uses them.+pattern AVX512IFMA :: ProcessorOption+pattern AVX512IFMA = ProcessorOption 19++-- | Advanced SIMD, which is not optional on AArch64.+pattern NEON :: ProcessorOption+pattern NEON = ProcessorOption 11++-- | The ARMv8 AES instructions.+pattern ARMAES :: ProcessorOption+pattern ARMAES = ProcessorOption 12++-- | @PMULL@, the ARMv8 carry-less multiply.+pattern ARMPMULL :: ProcessorOption+pattern ARMPMULL = ProcessorOption 13++-- | The ARMv8 SHA-1 instructions.+pattern ARMSHA1 :: ProcessorOption+pattern ARMSHA1 = ProcessorOption 14++-- | The ARMv8 SHA-256 instructions.+pattern ARMSHA2 :: ProcessorOption+pattern ARMSHA2 = ProcessorOption 15++-- | The ARMv8.2 SHA-512 instructions, which are optional where SHA-256's+-- are not.+pattern ARMSHA512 :: ProcessorOption+pattern ARMSHA512 = ProcessorOption 16++-- | Support for the PowerISA 2.07 vector AES instructions, which POWER8 was+-- the first to implement.+pattern PPCAES :: ProcessorOption+pattern PPCAES = ProcessorOption 17++-- | Support for @vpmsumd@, the vector carry-less multiply that came with+-- them, which is what makes GHASH fast.+pattern PPCVPMSUM :: ProcessorOption+pattern PPCVPMSUM = ProcessorOption 18++-- | Named where the name is known, numbered where it is not, so that a+-- binary built against an older crypton can still print a value a newer one+-- produced.+instance Show ProcessorOption where+ show AESNI = "AESNI"+ show PCLMUL = "PCLMUL"+ show SSSE3 = "SSSE3"+ show AVX = "AVX"+ show AVX2 = "AVX2"+ show SHANI = "SHANI"+ show MOVBE = "MOVBE"+ show ADX = "ADX"+ show VAES = "VAES"+ show VAES512 = "VAES512"+ show AVX512IFMA = "AVX512IFMA"+ show NEON = "NEON"+ show ARMAES = "ARMAES"+ show ARMPMULL = "ARMPMULL"+ show ARMSHA1 = "ARMSHA1"+ show ARMSHA2 = "ARMSHA2"+ show ARMSHA512 = "ARMSHA512"+ show PPCAES = "PPCAES"+ show PPCVPMSUM = "PPCVPMSUM"+ show (ProcessorOption n) = "ProcessorOption " ++ show n++-- | Options which have been enabled at compile time and which this machine+-- says may be used: on x86-64 what the processor declares through CPUID, and+-- for the vector extensions only where the operating system saves their+-- state as well; elsewhere what the operating system reports of the+-- processor.+--+-- That is what crypton itself decides by, and it is not always everything+-- the core underneath executes. A guest under a hypervisor may be shown an+-- older processor model than the host's, so that it can be moved to another+-- host -- and an instruction used because it happens to run would fail+-- there. So an option missing here means crypton will not use it, not that+-- the hardware lacks it.+--+-- Sorted, and without repeats. A machine reports the names of its own+-- architecture only: an AArch64 processor with AES says 'ARMAES', not+-- 'AESNI', which it does not have. processorOptions :: [ProcessorOption]-processorOptions = unsafeDoIO $ do- p <- crypton_aes_cpu_init- options <- traverse (getOption p) aesOptions- rdrand <- hasRDRand- return (decodeOptions options ++ [RDRAND | rdrand])+processorOptions = unsafeDoIO (sort <$> filterM askC allOptions) where- aesOptions = [AESNI .. PCLMUL]- getOption p = peekElemOff p . fromEnum- decodeOptions = map toEnum . findIndices (> 0)+ -- 2 is not asked for and has no name: it was RDRAND, which crypton no+ -- longer dispatches on. The number is left out rather than reused, so+ -- that the others keep the values they had.+ allOptions = [ProcessorOption n | n <- [0 .. 19], n /= 2]+ askC (ProcessorOption n) =+ (/= 0) <$> crypton_cpu_option (fromIntegral n) {-# NOINLINE processorOptions #-} -hasRDRand :: IO Bool-#ifdef SUPPORT_RDRAND-hasRDRand = fmap isJust getRDRand- where getRDRand = entropyOpen :: IO (Maybe RDRand)-#else-hasRDRand = return False-#endif+-- | Is there hardware AES on this machine?+--+-- The instructions have different names on different architectures, and a+-- caller that wants to know whether AES-GCM will be fast wants this rather+-- than either name.+hasAESAcceleration :: Bool+hasAESAcceleration =+ any+ (`elem` processorOptions)+ [AESNI, ARMAES, PPCAES] -foreign import ccall unsafe "crypton_aes_cpu_init"- crypton_aes_cpu_init :: IO (Ptr Word8)+-- | Is there a hardware carry-less multiply, which is what GHASH, and so+-- AES-GCM, spends its time in once AES itself is fast?+hasGHASHAcceleration :: Bool+hasGHASHAcceleration =+ any+ (`elem` processorOptions)+ [PCLMUL, ARMPMULL, PPCVPMSUM]++foreign import ccall unsafe "crypton_cpu_option"+ crypton_cpu_option :: CUInt -> IO CInt
@@ -1,4 +1,7 @@ -- | Examples of how to use @crypton@.+--+-- Every code block here is extracted and compiled against this version of+-- the library by @tests\/tutorial\/run.sh@, so what is written below builds. module Crypto.Tutorial ( -- * API design -- $api_design@@ -6,9 +9,21 @@ -- * Hash algorithms -- $hash_algorithms - -- * Symmetric block ciphers- -- $symmetric_block_ciphers+ -- * Authenticated encryption+ -- $authenticated_encryption + -- * Comparing secrets+ -- $comparing_secrets++ -- * Password storage+ -- $password_storage++ -- * Key derivation+ -- $key_derivation++ -- * Digital signatures+ -- $digital_signatures+ -- * Combining primitives -- $combining_primitives ) where@@ -31,6 +46,14 @@ -- Error conditions are returned with data type 'Crypto.Error.CryptoFailable'. -- Functions in module "Crypto.Error" can convert those values to runtime -- exceptions, 'Maybe' or 'Either' values.+--+-- Types that hold a secret do not print it. A private key's 'Show' renders+-- whatever is public and @\<secret\>@ or @\<scrubbed-bytes\>@ for the rest,+-- because 'Show' is what @print@, @error@, an exception and a failing test+-- all reach for, and a key arriving in a log that way is an accident nobody+-- asked for. "Crypto.Debug" is how one is printed when printing it is what+-- was meant. Several of those types keep their bytes in+-- 'Data.ByteArray.ScrubbedBytes', which is wiped when it is collected. -- $hash_algorithms --@@ -90,72 +113,258 @@ -- > hashMutableUpdate ctx ("dog" :: ByteString) -- > hashMutableFinalize ctx >>= print --- $symmetric_block_ciphers+-- $authenticated_encryption --+-- Encrypting hides a message; it does not stop anyone changing it. Under a+-- counter or stream mode, flipping a bit of the ciphertext flips the same+-- bit of the plaintext, and the receiver has no way to tell. An AEAD mode+-- binds the message, and anything else named as associated data, to a short+-- authentication tag, and decrypting something that does not match that tag+-- returns nothing at all.+--+-- That is the mode to use. The unauthenticated ones are in this library+-- for protocols that authenticate separately, not as a starting point.+-- -- > {-# LANGUAGE OverloadedStrings #-}--- > {-# LANGUAGE ScopedTypeVariables #-}--- > {-# LANGUAGE GADTs #-} -- > -- > import Crypto.Cipher.AES (AES256)--- > import Crypto.Cipher.Types (BlockCipher(..), Cipher(..), nullIV, KeySizeSpecifier(..), IV, makeIV)--- > import Crypto.Error (CryptoFailable(..), CryptoError(..))+-- > import Crypto.Cipher.Types+-- > ( AEADMode (AEAD_GCM)+-- > , AuthTag+-- > , BlockCipher (aeadInit)+-- > , Cipher (cipherInit, cipherKeySize)+-- > , KeySizeSpecifier (..)+-- > , aeadSimpleDecrypt+-- > , aeadSimpleEncrypt+-- > )+-- > import Crypto.Error (CryptoError, eitherCryptoError)+-- > import qualified Crypto.Random.Types as CRT -- >+-- > import Data.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes)+-- > import Data.ByteString (ByteString)+-- >+-- > -- | A key of the length the cipher asks for, rather than a length+-- > -- written out here. ScrubbedBytes rather than ByteString, so that it+-- > -- is wiped when it is collected and does not print.+-- > genSecretKey :: (Cipher c, CRT.MonadRandom m) => c -> m ScrubbedBytes+-- > genSecretKey c = CRT.getRandomBytes (longest (cipherKeySize c))+-- > where+-- > longest (KeySizeFixed n) = n+-- > longest (KeySizeRange _ n) = n+-- > longest (KeySizeEnum ns) = maximum ns+-- >+-- > -- | A fresh nonce for every message. GCM must never see one twice+-- > -- under the same key: a repeat does not just expose those two messages,+-- > -- it hands over the key that authenticates all of them. Twelve random+-- > -- bytes, sent along with the ciphertext.+-- > genNonce :: CRT.MonadRandom m => m ByteString+-- > genNonce = CRT.getRandomBytes 12+-- >+-- > -- | Encrypt and authenticate. The associated data is authenticated but+-- > -- not encrypted: it is for what the receiver can already see and must+-- > -- not have had altered, such as a header or an address.+-- > encrypt+-- > :: (ByteArray key, ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba)+-- > => key -> nonce -> aad -> ba -> Either CryptoError (AuthTag, ba)+-- > encrypt key nonce aad plaintext = do+-- > cipher <- eitherCryptoError (cipherInit key) :: Either CryptoError AES256+-- > aead <- eitherCryptoError (aeadInit AEAD_GCM cipher nonce)+-- > return (aeadSimpleEncrypt aead aad plaintext 16)+-- >+-- > -- | And back, with two different failures. Left is this code used+-- > -- wrongly -- a key of the wrong length, a mode the cipher has not got.+-- > -- Nothing is a message that is not the one that was sent; it carries no+-- > -- plaintext and says nothing about which byte was wrong, both of which+-- > -- are the point.+-- > decrypt+-- > :: (ByteArray key, ByteArrayAccess nonce, ByteArrayAccess aad, ByteArray ba)+-- > => key -> nonce -> aad -> AuthTag -> ba -> Either CryptoError (Maybe ba)+-- > decrypt key nonce aad tag ciphertext = do+-- > cipher <- eitherCryptoError (cipherInit key) :: Either CryptoError AES256+-- > aead <- eitherCryptoError (aeadInit AEAD_GCM cipher nonce)+-- > return (aeadSimpleDecrypt aead aad ciphertext tag)+-- >+-- > exampleAES256GCM :: ByteString -> IO ()+-- > exampleAES256GCM msg = do+-- > key <- genSecretKey (undefined :: AES256)+-- > nonce <- genNonce+-- > let aad = "to: alice" :: ByteString+-- > case encrypt key nonce aad msg of+-- > Left err -> error (show err)+-- > Right (tag, ciphertext) -> do+-- > putStrLn $ "ciphertext: " ++ show ciphertext+-- > putStrLn $ " tag: " ++ show tag+-- > putStrLn $ " recovered: "+-- > ++ show (decrypt key nonce aad tag ciphertext)+-- > -- The same bytes and the same tag, with one thing changed+-- > -- that was never encrypted: Right Nothing.+-- > putStrLn $ "redirected: "+-- > ++ show (decrypt key nonce ("to: eve" :: ByteString) tag ciphertext)+--+-- The two functions above work for any cipher that has an AEAD mode; what+-- changes is the mode given to 'Crypto.Cipher.Types.aeadInit'.+-- "Crypto.Cipher.ChaChaPoly1305" is the one to prefer on a machine with no+-- AES instructions, and "Crypto.Cipher.AESGCMSIV" is the one that survives+-- a repeated nonce, at the price of needing the whole message before it can+-- begin.++-- $comparing_secrets+--+-- Comparing two byte strings with '==' stops at the first byte that+-- differs, so how long it takes says where that byte was. Against an+-- authentication tag that is the whole secret: someone who can send a guess+-- and time the answer finds the first byte in a few hundred tries, then the+-- second, and has a tag that was supposed to cost 2^128 in a few thousand.+--+-- crypton's own authentication types already compare in constant time, so+-- for those there is nothing to do: 'Crypto.MAC.HMAC.HMAC',+-- 'Crypto.MAC.CMAC.CMAC', 'Crypto.MAC.Poly1305.Auth' and+-- 'Crypto.Cipher.Types.AuthTag' have an 'Eq' that looks at every byte+-- whatever it finds. What needs care is a tag that arrives as bytes, and+-- 'Data.ByteArray.constEq' is the comparison for it.+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > import Crypto.Hash.Algorithms (SHA256)+-- > import Crypto.MAC.HMAC (HMAC, hmac)+-- >+-- > import qualified Data.ByteArray as BA+-- > import Data.ByteString (ByteString)+-- >+-- > -- | The tag came off the wire as bytes, so it is compared as bytes.+-- > authentic :: ByteString -> ByteString -> ByteString -> Bool+-- > authentic key message tag =+-- > BA.constEq tag (hmac key message :: HMAC SHA256)+-- >+-- > -- | Once it has been parsed into the library's own type, (==) is+-- > -- already the constant-time comparison.+-- > authentic' :: ByteString -> ByteString -> HMAC SHA256 -> Bool+-- > authentic' key message tag = tag == hmac key message++-- $password_storage+--+-- A password is not a key. It is short and it is guessable, and whoever+-- takes the database can try every likely one without being watched. What+-- answers that is a function that is deliberately expensive to compute, and+-- crypton has four: "Crypto.KDF.BCrypt", "Crypto.KDF.Scrypt",+-- "Crypto.KDF.Argon2" and "Crypto.KDF.PBKDF2". A plain hash is not one of+-- them, however many times it is applied by hand.+--+-- bcrypt leaves the least to get wrong, because the record it returns+-- carries the salt and the cost inside it:+--+-- > import Crypto.KDF.BCrypt (hashPassword, validatePassword)+-- >+-- > import Data.ByteString (ByteString)+-- >+-- > -- | What goes in the database. The salt is drawn inside and ends up in+-- > -- the result, so two accounts with the same password do not look alike.+-- > register :: ByteString -> IO ByteString+-- > register password = hashPassword 12 password+-- >+-- > -- | And what is checked against it. The cost comes out of the stored+-- > -- record, so raising it for new accounts leaves the old ones working.+-- > login :: ByteString -> ByteString -> Bool+-- > login password stored = validatePassword password stored+--+-- Argon2 is the stronger choice and the one to pick for something new: it+-- asks for memory as well as time, which is what takes the advantage away+-- from the hardware that bcrypt's small working set leaves room for.+-- Nothing is encoded for the caller, though -- the salt and the options are+-- theirs to store, and without all three the hash cannot be recomputed when+-- the user comes back.+--+-- > import Crypto.Error (CryptoFailable)+-- > import qualified Crypto.KDF.Argon2 as Argon2 -- > import qualified Crypto.Random.Types as CRT -- >--- > import Data.ByteArray (ByteArray) -- > import Data.ByteString (ByteString) -- >--- > -- | Not required, but most general implementation--- > data Key c a where--- > Key :: (BlockCipher c, ByteArray a) => a -> Key c a+-- > -- | Argon2id, which is the variant to prefer: it resists both a machine+-- > -- built to guess and a process watching the cache.+-- > options :: Argon2.Options+-- > options = Argon2.defaultOptions{Argon2.variant = Argon2.Argon2id} -- >--- > -- | Generates a string of bytes (key) of a specific length for a given block cipher--- > genSecretKey :: forall m c a. (CRT.MonadRandom m, BlockCipher c, ByteArray a) => c -> Int -> m (Key c a)--- > genSecretKey _ = fmap Key . CRT.getRandomBytes+-- > newSalt :: CRT.MonadRandom m => m ByteString+-- > newSalt = CRT.getRandomBytes 16 -- >--- > -- | Generate a random initialization vector for a given block cipher--- > genRandomIV :: forall m c. (CRT.MonadRandom m, BlockCipher c) => c -> m (Maybe (IV c))--- > genRandomIV _ = do--- > bytes :: ByteString <- CRT.getRandomBytes $ blockSize (undefined :: c)--- > return $ makeIV bytes+-- > derive :: ByteString -> ByteString -> CryptoFailable ByteString+-- > derive salt password = Argon2.hash options password salt 32++-- $key_derivation+--+-- HKDF turns one secret into as many keys as a protocol needs. It is for+-- material that is already unguessable -- what comes out of a+-- Diffie-Hellman, or a key already agreed -- and it is deliberately cheap,+-- which is exactly what makes it the wrong thing for a password. Those go+-- to the section above.+--+-- The info string is what keeps the outputs independent: the same secret+-- with a different info gives an unrelated key, so each use of a secret+-- names itself there.+--+-- > {-# LANGUAGE OverloadedStrings #-} -- >--- > -- | Initialize a block cipher--- > initCipher :: (BlockCipher c, ByteArray a) => Key c a -> Either CryptoError c--- > initCipher (Key k) = case cipherInit k of--- > CryptoFailed e -> Left e--- > CryptoPassed a -> Right a+-- > import Crypto.Hash.Algorithms (SHA256)+-- > import qualified Crypto.KDF.HKDF as HKDF -- >--- > encrypt :: (BlockCipher c, ByteArray a) => Key c a -> IV c -> a -> Either CryptoError a--- > encrypt secretKey initIV msg =--- > case initCipher secretKey of--- > Left e -> Left e--- > Right c -> Right $ ctrCombine c initIV msg+-- > import Data.ByteArray (ScrubbedBytes)+-- > import Data.ByteString (ByteString) -- >--- > decrypt :: (BlockCipher c, ByteArray a) => Key c a -> IV c -> a -> Either CryptoError a--- > decrypt = encrypt+-- > -- | One shared secret in, two unrelated keys out.+-- > directionKeys :: ByteString -> ByteString -> (ScrubbedBytes, ScrubbedBytes)+-- > directionKeys salt shared = (keyFor "client write", keyFor "server write")+-- > where+-- > prk = HKDF.extract salt shared :: HKDF.PRK SHA256+-- > keyFor info = HKDF.expand prk (info :: ByteString) 32++-- $digital_signatures+--+-- Ed25519 is the one to reach for. The keys are thirty-two bytes, there is+-- nothing to choose and nothing to encode, and signing needs no randomness,+-- so it cannot be ruined by a bad source of it. "Crypto.PubKey.Ed448" is+-- the same shape at a larger size, "Crypto.PubKey.ECDSA" and+-- "Crypto.PubKey.RSA.PSS" are there for protocols that ask for them, and+-- "Crypto.PubKey.MLDSA" is the post-quantum one.+--+-- > {-# LANGUAGE OverloadedStrings #-} -- >--- > exampleAES256 :: ByteString -> IO ()--- > exampleAES256 msg = do--- > -- secret key needs 256 bits (32 * 8)--- > secretKey <- genSecretKey (undefined :: AES256) 32--- > mInitIV <- genRandomIV (undefined :: AES256)--- > case mInitIV of--- > Nothing -> error "Failed to generate and initialization vector."--- > Just initIV -> do--- > let encryptedMsg = encrypt secretKey initIV msg--- > decryptedMsg = decrypt secretKey initIV =<< encryptedMsg--- > case (,) <$> encryptedMsg <*> decryptedMsg of--- > Left err -> error $ show err--- > Right (eMsg, dMsg) -> do--- > putStrLn $ "Original Message: " ++ show msg--- > putStrLn $ "Message after encryption: " ++ show eMsg--- > putStrLn $ "Message after decryption: " ++ show dMsg+-- > import Crypto.Error (throwCryptoError)+-- > import qualified Crypto.PubKey.Ed25519 as Ed25519+-- >+-- > import qualified Data.ByteArray as BA+-- > import Data.ByteString (ByteString)+-- >+-- > exampleEd25519 :: ByteString -> IO ()+-- > exampleEd25519 msg = do+-- > sk <- Ed25519.generateSecretKey+-- > let pk = Ed25519.toPublic sk+-- > sig = Ed25519.sign sk pk msg+-- > print (Ed25519.verify pk msg sig)+-- > -- The same signature against a message one byte longer: False.+-- > print (Ed25519.verify pk (msg <> "!") sig)+-- >+-- > -- | A secret key on its way to storage. Printing one does not reveal+-- > -- it -- see the first section -- so this is the way out.+-- > store :: Ed25519.SecretKey -> ByteString+-- > store = BA.convert+-- >+-- > -- | And the way back in, which is checked, because the bytes read from+-- > -- a file may be anything at all.+-- > load :: ByteString -> Ed25519.SecretKey+-- > load = throwCryptoError . Ed25519.secretKey -- $combining_primitives -- -- This example shows how to use Curve25519, XSalsa and Poly1305 primitives to -- emulate NaCl's @crypto_box@ construct. --+-- It is here to show how the pieces fit together, not as something to+-- deploy. An authenticated encryption scheme assembled by hand is the kind+-- of code that is wrong in ways no test notices; for actual use,+-- "Crypto.Cipher.ChaChaPoly1305" does this job with the mistakes already+-- made.+-- -- > import qualified Data.ByteArray as BA -- > import Data.ByteString (ByteString) -- > import qualified Data.ByteString as B@@ -167,6 +376,9 @@ -- > -- > -- | Build a @crypto_box@ packet encrypting the specified content with a -- > -- 192-bit nonce, receiver public key and sender private key.+-- > crypto_box+-- > :: ByteString -> ByteString -> X25519.PublicKey -> X25519.SecretKey+-- > -> ByteString -- > crypto_box content nonce pk sk = BA.convert tag `B.append` c -- > where -- > zero = B.replicate 16 0@@ -181,6 +393,9 @@ -- > -- > -- | Try to open a @crypto_box@ packet and recover the content using the -- > -- 192-bit nonce, sender public key and receiver private key.+-- > crypto_box_open+-- > :: ByteString -> ByteString -> X25519.PublicKey -> X25519.SecretKey+-- > -> Maybe ByteString -- > crypto_box_open packet nonce pk sk -- > | B.length packet < 16 = Nothing -- > | BA.constEq tag' tag = Just content
@@ -1,4 +1,5 @@ Copyright (c) 2006-2015 Vincent Hanquez <vincent@snarc.org>+Copyright (c) 2023-2026 Kazu Yamamoto <kazu@iij.ad.jp> All rights reserved.
@@ -3,24 +3,98 @@ crypton ========== -Crypton is a fork from cryptonite with the original author's permission.+`crypton` is a fork from `cryptonite` with the original author's permission. -Crypton is a haskell repository of cryptographic primitives. Each crypto-algorithm has specificities that are hard to wrap in common APIs and types,-so instead of trying to provide a common ground for algorithms, this package-provides a non-consistent low-level API. -If you have no idea what you're doing, please do not use this directly.-Instead, rely on higher level protocols or implementations.+`crypton` is a low-level cryptography library. To achieve high+performance, it utilizes C and assembly language to define FFI+bindings, structuring them in a way that makes them easy to use. ++Side channels+-------------++### AES++AES is where this matters most, and which implementation runs is decided at+runtime from what the processor has.++On x86-64 with AES-NI and carry-less multiply, on AArch64 and on 32-bit ARM+with the ARMv8 cryptographic extension, and on ppc64le with the vector+instructions PowerISA 2.07 brought to POWER8, AES and GHASH are instructions+rather than software. crypton's AES and AES-GCM then make no branch and no+memory access that depends on the key or on the data: the secrets stay in+vector registers and never reach one a branch can test. Every x86-64 part+since about 2010 and every AArch64 part in ordinary use has these, and the+ppc64le path is little-endian only.++Where none of them is there, crypton computes AES and GHASH without a table.+The portable AES is bitsliced -- the S-box is boolean algebra over four+blocks held across eight 64-bit words -- and the GF(2^128) multiply is built+from shifts, masks and integer multiplies. Neither looks anything up, so+neither derives an address from a secret, and **the portable path is constant+time as well**. The code is BearSSL's, under MIT, in `cbits/bearssl`.++The constant-time harness in `cbits/tests/ct` runs the same driver against+the portable implementation and against each architecture's instructions, and+every one of them is required to report nothing at all.++So the answer does not depend on the machine any more, and what is left to+ask is whether AES is fast on it. `hasAESAcceleration` and+`hasGHASHAcceleration` answer that without naming an architecture.+`processorOptions` says what was found, in the processor's own names --+`AESNI` and `PCLMUL` on x86, `ARMAES` and `ARMPMULL` on AArch64 and 32-bit+ARM, `PPCAES` and `PPCVPMSUM` on ppc64le -- along with everything else it was+asked about, which is unrelated to this.++ ghci> import Crypto.System.CPU+ ghci> hasAESAcceleration+ True+ ghci> processorOptions -- on an x86-64 machine+ [AESNI,PCLMUL,SSSE3,AVX,AVX2,SHANI,MOVBE,ADX,VAES]+ ghci> processorOptions -- and on an AArch64 one+ [NEON,ARMAES,ARMPMULL,ARMSHA1,ARMSHA2,ARMSHA512]++### RSA++RSA is the other place to know about, and there the choice is the caller's.+The private key operations in `Crypto.PubKey.RSA.PKCS15`, `.OAEP` and `.PSS`+take a `Maybe Blinder`, and `Nothing` is no harder to write than the safe+form:++ decrypt :: Maybe Blinder -> PrivateKey -> ByteString -> ...+ decryptSafer :: MonadRandom m => PrivateKey -> ByteString -> m ...++The exponent itself is not what is at risk. `expSafe` keeps the *value* of an+exponent out of the work it does, so the private exponent does not leak+through the exponentiation. What a blinder covers is the other side: without+one, the operation runs on the ciphertext the caller was handed, so how long+it takes depends on a number an attacker may have chosen and can vary. That+is what a remote timing attack on RSA needs. With a blinder the input is+multiplied by a random value first and the result divided out afterwards, so+the timing carries nothing an attacker can steer.++`decryptSafer` and `signSafer` generate the blinder themselves and are the+ones to reach for. Pass `Nothing` only where the input is not attacker+controlled and you have decided that it is not.++The RSA rows in the tables below are the unblinded path. A fresh blinder+costs one more exponentiation, by the public exponent, which is the cheap+direction: measured on the M4, signing goes from about 316 to about 331+microseconds, under five per cent. `signSafer` and `decryptSafer` pay less+than that from 2.2.4: they keep the blinder of a key they have seen and+square it for the next use, as OpenSSL does, drawing a fresh one every 32+uses. `Crypto.PubKey.RSA.Blinded` gives a caller the same thing to hold, a+`BlindedKey` passed along from one operation to the next.+ Performance ----------- -The algorithms a TLS connection uses, measured against the previous release-and against OpenSSL on the same machine. Throughput is over 16 KiB messages;-the public key operations are one operation each; every figure is the best of-several runs, and crypton and OpenSSL are run alternately so that neither gets-the quieter machine.+The algorithms a TLS connection uses, measured against the last release+before the rewrite and against OpenSSL on the same machine. Throughput is+over 16 KiB messages; the public key operations are one operation each; every+figure is the best of several runs, and crypton and OpenSSL are run+alternately so that neither gets the quieter machine. Bulk encryption and hashing are measured through crypton's C layer, as `openssl speed` measures OpenSSL's. The public key operations are measured@@ -28,125 +102,209 @@ is what a program actually calls; the Haskell layer adds well under a microsecond, which the X25519 and ECDH P-256 rows confirm by agreeing with a C-level measurement to within a percent. Both releases of crypton are built-the same way -- `-optc-O3`, which is what both of them ask for -- and each-column of a table comes from one run on the machine named above it.+the same way -- `-optc-O3`, which is what each asks for -- and by+`cabal build`, since a copy of the sources compiled by hand does not measure+what a program linking the library gets, and leaves out whole implementations+without saying so. Each column of a table comes from one run on the machine+named above it. ### x86-64 -An AMD EPYC 7763, which has AES-NI, PCLMULQDQ, AVX2, ADX and the SHA-extensions, against OpenSSL 3.0.13.+An AMD EPYC 7763, which has AES-NI, PCLMULQDQ, AVX2, ADX, VAES, VPCLMULQDQ+and the SHA extensions, against OpenSSL 4.0.3. Throughput in MB/s, **higher is better**: -| | crypton 1.1.5 | crypton 2.0.0 | OpenSSL | 2.0.0 / OpenSSL |+| | crypton 1.1.5 | crypton 2.2.4 | OpenSSL | 2.2.4 / OpenSSL | | --- | ---: | ---: | ---: | ---: |-| AES-128-GCM | 1331 | 4118 | 4264 | 0.97 |-| AES-256-GCM | 1090 | 3810 | 3951 | 0.96 |-| ChaCha20-Poly1305 | 398 | 2195 | 2191 | 1.00 |-| SHA-1 | 738 | 1678 | 1672 | 1.00 |-| SHA-256 | 286 | 1585 | 1570 | 1.01 |-| SHA-512 | 448 | 769 | 746 | 1.03 |-| SHA3-256 | 109 | 421 | 426 | 0.99 |+| AES-128-GCM | 1335 | **6041** | 4066 | 1.49 |+| AES-256-GCM | 1093 | **5492** | 3766 | 1.46 |+| ChaCha20-Poly1305 | 399 | 2195 | 2222 | 0.99 |+| SHA-1 | 727 | 1663 | 1672 | 0.99 |+| SHA-256 | 289 | 1585 | 1576 | 1.01 |+| SHA-512 | 448 | 770 | 749 | 1.03 |+| SHA3-256 | 109 | 421 | 429 | 0.98 | -Time per operation in microseconds, **lower is better** -- so the last column-divides OpenSSL's time by crypton's, and is again better the larger it is:+Time per operation in microseconds, **lower is better**: -| | crypton 1.1.5 | crypton 2.0.0 | OpenSSL | OpenSSL / 2.0.0 |+| | crypton 1.1.5 | crypton 2.2.4 | OpenSSL | OpenSSL / 2.2.4 | | --- | ---: | ---: | ---: | ---: |-| X25519 | 43.57 | 43.52 | 36.58 | 0.84 |-| ECDH P-256 | 163.8 | 163.7 | 52.36 | 0.32 |-| ECDH P-384 | 2241 | 1101 | 857.1 | 0.78 |-| Ed25519 sign | 28.52 | 28.25 | 43.49 | 1.54 |-| Ed25519 verify | 46.06 | 46.16 | 119.3 | 2.59 |-| ECDSA P-256 sign | 76.04 | 75.02 | 22.91 | 0.31 |-| ECDSA P-256 verify | 229.2 | 228.5 | 67.98 | 0.30 |-| ECDSA P-384 sign | 2271 | 387.6 | 904.3 | 2.33 |-| ECDSA P-384 verify | 2667 | 1493 | 746.2 | 0.50 |-| RSA-2048 sign/decrypt | 759.8 | 1311 | 660.1 | 0.50 |-| RSA-2048 verify/encrypt | 31.62 | 28.59 | 18.63 | 0.65 |+| X25519 | 44.38 | 28.29 | 36.61 | 1.29 |+| ECDH P-256 | 164.0 | 51.31 | 51.70 | 1.01 |+| ECDH P-384 | 2242 | **164.3** | 836.1 | 5.09 |+| Ed25519 sign | 43.86 | 18.50 | 33.74 | 1.82 |+| Ed25519 verify | 48.30 | 48.43 | 109.8 | 2.27 |+| ECDSA P-256 sign | 81.80 | 19.72 | 21.84 | 1.11 |+| ECDSA P-256 verify | 231.8 | 70.47 | 67.55 | 0.96 |+| ECDSA P-384 sign | 2267 | **305.2** | 879.5 | 2.88 |+| ECDSA P-384 verify | 2698 | **473.6** | 725.2 | 1.53 |+| RSA-2048 sign/decrypt | 760.1 | 612.3 | 659.6 | 1.08 |+| RSA-2048 verify/encrypt | 33.61 | 23.50 | 18.88 | 0.80 |+| RSA-3072 sign/decrypt | 2499 | 2324 | 2012 | 0.87 |+| RSA-3072 verify/encrypt | 66.80 | 61.91 | 40.14 | 0.65 | ### AArch64 An Apple M4, which has the AES, PMULL, SHA-1, SHA-2, SHA-512 and SHA-3-instructions, against OpenSSL 3.6.4.+instructions, against OpenSSL 4.0.3. Throughput in MB/s, **higher is better**: -| | crypton 1.1.5 | crypton 2.0.0 | OpenSSL | 2.0.0 / OpenSSL |+| | crypton 1.1.5 | crypton 2.2.4 | OpenSSL | 2.2.4 / OpenSSL | | --- | ---: | ---: | ---: | ---: |-| AES-128-GCM | 126 | 8702 | 10719 | 0.81 |-| AES-256-GCM | 98 | 7648 | 9154 | 0.84 |-| ChaCha20-Poly1305 | 758 | 2323 | 2244 | 1.04 |-| SHA-1 | 1199 | 3380 | 3346 | 1.01 |-| SHA-256 | 467 | 3394 | 3352 | 1.01 |-| SHA-512 | 723 | 1868 | 1851 | 1.01 |-| SHA3-256 | 548 | 1091 | 1054 | 1.04 |+| AES-128-GCM | 131 | **12052** | 10922 | 1.10 |+| AES-256-GCM | 99 | **10192** | 9208 | 1.11 |+| ChaCha20-Poly1305 | 783 | 2342 | 2261 | 1.04 |+| SHA-1 | 1234 | 3383 | 3347 | 1.01 |+| SHA-256 | 486 | 3392 | 3354 | 1.01 |+| SHA-512 | 742 | 1869 | 1860 | 1.00 |+| SHA3-256 | 552 | 1096 | 1092 | 1.00 | -Time per operation in microseconds, **lower is better**; the last column again-divides OpenSSL's time by crypton's:+Time per operation in microseconds, **lower is better**: -| | crypton 1.1.5 | crypton 2.0.0 | OpenSSL | OpenSSL / 2.0.0 |+| | crypton 1.1.5 | crypton 2.2.4 | OpenSSL | OpenSSL / 2.2.4 | | --- | ---: | ---: | ---: | ---: |-| X25519 | 18.44 | 18.41 | 18.41 | 1.00 |-| ECDH P-256 | 69.46 | 56.24 | 24.68 | 0.44 |-| ECDH P-384 | 3252 | 511.1 | 379.7 | 0.74 |-| Ed25519 sign | 13.75 | 13.14 | 15.90 | 1.21 |-| Ed25519 verify | 18.17 | 18.04 | 39.27 | 2.18 |-| ECDSA P-256 sign | 32.56 | 27.91 | 11.05 | 0.40 |-| ECDSA P-256 verify | 96.50 | 80.19 | 32.82 | 0.41 |-| ECDSA P-384 sign | 3219 | 169.3 | 403.4 | 2.38 |-| ECDSA P-384 verify | 3807 | 688.1 | 335.1 | 0.49 |-| RSA-2048 sign/decrypt | 451.8 | 605.4 | 325.0 | 0.54 |-| RSA-2048 verify/encrypt | 18.32 | 15.28 | 8.50 | 0.56 |+| X25519 | 17.92 | **12.02** | 15.32 | 1.28 |+| ECDH P-256 | 67.50 | **19.05** | 24.36 | 1.28 |+| ECDH P-384 | 3256 | **71.78** | 373.1 | 5.20 |+| Ed25519 sign | 13.38 | **7.717** | 13.31 | 1.72 |+| Ed25519 verify | 18.32 | 18.18 | 34.77 | 1.91 |+| ECDSA P-256 sign | 31.08 | **6.500** | 10.66 | 1.64 |+| ECDSA P-256 verify | 94.27 | **26.58** | 32.25 | 1.21 |+| ECDSA P-384 sign | 3225 | **124.0** | 394.2 | 3.18 |+| ECDSA P-384 verify | 3866 | **203.4** | 332.3 | 1.63 |+| RSA-2048 sign/decrypt | 451.3 | 318.4 | 321.5 | 1.01 |+| RSA-2048 verify/encrypt | 18.15 | 11.12 | 8.405 | 0.76 |+| RSA-3072 sign/decrypt | 1473 | 937.4 | 931.1 | 0.99 |+| RSA-3072 verify/encrypt | 47.95 | 43.63 | 17.89 | 0.41 | ### What the numbers say -1.1.5 had no AArch64 code of its own at all, which is why AES-GCM there is-sixty-nine times what it was. On x86-64 it had AES-NI and nothing else. The-curves over a prime field other than P-256 moved from Haskell `Integer`-arithmetic into C, which is the nineteenfold change in ECDSA P-384 signing on-the M4. X25519 and Ed25519 are unchanged between the two releases, and the-rows say so: where they differ by half a percent, that is the measurement and-not the code. P-256 is unchanged on x86-64 and a fifth faster on AArch64,-which is the paragraph below.+There are two changes behind the 1.1.5 column and the 2.2.4 one, not a+single steady improvement. -Where crypton is behind, it is behind for three separate reasons.+The first, in 2.0.0, was a rewrite: the bulk algorithms moved into C, the+curves other than P-256 moved out of Haskell `Integer` arithmetic, and+everything that touches a secret was made to take the same time whatever the+secret is. 1.1.5 had no AArch64 code of its own at all, which is why AES-GCM+there is close to a hundred times what it was, and on x86-64 it had AES-NI+and nothing else. -*P-256.* crypton's field arithmetic is C where OpenSSL's is hand-written-assembly, and that is what is left of the difference: the two differ by about-the same factor on every P-256 row, and nothing above the field -- a wider-window, a different addition formula, another field representation -- recovers-a useful part of it.+The second, from 2.1.0 onwards, is assembly, for the operations where C+cannot reach. Which of the two a row owes its gain to is not the same+everywhere: ECDSA P-384 signing took nineteenfold from the rewrite and a+further fifth from the assembly, while X25519 waited for the assembly+entirely and ECDH P-384 is almost all of it. -The AArch64 rows are better than the x86-64 ones because of where a field-multiplication's latency goes. It ends in a carry chain the width of the-number, and the curve arithmetic has independent products that could cover-that chain -- but only if the compiler inlines the reduction instead of-calling it, since a call is a fence. Asking it to costs code and pays where-there are registers enough to hold two chains at once: a quarter on AArch64,-where there are thirty-one, and nothing on x86-64, where there are fifteen and-the same request makes it slower. So x86-64 is left to the compiler's own-judgement and stays at 0.3.+Most of that assembly is not crypton's. The prime curves, the inverse modulo+a group order, X25519, and RSA's Montgomery multiplication on x86-64 go+through [s2n-bignum](https://github.com/awslabs/s2n-bignum), vendored in+`cbits/s2n`. Every routine in it carries a machine-checked proof in+HOL-Light that it computes what it says, and is written in a constant-time+style. It is `Apache-2.0 OR ISC OR MIT-0`, and crypton takes it under ISC. -*RSA signing.* 2.0.0 is slower than 1.1.5 here on purpose. Its modular-exponentiation no longer indexes a table with the bits of the exponent, and-hiding the exponent is what the difference buys. What is left of the gap-against OpenSSL is the Montgomery multiplication, which is assembly there and-C here.+That licence is why any of this was possible. The obvious assembly to reach+for is OpenSSL's and BoringSSL's `ecp_nistz256`, and it cannot be used here:+it is Apache-2.0 only, and Intel and CloudFlare hold copyright in it besides+OpenSSL, so nobody is in a position to relicense it. -*The AVX-512 instructions.* Neither machine above has them. On one that does--- an EPYC 9V74, measured the same way -- OpenSSL uses them for AES-GCM and-ChaCha20 and reaches 12003 and 3789 MB/s, against 4745 and 2372 for crypton,-whose vendored assembly is generated without them. Those ratios are 0.40 and-0.63 rather than 0.97 and 1.00. Nothing else in either table moves by more-than a few percent between the two processors.+crypton is behind in a few rows now: RSA verification on both architectures,+and RSA-3072 signing and ECDSA P-256 verification on x86-64. The AES-GCM rows+were the other half of this section until 2.1.5; they are ahead on both+machines now, and what the instructions do is still worth setting out. +*RSA.* 2.0.0 made signing slower than 1.1.5 on purpose: its modular+exponentiation stopped indexing a table with the bits of the exponent, and+hiding the exponent is what the difference bought. 2.2.4 has repaid that+cost on both machines, by different means. On x86-64 s2n-bignum's+Montgomery multiplication is twice the C's, because the C cannot form the two+carry chains `ADCX` and `ADOX` give, and 2.2.4 signs in less than 1.1.5+took, at 3072 bits as well as 2048. On AArch64 s2n-bignum's routines measure+no better than the C, so the gain there is the C's own: the multiplication+and squaring for each key size are generated and unrolled, with the+reduction folded into each column as in Koç, Acar and Kaliski's FIPS method,+and signing is level with OpenSSL. The measurements are in+[#275](https://github.com/kazu-yamamoto/crypton/issues/275).++On processors with AVX-512 IFMA, Intel Xeons from Ice Lake and AMD from Zen 4,+2.2.4 computes the two halves of the CRT together in 52-bit digits, Gueron and+Krasnov's method and the one OpenSSL takes there. Neither machine above has+IFMA, so neither table shows it.++Verification's exponent is 65537, seventeen bits, so there is little+exponentiation to speed up and the work around it counts. 2.2.4 keeps R^2,+the Montgomery constant of a modulus, for the moduli it has seen, which is+most of what the RSA-2048 verification rows gained.++*The wide AES instructions.* `VAES` and `VPCLMULQDQ` do two blocks where+`AES-NI` and `PCLMULQDQ` do one, and four in their 512-bit form. crypton uses+the 256-bit form where the processor has it, which is Zen 3 and Ice Lake+onwards, and the 512-bit form where that is worth having, which is Ice Lake and+Zen 5 onwards. There was nothing to borrow: the wide AES-GCM in OpenSSL,+BoringSSL and AWS-LC is Apache-2.0 and s2n-bignum has no GCM, so both files are+crypton's own.++Having the 256-bit one is where the 1.49 in the x86-64 table comes from, and+it is narrower than it sounds. The EPYC 7763 is Zen 3: VAES and VPCLMULQDQ,+no AVX-512. OpenSSL's x86-64 AES-GCM is `aesni-gcm-x86_64.pl`, which is+128-bit -- its `vaesenc`s are the VEX encoding of `AESENC` on `xmm`, and+there is not one `ymm` in the file -- or `aes-gcm-avx512.pl`, which wants+`AVX512VAES`. There is no rung between them, so on this processor OpenSSL+takes a block at a time where crypton takes two. The same idea as theirs,+one step further down the feature ladder; not a better one.++The 512-bit path arrived after 2.1.2, so it is in the 2.2.4 column -- but+neither machine in the tables above has AVX-512, so neither column shows it.+On the runners that do, measured over 16 KiB in MB/s: an EPYC 9V45 (Zen 5)+goes from 9616 to 14268 with it, a Xeon 6973P-C from 8095 to 9848, a Xeon+8573C from 6983 to 8447. OpenSSL on those machines is ahead still -- 25760+on the first of them -- because it interleaves the GHASH with the AES where+crypton does them in turn. Zen 4 keeps the 256-bit path: its 512-bit+instructions are two passes through a 256-bit datapath, so the wider encoding+buys nothing there and costs a little.++AArch64 has no counterpart to any of these: one AES block and one GHASH+multiplication at a time is all the instruction set offers. Its AES-GCM+rows were 0.85 and 0.87 until 2.1.5, for that reason. What closed it was+not width but the GHASH's representation -- H is twisted once at key setup+so that GCM's bit reflection is already undone, which turns a reduction of+some twenty-five shifts and XORs into two PMULL and six EOR and makes+Karatsuba worth taking. The scheme is ARM's, from the BSD-3-Clause part of+[AArch64cryptolib](https://github.com/ARM-software/AArch64cryptolib),+written out in crypton's own intrinsics. The AES there is ahead of+OpenSSL's and always was; it was the GHASH beside it that was behind.+ One row wants a word of its own: crypton's `Ed25519.sign` derives the public key from the secret key every time it signs, so that a caller who passes a public key that does not match cannot be made to leak the private one. That-costs a second scalar multiplication, which OpenSSL's signing does not pay.+costs a second scalar multiplication, which OpenSSL's signing does not pay --+and the row is still 1.72 on AArch64 and 1.82 on x86-64, so the safety is had+for nothing here rather than paid for. +Ed25519 verification wanted one too, for an unhappier reason, and 2.2.1+settles it. On x86-64 the row was about eight per cent slower from 2.1.8+onwards: 2.1.5, 2.1.6 and 2.1.7 all measure near 48 microseconds there,+2.1.8, 2.1.10 and 2.2.0 all measure near 52, and 2.2.1 is near 48 again.+Nothing in Ed25519 ever changed -- no commit touches `cbits/ed25519` across+any of it, and AArch64 never moved, the compiled `ed25519.o` there being+byte for byte the same object either side of 2.1.8. What moved was a line+in this package's cabal file. The ML-KEM and ML-DSA backends that 2.1.8+vendored want `-mavx2 -mbmi2`, and they were given as `cc-options` inside an+`if arch(x86_64)` block -- but cc-options in a conditional belong to the+component and not to the block, so every C file in the library was compiled+with AVX2 allowed, `cbits/ed25519` among them, and what the compiler made of+it that way is slower on this machine than what it replaced. Signing, which+is the same file and a different routine, is where it always was. 2.2.1+narrowed the flags to the assembly that asked for them, which is also what+stopped a binary built on one x86-64 machine from dying on another, and the+row came back.+ SHA-1 is in the tables because a number of protocols and file formats still ask for it, not because it is a good choice for anything new. The algorithms that nothing should ask for any more -- MD5, 3DES, RC4, CBC mode -- are left out.++ML-KEM and ML-DSA are left out too, though 2.1.8 brought both and they are+fast -- `mlkem-native` and `mldsa-native`, from the PQ Code Package. No+comparison is reported here: the implementations to measure against are+still developing.
@@ -195,7 +195,9 @@ where cp k (ini, plain) = let iniState =- throwCryptoError $ CP.initialize k (throwCryptoError $ CP.nonce12 nonce12)+ CP.initialize+ (throwCryptoError $ CP.key k)+ (throwCryptoError $ CP.nonce12 nonce12) afterAAD = CP.finalizeAAD (CP.appendAAD ini iniState) (out, afterEncrypt) = CP.encrypt plain afterAAD outtag = CP.finalize afterEncrypt
@@ -0,0 +1,38 @@+The arrangement of the AArch64 multiply-accumulate loop in+cbits/crypton_bignum.h -- four limbs to an iteration, the low halves of the+products and the high halves accumulated in two chains -- follows+addMulVVWx in Go's crypto/internal/fips140/bigmod/nat_arm64.s, written out+in the assembler that file's compiler speaks. Go is at+https://github.com/golang/go and carries the licence below. That file's+own header reads "Copyright 2013 The Go Authors. All rights reserved. Use+of this source code is governed by a BSD-style license that can be found in+the LICENSE file", and the LICENSE file it means is this one.+++Copyright 2009 The Go Authors.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++ * Redistributions of source code must retain the above copyright+notice, this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above+copyright notice, this list of conditions and the following disclaimer+in the documentation and/or other materials provided with the+distribution.+ * Neither the name of Google LLC nor the names of its+contributors may be used to endorse or promote products derived from+this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,29 @@+Parts of cbits/aes/gcm_fused_x86.c follow the AES-GCM implementation in+picotls, lib/fusion.c, which is under the MIT license reproduced below.+The design is described by its author at++ http://blog.kazuhooku.com/2020/06/quicaes-gcm-12.html+ http://blog.kazuhooku.com/2020/06/quicaes-gcm-22.html++and the source is at https://github.com/h2o/picotls.+++Copyright (c) 2020-2022 Fastly, Kazuho Oku++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to+deal in the Software without restriction, including without limitation the+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or+sell copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS+IN THE SOFTWARE.
@@ -20,12 +20,9 @@ #include <stdint.h> #include <string.h> #include <arm_neon.h>-#if defined(__linux__)-#include <sys/auxv.h>-#include <asm/hwcap.h>-#endif #include "crypton_aes.h" #include "crypton_bitfn.h"+#include "crypton_cpu.h" /* * The AES and PMULL instructions are extensions, so a translation unit@@ -39,11 +36,7 @@ * * "+crypto" rather than "crypto": GCC rejects the latter. */-#ifdef WITH_TARGET_ATTRIBUTES-#define TARGET_ARMV8_CRYPTO __attribute__((target("+crypto")))-#else-#define TARGET_ARMV8_CRYPTO-#endif+#include "crypton_armv8_target.h" /* forward round keys: nbr + 1 of them, written by the generic key expansion */ #define FWD(key) ((const uint8_t *) (key)->data)@@ -70,14 +63,14 @@ * instructions exist to remove -- but a key schedule is the one thing an * attacker most wants and it costs little to keep it out of the cache. */-TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO static uint32x4_t sub_word(uint32x4_t w) { return vreinterpretq_u32_u8( vaeseq_u8(vreinterpretq_u8_u32(w), vdupq_n_u8(0))); } -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO static uint32x4_t sub_rot_word(uint32x4_t w) { const uint8x16_t s = vreinterpretq_u8_u32(sub_word(w));@@ -85,7 +78,7 @@ return vreinterpretq_u32_u8(vextq_u8(s, s, 1)); } -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void crypton_aes_armv8_init(aes_key *key, uint8_t *origkey, uint8_t size) { /* 2^0 .. 2^9 in GF(2^8), which is as far as any key size reaches */@@ -127,191 +120,194 @@ } /*- * Whether the extensions are actually present.- *- * They are mandatory on Apple silicon, and on other AArch64 systems the- * kernel reports them through the auxiliary vector. A system without them- * keeps the generic implementation.+ * Whether the extensions are actually present. crypton_cpu.c asks the+ * system once, in the one place that knows how each system answers; a+ * processor without them keeps the generic implementation. */ int crypton_aes_armv8_available(void) {-#if defined(__APPLE__)- return 1;-#elif defined(__linux__)- return (getauxval(AT_HWCAP) & HWCAP_AES) != 0;-#else- return 0;-#endif+ return (crypton_arm_features() & CRYPTON_ARM_AES) != 0; } /* * GHASH using PMULL, the AArch64 counterpart to PCLMULQDQ. *- * This is a transliteration of gfmul_pclmuldq in x86ni.c rather than a fresh- * formulation: that code is already pinned by the GCM known-answer tests, and- * every operation it uses has a direct NEON equivalent, so translating it is- * easier to check than reasoning about a new reduction from scratch.+ * Not the transliteration of gfmul_pclmuldq in x86ni.c this used to be. The+ * x86 formulation keeps H in the order GCM writes it and pays, at the end of+ * every batch, a reduction that first has to undo GCM's bit reflection: some+ * twenty-five shifts and XORs, and a batch of eight costs it once. *- * _mm_shuffle_epi8 with a reversing mask -> vrev64q_u8 then vextq_u8- * _mm_clmulepi64_si128 -> vmull_p64 / vmull_high_p64- * _mm_slli_si128 / _mm_srli_si128 -> vextq_u8 against zero- * _mm_slli_epi32 / _mm_srli_epi32 -> vshlq_n_u32 / vshrq_n_u32+ * Instead H is twisted once, at key setup, so that the reflection is already+ * undone and a reversed-polynomial multiply lands in the right place. Two+ * things follow. The reduction becomes two PMULL against 0xC2000..0 and six+ * EOR, a third of what it was. And because nothing has to be byte-reversed+ * back and forth, Karatsuba pays: three PMULL a block rather than four, with+ * the middle terms accumulated in a third register and tidied up once per+ * batch.+ *+ * crypton tried Karatsuba in the old representation and measured it 1.6 per+ * cent slower -- the saved PMULL did not cover the extra EOR when the+ * reduction stayed as expensive as it was. It is the pair that pays.+ * Measured over 16 KiB messages, this against the old code:+ *+ * Apple M4 Neoverse N2+ * AES-128-GCM 1.30 1.25+ * AES-192-GCM 1.22 1.25+ * AES-256-GCM 1.19 1.24+ *+ * The scheme is ARM's, from the 'big' AES-GCM kernel of+ * https://github.com/ARM-software/AArch64cryptolib, which is BSD-3-Clause,+ * (c) 2018-2019 ARM Limited. Their kernels under AArch64cryptolib_opt_bigger+ * are faster again and are NOT under that licence, whatever the repository's+ * LICENSE.md says; nothing here comes from those files.+ *+ * The table holds the twisted powers H^1 .. H^8 at htable[0 .. 7] and the+ * Karatsuba half of each -- its high 64 bits XOR its low -- in the first+ * eight bytes of htable[8 .. 15]. The running tag is kept the way GCM+ * writes it at every boundary, and swapped into the internal form on the way+ * in and out, which is two instructions. */ -/* reverse all 16 bytes */-TARGET_ARMV8_CRYPTO-static inline uint8x16_t bswap128(uint8x16_t v)-{- return vextq_u8(vrev64q_u8(v), vrev64q_u8(v), 8);-}--/* shift the whole register left by n bytes, as _mm_slli_si128 does */-#define SHIFT_LEFT_BYTES(v, n) vextq_u8(vdupq_n_u8(0), (v), 16 - (n))-/* and right, as _mm_srli_si128 does */-#define SHIFT_RIGHT_BYTES(v, n) vextq_u8((v), vdupq_n_u8(0), (n))--#define SHL32(v, n) vreinterpretq_u8_u32(vshlq_n_u32(vreinterpretq_u32_u8(v), (n)))-#define SHR32(v, n) vreinterpretq_u8_u32(vshrq_n_u32(vreinterpretq_u32_u8(v), (n)))--TARGET_ARMV8_CRYPTO-static inline uint8x16_t clmul_ll(uint8x16_t a, uint8x16_t b)-{- return vreinterpretq_u8_p128(vmull_p64(- (poly64_t) vgetq_lane_u64(vreinterpretq_u64_u8(a), 0),- (poly64_t) vgetq_lane_u64(vreinterpretq_u64_u8(b), 0)));-}+#define GHASH_MODC ((poly64_t) 0xC200000000000000ul) -TARGET_ARMV8_CRYPTO-static inline uint8x16_t clmul_lh(uint8x16_t a, uint8x16_t b)+/* the internal accumulator form, and back again: its own inverse */+CRYPTON_TARGET_ARMV8_CRYPTO+static inline uint8x16_t ghash_swap(uint8x16_t t) {- return vreinterpretq_u8_p128(vmull_p64(- (poly64_t) vgetq_lane_u64(vreinterpretq_u64_u8(a), 0),- (poly64_t) vgetq_lane_u64(vreinterpretq_u64_u8(b), 1)));+ t = vrev64q_u8(t);+ return vextq_u8(t, t, 8); } -TARGET_ARMV8_CRYPTO-static inline uint8x16_t clmul_hl(uint8x16_t a, uint8x16_t b)+/* the high and low halves XORed together, which is what Karatsuba wants */+CRYPTON_TARGET_ARMV8_CRYPTO+static inline poly64_t ghash_karat(poly64x2_t v) {- return vreinterpretq_u8_p128(vmull_p64(- (poly64_t) vgetq_lane_u64(vreinterpretq_u64_u8(a), 1),- (poly64_t) vgetq_lane_u64(vreinterpretq_u64_u8(b), 0)));+ return (poly64_t) veor_u64(vget_high_u64(vreinterpretq_u64_p64(v)),+ vget_low_u64(vreinterpretq_u64_p64(v))); } -TARGET_ARMV8_CRYPTO-static inline uint8x16_t clmul_hh(uint8x16_t a, uint8x16_t b)-{- return vreinterpretq_u8_p128(vmull_high_p64(- vreinterpretq_p64_u8(a), vreinterpretq_p64_u8(b)));-}+/* the twisted power H^(i+1) */+#define GHASH_POW(ht, i) \+ vreinterpretq_p64_u8(vld1q_u8((const uint8_t *) &(ht)[i]))+/* and its Karatsuba half */+#define GHASH_KARAT(ht, i) \+ ((poly64_t) vgetq_lane_u64( \+ vreinterpretq_u64_u8(vld1q_u8((const uint8_t *) &(ht)[8 + (i)])), 0)) /*- * The 256-bit carry-less product of a (normal byte order) and b (already- * reversed, as it sits in the table), before the reflection fixup and the- * reduction. Split out from the reduction because both of those are linear- * over XOR: several products can be added together and fixed up just once,- * which is what gf_mul4 below does.+ * One block's three partial products, XORed into the accumulators. b is+ * already in the internal form; hp and hk are the power it is to meet. */-TARGET_ARMV8_CRYPTO-static inline void clmul_pmull(uint8x16_t a, uint8x16_t b,- uint8x16_t *lo, uint8x16_t *hi)-{- uint8x16_t t3, t4, t5, t6;-- a = bswap128(a);-- t3 = clmul_ll(a, b);- t4 = clmul_lh(a, b);- t5 = clmul_hl(a, b);- t6 = clmul_hh(a, b);-- t4 = veorq_u8(t4, t5);- t5 = SHIFT_LEFT_BYTES(t4, 8);- t4 = SHIFT_RIGHT_BYTES(t4, 8);-- *lo = veorq_u8(t3, t5);- *hi = veorq_u8(t6, t4);-}+#define GHASH_MUL(b, hp, hk, H, M, L) \+ do { \+ poly64x2_t b__ = (b); \+ poly64x2_t hp__ = (hp); \+ (H) = veorq_u64((H), vreinterpretq_u64_p128( \+ vmull_high_p64(b__, hp__))); \+ (L) = veorq_u64((L), vreinterpretq_u64_p128(vmull_p64( \+ (poly64_t) vgetq_lane_u64(vreinterpretq_u64_p64(b__), 0), \+ (poly64_t) vgetq_lane_u64(vreinterpretq_u64_p64(hp__), 0)))); \+ (M) = veorq_u64((M), vreinterpretq_u64_p128( \+ vmull_p64(ghash_karat(b__), (hk)))); \+ } while (0) -/* Shift the 256-bit product left by one to undo GCM's bit reflection, then- * reduce modulo the GCM polynomial. This is the expensive half. */-TARGET_ARMV8_CRYPTO-static inline uint8x16_t gfred_pmull(uint8x16_t t3, uint8x16_t t6)+/*+ * Finish the Karatsuba -- the middle accumulator still holds only the+ * (ah^al)(bh^bl) terms and wants the other two taken out of it -- and reduce+ * the 256 bits modulo the GCM polynomial. The result is in internal form.+ */+CRYPTON_TARGET_ARMV8_CRYPTO+static inline uint64x2_t ghash_reduce(uint64x2_t H, uint64x2_t M, uint64x2_t L) {- uint8x16_t t2, t4, t5, t7, t8, t9;-- t7 = SHR32(t3, 31);- t8 = SHR32(t6, 31);- t3 = SHL32(t3, 1);- t6 = SHL32(t6, 1);-- t9 = SHIFT_RIGHT_BYTES(t7, 12);- t8 = SHIFT_LEFT_BYTES(t8, 4);- t7 = SHIFT_LEFT_BYTES(t7, 4);- t3 = vorrq_u8(t3, t7);- t6 = vorrq_u8(t6, t8);- t6 = vorrq_u8(t6, t9);-- t7 = SHL32(t3, 31);- t8 = SHL32(t3, 30);- t9 = SHL32(t3, 25);+ uint64x2_t t; - t7 = veorq_u8(t7, t8);- t7 = veorq_u8(t7, t9);- t8 = SHIFT_RIGHT_BYTES(t7, 4);- t7 = SHIFT_LEFT_BYTES(t7, 12);- t3 = veorq_u8(t3, t7);+ M = veorq_u64(M, H);+ M = veorq_u64(M, L); - t2 = SHR32(t3, 1);- t4 = SHR32(t3, 2);- t5 = SHR32(t3, 7);- t2 = veorq_u8(t2, t4);- t2 = veorq_u8(t2, t5);- t2 = veorq_u8(t2, t8);- t3 = veorq_u8(t3, t2);- t6 = veorq_u8(t6, t3);+ t = vreinterpretq_u64_p128(vmull_p64(+ (poly64_t) vgetq_lane_u64(H, 0), GHASH_MODC));+ H = vreinterpretq_u64_u8(vextq_u8(vreinterpretq_u8_u64(H),+ vreinterpretq_u8_u64(H), 8));+ M = veorq_u64(M, t);+ M = veorq_u64(M, H); - return bswap128(t6);+ t = vreinterpretq_u64_p128(vmull_p64(+ (poly64_t) vgetq_lane_u64(M, 0), GHASH_MODC));+ M = vreinterpretq_u64_u8(vextq_u8(vreinterpretq_u8_u64(M),+ vreinterpretq_u8_u64(M), 8));+ L = veorq_u64(L, t);+ return veorq_u64(L, M); } -TARGET_ARMV8_CRYPTO-static uint8x16_t gfmul_pmull(uint8x16_t a, const uint8_t *htable)+/* a single block against H^1, accumulator in internal form */+CRYPTON_TARGET_ARMV8_CRYPTO+static inline uint64x2_t ghash_one(uint64x2_t acc, uint8x16_t blk,+ const block128 *ht) {- uint8x16_t lo, hi;+ uint64x2_t H = vdupq_n_u64(0), M = H, L = H;+ poly64x2_t b; - clmul_pmull(a, vld1q_u8(htable), &lo, &hi);- return gfred_pmull(lo, hi);+ acc = vreinterpretq_u64_u8(vextq_u8(vreinterpretq_u8_u64(acc),+ vreinterpretq_u8_u64(acc), 8));+ b = vreinterpretq_p64_u64(veorq_u64(+ vreinterpretq_u64_u8(vrev64q_u8(blk)), acc));+ GHASH_MUL(b, GHASH_POW(ht, 0), GHASH_KARAT(ht, 0), H, M, L);+ return ghash_reduce(H, M, L); } /*- * With PMULL there is no 4-bit table to fill: H goes in at index 0, byte- * reversed, so that gfmul_pmull does not have to swap it every time. This- * mirrors crypton_aesni_hinit_pclmul.+ * Twist H and raise it to the powers a batch needs. *- * Indices 1..7 get H^2 .. H^8, which is what lets a group of blocks fold- * into one reduction: gf_mul4 uses the first four, the GCM loop all eight.- * The table has sixteen slots, so they are free.+ * The twist is a shift left by one with 0xC2000..01 folded back in when a+ * bit falls off the top -- the same correction the old reduction applied to+ * every product, done once here instead. Each further power is one multiply+ * in the twisted domain; the result comes out of ghash_reduce with its+ * halves swapped, which a batch undoes on the way in, so a stored power has+ * to be swapped back. */-TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void crypton_aes_armv8_hinit_pmull(block128 *htable, const block128 *h) {- uint8x16_t p;+ uint8x16_t hk = vrev64q_u8(vld1q_u8((const uint8_t *) h));+ uint64x2_t shl = vshlq_n_u64(vreinterpretq_u64_u8(hk), 1);+ uint64x2_t shr = vreinterpretq_u64_s64(+ vshrq_n_s64(vreinterpretq_s64_u8(hk), 63));+ uint8x16_t mask = vextq_u8(vreinterpretq_u8_u64(shr),+ vreinterpretq_u8_u64(shr), 12);+ uint64x2_t tc = vdupq_n_u64(0);+ poly64x2_t base, p; int i; - htable[0].q[0] = bitfn_swap64(h->q[1]);- htable[0].q[1] = bitfn_swap64(h->q[0]);+ tc = vsetq_lane_u64(0xC200000000000001ul, tc, 0);+ tc = vsetq_lane_u64(1, tc, 1);+ tc = vandq_u64(vreinterpretq_u64_u8(mask), tc);+ base = vreinterpretq_p64_u64(veorq_u64(tc, shl)); - p = vld1q_u8((const uint8_t *) h);- for (i = 1; i < 8; i++) {- p = gfmul_pmull(p, (const uint8_t *) &htable[0]);- vst1q_u8((uint8_t *) &htable[i], bswap128(p));+ p = base;+ for (i = 0; i < 8; i++) {+ uint64x2_t H = vdupq_n_u64(0), M = H, L = H, r;++ vst1q_u8((uint8_t *) &htable[i],+ vreinterpretq_u8_p64(p));+ vst1q_u8((uint8_t *) &htable[8 + i],+ vreinterpretq_u8_u64(+ vdupq_n_u64((uint64_t) ghash_karat(p))));++ GHASH_MUL(p, base, ghash_karat(base), H, M, L);+ r = ghash_reduce(H, M, L);+ p = vreinterpretq_p64_u8(vextq_u8(vreinterpretq_u8_u64(r),+ vreinterpretq_u8_u64(r), 8)); } } -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void crypton_aes_armv8_gf_mul_pmull(block128 *a, const block128 *htable) {- vst1q_u8((uint8_t *) a,- gfmul_pmull(vld1q_u8((const uint8_t *) a), (const uint8_t *) htable));+ uint64x2_t acc = vreinterpretq_u64_u8(+ ghash_swap(vld1q_u8((const uint8_t *) a)));++ acc = ghash_one(acc, vdupq_n_u8(0), htable);+ vst1q_u8((uint8_t *) a, ghash_swap(vreinterpretq_u8_u64(acc))); } /*@@ -320,36 +316,38 @@ * four products can be summed first and reduced once, which is where the * time goes. Aggregated reduction, from the Intel GCM paper. */-TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void crypton_aes_armv8_gf_mul4_pmull(block128 *a, const block128 *blocks, const block128 *htable) {- uint8x16_t lo, hi, l, h;+ uint64x2_t acc = vreinterpretq_u64_u8(+ ghash_swap(vld1q_u8((const uint8_t *) a)));+ uint64x2_t H = vdupq_n_u64(0), M = H, L = H;+ poly64x2_t b; int i; - clmul_pmull(veorq_u8(vld1q_u8((const uint8_t *) a),- vld1q_u8((const uint8_t *) &blocks[0])),- vld1q_u8((const uint8_t *) &htable[3]), &lo, &hi);+ acc = vreinterpretq_u64_u8(vextq_u8(vreinterpretq_u8_u64(acc),+ vreinterpretq_u8_u64(acc), 8));+ b = vreinterpretq_p64_u64(veorq_u64(+ vreinterpretq_u64_u8(vrev64q_u8(+ vld1q_u8((const uint8_t *) &blocks[0]))), acc));+ GHASH_MUL(b, GHASH_POW(htable, 3), GHASH_KARAT(htable, 3), H, M, L); for (i = 1; i < 4; i++) {- clmul_pmull(vld1q_u8((const uint8_t *) &blocks[i]),- vld1q_u8((const uint8_t *) &htable[3 - i]), &l, &h);- lo = veorq_u8(lo, l);- hi = veorq_u8(hi, h);+ b = vreinterpretq_p64_u8(vrev64q_u8(+ vld1q_u8((const uint8_t *) &blocks[i])));+ GHASH_MUL(b, GHASH_POW(htable, 3 - i),+ GHASH_KARAT(htable, 3 - i), H, M, L); } - vst1q_u8((uint8_t *) a, gfred_pmull(lo, hi));+ acc = ghash_reduce(H, M, L);+ vst1q_u8((uint8_t *) a, ghash_swap(vreinterpretq_u8_u64(acc))); } + int crypton_aes_armv8_pmull_available(void) {-#if defined(__APPLE__)- return 1;-#elif defined(__linux__)- return (getauxval(AT_HWCAP) & HWCAP_PMULL) != 0;-#else- return 0;-#endif+ return (crypton_arm_features() & CRYPTON_ARM_PMULL) != 0; } /*@@ -359,7 +357,7 @@ * the high half, and fold the bit that leaves the top back in as 0x87. The * block is little-endian, so lane 0 is the low half. */-TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO static inline uint8x16_t gfmulx_neon(uint8x16_t v) { const uint64x2_t x = vreinterpretq_u64_u8(v);@@ -396,3 +394,59 @@ #include <aes/armv8_impl.c> #undef SIZED #undef NBR++/*+ * The fused entry point, over the three key sizes. Each was generated with+ * its round count fixed, which is what lets the eight chains stay in+ * registers; the choice between them is made once per message here.+ */+CRYPTON_TARGET_ARMV8_CRYPTO+void crypton_aes_armv8_gcm_fused(uint8_t *out, const block128 *ht,+ aes_key *key, const uint8_t *nonce,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *in, uint32_t inlen,+ uint32_t taglen, aes_key *hpkey,+ uint32_t sampleoff, uint8_t *mask)+{+ switch (key->strength) {+ case 0:+ crypton_aes_armv8_gcm_fused128(out, ht, key, nonce, aad, aadlen,+ in, inlen, taglen, hpkey,+ sampleoff, mask);+ break;+ case 1:+ crypton_aes_armv8_gcm_fused192(out, ht, key, nonce, aad, aadlen,+ in, inlen, taglen, hpkey,+ sampleoff, mask);+ break;+ default:+ crypton_aes_armv8_gcm_fused256(out, ht, key, nonce, aad, aadlen,+ in, inlen, taglen, hpkey,+ sampleoff, mask);+ break;+ }+}++CRYPTON_TARGET_ARMV8_CRYPTO+int crypton_aes_armv8_gcm_fused_dec(uint8_t *out, const block128 *ht,+ aes_key *key, const uint8_t *nonce,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *in, uint32_t inlen,+ const uint8_t *tag, uint32_t taglen,+ uint8_t *outtag)+{+ switch (key->strength) {+ case 0:+ return crypton_aes_armv8_gcm_fused_dec128(out, ht, key, nonce,+ aad, aadlen, in, inlen,+ tag, taglen, outtag);+ case 1:+ return crypton_aes_armv8_gcm_fused_dec192(out, ht, key, nonce,+ aad, aadlen, in, inlen,+ tag, taglen, outtag);+ default:+ return crypton_aes_armv8_gcm_fused_dec256(out, ht, key, nonce,+ aad, aadlen, in, inlen,+ tag, taglen, outtag);+ }+}
@@ -25,8 +25,6 @@ #define EACH1(m) m(0) #define EACH8(m) m(0) m(1) m(2) m(3) m(4) m(5) m(6) m(7)-/* the blocks after the first; GHASH folds block 0 in with the tag */-#define EACH7(m) m(1) m(2) m(3) m(4) m(5) m(6) m(7) #define LOAD_IN(i) s[i] = vld1q_u8((const uint8_t *) (input + (i))); #define STORE_OUT(i) vst1q_u8((uint8_t *) (output + (i)), s[i]);@@ -74,7 +72,7 @@ } \ } while (0) -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_encrypt_block)(aes_block *output, aes_key *key, aes_block *input) { const uint8_t *rk = FWD(key);@@ -85,7 +83,7 @@ EACH1(STORE_OUT); } -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_decrypt_block)(aes_block *output, aes_key *key, aes_block *input) { const uint8_t *fwd = FWD(key);@@ -97,7 +95,7 @@ EACH1(STORE_OUT); } -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_encrypt_ecb)(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks) { const uint8_t *rk = FWD(key);@@ -115,7 +113,7 @@ } } -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_decrypt_ecb)(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks) { const uint8_t *fwd = FWD(key);@@ -136,7 +134,7 @@ /* CBC encryption chains, so there is nothing to interleave. It still gains * the round keys staying put. */-TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_encrypt_cbc)(aes_block *output, aes_key *key, aes_block *_iv, aes_block *input, uint32_t nb_blocks) { const uint8_t *rk = FWD(key);@@ -158,7 +156,7 @@ #define CBC_KEEP(i) c[(i) + 1] = s[i]; #define CBC_XOR(i) vst1q_u8((uint8_t *) (output + (i)), veorq_u8(s[i], c[i])); -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_decrypt_cbc)(aes_block *output, aes_key *key, aes_block *_iv, aes_block *input, uint32_t nb_blocks) { const uint8_t *fwd = FWD(key);@@ -192,7 +190,7 @@ #define CTR_XOR(i) vst1q_u8(output + 16 * (i), \ veorq_u8(s[i], vld1q_u8(input + 16 * (i)))); -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_encrypt_ctr)(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t len) { const uint8_t *rk = FWD(key);@@ -262,6 +260,47 @@ * * GCM's counter is the low 32 bits only and wraps there, so unlike CTR * there is no carry to chase: the top twelve bytes never move.+ *+ * What this loop is short of is not overlap but instructions. A group of+ * eight blocks compiles to 383 of them on an Apple M4, and only 152 are the+ * cipher -- eighty AESE and seventy-two AESMC. The rest is the GHASH and+ * the counters. Measured against OpenSSL on the same machine, 16 KiB+ * messages under AES-128:+ *+ * crypton, this loop with the GHASH taken out 19883 MB/s+ * OpenSSL, AES-128-CTR 17176+ * OpenSSL, AES-128-GCM 9869+ * crypton, AES-128-GCM 8641+ *+ * The cipher here is ahead of OpenSSL's; all of the 0.87 is the GHASH.+ * Four ways of closing it were tried and every one measured worse, so they+ * are written down here rather than tried again. Each was checked to give+ * the same ciphertext and tag as this code for three key sizes and+ * thirty-five lengths, encrypt and decrypt, before being timed:+ *+ * the GHASH held back a group and spread through the next -1.3%+ * group's AES rounds, so that the two do not queue to -3.6%+ * Karatsuba: three multiplications for the two halves -1.6%+ * instead of four+ * the same with every product on a lane the instruction 0.0%+ * reaches, which does remove sixteen fmov a group+ * the same again with the H powers' halves added together -3%+ * already, in the spare half of htable+ *+ * The first fails because there was nothing to gain: a group's AES depends+ * on nothing in the group before it, so a wide out-of-order core already+ * runs the two together, and holding a group back only adds copies. The+ * rest fail for one reason -- none of them makes the loop shorter.+ * Karatsuba buys a PMULL for two EOR and an EXT, and the folded table turns+ * sixteen `dup` into sixteen `ld1r` and sixteen more address adds.+ *+ * That last sentence used to end by saying a count which does come down+ * wants the data laid out differently. It does, and since the GHASH was+ * rewritten against a twisted H -- see cbits/aes/armv8.c -- it is laid out+ * differently, so the figures above are what the *previous* GHASH gave.+ * Karatsuba pays now that the reduction it has to carry is a third of what+ * it was; the other three are untried in the new representation and the+ * first of them has no more reason to work than it had. */ #define GCM_CTR(i) s[i] = vreinterpretq_u8_u32(vsetq_lane_u32(cpu_to_be32(c + 1 + (i)), base, 3)); #define GCM_ENC(i) { const uint8x16_t m_ = vld1q_u8(input + 16 * (i)); \@@ -270,27 +309,33 @@ #define GCM_DEC(i) { const uint8x16_t m_ = vld1q_u8(input + 16 * (i)); \ vst1q_u8(output + 16 * (i), veorq_u8(s[i], m_)); \ s[i] = m_; }-#define GCM_GHASH(i) { uint8x16_t l_, h_; \- clmul_pmull(s[i], vld1q_u8((const uint8_t *) &ht[WAY - 1 - (i)]), \- &l_, &h_); \- glo = veorq_u8(glo, l_); ghi = veorq_u8(ghi, h_); }+#define GCM_GHASH(i) \+ { \+ poly64x2_t b_ = vreinterpretq_p64_u8(vrev64q_u8(s[i])); \+ if ((i) == 0) \+ b_ = vreinterpretq_p64_u64(veorq_u64( \+ vreinterpretq_u64_p64(b_), acc)); \+ GHASH_MUL(b_, GHASH_POW(ht, WAY - 1 - (i)), \+ GHASH_KARAT(ht, WAY - 1 - (i)), gH, gM, gL); \+ } /* the eight blocks now in s[] are the ciphertext; fold them into the tag */ #define GCM_FOLD() \ do { \- uint8x16_t glo, ghi; \- clmul_pmull(veorq_u8(tag, s[0]), \- vld1q_u8((const uint8_t *) &ht[WAY - 1]), \- &glo, &ghi); \- EACH7(GCM_GHASH) \- tag = gfred_pmull(glo, ghi); \+ uint64x2_t gH = vdupq_n_u64(0), gM = gH, gL = gH; \+ acc = vreinterpretq_u64_u8( \+ vextq_u8(vreinterpretq_u8_u64(acc), \+ vreinterpretq_u8_u64(acc), 8)); \+ EACH8(GCM_GHASH) \+ acc = ghash_reduce(gH, gM, gL); \ } while (0) #define GCM_PROLOGUE \ const uint8_t *rk = FWD(key); \ const block128 *ht = gcm->htable; \ uint8x16_t s[WAY]; \- uint8x16_t tag = vld1q_u8((const uint8_t *) &gcm->tag); \+ uint64x2_t acc = vreinterpretq_u64_u8( \+ ghash_swap(vld1q_u8((const uint8_t *) &gcm->tag))); \ uint32_t c = be32_to_cpu(gcm->civ.d[3]); \ uint32x4_t base = vreinterpretq_u32_u8(vld1q_u8((const uint8_t *) &gcm->civ)) @@ -303,16 +348,17 @@ ENC_ROUNDS(EACH1); \ s[0] = veorq_u8(s[0], m_); \ (store_c); \- tag = gfmul_pmull(veorq_u8(tag, (ghash_of)), (const uint8_t *) ht); \+ acc = ghash_one(acc, (ghash_of), ht); \ } while (0) #define GCM_EPILOGUE \ do { \ gcm->civ.d[3] = cpu_to_be32(c); \- vst1q_u8((uint8_t *) &gcm->tag, tag); \+ vst1q_u8((uint8_t *) &gcm->tag, \+ ghash_swap(vreinterpretq_u8_u64(acc))); \ } while (0) -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_gcm_encrypt)(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length) { GCM_PROLOGUE;@@ -343,13 +389,12 @@ block128_zero(&m); for (i = 0; i < length; i++) output[i] = m.b[i] = o.b[i];- tag = gfmul_pmull(veorq_u8(tag, vld1q_u8((const uint8_t *) &m)),- (const uint8_t *) ht);+ acc = ghash_one(acc, vld1q_u8((const uint8_t *) &m), ht); } GCM_EPILOGUE; } -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_gcm_decrypt)(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length) { GCM_PROLOGUE;@@ -381,8 +426,7 @@ vst1q_u8((uint8_t *) &o, s[0]); for (i = 0; i < length; i++) output[i] = o.b[i];- tag = gfmul_pmull(veorq_u8(tag, vld1q_u8((const uint8_t *) &m)),- (const uint8_t *) ht);+ acc = ghash_one(acc, vld1q_u8((const uint8_t *) &m), ht); } GCM_EPILOGUE; }@@ -433,7 +477,7 @@ } while (0); #define XTS_TWEAK_ROLL(i) do { t[i] = tn[i]; } while (0); -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_encrypt_xts)(aes_block *output, aes_key *key, aes_key *key2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks) { const uint8_t *rk = FWD(key);@@ -477,7 +521,7 @@ } } -TARGET_ARMV8_CRYPTO+CRYPTON_TARGET_ARMV8_CRYPTO void SIZED(crypton_aes_armv8_decrypt_xts)(aes_block *output, aes_key *key, aes_key *key2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks) { const uint8_t *fwd = FWD(key);@@ -523,9 +567,237 @@ } } +/*+ * One message, one call: the additional data, the counter-mode encryption,+ * the tag and the QUIC header protection mask, with the running tag and the+ * counter kept in registers from end to end.+ *+ * What this saves over composing crypton_aes_gcm_aad, _encrypt and _finish is+ * not the arithmetic but the boundaries. Each of those reaches its+ * primitives through a branch table, so the 128-bit state goes back to memory+ * at every step and a header of one block pays a reduction of its own. On an+ * Apple M4 that framing was 0.07 of the 0.112 microseconds a 100-byte packet+ * cost -- more than the encryption of the packet itself.+ *+ * The GHASH is taken in batches of WAY against the powers of H the key+ * already holds, so a batch costs one reduction rather than one per block,+ * and the additional data and the length block ride in the same batches as+ * the ciphertext instead of being multiplied on their own.+ */++/* start a batch, or continue one; blen is how many blocks this batch holds */+#define FG_ABSORB(blk) \+ do { \+ poly64x2_t b_ = vreinterpretq_p64_u8(vrev64q_u8(blk)); \+ if (bn == 0) { \+ uint32_t left_ = gtotal - gidx; \+ blen = left_ < WAY ? left_ : WAY; \+ acc = vreinterpretq_u64_u8( \+ vextq_u8(vreinterpretq_u8_u64(acc), \+ vreinterpretq_u8_u64(acc), 8)); \+ b_ = vreinterpretq_p64_u64(veorq_u64( \+ vreinterpretq_u64_p64(b_), acc)); \+ gH = vdupq_n_u64(0); \+ gM = gH; \+ gL = gH; \+ } \+ GHASH_MUL(b_, GHASH_POW(ht, blen - bn - 1), \+ GHASH_KARAT(ht, blen - bn - 1), gH, gM, gL); \+ gidx++; bn++; \+ if (bn == blen) { acc = ghash_reduce(gH, gM, gL); bn = 0; } \+ } while (0)++/* a block that is short, zero padded, as GHASH wants it */+#define FG_PARTIAL(p, n) \+ ({ uint8_t buf_[16]; memset(buf_, 0, 16); memcpy(buf_, (p), (n)); \+ vld1q_u8(buf_); })++CRYPTON_TARGET_ARMV8_CRYPTO+void SIZED(crypton_aes_armv8_gcm_fused)(uint8_t *out, const block128 *ht,+ aes_key *key, const uint8_t *nonce,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *in, uint32_t inlen,+ uint32_t taglen, aes_key *hpkey,+ uint32_t sampleoff, uint8_t *mask)+{+ const uint8_t *rk = FWD(key);+ uint8x16_t s[WAY];+ uint8x16_t ek0;+ uint64x2_t acc = vdupq_n_u64(0), gH = acc, gM = acc, gL = acc;+ uint32x4_t base;+ uint32_t c = 1, bn = 0, blen = 0, gidx = 0;+ uint32_t gtotal = (aadlen + 15) / 16 + (inlen + 15) / 16 + 1;+ uint32_t i, done;+ uint8_t y0[16], lenb[16];+ uint64_t la, lc;++ memcpy(y0, nonce, 12);+ y0[12] = 0; y0[13] = 0; y0[14] = 0; y0[15] = 1;+ base = vreinterpretq_u32_u8(vld1q_u8(y0));++ s[0] = vld1q_u8(y0);+ ENC_ROUNDS(EACH1);+ ek0 = s[0];++ for (i = 0; i + 16 <= aadlen; i += 16)+ FG_ABSORB(vld1q_u8(aad + i));+ if (i < aadlen)+ FG_ABSORB(FG_PARTIAL(aad + i, aadlen - i));++ for (done = 0; done + 16 * WAY <= inlen; done += 16 * WAY) {+ const uint8_t *p = in + done;+ uint8_t *q = out + done;++ EACH8(GCM_CTR);+ c += WAY;+ ENC_ROUNDS(EACH8);+ {+ const uint8_t *input = p;+ uint8_t *output = q;+ EACH8(GCM_ENC);+ }+ FG_ABSORB(s[0]); FG_ABSORB(s[1]); FG_ABSORB(s[2]); FG_ABSORB(s[3]);+ FG_ABSORB(s[4]); FG_ABSORB(s[5]); FG_ABSORB(s[6]); FG_ABSORB(s[7]);+ }++ for (; done < inlen; done += 16) {+ uint32_t n = inlen - done < 16 ? inlen - done : 16;+ uint8x16_t m_ = n == 16 ? vld1q_u8(in + done)+ : FG_PARTIAL(in + done, n);+ c++;+ s[0] = vreinterpretq_u8_u32(vsetq_lane_u32(cpu_to_be32(c), base, 3));+ ENC_ROUNDS(EACH1);+ s[0] = veorq_u8(s[0], m_);+ if (n == 16) {+ vst1q_u8(out + done, s[0]);+ } else {+ uint8_t buf_[16];+ vst1q_u8(buf_, s[0]);+ memcpy(out + done, buf_, n);+ memset(buf_ + n, 0, 16 - n);+ s[0] = vld1q_u8(buf_);+ }+ FG_ABSORB(s[0]);+ }++ la = (uint64_t) aadlen << 3;+ lc = (uint64_t) inlen << 3;+ for (i = 0; i < 8; i++) lenb[i] = (uint8_t) (la >> (56 - 8 * i));+ for (i = 0; i < 8; i++) lenb[8 + i] = (uint8_t) (lc >> (56 - 8 * i));+ FG_ABSORB(vld1q_u8(lenb));++ {+ uint8_t tbuf[16];+ vst1q_u8(tbuf, veorq_u8(ghash_swap(vreinterpretq_u8_u64(acc)), ek0));+ memcpy(out + inlen, tbuf, taglen);+ }++ if (hpkey != 0 && mask != 0) {+ block128 sample, m;+ memcpy(&sample, out + sampleoff, 16);+ crypton_aes_encrypt_ecb(&m, hpkey, &sample, 1);+ memcpy(mask, &m, 16);+ }+}+++/*+ * The same for decryption. GCM_DEC leaves the ciphertext in s[] once it has+ * written the plaintext out, which is what GHASH wants, so the only other+ * difference is the end: the tag is compared here rather than written, every+ * byte of it whichever way the answer goes.+ */+CRYPTON_TARGET_ARMV8_CRYPTO+int SIZED(crypton_aes_armv8_gcm_fused_dec)(uint8_t *out, const block128 *ht,+ aes_key *key, const uint8_t *nonce,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *in, uint32_t inlen,+ const uint8_t *tagp, uint32_t taglen,+ uint8_t *outtag)+{+ const uint8_t *rk = FWD(key);+ uint8x16_t s[WAY];+ uint8x16_t ek0;+ uint64x2_t acc = vdupq_n_u64(0), gH = acc, gM = acc, gL = acc;+ uint32x4_t base;+ uint32_t c = 1, bn = 0, blen = 0, gidx = 0;+ uint32_t gtotal = (aadlen + 15) / 16 + (inlen + 15) / 16 + 1;+ uint32_t i, done;+ uint8_t y0[16], lenb[16], want[16];+ uint64_t la, lc;+ uint8_t diff = 0;++ memcpy(y0, nonce, 12);+ y0[12] = 0; y0[13] = 0; y0[14] = 0; y0[15] = 1;+ base = vreinterpretq_u32_u8(vld1q_u8(y0));++ s[0] = vld1q_u8(y0);+ ENC_ROUNDS(EACH1);+ ek0 = s[0];++ for (i = 0; i + 16 <= aadlen; i += 16)+ FG_ABSORB(vld1q_u8(aad + i));+ if (i < aadlen)+ FG_ABSORB(FG_PARTIAL(aad + i, aadlen - i));++ for (done = 0; done + 16 * WAY <= inlen; done += 16 * WAY) {+ const uint8_t *p = in + done;+ uint8_t *q = out + done;++ EACH8(GCM_CTR);+ c += WAY;+ ENC_ROUNDS(EACH8);+ {+ const uint8_t *input = p;+ uint8_t *output = q;+ EACH8(GCM_DEC);+ }+ FG_ABSORB(s[0]); FG_ABSORB(s[1]); FG_ABSORB(s[2]); FG_ABSORB(s[3]);+ FG_ABSORB(s[4]); FG_ABSORB(s[5]); FG_ABSORB(s[6]); FG_ABSORB(s[7]);+ }++ for (; done < inlen; done += 16) {+ uint32_t n = inlen - done < 16 ? inlen - done : 16;+ uint8x16_t m_ = n == 16 ? vld1q_u8(in + done)+ : FG_PARTIAL(in + done, n);+ c++;+ s[0] = vreinterpretq_u8_u32(vsetq_lane_u32(cpu_to_be32(c), base, 3));+ ENC_ROUNDS(EACH1);+ {+ uint8x16_t pl = veorq_u8(s[0], m_);+ if (n == 16) {+ vst1q_u8(out + done, pl);+ } else {+ uint8_t buf_[16];+ vst1q_u8(buf_, pl);+ memcpy(out + done, buf_, n);+ }+ }+ FG_ABSORB(m_);+ }++ la = (uint64_t) aadlen << 3;+ lc = (uint64_t) inlen << 3;+ for (i = 0; i < 8; i++) lenb[i] = (uint8_t) (la >> (56 - 8 * i));+ for (i = 0; i < 8; i++) lenb[8 + i] = (uint8_t) (lc >> (56 - 8 * i));+ FG_ABSORB(vld1q_u8(lenb));++ vst1q_u8(want, veorq_u8(ghash_swap(vreinterpretq_u8_u64(acc)), ek0));+ if (outtag) {+ /* The caller holds the expected tag and will compare it itself. */+ memcpy(outtag, want, taglen);+ return 1;+ }+ for (i = 0; i < taglen; i++)+ diff |= (uint8_t) (want[i] ^ tagp[i]);+ return diff == 0;+}++#undef FG_ABSORB+#undef FG_PARTIAL+ #undef WAY #undef EACH1-#undef EACH7 #undef EACH8 #undef LOAD_IN #undef STORE_OUT
@@ -34,7 +34,21 @@ #include <crypton_bitfn.h> #include <crypton_align.h> -typedef union {+/* Packed, so that the union asks nothing of the address it is at.+ *+ * Several callers here make one of these out of a pointer of their own -- a+ * ciphertext, a tag, a nonce -- and without this that cast produces a pointer+ * the standard says may not exist, and reading q[] out of it is a member+ * access at an address the type is not aligned for. crypton_align.h used to+ * answer that with need_alignment, which is zero on i386 and x86-64: the two+ * places the access is architecturally fine and the standard still says+ * nothing about it. UndefinedBehaviorSanitizer reported it.+ *+ * With the alignment declared to be one, the compiler is the one that knows+ * what the target can do: on i386, x86-64 and AArch64 it emits the same load+ * and store it emitted before, and where a target cannot read a word off an+ * odd address it emits what that target needs. */+typedef union __attribute__((packed)) { uint64_t q[2]; uint32_t d[4]; uint16_t w[8];
@@ -0,0 +1,1013 @@+/*+ * A fused AES-GCM for x86-64, following the design Kazuho Oku sets out in+ * "QUICむけにAES-GCM実装を最適化した話" and implements in picotls's+ * lib/fusion.c: keep AES-NI issuing every clock and fit everything else --+ * the additional data, the tag, the QUIC header protection mask -- into the+ * gaps it leaves. Written in C with intrinsics rather than assembly, for+ * the same reason he gives: the scheduling is what is complicated here, and+ * it has to stay readable to stay correct.+ *+ * Parts of this file follow fusion closely enough to say so: `loadn` and the+ * two tables it reads, `loadn_page_end` and `storen` are its `loadn128`,+ * `loadn_end_of_page` and `storen128` in another spelling, and the+ * reduction of a 256-bit product is the sequence fusion takes from Gueron's+ * "AES-GCM for Efficient Authenticated Encryption". fusion is under the MIT+ * license, which is in cbits/aes/LICENSE.fusion beside this file.+ *+ * The powers of H are built once per key, so the additional data, the+ * ciphertext and the length block are absorbed against them in batches that+ * share one reduction, rather than each block paying for a reduction of its+ * own. How many powers, and so how large a batch, is+ * CRYPTON_GCM_FUSED_POWERS in crypton_aes.h.+ *+ * Only messages shorter than CRYPTON_GCM_FUSED_MAX_MESSAGE come here. Above+ * that the stitched assembly in cbits/asm is faster, and crypton_aes.c sends+ * them there instead; below it, that assembly will not start at all.+ */++#include <crypton_cpu.h>++#ifdef WITH_GCM_FUSED++#include <stdint.h>+#include <string.h>+#include <wmmintrin.h>+#include <smmintrin.h>+#include <tmmintrin.h>++#include <crypton_aes.h>+#include <aes/gcm_fused_x86.h>++/*+ * aes_key is a struct of bytes, so its round keys sit wherever the members+ * before them leave them -- eight bytes in, as it happens. A __m128i *+ * pointed at that gets an aligned load and a fault, so each round key is+ * fetched with an unaligned load instead. Copying them somewhere aligned+ * would cost a copy per call, which at these message lengths is a tenth of+ * the whole; the load is free from L1 and the round key is fetched once for+ * all six lanes.+ */+#define RK(p, i) \+ _mm_loadu_si128((const __m128i *) ((const uint8_t *) (p) + 16 * (size_t) (i)))++/* a full sixteen-byte reversal: mask bytes 15,14,...,0 */+static const __m128i BSWAP = {0x08090a0b0c0d0e0fLL, 0x0001020304050607LL};+++#define TGT __attribute__((target("aes,pclmul,sse4.1")))++/* the two halves of a value added together: the term Karatsuba needs, and it+ * does not depend on what the value is multiplied by */+TGT static inline __m128i fold(__m128i a)+{+ return _mm_xor_si128(a, _mm_unpackhi_epi64(a, a));+}++/* H multiplied by x in the field, which is what puts H and its powers one+ * bit up: GCM numbers the bits of a field element the other way round from+ * the way the carry-less multiply does, and pre-shifting is what saves the+ * correction after every multiply.+ *+ * Written from the definition. The field is GF(2)[x] modulo x^128 + x^127 ++ * x^126 + x^121 + 1, so multiplying by x is a shift of one place, and the+ * term that leaves the top comes back as the other four. */+TGT static __m128i twist(__m128i h)+{+ /* x^127 + x^126 + x^121 + 1, the terms x^128 is congruent to */+ const __m128i poly = _mm_set_epi64x(0xc200000000000000ULL, 1);+ /* the top bit of each half */+ __m128i tops = _mm_srli_epi64(h, 63);+ /* doubling a polynomial is a shift by one: each half doubles, and the+ * low half's top bit becomes the high half's bottom bit */+ __m128i doubled = _mm_or_si128(_mm_add_epi64(h, h),+ _mm_slli_si128(tops, 8));+ /* bit 127 is the one that leaves the field; spread it to a mask by+ * subtracting it from zero, and it brings the four terms back */+ __m128i mask = _mm_sub_epi64(_mm_setzero_si128(),+ _mm_unpackhi_epi64(tops, tops));++ return _mm_xor_si128(doubled, _mm_and_si128(mask, poly));+}++/* one reduction of a 256-bit product back into the field */+TGT static __m128i reduce256(__m128i lo, __m128i hi)+{+ const __m128i poly = _mm_set_epi64x(0xc200000000000000ULL, 1);+ __m128i t;++ t = _mm_clmulepi64_si128(lo, poly, 0x10);+ lo = _mm_xor_si128(_mm_shuffle_epi32(lo, 0x4e), t);+ t = _mm_clmulepi64_si128(lo, poly, 0x10);+ lo = _mm_xor_si128(_mm_shuffle_epi32(lo, 0x4e), t);+ return _mm_xor_si128(hi, lo);+}++/*+ * One multiply in exactly the form the hot loop uses it: the left operand+ * plain, the right one already twisted. Building the table with the same+ * multiply that consumes it is the only way the two conventions cannot drift+ * apart.+ */+TGT static __m128i mul_twisted(__m128i a, __m128i ht)+{+ __m128i lo = _mm_clmulepi64_si128(a, ht, 0x00);+ __m128i hi = _mm_clmulepi64_si128(a, ht, 0x11);+ __m128i mid = _mm_clmulepi64_si128(fold(a), fold(ht), 0x00);++ mid = _mm_xor_si128(mid, _mm_xor_si128(lo, hi));+ lo = _mm_xor_si128(lo, _mm_slli_si128(mid, 8));+ hi = _mm_xor_si128(hi, _mm_srli_si128(mid, 8));+ return reduce256(lo, hi);+}++TGT void crypton_gcm_fused_key_init(aes_gcm_fused *fk, const aes_key *key)+{+ const uint8_t *rk = key->data;+ const int rounds = key->nbr;+ __m128i h, p;+ int i;++ /* H = E_K(0) */+ h = RK(rk, 0);+ for (i = 1; i < rounds; i++) h = _mm_aesenc_si128(h, RK(rk, i));+ h = _mm_aesenclast_si128(h, RK(rk, rounds));+ h = _mm_shuffle_epi8(h, BSWAP);++ {+ __m128i ht = twist(h);+ p = h;+ for (i = 0; i < CRYPTON_GCM_FUSED_POWERS; i++) {+ __m128i t = twist(p);+ _mm_storeu_si128((__m128i *) &fk->p[i].h, t);+ _mm_storeu_si128((__m128i *) &fk->p[i].r, fold(t));+ p = mul_twisted(p, ht);+ }+ }+}++/*+ * The running product. Three plain locals and a macro, not a struct behind+ * a pointer: taking the address of the accumulators is enough to keep them+ * out of registers, and then every multiply reloads and restores them. That+ * is the same mistake as reaching a table through an index the compiler+ * cannot fold, and it costs more here because it is on the inner path.+ */+#define GHASH_DECL __m128i glo = _mm_setzero_si128(), \+ ghi = _mm_setzero_si128(), \+ gmid = _mm_setzero_si128(), \+ gtag = _mm_setzero_si128(); \+ int gidx = 0, gblen = 0, gbpos = 0++/*+ * Absorb one block. Blocks are taken in batches of at most CRYPTON_GCM_FUSED_POWERS: the+ * first of a batch carries in the value the batch before it reduced to, the+ * rest go in against descending powers, and the batch ends with the one+ * reduction they share. With the batch as long as the message this is+ * picotls's single reduction; with it fixed, the state stays a fixed size.+ */+#define GHASH_ONE(blk, unused_power) \+ do { \+ __m128i _b = (blk); \+ __m128i _h, _r; \+ if (gbpos == 0) { \+ int _left = gtotal - gidx; \+ gblen = _left < CRYPTON_GCM_FUSED_POWERS ? _left : CRYPTON_GCM_FUSED_POWERS; \+ _b = _mm_xor_si128(_b, gtag); \+ glo = ghi = gmid = _mm_setzero_si128(); \+ } \+ _h = _mm_loadu_si128((const __m128i *) &fk->p[gblen-gbpos-1].h); \+ _r = _mm_loadu_si128((const __m128i *) &fk->p[gblen-gbpos-1].r); \+ glo = _mm_xor_si128(glo, _mm_clmulepi64_si128(_b, _h, 0x00)); \+ ghi = _mm_xor_si128(ghi, _mm_clmulepi64_si128(_b, _h, 0x11)); \+ gmid = _mm_xor_si128(gmid, \+ _mm_clmulepi64_si128(fold(_b), _r, 0x00)); \+ gidx++; gbpos++; \+ if (gbpos == gblen) { \+ gtag = ghash_reduce(glo, ghi, gmid); \+ gbpos = 0; \+ } \+ } while (0)++TGT static __m128i ghash_reduce(__m128i glo, __m128i ghi, __m128i gmid)+{+ __m128i mid = _mm_xor_si128(gmid, _mm_xor_si128(glo, ghi));+ __m128i lo = _mm_xor_si128(glo, _mm_slli_si128(mid, 8));+ __m128i hi = _mm_xor_si128(ghi, _mm_srli_si128(mid, 8));++ return reduce256(lo, hi);+}++/* zero every byte from n onwards, so a partial block can be fed to GHASH+ * without being written out and read back */+TGT static __m128i clampn(__m128i v, size_t n)+{+ const __m128i idx = {0x0706050403020100LL, 0x0f0e0d0c0b0a0908LL};+ return _mm_and_si128(v, _mm_cmpgt_epi8(_mm_set1_epi8((char) n), idx));+}++/*+ * A short block, zero padded, without going through the stack.+ *+ * The obvious way -- zero sixteen bytes, copy n in, load them back -- is+ * three trips to memory with a store the load has to wait for, and at these+ * lengths that is a tenth of the whole call. Reading the sixteen bytes and+ * masking off what is above n is two instructions, but it reads past the end+ * of what the caller gave, so it has to be sure those bytes exist.+ *+ * They do unless the block ends a page. A load of sixteen bytes that starts+ * at least sixteen from the end of a page stays inside it; and if the n bytes+ * asked for themselves cross the boundary then the next page is there to be+ * read as well. What is left is a block near the end of a page whose own+ * bytes stop short of it, and that is read aligned -- which cannot leave the+ * page -- and shuffled down. This is how picotls's fusion does it.+ */++/* thirty-two bytes of ones, then thirty-one of zeros: sixteen loaded from+ * 32 - n give n bytes of ones and the rest zeros */+static const uint8_t loadn_mask[63] = {+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};++/* the first sixteen map to byte offsets, the rest to zero */+static const uint8_t loadn_shuffle[31] = {+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};++#if defined(__has_feature)+#if __has_feature(address_sanitizer)+#define NO_ASAN __attribute__((no_sanitize_address))+#endif+#elif defined(__SANITIZE_ADDRESS__)+#define NO_ASAN __attribute__((no_sanitize_address))+#endif+#ifndef NO_ASAN+#define NO_ASAN+#endif++TGT NO_ASAN static __m128i loadn_page_end(const uint8_t *p, size_t n)+{+ uintptr_t shift = (uintptr_t) p & 15;+ __m128i pattern = _mm_loadu_si128((const __m128i *) (loadn_shuffle + shift));++ (void) n;+ return _mm_shuffle_epi8(+ _mm_load_si128((const __m128i *) ((uintptr_t) p - shift)), pattern);+}++TGT NO_ASAN static __m128i loadn(const uint8_t *p, size_t n)+{+ __m128i mask = _mm_loadu_si128((const __m128i *) (loadn_mask + 32 - n));+ uintptr_t mod4k = (uintptr_t) p % 4096;+ __m128i v;++ if (mod4k <= 4096 - 16 || mod4k + n > 4096)+ v = _mm_loadu_si128((const __m128i *) p);+ else+ v = loadn_page_end(p, n);+ return _mm_and_si128(v, mask);+}++TGT static void storen(uint8_t *p, __m128i v, size_t n)+{+ uint8_t buf[16];+ _mm_storeu_si128((__m128i *) buf, v);+ memcpy(p, buf, n);+}++/* One block. The ten rounds of the common case are written out for the+ * same reason the six-wide group is: a loop over a round count that lives in+ * the key leaves every round key fetched through an index the compiler+ * cannot fold, and adds a branch to a chain that is already latency-bound. */+TGT static __m128i aes_one_block(const uint8_t *rk, int rounds, __m128i v)+{+ const uint8_t *k = rk;+ int i;++ if (rounds == 10) {+ v = _mm_xor_si128(v, RK(k, 0));+ v = _mm_aesenc_si128(v, RK(k, 1));+ v = _mm_aesenc_si128(v, RK(k, 2));+ v = _mm_aesenc_si128(v, RK(k, 3));+ v = _mm_aesenc_si128(v, RK(k, 4));+ v = _mm_aesenc_si128(v, RK(k, 5));+ v = _mm_aesenc_si128(v, RK(k, 6));+ v = _mm_aesenc_si128(v, RK(k, 7));+ v = _mm_aesenc_si128(v, RK(k, 8));+ v = _mm_aesenc_si128(v, RK(k, 9));+ return _mm_aesenclast_si128(v, RK(k, 10));+ }+ v = _mm_xor_si128(v, RK(k, 0));+ for (i = 1; i < rounds; i++) v = _mm_aesenc_si128(v, RK(k, i));+ return _mm_aesenclast_si128(v, RK(k, rounds));+}++/*+ * Six blocks at once, with lane 5 free to run a different key schedule from+ * the rest. Which schedule that lane uses is chosen once, into a pointer,+ * rather than tested inside the rounds, and the six live in named variables+ * rather than an array -- an array indexed by a running variable goes to+ * memory, and then every round is a load and a store instead of a register+ * to register operation, which is the whole of what this is trying to avoid.+ *+ * Lanes beyond what the caller needs still run. Six are in flight whatever+ * the message length, so the spare ones cost nothing, and that is exactly+ * why the header protection mask and E(K,Y0) are worth putting in them+ * instead of giving each a dependent chain of its own.+ */+#define WIDE6(alt) \+ do { \+ const uint8_t *ak = (alt); \+ int r; \+ t0 = _mm_xor_si128(t0, RK(rk, 0)); \+ t1 = _mm_xor_si128(t1, RK(rk, 0)); \+ t2 = _mm_xor_si128(t2, RK(rk, 0)); \+ t3 = _mm_xor_si128(t3, RK(rk, 0)); \+ t4 = _mm_xor_si128(t4, RK(rk, 0)); \+ t5 = _mm_xor_si128(t5, RK(ak, 0)); \+ for (r = 1; r < rounds; r++) { \+ __m128i k = RK(rk, r); \+ t0 = _mm_aesenc_si128(t0, k); \+ t1 = _mm_aesenc_si128(t1, k); \+ t2 = _mm_aesenc_si128(t2, k); \+ t3 = _mm_aesenc_si128(t3, k); \+ t4 = _mm_aesenc_si128(t4, k); \+ t5 = _mm_aesenc_si128(t5, RK(ak, r)); \+ GSTEP(); \+ } \+ { \+ __m128i k = RK(rk, rounds); \+ t0 = _mm_aesenclast_si128(t0, k); \+ t1 = _mm_aesenclast_si128(t1, k); \+ t2 = _mm_aesenclast_si128(t2, k); \+ t3 = _mm_aesenclast_si128(t3, k); \+ t4 = _mm_aesenclast_si128(t4, k); \+ t5 = _mm_aesenclast_si128(t5, RK(ak, rounds)); \+ } \+ } while (0)++/* the same with nothing queued to absorb: the decryption side takes its+ * GHASH straight from the input and has no queue to drain */+#define WIDE6_NOQ(alt) \+ do { \+ const uint8_t *ak = (alt); \+ int r; \+ t0 = _mm_xor_si128(t0, RK(rk, 0)); \+ t1 = _mm_xor_si128(t1, RK(rk, 0)); \+ t2 = _mm_xor_si128(t2, RK(rk, 0)); \+ t3 = _mm_xor_si128(t3, RK(rk, 0)); \+ t4 = _mm_xor_si128(t4, RK(rk, 0)); \+ t5 = _mm_xor_si128(t5, RK(ak, 0)); \+ for (r = 1; r < rounds; r++) { \+ __m128i k = RK(rk, r); \+ t0 = _mm_aesenc_si128(t0, k); \+ t1 = _mm_aesenc_si128(t1, k); \+ t2 = _mm_aesenc_si128(t2, k); \+ t3 = _mm_aesenc_si128(t3, k); \+ t4 = _mm_aesenc_si128(t4, k); \+ t5 = _mm_aesenc_si128(t5, RK(ak, r)); \+ } \+ { \+ __m128i k = RK(rk, rounds); \+ t0 = _mm_aesenclast_si128(t0, k); \+ t1 = _mm_aesenclast_si128(t1, k); \+ t2 = _mm_aesenclast_si128(t2, k); \+ t3 = _mm_aesenclast_si128(t3, k); \+ t4 = _mm_aesenclast_si128(t4, k); \+ t5 = _mm_aesenclast_si128(t5, RK(ak, rounds)); \+ } \+ } while (0)++/*+ * The same written out for the ten rounds of AES-128, with a slot for one+ * queued multiply between each of the first six. The loop above cannot take+ * them: the round count is a value in the key, so there is no place the+ * compiler knows is a round apart from the next, and a test before each+ * multiply would end the basic block the scheduler works inside. This pass+ * runs with a group's multiplies still waiting, and on a short message that+ * is most of what it has to do.+ */+#define WROUND6(r, ak) \+ do { \+ __m128i k = RK(rk, r); \+ t0 = _mm_aesenc_si128(t0, k); \+ t1 = _mm_aesenc_si128(t1, k); \+ t2 = _mm_aesenc_si128(t2, k); \+ t3 = _mm_aesenc_si128(t3, k); \+ t4 = _mm_aesenc_si128(t4, k); \+ t5 = _mm_aesenc_si128(t5, RK(ak, r)); \+ } while (0)++#define WIDE6_10(alt) \+ do { \+ const uint8_t *ak = (alt); \+ t0 = _mm_xor_si128(t0, RK(rk, 0)); \+ t1 = _mm_xor_si128(t1, RK(rk, 0)); \+ t2 = _mm_xor_si128(t2, RK(rk, 0)); \+ t3 = _mm_xor_si128(t3, RK(rk, 0)); \+ t4 = _mm_xor_si128(t4, RK(rk, 0)); \+ t5 = _mm_xor_si128(t5, RK(ak, 0)); \+ WROUND6(1, ak); GAT(0); \+ WROUND6(2, ak); GAT(1); \+ WROUND6(3, ak); GAT(2); \+ WROUND6(4, ak); GAT(3); \+ WROUND6(5, ak); GAT(4); \+ WROUND6(6, ak); GAT(5); \+ WROUND6(7, ak); \+ WROUND6(8, ak); \+ WROUND6(9, ak); \+ { \+ __m128i k = RK(rk, 10); \+ t0 = _mm_aesenclast_si128(t0, k); \+ t1 = _mm_aesenclast_si128(t1, k); \+ t2 = _mm_aesenclast_si128(t2, k); \+ t3 = _mm_aesenclast_si128(t3, k); \+ t4 = _mm_aesenclast_si128(t4, k); \+ t5 = _mm_aesenclast_si128(t5, RK(ak, 10)); \+ } \+ } while (0)++/*+ * v2: six blocks of AES in flight at once, so the ten rounds of one block no+ * longer wait on each other -- AES-NI is pipelined and will take one+ * instruction a clock as long as the instructions in flight are independent.+ * The GHASH multiplies of the group just finished are issued between the+ * rounds of the group now running, which is the stitching: they do not want+ * the same execution port, so held against each other they cost about what+ * the rounds alone cost.+ */++/*+ * The counter block, built without leaving the vector registers.+ *+ * GCM counts in the low 32 bits of the block, big endian, and wraps there.+ * ctr holds the block with its bytes reversed, so those four bytes are the+ * low lane and _mm_add_epi32 steps them without carrying into the nonce+ * above -- which is the wrap GCM asks for. A shuffle puts the bytes back.+ *+ * The obvious way -- increment a uint32_t, byte swap it, pinsrd it in --+ * costs a move from a general register to a vector one for every lane, six+ * to a group, and those do not come free.+ */+#define CTR6(j) \+ do { \+ ctr = _mm_add_epi32(ctr, one32); \+ b##j = _mm_xor_si128(_mm_shuffle_epi8(ctr, BSWAP), RK(rk, 0)); \+ } while (0)++#define ROUND6(r) \+ do { \+ __m128i k = RK(rk, r); \+ b0 = _mm_aesenc_si128(b0, k); \+ b1 = _mm_aesenc_si128(b1, k); \+ b2 = _mm_aesenc_si128(b2, k); \+ b3 = _mm_aesenc_si128(b3, k); \+ b4 = _mm_aesenc_si128(b4, k); \+ b5 = _mm_aesenc_si128(b5, k); \+ } while (0)++#define LAST6(r) \+ do { \+ __m128i k = RK(rk, r); \+ b0 = _mm_aesenclast_si128(b0, k); \+ b1 = _mm_aesenclast_si128(b1, k); \+ b2 = _mm_aesenclast_si128(b2, k); \+ b3 = _mm_aesenclast_si128(b3, k); \+ b4 = _mm_aesenclast_si128(b4, k); \+ b5 = _mm_aesenclast_si128(b5, k); \+ } while (0)++/* one GHASH multiply, taken from a queue of blocks waiting to be absorbed,+ * to be issued in the gaps between AES rounds */+/* A ring, so that a block queued while others are still waiting costs an+ * index and not a move: the queue is walked from both ends and never+ * compacted. */+#define GQ_MASK 15++#define GPUSH(v) \+ do { gq[gw] = (v); gw++; gn++; } while (0)++#define GSTEP() \+ do { \+ if (gn > 0) { \+ GHASH_ONE(gq[gi], gp); \+ gi++; gp--; gn--; \+ } \+ } while (0)++/* the same at a slot the compiler can see, for the unrolled group below */+/*+ * One queued block, at a slot the compiler can see and with nothing to test+ * before it. A test here would end the basic block, and the scheduler works+ * inside one: six tests turn the group into twelve blocks and the multiplies+ * can no longer be moved up among the rounds, which is the whole point of+ * writing them there. The group below is entered only when the queue is+ * full, so there is nothing to test.+ */+/*+ * The block a slot names, read from the output where the group before it+ * left the ciphertext rather than from a copy kept beside it. The copy+ * cost six stores a group for bytes already in memory; picotls's fusion+ * points its GHASH at the output it has just written for the same reason.+ */+#define GAT(j) GHASH_ONE(_mm_shuffle_epi8( \+ _mm_loadu_si128((const __m128i *) (prev + 16 * (j))), BSWAP), gp - (j))++TGT void crypton_gcm_fused_encrypt(uint8_t *out, const aes_gcm_fused *fk,+ const aes_key *key, const uint8_t *nonce,+ const uint8_t *aad, size_t aadlen,+ const uint8_t *in, size_t inlen, size_t taglen,+ const aes_key *hpkey, size_t sampleoff,+ uint8_t *mask)+{+ const uint8_t *rk = key->data;+ const uint8_t *hprk = hpkey != 0 ? hpkey->data : rk;+ const int rounds = key->nbr;+ const int hprounds = hpkey != 0 ? hpkey->nbr : rounds;+ GHASH_DECL;+ __m128i ctrbase, ctr, one32, ek0, tag, b0, b1, b2, b3, b4, b5;+ const int ntail_pre = (int) ((inlen % 96 + 15) / 16);+ int lane_ek0;+ __m128i gq[6];+ unsigned gi = 0, gw = 0;+ int gn = 0;+ size_t nblk = (aadlen + 15) / 16 + (inlen + 15) / 16 + 1;+ const int gtotal = (int) nblk;+ int gp = (int) nblk;+ size_t i;+ size_t done;+ int lane_mask = 0;++ /*+ * Y0: the twelve bytes of nonce and a counter of one. loadn reads the+ * nonce where it lies and masks what is above it, so this is one load+ * rather than three of four bytes each and a set built from them.+ */+ ctrbase = _mm_insert_epi32(loadn(nonce, 12), (int) __builtin_bswap32(1), 3);+ ctr = _mm_shuffle_epi8(ctrbase, BSWAP);+ one32 = _mm_set_epi32(0, 0, 0, 1);++ lane_ek0 = ntail_pre > 0 && ntail_pre <= 4;+ if (!lane_ek0)+ ek0 = aes_one_block(rk, rounds, ctrbase);++ /* The additional data goes in first and takes the highest powers, but it+ * is only queued here: absorbing it takes multiplies, and the multiplies+ * belong in the gaps between the AES rounds below rather than in front+ * of them where nothing else is running. */+ /*+ * The additional data goes in first and takes the highest powers. It is+ * absorbed here rather than queued: what the queue is for is giving the+ * rounds below something to interleave with, and a queue that sometimes+ * holds the header and sometimes does not forces a test before every+ * multiply -- which is what stopped the interleaving from happening at+ * all. See the peeled first group below.+ */+ {+ size_t nfull = aadlen / 16;+ size_t rest = aadlen % 16;++ for (i = 0; i < nfull; i++)+ GHASH_ONE(_mm_shuffle_epi8(+ _mm_loadu_si128((const __m128i *) (aad + i * 16)), BSWAP), 0);+ if (rest)+ GHASH_ONE(_mm_shuffle_epi8(loadn(aad + nfull * 16, rest), BSWAP), 0);+ }++ /* Whole groups of six. The rounds are written out rather than looped:+ * the number of them is a value in the key, so a loop over it leaves the+ * compiler fetching each round key through an index it cannot fold, and+ * the six lanes go to memory with them. Written out, the whole group+ * stays in registers, and the six multiplies of the group before can be+ * placed between the rounds by hand -- which is the stitching: AES-NI+ * and PCLMULQDQ do not contend for the same port, so the multiplies are+ * very nearly free.+ */+ done = 0;+ if (rounds == 10) {+ if (done + 96 <= inlen) {+ const uint8_t *p = in + done;+ uint8_t *q = out + done;++ CTR6(0); CTR6(1); CTR6(2); CTR6(3); CTR6(4); CTR6(5);+ ROUND6(1);+ ROUND6(2);+ ROUND6(3);+ ROUND6(4);+ ROUND6(5);+ ROUND6(6);+ ROUND6(7);+ ROUND6(8);+ ROUND6(9);+ LAST6(10);+ gn = 0; gi = 0; gw = 0;++ b0 = _mm_xor_si128(b0, _mm_loadu_si128((const __m128i *) p));+ b1 = _mm_xor_si128(b1, _mm_loadu_si128((const __m128i *) (p + 16)));+ b2 = _mm_xor_si128(b2, _mm_loadu_si128((const __m128i *) (p + 32)));+ b3 = _mm_xor_si128(b3, _mm_loadu_si128((const __m128i *) (p + 48)));+ b4 = _mm_xor_si128(b4, _mm_loadu_si128((const __m128i *) (p + 64)));+ b5 = _mm_xor_si128(b5, _mm_loadu_si128((const __m128i *) (p + 80)));+ _mm_storeu_si128((__m128i *) q, b0);+ _mm_storeu_si128((__m128i *) (q + 16), b1);+ _mm_storeu_si128((__m128i *) (q + 32), b2);+ _mm_storeu_si128((__m128i *) (q + 48), b3);+ _mm_storeu_si128((__m128i *) (q + 64), b4);+ _mm_storeu_si128((__m128i *) (q + 80), b5);++ done += 96;+ }+ for (; done + 96 <= inlen; done += 96) {+ const uint8_t *p = in + done;+ uint8_t *q = out + done;+ const uint8_t *prev = out + done - 96;++ CTR6(0); CTR6(1); CTR6(2); CTR6(3); CTR6(4); CTR6(5);+ ROUND6(1); GAT(0);+ ROUND6(2); GAT(1);+ ROUND6(3); GAT(2);+ ROUND6(4); GAT(3);+ ROUND6(5); GAT(4);+ ROUND6(6); GAT(5);+ ROUND6(7);+ ROUND6(8);+ ROUND6(9);+ LAST6(10);+ gp -= 6;++ b0 = _mm_xor_si128(b0, _mm_loadu_si128((const __m128i *) p));+ b1 = _mm_xor_si128(b1, _mm_loadu_si128((const __m128i *) (p + 16)));+ b2 = _mm_xor_si128(b2, _mm_loadu_si128((const __m128i *) (p + 32)));+ b3 = _mm_xor_si128(b3, _mm_loadu_si128((const __m128i *) (p + 48)));+ b4 = _mm_xor_si128(b4, _mm_loadu_si128((const __m128i *) (p + 64)));+ b5 = _mm_xor_si128(b5, _mm_loadu_si128((const __m128i *) (p + 80)));+ _mm_storeu_si128((__m128i *) q, b0);+ _mm_storeu_si128((__m128i *) (q + 16), b1);+ _mm_storeu_si128((__m128i *) (q + 32), b2);+ _mm_storeu_si128((__m128i *) (q + 48), b3);+ _mm_storeu_si128((__m128i *) (q + 64), b4);+ _mm_storeu_si128((__m128i *) (q + 80), b5);++ /* straight from the registers the last round left them in: the+ * queue existed only to hold them until the next group's rounds+ * could hide the multiplies, and that is 192 bytes of store and+ * load per 96 bytes of payload */+ }++ } else {+ for (done = 0; done + 96 <= inlen; done += 96) {+ const uint8_t *p = in + done;+ uint8_t *q = out + done;+ int r;++ CTR6(0); CTR6(1); CTR6(2); CTR6(3); CTR6(4); CTR6(5);+ for (r = 1; r < rounds; r++) {+ ROUND6(r);+ GSTEP();+ }+ LAST6(rounds);++ b0 = _mm_xor_si128(b0, _mm_loadu_si128((const __m128i *) p));+ b1 = _mm_xor_si128(b1, _mm_loadu_si128((const __m128i *) (p + 16)));+ b2 = _mm_xor_si128(b2, _mm_loadu_si128((const __m128i *) (p + 32)));+ b3 = _mm_xor_si128(b3, _mm_loadu_si128((const __m128i *) (p + 48)));+ b4 = _mm_xor_si128(b4, _mm_loadu_si128((const __m128i *) (p + 64)));+ b5 = _mm_xor_si128(b5, _mm_loadu_si128((const __m128i *) (p + 80)));+ _mm_storeu_si128((__m128i *) q, b0);+ _mm_storeu_si128((__m128i *) (q + 16), b1);+ _mm_storeu_si128((__m128i *) (q + 32), b2);+ _mm_storeu_si128((__m128i *) (q + 48), b3);+ _mm_storeu_si128((__m128i *) (q + 64), b4);+ _mm_storeu_si128((__m128i *) (q + 80), b5);++ while (gn > 0) GSTEP();+ gi = 0; gw = 0;+ gq[0] = _mm_shuffle_epi8(b0, BSWAP);+ gq[1] = _mm_shuffle_epi8(b1, BSWAP);+ gq[2] = _mm_shuffle_epi8(b2, BSWAP);+ gq[3] = _mm_shuffle_epi8(b3, BSWAP);+ gq[4] = _mm_shuffle_epi8(b4, BSWAP);+ gq[5] = _mm_shuffle_epi8(b5, BSWAP);+ gn = 6;+ }+ }++ /* The tail. The wide pass below runs only when there are blocks for it:+ * sixty AES instructions to fill one lane is not worth it, so a message+ * that ends on a group boundary leaves E(K,Y0) the chain it was given+ * above and takes the mask on one of its own.+ *+ * The spare lane carries the mask only when two things hold. The sample+ * has to lie entirely in output the groups above have already written:+ * this pass reads it while it runs, and the blocks it is itself+ * computing are stored after it, so a sample reaching into them would be+ * read before it exists. And the two key schedules have to have the+ * same number of rounds, because the lanes share the loop that counts+ * them and a shorter schedule would be read past its end. TLS and QUIC+ * satisfy both; anything else gets the mask on a chain of its own, which+ * is what it would have had anyway. */+ {+ __m128i t0, t1, t2, t3, t4, t5;+ __m128i tv[6];+ size_t toff[6];+ int ntail = 0, j;++ if (done >= inlen) goto no_tail;++ for (i = done; i < inlen; i += 16) {+ toff[ntail] = i;+ ctr = _mm_add_epi32(ctr, one32);+ tv[ntail] = _mm_shuffle_epi8(ctr, BSWAP);+ ntail++;+ }++ lane_mask = ntail > 0 && ntail <= 5 && hpkey != 0 && mask != 0+ && hprounds == rounds+ && sampleoff + 16 <= done;++ if (ntail > 0) {+ t0 = tv[0];+ t1 = ntail > 1 ? tv[1] : ctrbase;+ t2 = ntail > 2 ? tv[2] : ctrbase;+ t3 = ntail > 3 ? tv[3] : ctrbase;+ t4 = lane_ek0 ? ctrbase : (ntail > 4 ? tv[4] : ctrbase);+ t5 = lane_mask+ ? _mm_loadu_si128((const __m128i *) (out + sampleoff))+ : (ntail > 5 ? tv[5] : ctrbase);+ /* A group leaves exactly six queued, which is what lets the+ * slots below be named at compile time. Where no group ran+ * there is nothing to place and the plain pass will do. */+ if (rounds == 10 && done >= 96) {+ const uint8_t *prev = out + done - 96;+ WIDE6_10(lane_mask ? hprk : rk);+ } else {+ WIDE6(lane_mask ? hprk : rk);+ }+ if (lane_ek0)+ ek0 = t4;+ else+ tv[4] = t4;+ if (lane_mask)+ _mm_storeu_si128((__m128i *) mask, t5);+ else if (ntail > 5)+ tv[5] = t5;+ }+no_tail:+ while (gn > 0) GSTEP();++ /* The last group's ciphertext is absorbed by the pass above where+ * there is one to absorb it. A message that ends on a group+ * boundary has no such pass, so it is taken here. */+ if (rounds == 10 && done >= 96 && ntail == 0) {+ const uint8_t *prev = out + done - 96;+ GAT(0); GAT(1); GAT(2); GAT(3); GAT(4); GAT(5);+ }++ /*+ * The tail blocks, from the registers the pass left them in. They+ * were going through an array indexed by the loop variable, which+ * the compiler cannot see through and so keeps in memory: every+ * block then reloaded its own keystream. Named one per block and+ * reached by a test on a count instead, they stay where they are.+ */+#define TAILBLK(j, reg) \+ do { \+ size_t off = done + 16 * (j); \+ size_t n = inlen - off < 16 ? inlen - off : 16; \+ __m128i c = _mm_xor_si128(reg, n == 16 \+ ? _mm_loadu_si128((const __m128i *) (in + off)) \+ : loadn(in + off, n)); \+ if (n == 16) { \+ _mm_storeu_si128((__m128i *) (out + off), c); \+ } else { \+ /* the tag goes in directly above, so those bytes are \+ * written over anyway where there are sixteen to spare */ \+ if (n + taglen >= 16) \+ _mm_storeu_si128((__m128i *) (out + off), c); \+ else \+ storen(out + off, c, n); \+ c = clampn(c, n); \+ } \+ GHASH_ONE(_mm_shuffle_epi8(c, BSWAP), gp); \+ gp--; \+ } while (0)++ if (ntail > 0) TAILBLK(0, t0);+ if (ntail > 1) TAILBLK(1, t1);+ if (ntail > 2) TAILBLK(2, t2);+ if (ntail > 3) TAILBLK(3, t3);+ if (ntail > 4) TAILBLK(4, tv[4]);+ if (ntail > 5) TAILBLK(5, tv[5]);+#undef TAILBLK+ }++ {+ /*+ * The length block: the additional data's bit count and the+ * message's, each big endian in a half, and then reversed like+ * every other block on its way to GHASH.+ *+ * Reversed, that block is the two counts as ordinary little endian+ * words with the message's in the low half -- which is one set, and+ * no shuffle. Sixteen byte stores to the stack and a load back is+ * what it cost before.+ */+ GHASH_ONE(_mm_set_epi64x((long long) ((uint64_t) aadlen << 3),+ (long long) ((uint64_t) inlen << 3)), gp);+ }++ tag = _mm_shuffle_epi8(gtag, BSWAP);+ tag = _mm_xor_si128(tag, ek0);+ if (taglen == 16)+ _mm_storeu_si128((__m128i *) (out + inlen), tag);+ else+ storen(out + inlen, tag, taglen);++ /* A sample the pass above could not reach -- because it covered blocks+ * that pass was still computing, or the tag, which is written just now+ * -- is taken here instead, where everything it can cover exists. */+ if (!lane_mask && hpkey != 0 && mask != 0)+ _mm_storeu_si128((__m128i *) mask,+ aes_one_block(hprk, hprounds, _mm_loadu_si128(+ (const __m128i *) (out + sampleoff))));+}+++/*+ * The same for decryption, which is the simpler of the two.+ *+ * What GHASH absorbs here is the ciphertext, and the ciphertext is the+ * input: it is there before any of the AES has run. So there is no queue --+ * the multiplies of a group go between the rounds of that same group rather+ * than waiting for the one after, and nothing is stored and loaded back to+ * carry them across.+ *+ * The tag is compared here, every byte of it whichever way the answer goes,+ * and the answer is 1 for a message whose tag matched.+ */++/* one ciphertext block straight from the input, at a slot named here */+#define DAT(j) GHASH_ONE(_mm_shuffle_epi8( \+ _mm_loadu_si128((const __m128i *) (p + 16 * (j))), BSWAP), 0)++/* the next counter block, into a named register */+#define CTRT(t) \+ do { ctr = _mm_add_epi32(ctr, one32); \+ t = _mm_shuffle_epi8(ctr, BSWAP); } while (0)++TGT int crypton_gcm_fused_decrypt(uint8_t *out, const aes_gcm_fused *fk,+ const aes_key *key, const uint8_t *nonce,+ const uint8_t *aad, size_t aadlen,+ const uint8_t *in, size_t inlen,+ const uint8_t *tag, size_t taglen,+ uint8_t *outtag)+{+ const uint8_t *rk = key->data;+ const int rounds = key->nbr;+ GHASH_DECL;+ __m128i ctrbase, ctr, one32, ek0, want, b0, b1, b2, b3, b4, b5;+ const int ntail_pre = (int) ((inlen % 96 + 15) / 16);+ int lane_ek0, gp = 0;+ const int gtotal = (int) ((aadlen + 15) / 16 + (inlen + 15) / 16 + 1);+ size_t i;+ size_t done;+ uint8_t diff = 0;++ ctrbase = _mm_insert_epi32(loadn(nonce, 12), (int) __builtin_bswap32(1), 3);+ ctr = _mm_shuffle_epi8(ctrbase, BSWAP);+ one32 = _mm_set_epi32(0, 0, 0, 1);++ lane_ek0 = ntail_pre > 0 && ntail_pre <= 5;+ if (!lane_ek0)+ ek0 = aes_one_block(rk, rounds, ctrbase);++ {+ size_t nfull = aadlen / 16;+ size_t rest = aadlen % 16;++ for (i = 0; i < nfull; i++)+ GHASH_ONE(_mm_shuffle_epi8(+ _mm_loadu_si128((const __m128i *) (aad + i * 16)), BSWAP), 0);+ if (rest)+ GHASH_ONE(_mm_shuffle_epi8(loadn(aad + nfull * 16, rest), BSWAP), 0);+ }++ done = 0;+ if (rounds == 10) {+ for (; done + 96 <= inlen; done += 96) {+ const uint8_t *p = in + done;+ uint8_t *q = out + done;++ CTR6(0); CTR6(1); CTR6(2); CTR6(3); CTR6(4); CTR6(5);+ ROUND6(1); DAT(0);+ ROUND6(2); DAT(1);+ ROUND6(3); DAT(2);+ ROUND6(4); DAT(3);+ ROUND6(5); DAT(4);+ ROUND6(6); DAT(5);+ ROUND6(7);+ ROUND6(8);+ ROUND6(9);+ LAST6(10);++ _mm_storeu_si128((__m128i *) q,+ _mm_xor_si128(b0, _mm_loadu_si128((const __m128i *) p)));+ _mm_storeu_si128((__m128i *) (q + 16),+ _mm_xor_si128(b1, _mm_loadu_si128((const __m128i *) (p + 16))));+ _mm_storeu_si128((__m128i *) (q + 32),+ _mm_xor_si128(b2, _mm_loadu_si128((const __m128i *) (p + 32))));+ _mm_storeu_si128((__m128i *) (q + 48),+ _mm_xor_si128(b3, _mm_loadu_si128((const __m128i *) (p + 48))));+ _mm_storeu_si128((__m128i *) (q + 64),+ _mm_xor_si128(b4, _mm_loadu_si128((const __m128i *) (p + 64))));+ _mm_storeu_si128((__m128i *) (q + 80),+ _mm_xor_si128(b5, _mm_loadu_si128((const __m128i *) (p + 80))));+ }+ } else {+ for (; done + 96 <= inlen; done += 96) {+ const uint8_t *p = in + done;+ uint8_t *q = out + done;+ int r;++ CTR6(0); CTR6(1); CTR6(2); CTR6(3); CTR6(4); CTR6(5);+ for (r = 1; r < rounds; r++) {+ ROUND6(r);+ if (r <= 6) DAT(r - 1);+ }+ LAST6(rounds);++ _mm_storeu_si128((__m128i *) q,+ _mm_xor_si128(b0, _mm_loadu_si128((const __m128i *) p)));+ _mm_storeu_si128((__m128i *) (q + 16),+ _mm_xor_si128(b1, _mm_loadu_si128((const __m128i *) (p + 16))));+ _mm_storeu_si128((__m128i *) (q + 32),+ _mm_xor_si128(b2, _mm_loadu_si128((const __m128i *) (p + 32))));+ _mm_storeu_si128((__m128i *) (q + 48),+ _mm_xor_si128(b3, _mm_loadu_si128((const __m128i *) (p + 48))));+ _mm_storeu_si128((__m128i *) (q + 64),+ _mm_xor_si128(b4, _mm_loadu_si128((const __m128i *) (p + 64))));+ _mm_storeu_si128((__m128i *) (q + 80),+ _mm_xor_si128(b5, _mm_loadu_si128((const __m128i *) (p + 80))));+ }+ }++ /* the tail, with E(K,Y0) in a lane the length leaves idle */+ {+ __m128i t0, t1, t2, t3, t4, t5;+ int ntail = (int) ((inlen - done + 15) / 16), j;++ /* the counter is where the groups left it */+ t0 = t1 = t2 = t3 = t4 = t5 = ctrbase;+ if (ntail > 0) CTRT(t0);+ if (ntail > 1) CTRT(t1);+ if (ntail > 2) CTRT(t2);+ if (ntail > 3) CTRT(t3);+ if (ntail > 4) CTRT(t4);+ if (ntail > 5) CTRT(t5);++ if (ntail > 0) {+ WIDE6_NOQ(rk);+ if (lane_ek0) ek0 = t5;+ }++ for (j = 0; j < ntail; j++) {+ size_t off = done + 16 * (size_t) j;+ size_t n = inlen - off < 16 ? inlen - off : 16;+ __m128i c = n == 16 ? _mm_loadu_si128((const __m128i *) (in + off))+ : loadn(in + off, n);+ __m128i ks = j == 0 ? t0 : j == 1 ? t1 : j == 2 ? t2+ : j == 3 ? t3 : j == 4 ? t4 : t5;++ GHASH_ONE(_mm_shuffle_epi8(c, BSWAP), 0);+ {+ __m128i pl = _mm_xor_si128(ks, c);+ if (n == 16)+ _mm_storeu_si128((__m128i *) (out + off), pl);+ else+ storen(out + off, pl, n);+ }+ }+ }++ GHASH_ONE(_mm_set_epi64x((long long) ((uint64_t) aadlen << 3),+ (long long) ((uint64_t) inlen << 3)), gp);++ want = _mm_xor_si128(_mm_shuffle_epi8(gtag, BSWAP), ek0);+ {+ uint8_t got[16];+ _mm_storeu_si128((__m128i *) got, want);+ if (outtag) {+ /* The caller holds the expected tag and will compare it itself. */+ memcpy(outtag, got, taglen);+ return 1;+ }+ for (i = 0; i < taglen; i++)+ diff |= (uint8_t) (got[i] ^ tag[i]);+ }+ return diff == 0;+}++#endif /* WITH_GCM_FUSED */
@@ -0,0 +1,55 @@+/*+ * Copyright (c) 2026 Kazu Yamamoto <kazu@iij.ad.jp>+ *+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ * notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ * notice, this list of conditions and the following disclaimer in the+ * documentation and/or other materials provided with the distribution.+ * 3. Neither the name of the author nor the names of his contributors+ * may be used to endorse or promote products derived from this software+ * without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ * SUCH DAMAGE.+ */++#ifndef CRYPTON_GCM_FUSED_X86_H+#define CRYPTON_GCM_FUSED_X86_H++#include <stdint.h>+#include <stddef.h>+#include <crypton_aes.h>++void crypton_gcm_fused_key_init(aes_gcm_fused *fk, const aes_key *key);++void crypton_gcm_fused_encrypt(uint8_t *out, const aes_gcm_fused *fk,+ const aes_key *key,+ const uint8_t *nonce,+ const uint8_t *aad, size_t aadlen,+ const uint8_t *in, size_t inlen, size_t taglen,+ const aes_key *hpkey, size_t sampleoff,+ uint8_t *mask);++int crypton_gcm_fused_decrypt(uint8_t *out, const aes_gcm_fused *fk,+ const aes_key *key, const uint8_t *nonce,+ const uint8_t *aad, size_t aadlen,+ const uint8_t *in, size_t inlen,+ const uint8_t *tag, size_t taglen,+ uint8_t *outtag);++#endif
@@ -0,0 +1,364 @@+/*+ * AES-GCM through VAES and VPCLMULQDQ in their 512-bit form, which takes+ * four blocks where the 256-bit form in cbits/aes/gcm_vaes_x86.c takes two+ * and the 128-bit one takes one. The instruction rate is the same, so the+ * work per group halves again.+ *+ * This is that file widened and nothing else: the same group of sixteen+ * blocks, the same descending powers of H sharing one reduction, the same+ * round keys read from memory rather than held in registers. Four blocks to+ * a register means the group fills four of them rather than eight, which is+ * what leaves room for the group's own ciphertext to be kept for the GHASH+ * when encrypting.+ *+ * Nothing here is borrowed. OpenSSL's and BoringSSL's AVX-512 AES-GCM is+ * Apache-2.0 and s2n-bignum has no GCM at all.+ *+ * The reduction at the end is a copy of the one in gcm_vaes_x86.c rather+ * than a call to it: the two files are compiled for different instruction+ * sets, and a function compiled for one cannot be inlined into the other.+ */+#include "aes/gcm_vaes512_x86.h"++#ifdef WITH_GCM_VAES512++#include <string.h>+#include <immintrin.h>++#include <aes/gf.h>+#include <aes/block128.h>++#if defined(__clang__) || defined(__GNUC__)+#define V512_TARGET \+ __attribute__((target("avx512f,avx512bw,avx512vl,aes,pclmul,vaes,vpclmulqdq")))+#else+#define V512_TARGET+#endif++/*+ * Thirty-two blocks to a group, four to a register, so eight registers are+ * in flight. The number of registers is what matters as much as the blocks+ * per instruction: AES-NI has a latency of four cycles against a throughput+ * of one, so it takes eight independent chains to keep two ports busy. Four+ * registers of four blocks was written first and measured *slower* than the+ * 256-bit path -- the blocks per instruction had doubled and the chains had+ * halved.+ *+ * The table holds sixteen powers of H, so the GHASH of a group is two passes+ * of sixteen blocks, the second picking up the tag the first leaves.+ */+#define V512WIDE 8+#define V512HALF 4+#define V512BYTES 512++/*+ * The 128-bit multiply of cbits/aes/x86ni.c, done in all four lanes at once.+ * Every shuffle and shift here works inside its own 128-bit lane, so the+ * four products never mix: what comes out is four independent carry-less+ * products, accumulated by the caller and reduced together at the end.+ */+V512_TARGET+static inline void clmul512(__m512i a, __m512i b, __m512i *lo, __m512i *hi)+{+ const __m512i bswap = _mm512_set4_epi32(+ 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f);+ __m512i t3, t4, t5, t6;++ a = _mm512_shuffle_epi8(a, bswap);++ /* Karatsuba, as in the 128-bit one: three multiplies, not four */+ t3 = _mm512_clmulepi64_epi128(a, b, 0x00);+ t6 = _mm512_clmulepi64_epi128(a, b, 0x11);+ t4 = _mm512_clmulepi64_epi128(+ _mm512_xor_si512(a, _mm512_shuffle_epi32(a, _MM_PERM_BADC)),+ _mm512_xor_si512(b, _mm512_shuffle_epi32(b, _MM_PERM_BADC)),+ 0x00);+ t4 = _mm512_xor_si512(t4, _mm512_xor_si512(t3, t6));++ t5 = _mm512_bslli_epi128(t4, 8);+ t4 = _mm512_bsrli_epi128(t4, 8);++ *lo = _mm512_xor_si512(t3, t5);+ *hi = _mm512_xor_si512(t6, t4);+}++/*+ * The reduction of cbits/aes/x86ni.c. By the time it runs the four lanes+ * have been folded into one, so there is one 256-bit product to reduce.+ */+V512_TARGET+static inline __m128i gfred512(__m128i t3, __m128i t6)+{+ const __m128i bswap = _mm_set_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);+ __m128i t2, t4, t5, t7, t8, t9;++ t7 = _mm_srli_epi32(t3, 31);+ t8 = _mm_srli_epi32(t6, 31);+ t3 = _mm_slli_epi32(t3, 1);+ t6 = _mm_slli_epi32(t6, 1);++ t9 = _mm_srli_si128(t7, 12);+ t8 = _mm_slli_si128(t8, 4);+ t7 = _mm_slli_si128(t7, 4);+ t3 = _mm_or_si128(t3, t7);+ t6 = _mm_or_si128(t6, t8);+ t6 = _mm_or_si128(t6, t9);++ t7 = _mm_slli_epi32(t3, 31);+ t8 = _mm_slli_epi32(t3, 30);+ t9 = _mm_slli_epi32(t3, 25);++ t7 = _mm_xor_si128(t7, t8);+ t7 = _mm_xor_si128(t7, t9);+ t8 = _mm_srli_si128(t7, 4);+ t7 = _mm_slli_si128(t7, 12);+ t3 = _mm_xor_si128(t3, t7);++ t2 = _mm_srli_epi32(t3, 1);+ t4 = _mm_srli_epi32(t3, 2);+ t5 = _mm_srli_epi32(t3, 7);+ t2 = _mm_xor_si128(t2, t4);+ t2 = _mm_xor_si128(t2, t5);+ t2 = _mm_xor_si128(t2, t8);+ t3 = _mm_xor_si128(t3, t2);+ t6 = _mm_xor_si128(t6, t3);++ return _mm_shuffle_epi8(t6, bswap);+}++/* the four 128-bit lanes of a register added together */+V512_TARGET+static inline __m128i fold512(__m512i v)+{+ __m256i h = _mm256_xor_si256(_mm512_castsi512_si256(v),+ _mm512_extracti64x4_epi64(v, 1));++ return _mm_xor_si128(_mm256_castsi256_si128(h),+ _mm256_extracti128_si256(h, 1));+}++/*+ * Sixteen blocks against H^16 .. H^1, one reduction. v[j] holds blocks 4j+ * to 4j+3 in its four lanes, so the powers for it are H^(16-4j) down to+ * H^(13-4j) -- the table's own order the other way round, hence the four+ * 128-bit loads rather than one 512-bit one.+ */+V512_TARGET+static inline __m128i ghash16(__m128i tag, const table_4bit htable,+ const __m512i *v, int fromwire)+{+ __m512i lo = _mm512_setzero_si512(), hi = _mm512_setzero_si512();+ __m512i l, h, b;+ int j;++ for (j = 0; j < V512HALF; j++) {+ const __m128i p0 =+ _mm_loadu_si128((const __m128i *) &htable[15 - 4 * j]);+ const __m128i p1 =+ _mm_loadu_si128((const __m128i *) &htable[14 - 4 * j]);+ const __m128i p2 =+ _mm_loadu_si128((const __m128i *) &htable[13 - 4 * j]);+ const __m128i p3 =+ _mm_loadu_si128((const __m128i *) &htable[12 - 4 * j]);+ __m512i hp = _mm512_castsi128_si512(p0);++ hp = _mm512_inserti32x4(hp, p1, 1);+ hp = _mm512_inserti32x4(hp, p2, 2);+ hp = _mm512_inserti32x4(hp, p3, 3);++ b = fromwire ? _mm512_loadu_si512(v + j) : v[j];+ if (j == 0) /* the running tag joins the first block */+ b = _mm512_xor_si512(+ b, _mm512_inserti32x4(+ _mm512_setzero_si512(), tag, 0));+ clmul512(b, hp, &l, &h);+ lo = _mm512_xor_si512(lo, l);+ hi = _mm512_xor_si512(hi, h);+ }++ /* the four lanes are independent products of the same sum: fold them */+ return gfred512(fold512(lo), fold512(hi));+}++#define KK512(r) _mm512_broadcast_i32x4(_mm_loadu_si128(k_ + (r)))++#define AESENC32(K) \+ do { \+ const __m512i rk = (K); \+ v[0] = _mm512_aesenc_epi128(v[0], rk); \+ v[1] = _mm512_aesenc_epi128(v[1], rk); \+ v[2] = _mm512_aesenc_epi128(v[2], rk); \+ v[3] = _mm512_aesenc_epi128(v[3], rk); \+ v[4] = _mm512_aesenc_epi128(v[4], rk); \+ v[5] = _mm512_aesenc_epi128(v[5], rk); \+ v[6] = _mm512_aesenc_epi128(v[6], rk); \+ v[7] = _mm512_aesenc_epi128(v[7], rk); \+ } while (0)++#define AESLAST32(K) \+ do { \+ const __m512i rk = (K); \+ v[0] = _mm512_aesenclast_epi128(v[0], rk); \+ v[1] = _mm512_aesenclast_epi128(v[1], rk); \+ v[2] = _mm512_aesenclast_epi128(v[2], rk); \+ v[3] = _mm512_aesenclast_epi128(v[3], rk); \+ v[4] = _mm512_aesenclast_epi128(v[4], rk); \+ v[5] = _mm512_aesenclast_epi128(v[5], rk); \+ v[6] = _mm512_aesenclast_epi128(v[6], rk); \+ v[7] = _mm512_aesenclast_epi128(v[7], rk); \+ } while (0)++#define XOR32(K) \+ do { \+ const __m512i rk = (K); \+ v[0] = _mm512_xor_si512(v[0], rk); \+ v[1] = _mm512_xor_si512(v[1], rk); \+ v[2] = _mm512_xor_si512(v[2], rk); \+ v[3] = _mm512_xor_si512(v[3], rk); \+ v[4] = _mm512_xor_si512(v[4], rk); \+ v[5] = _mm512_xor_si512(v[5], rk); \+ v[6] = _mm512_xor_si512(v[6], rk); \+ v[7] = _mm512_xor_si512(v[7], rk); \+ } while (0)++/*+ * The rounds are written out rather than looped for the reason the 128-bit+ * loop gives: the count is a value in the key, and a loop over it leaves the+ * round key reached through an index the compiler cannot fold.+ */+V512_TARGET+static inline __attribute__((always_inline)) void+rounds32(__m512i *v, const uint8_t *k, const int nbr)+{+ const __m128i *k_ = (const __m128i *) k;++ XOR32(KK512(0));+ AESENC32(KK512(1)); AESENC32(KK512(2)); AESENC32(KK512(3));+ AESENC32(KK512(4)); AESENC32(KK512(5)); AESENC32(KK512(6));+ AESENC32(KK512(7)); AESENC32(KK512(8)); AESENC32(KK512(9));+ if (nbr > 10) {+ AESENC32(KK512(10)); AESENC32(KK512(11));+ if (nbr > 12) {+ AESENC32(KK512(12)); AESENC32(KK512(13));+ }+ }+ AESLAST32(_mm512_broadcast_i32x4(_mm_loadu_si128(k_ + nbr)));+}++/* sixteen consecutive counters, four to a register. GCM counts in the low+ * thirty-two bits and wraps there, which is what _mm_add_epi32 does. */+V512_TARGET+static inline __m128i counters32(__m512i *v, __m128i iv, __m128i one,+ __m128i bswap)+{+ int j;++ for (j = 0; j < V512WIDE; j++) {+ __m128i c0, c1, c2, c3;+ __m512i c;++ iv = _mm_add_epi32(iv, one);+ c0 = _mm_shuffle_epi8(iv, bswap);+ iv = _mm_add_epi32(iv, one);+ c1 = _mm_shuffle_epi8(iv, bswap);+ iv = _mm_add_epi32(iv, one);+ c2 = _mm_shuffle_epi8(iv, bswap);+ iv = _mm_add_epi32(iv, one);+ c3 = _mm_shuffle_epi8(iv, bswap);++ c = _mm512_castsi128_si512(c0);+ c = _mm512_inserti32x4(c, c1, 1);+ c = _mm512_inserti32x4(c, c2, 2);+ c = _mm512_inserti32x4(c, c3, 3);+ v[j] = c;+ }+ return iv;+}++/*+ * Inlined into three callers with the round count a constant in each, which+ * folds away the tests inside the group loop -- the same reason the 256-bit+ * file gives, where without it AES-256 lost what AES-128 gained.+ */+V512_TARGET+static inline __attribute__((always_inline)) uint32_t+bulk_n(uint8_t *output, aes_gcm *gcm, const aes_key *key,+ const uint8_t *input, uint32_t length, int decrypt, const int nbr)+{+ const __m128i bswap = _mm_setr_epi8(7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8);+ const __m128i one = _mm_set_epi32(0, 1, 0, 0);+ __m512i v[V512WIDE];+ __m128i iv, tag;+ uint32_t groups = length / V512BYTES;+ uint32_t done = 0;+ uint32_t g;+ int j;++ if (groups == 0)+ return 0;++ iv = _mm_shuffle_epi8(_mm_loadu_si128((const __m128i *) &gcm->civ), bswap);+ tag = _mm_loadu_si128((const __m128i *) &gcm->tag);++ for (g = 0; g < groups; g++, input += V512BYTES, output += V512BYTES,+ done += V512BYTES) {+ iv = counters32(v, iv, one, bswap);+ rounds32(v, key->data, nbr);++ for (j = 0; j < V512WIDE; j++) {+ const __m512i in =+ _mm512_loadu_si512((const __m512i *) (input + 64 * j));++ v[j] = _mm512_xor_si512(v[j], in);+ _mm512_storeu_si512((__m512i *) (output + 64 * j), v[j]);+ }+ /* sixteen blocks to a pass, since that is how many powers of+ * H the table holds; the second picks up the tag the first+ * leaves */+ tag = ghash16(tag, gcm->htable,+ decrypt ? (const __m512i *) input : v,+ decrypt);+ tag = ghash16(tag, gcm->htable,+ decrypt ? (const __m512i *) (input + 256)+ : v + V512HALF,+ decrypt);+ }++ _mm_storeu_si128((__m128i *) &gcm->civ, _mm_shuffle_epi8(iv, bswap));+ _mm_storeu_si128((__m128i *) &gcm->tag, tag);+ return done;+}++V512_TARGET+static uint32_t bulk(uint8_t *output, aes_gcm *gcm, const aes_key *key,+ const uint8_t *input, uint32_t length, int decrypt)+{+ switch (key->nbr) {+ case 10:+ return bulk_n(output, gcm, key, input, length, decrypt, 10);+ case 12:+ return bulk_n(output, gcm, key, input, length, decrypt, 12);+ case 14:+ return bulk_n(output, gcm, key, input, length, decrypt, 14);+ default:+ return 0; /* not a key length AES has */+ }+}++uint32_t crypton_gcm_vaes512_bulk_encrypt(uint8_t *output, aes_gcm *gcm,+ const aes_key *key,+ const uint8_t *input,+ uint32_t length)+{+ return bulk(output, gcm, key, input, length, 0);+}++uint32_t crypton_gcm_vaes512_bulk_decrypt(uint8_t *output, aes_gcm *gcm,+ const aes_key *key,+ const uint8_t *input,+ uint32_t length)+{+ return bulk(output, gcm, key, input, length, 1);+}++#endif
@@ -0,0 +1,37 @@+/*+ * AES-GCM in the 512-bit form of the AES and carry-less multiply+ * instructions, which do four blocks where the 128-bit ones do one and the+ * 256-bit ones in cbits/aes/gcm_vaes_x86.c do two.+ */+#ifndef CRYPTON_GCM_VAES512_X86_H+#define CRYPTON_GCM_VAES512_X86_H++#include <crypton_cpu.h>++#if defined(ARCH_X86) && defined(__x86_64__) && defined(WITH_AESNI) \+ && defined(WITH_PCLMUL)+#define WITH_GCM_VAES512+#endif++#ifdef WITH_GCM_VAES512++#include <stdint.h>+#include <crypton_aes.h>++/* The same contract as the 256-bit pair: whole groups off the front, the+ * counter left in gcm->civ and the running tag in gcm->tag, and the number+ * of bytes taken returned, a multiple of 512 and possibly zero. */+uint32_t crypton_gcm_vaes512_bulk_encrypt(uint8_t *output, aes_gcm *gcm,+ const aes_key *key,+ const uint8_t *input,+ uint32_t length);+uint32_t crypton_gcm_vaes512_bulk_decrypt(uint8_t *output, aes_gcm *gcm,+ const aes_key *key,+ const uint8_t *input,+ uint32_t length);++/* Thirty-two blocks is the least it will start on. */+#define GCM_VAES512_MIN_BLOCKS 32++#endif+#endif
@@ -0,0 +1,325 @@+/*+ * AES-GCM through VAES and VPCLMULQDQ: the same AES and carry-less multiply+ * instructions the rest of this directory uses, in their 256-bit form, which+ * takes two blocks where the 128-bit form takes one. The instruction rate is+ * the same, so the throughput is twice -- measured at 2.00 on an EPYC 9V74,+ * for both halves, with nothing else in the loop.+ *+ * Nothing here is borrowed. OpenSSL's and BoringSSL's wide AES-GCM is+ * Apache-2.0, s2n-bignum has no GCM at all, and the CRYPTOGAMS assembly in+ * cbits/asm is 128-bit throughout -- its `vaesenc` is the VEX encoding of+ * AESENC on XMM, not the VAES extension. So this is the 128-bit loop in+ * cbits/aes/x86ni_impl.c widened, and it keeps that loop's shape: a group of+ * counters through the rounds together, the round keys read from memory+ * rather than held in registers, and the group's GHASH folded against+ * descending powers of H so that sixteen blocks share one reduction.+ *+ * The powers come from the table crypton_aesni_hinit_pclmul fills. It has+ * sixteen slots and the 128-bit loop uses eight of them; this uses all+ * sixteen, which is why that function now fills them.+ */+#include "aes/gcm_vaes_x86.h"++#ifdef WITH_GCM_VAES++#include <string.h>+#include <immintrin.h>++#include <aes/gf.h>+#include <aes/block128.h>++#if defined(__clang__) || defined(__GNUC__)+#define VAES_TARGET __attribute__((target("avx2,aes,pclmul,vaes,vpclmulqdq")))+#else+#define VAES_TARGET+#endif++/* sixteen blocks to a group, two to a register */+#define VWIDE 8++/*+ * The 128-bit multiply of cbits/aes/x86ni.c, done in both lanes at once.+ * Every shuffle and shift here works inside its own 128-bit half, so the two+ * products never mix: what comes out is two independent carry-less products,+ * accumulated by the caller and reduced together at the end.+ */+VAES_TARGET+static inline void clmul256(__m256i a, __m256i b, __m256i *lo, __m256i *hi)+{+ const __m256i bswap = _mm256_setr_epi8(+ 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,+ 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0);+ __m256i t3, t4, t5, t6;++ a = _mm256_shuffle_epi8(a, bswap);++ /* Karatsuba, as in the 128-bit one: three multiplies, not four */+ t3 = _mm256_clmulepi64_epi128(a, b, 0x00);+ t6 = _mm256_clmulepi64_epi128(a, b, 0x11);+ t4 = _mm256_clmulepi64_epi128(+ _mm256_xor_si256(a, _mm256_shuffle_epi32(a, 0x4e)),+ _mm256_xor_si256(b, _mm256_shuffle_epi32(b, 0x4e)), 0x00);+ t4 = _mm256_xor_si256(t4, _mm256_xor_si256(t3, t6));++ t5 = _mm256_slli_si256(t4, 8);+ t4 = _mm256_srli_si256(t4, 8);++ *lo = _mm256_xor_si256(t3, t5);+ *hi = _mm256_xor_si256(t6, t4);+}++/*+ * The reduction of cbits/aes/x86ni.c, unchanged: by the time it runs the two+ * lanes have been folded into one, so there is one 256-bit product to reduce+ * and no reason to do it twice.+ */+VAES_TARGET+static inline __m128i gfred(__m128i t3, __m128i t6)+{+ const __m128i bswap = _mm_set_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);+ __m128i t2, t4, t5, t7, t8, t9;++ t7 = _mm_srli_epi32(t3, 31);+ t8 = _mm_srli_epi32(t6, 31);+ t3 = _mm_slli_epi32(t3, 1);+ t6 = _mm_slli_epi32(t6, 1);++ t9 = _mm_srli_si128(t7, 12);+ t8 = _mm_slli_si128(t8, 4);+ t7 = _mm_slli_si128(t7, 4);+ t3 = _mm_or_si128(t3, t7);+ t6 = _mm_or_si128(t6, t8);+ t6 = _mm_or_si128(t6, t9);++ t7 = _mm_slli_epi32(t3, 31);+ t8 = _mm_slli_epi32(t3, 30);+ t9 = _mm_slli_epi32(t3, 25);++ t7 = _mm_xor_si128(t7, t8);+ t7 = _mm_xor_si128(t7, t9);+ t8 = _mm_srli_si128(t7, 4);+ t7 = _mm_slli_si128(t7, 12);+ t3 = _mm_xor_si128(t3, t7);++ t2 = _mm_srli_epi32(t3, 1);+ t4 = _mm_srli_epi32(t3, 2);+ t5 = _mm_srli_epi32(t3, 7);+ t2 = _mm_xor_si128(t2, t4);+ t2 = _mm_xor_si128(t2, t5);+ t2 = _mm_xor_si128(t2, t8);+ t3 = _mm_xor_si128(t3, t2);+ t6 = _mm_xor_si128(t6, t3);++ return _mm_shuffle_epi8(t6, bswap);+}++/*+ * Sixteen blocks against H^16 .. H^1, one reduction. v[j] holds blocks 2j+ * and 2j+1 in its low and high halves, so the powers for it are H^(16-2j)+ * low and H^(15-2j) high -- the table's own order the other way round, hence+ * the pair of 128-bit loads rather than one 256-bit one.+ */+VAES_TARGET+static inline __m128i ghash16(__m128i tag, const table_4bit htable,+ const __m256i *v, int fromwire)+{+ __m256i lo = _mm256_setzero_si256(), hi = _mm256_setzero_si256();+ __m256i l, h, b;+ int j;++ for (j = 0; j < VWIDE; j++) {+ const __m256i hp = _mm256_set_m128i(+ _mm_loadu_si128((const __m128i *) &htable[14 - 2 * j]),+ _mm_loadu_si128((const __m128i *) &htable[15 - 2 * j]));++ b = fromwire ? _mm256_loadu_si256(v + j) : v[j];+ if (j == 0) /* the running tag joins the first block */+ b = _mm256_xor_si256(+ b, _mm256_inserti128_si256(+ _mm256_setzero_si256(), tag, 0));+ clmul256(b, hp, &l, &h);+ lo = _mm256_xor_si256(lo, l);+ hi = _mm256_xor_si256(hi, h);+ }++ /* the two lanes are independent products of the same sum: fold them */+ return gfred(_mm_xor_si128(_mm256_castsi256_si128(lo),+ _mm256_extracti128_si256(lo, 1)),+ _mm_xor_si128(_mm256_castsi256_si128(hi),+ _mm256_extracti128_si256(hi, 1)));+}++#define KK(r) _mm256_broadcastsi128_si256(_mm_loadu_si128(k_ + (r)))++#define AESENC16(K) \+ do { \+ const __m256i rk = (K); \+ v[0] = _mm256_aesenc_epi128(v[0], rk); \+ v[1] = _mm256_aesenc_epi128(v[1], rk); \+ v[2] = _mm256_aesenc_epi128(v[2], rk); \+ v[3] = _mm256_aesenc_epi128(v[3], rk); \+ v[4] = _mm256_aesenc_epi128(v[4], rk); \+ v[5] = _mm256_aesenc_epi128(v[5], rk); \+ v[6] = _mm256_aesenc_epi128(v[6], rk); \+ v[7] = _mm256_aesenc_epi128(v[7], rk); \+ } while (0)++#define AESLAST16(K) \+ do { \+ const __m256i rk = (K); \+ v[0] = _mm256_aesenclast_epi128(v[0], rk); \+ v[1] = _mm256_aesenclast_epi128(v[1], rk); \+ v[2] = _mm256_aesenclast_epi128(v[2], rk); \+ v[3] = _mm256_aesenclast_epi128(v[3], rk); \+ v[4] = _mm256_aesenclast_epi128(v[4], rk); \+ v[5] = _mm256_aesenclast_epi128(v[5], rk); \+ v[6] = _mm256_aesenclast_epi128(v[6], rk); \+ v[7] = _mm256_aesenclast_epi128(v[7], rk); \+ } while (0)++#define XOR16(K) \+ do { \+ const __m256i rk = (K); \+ v[0] = _mm256_xor_si256(v[0], rk); \+ v[1] = _mm256_xor_si256(v[1], rk); \+ v[2] = _mm256_xor_si256(v[2], rk); \+ v[3] = _mm256_xor_si256(v[3], rk); \+ v[4] = _mm256_xor_si256(v[4], rk); \+ v[5] = _mm256_xor_si256(v[5], rk); \+ v[6] = _mm256_xor_si256(v[6], rk); \+ v[7] = _mm256_xor_si256(v[7], rk); \+ } while (0)++/*+ * The rounds are written out rather than looped for the reason the 128-bit+ * loop gives: the count is a value in the key, and a loop over it leaves the+ * round key reached through an index the compiler cannot fold.+ */+VAES_TARGET+static inline __attribute__((always_inline)) void+rounds16(__m256i *v, const uint8_t *k, const int nbr)+{+ const __m128i *k_ = (const __m128i *) k;++ XOR16(KK(0));+ AESENC16(KK(1)); AESENC16(KK(2)); AESENC16(KK(3));+ AESENC16(KK(4)); AESENC16(KK(5)); AESENC16(KK(6));+ AESENC16(KK(7)); AESENC16(KK(8)); AESENC16(KK(9));+ if (nbr > 10) {+ AESENC16(KK(10)); AESENC16(KK(11));+ if (nbr > 12) {+ AESENC16(KK(12)); AESENC16(KK(13));+ }+ }+ AESLAST16(_mm256_broadcastsi128_si256(_mm_loadu_si128(k_ + nbr)));+}++/* sixteen consecutive counters, two to a register. GCM counts in the low+ * thirty-two bits and wraps there, which is what _mm_add_epi32 does. */+VAES_TARGET+static inline __m128i counters16(__m256i *v, __m128i iv, __m128i one,+ __m128i bswap)+{+ int j;++ for (j = 0; j < VWIDE; j++) {+ __m128i c0, c1;++ iv = _mm_add_epi32(iv, one);+ c0 = _mm_shuffle_epi8(iv, bswap);+ iv = _mm_add_epi32(iv, one);+ c1 = _mm_shuffle_epi8(iv, bswap);+ v[j] = _mm256_set_m128i(c1, c0);+ }+ return iv;+}++/*+ * The round count is a value in the key, and a test on it inside the group+ * loop is a branch the 128-bit path does not have: that one compiles a+ * separate function for each key length through the SIZED macro. This does+ * the same thing by being inlined into three callers with the count a+ * constant in each, which folds the tests away. Without it AES-256 lost+ * what AES-128 gained.+ */+VAES_TARGET+static inline __attribute__((always_inline)) uint32_t+bulk_n(uint8_t *output, aes_gcm *gcm, const aes_key *key,+ const uint8_t *input, uint32_t length, int decrypt, const int nbr)+{+ const __m128i bswap = _mm_setr_epi8(7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8);+ const __m128i one = _mm_set_epi32(0, 1, 0, 0);+ __m256i v[VWIDE];+ __m128i iv, tag;+ uint32_t groups = length / 256;+ uint32_t done = 0;+ uint32_t g;+ int j;++ if (groups == 0)+ return 0;++ iv = _mm_shuffle_epi8(_mm_loadu_si128((const __m128i *) &gcm->civ), bswap);+ tag = _mm_loadu_si128((const __m128i *) &gcm->tag);++ for (g = 0; g < groups; g++, input += 256, output += 256, done += 256) {+ iv = counters16(v, iv, one, bswap);+ rounds16(v, key->data, nbr);++ /*+ * The ciphertext is what the tag is taken over, and after+ * this exclusive or it is in v itself when encrypting. When+ * decrypting it is the input, which the GHASH below reads+ * again rather than keeping: there are sixteen vector+ * registers, the group fills eight of them, and a second+ * eight held aside is what makes the compiler spill. The+ * input is in L1 from the load a moment ago.+ */+ for (j = 0; j < VWIDE; j++) {+ const __m256i in =+ _mm256_loadu_si256((const __m256i *) (input + 32 * j));++ v[j] = _mm256_xor_si256(v[j], in);+ _mm256_storeu_si256((__m256i *) (output + 32 * j), v[j]);+ }+ tag = ghash16(tag, gcm->htable,+ decrypt ? (const __m256i *) input : v,+ decrypt);+ }++ _mm_storeu_si128((__m128i *) &gcm->civ, _mm_shuffle_epi8(iv, bswap));+ _mm_storeu_si128((__m128i *) &gcm->tag, tag);+ return done;+}++VAES_TARGET+static uint32_t bulk(uint8_t *output, aes_gcm *gcm, const aes_key *key,+ const uint8_t *input, uint32_t length, int decrypt)+{+ switch (key->nbr) {+ case 10:+ return bulk_n(output, gcm, key, input, length, decrypt, 10);+ case 12:+ return bulk_n(output, gcm, key, input, length, decrypt, 12);+ case 14:+ return bulk_n(output, gcm, key, input, length, decrypt, 14);+ default:+ return 0; /* not a key length AES has */+ }+}++uint32_t crypton_gcm_vaes_bulk_encrypt(uint8_t *output, aes_gcm *gcm,+ const aes_key *key,+ const uint8_t *input, uint32_t length)+{+ return bulk(output, gcm, key, input, length, 0);+}++uint32_t crypton_gcm_vaes_bulk_decrypt(uint8_t *output, aes_gcm *gcm,+ const aes_key *key,+ const uint8_t *input, uint32_t length)+{+ return bulk(output, gcm, key, input, length, 1);+}++#endif
@@ -0,0 +1,35 @@+/*+ * AES-GCM in the 256-bit form of the AES and carry-less multiply+ * instructions, which do two blocks where the 128-bit ones do one.+ */+#ifndef CRYPTON_GCM_VAES_X86_H+#define CRYPTON_GCM_VAES_X86_H++#include <crypton_cpu.h>++#if defined(ARCH_X86) && defined(__x86_64__) && defined(WITH_AESNI) \+ && defined(WITH_PCLMUL)+#define WITH_GCM_VAES+#endif++#ifdef WITH_GCM_VAES++#include <stdint.h>+#include <crypton_aes.h>++/* The bulk of a message in whole groups of sixteen blocks, leaving the+ * counter in gcm->civ and the running tag in gcm->tag where the caller's own+ * loop expects to find them. Returns the number of bytes taken, which is a+ * multiple of 256 and may be zero. */+uint32_t crypton_gcm_vaes_bulk_encrypt(uint8_t *output, aes_gcm *gcm,+ const aes_key *key,+ const uint8_t *input, uint32_t length);+uint32_t crypton_gcm_vaes_bulk_decrypt(uint8_t *output, aes_gcm *gcm,+ const aes_key *key,+ const uint8_t *input, uint32_t length);++/* Sixteen blocks is the least it will start on. */+#define GCM_VAES_MIN_BLOCKS 16++#endif+#endif
@@ -92,19 +92,29 @@ * H, and every power of it, is kept shifted up by one bit: GCM numbers the * bits of a field element the other way round from the way the carry-less * multiply does, and pre-shifting the operand is what saves the correction- * after each multiply. The bit that falls off the top is the one that the- * polynomial reduces.+ * after each multiply.+ *+ * Written from the definition. The field is GF(2)[x] modulo x^128 + x^127 ++ * x^126 + x^121 + 1, so multiplying by x is a shift of one place, and the+ * term that leaves the top comes back as the other four. */ TARGET_PCLMUL static __m128i twist(__m128i h) {+ /* x^127 + x^126 + x^121 + 1, the terms x^128 is congruent to */ const __m128i poly = _mm_set_epi64x(0xc200000000000000ULL, 1);- __m128i carried = _mm_slli_si128(_mm_srli_epi64(h, 63), 8);- __m128i top = _mm_shuffle_epi32(h, 0xff);- __m128i reduce = _mm_cmpgt_epi32(_mm_setzero_si128(), top);+ /* the top bit of each half */+ __m128i tops = _mm_srli_epi64(h, 63);+ /* doubling a polynomial is a shift by one: each half doubles, and the+ * low half's top bit becomes the high half's bottom bit */+ __m128i doubled = _mm_or_si128(_mm_add_epi64(h, h),+ _mm_slli_si128(tops, 8));+ /* bit 127 is the one that leaves the field; spread it to a mask by+ * subtracting it from zero, and it brings the four terms back */+ __m128i mask = _mm_sub_epi64(_mm_setzero_si128(),+ _mm_unpackhi_epi64(tops, tops)); - h = _mm_or_si128(_mm_slli_epi64(h, 1), carried);- return _mm_xor_si128(h, _mm_and_si128(reduce, poly));+ return _mm_xor_si128(doubled, _mm_and_si128(mask, poly)); } /* the two halves of a value added together, which is the term Karatsuba
@@ -27,420 +27,191 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *- * AES implementation+ * AES, portable, for machines whose processor has no AES instructions or+ * whose build was not given them.+ *+ * This was a table-driven implementation: an S-box indexed by a byte of the+ * state, in every round and in the key expansion, which is what made it fast+ * and what made it variable-time. It is now BearSSL's bitsliced aes_ct64,+ * which holds four blocks interleaved across eight 64-bit words and computes+ * the S-box as boolean algebra -- no table, and so no address derived from a+ * secret. See cbits/bearssl/README.md.+ *+ * What is here is only the glue. Nothing in this file branches or indexes on+ * the key or the data. */ #include <stdint.h>-#include <stdlib.h>+#include <string.h> #include <crypton_aes.h>-#include <crypton_bitfn.h>--static uint8_t sbox[256] = {- 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe,- 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4,- 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7,- 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3,- 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09,- 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3,- 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe,- 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,- 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92,- 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c,- 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,- 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,- 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2,- 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5,- 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25,- 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,- 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86,- 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e,- 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42,- 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16-};--static uint8_t rsbox[256] = {- 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81,- 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e,- 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23,- 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66,- 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72,- 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65,- 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46,- 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,- 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca,- 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91,- 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6,- 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,- 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f,- 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2,- 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8,- 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,- 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93,- 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb,- 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6,- 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d-};--static uint8_t Rcon[] = {- 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,- 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,- 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,- 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,-};+#include "bearssl/inner.h"+#include "aes/block128.h"+#include "aes/generic.h" -#define G(a,b,c,d,e,f) { a,b,c,d,e,f }-static uint8_t gmtab[256][6] =-{- G(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), G(0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e),- G(0x04, 0x06, 0x12, 0x16, 0x1a, 0x1c), G(0x06, 0x05, 0x1b, 0x1d, 0x17, 0x12),- G(0x08, 0x0c, 0x24, 0x2c, 0x34, 0x38), G(0x0a, 0x0f, 0x2d, 0x27, 0x39, 0x36),- G(0x0c, 0x0a, 0x36, 0x3a, 0x2e, 0x24), G(0x0e, 0x09, 0x3f, 0x31, 0x23, 0x2a),- G(0x10, 0x18, 0x48, 0x58, 0x68, 0x70), G(0x12, 0x1b, 0x41, 0x53, 0x65, 0x7e),- G(0x14, 0x1e, 0x5a, 0x4e, 0x72, 0x6c), G(0x16, 0x1d, 0x53, 0x45, 0x7f, 0x62),- G(0x18, 0x14, 0x6c, 0x74, 0x5c, 0x48), G(0x1a, 0x17, 0x65, 0x7f, 0x51, 0x46),- G(0x1c, 0x12, 0x7e, 0x62, 0x46, 0x54), G(0x1e, 0x11, 0x77, 0x69, 0x4b, 0x5a),- G(0x20, 0x30, 0x90, 0xb0, 0xd0, 0xe0), G(0x22, 0x33, 0x99, 0xbb, 0xdd, 0xee),- G(0x24, 0x36, 0x82, 0xa6, 0xca, 0xfc), G(0x26, 0x35, 0x8b, 0xad, 0xc7, 0xf2),- G(0x28, 0x3c, 0xb4, 0x9c, 0xe4, 0xd8), G(0x2a, 0x3f, 0xbd, 0x97, 0xe9, 0xd6),- G(0x2c, 0x3a, 0xa6, 0x8a, 0xfe, 0xc4), G(0x2e, 0x39, 0xaf, 0x81, 0xf3, 0xca),- G(0x30, 0x28, 0xd8, 0xe8, 0xb8, 0x90), G(0x32, 0x2b, 0xd1, 0xe3, 0xb5, 0x9e),- G(0x34, 0x2e, 0xca, 0xfe, 0xa2, 0x8c), G(0x36, 0x2d, 0xc3, 0xf5, 0xaf, 0x82),- G(0x38, 0x24, 0xfc, 0xc4, 0x8c, 0xa8), G(0x3a, 0x27, 0xf5, 0xcf, 0x81, 0xa6),- G(0x3c, 0x22, 0xee, 0xd2, 0x96, 0xb4), G(0x3e, 0x21, 0xe7, 0xd9, 0x9b, 0xba),- G(0x40, 0x60, 0x3b, 0x7b, 0xbb, 0xdb), G(0x42, 0x63, 0x32, 0x70, 0xb6, 0xd5),- G(0x44, 0x66, 0x29, 0x6d, 0xa1, 0xc7), G(0x46, 0x65, 0x20, 0x66, 0xac, 0xc9),- G(0x48, 0x6c, 0x1f, 0x57, 0x8f, 0xe3), G(0x4a, 0x6f, 0x16, 0x5c, 0x82, 0xed),- G(0x4c, 0x6a, 0x0d, 0x41, 0x95, 0xff), G(0x4e, 0x69, 0x04, 0x4a, 0x98, 0xf1),- G(0x50, 0x78, 0x73, 0x23, 0xd3, 0xab), G(0x52, 0x7b, 0x7a, 0x28, 0xde, 0xa5),- G(0x54, 0x7e, 0x61, 0x35, 0xc9, 0xb7), G(0x56, 0x7d, 0x68, 0x3e, 0xc4, 0xb9),- G(0x58, 0x74, 0x57, 0x0f, 0xe7, 0x93), G(0x5a, 0x77, 0x5e, 0x04, 0xea, 0x9d),- G(0x5c, 0x72, 0x45, 0x19, 0xfd, 0x8f), G(0x5e, 0x71, 0x4c, 0x12, 0xf0, 0x81),- G(0x60, 0x50, 0xab, 0xcb, 0x6b, 0x3b), G(0x62, 0x53, 0xa2, 0xc0, 0x66, 0x35),- G(0x64, 0x56, 0xb9, 0xdd, 0x71, 0x27), G(0x66, 0x55, 0xb0, 0xd6, 0x7c, 0x29),- G(0x68, 0x5c, 0x8f, 0xe7, 0x5f, 0x03), G(0x6a, 0x5f, 0x86, 0xec, 0x52, 0x0d),- G(0x6c, 0x5a, 0x9d, 0xf1, 0x45, 0x1f), G(0x6e, 0x59, 0x94, 0xfa, 0x48, 0x11),- G(0x70, 0x48, 0xe3, 0x93, 0x03, 0x4b), G(0x72, 0x4b, 0xea, 0x98, 0x0e, 0x45),- G(0x74, 0x4e, 0xf1, 0x85, 0x19, 0x57), G(0x76, 0x4d, 0xf8, 0x8e, 0x14, 0x59),- G(0x78, 0x44, 0xc7, 0xbf, 0x37, 0x73), G(0x7a, 0x47, 0xce, 0xb4, 0x3a, 0x7d),- G(0x7c, 0x42, 0xd5, 0xa9, 0x2d, 0x6f), G(0x7e, 0x41, 0xdc, 0xa2, 0x20, 0x61),- G(0x80, 0xc0, 0x76, 0xf6, 0x6d, 0xad), G(0x82, 0xc3, 0x7f, 0xfd, 0x60, 0xa3),- G(0x84, 0xc6, 0x64, 0xe0, 0x77, 0xb1), G(0x86, 0xc5, 0x6d, 0xeb, 0x7a, 0xbf),- G(0x88, 0xcc, 0x52, 0xda, 0x59, 0x95), G(0x8a, 0xcf, 0x5b, 0xd1, 0x54, 0x9b),- G(0x8c, 0xca, 0x40, 0xcc, 0x43, 0x89), G(0x8e, 0xc9, 0x49, 0xc7, 0x4e, 0x87),- G(0x90, 0xd8, 0x3e, 0xae, 0x05, 0xdd), G(0x92, 0xdb, 0x37, 0xa5, 0x08, 0xd3),- G(0x94, 0xde, 0x2c, 0xb8, 0x1f, 0xc1), G(0x96, 0xdd, 0x25, 0xb3, 0x12, 0xcf),- G(0x98, 0xd4, 0x1a, 0x82, 0x31, 0xe5), G(0x9a, 0xd7, 0x13, 0x89, 0x3c, 0xeb),- G(0x9c, 0xd2, 0x08, 0x94, 0x2b, 0xf9), G(0x9e, 0xd1, 0x01, 0x9f, 0x26, 0xf7),- G(0xa0, 0xf0, 0xe6, 0x46, 0xbd, 0x4d), G(0xa2, 0xf3, 0xef, 0x4d, 0xb0, 0x43),- G(0xa4, 0xf6, 0xf4, 0x50, 0xa7, 0x51), G(0xa6, 0xf5, 0xfd, 0x5b, 0xaa, 0x5f),- G(0xa8, 0xfc, 0xc2, 0x6a, 0x89, 0x75), G(0xaa, 0xff, 0xcb, 0x61, 0x84, 0x7b),- G(0xac, 0xfa, 0xd0, 0x7c, 0x93, 0x69), G(0xae, 0xf9, 0xd9, 0x77, 0x9e, 0x67),- G(0xb0, 0xe8, 0xae, 0x1e, 0xd5, 0x3d), G(0xb2, 0xeb, 0xa7, 0x15, 0xd8, 0x33),- G(0xb4, 0xee, 0xbc, 0x08, 0xcf, 0x21), G(0xb6, 0xed, 0xb5, 0x03, 0xc2, 0x2f),- G(0xb8, 0xe4, 0x8a, 0x32, 0xe1, 0x05), G(0xba, 0xe7, 0x83, 0x39, 0xec, 0x0b),- G(0xbc, 0xe2, 0x98, 0x24, 0xfb, 0x19), G(0xbe, 0xe1, 0x91, 0x2f, 0xf6, 0x17),- G(0xc0, 0xa0, 0x4d, 0x8d, 0xd6, 0x76), G(0xc2, 0xa3, 0x44, 0x86, 0xdb, 0x78),- G(0xc4, 0xa6, 0x5f, 0x9b, 0xcc, 0x6a), G(0xc6, 0xa5, 0x56, 0x90, 0xc1, 0x64),- G(0xc8, 0xac, 0x69, 0xa1, 0xe2, 0x4e), G(0xca, 0xaf, 0x60, 0xaa, 0xef, 0x40),- G(0xcc, 0xaa, 0x7b, 0xb7, 0xf8, 0x52), G(0xce, 0xa9, 0x72, 0xbc, 0xf5, 0x5c),- G(0xd0, 0xb8, 0x05, 0xd5, 0xbe, 0x06), G(0xd2, 0xbb, 0x0c, 0xde, 0xb3, 0x08),- G(0xd4, 0xbe, 0x17, 0xc3, 0xa4, 0x1a), G(0xd6, 0xbd, 0x1e, 0xc8, 0xa9, 0x14),- G(0xd8, 0xb4, 0x21, 0xf9, 0x8a, 0x3e), G(0xda, 0xb7, 0x28, 0xf2, 0x87, 0x30),- G(0xdc, 0xb2, 0x33, 0xef, 0x90, 0x22), G(0xde, 0xb1, 0x3a, 0xe4, 0x9d, 0x2c),- G(0xe0, 0x90, 0xdd, 0x3d, 0x06, 0x96), G(0xe2, 0x93, 0xd4, 0x36, 0x0b, 0x98),- G(0xe4, 0x96, 0xcf, 0x2b, 0x1c, 0x8a), G(0xe6, 0x95, 0xc6, 0x20, 0x11, 0x84),- G(0xe8, 0x9c, 0xf9, 0x11, 0x32, 0xae), G(0xea, 0x9f, 0xf0, 0x1a, 0x3f, 0xa0),- G(0xec, 0x9a, 0xeb, 0x07, 0x28, 0xb2), G(0xee, 0x99, 0xe2, 0x0c, 0x25, 0xbc),- G(0xf0, 0x88, 0x95, 0x65, 0x6e, 0xe6), G(0xf2, 0x8b, 0x9c, 0x6e, 0x63, 0xe8),- G(0xf4, 0x8e, 0x87, 0x73, 0x74, 0xfa), G(0xf6, 0x8d, 0x8e, 0x78, 0x79, 0xf4),- G(0xf8, 0x84, 0xb1, 0x49, 0x5a, 0xde), G(0xfa, 0x87, 0xb8, 0x42, 0x57, 0xd0),- G(0xfc, 0x82, 0xa3, 0x5f, 0x40, 0xc2), G(0xfe, 0x81, 0xaa, 0x54, 0x4d, 0xcc),- G(0x1b, 0x9b, 0xec, 0xf7, 0xda, 0x41), G(0x19, 0x98, 0xe5, 0xfc, 0xd7, 0x4f),- G(0x1f, 0x9d, 0xfe, 0xe1, 0xc0, 0x5d), G(0x1d, 0x9e, 0xf7, 0xea, 0xcd, 0x53),- G(0x13, 0x97, 0xc8, 0xdb, 0xee, 0x79), G(0x11, 0x94, 0xc1, 0xd0, 0xe3, 0x77),- G(0x17, 0x91, 0xda, 0xcd, 0xf4, 0x65), G(0x15, 0x92, 0xd3, 0xc6, 0xf9, 0x6b),- G(0x0b, 0x83, 0xa4, 0xaf, 0xb2, 0x31), G(0x09, 0x80, 0xad, 0xa4, 0xbf, 0x3f),- G(0x0f, 0x85, 0xb6, 0xb9, 0xa8, 0x2d), G(0x0d, 0x86, 0xbf, 0xb2, 0xa5, 0x23),- G(0x03, 0x8f, 0x80, 0x83, 0x86, 0x09), G(0x01, 0x8c, 0x89, 0x88, 0x8b, 0x07),- G(0x07, 0x89, 0x92, 0x95, 0x9c, 0x15), G(0x05, 0x8a, 0x9b, 0x9e, 0x91, 0x1b),- G(0x3b, 0xab, 0x7c, 0x47, 0x0a, 0xa1), G(0x39, 0xa8, 0x75, 0x4c, 0x07, 0xaf),- G(0x3f, 0xad, 0x6e, 0x51, 0x10, 0xbd), G(0x3d, 0xae, 0x67, 0x5a, 0x1d, 0xb3),- G(0x33, 0xa7, 0x58, 0x6b, 0x3e, 0x99), G(0x31, 0xa4, 0x51, 0x60, 0x33, 0x97),- G(0x37, 0xa1, 0x4a, 0x7d, 0x24, 0x85), G(0x35, 0xa2, 0x43, 0x76, 0x29, 0x8b),- G(0x2b, 0xb3, 0x34, 0x1f, 0x62, 0xd1), G(0x29, 0xb0, 0x3d, 0x14, 0x6f, 0xdf),- G(0x2f, 0xb5, 0x26, 0x09, 0x78, 0xcd), G(0x2d, 0xb6, 0x2f, 0x02, 0x75, 0xc3),- G(0x23, 0xbf, 0x10, 0x33, 0x56, 0xe9), G(0x21, 0xbc, 0x19, 0x38, 0x5b, 0xe7),- G(0x27, 0xb9, 0x02, 0x25, 0x4c, 0xf5), G(0x25, 0xba, 0x0b, 0x2e, 0x41, 0xfb),- G(0x5b, 0xfb, 0xd7, 0x8c, 0x61, 0x9a), G(0x59, 0xf8, 0xde, 0x87, 0x6c, 0x94),- G(0x5f, 0xfd, 0xc5, 0x9a, 0x7b, 0x86), G(0x5d, 0xfe, 0xcc, 0x91, 0x76, 0x88),- G(0x53, 0xf7, 0xf3, 0xa0, 0x55, 0xa2), G(0x51, 0xf4, 0xfa, 0xab, 0x58, 0xac),- G(0x57, 0xf1, 0xe1, 0xb6, 0x4f, 0xbe), G(0x55, 0xf2, 0xe8, 0xbd, 0x42, 0xb0),- G(0x4b, 0xe3, 0x9f, 0xd4, 0x09, 0xea), G(0x49, 0xe0, 0x96, 0xdf, 0x04, 0xe4),- G(0x4f, 0xe5, 0x8d, 0xc2, 0x13, 0xf6), G(0x4d, 0xe6, 0x84, 0xc9, 0x1e, 0xf8),- G(0x43, 0xef, 0xbb, 0xf8, 0x3d, 0xd2), G(0x41, 0xec, 0xb2, 0xf3, 0x30, 0xdc),- G(0x47, 0xe9, 0xa9, 0xee, 0x27, 0xce), G(0x45, 0xea, 0xa0, 0xe5, 0x2a, 0xc0),- G(0x7b, 0xcb, 0x47, 0x3c, 0xb1, 0x7a), G(0x79, 0xc8, 0x4e, 0x37, 0xbc, 0x74),- G(0x7f, 0xcd, 0x55, 0x2a, 0xab, 0x66), G(0x7d, 0xce, 0x5c, 0x21, 0xa6, 0x68),- G(0x73, 0xc7, 0x63, 0x10, 0x85, 0x42), G(0x71, 0xc4, 0x6a, 0x1b, 0x88, 0x4c),- G(0x77, 0xc1, 0x71, 0x06, 0x9f, 0x5e), G(0x75, 0xc2, 0x78, 0x0d, 0x92, 0x50),- G(0x6b, 0xd3, 0x0f, 0x64, 0xd9, 0x0a), G(0x69, 0xd0, 0x06, 0x6f, 0xd4, 0x04),- G(0x6f, 0xd5, 0x1d, 0x72, 0xc3, 0x16), G(0x6d, 0xd6, 0x14, 0x79, 0xce, 0x18),- G(0x63, 0xdf, 0x2b, 0x48, 0xed, 0x32), G(0x61, 0xdc, 0x22, 0x43, 0xe0, 0x3c),- G(0x67, 0xd9, 0x39, 0x5e, 0xf7, 0x2e), G(0x65, 0xda, 0x30, 0x55, 0xfa, 0x20),- G(0x9b, 0x5b, 0x9a, 0x01, 0xb7, 0xec), G(0x99, 0x58, 0x93, 0x0a, 0xba, 0xe2),- G(0x9f, 0x5d, 0x88, 0x17, 0xad, 0xf0), G(0x9d, 0x5e, 0x81, 0x1c, 0xa0, 0xfe),- G(0x93, 0x57, 0xbe, 0x2d, 0x83, 0xd4), G(0x91, 0x54, 0xb7, 0x26, 0x8e, 0xda),- G(0x97, 0x51, 0xac, 0x3b, 0x99, 0xc8), G(0x95, 0x52, 0xa5, 0x30, 0x94, 0xc6),- G(0x8b, 0x43, 0xd2, 0x59, 0xdf, 0x9c), G(0x89, 0x40, 0xdb, 0x52, 0xd2, 0x92),- G(0x8f, 0x45, 0xc0, 0x4f, 0xc5, 0x80), G(0x8d, 0x46, 0xc9, 0x44, 0xc8, 0x8e),- G(0x83, 0x4f, 0xf6, 0x75, 0xeb, 0xa4), G(0x81, 0x4c, 0xff, 0x7e, 0xe6, 0xaa),- G(0x87, 0x49, 0xe4, 0x63, 0xf1, 0xb8), G(0x85, 0x4a, 0xed, 0x68, 0xfc, 0xb6),- G(0xbb, 0x6b, 0x0a, 0xb1, 0x67, 0x0c), G(0xb9, 0x68, 0x03, 0xba, 0x6a, 0x02),- G(0xbf, 0x6d, 0x18, 0xa7, 0x7d, 0x10), G(0xbd, 0x6e, 0x11, 0xac, 0x70, 0x1e),- G(0xb3, 0x67, 0x2e, 0x9d, 0x53, 0x34), G(0xb1, 0x64, 0x27, 0x96, 0x5e, 0x3a),- G(0xb7, 0x61, 0x3c, 0x8b, 0x49, 0x28), G(0xb5, 0x62, 0x35, 0x80, 0x44, 0x26),- G(0xab, 0x73, 0x42, 0xe9, 0x0f, 0x7c), G(0xa9, 0x70, 0x4b, 0xe2, 0x02, 0x72),- G(0xaf, 0x75, 0x50, 0xff, 0x15, 0x60), G(0xad, 0x76, 0x59, 0xf4, 0x18, 0x6e),- G(0xa3, 0x7f, 0x66, 0xc5, 0x3b, 0x44), G(0xa1, 0x7c, 0x6f, 0xce, 0x36, 0x4a),- G(0xa7, 0x79, 0x74, 0xd3, 0x21, 0x58), G(0xa5, 0x7a, 0x7d, 0xd8, 0x2c, 0x56),- G(0xdb, 0x3b, 0xa1, 0x7a, 0x0c, 0x37), G(0xd9, 0x38, 0xa8, 0x71, 0x01, 0x39),- G(0xdf, 0x3d, 0xb3, 0x6c, 0x16, 0x2b), G(0xdd, 0x3e, 0xba, 0x67, 0x1b, 0x25),- G(0xd3, 0x37, 0x85, 0x56, 0x38, 0x0f), G(0xd1, 0x34, 0x8c, 0x5d, 0x35, 0x01),- G(0xd7, 0x31, 0x97, 0x40, 0x22, 0x13), G(0xd5, 0x32, 0x9e, 0x4b, 0x2f, 0x1d),- G(0xcb, 0x23, 0xe9, 0x22, 0x64, 0x47), G(0xc9, 0x20, 0xe0, 0x29, 0x69, 0x49),- G(0xcf, 0x25, 0xfb, 0x34, 0x7e, 0x5b), G(0xcd, 0x26, 0xf2, 0x3f, 0x73, 0x55),- G(0xc3, 0x2f, 0xcd, 0x0e, 0x50, 0x7f), G(0xc1, 0x2c, 0xc4, 0x05, 0x5d, 0x71),- G(0xc7, 0x29, 0xdf, 0x18, 0x4a, 0x63), G(0xc5, 0x2a, 0xd6, 0x13, 0x47, 0x6d),- G(0xfb, 0x0b, 0x31, 0xca, 0xdc, 0xd7), G(0xf9, 0x08, 0x38, 0xc1, 0xd1, 0xd9),- G(0xff, 0x0d, 0x23, 0xdc, 0xc6, 0xcb), G(0xfd, 0x0e, 0x2a, 0xd7, 0xcb, 0xc5),- G(0xf3, 0x07, 0x15, 0xe6, 0xe8, 0xef), G(0xf1, 0x04, 0x1c, 0xed, 0xe5, 0xe1),- G(0xf7, 0x01, 0x07, 0xf0, 0xf2, 0xf3), G(0xf5, 0x02, 0x0e, 0xfb, 0xff, 0xfd),- G(0xeb, 0x13, 0x79, 0x92, 0xb4, 0xa7), G(0xe9, 0x10, 0x70, 0x99, 0xb9, 0xa9),- G(0xef, 0x15, 0x6b, 0x84, 0xae, 0xbb), G(0xed, 0x16, 0x62, 0x8f, 0xa3, 0xb5),- G(0xe3, 0x1f, 0x5d, 0xbe, 0x80, 0x9f), G(0xe1, 0x1c, 0x54, 0xb5, 0x8d, 0x91),- G(0xe7, 0x19, 0x4f, 0xa8, 0x9a, 0x83), G(0xe5, 0x1a, 0x46, 0xa3, 0x97, 0x8d),-};-#undef G+/*+ * The schedule is kept in its compressed form, 30 words of it, inside the+ * aes_key the caller already has -- comfortably inside the 448 bytes that+ * held the round keys before. br_aes_ct64_skey_expand blows it up to 120+ * words on the stack once per call, which is how BearSSL's own CTR and CBC+ * use it.+ *+ * It travels through memcpy rather than a cast because aes_key is all+ * uint8_t and so carries no alignment of its own, whatever the allocator+ * happens to give it.+ */+#define COMP_SKEY_WORDS 30 -static void expand_key(uint8_t *expandedKey, uint8_t *key, int size, size_t expandedKeySize)+void crypton_aes_generic_schedule(aes_sched *sched, const aes_key *key) {- int csz;- int i;- uint8_t t[4] = { 0 };-- for (i = 0; i < size; i++)- expandedKey[i] = key[i];- csz = size;+ uint64_t comp_skey[COMP_SKEY_WORDS]; - i = 1;- while (csz < expandedKeySize) {- t[0] = expandedKey[(csz - 4) + 0];- t[1] = expandedKey[(csz - 4) + 1];- t[2] = expandedKey[(csz - 4) + 2];- t[3] = expandedKey[(csz - 4) + 3];+ memcpy(comp_skey, key->data, sizeof comp_skey);+ sched->nbr = key->nbr;+ br_aes_ct64_skey_expand(sched->sk_exp, sched->nbr, comp_skey);+} - if (csz % size == 0) {- uint8_t tmp;+/*+ * Up to four blocks through the bitsliced core at once. Fewer than four is+ * the same work as four -- the lanes are there whether anything is in them+ * -- so a caller with four to offer gets them for what one used to cost.+ */+static void pass(uint8_t *output, const uint8_t *input, unsigned n,+ const aes_sched *sched, int decrypt)+{+ uint32_t w[16];+ uint64_t q[8];+ unsigned i; - tmp = t[0];- t[0] = sbox[t[1]] ^ Rcon[i++ % sizeof(Rcon)];- t[1] = sbox[t[2]];- t[2] = sbox[t[3]];- t[3] = sbox[tmp];- }+ memset(w, 0, sizeof w);+ for (i = 0; i < n; i++) {+ w[4 * i] = br_dec32le(input + 16 * i);+ w[4 * i + 1] = br_dec32le(input + 16 * i + 4);+ w[4 * i + 2] = br_dec32le(input + 16 * i + 8);+ w[4 * i + 3] = br_dec32le(input + 16 * i + 12);+ } - if (size == 32 && ((csz % size) == 16)) {- t[0] = sbox[t[0]];- t[1] = sbox[t[1]];- t[2] = sbox[t[2]];- t[3] = sbox[t[3]];- }+ for (i = 0; i < 4; i++)+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + 4 * i);+ br_aes_ct64_ortho(q);+ if (decrypt)+ br_aes_ct64_bitslice_decrypt(sched->nbr, sched->sk_exp, q);+ else+ br_aes_ct64_bitslice_encrypt(sched->nbr, sched->sk_exp, q);+ br_aes_ct64_ortho(q);+ for (i = 0; i < 4; i++)+ br_aes_ct64_interleave_out(w + 4 * i, q[i], q[i + 4]); - expandedKey[csz] = expandedKey[csz - size] ^ t[0]; csz++;- expandedKey[csz] = expandedKey[csz - size] ^ t[1]; csz++;- expandedKey[csz] = expandedKey[csz - size] ^ t[2]; csz++;- expandedKey[csz] = expandedKey[csz - size] ^ t[3]; csz++;+ for (i = 0; i < n; i++) {+ br_enc32le(output + 16 * i, w[4 * i]);+ br_enc32le(output + 16 * i + 4, w[4 * i + 1]);+ br_enc32le(output + 16 * i + 8, w[4 * i + 2]);+ br_enc32le(output + 16 * i + 12, w[4 * i + 3]); } } -static void shift_rows(uint8_t *state)+void crypton_aes_generic_blocks(uint8_t *output, const uint8_t *input,+ uint32_t nb_blocks, const aes_sched *sched,+ int decrypt) {- uint32_t *s32;- int i;-- for (i = 0; i < 16; i++)- state[i] = sbox[state[i]];- s32 = (uint32_t *) state;- s32[1] = rol32_be(s32[1], 8);- s32[2] = rol32_be(s32[2], 16);- s32[3] = rol32_be(s32[3], 24);+ while (nb_blocks >= 4) {+ pass(output, input, 4, sched, decrypt);+ output += 64;+ input += 64;+ nb_blocks -= 4;+ }+ if (nb_blocks > 0)+ pass(output, input, (unsigned) nb_blocks, sched, decrypt); } -static void add_round_key(uint8_t *state, uint8_t *rk)+static void one(aes_block *output, aes_key *key, aes_block *input, int decrypt) {- uint32_t *s32, *r32;+ aes_sched sched; - s32 = (uint32_t *) state;- r32 = (uint32_t *) rk;- s32[0] ^= r32[0];- s32[1] ^= r32[1];- s32[2] ^= r32[2];- s32[3] ^= r32[3];+ crypton_aes_generic_schedule(&sched, key);+ crypton_aes_generic_blocks((uint8_t *) output, (const uint8_t *) input,+ 1, &sched, decrypt); } -#define gm1(a) (a)-#define gm2(a) gmtab[a][0]-#define gm3(a) gmtab[a][1]-#define gm9(a) gmtab[a][2]-#define gm11(a) gmtab[a][3]-#define gm13(a) gmtab[a][4]-#define gm14(a) gmtab[a][5]--static void mix_columns(uint8_t *state)+void crypton_aes_generic_encrypt_block(aes_block *output, aes_key *key, aes_block *input) {- int i;- uint8_t cpy[4];-- for (i = 0; i < 4; i++) {- cpy[0] = state[0 * 4 + i];- cpy[1] = state[1 * 4 + i];- cpy[2] = state[2 * 4 + i];- cpy[3] = state[3 * 4 + i];- state[i] = gm2(cpy[0]) ^ gm1(cpy[3]) ^ gm1(cpy[2]) ^ gm3(cpy[1]);- state[4+i] = gm2(cpy[1]) ^ gm1(cpy[0]) ^ gm1(cpy[3]) ^ gm3(cpy[2]);- state[8+i] = gm2(cpy[2]) ^ gm1(cpy[1]) ^ gm1(cpy[0]) ^ gm3(cpy[3]);- state[12+i] = gm2(cpy[3]) ^ gm1(cpy[2]) ^ gm1(cpy[1]) ^ gm3(cpy[0]);- }+ one(output, key, input, 0); } -static void create_round_key(uint8_t *expandedKey, uint8_t *rk)+void crypton_aes_generic_decrypt_block(aes_block *output, aes_key *key, aes_block *input) {- int i,j;- for (i = 0; i < 4; i++)- for (j = 0; j < 4; j++)- rk[i + j * 4] = expandedKey[i * 4 + j];+ one(output, key, input, 1); } -static void aes_main(aes_key *key, uint8_t *state)+void crypton_aes_generic_init(aes_key *key, uint8_t *origkey, uint8_t size) {- int i = 0;- uint32_t rk[4];- uint8_t *rkptr = (uint8_t *) rk;-- create_round_key(key->data, rkptr);- add_round_key(state, rkptr);-- for (i = 1; i < key->nbr; i++) {- create_round_key(key->data + 16 * i, rkptr);- shift_rows(state);- mix_columns(state);- add_round_key(state, rkptr);- }-- create_round_key(key->data + 16 * key->nbr, rkptr);- shift_rows(state);- add_round_key(state, rkptr);-}+ uint64_t comp_skey[COMP_SKEY_WORDS];+ unsigned nbr; -static void shift_rows_inv(uint8_t *state)-{- uint32_t *s32;- int i;+ /* 0 for a key length that is not 16, 24 or 32; the old code returned+ * without touching the key in that case and so does this */+ nbr = br_aes_ct64_keysched(comp_skey, origkey, size);+ if (nbr == 0)+ return; - s32 = (uint32_t *) state;- s32[1] = ror32_be(s32[1], 8);- s32[2] = ror32_be(s32[2], 16);- s32[3] = ror32_be(s32[3], 24);- for (i = 0; i < 16; i++)- state[i] = rsbox[state[i]];+ key->nbr = (uint8_t) nbr;+ memcpy(key->data, comp_skey, sizeof comp_skey); } -static void mix_columns_inv(uint8_t *state)+/*+ * CTR, four counter blocks at a time. The counter itself is serial, but+ * nothing about it depends on the keystream, so the four blocks it will+ * reach next can be written down before any of them is encrypted.+ */+static void ctr(uint8_t *output, aes_key *key, aes_block *iv,+ uint8_t *input, uint32_t len, int c32) {- int i;- uint8_t cpy[4];+ aes_sched sched;+ aes_block counter;+ uint8_t ks[64];+ uint32_t nb_blocks = len / 16;+ uint32_t tail = len % 16;+ uint32_t i; - for (i = 0; i < 4; i++) {- cpy[0] = state[0 * 4 + i];- cpy[1] = state[1 * 4 + i];- cpy[2] = state[2 * 4 + i];- cpy[3] = state[3 * 4 + i];- state[i] = gm14(cpy[0]) ^ gm9(cpy[3]) ^ gm13(cpy[2]) ^ gm11(cpy[1]);- state[4+i] = gm14(cpy[1]) ^ gm9(cpy[0]) ^ gm13(cpy[3]) ^ gm11(cpy[2]);- state[8+i] = gm14(cpy[2]) ^ gm9(cpy[1]) ^ gm13(cpy[0]) ^ gm11(cpy[3]);- state[12+i] = gm14(cpy[3]) ^ gm9(cpy[2]) ^ gm13(cpy[1]) ^ gm11(cpy[0]);- }-}+ crypton_aes_generic_schedule(&sched, key);+ block128_copy(&counter, iv); -static void aes_main_inv(aes_key *key, uint8_t *state)-{- int i = 0;- uint32_t rk[4];- uint8_t *rkptr = (uint8_t *) rk;+ while (nb_blocks > 0) {+ uint32_t n = nb_blocks < 4 ? nb_blocks : 4; - create_round_key(key->data + 16 * key->nbr, rkptr);- add_round_key(state, rkptr);+ for (i = 0; i < n; i++) {+ block128_copy((block128 *) (ks + 16 * i), &counter);+ if (c32)+ block128_inc32_le(&counter);+ else+ block128_inc_be(&counter);+ }+ crypton_aes_generic_blocks(ks, ks, n, &sched, 0);+ for (i = 0; i < n * 16; i++)+ output[i] = ks[i] ^ input[i]; - for (i = key->nbr - 1; i > 0; i--) {- create_round_key(key->data + 16 * i, rkptr);- shift_rows_inv(state);- add_round_key(state, rkptr);- mix_columns_inv(state);+ output += n * 16;+ input += n * 16;+ nb_blocks -= n; } - create_round_key(key->data, rkptr);- shift_rows_inv(state);- add_round_key(state, rkptr);-}--/* Set the block values, for the block:- * a0,0 a0,1 a0,2 a0,3- * a1,0 a1,1 a1,2 a1,3 -> a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3- * a2,0 a2,1 a2,2 a2,3- * a3,0 a3,1 a3,2 a3,3- */-#define swap_block(t, f) \- t[0] = f[0]; t[4] = f[1]; t[8] = f[2]; t[12] = f[3]; \- t[1] = f[4]; t[5] = f[5]; t[9] = f[6]; t[13] = f[7]; \- t[2] = f[8]; t[6] = f[9]; t[10] = f[10]; t[14] = f[11]; \- t[3] = f[12]; t[7] = f[13]; t[11] = f[14]; t[15] = f[15]--void crypton_aes_generic_encrypt_block(aes_block *output, aes_key *key, aes_block *input)-{- uint32_t block[4];- uint8_t *iptr, *optr, *bptr;-- iptr = (uint8_t *) input;- optr = (uint8_t *) output;- bptr = (uint8_t *) block;- swap_block(bptr, iptr);- aes_main(key, bptr);- swap_block(optr, bptr);+ if (tail != 0) {+ block128_copy((block128 *) ks, &counter);+ crypton_aes_generic_blocks(ks, ks, 1, &sched, 0);+ for (i = 0; i < tail; i++)+ output[i] = ks[i] ^ input[i];+ } } -void crypton_aes_generic_decrypt_block(aes_block *output, aes_key *key, aes_block *input)+void crypton_aes_bitsliced_encrypt_ctr(uint8_t *output, aes_key *key,+ aes_block *iv, uint8_t *input,+ uint32_t len) {- uint32_t block[4];- uint8_t *iptr, *optr, *bptr;-- iptr = (uint8_t *) input;- optr = (uint8_t *) output;- bptr = (uint8_t *) block;- swap_block(bptr, iptr);- aes_main_inv(key, bptr);- swap_block(optr, bptr);+ ctr(output, key, iv, input, len, 0); } -void crypton_aes_generic_init(aes_key *key, uint8_t *origkey, uint8_t size)+void crypton_aes_bitsliced_encrypt_c32(uint8_t *output, aes_key *key,+ aes_block *iv, uint8_t *input,+ uint32_t len) {- int esz;-- switch (size) {- case 16: key->nbr = 10; esz = 176; break;- case 24: key->nbr = 12; esz = 208; break;- case 32: key->nbr = 14; esz = 240; break;- default: return;- }- expand_key(key->data, origkey, size, esz);- return;+ ctr(output, key, iv, input, len, 1); }
@@ -32,3 +32,35 @@ void crypton_aes_generic_encrypt_block(aes_block *output, aes_key *key, aes_block *input); void crypton_aes_generic_decrypt_block(aes_block *output, aes_key *key, aes_block *input); void crypton_aes_generic_init(aes_key *key, uint8_t *origkey, uint8_t size);++/*+ * The bitsliced core takes four blocks at a time, and the schedule it reads+ * is the expanded one rather than the compressed form the aes_key holds.+ * Expanding costs about what a block costs, so a mode with more than one+ * block to do expands once, here, and hands the result to every group.+ */+typedef struct {+ uint64_t sk_exp[120];+ unsigned nbr;+} aes_sched;++void crypton_aes_generic_schedule(aes_sched *sched, const aes_key *key);++/* nb_blocks of them, four at a pass; decrypt selects the direction */+void crypton_aes_generic_blocks(uint8_t *output, const uint8_t *input,+ uint32_t nb_blocks, const aes_sched *sched,+ int decrypt);++/*+ * CTR with the two counters crypton uses. These are not the generic+ * entries: those go through the branch table for the block itself and so+ * run on accelerated machines too, where the key holds a different+ * schedule. crypton_aes.c installs these only when nothing was+ * accelerated.+ */+void crypton_aes_bitsliced_encrypt_ctr(uint8_t *output, aes_key *key,+ aes_block *iv, uint8_t *input,+ uint32_t len);+void crypton_aes_bitsliced_encrypt_c32(uint8_t *output, aes_key *key,+ aes_block *iv, uint8_t *input,+ uint32_t len);
@@ -33,6 +33,7 @@ #include <crypton_cpu.h> #include <aes/gf.h> #include <aes/x86ni.h>+#include "bearssl/inner.h" /* inplace GFMUL for xts mode */ void crypton_aes_generic_gf_mulx(block128 *a)@@ -45,118 +46,43 @@ /*- * GF multiplication with Shoup's method and 4-bit table.+ * GHASH, without a table. *- * We precompute the products of H with all 4-bit polynomials and store them in- * a 'table_4bit' array. To avoid unnecessary byte swapping, the 16 blocks are- * written to the table with qwords already converted to CPU order. Table- * indices use the reflected bit ordering, i.e. polynomials X^0, X^1, X^2, X^3- * map to bit positions 3, 2, 1, 0 respectively.+ * This was Shoup's method: the products of H with all sixteen 4-bit+ * polynomials, precomputed, and thirty-two lookups a block at indices taken+ * from the accumulator -- which is to say, thirty-two addresses derived from+ * a secret. It is now BearSSL's ghash_ctmul64, which builds the GF(2^128)+ * multiply out of shifts, masks and integer multiplies and looks nothing up.+ * See cbits/bearssl/README.md. *- * To multiply an arbitrary block with H, the input block is decomposed in 4-bit- * segments. We get the final result after 32 table lookups and additions, one- * for each segment, interleaving multiplication by P(X)=X^4.+ * The table_4bit the interface names is sixteen blocks wide because the+ * table needed it. This keeps H in the first and leaves the rest alone; the+ * PMULL and PCLMUL implementations keep their own powers of H in that same+ * space, so the width stays as it is. */ -/* convert block128 qwords between BE and CPU order */-static inline void block128_cpu_swap_be(block128 *a, const block128 *b)-{- a->q[1] = cpu_to_be64(b->q[1]);- a->q[0] = cpu_to_be64(b->q[0]);-}--/* multiplication by P(X)=X, assuming qwords already in CPU order */-static inline void cpu_gf_mulx(block128 *a, const block128 *b)-{- uint64_t v0 = b->q[0];- uint64_t v1 = b->q[1];- a->q[1] = v1 >> 1 | v0 << 63;- a->q[0] = v0 >> 1 ^ ((0-(v1 & 1)) & 0xe100000000000000ULL);-}--static const uint64_t r4_0[] =- { 0x0000000000000000ULL, 0x1c20000000000000ULL- , 0x3840000000000000ULL, 0x2460000000000000ULL- , 0x7080000000000000ULL, 0x6ca0000000000000ULL- , 0x48c0000000000000ULL, 0x54e0000000000000ULL- , 0xe100000000000000ULL, 0xfd20000000000000ULL- , 0xd940000000000000ULL, 0xc560000000000000ULL- , 0x9180000000000000ULL, 0x8da0000000000000ULL- , 0xa9c0000000000000ULL, 0xb5e0000000000000ULL- };--/* multiplication by P(X)=X^4, assuming qwords already in CPU order */-static inline void cpu_gf_mulx4(block128 *a, const block128 *b)-{- uint64_t v0 = b->q[0];- uint64_t v1 = b->q[1];- a->q[1] = v1 >> 4 | v0 << 60;- a->q[0] = v0 >> 4 ^ r4_0[v1 & 0xf];-}--/* initialize the 4-bit table given H */+/* remember H */ void crypton_aes_generic_hinit(table_4bit htable, const block128 *h) {- block128 v, *p;- int i, j;-- /* multiplication by 0 is 0 */- block128_zero(&htable[0]);-- /* at index 8=2^3 we have H.X^0 = H */- i = 8;- block128_cpu_swap_be(&htable[i], h); /* in CPU order */- p = &htable[i];-- /* for other powers of 2, repeat multiplication by P(X)=X */- for (i = 4; i > 0; i >>= 1)- {- cpu_gf_mulx(&htable[i], p);- p = &htable[i];- }-- /* remaining elements are linear combinations */- for (i = 2; i < 16; i <<= 1) {- p = &htable[i];- v = *p;- for (j = 1; j < i; j++) {- p[j] = v;- block128_xor_aligned(&p[j], &htable[j]);- }- }+ block128_copy(&htable[0], h); } -/* multiply a block with H */+/*+ * br_ghash_ctmul64 computes y = (y ^ x) * H for each block x it is given, so+ * a block of zeros is the bare multiply this entry is asked for.+ */ void crypton_aes_generic_gf_mul(block128 *a, const table_4bit htable) {- block128 b;- int i;- block128_zero(&b);- for (i = 15; i >= 0; i--)- {- uint8_t v = a->b[i];- block128_xor_aligned(&b, &htable[v & 0xf]); /* high bits (reflected) */- cpu_gf_mulx4(&b, &b);- block128_xor_aligned(&b, &htable[v >> 4]); /* low bits (reflected) */- if (i > 0)- cpu_gf_mulx4(&b, &b);- else- block128_cpu_swap_be(a, &b); /* restore BE order when done */- }+ static const uint8_t zero[16] = { 0 };++ br_ghash_ctmul64(a, &htable[0], zero, sizeof zero); } /*- * Four GHASH steps at once. The generic table-driven multiply has no cheaper- * way to do this than one block at a time; the point of the entry is that the- * PMULL and PCLMUL versions can fold the four products into one reduction, so- * the GCM loops hand over four blocks whenever they have them.+ * Four GHASH steps at once, which here is one call rather than four: the+ * loop inside br_ghash_ctmul64 takes the blocks as they come. */ void crypton_aes_generic_gf_mul4(block128 *a, const block128 *blocks, const table_4bit htable) {- int i;-- for (i = 0; i < 4; i++) {- block128_xor(a, &blocks[i]);- crypton_aes_generic_gf_mul(a, htable);- }+ br_ghash_ctmul64(a, &htable[0], blocks, 4 * sizeof(block128)); }
@@ -0,0 +1,287 @@+/*+ * AES and GHASH using the PowerISA 2.07 vector instructions, first+ * implemented by POWER8.+ *+ * The instructions themselves come from CRYPTOGAMS, assembled from+ * cbits/asm/aesp8-ppc-*.S and cbits/asm/ghashp8-ppc-*.S; what is here is the+ * glue that puts them behind crypton's branch table. Nothing in this file+ * branches or indexes on a key or on data.+ *+ * == Where the key schedule lives+ *+ * The assembly takes OpenSSL's AES_KEY -- sixty round-key words and a round+ * count, 244 bytes -- and its set_decrypt_key writes a second, complete one+ * rather than sharing ends with the first the way cbits/aes/armv8.c does.+ * Two of those are 488 bytes and aes_key.data is 448, so both do not fit.+ *+ * So the forward schedule is kept there, with the key the caller gave after+ * it, and the inverse is built on the stack by the operations that need it.+ * Those are all bulk -- ECB, CBC and XTS decryption -- so it is one key+ * schedule per call rather than per block. Single-block decryption pays for+ * one too, and is reached by nothing that runs in a loop: OCB and CCM drive+ * the block function in the encrypting direction.+ */++#include <stdint.h>+#include <string.h>+#include <crypton_aes.h>+#include <crypton_bitfn.h>+#include "aes/block128.h"+#include "aes/gf.h"+#include "aes/ppc8.h"++/* OpenSSL's AES_KEY, which is what the assembly was written against */+typedef struct {+ unsigned int rd_key[60];+ int rounds;+} p8_key;++int crypton_aes_p8_set_encrypt_key(const unsigned char *, int, p8_key *);+int crypton_aes_p8_set_decrypt_key(const unsigned char *, int, p8_key *);+void crypton_aes_p8_encrypt(const unsigned char *, unsigned char *, const p8_key *);+void crypton_aes_p8_decrypt(const unsigned char *, unsigned char *, const p8_key *);+void crypton_aes_p8_cbc_encrypt(const unsigned char *, unsigned char *, size_t,+ const p8_key *, unsigned char *, int);+void crypton_aes_p8_ctr32_encrypt_blocks(const unsigned char *, unsigned char *,+ size_t, const p8_key *,+ const unsigned char *);+void crypton_aes_p8_xts_encrypt(const unsigned char *, unsigned char *, size_t,+ const p8_key *, const p8_key *,+ const unsigned char *);+void crypton_aes_p8_xts_decrypt(const unsigned char *, unsigned char *, size_t,+ const p8_key *, const p8_key *,+ const unsigned char *);+/* void * rather than uint64_t *: the assembly loads these with lvx_u and so+ * does not want the alignment a uint64_t pointer would promise, and+ * block128 is packed. */+void crypton_gcm_init_p8(void *Htable, const void *H);+void crypton_gcm_gmult_p8(void *Xi, const void *Htable);+void crypton_gcm_ghash_p8(void *Xi, const void *Htable,+ const unsigned char *inp, size_t len);++#define FORWARD(k) ((p8_key *) (void *) (k)->data)+#define USERKEY(k) ((uint8_t *) (k)->data + sizeof(p8_key))+#define USERLEN(k) (*((uint8_t *) (k)->data + sizeof(p8_key) + 32))++static void inverse(p8_key *dk, aes_key *key)+{+ crypton_aes_p8_set_decrypt_key(USERKEY(key), USERLEN(key) * 8, dk);+}++void crypton_aes_ppc8_init(aes_key *key, uint8_t *origkey, uint8_t size)+{+ if (size != 16 && size != 24 && size != 32)+ return;+ crypton_aes_p8_set_encrypt_key(origkey, size * 8, FORWARD(key));+ memcpy(USERKEY(key), origkey, size);+ USERLEN(key) = size;+}++void crypton_aes_ppc8_encrypt_block(aes_block *output, aes_key *key, aes_block *input)+{+ crypton_aes_p8_encrypt((const unsigned char *) input,+ (unsigned char *) output, FORWARD(key));+}++void crypton_aes_ppc8_decrypt_block(aes_block *output, aes_key *key, aes_block *input)+{+ p8_key dk;++ inverse(&dk, key);+ crypton_aes_p8_decrypt((const unsigned char *) input,+ (unsigned char *) output, &dk);+ memset(&dk, 0, sizeof dk);+}++/* The assembly has no ECB entry: it is the block function in a loop, which+ * is what the generic implementation does too. */+void crypton_aes_ppc8_encrypt_ecb(aes_block *output, aes_key *key, aes_block *input,+ uint32_t nb_blocks)+{+ for (; nb_blocks-- > 0; input++, output++)+ crypton_aes_p8_encrypt((const unsigned char *) input,+ (unsigned char *) output, FORWARD(key));+}++void crypton_aes_ppc8_decrypt_ecb(aes_block *output, aes_key *key, aes_block *input,+ uint32_t nb_blocks)+{+ p8_key dk;++ inverse(&dk, key);+ for (; nb_blocks-- > 0; input++, output++)+ crypton_aes_p8_decrypt((const unsigned char *) input,+ (unsigned char *) output, &dk);+ memset(&dk, 0, sizeof dk);+}++void crypton_aes_ppc8_encrypt_cbc(aes_block *output, aes_key *key, aes_block *iv,+ aes_block *input, uint32_t nb_blocks)+{+ uint8_t ivbuf[16];++ /* a copy, because the assembly writes the last block back through this+ * pointer and the callers of this entry do not expect their IV touched */+ memcpy(ivbuf, iv, 16);+ crypton_aes_p8_cbc_encrypt((const unsigned char *) input,+ (unsigned char *) output,+ (size_t) nb_blocks * 16, FORWARD(key), ivbuf, 1);+}++void crypton_aes_ppc8_decrypt_cbc(aes_block *output, aes_key *key, aes_block *iv,+ aes_block *input, uint32_t nb_blocks)+{+ p8_key dk;+ uint8_t ivbuf[16];++ inverse(&dk, key);+ memcpy(ivbuf, iv, 16);+ crypton_aes_p8_cbc_encrypt((const unsigned char *) input,+ (unsigned char *) output,+ (size_t) nb_blocks * 16, &dk, ivbuf, 0);+ memset(&dk, 0, sizeof dk);+}++/*+ * CTR, which is where the two counters have to be reconciled.+ *+ * crypton counts with block128_inc_be, over the whole 128 bits; the assembly+ * counts over the low 32 only. They agree until that word wraps, so the+ * work is handed over in runs that stop there, and the carry into the upper+ * bits is done here. This is the same arrangement OpenSSL makes for the+ * same reason.+ */+void crypton_aes_ppc8_encrypt_ctr(uint8_t *output, aes_key *key, aes_block *iv,+ uint8_t *input, uint32_t len)+{+ block128 ctr;+ uint32_t nb_blocks = len / 16;+ uint32_t tail = len % 16;+ uint32_t i;++ block128_copy(&ctr, iv);++ while (nb_blocks > 0) {+ uint64_t low = (uint64_t) be32_to_cpu(ctr.d[3]);+ uint64_t room = 0x100000000ULL - low; /* blocks before it wraps */+ uint32_t n;++ /* room is 2^32 when the word is at zero, which does not fit the+ * type the comparison would narrow it to -- and a zero n here+ * would not advance */+ if (room > (uint64_t) nb_blocks)+ room = (uint64_t) nb_blocks;+ n = (uint32_t) room;++ crypton_aes_p8_ctr32_encrypt_blocks((const unsigned char *) input,+ (unsigned char *) output,+ n, FORWARD(key),+ (const unsigned char *) &ctr);+ /* the assembly does not write the counter back */+ for (i = 0; i < n; i++)+ block128_inc_be(&ctr);++ output += (size_t) n * 16;+ input += (size_t) n * 16;+ nb_blocks -= n;+ }++ if (tail != 0) {+ block128 ks;++ crypton_aes_p8_encrypt((const unsigned char *) &ctr,+ (unsigned char *) &ks, FORWARD(key));+ for (i = 0; i < tail; i++)+ output[i] = ks.b[i] ^ input[i];+ }+}++/*+ * XTS. The assembly encrypts the tweak with its second key, unless that key+ * is NULL, in which case it takes the tweak already encrypted -- which is+ * what this needs, because crypton's entry also carries a starting point and+ * the tweak has to be advanced that many doublings before any block is+ * enciphered.+ */+static void xts_tweak(block128 *tweak, aes_key *k2, aes_block *dataunit,+ uint32_t spoint)+{+ block128_copy(tweak, dataunit);+ crypton_aes_p8_encrypt((const unsigned char *) tweak,+ (unsigned char *) tweak, FORWARD(k2));+ while (spoint-- > 0)+ crypton_aes_generic_gf_mulx(tweak);+}++void crypton_aes_ppc8_encrypt_xts(aes_block *output, aes_key *k1, aes_key *k2,+ aes_block *dataunit, uint32_t spoint,+ aes_block *input, uint32_t nb_blocks)+{+ block128 tweak;++ xts_tweak(&tweak, k2, dataunit, spoint);+ crypton_aes_p8_xts_encrypt((const unsigned char *) input,+ (unsigned char *) output,+ (size_t) nb_blocks * 16, FORWARD(k1), NULL,+ (const unsigned char *) &tweak);+}++void crypton_aes_ppc8_decrypt_xts(aes_block *output, aes_key *k1, aes_key *k2,+ aes_block *dataunit, uint32_t spoint,+ aes_block *input, uint32_t nb_blocks)+{+ block128 tweak;+ p8_key dk;++ /* the tweak is enciphered with k2 forwards either way */+ xts_tweak(&tweak, k2, dataunit, spoint);+ inverse(&dk, k1);+ crypton_aes_p8_xts_decrypt((const unsigned char *) input,+ (unsigned char *) output,+ (size_t) nb_blocks * 16, &dk, NULL,+ (const unsigned char *) &tweak);+ memset(&dk, 0, sizeof dk);+}++/*+ * GHASH. The table the assembly builds is 192 bytes, which fits the sixteen+ * blocks the interface names.+ *+ * The two arguments do not take the same convention, which is worth saying+ * because it does not look like an accident until it is checked. H arrives+ * here as the sixteen bytes GCM defines, and gcm_init_p8 wants those as a+ * pair of host-order words -- so they are swapped on a little-endian machine+ * and left alone on a big-endian one, which be64_to_cpu does. The+ * accumulator is the byte string throughout, in and out, and is passed as it+ * stands. OpenSSL makes the same pair of choices.+ *+ * Checked rather than assumed: against crypton's own GHASH, over two+ * different H and with a non-zero accumulator, so that neither a symmetric+ * value nor a zero start could hide a wrong one.+ */+void crypton_aes_ppc8_hinit(table_4bit htable, const block128 *h)+{+ uint64_t H[2];++ memcpy(H, h, sizeof H);+ H[0] = be64_to_cpu(H[0]);+ H[1] = be64_to_cpu(H[1]);+ crypton_gcm_init_p8(htable, H);+}++void crypton_aes_ppc8_gf_mul(block128 *a, const table_4bit htable)+{+ crypton_gcm_gmult_p8(a, htable);+}++void crypton_aes_ppc8_gf_mul4(block128 *a, const block128 *blocks,+ const table_4bit htable)+{+ crypton_gcm_ghash_p8(a, htable, (const unsigned char *) blocks,+ 4 * sizeof(block128));+}++int crypton_aes_ppc8_available(void)+{+ return (crypton_ppc_features() & CRYPTON_PPC_VCRYPTO) != 0;+}
@@ -0,0 +1,29 @@+/*+ * AES and GHASH on PowerISA 2.07, as implemented by cbits/aes/ppc8.c over+ * the CRYPTOGAMS assembly. crypton_aes.c installs these when+ * crypton_aes_ppc8_available says the processor has the instructions.+ */+#ifndef CRYPTON_AES_PPC8_H+#define CRYPTON_AES_PPC8_H++#include "crypton_aes.h"+#include "aes/gf.h"+#include "crypton_cpu.h"++int crypton_aes_ppc8_available(void);++void crypton_aes_ppc8_init(aes_key *key, uint8_t *origkey, uint8_t size);+void crypton_aes_ppc8_encrypt_block(aes_block *output, aes_key *key, aes_block *input);+void crypton_aes_ppc8_decrypt_block(aes_block *output, aes_key *key, aes_block *input);+void crypton_aes_ppc8_encrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks);+void crypton_aes_ppc8_decrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks);+void crypton_aes_ppc8_encrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks);+void crypton_aes_ppc8_decrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks);+void crypton_aes_ppc8_encrypt_ctr(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t len);+void crypton_aes_ppc8_encrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks);+void crypton_aes_ppc8_decrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks);+void crypton_aes_ppc8_hinit(table_4bit htable, const block128 *h);+void crypton_aes_ppc8_gf_mul(block128 *a, const table_4bit htable);+void crypton_aes_ppc8_gf_mul4(block128 *a, const block128 *blocks, const table_4bit htable);++#endif
@@ -37,6 +37,8 @@ #include <crypton_cpu.h> #include <aes/gf.h> #include <aes/x86ni.h>+#include <aes/gcm_vaes_x86.h>+#include <aes/gcm_vaes512_x86.h> #include <aes/block128.h> #include <aes/gcm_x86_asm.h> @@ -207,13 +209,23 @@ return v; } +/* memcpy rather than a cast, as everything else that moves bytes between a+ * crypton structure and a word does since block128 was packed. The cast+ * this replaces was written in 2014, when block128 was a plain union and+ * taking a __m128i * to one promised nothing the type did not already+ * offer. Packing it dropped its alignment to one, and the promise with it:+ * gcc has reported the cast ever since, and it is right to -- the attribute+ * on the local below is what makes the promise true, and nothing obliges+ * the next edit to keep it. Sixteen bytes of memcpy between a __m128i and+ * a sixteen-byte object is one movdqu, or nothing at all when both stay in+ * registers. */ TARGET_AESNI static __m128i gfmul_generic(__m128i tag, const table_4bit htable) {- aes_block _t ALIGNMENT(16);- _mm_store_si128((__m128i *) &_t, tag);+ aes_block _t;+ memcpy(&_t, &tag, sizeof _t); crypton_aes_generic_gf_mul(&_t, htable);- tag = _mm_load_si128((__m128i *) &_t);+ memcpy(&tag, &_t, sizeof tag); return tag; } @@ -357,11 +369,14 @@ htable[0].q[0] = bitfn_swap64(h->q[1]); htable[0].q[1] = bitfn_swap64(h->q[0]); - /* Indices 1..7 get H^2 .. H^8, which is what lets a group of blocks- * fold into one reduction: gf_mul4 uses the first four, the GCM loop- * all eight. The table has sixteen slots. */+ /* Indices 1..15 get H^2 .. H^16, which is what lets a group of blocks+ * fold into one reduction: gf_mul4 uses the first four, the 128-bit+ * GCM loop eight, and the 256-bit one all sixteen. The table has+ * sixteen slots and now they are all used. Filling the upper half+ * costs eight multiplies once per key, which is nothing beside a+ * message. */ p = _mm_loadu_si128((const __m128i *) h);- for (i = 1; i < 8; i++) {+ for (i = 1; i < 16; i++) { p = gfmul_pclmuldq(p, htable); _mm_storeu_si128((__m128i *) &htable[i], _mm_shuffle_epi8(p, bswap_mask));
@@ -335,9 +335,43 @@ gcm->length_input += length; +#ifdef WITH_GCM_VAES512+ /*+ * The widest form the processor has, first: four blocks to an+ * instruction where the 256-bit one below takes two and the assembly+ * after that takes one. Same contract throughout -- whole groups off+ * the front, the counter and the tag left behind.+ */+ if (nb_blocks >= GCM_VAES512_MIN_BLOCKS+ && (crypton_x86_simd_features() & CRYPTON_X86_VAES512)) {+ uint32_t done = crypton_gcm_vaes512_bulk_encrypt(+ output, gcm, key, input, nb_blocks * 16);++ output += done;+ input += done;+ nb_blocks -= done / 16;+ }+#endif+#ifdef WITH_GCM_VAES+ /*+ * The 256-bit instructions next: they take two blocks where the ones+ * below take one, and the assembly that follows is 128-bit+ * throughout.+ */+ if (nb_blocks >= GCM_VAES_MIN_BLOCKS+ && (crypton_x86_simd_features() & CRYPTON_X86_VAES)) {+ uint32_t done = crypton_gcm_vaes_bulk_encrypt(output, gcm, key,+ input,+ nb_blocks * 16);++ output += done;+ input += done;+ nb_blocks -= done / 16;+ }+#endif #if defined(WITH_X86_GCM_ASM) && defined(WITH_PCLMUL) /*- * The stitched assembly first, which takes whole groups of six+ * The stitched assembly next, which takes whole groups of six * blocks off the front of the message and leaves the counter and the * running tag where the loop below expects to find them. It wants * eighteen blocks before it will start, and answers with what it did.@@ -483,6 +517,31 @@ gcm->length_input += length; +#ifdef WITH_GCM_VAES512+ /* as in encryption; the tag is taken over the input here */+ if (nb_blocks >= GCM_VAES512_MIN_BLOCKS+ && (crypton_x86_simd_features() & CRYPTON_X86_VAES512)) {+ uint32_t done = crypton_gcm_vaes512_bulk_decrypt(+ output, gcm, key, input, nb_blocks * 16);++ output += done;+ input += done;+ nb_blocks -= done / 16;+ }+#endif+#ifdef WITH_GCM_VAES+ /* as in encryption; the tag is taken over the input here */+ if (nb_blocks >= GCM_VAES_MIN_BLOCKS+ && (crypton_x86_simd_features() & CRYPTON_X86_VAES)) {+ uint32_t done = crypton_gcm_vaes_bulk_decrypt(output, gcm, key,+ input,+ nb_blocks * 16);++ output += done;+ input += done;+ nb_blocks -= done / 16;+ }+#endif #if defined(WITH_X86_GCM_ASM) && defined(WITH_PCLMUL) /* the same as encryption, except that decryption has nothing to * hold back and so will start on six blocks */
@@ -2,7 +2,7 @@ ## What is here -Two modules from [CRYPTOGAMS](https://github.com/dot-asm/cryptogams), by Andy+Modules from [CRYPTOGAMS](https://github.com/dot-asm/cryptogams), by Andy Polyakov, checked in unmodified together with the translators they need: | generator | what it is |@@ -17,6 +17,8 @@ | `sha1-armv8.pl` | SHA-1 for AArch64 | | `sha512-armv8.pl` | SHA-256 for AArch64 (the generator emits SHA-512 or SHA-256 according to the name it is given, and only the latter is wanted) | | `keccak1600-armv8.pl` | Keccak for AArch64 |+| `aesp8-ppc.pl` | AES for PowerISA 2.07, which POWER8 was the first to implement |+| `ghashp8-ppc.pl` | GHASH for the same, over `vpmsumd` | `x86_64-xlate.pl`, `arm-xlate.pl` and `arm_arch.h` are the machinery those modules use. `generate.sh` runs the generators to produce the `.S` files, which are
@@ -0,0 +1,3658 @@+.machine "any"++.abiversion 2+.text++.align 7+rcon:+.byte 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01+.byte 0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x1b+.byte 0x0c,0x0f,0x0e,0x0d,0x0c,0x0f,0x0e,0x0d,0x0c,0x0f,0x0e,0x0d,0x0c,0x0f,0x0e,0x0d+.byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00+.Lconsts:+ mflr 0+ bcl 20,31,$+4+ mflr 6+ addi 6,6,-0x48+ mtlr 0+ blr +.long 0+.byte 0,12,0x14,0,0,0,0,0+.byte 65,69,83,32,102,111,114,32,80,111,119,101,114,73,83,65,32,50,46,48,55,44,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0+.align 2++.globl crypton_aes_p8_set_encrypt_key+.type crypton_aes_p8_set_encrypt_key,@function+.align 5+crypton_aes_p8_set_encrypt_key:+.localentry crypton_aes_p8_set_encrypt_key,0++.Lset_encrypt_key:+ mflr 11+ std 11,16(1)++ li 6,-1+ cmpldi 3,0+ beq- .Lenc_key_abort+ cmpldi 5,0+ beq- .Lenc_key_abort+ li 6,-2+ cmpwi 4,128+ blt- .Lenc_key_abort+ cmpwi 4,256+ bgt- .Lenc_key_abort+ andi. 0,4,0x3f+ bne- .Lenc_key_abort++ lis 0,0xfff0+ li 12,-1+ or 0,0,0++ bl .Lconsts+ mtlr 11++ neg 9,3+ lvx 1,0,3+ addi 3,3,15+ lvsr 3,0,9+ li 8,0x20+ cmpwi 4,192+ lvx 2,0,3+ vspltisb 5,0x0f+ lvx 4,0,6+ vxor 3,3,5+ lvx 5,8,6+ addi 6,6,0x10+ vperm 1,1,2,3+ li 7,8+ vxor 0,0,0+ mtctr 7++ lvsl 8,0,5+ vspltisb 9,-1+ lvx 10,0,5+ vperm 9,9,0,8++ blt .Loop128+ addi 3,3,8+ beq .L192+ addi 3,3,8+ b .L256++.align 4+.Loop128:+ vperm 3,1,1,5+ vsldoi 6,0,1,12+ vperm 11,1,1,8+ vsel 7,10,11,9+ vor 10,11,11+ .long 0x10632509+ stvx 7,0,5+ addi 5,5,16++ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ vadduwm 4,4,4+ vxor 1,1,3+ bdnz .Loop128++ lvx 4,0,6++ vperm 3,1,1,5+ vsldoi 6,0,1,12+ vperm 11,1,1,8+ vsel 7,10,11,9+ vor 10,11,11+ .long 0x10632509+ stvx 7,0,5+ addi 5,5,16++ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ vadduwm 4,4,4+ vxor 1,1,3++ vperm 3,1,1,5+ vsldoi 6,0,1,12+ vperm 11,1,1,8+ vsel 7,10,11,9+ vor 10,11,11+ .long 0x10632509+ stvx 7,0,5+ addi 5,5,16++ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ vxor 1,1,3+ vperm 11,1,1,8+ vsel 7,10,11,9+ vor 10,11,11+ stvx 7,0,5++ addi 3,5,15+ addi 5,5,0x50++ li 8,10+ b .Ldone++.align 4+.L192:+ lvx 6,0,3+ li 7,4+ vperm 11,1,1,8+ vsel 7,10,11,9+ vor 10,11,11+ stvx 7,0,5+ addi 5,5,16+ vperm 2,2,6,3+ vspltisb 3,8+ mtctr 7+ vsububm 5,5,3++.Loop192:+ vperm 3,2,2,5+ vsldoi 6,0,1,12+ .long 0x10632509++ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6++ vsldoi 7,0,2,8+ vspltw 6,1,3+ vxor 6,6,2+ vsldoi 2,0,2,12+ vadduwm 4,4,4+ vxor 2,2,6+ vxor 1,1,3+ vxor 2,2,3+ vsldoi 7,7,1,8++ vperm 3,2,2,5+ vsldoi 6,0,1,12+ vperm 11,7,7,8+ vsel 7,10,11,9+ vor 10,11,11+ .long 0x10632509+ stvx 7,0,5+ addi 5,5,16++ vsldoi 7,1,2,8+ vxor 1,1,6+ vsldoi 6,0,6,12+ vperm 11,7,7,8+ vsel 7,10,11,9+ vor 10,11,11+ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ stvx 7,0,5+ addi 5,5,16++ vspltw 6,1,3+ vxor 6,6,2+ vsldoi 2,0,2,12+ vadduwm 4,4,4+ vxor 2,2,6+ vxor 1,1,3+ vxor 2,2,3+ vperm 11,1,1,8+ vsel 7,10,11,9+ vor 10,11,11+ stvx 7,0,5+ addi 3,5,15+ addi 5,5,16+ bdnz .Loop192++ li 8,12+ addi 5,5,0x20+ b .Ldone++.align 4+.L256:+ lvx 6,0,3+ li 7,7+ li 8,14+ vperm 11,1,1,8+ vsel 7,10,11,9+ vor 10,11,11+ stvx 7,0,5+ addi 5,5,16+ vperm 2,2,6,3+ mtctr 7++.Loop256:+ vperm 3,2,2,5+ vsldoi 6,0,1,12+ vperm 11,2,2,8+ vsel 7,10,11,9+ vor 10,11,11+ .long 0x10632509+ stvx 7,0,5+ addi 5,5,16++ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ vsldoi 6,0,6,12+ vxor 1,1,6+ vadduwm 4,4,4+ vxor 1,1,3+ vperm 11,1,1,8+ vsel 7,10,11,9+ vor 10,11,11+ stvx 7,0,5+ addi 3,5,15+ addi 5,5,16+ bdz .Ldone++ vspltw 3,1,3+ vsldoi 6,0,2,12+ .long 0x106305C8++ vxor 2,2,6+ vsldoi 6,0,6,12+ vxor 2,2,6+ vsldoi 6,0,6,12+ vxor 2,2,6++ vxor 2,2,3+ b .Loop256++.align 4+.Ldone:+ lvx 2,0,3+ vsel 2,10,2,9+ stvx 2,0,3+ li 6,0+ or 12,12,12+ stw 8,0(5)++.Lenc_key_abort:+ mr 3,6+ blr +.long 0+.byte 0,12,0x14,1,0,0,3,0+.long 0+.size crypton_aes_p8_set_encrypt_key,.-crypton_aes_p8_set_encrypt_key++.globl crypton_aes_p8_set_decrypt_key+.type crypton_aes_p8_set_decrypt_key,@function+.align 5+crypton_aes_p8_set_decrypt_key:+.localentry crypton_aes_p8_set_decrypt_key,0++ stdu 1,-64(1)+ mflr 10+ std 10,64+16(1)+ bl .Lset_encrypt_key+ mtlr 10++ cmpwi 3,0+ bne- .Ldec_key_abort++ slwi 7,8,4+ subi 3,5,240+ srwi 8,8,1+ add 5,3,7+ mtctr 8++.Ldeckey:+ lwz 0, 0(3)+ lwz 6, 4(3)+ lwz 7, 8(3)+ lwz 8, 12(3)+ addi 3,3,16+ lwz 9, 0(5)+ lwz 10,4(5)+ lwz 11,8(5)+ lwz 12,12(5)+ stw 0, 0(5)+ stw 6, 4(5)+ stw 7, 8(5)+ stw 8, 12(5)+ subi 5,5,16+ stw 9, -16(3)+ stw 10,-12(3)+ stw 11,-8(3)+ stw 12,-4(3)+ bdnz .Ldeckey++ xor 3,3,3+.Ldec_key_abort:+ addi 1,1,64+ blr +.long 0+.byte 0,12,4,1,0x80,0,3,0+.long 0+.size crypton_aes_p8_set_decrypt_key,.-crypton_aes_p8_set_decrypt_key+.globl crypton_aes_p8_encrypt+.type crypton_aes_p8_encrypt,@function+.align 5+crypton_aes_p8_encrypt:+.localentry crypton_aes_p8_encrypt,0++ lwz 6,240(5)+ lis 0,0xfc00+ li 12,-1+ li 7,15+ or 0,0,0++ lvx 0,0,3+ neg 11,4+ lvx 1,7,3+ lvsl 2,0,3+ vspltisb 4,0x0f+ lvsr 3,0,11+ vxor 2,2,4+ li 7,16+ vperm 0,0,1,2+ lvx 1,0,5+ lvsr 5,0,5+ srwi 6,6,1+ lvx 2,7,5+ addi 7,7,16+ subi 6,6,1+ vperm 1,2,1,5++ vxor 0,0,1+ lvx 1,7,5+ addi 7,7,16+ mtctr 6++.Loop_enc:+ vperm 2,1,2,5+ .long 0x10001508+ lvx 2,7,5+ addi 7,7,16+ vperm 1,2,1,5+ .long 0x10000D08+ lvx 1,7,5+ addi 7,7,16+ bdnz .Loop_enc++ vperm 2,1,2,5+ .long 0x10001508+ lvx 2,7,5+ vperm 1,2,1,5+ .long 0x10000D09++ vspltisb 2,-1+ vxor 1,1,1+ li 7,15+ vperm 2,2,1,3+ vxor 3,3,4+ lvx 1,0,4+ vperm 0,0,0,3+ vsel 1,1,0,2+ lvx 4,7,4+ stvx 1,0,4+ vsel 0,0,4,2+ stvx 0,7,4++ or 12,12,12+ blr +.long 0+.byte 0,12,0x14,0,0,0,3,0+.long 0+.size crypton_aes_p8_encrypt,.-crypton_aes_p8_encrypt+.globl crypton_aes_p8_decrypt+.type crypton_aes_p8_decrypt,@function+.align 5+crypton_aes_p8_decrypt:+.localentry crypton_aes_p8_decrypt,0++ lwz 6,240(5)+ lis 0,0xfc00+ li 12,-1+ li 7,15+ or 0,0,0++ lvx 0,0,3+ neg 11,4+ lvx 1,7,3+ lvsl 2,0,3+ vspltisb 4,0x0f+ lvsr 3,0,11+ vxor 2,2,4+ li 7,16+ vperm 0,0,1,2+ lvx 1,0,5+ lvsr 5,0,5+ srwi 6,6,1+ lvx 2,7,5+ addi 7,7,16+ subi 6,6,1+ vperm 1,2,1,5++ vxor 0,0,1+ lvx 1,7,5+ addi 7,7,16+ mtctr 6++.Loop_dec:+ vperm 2,1,2,5+ .long 0x10001548+ lvx 2,7,5+ addi 7,7,16+ vperm 1,2,1,5+ .long 0x10000D48+ lvx 1,7,5+ addi 7,7,16+ bdnz .Loop_dec++ vperm 2,1,2,5+ .long 0x10001548+ lvx 2,7,5+ vperm 1,2,1,5+ .long 0x10000D49++ vspltisb 2,-1+ vxor 1,1,1+ li 7,15+ vperm 2,2,1,3+ vxor 3,3,4+ lvx 1,0,4+ vperm 0,0,0,3+ vsel 1,1,0,2+ lvx 4,7,4+ stvx 1,0,4+ vsel 0,0,4,2+ stvx 0,7,4++ or 12,12,12+ blr +.long 0+.byte 0,12,0x14,0,0,0,3,0+.long 0+.size crypton_aes_p8_decrypt,.-crypton_aes_p8_decrypt+.globl crypton_aes_p8_cbc_encrypt+.type crypton_aes_p8_cbc_encrypt,@function+.align 5+crypton_aes_p8_cbc_encrypt:+.localentry crypton_aes_p8_cbc_encrypt,0++ cmpldi 5,16+ .long 0x4dc00020++ cmpwi 8,0+ lis 0,0xffe0+ li 12,-1+ or 0,0,0++ li 10,15+ vxor 0,0,0+ vspltisb 3,0x0f++ lvx 4,0,7+ lvsl 6,0,7+ lvx 5,10,7+ vxor 6,6,3+ vperm 4,4,5,6++ neg 11,3+ lvsr 10,0,6+ lwz 9,240(6)++ lvsr 6,0,11+ lvx 5,0,3+ addi 3,3,15+ vxor 6,6,3++ lvsl 8,0,4+ vspltisb 9,-1+ lvx 7,0,4+ vperm 9,9,0,8+ vxor 8,8,3++ srwi 9,9,1+ li 10,16+ subi 9,9,1+ beq .Lcbc_dec++.Lcbc_enc:+ vor 2,5,5+ lvx 5,0,3+ addi 3,3,16+ mtctr 9+ subi 5,5,16++ lvx 0,0,6+ vperm 2,2,5,6+ lvx 1,10,6+ addi 10,10,16+ vperm 0,1,0,10+ vxor 2,2,0+ lvx 0,10,6+ addi 10,10,16+ vxor 2,2,4++.Loop_cbc_enc:+ vperm 1,0,1,10+ .long 0x10420D08+ lvx 1,10,6+ addi 10,10,16+ vperm 0,1,0,10+ .long 0x10420508+ lvx 0,10,6+ addi 10,10,16+ bdnz .Loop_cbc_enc++ vperm 1,0,1,10+ .long 0x10420D08+ lvx 1,10,6+ li 10,16+ vperm 0,1,0,10+ .long 0x10820509+ cmpldi 5,16++ vperm 3,4,4,8+ vsel 2,7,3,9+ vor 7,3,3+ stvx 2,0,4+ addi 4,4,16+ bge .Lcbc_enc++ b .Lcbc_done++.align 4+.Lcbc_dec:+ cmpldi 5,128+ bge _aesp8_cbc_decrypt8x+ vor 3,5,5+ lvx 5,0,3+ addi 3,3,16+ mtctr 9+ subi 5,5,16++ lvx 0,0,6+ vperm 3,3,5,6+ lvx 1,10,6+ addi 10,10,16+ vperm 0,1,0,10+ vxor 2,3,0+ lvx 0,10,6+ addi 10,10,16++.Loop_cbc_dec:+ vperm 1,0,1,10+ .long 0x10420D48+ lvx 1,10,6+ addi 10,10,16+ vperm 0,1,0,10+ .long 0x10420548+ lvx 0,10,6+ addi 10,10,16+ bdnz .Loop_cbc_dec++ vperm 1,0,1,10+ .long 0x10420D48+ lvx 1,10,6+ li 10,16+ vperm 0,1,0,10+ .long 0x10420549+ cmpldi 5,16++ vxor 2,2,4+ vor 4,3,3+ vperm 3,2,2,8+ vsel 2,7,3,9+ vor 7,3,3+ stvx 2,0,4+ addi 4,4,16+ bge .Lcbc_dec++.Lcbc_done:+ addi 4,4,-1+ lvx 2,0,4+ vsel 2,7,2,9+ stvx 2,0,4++ neg 8,7+ li 10,15+ vxor 0,0,0+ vspltisb 9,-1+ vspltisb 3,0x0f+ lvsr 8,0,8+ vperm 9,9,0,8+ vxor 8,8,3+ lvx 7,0,7+ vperm 4,4,4,8+ vsel 2,7,4,9+ lvx 5,10,7+ stvx 2,0,7+ vsel 2,4,5,9+ stvx 2,10,7++ or 12,12,12+ blr +.long 0+.byte 0,12,0x14,0,0,0,6,0+.long 0+.align 5+_aesp8_cbc_decrypt8x:+ stdu 1,-448(1)+ li 10,207+ li 11,223+ stvx 20,10,1+ addi 10,10,32+ stvx 21,11,1+ addi 11,11,32+ stvx 22,10,1+ addi 10,10,32+ stvx 23,11,1+ addi 11,11,32+ stvx 24,10,1+ addi 10,10,32+ stvx 25,11,1+ addi 11,11,32+ stvx 26,10,1+ addi 10,10,32+ stvx 27,11,1+ addi 11,11,32+ stvx 28,10,1+ addi 10,10,32+ stvx 29,11,1+ addi 11,11,32+ stvx 30,10,1+ stvx 31,11,1+ li 0,-1+ stw 12,396(1)+ li 8,0x10+ std 26,400(1)+ li 26,0x20+ std 27,408(1)+ li 27,0x30+ std 28,416(1)+ li 28,0x40+ std 29,424(1)+ li 29,0x50+ std 30,432(1)+ li 30,0x60+ std 31,440(1)+ li 31,0x70+ or 0,0,0++ subi 9,9,3+ subi 5,5,128++ lvx 23,0,6+ lvx 30,8,6+ addi 6,6,0x20+ lvx 31,0,6+ vperm 23,30,23,10+ addi 11,1,64+15+ mtctr 9++.Load_cbc_dec_key:+ vperm 24,31,30,10+ lvx 30,8,6+ addi 6,6,0x20+ stvx 24,0,11+ vperm 25,30,31,10+ lvx 31,0,6+ stvx 25,8,11+ addi 11,11,0x20+ bdnz .Load_cbc_dec_key++ lvx 26,8,6+ vperm 24,31,30,10+ lvx 27,26,6+ stvx 24,0,11+ vperm 25,26,31,10+ lvx 28,27,6+ stvx 25,8,11+ addi 11,1,64+15+ vperm 26,27,26,10+ lvx 29,28,6+ vperm 27,28,27,10+ lvx 30,29,6+ vperm 28,29,28,10+ lvx 31,30,6+ vperm 29,30,29,10+ lvx 14,31,6+ vperm 30,31,30,10+ lvx 24,0,11+ vperm 31,14,31,10+ lvx 25,8,11++++ subi 3,3,15++ li 10,8+ .long 0x7C001E99+ lvsl 6,0,10+ vspltisb 3,0x0f+ .long 0x7C281E99+ vxor 6,6,3+ .long 0x7C5A1E99+ vperm 0,0,0,6+ .long 0x7C7B1E99+ vperm 1,1,1,6+ .long 0x7D5C1E99+ vperm 2,2,2,6+ vxor 14,0,23+ .long 0x7D7D1E99+ vperm 3,3,3,6+ vxor 15,1,23+ .long 0x7D9E1E99+ vperm 10,10,10,6+ vxor 16,2,23+ .long 0x7DBF1E99+ addi 3,3,0x80+ vperm 11,11,11,6+ vxor 17,3,23+ vperm 12,12,12,6+ vxor 18,10,23+ vperm 13,13,13,6+ vxor 19,11,23+ vxor 20,12,23+ vxor 21,13,23++ mtctr 9+ b .Loop_cbc_dec8x+.align 5+.Loop_cbc_dec8x:+ .long 0x11CEC548+ .long 0x11EFC548+ .long 0x1210C548+ .long 0x1231C548+ .long 0x1252C548+ .long 0x1273C548+ .long 0x1294C548+ .long 0x12B5C548+ lvx 24,26,11+ addi 11,11,0x20++ .long 0x11CECD48+ .long 0x11EFCD48+ .long 0x1210CD48+ .long 0x1231CD48+ .long 0x1252CD48+ .long 0x1273CD48+ .long 0x1294CD48+ .long 0x12B5CD48+ lvx 25,8,11+ bdnz .Loop_cbc_dec8x++ subic 5,5,128+ .long 0x11CEC548+ .long 0x11EFC548+ .long 0x1210C548+ .long 0x1231C548+ .long 0x1252C548+ .long 0x1273C548+ .long 0x1294C548+ .long 0x12B5C548++ subfe. 0,0,0+ .long 0x11CECD48+ .long 0x11EFCD48+ .long 0x1210CD48+ .long 0x1231CD48+ .long 0x1252CD48+ .long 0x1273CD48+ .long 0x1294CD48+ .long 0x12B5CD48++ and 0,0,5+ .long 0x11CED548+ .long 0x11EFD548+ .long 0x1210D548+ .long 0x1231D548+ .long 0x1252D548+ .long 0x1273D548+ .long 0x1294D548+ .long 0x12B5D548++ add 3,3,0++++ .long 0x11CEDD48+ .long 0x11EFDD48+ .long 0x1210DD48+ .long 0x1231DD48+ .long 0x1252DD48+ .long 0x1273DD48+ .long 0x1294DD48+ .long 0x12B5DD48++ addi 11,1,64+15+ .long 0x11CEE548+ .long 0x11EFE548+ .long 0x1210E548+ .long 0x1231E548+ .long 0x1252E548+ .long 0x1273E548+ .long 0x1294E548+ .long 0x12B5E548+ lvx 24,0,11++ .long 0x11CEED48+ .long 0x11EFED48+ .long 0x1210ED48+ .long 0x1231ED48+ .long 0x1252ED48+ .long 0x1273ED48+ .long 0x1294ED48+ .long 0x12B5ED48+ lvx 25,8,11++ .long 0x11CEF548+ vxor 4,4,31+ .long 0x11EFF548+ vxor 0,0,31+ .long 0x1210F548+ vxor 1,1,31+ .long 0x1231F548+ vxor 2,2,31+ .long 0x1252F548+ vxor 3,3,31+ .long 0x1273F548+ vxor 10,10,31+ .long 0x1294F548+ vxor 11,11,31+ .long 0x12B5F548+ vxor 12,12,31++ .long 0x11CE2549+ .long 0x11EF0549+ .long 0x7C001E99+ .long 0x12100D49+ .long 0x7C281E99+ .long 0x12311549+ vperm 0,0,0,6+ .long 0x7C5A1E99+ .long 0x12521D49+ vperm 1,1,1,6+ .long 0x7C7B1E99+ .long 0x12735549+ vperm 2,2,2,6+ .long 0x7D5C1E99+ .long 0x12945D49+ vperm 3,3,3,6+ .long 0x7D7D1E99+ .long 0x12B56549+ vperm 10,10,10,6+ .long 0x7D9E1E99+ vor 4,13,13+ vperm 11,11,11,6+ .long 0x7DBF1E99+ addi 3,3,0x80++ vperm 14,14,14,6+ vperm 15,15,15,6+ .long 0x7DC02799+ vperm 12,12,12,6+ vxor 14,0,23+ vperm 16,16,16,6+ .long 0x7DE82799+ vperm 13,13,13,6+ vxor 15,1,23+ vperm 17,17,17,6+ .long 0x7E1A2799+ vxor 16,2,23+ vperm 18,18,18,6+ .long 0x7E3B2799+ vxor 17,3,23+ vperm 19,19,19,6+ .long 0x7E5C2799+ vxor 18,10,23+ vperm 20,20,20,6+ .long 0x7E7D2799+ vxor 19,11,23+ vperm 21,21,21,6+ .long 0x7E9E2799+ vxor 20,12,23+ .long 0x7EBF2799+ addi 4,4,0x80+ vxor 21,13,23++ mtctr 9+ beq .Loop_cbc_dec8x++ addic. 5,5,128+ beq .Lcbc_dec8x_done+ nop + nop ++.Loop_cbc_dec8x_tail:+ .long 0x11EFC548+ .long 0x1210C548+ .long 0x1231C548+ .long 0x1252C548+ .long 0x1273C548+ .long 0x1294C548+ .long 0x12B5C548+ lvx 24,26,11+ addi 11,11,0x20++ .long 0x11EFCD48+ .long 0x1210CD48+ .long 0x1231CD48+ .long 0x1252CD48+ .long 0x1273CD48+ .long 0x1294CD48+ .long 0x12B5CD48+ lvx 25,8,11+ bdnz .Loop_cbc_dec8x_tail++ .long 0x11EFC548+ .long 0x1210C548+ .long 0x1231C548+ .long 0x1252C548+ .long 0x1273C548+ .long 0x1294C548+ .long 0x12B5C548++ .long 0x11EFCD48+ .long 0x1210CD48+ .long 0x1231CD48+ .long 0x1252CD48+ .long 0x1273CD48+ .long 0x1294CD48+ .long 0x12B5CD48++ .long 0x11EFD548+ .long 0x1210D548+ .long 0x1231D548+ .long 0x1252D548+ .long 0x1273D548+ .long 0x1294D548+ .long 0x12B5D548++ .long 0x11EFDD48+ .long 0x1210DD48+ .long 0x1231DD48+ .long 0x1252DD48+ .long 0x1273DD48+ .long 0x1294DD48+ .long 0x12B5DD48++ .long 0x11EFE548+ .long 0x1210E548+ .long 0x1231E548+ .long 0x1252E548+ .long 0x1273E548+ .long 0x1294E548+ .long 0x12B5E548++ .long 0x11EFED48+ .long 0x1210ED48+ .long 0x1231ED48+ .long 0x1252ED48+ .long 0x1273ED48+ .long 0x1294ED48+ .long 0x12B5ED48++ .long 0x11EFF548+ vxor 4,4,31+ .long 0x1210F548+ vxor 1,1,31+ .long 0x1231F548+ vxor 2,2,31+ .long 0x1252F548+ vxor 3,3,31+ .long 0x1273F548+ vxor 10,10,31+ .long 0x1294F548+ vxor 11,11,31+ .long 0x12B5F548+ vxor 12,12,31++ cmplwi 5,32+ blt .Lcbc_dec8x_one+ nop + beq .Lcbc_dec8x_two+ cmplwi 5,64+ blt .Lcbc_dec8x_three+ nop + beq .Lcbc_dec8x_four+ cmplwi 5,96+ blt .Lcbc_dec8x_five+ nop + beq .Lcbc_dec8x_six++.Lcbc_dec8x_seven:+ .long 0x11EF2549+ .long 0x12100D49+ .long 0x12311549+ .long 0x12521D49+ .long 0x12735549+ .long 0x12945D49+ .long 0x12B56549+ vor 4,13,13++ vperm 15,15,15,6+ vperm 16,16,16,6+ .long 0x7DE02799+ vperm 17,17,17,6+ .long 0x7E082799+ vperm 18,18,18,6+ .long 0x7E3A2799+ vperm 19,19,19,6+ .long 0x7E5B2799+ vperm 20,20,20,6+ .long 0x7E7C2799+ vperm 21,21,21,6+ .long 0x7E9D2799+ .long 0x7EBE2799+ addi 4,4,0x70+ b .Lcbc_dec8x_done++.align 5+.Lcbc_dec8x_six:+ .long 0x12102549+ .long 0x12311549+ .long 0x12521D49+ .long 0x12735549+ .long 0x12945D49+ .long 0x12B56549+ vor 4,13,13++ vperm 16,16,16,6+ vperm 17,17,17,6+ .long 0x7E002799+ vperm 18,18,18,6+ .long 0x7E282799+ vperm 19,19,19,6+ .long 0x7E5A2799+ vperm 20,20,20,6+ .long 0x7E7B2799+ vperm 21,21,21,6+ .long 0x7E9C2799+ .long 0x7EBD2799+ addi 4,4,0x60+ b .Lcbc_dec8x_done++.align 5+.Lcbc_dec8x_five:+ .long 0x12312549+ .long 0x12521D49+ .long 0x12735549+ .long 0x12945D49+ .long 0x12B56549+ vor 4,13,13++ vperm 17,17,17,6+ vperm 18,18,18,6+ .long 0x7E202799+ vperm 19,19,19,6+ .long 0x7E482799+ vperm 20,20,20,6+ .long 0x7E7A2799+ vperm 21,21,21,6+ .long 0x7E9B2799+ .long 0x7EBC2799+ addi 4,4,0x50+ b .Lcbc_dec8x_done++.align 5+.Lcbc_dec8x_four:+ .long 0x12522549+ .long 0x12735549+ .long 0x12945D49+ .long 0x12B56549+ vor 4,13,13++ vperm 18,18,18,6+ vperm 19,19,19,6+ .long 0x7E402799+ vperm 20,20,20,6+ .long 0x7E682799+ vperm 21,21,21,6+ .long 0x7E9A2799+ .long 0x7EBB2799+ addi 4,4,0x40+ b .Lcbc_dec8x_done++.align 5+.Lcbc_dec8x_three:+ .long 0x12732549+ .long 0x12945D49+ .long 0x12B56549+ vor 4,13,13++ vperm 19,19,19,6+ vperm 20,20,20,6+ .long 0x7E602799+ vperm 21,21,21,6+ .long 0x7E882799+ .long 0x7EBA2799+ addi 4,4,0x30+ b .Lcbc_dec8x_done++.align 5+.Lcbc_dec8x_two:+ .long 0x12942549+ .long 0x12B56549+ vor 4,13,13++ vperm 20,20,20,6+ vperm 21,21,21,6+ .long 0x7E802799+ .long 0x7EA82799+ addi 4,4,0x20+ b .Lcbc_dec8x_done++.align 5+.Lcbc_dec8x_one:+ .long 0x12B52549+ vor 4,13,13++ vperm 21,21,21,6+ .long 0x7EA02799+ addi 4,4,0x10++.Lcbc_dec8x_done:+ vperm 4,4,4,6+ .long 0x7C803F99++ li 10,79+ li 11,95+ stvx 6,10,1+ addi 10,10,32+ stvx 6,11,1+ addi 11,11,32+ stvx 6,10,1+ addi 10,10,32+ stvx 6,11,1+ addi 11,11,32+ stvx 6,10,1+ addi 10,10,32+ stvx 6,11,1+ addi 11,11,32+ stvx 6,10,1+ addi 10,10,32+ stvx 6,11,1+ addi 11,11,32++ or 12,12,12+ lvx 20,10,1+ addi 10,10,32+ lvx 21,11,1+ addi 11,11,32+ lvx 22,10,1+ addi 10,10,32+ lvx 23,11,1+ addi 11,11,32+ lvx 24,10,1+ addi 10,10,32+ lvx 25,11,1+ addi 11,11,32+ lvx 26,10,1+ addi 10,10,32+ lvx 27,11,1+ addi 11,11,32+ lvx 28,10,1+ addi 10,10,32+ lvx 29,11,1+ addi 11,11,32+ lvx 30,10,1+ lvx 31,11,1+ ld 26,400(1)+ ld 27,408(1)+ ld 28,416(1)+ ld 29,424(1)+ ld 30,432(1)+ ld 31,440(1)+ addi 1,1,448+ blr +.long 0+.byte 0,12,0x04,0,0x80,6,6,0+.long 0+.size crypton_aes_p8_cbc_encrypt,.-crypton_aes_p8_cbc_encrypt+.globl crypton_aes_p8_ctr32_encrypt_blocks+.type crypton_aes_p8_ctr32_encrypt_blocks,@function+.align 5+crypton_aes_p8_ctr32_encrypt_blocks:+.localentry crypton_aes_p8_ctr32_encrypt_blocks,0++ cmpldi 5,1+ .long 0x4dc00020++ lis 0,0xfff0+ li 12,-1+ or 0,0,0++ li 10,15+ vxor 0,0,0+ vspltisb 3,0x0f++ lvx 4,0,7+ lvsl 6,0,7+ lvx 5,10,7+ vspltisb 11,1+ vxor 6,6,3+ vperm 4,4,5,6+ vsldoi 11,0,11,1++ neg 11,3+ lvsr 10,0,6+ lwz 9,240(6)++ lvsr 6,0,11+ lvx 5,0,3+ addi 3,3,15+ vxor 6,6,3++ srwi 9,9,1+ li 10,16+ subi 9,9,1++ cmpldi 5,8+ bge _aesp8_ctr32_encrypt8x++ lvsl 8,0,4+ vspltisb 9,-1+ lvx 7,0,4+ vperm 9,9,0,8+ vxor 8,8,3++ lvx 0,0,6+ mtctr 9+ lvx 1,10,6+ addi 10,10,16+ vperm 0,1,0,10+ vxor 2,4,0+ lvx 0,10,6+ addi 10,10,16+ b .Loop_ctr32_enc++.align 5+.Loop_ctr32_enc:+ vperm 1,0,1,10+ .long 0x10420D08+ lvx 1,10,6+ addi 10,10,16+ vperm 0,1,0,10+ .long 0x10420508+ lvx 0,10,6+ addi 10,10,16+ bdnz .Loop_ctr32_enc++ vadduwm 4,4,11+ vor 3,5,5+ lvx 5,0,3+ addi 3,3,16+ subic. 5,5,1++ vperm 1,0,1,10+ .long 0x10420D08+ lvx 1,10,6+ vperm 3,3,5,6+ li 10,16+ vperm 1,1,0,10+ lvx 0,0,6+ vxor 3,3,1+ .long 0x10421D09++ lvx 1,10,6+ addi 10,10,16+ vperm 2,2,2,8+ vsel 3,7,2,9+ mtctr 9+ vperm 0,1,0,10+ vor 7,2,2+ vxor 2,4,0+ lvx 0,10,6+ addi 10,10,16+ stvx 3,0,4+ addi 4,4,16+ bne .Loop_ctr32_enc++ addi 4,4,-1+ lvx 2,0,4+ vsel 2,7,2,9+ stvx 2,0,4++ or 12,12,12+ blr +.long 0+.byte 0,12,0x14,0,0,0,6,0+.long 0+.align 5+_aesp8_ctr32_encrypt8x:+ stdu 1,-448(1)+ li 10,207+ li 11,223+ stvx 20,10,1+ addi 10,10,32+ stvx 21,11,1+ addi 11,11,32+ stvx 22,10,1+ addi 10,10,32+ stvx 23,11,1+ addi 11,11,32+ stvx 24,10,1+ addi 10,10,32+ stvx 25,11,1+ addi 11,11,32+ stvx 26,10,1+ addi 10,10,32+ stvx 27,11,1+ addi 11,11,32+ stvx 28,10,1+ addi 10,10,32+ stvx 29,11,1+ addi 11,11,32+ stvx 30,10,1+ stvx 31,11,1+ li 0,-1+ stw 12,396(1)+ li 8,0x10+ std 26,400(1)+ li 26,0x20+ std 27,408(1)+ li 27,0x30+ std 28,416(1)+ li 28,0x40+ std 29,424(1)+ li 29,0x50+ std 30,432(1)+ li 30,0x60+ std 31,440(1)+ li 31,0x70+ or 0,0,0++ subi 9,9,3++ lvx 23,0,6+ lvx 30,8,6+ addi 6,6,0x20+ lvx 31,0,6+ vperm 23,30,23,10+ addi 11,1,64+15+ mtctr 9++.Load_ctr32_enc_key:+ vperm 24,31,30,10+ lvx 30,8,6+ addi 6,6,0x20+ stvx 24,0,11+ vperm 25,30,31,10+ lvx 31,0,6+ stvx 25,8,11+ addi 11,11,0x20+ bdnz .Load_ctr32_enc_key++ lvx 26,8,6+ vperm 24,31,30,10+ lvx 27,26,6+ stvx 24,0,11+ vperm 25,26,31,10+ lvx 28,27,6+ stvx 25,8,11+ addi 11,1,64+15+ vperm 26,27,26,10+ lvx 29,28,6+ vperm 27,28,27,10+ lvx 30,29,6+ vperm 28,29,28,10+ lvx 31,30,6+ vperm 29,30,29,10+ lvx 15,31,6+ vperm 30,31,30,10+ lvx 24,0,11+ vperm 31,15,31,10+ lvx 25,8,11++ vadduwm 7,11,11+ subi 3,3,15+ sldi 5,5,4++ vadduwm 16,4,11+ vadduwm 17,4,7+ vxor 15,4,23+ li 10,8+ vadduwm 18,16,7+ vxor 16,16,23+ lvsl 6,0,10+ vadduwm 19,17,7+ vxor 17,17,23+ vspltisb 3,0x0f+ vadduwm 20,18,7+ vxor 18,18,23+ vxor 6,6,3+ vadduwm 21,19,7+ vxor 19,19,23+ vadduwm 22,20,7+ vxor 20,20,23+ vadduwm 4,21,7+ vxor 21,21,23+ vxor 22,22,23++ mtctr 9+ b .Loop_ctr32_enc8x+.align 5+.Loop_ctr32_enc8x:+ .long 0x11EFC508+ .long 0x1210C508+ .long 0x1231C508+ .long 0x1252C508+ .long 0x1273C508+ .long 0x1294C508+ .long 0x12B5C508+ .long 0x12D6C508+.Loop_ctr32_enc8x_middle:+ lvx 24,26,11+ addi 11,11,0x20++ .long 0x11EFCD08+ .long 0x1210CD08+ .long 0x1231CD08+ .long 0x1252CD08+ .long 0x1273CD08+ .long 0x1294CD08+ .long 0x12B5CD08+ .long 0x12D6CD08+ lvx 25,8,11+ bdnz .Loop_ctr32_enc8x++ subic 11,5,256+ .long 0x11EFC508+ .long 0x1210C508+ .long 0x1231C508+ .long 0x1252C508+ .long 0x1273C508+ .long 0x1294C508+ .long 0x12B5C508+ .long 0x12D6C508++ subfe 0,0,0+ .long 0x11EFCD08+ .long 0x1210CD08+ .long 0x1231CD08+ .long 0x1252CD08+ .long 0x1273CD08+ .long 0x1294CD08+ .long 0x12B5CD08+ .long 0x12D6CD08++ and 0,0,11+ addi 11,1,64+15+ .long 0x11EFD508+ .long 0x1210D508+ .long 0x1231D508+ .long 0x1252D508+ .long 0x1273D508+ .long 0x1294D508+ .long 0x12B5D508+ .long 0x12D6D508+ lvx 24,0,11++ subic 5,5,129+ .long 0x11EFDD08+ addi 5,5,1+ .long 0x1210DD08+ .long 0x1231DD08+ .long 0x1252DD08+ .long 0x1273DD08+ .long 0x1294DD08+ .long 0x12B5DD08+ .long 0x12D6DD08+ lvx 25,8,11++ .long 0x11EFE508+ .long 0x7C001E99+ .long 0x1210E508+ .long 0x7C281E99+ .long 0x1231E508+ .long 0x7C5A1E99+ .long 0x1252E508+ .long 0x7C7B1E99+ .long 0x1273E508+ .long 0x7D5C1E99+ .long 0x1294E508+ .long 0x7D9D1E99+ .long 0x12B5E508+ .long 0x7DBE1E99+ .long 0x12D6E508+ .long 0x7DDF1E99+ addi 3,3,0x80++ .long 0x11EFED08+ vperm 0,0,0,6+ .long 0x1210ED08+ vperm 1,1,1,6+ .long 0x1231ED08+ vperm 2,2,2,6+ .long 0x1252ED08+ vperm 3,3,3,6+ .long 0x1273ED08+ vperm 10,10,10,6+ .long 0x1294ED08+ vperm 12,12,12,6+ .long 0x12B5ED08+ vperm 13,13,13,6+ .long 0x12D6ED08+ vperm 14,14,14,6++ add 3,3,0++++ subfe. 0,0,0+ .long 0x11EFF508+ vxor 0,0,31+ .long 0x1210F508+ vxor 1,1,31+ .long 0x1231F508+ vxor 2,2,31+ .long 0x1252F508+ vxor 3,3,31+ .long 0x1273F508+ vxor 10,10,31+ .long 0x1294F508+ vxor 12,12,31+ .long 0x12B5F508+ vxor 13,13,31+ .long 0x12D6F508+ vxor 14,14,31++ bne .Lctr32_enc8x_break++ .long 0x100F0509+ .long 0x10300D09+ vadduwm 16,4,11+ .long 0x10511509+ vadduwm 17,4,7+ vxor 15,4,23+ .long 0x10721D09+ vadduwm 18,16,7+ vxor 16,16,23+ .long 0x11535509+ vadduwm 19,17,7+ vxor 17,17,23+ .long 0x11946509+ vadduwm 20,18,7+ vxor 18,18,23+ .long 0x11B56D09+ vadduwm 21,19,7+ vxor 19,19,23+ .long 0x11D67509+ vadduwm 22,20,7+ vxor 20,20,23+ vperm 0,0,0,6+ vadduwm 4,21,7+ vxor 21,21,23+ vperm 1,1,1,6+ vxor 22,22,23+ mtctr 9++ .long 0x11EFC508+ .long 0x7C002799+ vperm 2,2,2,6+ .long 0x1210C508+ .long 0x7C282799+ vperm 3,3,3,6+ .long 0x1231C508+ .long 0x7C5A2799+ vperm 10,10,10,6+ .long 0x1252C508+ .long 0x7C7B2799+ vperm 12,12,12,6+ .long 0x1273C508+ .long 0x7D5C2799+ vperm 13,13,13,6+ .long 0x1294C508+ .long 0x7D9D2799+ vperm 14,14,14,6+ .long 0x12B5C508+ .long 0x7DBE2799+ .long 0x12D6C508+ .long 0x7DDF2799+ addi 4,4,0x80++ b .Loop_ctr32_enc8x_middle++.align 5+.Lctr32_enc8x_break:+ cmpwi 5,-0x60+ blt .Lctr32_enc8x_one+ nop + beq .Lctr32_enc8x_two+ cmpwi 5,-0x40+ blt .Lctr32_enc8x_three+ nop + beq .Lctr32_enc8x_four+ cmpwi 5,-0x20+ blt .Lctr32_enc8x_five+ nop + beq .Lctr32_enc8x_six+ cmpwi 5,0x00+ blt .Lctr32_enc8x_seven++.Lctr32_enc8x_eight:+ .long 0x11EF0509+ .long 0x12100D09+ .long 0x12311509+ .long 0x12521D09+ .long 0x12735509+ .long 0x12946509+ .long 0x12B56D09+ .long 0x12D67509++ vperm 15,15,15,6+ vperm 16,16,16,6+ .long 0x7DE02799+ vperm 17,17,17,6+ .long 0x7E082799+ vperm 18,18,18,6+ .long 0x7E3A2799+ vperm 19,19,19,6+ .long 0x7E5B2799+ vperm 20,20,20,6+ .long 0x7E7C2799+ vperm 21,21,21,6+ .long 0x7E9D2799+ vperm 22,22,22,6+ .long 0x7EBE2799+ .long 0x7EDF2799+ addi 4,4,0x80+ b .Lctr32_enc8x_done++.align 5+.Lctr32_enc8x_seven:+ .long 0x11EF0D09+ .long 0x12101509+ .long 0x12311D09+ .long 0x12525509+ .long 0x12736509+ .long 0x12946D09+ .long 0x12B57509++ vperm 15,15,15,6+ vperm 16,16,16,6+ .long 0x7DE02799+ vperm 17,17,17,6+ .long 0x7E082799+ vperm 18,18,18,6+ .long 0x7E3A2799+ vperm 19,19,19,6+ .long 0x7E5B2799+ vperm 20,20,20,6+ .long 0x7E7C2799+ vperm 21,21,21,6+ .long 0x7E9D2799+ .long 0x7EBE2799+ addi 4,4,0x70+ b .Lctr32_enc8x_done++.align 5+.Lctr32_enc8x_six:+ .long 0x11EF1509+ .long 0x12101D09+ .long 0x12315509+ .long 0x12526509+ .long 0x12736D09+ .long 0x12947509++ vperm 15,15,15,6+ vperm 16,16,16,6+ .long 0x7DE02799+ vperm 17,17,17,6+ .long 0x7E082799+ vperm 18,18,18,6+ .long 0x7E3A2799+ vperm 19,19,19,6+ .long 0x7E5B2799+ vperm 20,20,20,6+ .long 0x7E7C2799+ .long 0x7E9D2799+ addi 4,4,0x60+ b .Lctr32_enc8x_done++.align 5+.Lctr32_enc8x_five:+ .long 0x11EF1D09+ .long 0x12105509+ .long 0x12316509+ .long 0x12526D09+ .long 0x12737509++ vperm 15,15,15,6+ vperm 16,16,16,6+ .long 0x7DE02799+ vperm 17,17,17,6+ .long 0x7E082799+ vperm 18,18,18,6+ .long 0x7E3A2799+ vperm 19,19,19,6+ .long 0x7E5B2799+ .long 0x7E7C2799+ addi 4,4,0x50+ b .Lctr32_enc8x_done++.align 5+.Lctr32_enc8x_four:+ .long 0x11EF5509+ .long 0x12106509+ .long 0x12316D09+ .long 0x12527509++ vperm 15,15,15,6+ vperm 16,16,16,6+ .long 0x7DE02799+ vperm 17,17,17,6+ .long 0x7E082799+ vperm 18,18,18,6+ .long 0x7E3A2799+ .long 0x7E5B2799+ addi 4,4,0x40+ b .Lctr32_enc8x_done++.align 5+.Lctr32_enc8x_three:+ .long 0x11EF6509+ .long 0x12106D09+ .long 0x12317509++ vperm 15,15,15,6+ vperm 16,16,16,6+ .long 0x7DE02799+ vperm 17,17,17,6+ .long 0x7E082799+ .long 0x7E3A2799+ addi 4,4,0x30+ b .Lctr32_enc8x_done++.align 5+.Lctr32_enc8x_two:+ .long 0x11EF6D09+ .long 0x12107509++ vperm 15,15,15,6+ vperm 16,16,16,6+ .long 0x7DE02799+ .long 0x7E082799+ addi 4,4,0x20+ b .Lctr32_enc8x_done++.align 5+.Lctr32_enc8x_one:+ .long 0x11EF7509++ vperm 15,15,15,6+ .long 0x7DE02799+ addi 4,4,0x10++.Lctr32_enc8x_done:+ li 10,79+ li 11,95+ stvx 6,10,1+ addi 10,10,32+ stvx 6,11,1+ addi 11,11,32+ stvx 6,10,1+ addi 10,10,32+ stvx 6,11,1+ addi 11,11,32+ stvx 6,10,1+ addi 10,10,32+ stvx 6,11,1+ addi 11,11,32+ stvx 6,10,1+ addi 10,10,32+ stvx 6,11,1+ addi 11,11,32++ or 12,12,12+ lvx 20,10,1+ addi 10,10,32+ lvx 21,11,1+ addi 11,11,32+ lvx 22,10,1+ addi 10,10,32+ lvx 23,11,1+ addi 11,11,32+ lvx 24,10,1+ addi 10,10,32+ lvx 25,11,1+ addi 11,11,32+ lvx 26,10,1+ addi 10,10,32+ lvx 27,11,1+ addi 11,11,32+ lvx 28,10,1+ addi 10,10,32+ lvx 29,11,1+ addi 11,11,32+ lvx 30,10,1+ lvx 31,11,1+ ld 26,400(1)+ ld 27,408(1)+ ld 28,416(1)+ ld 29,424(1)+ ld 30,432(1)+ ld 31,440(1)+ addi 1,1,448+ blr +.long 0+.byte 0,12,0x04,0,0x80,6,6,0+.long 0+.size crypton_aes_p8_ctr32_encrypt_blocks,.-crypton_aes_p8_ctr32_encrypt_blocks+.globl crypton_aes_p8_xts_encrypt+.type crypton_aes_p8_xts_encrypt,@function+.align 5+crypton_aes_p8_xts_encrypt:+.localentry crypton_aes_p8_xts_encrypt,0++ mr 10,3+ li 3,-1+ cmpldi 5,16+ .long 0x4dc00020++ lis 0,0xfff0+ li 12,-1+ li 11,0+ or 0,0,0++ vspltisb 9,0x07+ lvsl 6,11,11+ vspltisb 11,0x0f+ vxor 6,6,9++ li 3,15+ lvx 8,0,8+ lvsl 5,0,8+ lvx 4,3,8+ vxor 5,5,11+ vperm 8,8,4,5++ neg 11,10+ lvsr 5,0,11+ lvx 2,0,10+ addi 10,10,15+ vxor 5,5,11++ cmpldi 7,0+ beq .Lxts_enc_no_key2++ lvsr 7,0,7+ lwz 9,240(7)+ srwi 9,9,1+ subi 9,9,1+ li 3,16++ lvx 0,0,7+ lvx 1,3,7+ addi 3,3,16+ vperm 0,1,0,7+ vxor 8,8,0+ lvx 0,3,7+ addi 3,3,16+ mtctr 9++.Ltweak_xts_enc:+ vperm 1,0,1,7+ .long 0x11080D08+ lvx 1,3,7+ addi 3,3,16+ vperm 0,1,0,7+ .long 0x11080508+ lvx 0,3,7+ addi 3,3,16+ bdnz .Ltweak_xts_enc++ vperm 1,0,1,7+ .long 0x11080D08+ lvx 1,3,7+ vperm 0,1,0,7+ .long 0x11080509++ li 8,0+ b .Lxts_enc++.Lxts_enc_no_key2:+ li 3,-16+ and 5,5,3+++.Lxts_enc:+ lvx 4,0,10+ addi 10,10,16++ lvsr 7,0,6+ lwz 9,240(6)+ srwi 9,9,1+ subi 9,9,1+ li 3,16++ vslb 10,9,9+ vor 10,10,9+ vspltisb 11,1+ vsldoi 10,10,11,15++ cmpldi 5,96+ bge _aesp8_xts_encrypt6x++ andi. 7,5,15+ subic 0,5,32+ subi 7,7,16+ subfe 0,0,0+ and 0,0,7+ add 10,10,0++ lvx 0,0,6+ lvx 1,3,6+ addi 3,3,16+ vperm 2,2,4,5+ vperm 0,1,0,7+ vxor 2,2,8+ vxor 2,2,0+ lvx 0,3,6+ addi 3,3,16+ mtctr 9+ b .Loop_xts_enc++.align 5+.Loop_xts_enc:+ vperm 1,0,1,7+ .long 0x10420D08+ lvx 1,3,6+ addi 3,3,16+ vperm 0,1,0,7+ .long 0x10420508+ lvx 0,3,6+ addi 3,3,16+ bdnz .Loop_xts_enc++ vperm 1,0,1,7+ .long 0x10420D08+ lvx 1,3,6+ li 3,16+ vperm 0,1,0,7+ vxor 0,0,8+ .long 0x10620509++ vperm 11,3,3,6++ .long 0x7D602799++ addi 4,4,16++ subic. 5,5,16+ beq .Lxts_enc_done++ vor 2,4,4+ lvx 4,0,10+ addi 10,10,16+ lvx 0,0,6+ lvx 1,3,6+ addi 3,3,16++ subic 0,5,32+ subfe 0,0,0+ and 0,0,7+ add 10,10,0++ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vand 11,11,10+ vxor 8,8,11++ vperm 2,2,4,5+ vperm 0,1,0,7+ vxor 2,2,8+ vxor 3,3,0+ vxor 2,2,0+ lvx 0,3,6+ addi 3,3,16++ mtctr 9+ cmpldi 5,16+ bge .Loop_xts_enc++ vxor 3,3,8+ lvsr 5,0,5+ vxor 4,4,4+ vspltisb 11,-1+ vperm 4,4,11,5+ vsel 2,2,3,4++ subi 11,4,17+ subi 4,4,16+ mtctr 5+ li 5,16+.Loop_xts_enc_steal:+ lbzu 0,1(11)+ stb 0,16(11)+ bdnz .Loop_xts_enc_steal++ mtctr 9+ b .Loop_xts_enc++.Lxts_enc_done:+ cmpldi 8,0+ beq .Lxts_enc_ret++ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vand 11,11,10+ vxor 8,8,11++ vperm 8,8,8,6+ .long 0x7D004799++.Lxts_enc_ret:+ or 12,12,12+ li 3,0+ blr +.long 0+.byte 0,12,0x04,0,0x80,6,6,0+.long 0+.size crypton_aes_p8_xts_encrypt,.-crypton_aes_p8_xts_encrypt++.globl crypton_aes_p8_xts_decrypt+.type crypton_aes_p8_xts_decrypt,@function+.align 5+crypton_aes_p8_xts_decrypt:+.localentry crypton_aes_p8_xts_decrypt,0++ mr 10,3+ li 3,-1+ cmpldi 5,16+ .long 0x4dc00020++ lis 0,0xfff8+ li 12,-1+ li 11,0+ or 0,0,0++ andi. 0,5,15+ neg 0,0+ andi. 0,0,16+ sub 5,5,0++ vspltisb 9,0x07+ lvsl 6,11,11+ vspltisb 11,0x0f+ vxor 6,6,9++ li 3,15+ lvx 8,0,8+ lvsl 5,0,8+ lvx 4,3,8+ vxor 5,5,11+ vperm 8,8,4,5++ neg 11,10+ lvsr 5,0,11+ lvx 2,0,10+ addi 10,10,15+ vxor 5,5,11++ cmpldi 7,0+ beq .Lxts_dec_no_key2++ lvsr 7,0,7+ lwz 9,240(7)+ srwi 9,9,1+ subi 9,9,1+ li 3,16++ lvx 0,0,7+ lvx 1,3,7+ addi 3,3,16+ vperm 0,1,0,7+ vxor 8,8,0+ lvx 0,3,7+ addi 3,3,16+ mtctr 9++.Ltweak_xts_dec:+ vperm 1,0,1,7+ .long 0x11080D08+ lvx 1,3,7+ addi 3,3,16+ vperm 0,1,0,7+ .long 0x11080508+ lvx 0,3,7+ addi 3,3,16+ bdnz .Ltweak_xts_dec++ vperm 1,0,1,7+ .long 0x11080D08+ lvx 1,3,7+ vperm 0,1,0,7+ .long 0x11080509++ li 8,0+ b .Lxts_dec++.Lxts_dec_no_key2:+ neg 3,5+ andi. 3,3,15+ add 5,5,3+++.Lxts_dec:+ lvx 4,0,10+ addi 10,10,16++ lvsr 7,0,6+ lwz 9,240(6)+ srwi 9,9,1+ subi 9,9,1+ li 3,16++ vslb 10,9,9+ vor 10,10,9+ vspltisb 11,1+ vsldoi 10,10,11,15++ cmpldi 5,96+ bge _aesp8_xts_decrypt6x++ lvx 0,0,6+ lvx 1,3,6+ addi 3,3,16+ vperm 2,2,4,5+ vperm 0,1,0,7+ vxor 2,2,8+ vxor 2,2,0+ lvx 0,3,6+ addi 3,3,16+ mtctr 9++ cmpldi 5,16+ blt .Ltail_xts_dec+++.align 5+.Loop_xts_dec:+ vperm 1,0,1,7+ .long 0x10420D48+ lvx 1,3,6+ addi 3,3,16+ vperm 0,1,0,7+ .long 0x10420548+ lvx 0,3,6+ addi 3,3,16+ bdnz .Loop_xts_dec++ vperm 1,0,1,7+ .long 0x10420D48+ lvx 1,3,6+ li 3,16+ vperm 0,1,0,7+ vxor 0,0,8+ .long 0x10620549++ vperm 11,3,3,6++ .long 0x7D602799++ addi 4,4,16++ subic. 5,5,16+ beq .Lxts_dec_done++ vor 2,4,4+ lvx 4,0,10+ addi 10,10,16+ lvx 0,0,6+ lvx 1,3,6+ addi 3,3,16++ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vand 11,11,10+ vxor 8,8,11++ vperm 2,2,4,5+ vperm 0,1,0,7+ vxor 2,2,8+ vxor 2,2,0+ lvx 0,3,6+ addi 3,3,16++ mtctr 9+ cmpldi 5,16+ bge .Loop_xts_dec++.Ltail_xts_dec:+ vsrab 11,8,9+ vaddubm 12,8,8+ vsldoi 11,11,11,15+ vand 11,11,10+ vxor 12,12,11++ subi 10,10,16+ add 10,10,5++ vxor 2,2,8+ vxor 2,2,12++.Loop_xts_dec_short:+ vperm 1,0,1,7+ .long 0x10420D48+ lvx 1,3,6+ addi 3,3,16+ vperm 0,1,0,7+ .long 0x10420548+ lvx 0,3,6+ addi 3,3,16+ bdnz .Loop_xts_dec_short++ vperm 1,0,1,7+ .long 0x10420D48+ lvx 1,3,6+ li 3,16+ vperm 0,1,0,7+ vxor 0,0,12+ .long 0x10620549++ vperm 11,3,3,6++ .long 0x7D602799+++ vor 2,4,4+ lvx 4,0,10++ lvx 0,0,6+ lvx 1,3,6+ addi 3,3,16+ vperm 2,2,4,5+ vperm 0,1,0,7++ lvsr 5,0,5+ vxor 4,4,4+ vspltisb 11,-1+ vperm 4,4,11,5+ vsel 2,2,3,4++ vxor 0,0,8+ vxor 2,2,0+ lvx 0,3,6+ addi 3,3,16++ subi 11,4,1+ mtctr 5+ li 5,16+.Loop_xts_dec_steal:+ lbzu 0,1(11)+ stb 0,16(11)+ bdnz .Loop_xts_dec_steal++ mtctr 9+ b .Loop_xts_dec++.Lxts_dec_done:+ cmpldi 8,0+ beq .Lxts_dec_ret++ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vand 11,11,10+ vxor 8,8,11++ vperm 8,8,8,6+ .long 0x7D004799++.Lxts_dec_ret:+ or 12,12,12+ li 3,0+ blr +.long 0+.byte 0,12,0x04,0,0x80,6,6,0+.long 0+.size crypton_aes_p8_xts_decrypt,.-crypton_aes_p8_xts_decrypt+.align 5+_aesp8_xts_encrypt6x:+ stdu 1,-448(1)+ mflr 11+ li 7,207+ li 3,223+ std 11,464(1)+ stvx 20,7,1+ addi 7,7,32+ stvx 21,3,1+ addi 3,3,32+ stvx 22,7,1+ addi 7,7,32+ stvx 23,3,1+ addi 3,3,32+ stvx 24,7,1+ addi 7,7,32+ stvx 25,3,1+ addi 3,3,32+ stvx 26,7,1+ addi 7,7,32+ stvx 27,3,1+ addi 3,3,32+ stvx 28,7,1+ addi 7,7,32+ stvx 29,3,1+ addi 3,3,32+ stvx 30,7,1+ stvx 31,3,1+ li 0,-1+ stw 12,396(1)+ li 3,0x10+ std 26,400(1)+ li 26,0x20+ std 27,408(1)+ li 27,0x30+ std 28,416(1)+ li 28,0x40+ std 29,424(1)+ li 29,0x50+ std 30,432(1)+ li 30,0x60+ std 31,440(1)+ li 31,0x70+ or 0,0,0++ subi 9,9,3++ lvx 23,0,6+ lvx 30,3,6+ addi 6,6,0x20+ lvx 31,0,6+ vperm 23,30,23,7+ addi 7,1,64+15+ mtctr 9++.Load_xts_enc_key:+ vperm 24,31,30,7+ lvx 30,3,6+ addi 6,6,0x20+ stvx 24,0,7+ vperm 25,30,31,7+ lvx 31,0,6+ stvx 25,3,7+ addi 7,7,0x20+ bdnz .Load_xts_enc_key++ lvx 26,3,6+ vperm 24,31,30,7+ lvx 27,26,6+ stvx 24,0,7+ vperm 25,26,31,7+ lvx 28,27,6+ stvx 25,3,7+ addi 7,1,64+15+ vperm 26,27,26,7+ lvx 29,28,6+ vperm 27,28,27,7+ lvx 30,29,6+ vperm 28,29,28,7+ lvx 31,30,6+ vperm 29,30,29,7+ lvx 22,31,6+ vperm 30,31,30,7+ lvx 24,0,7+ vperm 31,22,31,7+ lvx 25,3,7++ vperm 0,2,4,5+ subi 10,10,31+ vxor 17,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vand 11,11,10+ vxor 7,0,17+ vxor 8,8,11++ .long 0x7C235699+ vxor 18,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 1,1,1,6+ vand 11,11,10+ vxor 12,1,18+ vxor 8,8,11++ .long 0x7C5A5699+ andi. 31,5,15+ vxor 19,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 2,2,2,6+ vand 11,11,10+ vxor 13,2,19+ vxor 8,8,11++ .long 0x7C7B5699+ sub 5,5,31+ vxor 20,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 3,3,3,6+ vand 11,11,10+ vxor 14,3,20+ vxor 8,8,11++ .long 0x7C9C5699+ subi 5,5,0x60+ vxor 21,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 4,4,4,6+ vand 11,11,10+ vxor 15,4,21+ vxor 8,8,11++ .long 0x7CBD5699+ addi 10,10,0x60+ vxor 22,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 5,5,5,6+ vand 11,11,10+ vxor 16,5,22+ vxor 8,8,11++ vxor 31,31,23+ mtctr 9+ b .Loop_xts_enc6x++.align 5+.Loop_xts_enc6x:+ .long 0x10E7C508+ .long 0x118CC508+ .long 0x11ADC508+ .long 0x11CEC508+ .long 0x11EFC508+ .long 0x1210C508+ lvx 24,26,7+ addi 7,7,0x20++ .long 0x10E7CD08+ .long 0x118CCD08+ .long 0x11ADCD08+ .long 0x11CECD08+ .long 0x11EFCD08+ .long 0x1210CD08+ lvx 25,3,7+ bdnz .Loop_xts_enc6x++ subic 5,5,96+ vxor 0,17,31+ .long 0x10E7C508+ .long 0x118CC508+ vsrab 11,8,9+ vxor 17,8,23+ vaddubm 8,8,8+ .long 0x11ADC508+ .long 0x11CEC508+ vsldoi 11,11,11,15+ .long 0x11EFC508+ .long 0x1210C508++ subfe. 0,0,0+ vand 11,11,10+ .long 0x10E7CD08+ .long 0x118CCD08+ vxor 8,8,11+ .long 0x11ADCD08+ .long 0x11CECD08+ vxor 1,18,31+ vsrab 11,8,9+ vxor 18,8,23+ .long 0x11EFCD08+ .long 0x1210CD08++ and 0,0,5+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ .long 0x10E7D508+ .long 0x118CD508+ vand 11,11,10+ .long 0x11ADD508+ .long 0x11CED508+ vxor 8,8,11+ .long 0x11EFD508+ .long 0x1210D508++ add 10,10,0++++ vxor 2,19,31+ vsrab 11,8,9+ vxor 19,8,23+ vaddubm 8,8,8+ .long 0x10E7DD08+ .long 0x118CDD08+ vsldoi 11,11,11,15+ .long 0x11ADDD08+ .long 0x11CEDD08+ vand 11,11,10+ .long 0x11EFDD08+ .long 0x1210DD08++ addi 7,1,64+15+ vxor 8,8,11+ .long 0x10E7E508+ .long 0x118CE508+ vxor 3,20,31+ vsrab 11,8,9+ vxor 20,8,23+ .long 0x11ADE508+ .long 0x11CEE508+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ .long 0x11EFE508+ .long 0x1210E508+ lvx 24,0,7+ vand 11,11,10++ .long 0x10E7ED08+ .long 0x118CED08+ vxor 8,8,11+ .long 0x11ADED08+ .long 0x11CEED08+ vxor 4,21,31+ vsrab 11,8,9+ vxor 21,8,23+ .long 0x11EFED08+ .long 0x1210ED08+ lvx 25,3,7+ vaddubm 8,8,8+ vsldoi 11,11,11,15++ .long 0x10E7F508+ .long 0x118CF508+ vand 11,11,10+ .long 0x11ADF508+ .long 0x11CEF508+ vxor 8,8,11+ .long 0x11EFF508+ .long 0x1210F508+ vxor 5,22,31+ vsrab 11,8,9+ vxor 22,8,23++ .long 0x10E70509+ .long 0x7C005699+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ .long 0x118C0D09+ .long 0x7C235699+ .long 0x11AD1509+ vperm 0,0,0,6+ .long 0x7C5A5699+ vand 11,11,10+ .long 0x11CE1D09+ vperm 1,1,1,6+ .long 0x7C7B5699+ .long 0x11EF2509+ vperm 2,2,2,6+ .long 0x7C9C5699+ vxor 8,8,11+ .long 0x11702D09++ vperm 3,3,3,6+ .long 0x7CBD5699+ addi 10,10,0x60+ vperm 4,4,4,6+ vperm 5,5,5,6++ vperm 7,7,7,6+ vperm 12,12,12,6+ .long 0x7CE02799+ vxor 7,0,17+ vperm 13,13,13,6+ .long 0x7D832799+ vxor 12,1,18+ vperm 14,14,14,6+ .long 0x7DBA2799+ vxor 13,2,19+ vperm 15,15,15,6+ .long 0x7DDB2799+ vxor 14,3,20+ vperm 16,11,11,6+ .long 0x7DFC2799+ vxor 15,4,21+ .long 0x7E1D2799++ vxor 16,5,22+ addi 4,4,0x60++ mtctr 9+ beq .Loop_xts_enc6x++ addic. 5,5,0x60+ beq .Lxts_enc6x_zero+ cmpwi 5,0x20+ blt .Lxts_enc6x_one+ nop + beq .Lxts_enc6x_two+ cmpwi 5,0x40+ blt .Lxts_enc6x_three+ nop + beq .Lxts_enc6x_four++.Lxts_enc6x_five:+ vxor 7,1,17+ vxor 12,2,18+ vxor 13,3,19+ vxor 14,4,20+ vxor 15,5,21++ bl _aesp8_xts_enc5x++ vperm 7,7,7,6+ vor 17,22,22+ vperm 12,12,12,6+ .long 0x7CE02799+ vperm 13,13,13,6+ .long 0x7D832799+ vperm 14,14,14,6+ .long 0x7DBA2799+ vxor 11,15,22+ vperm 15,15,15,6+ .long 0x7DDB2799+ .long 0x7DFC2799+ addi 4,4,0x50+ bne .Lxts_enc6x_steal+ b .Lxts_enc6x_done++.align 4+.Lxts_enc6x_four:+ vxor 7,2,17+ vxor 12,3,18+ vxor 13,4,19+ vxor 14,5,20+ vxor 15,15,15++ bl _aesp8_xts_enc5x++ vperm 7,7,7,6+ vor 17,21,21+ vperm 12,12,12,6+ .long 0x7CE02799+ vperm 13,13,13,6+ .long 0x7D832799+ vxor 11,14,21+ vperm 14,14,14,6+ .long 0x7DBA2799+ .long 0x7DDB2799+ addi 4,4,0x40+ bne .Lxts_enc6x_steal+ b .Lxts_enc6x_done++.align 4+.Lxts_enc6x_three:+ vxor 7,3,17+ vxor 12,4,18+ vxor 13,5,19+ vxor 14,14,14+ vxor 15,15,15++ bl _aesp8_xts_enc5x++ vperm 7,7,7,6+ vor 17,20,20+ vperm 12,12,12,6+ .long 0x7CE02799+ vxor 11,13,20+ vperm 13,13,13,6+ .long 0x7D832799+ .long 0x7DBA2799+ addi 4,4,0x30+ bne .Lxts_enc6x_steal+ b .Lxts_enc6x_done++.align 4+.Lxts_enc6x_two:+ vxor 7,4,17+ vxor 12,5,18+ vxor 13,13,13+ vxor 14,14,14+ vxor 15,15,15++ bl _aesp8_xts_enc5x++ vperm 7,7,7,6+ vor 17,19,19+ vxor 11,12,19+ vperm 12,12,12,6+ .long 0x7CE02799+ .long 0x7D832799+ addi 4,4,0x20+ bne .Lxts_enc6x_steal+ b .Lxts_enc6x_done++.align 4+.Lxts_enc6x_one:+ vxor 7,5,17+ nop +.Loop_xts_enc1x:+ .long 0x10E7C508+ lvx 24,26,7+ addi 7,7,0x20++ .long 0x10E7CD08+ lvx 25,3,7+ bdnz .Loop_xts_enc1x++ add 10,10,31+ cmpwi 31,0+ .long 0x10E7C508++ subi 10,10,16+ .long 0x10E7CD08++ lvsr 5,0,31+ .long 0x10E7D508++ .long 0x7C005699+ .long 0x10E7DD08++ addi 7,1,64+15+ .long 0x10E7E508+ lvx 24,0,7++ .long 0x10E7ED08+ lvx 25,3,7+ vxor 17,17,31++ vperm 0,0,0,6+ .long 0x10E7F508++ vperm 0,0,0,5+ .long 0x10E78D09++ vor 17,18,18+ vxor 11,7,18+ vperm 7,7,7,6+ .long 0x7CE02799+ addi 4,4,0x10+ bne .Lxts_enc6x_steal+ b .Lxts_enc6x_done++.align 4+.Lxts_enc6x_zero:+ cmpwi 31,0+ beq .Lxts_enc6x_done++ add 10,10,31+ subi 10,10,16+ .long 0x7C005699+ lvsr 5,0,31+ vperm 0,0,0,6+ vperm 0,0,0,5+ vxor 11,11,17+.Lxts_enc6x_steal:+ vxor 0,0,17+ vxor 7,7,7+ vspltisb 12,-1+ vperm 7,7,12,5+ vsel 7,0,11,7++ subi 30,4,17+ subi 4,4,16+ mtctr 31+.Loop_xts_enc6x_steal:+ lbzu 0,1(30)+ stb 0,16(30)+ bdnz .Loop_xts_enc6x_steal++ li 31,0+ mtctr 9+ b .Loop_xts_enc1x++.align 4+.Lxts_enc6x_done:+ cmpldi 8,0+ beq .Lxts_enc6x_ret++ vxor 8,17,23+ vperm 8,8,8,6+ .long 0x7D004799++.Lxts_enc6x_ret:+ mtlr 11+ li 10,79+ li 11,95+ stvx 9,10,1+ addi 10,10,32+ stvx 9,11,1+ addi 11,11,32+ stvx 9,10,1+ addi 10,10,32+ stvx 9,11,1+ addi 11,11,32+ stvx 9,10,1+ addi 10,10,32+ stvx 9,11,1+ addi 11,11,32+ stvx 9,10,1+ addi 10,10,32+ stvx 9,11,1+ addi 11,11,32++ or 12,12,12+ lvx 20,10,1+ addi 10,10,32+ lvx 21,11,1+ addi 11,11,32+ lvx 22,10,1+ addi 10,10,32+ lvx 23,11,1+ addi 11,11,32+ lvx 24,10,1+ addi 10,10,32+ lvx 25,11,1+ addi 11,11,32+ lvx 26,10,1+ addi 10,10,32+ lvx 27,11,1+ addi 11,11,32+ lvx 28,10,1+ addi 10,10,32+ lvx 29,11,1+ addi 11,11,32+ lvx 30,10,1+ lvx 31,11,1+ ld 26,400(1)+ ld 27,408(1)+ ld 28,416(1)+ ld 29,424(1)+ ld 30,432(1)+ ld 31,440(1)+ addi 1,1,448+ blr +.long 0+.byte 0,12,0x04,1,0x80,6,6,0+.long 0++.align 5+_aesp8_xts_enc5x:+ .long 0x10E7C508+ .long 0x118CC508+ .long 0x11ADC508+ .long 0x11CEC508+ .long 0x11EFC508+ lvx 24,26,7+ addi 7,7,0x20++ .long 0x10E7CD08+ .long 0x118CCD08+ .long 0x11ADCD08+ .long 0x11CECD08+ .long 0x11EFCD08+ lvx 25,3,7+ bdnz _aesp8_xts_enc5x++ add 10,10,31+ cmpwi 31,0+ .long 0x10E7C508+ .long 0x118CC508+ .long 0x11ADC508+ .long 0x11CEC508+ .long 0x11EFC508++ subi 10,10,16+ .long 0x10E7CD08+ .long 0x118CCD08+ .long 0x11ADCD08+ .long 0x11CECD08+ .long 0x11EFCD08+ vxor 17,17,31++ .long 0x10E7D508+ lvsr 5,0,31+ .long 0x118CD508+ .long 0x11ADD508+ .long 0x11CED508+ .long 0x11EFD508+ vxor 1,18,31++ .long 0x10E7DD08+ .long 0x7C005699+ .long 0x118CDD08+ .long 0x11ADDD08+ .long 0x11CEDD08+ .long 0x11EFDD08+ vxor 2,19,31++ addi 7,1,64+15+ .long 0x10E7E508+ .long 0x118CE508+ .long 0x11ADE508+ .long 0x11CEE508+ .long 0x11EFE508+ lvx 24,0,7+ vxor 3,20,31++ .long 0x10E7ED08+ vperm 0,0,0,6+ .long 0x118CED08+ .long 0x11ADED08+ .long 0x11CEED08+ .long 0x11EFED08+ lvx 25,3,7+ vxor 4,21,31++ .long 0x10E7F508+ vperm 0,0,0,5+ .long 0x118CF508+ .long 0x11ADF508+ .long 0x11CEF508+ .long 0x11EFF508++ .long 0x10E78D09+ .long 0x118C0D09+ .long 0x11AD1509+ .long 0x11CE1D09+ .long 0x11EF2509+ blr +.long 0+.byte 0,12,0x14,0,0,0,0,0++.align 5+_aesp8_xts_decrypt6x:+ stdu 1,-448(1)+ mflr 11+ li 7,207+ li 3,223+ std 11,464(1)+ stvx 20,7,1+ addi 7,7,32+ stvx 21,3,1+ addi 3,3,32+ stvx 22,7,1+ addi 7,7,32+ stvx 23,3,1+ addi 3,3,32+ stvx 24,7,1+ addi 7,7,32+ stvx 25,3,1+ addi 3,3,32+ stvx 26,7,1+ addi 7,7,32+ stvx 27,3,1+ addi 3,3,32+ stvx 28,7,1+ addi 7,7,32+ stvx 29,3,1+ addi 3,3,32+ stvx 30,7,1+ stvx 31,3,1+ li 0,-1+ stw 12,396(1)+ li 3,0x10+ std 26,400(1)+ li 26,0x20+ std 27,408(1)+ li 27,0x30+ std 28,416(1)+ li 28,0x40+ std 29,424(1)+ li 29,0x50+ std 30,432(1)+ li 30,0x60+ std 31,440(1)+ li 31,0x70+ or 0,0,0++ subi 9,9,3++ lvx 23,0,6+ lvx 30,3,6+ addi 6,6,0x20+ lvx 31,0,6+ vperm 23,30,23,7+ addi 7,1,64+15+ mtctr 9++.Load_xts_dec_key:+ vperm 24,31,30,7+ lvx 30,3,6+ addi 6,6,0x20+ stvx 24,0,7+ vperm 25,30,31,7+ lvx 31,0,6+ stvx 25,3,7+ addi 7,7,0x20+ bdnz .Load_xts_dec_key++ lvx 26,3,6+ vperm 24,31,30,7+ lvx 27,26,6+ stvx 24,0,7+ vperm 25,26,31,7+ lvx 28,27,6+ stvx 25,3,7+ addi 7,1,64+15+ vperm 26,27,26,7+ lvx 29,28,6+ vperm 27,28,27,7+ lvx 30,29,6+ vperm 28,29,28,7+ lvx 31,30,6+ vperm 29,30,29,7+ lvx 22,31,6+ vperm 30,31,30,7+ lvx 24,0,7+ vperm 31,22,31,7+ lvx 25,3,7++ vperm 0,2,4,5+ subi 10,10,31+ vxor 17,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vand 11,11,10+ vxor 7,0,17+ vxor 8,8,11++ .long 0x7C235699+ vxor 18,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 1,1,1,6+ vand 11,11,10+ vxor 12,1,18+ vxor 8,8,11++ .long 0x7C5A5699+ andi. 31,5,15+ vxor 19,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 2,2,2,6+ vand 11,11,10+ vxor 13,2,19+ vxor 8,8,11++ .long 0x7C7B5699+ sub 5,5,31+ vxor 20,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 3,3,3,6+ vand 11,11,10+ vxor 14,3,20+ vxor 8,8,11++ .long 0x7C9C5699+ subi 5,5,0x60+ vxor 21,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 4,4,4,6+ vand 11,11,10+ vxor 15,4,21+ vxor 8,8,11++ .long 0x7CBD5699+ addi 10,10,0x60+ vxor 22,8,23+ vsrab 11,8,9+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ vperm 5,5,5,6+ vand 11,11,10+ vxor 16,5,22+ vxor 8,8,11++ vxor 31,31,23+ mtctr 9+ b .Loop_xts_dec6x++.align 5+.Loop_xts_dec6x:+ .long 0x10E7C548+ .long 0x118CC548+ .long 0x11ADC548+ .long 0x11CEC548+ .long 0x11EFC548+ .long 0x1210C548+ lvx 24,26,7+ addi 7,7,0x20++ .long 0x10E7CD48+ .long 0x118CCD48+ .long 0x11ADCD48+ .long 0x11CECD48+ .long 0x11EFCD48+ .long 0x1210CD48+ lvx 25,3,7+ bdnz .Loop_xts_dec6x++ subic 5,5,96+ vxor 0,17,31+ .long 0x10E7C548+ .long 0x118CC548+ vsrab 11,8,9+ vxor 17,8,23+ vaddubm 8,8,8+ .long 0x11ADC548+ .long 0x11CEC548+ vsldoi 11,11,11,15+ .long 0x11EFC548+ .long 0x1210C548++ subfe. 0,0,0+ vand 11,11,10+ .long 0x10E7CD48+ .long 0x118CCD48+ vxor 8,8,11+ .long 0x11ADCD48+ .long 0x11CECD48+ vxor 1,18,31+ vsrab 11,8,9+ vxor 18,8,23+ .long 0x11EFCD48+ .long 0x1210CD48++ and 0,0,5+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ .long 0x10E7D548+ .long 0x118CD548+ vand 11,11,10+ .long 0x11ADD548+ .long 0x11CED548+ vxor 8,8,11+ .long 0x11EFD548+ .long 0x1210D548++ add 10,10,0++++ vxor 2,19,31+ vsrab 11,8,9+ vxor 19,8,23+ vaddubm 8,8,8+ .long 0x10E7DD48+ .long 0x118CDD48+ vsldoi 11,11,11,15+ .long 0x11ADDD48+ .long 0x11CEDD48+ vand 11,11,10+ .long 0x11EFDD48+ .long 0x1210DD48++ addi 7,1,64+15+ vxor 8,8,11+ .long 0x10E7E548+ .long 0x118CE548+ vxor 3,20,31+ vsrab 11,8,9+ vxor 20,8,23+ .long 0x11ADE548+ .long 0x11CEE548+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ .long 0x11EFE548+ .long 0x1210E548+ lvx 24,0,7+ vand 11,11,10++ .long 0x10E7ED48+ .long 0x118CED48+ vxor 8,8,11+ .long 0x11ADED48+ .long 0x11CEED48+ vxor 4,21,31+ vsrab 11,8,9+ vxor 21,8,23+ .long 0x11EFED48+ .long 0x1210ED48+ lvx 25,3,7+ vaddubm 8,8,8+ vsldoi 11,11,11,15++ .long 0x10E7F548+ .long 0x118CF548+ vand 11,11,10+ .long 0x11ADF548+ .long 0x11CEF548+ vxor 8,8,11+ .long 0x11EFF548+ .long 0x1210F548+ vxor 5,22,31+ vsrab 11,8,9+ vxor 22,8,23++ .long 0x10E70549+ .long 0x7C005699+ vaddubm 8,8,8+ vsldoi 11,11,11,15+ .long 0x118C0D49+ .long 0x7C235699+ .long 0x11AD1549+ vperm 0,0,0,6+ .long 0x7C5A5699+ vand 11,11,10+ .long 0x11CE1D49+ vperm 1,1,1,6+ .long 0x7C7B5699+ .long 0x11EF2549+ vperm 2,2,2,6+ .long 0x7C9C5699+ vxor 8,8,11+ .long 0x12102D49+ vperm 3,3,3,6+ .long 0x7CBD5699+ addi 10,10,0x60+ vperm 4,4,4,6+ vperm 5,5,5,6++ vperm 7,7,7,6+ vperm 12,12,12,6+ .long 0x7CE02799+ vxor 7,0,17+ vperm 13,13,13,6+ .long 0x7D832799+ vxor 12,1,18+ vperm 14,14,14,6+ .long 0x7DBA2799+ vxor 13,2,19+ vperm 15,15,15,6+ .long 0x7DDB2799+ vxor 14,3,20+ vperm 16,16,16,6+ .long 0x7DFC2799+ vxor 15,4,21+ .long 0x7E1D2799+ vxor 16,5,22+ addi 4,4,0x60++ mtctr 9+ beq .Loop_xts_dec6x++ addic. 5,5,0x60+ beq .Lxts_dec6x_zero+ cmpwi 5,0x20+ blt .Lxts_dec6x_one+ nop + beq .Lxts_dec6x_two+ cmpwi 5,0x40+ blt .Lxts_dec6x_three+ nop + beq .Lxts_dec6x_four++.Lxts_dec6x_five:+ vxor 7,1,17+ vxor 12,2,18+ vxor 13,3,19+ vxor 14,4,20+ vxor 15,5,21++ bl _aesp8_xts_dec5x++ vperm 7,7,7,6+ vor 17,22,22+ vxor 18,8,23+ vperm 12,12,12,6+ .long 0x7CE02799+ vxor 7,0,18+ vperm 13,13,13,6+ .long 0x7D832799+ vperm 14,14,14,6+ .long 0x7DBA2799+ vperm 15,15,15,6+ .long 0x7DDB2799+ .long 0x7DFC2799+ addi 4,4,0x50+ bne .Lxts_dec6x_steal+ b .Lxts_dec6x_done++.align 4+.Lxts_dec6x_four:+ vxor 7,2,17+ vxor 12,3,18+ vxor 13,4,19+ vxor 14,5,20+ vxor 15,15,15++ bl _aesp8_xts_dec5x++ vperm 7,7,7,6+ vor 17,21,21+ vor 18,22,22+ vperm 12,12,12,6+ .long 0x7CE02799+ vxor 7,0,22+ vperm 13,13,13,6+ .long 0x7D832799+ vperm 14,14,14,6+ .long 0x7DBA2799+ .long 0x7DDB2799+ addi 4,4,0x40+ bne .Lxts_dec6x_steal+ b .Lxts_dec6x_done++.align 4+.Lxts_dec6x_three:+ vxor 7,3,17+ vxor 12,4,18+ vxor 13,5,19+ vxor 14,14,14+ vxor 15,15,15++ bl _aesp8_xts_dec5x++ vperm 7,7,7,6+ vor 17,20,20+ vor 18,21,21+ vperm 12,12,12,6+ .long 0x7CE02799+ vxor 7,0,21+ vperm 13,13,13,6+ .long 0x7D832799+ .long 0x7DBA2799+ addi 4,4,0x30+ bne .Lxts_dec6x_steal+ b .Lxts_dec6x_done++.align 4+.Lxts_dec6x_two:+ vxor 7,4,17+ vxor 12,5,18+ vxor 13,13,13+ vxor 14,14,14+ vxor 15,15,15++ bl _aesp8_xts_dec5x++ vperm 7,7,7,6+ vor 17,19,19+ vor 18,20,20+ vperm 12,12,12,6+ .long 0x7CE02799+ vxor 7,0,20+ .long 0x7D832799+ addi 4,4,0x20+ bne .Lxts_dec6x_steal+ b .Lxts_dec6x_done++.align 4+.Lxts_dec6x_one:+ vxor 7,5,17+ nop +.Loop_xts_dec1x:+ .long 0x10E7C548+ lvx 24,26,7+ addi 7,7,0x20++ .long 0x10E7CD48+ lvx 25,3,7+ bdnz .Loop_xts_dec1x++ subi 0,31,1+ .long 0x10E7C548++ andi. 0,0,16+ cmpwi 31,0+ .long 0x10E7CD48++ sub 10,10,0+ .long 0x10E7D548++ .long 0x7C005699+ .long 0x10E7DD48++ addi 7,1,64+15+ .long 0x10E7E548+ lvx 24,0,7++ .long 0x10E7ED48+ lvx 25,3,7+ vxor 17,17,31++ vperm 0,0,0,6+ .long 0x10E7F548++ mtctr 9+ .long 0x10E78D49++ vor 17,18,18+ vor 18,19,19+ vperm 7,7,7,6+ .long 0x7CE02799+ addi 4,4,0x10+ vxor 7,0,19+ bne .Lxts_dec6x_steal+ b .Lxts_dec6x_done++.align 4+.Lxts_dec6x_zero:+ cmpwi 31,0+ beq .Lxts_dec6x_done++ .long 0x7C005699+ vperm 0,0,0,6+ vxor 7,0,18+.Lxts_dec6x_steal:+ .long 0x10E7C548+ lvx 24,26,7+ addi 7,7,0x20++ .long 0x10E7CD48+ lvx 25,3,7+ bdnz .Lxts_dec6x_steal++ add 10,10,31+ .long 0x10E7C548++ cmpwi 31,0+ .long 0x10E7CD48++ .long 0x7C005699+ .long 0x10E7D548++ lvsr 5,0,31+ .long 0x10E7DD48++ addi 7,1,64+15+ .long 0x10E7E548+ lvx 24,0,7++ .long 0x10E7ED48+ lvx 25,3,7+ vxor 18,18,31++ vperm 0,0,0,6+ .long 0x10E7F548++ vperm 0,0,0,5+ .long 0x11679549++ vperm 7,11,11,6+ .long 0x7CE02799+++ vxor 7,7,7+ vspltisb 12,-1+ vperm 7,7,12,5+ vsel 7,0,11,7+ vxor 7,7,17++ subi 30,4,1+ mtctr 31+.Loop_xts_dec6x_steal:+ lbzu 0,1(30)+ stb 0,16(30)+ bdnz .Loop_xts_dec6x_steal++ li 31,0+ mtctr 9+ b .Loop_xts_dec1x++.align 4+.Lxts_dec6x_done:+ cmpldi 8,0+ beq .Lxts_dec6x_ret++ vxor 8,17,23+ vperm 8,8,8,6+ .long 0x7D004799++.Lxts_dec6x_ret:+ mtlr 11+ li 10,79+ li 11,95+ stvx 9,10,1+ addi 10,10,32+ stvx 9,11,1+ addi 11,11,32+ stvx 9,10,1+ addi 10,10,32+ stvx 9,11,1+ addi 11,11,32+ stvx 9,10,1+ addi 10,10,32+ stvx 9,11,1+ addi 11,11,32+ stvx 9,10,1+ addi 10,10,32+ stvx 9,11,1+ addi 11,11,32++ or 12,12,12+ lvx 20,10,1+ addi 10,10,32+ lvx 21,11,1+ addi 11,11,32+ lvx 22,10,1+ addi 10,10,32+ lvx 23,11,1+ addi 11,11,32+ lvx 24,10,1+ addi 10,10,32+ lvx 25,11,1+ addi 11,11,32+ lvx 26,10,1+ addi 10,10,32+ lvx 27,11,1+ addi 11,11,32+ lvx 28,10,1+ addi 10,10,32+ lvx 29,11,1+ addi 11,11,32+ lvx 30,10,1+ lvx 31,11,1+ ld 26,400(1)+ ld 27,408(1)+ ld 28,416(1)+ ld 29,424(1)+ ld 30,432(1)+ ld 31,440(1)+ addi 1,1,448+ blr +.long 0+.byte 0,12,0x04,1,0x80,6,6,0+.long 0++.align 5+_aesp8_xts_dec5x:+ .long 0x10E7C548+ .long 0x118CC548+ .long 0x11ADC548+ .long 0x11CEC548+ .long 0x11EFC548+ lvx 24,26,7+ addi 7,7,0x20++ .long 0x10E7CD48+ .long 0x118CCD48+ .long 0x11ADCD48+ .long 0x11CECD48+ .long 0x11EFCD48+ lvx 25,3,7+ bdnz _aesp8_xts_dec5x++ subi 0,31,1+ .long 0x10E7C548+ .long 0x118CC548+ .long 0x11ADC548+ .long 0x11CEC548+ .long 0x11EFC548++ andi. 0,0,16+ cmpwi 31,0+ .long 0x10E7CD48+ .long 0x118CCD48+ .long 0x11ADCD48+ .long 0x11CECD48+ .long 0x11EFCD48+ vxor 17,17,31++ sub 10,10,0+ .long 0x10E7D548+ .long 0x118CD548+ .long 0x11ADD548+ .long 0x11CED548+ .long 0x11EFD548+ vxor 1,18,31++ .long 0x10E7DD48+ .long 0x7C005699+ .long 0x118CDD48+ .long 0x11ADDD48+ .long 0x11CEDD48+ .long 0x11EFDD48+ vxor 2,19,31++ addi 7,1,64+15+ .long 0x10E7E548+ .long 0x118CE548+ .long 0x11ADE548+ .long 0x11CEE548+ .long 0x11EFE548+ lvx 24,0,7+ vxor 3,20,31++ .long 0x10E7ED48+ vperm 0,0,0,6+ .long 0x118CED48+ .long 0x11ADED48+ .long 0x11CEED48+ .long 0x11EFED48+ lvx 25,3,7+ vxor 4,21,31++ .long 0x10E7F548+ .long 0x118CF548+ .long 0x11ADF548+ .long 0x11CEF548+ .long 0x11EFF548++ .long 0x10E78D49+ .long 0x118C0D49+ .long 0x11AD1549+ .long 0x11CE1D49+ .long 0x11EF2549+ mtctr 9+ blr +.long 0+.byte 0,12,0x14,0,0,0,0,0
@@ -0,0 +1,3801 @@+#!/usr/bin/env perl+#+# ====================================================================+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL+# project. The module is, however, dual licensed under OpenSSL and+# CRYPTOGAMS licenses depending on where you obtain it. For further+# details see http://www.openssl.org/~appro/cryptogams/.+# ====================================================================+#+# This module implements support for AES instructions as per PowerISA+# specification version 2.07, first implemented by POWER8 processor.+# The module is endian-agnostic in sense that it supports both big-+# and little-endian cases. Data alignment in parallelizable modes is+# handled with VSX loads and stores, which implies MSR.VSX flag being+# set. It should also be noted that ISA specification doesn't prohibit+# alignment exceptions for these instructions on page boundaries.+# Initially alignment was handled in pure AltiVec/VMX way [when data+# is aligned programmatically, which in turn guarantees exception-+# free execution], but it turned to hamper performance when vcipher+# instructions are interleaved. It's reckoned that eventual+# misalignment penalties at page boundaries are in average lower+# than additional overhead in pure AltiVec approach.+#+# May 2016+#+# Add XTS subroutine, 9x on little- and 12x improvement on big-endian+# systems were measured.+#+######################################################################+# Current large-block performance in cycles per byte processed with+# 128-bit key (less is better).+#+# CBC en-/decrypt CTR XTS+# POWER8[le] 3.96/0.72 0.74 1.1+# POWER8[be] 3.75/0.65 0.66 1.0+# POWER9[le] 4.02/0.86 0.84 1.05+# POWER9[be] 3.99/0.78 0.79 0.97+++$flavour = shift;++if ($flavour =~ /64/) {+ $SIZE_T =8;+ $LRSAVE =2*$SIZE_T;+ $STU ="stdu";+ $POP ="ld";+ $PUSH ="std";+ $UCMP ="cmpld";+ $SHL ="sldi";+} elsif ($flavour =~ /32/) {+ $SIZE_T =4;+ $LRSAVE =$SIZE_T;+ $STU ="stwu";+ $POP ="lwz";+ $PUSH ="stw";+ $UCMP ="cmplw";+ $SHL ="slwi";+} else { die "nonsense $flavour"; }++$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0;++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;+( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or+( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or+die "can't locate ppc-xlate.pl";++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";++$FRAME=8*$SIZE_T;+$prefix="aes_p8";++$sp="r1";+$vrsave="r12";++#########################################################################+{{{ # Key setup procedures #+my ($inp,$bits,$out,$ptr,$cnt,$rounds)=map("r$_",(3..8));+my ($zero,$in0,$in1,$key,$rcon,$mask,$tmp)=map("v$_",(0..6));+my ($stage,$outperm,$outmask,$outhead,$outtail)=map("v$_",(7..11));++$code.=<<___;+.machine "any"++.text++.align 7+rcon:+.long 0x01000000, 0x01000000, 0x01000000, 0x01000000 ?rev+.long 0x1b000000, 0x1b000000, 0x1b000000, 0x1b000000 ?rev+.long 0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c ?rev+.long 0,0,0,0 ?asis+Lconsts:+ mflr r0+ bcl 20,31,\$+4+ mflr $ptr #vvvvv "distance between . and rcon+ addi $ptr,$ptr,-0x48+ mtlr r0+ blr+ .long 0+ .byte 0,12,0x14,0,0,0,0,0+.asciz "AES for PowerISA 2.07, CRYPTOGAMS by <appro\@openssl.org>"++.globl .${prefix}_set_encrypt_key+.align 5+.${prefix}_set_encrypt_key:+Lset_encrypt_key:+ mflr r11+ $PUSH r11,$LRSAVE($sp)++ li $ptr,-1+ ${UCMP}i $inp,0+ beq- Lenc_key_abort # if ($inp==0) return -1;+ ${UCMP}i $out,0+ beq- Lenc_key_abort # if ($out==0) return -1;+ li $ptr,-2+ cmpwi $bits,128+ blt- Lenc_key_abort+ cmpwi $bits,256+ bgt- Lenc_key_abort+ andi. r0,$bits,0x3f+ bne- Lenc_key_abort++ lis r0,0xfff0+ mfspr $vrsave,256+ mtspr 256,r0++ bl Lconsts+ mtlr r11++ neg r9,$inp+ lvx $in0,0,$inp+ addi $inp,$inp,15 # 15 is not typo+ lvsr $key,0,r9 # borrow $key+ li r8,0x20+ cmpwi $bits,192+ lvx $in1,0,$inp+ le?vspltisb $mask,0x0f # borrow $mask+ lvx $rcon,0,$ptr+ le?vxor $key,$key,$mask # adjust for byte swap+ lvx $mask,r8,$ptr+ addi $ptr,$ptr,0x10+ vperm $in0,$in0,$in1,$key # align [and byte swap in LE]+ li $cnt,8+ vxor $zero,$zero,$zero+ mtctr $cnt++ ?lvsr $outperm,0,$out+ vspltisb $outmask,-1+ lvx $outhead,0,$out+ ?vperm $outmask,$zero,$outmask,$outperm++ blt Loop128+ addi $inp,$inp,8+ beq L192+ addi $inp,$inp,8+ b L256++.align 4+Loop128:+ vperm $key,$in0,$in0,$mask # rotate-n-splat+ vsldoi $tmp,$zero,$in0,12 # >>32+ vperm $outtail,$in0,$in0,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ vcipherlast $key,$key,$rcon+ stvx $stage,0,$out+ addi $out,$out,16++ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ vadduwm $rcon,$rcon,$rcon+ vxor $in0,$in0,$key+ bdnz Loop128++ lvx $rcon,0,$ptr # last two round keys++ vperm $key,$in0,$in0,$mask # rotate-n-splat+ vsldoi $tmp,$zero,$in0,12 # >>32+ vperm $outtail,$in0,$in0,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ vcipherlast $key,$key,$rcon+ stvx $stage,0,$out+ addi $out,$out,16++ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ vadduwm $rcon,$rcon,$rcon+ vxor $in0,$in0,$key++ vperm $key,$in0,$in0,$mask # rotate-n-splat+ vsldoi $tmp,$zero,$in0,12 # >>32+ vperm $outtail,$in0,$in0,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ vcipherlast $key,$key,$rcon+ stvx $stage,0,$out+ addi $out,$out,16++ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ vxor $in0,$in0,$key+ vperm $outtail,$in0,$in0,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ stvx $stage,0,$out++ addi $inp,$out,15 # 15 is not typo+ addi $out,$out,0x50++ li $rounds,10+ b Ldone++.align 4+L192:+ lvx $tmp,0,$inp+ li $cnt,4+ vperm $outtail,$in0,$in0,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ stvx $stage,0,$out+ addi $out,$out,16+ vperm $in1,$in1,$tmp,$key # align [and byte swap in LE]+ vspltisb $key,8 # borrow $key+ mtctr $cnt+ vsububm $mask,$mask,$key # adjust the mask++Loop192:+ vperm $key,$in1,$in1,$mask # roate-n-splat+ vsldoi $tmp,$zero,$in0,12 # >>32+ vcipherlast $key,$key,$rcon++ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp++ vsldoi $stage,$zero,$in1,8+ vspltw $tmp,$in0,3+ vxor $tmp,$tmp,$in1+ vsldoi $in1,$zero,$in1,12 # >>32+ vadduwm $rcon,$rcon,$rcon+ vxor $in1,$in1,$tmp+ vxor $in0,$in0,$key+ vxor $in1,$in1,$key+ vsldoi $stage,$stage,$in0,8++ vperm $key,$in1,$in1,$mask # rotate-n-splat+ vsldoi $tmp,$zero,$in0,12 # >>32+ vperm $outtail,$stage,$stage,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ vcipherlast $key,$key,$rcon+ stvx $stage,0,$out+ addi $out,$out,16++ vsldoi $stage,$in0,$in1,8+ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vperm $outtail,$stage,$stage,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ stvx $stage,0,$out+ addi $out,$out,16++ vspltw $tmp,$in0,3+ vxor $tmp,$tmp,$in1+ vsldoi $in1,$zero,$in1,12 # >>32+ vadduwm $rcon,$rcon,$rcon+ vxor $in1,$in1,$tmp+ vxor $in0,$in0,$key+ vxor $in1,$in1,$key+ vperm $outtail,$in0,$in0,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ stvx $stage,0,$out+ addi $inp,$out,15 # 15 is not typo+ addi $out,$out,16+ bdnz Loop192++ li $rounds,12+ addi $out,$out,0x20+ b Ldone++.align 4+L256:+ lvx $tmp,0,$inp+ li $cnt,7+ li $rounds,14+ vperm $outtail,$in0,$in0,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ stvx $stage,0,$out+ addi $out,$out,16+ vperm $in1,$in1,$tmp,$key # align [and byte swap in LE]+ mtctr $cnt++Loop256:+ vperm $key,$in1,$in1,$mask # rotate-n-splat+ vsldoi $tmp,$zero,$in0,12 # >>32+ vperm $outtail,$in1,$in1,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ vcipherlast $key,$key,$rcon+ stvx $stage,0,$out+ addi $out,$out,16++ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in0,$in0,$tmp+ vadduwm $rcon,$rcon,$rcon+ vxor $in0,$in0,$key+ vperm $outtail,$in0,$in0,$outperm # rotate+ vsel $stage,$outhead,$outtail,$outmask+ vmr $outhead,$outtail+ stvx $stage,0,$out+ addi $inp,$out,15 # 15 is not typo+ addi $out,$out,16+ bdz Ldone++ vspltw $key,$in0,3 # just splat+ vsldoi $tmp,$zero,$in1,12 # >>32+ vsbox $key,$key++ vxor $in1,$in1,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in1,$in1,$tmp+ vsldoi $tmp,$zero,$tmp,12 # >>32+ vxor $in1,$in1,$tmp++ vxor $in1,$in1,$key+ b Loop256++.align 4+Ldone:+ lvx $in1,0,$inp # redundant in aligned case+ vsel $in1,$outhead,$in1,$outmask+ stvx $in1,0,$inp+ li $ptr,0+ mtspr 256,$vrsave+ stw $rounds,0($out)++Lenc_key_abort:+ mr r3,$ptr+ blr+ .long 0+ .byte 0,12,0x14,1,0,0,3,0+ .long 0+.size .${prefix}_set_encrypt_key,.-.${prefix}_set_encrypt_key++.globl .${prefix}_set_decrypt_key+.align 5+.${prefix}_set_decrypt_key:+ $STU $sp,-$FRAME($sp)+ mflr r10+ $PUSH r10,$FRAME+$LRSAVE($sp)+ bl Lset_encrypt_key+ mtlr r10++ cmpwi r3,0+ bne- Ldec_key_abort++ slwi $cnt,$rounds,4+ subi $inp,$out,240 # first round key+ srwi $rounds,$rounds,1+ add $out,$inp,$cnt # last round key+ mtctr $rounds++Ldeckey:+ lwz r0, 0($inp)+ lwz r6, 4($inp)+ lwz r7, 8($inp)+ lwz r8, 12($inp)+ addi $inp,$inp,16+ lwz r9, 0($out)+ lwz r10,4($out)+ lwz r11,8($out)+ lwz r12,12($out)+ stw r0, 0($out)+ stw r6, 4($out)+ stw r7, 8($out)+ stw r8, 12($out)+ subi $out,$out,16+ stw r9, -16($inp)+ stw r10,-12($inp)+ stw r11,-8($inp)+ stw r12,-4($inp)+ bdnz Ldeckey++ xor r3,r3,r3 # return value+Ldec_key_abort:+ addi $sp,$sp,$FRAME+ blr+ .long 0+ .byte 0,12,4,1,0x80,0,3,0+ .long 0+.size .${prefix}_set_decrypt_key,.-.${prefix}_set_decrypt_key+___+}}}+#########################################################################+{{{ # Single block en- and decrypt procedures #+sub gen_block () {+my $dir = shift;+my $n = $dir eq "de" ? "n" : "";+my ($inp,$out,$key,$rounds,$idx)=map("r$_",(3..7));++$code.=<<___;+.globl .${prefix}_${dir}crypt+.align 5+.${prefix}_${dir}crypt:+ lwz $rounds,240($key)+ lis r0,0xfc00+ mfspr $vrsave,256+ li $idx,15 # 15 is not typo+ mtspr 256,r0++ lvx v0,0,$inp+ neg r11,$out+ lvx v1,$idx,$inp+ lvsl v2,0,$inp # inpperm+ le?vspltisb v4,0x0f+ ?lvsl v3,0,r11 # outperm+ le?vxor v2,v2,v4+ li $idx,16+ vperm v0,v0,v1,v2 # align [and byte swap in LE]+ lvx v1,0,$key+ ?lvsl v5,0,$key # keyperm+ srwi $rounds,$rounds,1+ lvx v2,$idx,$key+ addi $idx,$idx,16+ subi $rounds,$rounds,1+ ?vperm v1,v1,v2,v5 # align round key++ vxor v0,v0,v1+ lvx v1,$idx,$key+ addi $idx,$idx,16+ mtctr $rounds++Loop_${dir}c:+ ?vperm v2,v2,v1,v5+ v${n}cipher v0,v0,v2+ lvx v2,$idx,$key+ addi $idx,$idx,16+ ?vperm v1,v1,v2,v5+ v${n}cipher v0,v0,v1+ lvx v1,$idx,$key+ addi $idx,$idx,16+ bdnz Loop_${dir}c++ ?vperm v2,v2,v1,v5+ v${n}cipher v0,v0,v2+ lvx v2,$idx,$key+ ?vperm v1,v1,v2,v5+ v${n}cipherlast v0,v0,v1++ vspltisb v2,-1+ vxor v1,v1,v1+ li $idx,15 # 15 is not typo+ ?vperm v2,v1,v2,v3 # outmask+ le?vxor v3,v3,v4+ lvx v1,0,$out # outhead+ vperm v0,v0,v0,v3 # rotate [and byte swap in LE]+ vsel v1,v1,v0,v2+ lvx v4,$idx,$out+ stvx v1,0,$out+ vsel v0,v0,v4,v2+ stvx v0,$idx,$out++ mtspr 256,$vrsave+ blr+ .long 0+ .byte 0,12,0x14,0,0,0,3,0+ .long 0+.size .${prefix}_${dir}crypt,.-.${prefix}_${dir}crypt+___+}+&gen_block("en");+&gen_block("de");+}}}+#########################################################################+{{{ # CBC en- and decrypt procedures #+my ($inp,$out,$len,$key,$ivp,$enc,$rounds,$idx)=map("r$_",(3..10));+my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3));+my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm)=+ map("v$_",(4..10));+$code.=<<___;+.globl .${prefix}_cbc_encrypt+.align 5+.${prefix}_cbc_encrypt:+ ${UCMP}i $len,16+ bltlr-++ cmpwi $enc,0 # test direction+ lis r0,0xffe0+ mfspr $vrsave,256+ mtspr 256,r0++ li $idx,15+ vxor $rndkey0,$rndkey0,$rndkey0+ le?vspltisb $tmp,0x0f++ lvx $ivec,0,$ivp # load [unaligned] iv+ lvsl $inpperm,0,$ivp+ lvx $inptail,$idx,$ivp+ le?vxor $inpperm,$inpperm,$tmp+ vperm $ivec,$ivec,$inptail,$inpperm++ neg r11,$inp+ ?lvsl $keyperm,0,$key # prepare for unaligned key+ lwz $rounds,240($key)++ lvsr $inpperm,0,r11 # prepare for unaligned load+ lvx $inptail,0,$inp+ addi $inp,$inp,15 # 15 is not typo+ le?vxor $inpperm,$inpperm,$tmp++ ?lvsr $outperm,0,$out # prepare for unaligned store+ vspltisb $outmask,-1+ lvx $outhead,0,$out+ ?vperm $outmask,$rndkey0,$outmask,$outperm+ le?vxor $outperm,$outperm,$tmp++ srwi $rounds,$rounds,1+ li $idx,16+ subi $rounds,$rounds,1+ beq Lcbc_dec++Lcbc_enc:+ vmr $inout,$inptail+ lvx $inptail,0,$inp+ addi $inp,$inp,16+ mtctr $rounds+ subi $len,$len,16 # len-=16++ lvx $rndkey0,0,$key+ vperm $inout,$inout,$inptail,$inpperm+ lvx $rndkey1,$idx,$key+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key+ addi $idx,$idx,16+ vxor $inout,$inout,$ivec++Loop_cbc_enc:+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vcipher $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key+ addi $idx,$idx,16+ bdnz Loop_cbc_enc++ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key+ li $idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vcipherlast $ivec,$inout,$rndkey0+ ${UCMP}i $len,16++ vperm $tmp,$ivec,$ivec,$outperm+ vsel $inout,$outhead,$tmp,$outmask+ vmr $outhead,$tmp+ stvx $inout,0,$out+ addi $out,$out,16+ bge Lcbc_enc++ b Lcbc_done++.align 4+Lcbc_dec:+ ${UCMP}i $len,128+ bge _aesp8_cbc_decrypt8x+ vmr $tmp,$inptail+ lvx $inptail,0,$inp+ addi $inp,$inp,16+ mtctr $rounds+ subi $len,$len,16 # len-=16++ lvx $rndkey0,0,$key+ vperm $tmp,$tmp,$inptail,$inpperm+ lvx $rndkey1,$idx,$key+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $inout,$tmp,$rndkey0+ lvx $rndkey0,$idx,$key+ addi $idx,$idx,16++Loop_cbc_dec:+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vncipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vncipher $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key+ addi $idx,$idx,16+ bdnz Loop_cbc_dec++ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vncipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key+ li $idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vncipherlast $inout,$inout,$rndkey0+ ${UCMP}i $len,16++ vxor $inout,$inout,$ivec+ vmr $ivec,$tmp+ vperm $tmp,$inout,$inout,$outperm+ vsel $inout,$outhead,$tmp,$outmask+ vmr $outhead,$tmp+ stvx $inout,0,$out+ addi $out,$out,16+ bge Lcbc_dec++Lcbc_done:+ addi $out,$out,-1+ lvx $inout,0,$out # redundant in aligned case+ vsel $inout,$outhead,$inout,$outmask+ stvx $inout,0,$out++ neg $enc,$ivp # write [unaligned] iv+ li $idx,15 # 15 is not typo+ vxor $rndkey0,$rndkey0,$rndkey0+ vspltisb $outmask,-1+ le?vspltisb $tmp,0x0f+ ?lvsl $outperm,0,$enc+ ?vperm $outmask,$rndkey0,$outmask,$outperm+ le?vxor $outperm,$outperm,$tmp+ lvx $outhead,0,$ivp+ vperm $ivec,$ivec,$ivec,$outperm+ vsel $inout,$outhead,$ivec,$outmask+ lvx $inptail,$idx,$ivp+ stvx $inout,0,$ivp+ vsel $inout,$ivec,$inptail,$outmask+ stvx $inout,$idx,$ivp++ mtspr 256,$vrsave+ blr+ .long 0+ .byte 0,12,0x14,0,0,0,6,0+ .long 0+___+#########################################################################+{{ # Optimized CBC decrypt procedure #+my $key_="r11";+my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31));+ $x00=0 if ($flavour =~ /osx/);+my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10..13));+my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(14..21));+my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys+ # v26-v31 last 6 round keys+my ($tmp,$keyperm)=($in3,$in4); # aliases with "caller", redundant assignment++$code.=<<___;+.align 5+_aesp8_cbc_decrypt8x:+ $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)+ li r10,`$FRAME+8*16+15`+ li r11,`$FRAME+8*16+31`+ stvx v20,r10,$sp # ABI says so+ addi r10,r10,32+ stvx v21,r11,$sp+ addi r11,r11,32+ stvx v22,r10,$sp+ addi r10,r10,32+ stvx v23,r11,$sp+ addi r11,r11,32+ stvx v24,r10,$sp+ addi r10,r10,32+ stvx v25,r11,$sp+ addi r11,r11,32+ stvx v26,r10,$sp+ addi r10,r10,32+ stvx v27,r11,$sp+ addi r11,r11,32+ stvx v28,r10,$sp+ addi r10,r10,32+ stvx v29,r11,$sp+ addi r11,r11,32+ stvx v30,r10,$sp+ stvx v31,r11,$sp+ li r0,-1+ stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave+ li $x10,0x10+ $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp)+ li $x20,0x20+ $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp)+ li $x30,0x30+ $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp)+ li $x40,0x40+ $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp)+ li $x50,0x50+ $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp)+ li $x60,0x60+ $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp)+ li $x70,0x70+ mtspr 256,r0++ subi $rounds,$rounds,3 # -4 in total+ subi $len,$len,128 # bias++ lvx $rndkey0,$x00,$key # load key schedule+ lvx v30,$x10,$key+ addi $key,$key,0x20+ lvx v31,$x00,$key+ ?vperm $rndkey0,$rndkey0,v30,$keyperm+ addi $key_,$sp,$FRAME+15+ mtctr $rounds++Load_cbc_dec_key:+ ?vperm v24,v30,v31,$keyperm+ lvx v30,$x10,$key+ addi $key,$key,0x20+ stvx v24,$x00,$key_ # off-load round[1]+ ?vperm v25,v31,v30,$keyperm+ lvx v31,$x00,$key+ stvx v25,$x10,$key_ # off-load round[2]+ addi $key_,$key_,0x20+ bdnz Load_cbc_dec_key++ lvx v26,$x10,$key+ ?vperm v24,v30,v31,$keyperm+ lvx v27,$x20,$key+ stvx v24,$x00,$key_ # off-load round[3]+ ?vperm v25,v31,v26,$keyperm+ lvx v28,$x30,$key+ stvx v25,$x10,$key_ # off-load round[4]+ addi $key_,$sp,$FRAME+15 # rewind $key_+ ?vperm v26,v26,v27,$keyperm+ lvx v29,$x40,$key+ ?vperm v27,v27,v28,$keyperm+ lvx v30,$x50,$key+ ?vperm v28,v28,v29,$keyperm+ lvx v31,$x60,$key+ ?vperm v29,v29,v30,$keyperm+ lvx $out0,$x70,$key # borrow $out0+ ?vperm v30,v30,v31,$keyperm+ lvx v24,$x00,$key_ # pre-load round[1]+ ?vperm v31,v31,$out0,$keyperm+ lvx v25,$x10,$key_ # pre-load round[2]++ #lvx $inptail,0,$inp # "caller" already did this+ #addi $inp,$inp,15 # 15 is not typo+ subi $inp,$inp,15 # undo "caller"++ le?li $idx,8+ lvx_u $in0,$x00,$inp # load first 8 "words"+ le?lvsl $inpperm,0,$idx+ le?vspltisb $tmp,0x0f+ lvx_u $in1,$x10,$inp+ le?vxor $inpperm,$inpperm,$tmp # transform for lvx_u/stvx_u+ lvx_u $in2,$x20,$inp+ le?vperm $in0,$in0,$in0,$inpperm+ lvx_u $in3,$x30,$inp+ le?vperm $in1,$in1,$in1,$inpperm+ lvx_u $in4,$x40,$inp+ le?vperm $in2,$in2,$in2,$inpperm+ vxor $out0,$in0,$rndkey0+ lvx_u $in5,$x50,$inp+ le?vperm $in3,$in3,$in3,$inpperm+ vxor $out1,$in1,$rndkey0+ lvx_u $in6,$x60,$inp+ le?vperm $in4,$in4,$in4,$inpperm+ vxor $out2,$in2,$rndkey0+ lvx_u $in7,$x70,$inp+ addi $inp,$inp,0x80+ le?vperm $in5,$in5,$in5,$inpperm+ vxor $out3,$in3,$rndkey0+ le?vperm $in6,$in6,$in6,$inpperm+ vxor $out4,$in4,$rndkey0+ le?vperm $in7,$in7,$in7,$inpperm+ vxor $out5,$in5,$rndkey0+ vxor $out6,$in6,$rndkey0+ vxor $out7,$in7,$rndkey0++ mtctr $rounds+ b Loop_cbc_dec8x+.align 5+Loop_cbc_dec8x:+ vncipher $out0,$out0,v24+ vncipher $out1,$out1,v24+ vncipher $out2,$out2,v24+ vncipher $out3,$out3,v24+ vncipher $out4,$out4,v24+ vncipher $out5,$out5,v24+ vncipher $out6,$out6,v24+ vncipher $out7,$out7,v24+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vncipher $out0,$out0,v25+ vncipher $out1,$out1,v25+ vncipher $out2,$out2,v25+ vncipher $out3,$out3,v25+ vncipher $out4,$out4,v25+ vncipher $out5,$out5,v25+ vncipher $out6,$out6,v25+ vncipher $out7,$out7,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz Loop_cbc_dec8x++ subic $len,$len,128 # $len-=128+ vncipher $out0,$out0,v24+ vncipher $out1,$out1,v24+ vncipher $out2,$out2,v24+ vncipher $out3,$out3,v24+ vncipher $out4,$out4,v24+ vncipher $out5,$out5,v24+ vncipher $out6,$out6,v24+ vncipher $out7,$out7,v24++ subfe. r0,r0,r0 # borrow?-1:0+ vncipher $out0,$out0,v25+ vncipher $out1,$out1,v25+ vncipher $out2,$out2,v25+ vncipher $out3,$out3,v25+ vncipher $out4,$out4,v25+ vncipher $out5,$out5,v25+ vncipher $out6,$out6,v25+ vncipher $out7,$out7,v25++ and r0,r0,$len+ vncipher $out0,$out0,v26+ vncipher $out1,$out1,v26+ vncipher $out2,$out2,v26+ vncipher $out3,$out3,v26+ vncipher $out4,$out4,v26+ vncipher $out5,$out5,v26+ vncipher $out6,$out6,v26+ vncipher $out7,$out7,v26++ add $inp,$inp,r0 # $inp is adjusted in such+ # way that at exit from the+ # loop inX-in7 are loaded+ # with last "words"+ vncipher $out0,$out0,v27+ vncipher $out1,$out1,v27+ vncipher $out2,$out2,v27+ vncipher $out3,$out3,v27+ vncipher $out4,$out4,v27+ vncipher $out5,$out5,v27+ vncipher $out6,$out6,v27+ vncipher $out7,$out7,v27++ addi $key_,$sp,$FRAME+15 # rewind $key_+ vncipher $out0,$out0,v28+ vncipher $out1,$out1,v28+ vncipher $out2,$out2,v28+ vncipher $out3,$out3,v28+ vncipher $out4,$out4,v28+ vncipher $out5,$out5,v28+ vncipher $out6,$out6,v28+ vncipher $out7,$out7,v28+ lvx v24,$x00,$key_ # re-pre-load round[1]++ vncipher $out0,$out0,v29+ vncipher $out1,$out1,v29+ vncipher $out2,$out2,v29+ vncipher $out3,$out3,v29+ vncipher $out4,$out4,v29+ vncipher $out5,$out5,v29+ vncipher $out6,$out6,v29+ vncipher $out7,$out7,v29+ lvx v25,$x10,$key_ # re-pre-load round[2]++ vncipher $out0,$out0,v30+ vxor $ivec,$ivec,v31 # xor with last round key+ vncipher $out1,$out1,v30+ vxor $in0,$in0,v31+ vncipher $out2,$out2,v30+ vxor $in1,$in1,v31+ vncipher $out3,$out3,v30+ vxor $in2,$in2,v31+ vncipher $out4,$out4,v30+ vxor $in3,$in3,v31+ vncipher $out5,$out5,v30+ vxor $in4,$in4,v31+ vncipher $out6,$out6,v30+ vxor $in5,$in5,v31+ vncipher $out7,$out7,v30+ vxor $in6,$in6,v31++ vncipherlast $out0,$out0,$ivec+ vncipherlast $out1,$out1,$in0+ lvx_u $in0,$x00,$inp # load next input block+ vncipherlast $out2,$out2,$in1+ lvx_u $in1,$x10,$inp+ vncipherlast $out3,$out3,$in2+ le?vperm $in0,$in0,$in0,$inpperm+ lvx_u $in2,$x20,$inp+ vncipherlast $out4,$out4,$in3+ le?vperm $in1,$in1,$in1,$inpperm+ lvx_u $in3,$x30,$inp+ vncipherlast $out5,$out5,$in4+ le?vperm $in2,$in2,$in2,$inpperm+ lvx_u $in4,$x40,$inp+ vncipherlast $out6,$out6,$in5+ le?vperm $in3,$in3,$in3,$inpperm+ lvx_u $in5,$x50,$inp+ vncipherlast $out7,$out7,$in6+ le?vperm $in4,$in4,$in4,$inpperm+ lvx_u $in6,$x60,$inp+ vmr $ivec,$in7+ le?vperm $in5,$in5,$in5,$inpperm+ lvx_u $in7,$x70,$inp+ addi $inp,$inp,0x80++ le?vperm $out0,$out0,$out0,$inpperm+ le?vperm $out1,$out1,$out1,$inpperm+ stvx_u $out0,$x00,$out+ le?vperm $in6,$in6,$in6,$inpperm+ vxor $out0,$in0,$rndkey0+ le?vperm $out2,$out2,$out2,$inpperm+ stvx_u $out1,$x10,$out+ le?vperm $in7,$in7,$in7,$inpperm+ vxor $out1,$in1,$rndkey0+ le?vperm $out3,$out3,$out3,$inpperm+ stvx_u $out2,$x20,$out+ vxor $out2,$in2,$rndkey0+ le?vperm $out4,$out4,$out4,$inpperm+ stvx_u $out3,$x30,$out+ vxor $out3,$in3,$rndkey0+ le?vperm $out5,$out5,$out5,$inpperm+ stvx_u $out4,$x40,$out+ vxor $out4,$in4,$rndkey0+ le?vperm $out6,$out6,$out6,$inpperm+ stvx_u $out5,$x50,$out+ vxor $out5,$in5,$rndkey0+ le?vperm $out7,$out7,$out7,$inpperm+ stvx_u $out6,$x60,$out+ vxor $out6,$in6,$rndkey0+ stvx_u $out7,$x70,$out+ addi $out,$out,0x80+ vxor $out7,$in7,$rndkey0++ mtctr $rounds+ beq Loop_cbc_dec8x # did $len-=128 borrow?++ addic. $len,$len,128+ beq Lcbc_dec8x_done+ nop+ nop++Loop_cbc_dec8x_tail: # up to 7 "words" tail...+ vncipher $out1,$out1,v24+ vncipher $out2,$out2,v24+ vncipher $out3,$out3,v24+ vncipher $out4,$out4,v24+ vncipher $out5,$out5,v24+ vncipher $out6,$out6,v24+ vncipher $out7,$out7,v24+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vncipher $out1,$out1,v25+ vncipher $out2,$out2,v25+ vncipher $out3,$out3,v25+ vncipher $out4,$out4,v25+ vncipher $out5,$out5,v25+ vncipher $out6,$out6,v25+ vncipher $out7,$out7,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz Loop_cbc_dec8x_tail++ vncipher $out1,$out1,v24+ vncipher $out2,$out2,v24+ vncipher $out3,$out3,v24+ vncipher $out4,$out4,v24+ vncipher $out5,$out5,v24+ vncipher $out6,$out6,v24+ vncipher $out7,$out7,v24++ vncipher $out1,$out1,v25+ vncipher $out2,$out2,v25+ vncipher $out3,$out3,v25+ vncipher $out4,$out4,v25+ vncipher $out5,$out5,v25+ vncipher $out6,$out6,v25+ vncipher $out7,$out7,v25++ vncipher $out1,$out1,v26+ vncipher $out2,$out2,v26+ vncipher $out3,$out3,v26+ vncipher $out4,$out4,v26+ vncipher $out5,$out5,v26+ vncipher $out6,$out6,v26+ vncipher $out7,$out7,v26++ vncipher $out1,$out1,v27+ vncipher $out2,$out2,v27+ vncipher $out3,$out3,v27+ vncipher $out4,$out4,v27+ vncipher $out5,$out5,v27+ vncipher $out6,$out6,v27+ vncipher $out7,$out7,v27++ vncipher $out1,$out1,v28+ vncipher $out2,$out2,v28+ vncipher $out3,$out3,v28+ vncipher $out4,$out4,v28+ vncipher $out5,$out5,v28+ vncipher $out6,$out6,v28+ vncipher $out7,$out7,v28++ vncipher $out1,$out1,v29+ vncipher $out2,$out2,v29+ vncipher $out3,$out3,v29+ vncipher $out4,$out4,v29+ vncipher $out5,$out5,v29+ vncipher $out6,$out6,v29+ vncipher $out7,$out7,v29++ vncipher $out1,$out1,v30+ vxor $ivec,$ivec,v31 # last round key+ vncipher $out2,$out2,v30+ vxor $in1,$in1,v31+ vncipher $out3,$out3,v30+ vxor $in2,$in2,v31+ vncipher $out4,$out4,v30+ vxor $in3,$in3,v31+ vncipher $out5,$out5,v30+ vxor $in4,$in4,v31+ vncipher $out6,$out6,v30+ vxor $in5,$in5,v31+ vncipher $out7,$out7,v30+ vxor $in6,$in6,v31++ cmplwi $len,32 # switch($len)+ blt Lcbc_dec8x_one+ nop+ beq Lcbc_dec8x_two+ cmplwi $len,64+ blt Lcbc_dec8x_three+ nop+ beq Lcbc_dec8x_four+ cmplwi $len,96+ blt Lcbc_dec8x_five+ nop+ beq Lcbc_dec8x_six++Lcbc_dec8x_seven:+ vncipherlast $out1,$out1,$ivec+ vncipherlast $out2,$out2,$in1+ vncipherlast $out3,$out3,$in2+ vncipherlast $out4,$out4,$in3+ vncipherlast $out5,$out5,$in4+ vncipherlast $out6,$out6,$in5+ vncipherlast $out7,$out7,$in6+ vmr $ivec,$in7++ le?vperm $out1,$out1,$out1,$inpperm+ le?vperm $out2,$out2,$out2,$inpperm+ stvx_u $out1,$x00,$out+ le?vperm $out3,$out3,$out3,$inpperm+ stvx_u $out2,$x10,$out+ le?vperm $out4,$out4,$out4,$inpperm+ stvx_u $out3,$x20,$out+ le?vperm $out5,$out5,$out5,$inpperm+ stvx_u $out4,$x30,$out+ le?vperm $out6,$out6,$out6,$inpperm+ stvx_u $out5,$x40,$out+ le?vperm $out7,$out7,$out7,$inpperm+ stvx_u $out6,$x50,$out+ stvx_u $out7,$x60,$out+ addi $out,$out,0x70+ b Lcbc_dec8x_done++.align 5+Lcbc_dec8x_six:+ vncipherlast $out2,$out2,$ivec+ vncipherlast $out3,$out3,$in2+ vncipherlast $out4,$out4,$in3+ vncipherlast $out5,$out5,$in4+ vncipherlast $out6,$out6,$in5+ vncipherlast $out7,$out7,$in6+ vmr $ivec,$in7++ le?vperm $out2,$out2,$out2,$inpperm+ le?vperm $out3,$out3,$out3,$inpperm+ stvx_u $out2,$x00,$out+ le?vperm $out4,$out4,$out4,$inpperm+ stvx_u $out3,$x10,$out+ le?vperm $out5,$out5,$out5,$inpperm+ stvx_u $out4,$x20,$out+ le?vperm $out6,$out6,$out6,$inpperm+ stvx_u $out5,$x30,$out+ le?vperm $out7,$out7,$out7,$inpperm+ stvx_u $out6,$x40,$out+ stvx_u $out7,$x50,$out+ addi $out,$out,0x60+ b Lcbc_dec8x_done++.align 5+Lcbc_dec8x_five:+ vncipherlast $out3,$out3,$ivec+ vncipherlast $out4,$out4,$in3+ vncipherlast $out5,$out5,$in4+ vncipherlast $out6,$out6,$in5+ vncipherlast $out7,$out7,$in6+ vmr $ivec,$in7++ le?vperm $out3,$out3,$out3,$inpperm+ le?vperm $out4,$out4,$out4,$inpperm+ stvx_u $out3,$x00,$out+ le?vperm $out5,$out5,$out5,$inpperm+ stvx_u $out4,$x10,$out+ le?vperm $out6,$out6,$out6,$inpperm+ stvx_u $out5,$x20,$out+ le?vperm $out7,$out7,$out7,$inpperm+ stvx_u $out6,$x30,$out+ stvx_u $out7,$x40,$out+ addi $out,$out,0x50+ b Lcbc_dec8x_done++.align 5+Lcbc_dec8x_four:+ vncipherlast $out4,$out4,$ivec+ vncipherlast $out5,$out5,$in4+ vncipherlast $out6,$out6,$in5+ vncipherlast $out7,$out7,$in6+ vmr $ivec,$in7++ le?vperm $out4,$out4,$out4,$inpperm+ le?vperm $out5,$out5,$out5,$inpperm+ stvx_u $out4,$x00,$out+ le?vperm $out6,$out6,$out6,$inpperm+ stvx_u $out5,$x10,$out+ le?vperm $out7,$out7,$out7,$inpperm+ stvx_u $out6,$x20,$out+ stvx_u $out7,$x30,$out+ addi $out,$out,0x40+ b Lcbc_dec8x_done++.align 5+Lcbc_dec8x_three:+ vncipherlast $out5,$out5,$ivec+ vncipherlast $out6,$out6,$in5+ vncipherlast $out7,$out7,$in6+ vmr $ivec,$in7++ le?vperm $out5,$out5,$out5,$inpperm+ le?vperm $out6,$out6,$out6,$inpperm+ stvx_u $out5,$x00,$out+ le?vperm $out7,$out7,$out7,$inpperm+ stvx_u $out6,$x10,$out+ stvx_u $out7,$x20,$out+ addi $out,$out,0x30+ b Lcbc_dec8x_done++.align 5+Lcbc_dec8x_two:+ vncipherlast $out6,$out6,$ivec+ vncipherlast $out7,$out7,$in6+ vmr $ivec,$in7++ le?vperm $out6,$out6,$out6,$inpperm+ le?vperm $out7,$out7,$out7,$inpperm+ stvx_u $out6,$x00,$out+ stvx_u $out7,$x10,$out+ addi $out,$out,0x20+ b Lcbc_dec8x_done++.align 5+Lcbc_dec8x_one:+ vncipherlast $out7,$out7,$ivec+ vmr $ivec,$in7++ le?vperm $out7,$out7,$out7,$inpperm+ stvx_u $out7,0,$out+ addi $out,$out,0x10++Lcbc_dec8x_done:+ le?vperm $ivec,$ivec,$ivec,$inpperm+ stvx_u $ivec,0,$ivp # write [unaligned] iv++ li r10,`$FRAME+15`+ li r11,`$FRAME+31`+ stvx $inpperm,r10,$sp # wipe copies of round keys+ addi r10,r10,32+ stvx $inpperm,r11,$sp+ addi r11,r11,32+ stvx $inpperm,r10,$sp+ addi r10,r10,32+ stvx $inpperm,r11,$sp+ addi r11,r11,32+ stvx $inpperm,r10,$sp+ addi r10,r10,32+ stvx $inpperm,r11,$sp+ addi r11,r11,32+ stvx $inpperm,r10,$sp+ addi r10,r10,32+ stvx $inpperm,r11,$sp+ addi r11,r11,32++ mtspr 256,$vrsave+ lvx v20,r10,$sp # ABI says so+ addi r10,r10,32+ lvx v21,r11,$sp+ addi r11,r11,32+ lvx v22,r10,$sp+ addi r10,r10,32+ lvx v23,r11,$sp+ addi r11,r11,32+ lvx v24,r10,$sp+ addi r10,r10,32+ lvx v25,r11,$sp+ addi r11,r11,32+ lvx v26,r10,$sp+ addi r10,r10,32+ lvx v27,r11,$sp+ addi r11,r11,32+ lvx v28,r10,$sp+ addi r10,r10,32+ lvx v29,r11,$sp+ addi r11,r11,32+ lvx v30,r10,$sp+ lvx v31,r11,$sp+ $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp)+ $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp)+ $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp)+ $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp)+ $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp)+ $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp)+ addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T`+ blr+ .long 0+ .byte 0,12,0x04,0,0x80,6,6,0+ .long 0+.size .${prefix}_cbc_encrypt,.-.${prefix}_cbc_encrypt+___+}} }}}++#########################################################################+{{{ # CTR procedure[s] #+my ($inp,$out,$len,$key,$ivp,$x10,$rounds,$idx)=map("r$_",(3..10));+my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3));+my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm,$one)=+ map("v$_",(4..11));+my $dat=$tmp;++$code.=<<___;+.globl .${prefix}_ctr32_encrypt_blocks+.align 5+.${prefix}_ctr32_encrypt_blocks:+ ${UCMP}i $len,1+ bltlr-++ lis r0,0xfff0+ mfspr $vrsave,256+ mtspr 256,r0++ li $idx,15+ vxor $rndkey0,$rndkey0,$rndkey0+ le?vspltisb $tmp,0x0f++ lvx $ivec,0,$ivp # load [unaligned] iv+ lvsl $inpperm,0,$ivp+ lvx $inptail,$idx,$ivp+ vspltisb $one,1+ le?vxor $inpperm,$inpperm,$tmp+ vperm $ivec,$ivec,$inptail,$inpperm+ vsldoi $one,$rndkey0,$one,1++ neg r11,$inp+ ?lvsl $keyperm,0,$key # prepare for unaligned key+ lwz $rounds,240($key)++ lvsr $inpperm,0,r11 # prepare for unaligned load+ lvx $inptail,0,$inp+ addi $inp,$inp,15 # 15 is not typo+ le?vxor $inpperm,$inpperm,$tmp++ srwi $rounds,$rounds,1+ li $idx,16+ subi $rounds,$rounds,1++ ${UCMP}i $len,8+ bge _aesp8_ctr32_encrypt8x++ ?lvsr $outperm,0,$out # prepare for unaligned store+ vspltisb $outmask,-1+ lvx $outhead,0,$out+ ?vperm $outmask,$rndkey0,$outmask,$outperm+ le?vxor $outperm,$outperm,$tmp++ lvx $rndkey0,0,$key+ mtctr $rounds+ lvx $rndkey1,$idx,$key+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $inout,$ivec,$rndkey0+ lvx $rndkey0,$idx,$key+ addi $idx,$idx,16+ b Loop_ctr32_enc++.align 5+Loop_ctr32_enc:+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vcipher $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key+ addi $idx,$idx,16+ bdnz Loop_ctr32_enc++ vadduwm $ivec,$ivec,$one+ vmr $dat,$inptail+ lvx $inptail,0,$inp+ addi $inp,$inp,16+ subic. $len,$len,1 # blocks--++ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key+ vperm $dat,$dat,$inptail,$inpperm+ li $idx,16+ ?vperm $rndkey1,$rndkey0,$rndkey1,$keyperm+ lvx $rndkey0,0,$key+ vxor $dat,$dat,$rndkey1 # last round key+ vcipherlast $inout,$inout,$dat++ lvx $rndkey1,$idx,$key+ addi $idx,$idx,16+ vperm $inout,$inout,$inout,$outperm+ vsel $dat,$outhead,$inout,$outmask+ mtctr $rounds+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vmr $outhead,$inout+ vxor $inout,$ivec,$rndkey0+ lvx $rndkey0,$idx,$key+ addi $idx,$idx,16+ stvx $dat,0,$out+ addi $out,$out,16+ bne Loop_ctr32_enc++ addi $out,$out,-1+ lvx $inout,0,$out # redundant in aligned case+ vsel $inout,$outhead,$inout,$outmask+ stvx $inout,0,$out++ mtspr 256,$vrsave+ blr+ .long 0+ .byte 0,12,0x14,0,0,0,6,0+ .long 0+___+#########################################################################+{{ # Optimized CTR procedure #+my $key_="r11";+my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31));+ $x00=0 if ($flavour =~ /osx/);+my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10,12..14));+my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(15..22));+my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys+ # v26-v31 last 6 round keys+my ($tmp,$keyperm)=($in3,$in4); # aliases with "caller", redundant assignment+my ($two,$three,$four)=($outhead,$outperm,$outmask);++$code.=<<___;+.align 5+_aesp8_ctr32_encrypt8x:+ $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)+ li r10,`$FRAME+8*16+15`+ li r11,`$FRAME+8*16+31`+ stvx v20,r10,$sp # ABI says so+ addi r10,r10,32+ stvx v21,r11,$sp+ addi r11,r11,32+ stvx v22,r10,$sp+ addi r10,r10,32+ stvx v23,r11,$sp+ addi r11,r11,32+ stvx v24,r10,$sp+ addi r10,r10,32+ stvx v25,r11,$sp+ addi r11,r11,32+ stvx v26,r10,$sp+ addi r10,r10,32+ stvx v27,r11,$sp+ addi r11,r11,32+ stvx v28,r10,$sp+ addi r10,r10,32+ stvx v29,r11,$sp+ addi r11,r11,32+ stvx v30,r10,$sp+ stvx v31,r11,$sp+ li r0,-1+ stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave+ li $x10,0x10+ $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp)+ li $x20,0x20+ $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp)+ li $x30,0x30+ $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp)+ li $x40,0x40+ $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp)+ li $x50,0x50+ $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp)+ li $x60,0x60+ $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp)+ li $x70,0x70+ mtspr 256,r0++ subi $rounds,$rounds,3 # -4 in total++ lvx $rndkey0,$x00,$key # load key schedule+ lvx v30,$x10,$key+ addi $key,$key,0x20+ lvx v31,$x00,$key+ ?vperm $rndkey0,$rndkey0,v30,$keyperm+ addi $key_,$sp,$FRAME+15+ mtctr $rounds++Load_ctr32_enc_key:+ ?vperm v24,v30,v31,$keyperm+ lvx v30,$x10,$key+ addi $key,$key,0x20+ stvx v24,$x00,$key_ # off-load round[1]+ ?vperm v25,v31,v30,$keyperm+ lvx v31,$x00,$key+ stvx v25,$x10,$key_ # off-load round[2]+ addi $key_,$key_,0x20+ bdnz Load_ctr32_enc_key++ lvx v26,$x10,$key+ ?vperm v24,v30,v31,$keyperm+ lvx v27,$x20,$key+ stvx v24,$x00,$key_ # off-load round[3]+ ?vperm v25,v31,v26,$keyperm+ lvx v28,$x30,$key+ stvx v25,$x10,$key_ # off-load round[4]+ addi $key_,$sp,$FRAME+15 # rewind $key_+ ?vperm v26,v26,v27,$keyperm+ lvx v29,$x40,$key+ ?vperm v27,v27,v28,$keyperm+ lvx v30,$x50,$key+ ?vperm v28,v28,v29,$keyperm+ lvx v31,$x60,$key+ ?vperm v29,v29,v30,$keyperm+ lvx $out0,$x70,$key # borrow $out0+ ?vperm v30,v30,v31,$keyperm+ lvx v24,$x00,$key_ # pre-load round[1]+ ?vperm v31,v31,$out0,$keyperm+ lvx v25,$x10,$key_ # pre-load round[2]++ vadduwm $two,$one,$one+ subi $inp,$inp,15 # undo "caller"+ $SHL $len,$len,4++ vadduwm $out1,$ivec,$one # counter values ...+ vadduwm $out2,$ivec,$two+ vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0]+ le?li $idx,8+ vadduwm $out3,$out1,$two+ vxor $out1,$out1,$rndkey0+ le?lvsl $inpperm,0,$idx+ vadduwm $out4,$out2,$two+ vxor $out2,$out2,$rndkey0+ le?vspltisb $tmp,0x0f+ vadduwm $out5,$out3,$two+ vxor $out3,$out3,$rndkey0+ le?vxor $inpperm,$inpperm,$tmp # transform for lvx_u/stvx_u+ vadduwm $out6,$out4,$two+ vxor $out4,$out4,$rndkey0+ vadduwm $out7,$out5,$two+ vxor $out5,$out5,$rndkey0+ vadduwm $ivec,$out6,$two # next counter value+ vxor $out6,$out6,$rndkey0+ vxor $out7,$out7,$rndkey0++ mtctr $rounds+ b Loop_ctr32_enc8x+.align 5+Loop_ctr32_enc8x:+ vcipher $out0,$out0,v24+ vcipher $out1,$out1,v24+ vcipher $out2,$out2,v24+ vcipher $out3,$out3,v24+ vcipher $out4,$out4,v24+ vcipher $out5,$out5,v24+ vcipher $out6,$out6,v24+ vcipher $out7,$out7,v24+Loop_ctr32_enc8x_middle:+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vcipher $out0,$out0,v25+ vcipher $out1,$out1,v25+ vcipher $out2,$out2,v25+ vcipher $out3,$out3,v25+ vcipher $out4,$out4,v25+ vcipher $out5,$out5,v25+ vcipher $out6,$out6,v25+ vcipher $out7,$out7,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz Loop_ctr32_enc8x++ subic r11,$len,256 # $len-256, borrow $key_+ vcipher $out0,$out0,v24+ vcipher $out1,$out1,v24+ vcipher $out2,$out2,v24+ vcipher $out3,$out3,v24+ vcipher $out4,$out4,v24+ vcipher $out5,$out5,v24+ vcipher $out6,$out6,v24+ vcipher $out7,$out7,v24++ subfe r0,r0,r0 # borrow?-1:0+ vcipher $out0,$out0,v25+ vcipher $out1,$out1,v25+ vcipher $out2,$out2,v25+ vcipher $out3,$out3,v25+ vcipher $out4,$out4,v25+ vcipher $out5,$out5,v25+ vcipher $out6,$out6,v25+ vcipher $out7,$out7,v25++ and r0,r0,r11+ addi $key_,$sp,$FRAME+15 # rewind $key_+ vcipher $out0,$out0,v26+ vcipher $out1,$out1,v26+ vcipher $out2,$out2,v26+ vcipher $out3,$out3,v26+ vcipher $out4,$out4,v26+ vcipher $out5,$out5,v26+ vcipher $out6,$out6,v26+ vcipher $out7,$out7,v26+ lvx v24,$x00,$key_ # re-pre-load round[1]++ subic $len,$len,129 # $len-=129+ vcipher $out0,$out0,v27+ addi $len,$len,1 # $len-=128 really+ vcipher $out1,$out1,v27+ vcipher $out2,$out2,v27+ vcipher $out3,$out3,v27+ vcipher $out4,$out4,v27+ vcipher $out5,$out5,v27+ vcipher $out6,$out6,v27+ vcipher $out7,$out7,v27+ lvx v25,$x10,$key_ # re-pre-load round[2]++ vcipher $out0,$out0,v28+ lvx_u $in0,$x00,$inp # load input+ vcipher $out1,$out1,v28+ lvx_u $in1,$x10,$inp+ vcipher $out2,$out2,v28+ lvx_u $in2,$x20,$inp+ vcipher $out3,$out3,v28+ lvx_u $in3,$x30,$inp+ vcipher $out4,$out4,v28+ lvx_u $in4,$x40,$inp+ vcipher $out5,$out5,v28+ lvx_u $in5,$x50,$inp+ vcipher $out6,$out6,v28+ lvx_u $in6,$x60,$inp+ vcipher $out7,$out7,v28+ lvx_u $in7,$x70,$inp+ addi $inp,$inp,0x80++ vcipher $out0,$out0,v29+ le?vperm $in0,$in0,$in0,$inpperm+ vcipher $out1,$out1,v29+ le?vperm $in1,$in1,$in1,$inpperm+ vcipher $out2,$out2,v29+ le?vperm $in2,$in2,$in2,$inpperm+ vcipher $out3,$out3,v29+ le?vperm $in3,$in3,$in3,$inpperm+ vcipher $out4,$out4,v29+ le?vperm $in4,$in4,$in4,$inpperm+ vcipher $out5,$out5,v29+ le?vperm $in5,$in5,$in5,$inpperm+ vcipher $out6,$out6,v29+ le?vperm $in6,$in6,$in6,$inpperm+ vcipher $out7,$out7,v29+ le?vperm $in7,$in7,$in7,$inpperm++ add $inp,$inp,r0 # $inp is adjusted in such+ # way that at exit from the+ # loop inX-in7 are loaded+ # with last "words"+ subfe. r0,r0,r0 # borrow?-1:0+ vcipher $out0,$out0,v30+ vxor $in0,$in0,v31 # xor with last round key+ vcipher $out1,$out1,v30+ vxor $in1,$in1,v31+ vcipher $out2,$out2,v30+ vxor $in2,$in2,v31+ vcipher $out3,$out3,v30+ vxor $in3,$in3,v31+ vcipher $out4,$out4,v30+ vxor $in4,$in4,v31+ vcipher $out5,$out5,v30+ vxor $in5,$in5,v31+ vcipher $out6,$out6,v30+ vxor $in6,$in6,v31+ vcipher $out7,$out7,v30+ vxor $in7,$in7,v31++ bne Lctr32_enc8x_break # did $len-129 borrow?++ vcipherlast $in0,$out0,$in0+ vcipherlast $in1,$out1,$in1+ vadduwm $out1,$ivec,$one # counter values ...+ vcipherlast $in2,$out2,$in2+ vadduwm $out2,$ivec,$two+ vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0]+ vcipherlast $in3,$out3,$in3+ vadduwm $out3,$out1,$two+ vxor $out1,$out1,$rndkey0+ vcipherlast $in4,$out4,$in4+ vadduwm $out4,$out2,$two+ vxor $out2,$out2,$rndkey0+ vcipherlast $in5,$out5,$in5+ vadduwm $out5,$out3,$two+ vxor $out3,$out3,$rndkey0+ vcipherlast $in6,$out6,$in6+ vadduwm $out6,$out4,$two+ vxor $out4,$out4,$rndkey0+ vcipherlast $in7,$out7,$in7+ vadduwm $out7,$out5,$two+ vxor $out5,$out5,$rndkey0+ le?vperm $in0,$in0,$in0,$inpperm+ vadduwm $ivec,$out6,$two # next counter value+ vxor $out6,$out6,$rndkey0+ le?vperm $in1,$in1,$in1,$inpperm+ vxor $out7,$out7,$rndkey0+ mtctr $rounds++ vcipher $out0,$out0,v24+ stvx_u $in0,$x00,$out+ le?vperm $in2,$in2,$in2,$inpperm+ vcipher $out1,$out1,v24+ stvx_u $in1,$x10,$out+ le?vperm $in3,$in3,$in3,$inpperm+ vcipher $out2,$out2,v24+ stvx_u $in2,$x20,$out+ le?vperm $in4,$in4,$in4,$inpperm+ vcipher $out3,$out3,v24+ stvx_u $in3,$x30,$out+ le?vperm $in5,$in5,$in5,$inpperm+ vcipher $out4,$out4,v24+ stvx_u $in4,$x40,$out+ le?vperm $in6,$in6,$in6,$inpperm+ vcipher $out5,$out5,v24+ stvx_u $in5,$x50,$out+ le?vperm $in7,$in7,$in7,$inpperm+ vcipher $out6,$out6,v24+ stvx_u $in6,$x60,$out+ vcipher $out7,$out7,v24+ stvx_u $in7,$x70,$out+ addi $out,$out,0x80++ b Loop_ctr32_enc8x_middle++.align 5+Lctr32_enc8x_break:+ cmpwi $len,-0x60+ blt Lctr32_enc8x_one+ nop+ beq Lctr32_enc8x_two+ cmpwi $len,-0x40+ blt Lctr32_enc8x_three+ nop+ beq Lctr32_enc8x_four+ cmpwi $len,-0x20+ blt Lctr32_enc8x_five+ nop+ beq Lctr32_enc8x_six+ cmpwi $len,0x00+ blt Lctr32_enc8x_seven++Lctr32_enc8x_eight:+ vcipherlast $out0,$out0,$in0+ vcipherlast $out1,$out1,$in1+ vcipherlast $out2,$out2,$in2+ vcipherlast $out3,$out3,$in3+ vcipherlast $out4,$out4,$in4+ vcipherlast $out5,$out5,$in5+ vcipherlast $out6,$out6,$in6+ vcipherlast $out7,$out7,$in7++ le?vperm $out0,$out0,$out0,$inpperm+ le?vperm $out1,$out1,$out1,$inpperm+ stvx_u $out0,$x00,$out+ le?vperm $out2,$out2,$out2,$inpperm+ stvx_u $out1,$x10,$out+ le?vperm $out3,$out3,$out3,$inpperm+ stvx_u $out2,$x20,$out+ le?vperm $out4,$out4,$out4,$inpperm+ stvx_u $out3,$x30,$out+ le?vperm $out5,$out5,$out5,$inpperm+ stvx_u $out4,$x40,$out+ le?vperm $out6,$out6,$out6,$inpperm+ stvx_u $out5,$x50,$out+ le?vperm $out7,$out7,$out7,$inpperm+ stvx_u $out6,$x60,$out+ stvx_u $out7,$x70,$out+ addi $out,$out,0x80+ b Lctr32_enc8x_done++.align 5+Lctr32_enc8x_seven:+ vcipherlast $out0,$out0,$in1+ vcipherlast $out1,$out1,$in2+ vcipherlast $out2,$out2,$in3+ vcipherlast $out3,$out3,$in4+ vcipherlast $out4,$out4,$in5+ vcipherlast $out5,$out5,$in6+ vcipherlast $out6,$out6,$in7++ le?vperm $out0,$out0,$out0,$inpperm+ le?vperm $out1,$out1,$out1,$inpperm+ stvx_u $out0,$x00,$out+ le?vperm $out2,$out2,$out2,$inpperm+ stvx_u $out1,$x10,$out+ le?vperm $out3,$out3,$out3,$inpperm+ stvx_u $out2,$x20,$out+ le?vperm $out4,$out4,$out4,$inpperm+ stvx_u $out3,$x30,$out+ le?vperm $out5,$out5,$out5,$inpperm+ stvx_u $out4,$x40,$out+ le?vperm $out6,$out6,$out6,$inpperm+ stvx_u $out5,$x50,$out+ stvx_u $out6,$x60,$out+ addi $out,$out,0x70+ b Lctr32_enc8x_done++.align 5+Lctr32_enc8x_six:+ vcipherlast $out0,$out0,$in2+ vcipherlast $out1,$out1,$in3+ vcipherlast $out2,$out2,$in4+ vcipherlast $out3,$out3,$in5+ vcipherlast $out4,$out4,$in6+ vcipherlast $out5,$out5,$in7++ le?vperm $out0,$out0,$out0,$inpperm+ le?vperm $out1,$out1,$out1,$inpperm+ stvx_u $out0,$x00,$out+ le?vperm $out2,$out2,$out2,$inpperm+ stvx_u $out1,$x10,$out+ le?vperm $out3,$out3,$out3,$inpperm+ stvx_u $out2,$x20,$out+ le?vperm $out4,$out4,$out4,$inpperm+ stvx_u $out3,$x30,$out+ le?vperm $out5,$out5,$out5,$inpperm+ stvx_u $out4,$x40,$out+ stvx_u $out5,$x50,$out+ addi $out,$out,0x60+ b Lctr32_enc8x_done++.align 5+Lctr32_enc8x_five:+ vcipherlast $out0,$out0,$in3+ vcipherlast $out1,$out1,$in4+ vcipherlast $out2,$out2,$in5+ vcipherlast $out3,$out3,$in6+ vcipherlast $out4,$out4,$in7++ le?vperm $out0,$out0,$out0,$inpperm+ le?vperm $out1,$out1,$out1,$inpperm+ stvx_u $out0,$x00,$out+ le?vperm $out2,$out2,$out2,$inpperm+ stvx_u $out1,$x10,$out+ le?vperm $out3,$out3,$out3,$inpperm+ stvx_u $out2,$x20,$out+ le?vperm $out4,$out4,$out4,$inpperm+ stvx_u $out3,$x30,$out+ stvx_u $out4,$x40,$out+ addi $out,$out,0x50+ b Lctr32_enc8x_done++.align 5+Lctr32_enc8x_four:+ vcipherlast $out0,$out0,$in4+ vcipherlast $out1,$out1,$in5+ vcipherlast $out2,$out2,$in6+ vcipherlast $out3,$out3,$in7++ le?vperm $out0,$out0,$out0,$inpperm+ le?vperm $out1,$out1,$out1,$inpperm+ stvx_u $out0,$x00,$out+ le?vperm $out2,$out2,$out2,$inpperm+ stvx_u $out1,$x10,$out+ le?vperm $out3,$out3,$out3,$inpperm+ stvx_u $out2,$x20,$out+ stvx_u $out3,$x30,$out+ addi $out,$out,0x40+ b Lctr32_enc8x_done++.align 5+Lctr32_enc8x_three:+ vcipherlast $out0,$out0,$in5+ vcipherlast $out1,$out1,$in6+ vcipherlast $out2,$out2,$in7++ le?vperm $out0,$out0,$out0,$inpperm+ le?vperm $out1,$out1,$out1,$inpperm+ stvx_u $out0,$x00,$out+ le?vperm $out2,$out2,$out2,$inpperm+ stvx_u $out1,$x10,$out+ stvx_u $out2,$x20,$out+ addi $out,$out,0x30+ b Lctr32_enc8x_done++.align 5+Lctr32_enc8x_two:+ vcipherlast $out0,$out0,$in6+ vcipherlast $out1,$out1,$in7++ le?vperm $out0,$out0,$out0,$inpperm+ le?vperm $out1,$out1,$out1,$inpperm+ stvx_u $out0,$x00,$out+ stvx_u $out1,$x10,$out+ addi $out,$out,0x20+ b Lctr32_enc8x_done++.align 5+Lctr32_enc8x_one:+ vcipherlast $out0,$out0,$in7++ le?vperm $out0,$out0,$out0,$inpperm+ stvx_u $out0,0,$out+ addi $out,$out,0x10++Lctr32_enc8x_done:+ li r10,`$FRAME+15`+ li r11,`$FRAME+31`+ stvx $inpperm,r10,$sp # wipe copies of round keys+ addi r10,r10,32+ stvx $inpperm,r11,$sp+ addi r11,r11,32+ stvx $inpperm,r10,$sp+ addi r10,r10,32+ stvx $inpperm,r11,$sp+ addi r11,r11,32+ stvx $inpperm,r10,$sp+ addi r10,r10,32+ stvx $inpperm,r11,$sp+ addi r11,r11,32+ stvx $inpperm,r10,$sp+ addi r10,r10,32+ stvx $inpperm,r11,$sp+ addi r11,r11,32++ mtspr 256,$vrsave+ lvx v20,r10,$sp # ABI says so+ addi r10,r10,32+ lvx v21,r11,$sp+ addi r11,r11,32+ lvx v22,r10,$sp+ addi r10,r10,32+ lvx v23,r11,$sp+ addi r11,r11,32+ lvx v24,r10,$sp+ addi r10,r10,32+ lvx v25,r11,$sp+ addi r11,r11,32+ lvx v26,r10,$sp+ addi r10,r10,32+ lvx v27,r11,$sp+ addi r11,r11,32+ lvx v28,r10,$sp+ addi r10,r10,32+ lvx v29,r11,$sp+ addi r11,r11,32+ lvx v30,r10,$sp+ lvx v31,r11,$sp+ $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp)+ $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp)+ $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp)+ $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp)+ $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp)+ $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp)+ addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T`+ blr+ .long 0+ .byte 0,12,0x04,0,0x80,6,6,0+ .long 0+.size .${prefix}_ctr32_encrypt_blocks,.-.${prefix}_ctr32_encrypt_blocks+___+}} }}}++#########################################################################+{{{ # XTS procedures #+# int aes_p8_xts_[en|de]crypt(const char *inp, char *out, size_t len, #+# const AES_KEY *key1, const AES_KEY *key2, #+# [const] unsigned char iv[16]); #+# If $key2 is NULL, then a "tweak chaining" mode is engaged, in which #+# input tweak value is assumed to be encrypted already, and last tweak #+# value, one suitable for consecutive call on same chunk of data, is #+# written back to original buffer. In addition, in "tweak chaining" #+# mode only complete input blocks are processed. #++my ($inp,$out,$len,$key1,$key2,$ivp,$rounds,$idx) = map("r$_",(3..10));+my ($rndkey0,$rndkey1,$inout) = map("v$_",(0..2));+my ($output,$inptail,$inpperm,$leperm,$keyperm) = map("v$_",(3..7));+my ($tweak,$seven,$eighty7,$tmp,$tweak1) = map("v$_",(8..12));+my $taillen = $key2;++ ($inp,$idx) = ($idx,$inp); # reassign++$code.=<<___;+.globl .${prefix}_xts_encrypt+.align 5+.${prefix}_xts_encrypt:+ mr $inp,r3 # reassign+ li r3,-1+ ${UCMP}i $len,16+ bltlr-++ lis r0,0xfff0+ mfspr r12,256 # save vrsave+ li r11,0+ mtspr 256,r0++ vspltisb $seven,0x07 # 0x070707..07+ le?lvsl $leperm,r11,r11+ le?vspltisb $tmp,0x0f+ le?vxor $leperm,$leperm,$seven++ li $idx,15+ lvx $tweak,0,$ivp # load [unaligned] iv+ lvsl $inpperm,0,$ivp+ lvx $inptail,$idx,$ivp+ le?vxor $inpperm,$inpperm,$tmp+ vperm $tweak,$tweak,$inptail,$inpperm++ neg r11,$inp+ lvsr $inpperm,0,r11 # prepare for unaligned load+ lvx $inout,0,$inp+ addi $inp,$inp,15 # 15 is not typo+ le?vxor $inpperm,$inpperm,$tmp++ ${UCMP}i $key2,0 # key2==NULL?+ beq Lxts_enc_no_key2++ ?lvsl $keyperm,0,$key2 # prepare for unaligned key+ lwz $rounds,240($key2)+ srwi $rounds,$rounds,1+ subi $rounds,$rounds,1+ li $idx,16++ lvx $rndkey0,0,$key2+ lvx $rndkey1,$idx,$key2+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $tweak,$tweak,$rndkey0+ lvx $rndkey0,$idx,$key2+ addi $idx,$idx,16+ mtctr $rounds++Ltweak_xts_enc:+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $tweak,$tweak,$rndkey1+ lvx $rndkey1,$idx,$key2+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vcipher $tweak,$tweak,$rndkey0+ lvx $rndkey0,$idx,$key2+ addi $idx,$idx,16+ bdnz Ltweak_xts_enc++ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $tweak,$tweak,$rndkey1+ lvx $rndkey1,$idx,$key2+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vcipherlast $tweak,$tweak,$rndkey0++ li $ivp,0 # don't chain the tweak+ b Lxts_enc++Lxts_enc_no_key2:+ li $idx,-16+ and $len,$len,$idx # in "tweak chaining"+ # mode only complete+ # blocks are processed+Lxts_enc:+ lvx $inptail,0,$inp+ addi $inp,$inp,16++ ?lvsl $keyperm,0,$key1 # prepare for unaligned key+ lwz $rounds,240($key1)+ srwi $rounds,$rounds,1+ subi $rounds,$rounds,1+ li $idx,16++ vslb $eighty7,$seven,$seven # 0x808080..80+ vor $eighty7,$eighty7,$seven # 0x878787..87+ vspltisb $tmp,1 # 0x010101..01+ vsldoi $eighty7,$eighty7,$tmp,15 # 0x870101..01++ ${UCMP}i $len,96+ bge _aesp8_xts_encrypt6x++ andi. $taillen,$len,15+ subic r0,$len,32+ subi $taillen,$taillen,16+ subfe r0,r0,r0+ and r0,r0,$taillen+ add $inp,$inp,r0++ lvx $rndkey0,0,$key1+ lvx $rndkey1,$idx,$key1+ addi $idx,$idx,16+ vperm $inout,$inout,$inptail,$inpperm+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $inout,$inout,$tweak+ vxor $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key1+ addi $idx,$idx,16+ mtctr $rounds+ b Loop_xts_enc++.align 5+Loop_xts_enc:+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key1+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vcipher $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key1+ addi $idx,$idx,16+ bdnz Loop_xts_enc++ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key1+ li $idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $rndkey0,$rndkey0,$tweak+ vcipherlast $output,$inout,$rndkey0++ le?vperm $tmp,$output,$output,$leperm+ be?nop+ le?stvx_u $tmp,0,$out+ be?stvx_u $output,0,$out+ addi $out,$out,16++ subic. $len,$len,16+ beq Lxts_enc_done++ vmr $inout,$inptail+ lvx $inptail,0,$inp+ addi $inp,$inp,16+ lvx $rndkey0,0,$key1+ lvx $rndkey1,$idx,$key1+ addi $idx,$idx,16++ subic r0,$len,32+ subfe r0,r0,r0+ and r0,r0,$taillen+ add $inp,$inp,r0++ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vand $tmp,$tmp,$eighty7+ vxor $tweak,$tweak,$tmp++ vperm $inout,$inout,$inptail,$inpperm+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $inout,$inout,$tweak+ vxor $output,$output,$rndkey0 # just in case $len<16+ vxor $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key1+ addi $idx,$idx,16++ mtctr $rounds+ ${UCMP}i $len,16+ bge Loop_xts_enc++ vxor $output,$output,$tweak+ lvsr $inpperm,0,$len # $inpperm is no longer needed+ vxor $inptail,$inptail,$inptail # $inptail is no longer needed+ vspltisb $tmp,-1+ vperm $inptail,$inptail,$tmp,$inpperm+ vsel $inout,$inout,$output,$inptail++ subi r11,$out,17+ subi $out,$out,16+ mtctr $len+ li $len,16+Loop_xts_enc_steal:+ lbzu r0,1(r11)+ stb r0,16(r11)+ bdnz Loop_xts_enc_steal++ mtctr $rounds+ b Loop_xts_enc # one more time...++Lxts_enc_done:+ ${UCMP}i $ivp,0+ beq Lxts_enc_ret++ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vand $tmp,$tmp,$eighty7+ vxor $tweak,$tweak,$tmp++ le?vperm $tweak,$tweak,$tweak,$leperm+ stvx_u $tweak,0,$ivp++Lxts_enc_ret:+ mtspr 256,r12 # restore vrsave+ li r3,0+ blr+ .long 0+ .byte 0,12,0x04,0,0x80,6,6,0+ .long 0+.size .${prefix}_xts_encrypt,.-.${prefix}_xts_encrypt++.globl .${prefix}_xts_decrypt+.align 5+.${prefix}_xts_decrypt:+ mr $inp,r3 # reassign+ li r3,-1+ ${UCMP}i $len,16+ bltlr-++ lis r0,0xfff8+ mfspr r12,256 # save vrsave+ li r11,0+ mtspr 256,r0++ andi. r0,$len,15+ neg r0,r0+ andi. r0,r0,16+ sub $len,$len,r0++ vspltisb $seven,0x07 # 0x070707..07+ le?lvsl $leperm,r11,r11+ le?vspltisb $tmp,0x0f+ le?vxor $leperm,$leperm,$seven++ li $idx,15+ lvx $tweak,0,$ivp # load [unaligned] iv+ lvsl $inpperm,0,$ivp+ lvx $inptail,$idx,$ivp+ le?vxor $inpperm,$inpperm,$tmp+ vperm $tweak,$tweak,$inptail,$inpperm++ neg r11,$inp+ lvsr $inpperm,0,r11 # prepare for unaligned load+ lvx $inout,0,$inp+ addi $inp,$inp,15 # 15 is not typo+ le?vxor $inpperm,$inpperm,$tmp++ ${UCMP}i $key2,0 # key2==NULL?+ beq Lxts_dec_no_key2++ ?lvsl $keyperm,0,$key2 # prepare for unaligned key+ lwz $rounds,240($key2)+ srwi $rounds,$rounds,1+ subi $rounds,$rounds,1+ li $idx,16++ lvx $rndkey0,0,$key2+ lvx $rndkey1,$idx,$key2+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $tweak,$tweak,$rndkey0+ lvx $rndkey0,$idx,$key2+ addi $idx,$idx,16+ mtctr $rounds++Ltweak_xts_dec:+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $tweak,$tweak,$rndkey1+ lvx $rndkey1,$idx,$key2+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vcipher $tweak,$tweak,$rndkey0+ lvx $rndkey0,$idx,$key2+ addi $idx,$idx,16+ bdnz Ltweak_xts_dec++ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vcipher $tweak,$tweak,$rndkey1+ lvx $rndkey1,$idx,$key2+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vcipherlast $tweak,$tweak,$rndkey0++ li $ivp,0 # don't chain the tweak+ b Lxts_dec++Lxts_dec_no_key2:+ neg $idx,$len+ andi. $idx,$idx,15+ add $len,$len,$idx # in "tweak chaining"+ # mode only complete+ # blocks are processed+Lxts_dec:+ lvx $inptail,0,$inp+ addi $inp,$inp,16++ ?lvsl $keyperm,0,$key1 # prepare for unaligned key+ lwz $rounds,240($key1)+ srwi $rounds,$rounds,1+ subi $rounds,$rounds,1+ li $idx,16++ vslb $eighty7,$seven,$seven # 0x808080..80+ vor $eighty7,$eighty7,$seven # 0x878787..87+ vspltisb $tmp,1 # 0x010101..01+ vsldoi $eighty7,$eighty7,$tmp,15 # 0x870101..01++ ${UCMP}i $len,96+ bge _aesp8_xts_decrypt6x++ lvx $rndkey0,0,$key1+ lvx $rndkey1,$idx,$key1+ addi $idx,$idx,16+ vperm $inout,$inout,$inptail,$inpperm+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $inout,$inout,$tweak+ vxor $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key1+ addi $idx,$idx,16+ mtctr $rounds++ ${UCMP}i $len,16+ blt Ltail_xts_dec+ be?b Loop_xts_dec++.align 5+Loop_xts_dec:+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vncipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key1+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vncipher $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key1+ addi $idx,$idx,16+ bdnz Loop_xts_dec++ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vncipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key1+ li $idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $rndkey0,$rndkey0,$tweak+ vncipherlast $output,$inout,$rndkey0++ le?vperm $tmp,$output,$output,$leperm+ be?nop+ le?stvx_u $tmp,0,$out+ be?stvx_u $output,0,$out+ addi $out,$out,16++ subic. $len,$len,16+ beq Lxts_dec_done++ vmr $inout,$inptail+ lvx $inptail,0,$inp+ addi $inp,$inp,16+ lvx $rndkey0,0,$key1+ lvx $rndkey1,$idx,$key1+ addi $idx,$idx,16++ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vand $tmp,$tmp,$eighty7+ vxor $tweak,$tweak,$tmp++ vperm $inout,$inout,$inptail,$inpperm+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $inout,$inout,$tweak+ vxor $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key1+ addi $idx,$idx,16++ mtctr $rounds+ ${UCMP}i $len,16+ bge Loop_xts_dec++Ltail_xts_dec:+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak1,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vand $tmp,$tmp,$eighty7+ vxor $tweak1,$tweak1,$tmp++ subi $inp,$inp,16+ add $inp,$inp,$len++ vxor $inout,$inout,$tweak # :-(+ vxor $inout,$inout,$tweak1 # :-)++Loop_xts_dec_short:+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vncipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key1+ addi $idx,$idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vncipher $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key1+ addi $idx,$idx,16+ bdnz Loop_xts_dec_short++ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm+ vncipher $inout,$inout,$rndkey1+ lvx $rndkey1,$idx,$key1+ li $idx,16+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm+ vxor $rndkey0,$rndkey0,$tweak1+ vncipherlast $output,$inout,$rndkey0++ le?vperm $tmp,$output,$output,$leperm+ be?nop+ le?stvx_u $tmp,0,$out+ be?stvx_u $output,0,$out++ vmr $inout,$inptail+ lvx $inptail,0,$inp+ #addi $inp,$inp,16+ lvx $rndkey0,0,$key1+ lvx $rndkey1,$idx,$key1+ addi $idx,$idx,16+ vperm $inout,$inout,$inptail,$inpperm+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm++ lvsr $inpperm,0,$len # $inpperm is no longer needed+ vxor $inptail,$inptail,$inptail # $inptail is no longer needed+ vspltisb $tmp,-1+ vperm $inptail,$inptail,$tmp,$inpperm+ vsel $inout,$inout,$output,$inptail++ vxor $rndkey0,$rndkey0,$tweak+ vxor $inout,$inout,$rndkey0+ lvx $rndkey0,$idx,$key1+ addi $idx,$idx,16++ subi r11,$out,1+ mtctr $len+ li $len,16+Loop_xts_dec_steal:+ lbzu r0,1(r11)+ stb r0,16(r11)+ bdnz Loop_xts_dec_steal++ mtctr $rounds+ b Loop_xts_dec # one more time...++Lxts_dec_done:+ ${UCMP}i $ivp,0+ beq Lxts_dec_ret++ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vand $tmp,$tmp,$eighty7+ vxor $tweak,$tweak,$tmp++ le?vperm $tweak,$tweak,$tweak,$leperm+ stvx_u $tweak,0,$ivp++Lxts_dec_ret:+ mtspr 256,r12 # restore vrsave+ li r3,0+ blr+ .long 0+ .byte 0,12,0x04,0,0x80,6,6,0+ .long 0+.size .${prefix}_xts_decrypt,.-.${prefix}_xts_decrypt+___+#########################################################################+{{ # Optimized XTS procedures #+my $key_=$key2;+my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,3,26..31));+ $x00=0 if ($flavour =~ /osx/);+my ($in0, $in1, $in2, $in3, $in4, $in5 )=map("v$_",(0..5));+my ($out0, $out1, $out2, $out3, $out4, $out5)=map("v$_",(7,12..16));+my ($twk0, $twk1, $twk2, $twk3, $twk4, $twk5)=map("v$_",(17..22));+my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys+ # v26-v31 last 6 round keys+my ($keyperm)=($out0); # aliases with "caller", redundant assignment+my $taillen=$x70;++$code.=<<___;+.align 5+_aesp8_xts_encrypt6x:+ $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)+ mflr r11+ li r7,`$FRAME+8*16+15`+ li r3,`$FRAME+8*16+31`+ $PUSH r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp)+ stvx v20,r7,$sp # ABI says so+ addi r7,r7,32+ stvx v21,r3,$sp+ addi r3,r3,32+ stvx v22,r7,$sp+ addi r7,r7,32+ stvx v23,r3,$sp+ addi r3,r3,32+ stvx v24,r7,$sp+ addi r7,r7,32+ stvx v25,r3,$sp+ addi r3,r3,32+ stvx v26,r7,$sp+ addi r7,r7,32+ stvx v27,r3,$sp+ addi r3,r3,32+ stvx v28,r7,$sp+ addi r7,r7,32+ stvx v29,r3,$sp+ addi r3,r3,32+ stvx v30,r7,$sp+ stvx v31,r3,$sp+ li r0,-1+ stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave+ li $x10,0x10+ $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp)+ li $x20,0x20+ $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp)+ li $x30,0x30+ $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp)+ li $x40,0x40+ $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp)+ li $x50,0x50+ $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp)+ li $x60,0x60+ $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp)+ li $x70,0x70+ mtspr 256,r0++ subi $rounds,$rounds,3 # -4 in total++ lvx $rndkey0,$x00,$key1 # load key schedule+ lvx v30,$x10,$key1+ addi $key1,$key1,0x20+ lvx v31,$x00,$key1+ ?vperm $rndkey0,$rndkey0,v30,$keyperm+ addi $key_,$sp,$FRAME+15+ mtctr $rounds++Load_xts_enc_key:+ ?vperm v24,v30,v31,$keyperm+ lvx v30,$x10,$key1+ addi $key1,$key1,0x20+ stvx v24,$x00,$key_ # off-load round[1]+ ?vperm v25,v31,v30,$keyperm+ lvx v31,$x00,$key1+ stvx v25,$x10,$key_ # off-load round[2]+ addi $key_,$key_,0x20+ bdnz Load_xts_enc_key++ lvx v26,$x10,$key1+ ?vperm v24,v30,v31,$keyperm+ lvx v27,$x20,$key1+ stvx v24,$x00,$key_ # off-load round[3]+ ?vperm v25,v31,v26,$keyperm+ lvx v28,$x30,$key1+ stvx v25,$x10,$key_ # off-load round[4]+ addi $key_,$sp,$FRAME+15 # rewind $key_+ ?vperm v26,v26,v27,$keyperm+ lvx v29,$x40,$key1+ ?vperm v27,v27,v28,$keyperm+ lvx v30,$x50,$key1+ ?vperm v28,v28,v29,$keyperm+ lvx v31,$x60,$key1+ ?vperm v29,v29,v30,$keyperm+ lvx $twk5,$x70,$key1 # borrow $twk5+ ?vperm v30,v30,v31,$keyperm+ lvx v24,$x00,$key_ # pre-load round[1]+ ?vperm v31,v31,$twk5,$keyperm+ lvx v25,$x10,$key_ # pre-load round[2]++ vperm $in0,$inout,$inptail,$inpperm+ subi $inp,$inp,31 # undo "caller"+ vxor $twk0,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vand $tmp,$tmp,$eighty7+ vxor $out0,$in0,$twk0+ vxor $tweak,$tweak,$tmp++ lvx_u $in1,$x10,$inp+ vxor $twk1,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in1,$in1,$in1,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out1,$in1,$twk1+ vxor $tweak,$tweak,$tmp++ lvx_u $in2,$x20,$inp+ andi. $taillen,$len,15+ vxor $twk2,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in2,$in2,$in2,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out2,$in2,$twk2+ vxor $tweak,$tweak,$tmp++ lvx_u $in3,$x30,$inp+ sub $len,$len,$taillen+ vxor $twk3,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in3,$in3,$in3,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out3,$in3,$twk3+ vxor $tweak,$tweak,$tmp++ lvx_u $in4,$x40,$inp+ subi $len,$len,0x60+ vxor $twk4,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in4,$in4,$in4,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out4,$in4,$twk4+ vxor $tweak,$tweak,$tmp++ lvx_u $in5,$x50,$inp+ addi $inp,$inp,0x60+ vxor $twk5,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in5,$in5,$in5,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out5,$in5,$twk5+ vxor $tweak,$tweak,$tmp++ vxor v31,v31,$rndkey0+ mtctr $rounds+ b Loop_xts_enc6x++.align 5+Loop_xts_enc6x:+ vcipher $out0,$out0,v24+ vcipher $out1,$out1,v24+ vcipher $out2,$out2,v24+ vcipher $out3,$out3,v24+ vcipher $out4,$out4,v24+ vcipher $out5,$out5,v24+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vcipher $out0,$out0,v25+ vcipher $out1,$out1,v25+ vcipher $out2,$out2,v25+ vcipher $out3,$out3,v25+ vcipher $out4,$out4,v25+ vcipher $out5,$out5,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz Loop_xts_enc6x++ subic $len,$len,96 # $len-=96+ vxor $in0,$twk0,v31 # xor with last round key+ vcipher $out0,$out0,v24+ vcipher $out1,$out1,v24+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk0,$tweak,$rndkey0+ vaddubm $tweak,$tweak,$tweak+ vcipher $out2,$out2,v24+ vcipher $out3,$out3,v24+ vsldoi $tmp,$tmp,$tmp,15+ vcipher $out4,$out4,v24+ vcipher $out5,$out5,v24++ subfe. r0,r0,r0 # borrow?-1:0+ vand $tmp,$tmp,$eighty7+ vcipher $out0,$out0,v25+ vcipher $out1,$out1,v25+ vxor $tweak,$tweak,$tmp+ vcipher $out2,$out2,v25+ vcipher $out3,$out3,v25+ vxor $in1,$twk1,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk1,$tweak,$rndkey0+ vcipher $out4,$out4,v25+ vcipher $out5,$out5,v25++ and r0,r0,$len+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vcipher $out0,$out0,v26+ vcipher $out1,$out1,v26+ vand $tmp,$tmp,$eighty7+ vcipher $out2,$out2,v26+ vcipher $out3,$out3,v26+ vxor $tweak,$tweak,$tmp+ vcipher $out4,$out4,v26+ vcipher $out5,$out5,v26++ add $inp,$inp,r0 # $inp is adjusted in such+ # way that at exit from the+ # loop inX-in5 are loaded+ # with last "words"+ vxor $in2,$twk2,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk2,$tweak,$rndkey0+ vaddubm $tweak,$tweak,$tweak+ vcipher $out0,$out0,v27+ vcipher $out1,$out1,v27+ vsldoi $tmp,$tmp,$tmp,15+ vcipher $out2,$out2,v27+ vcipher $out3,$out3,v27+ vand $tmp,$tmp,$eighty7+ vcipher $out4,$out4,v27+ vcipher $out5,$out5,v27++ addi $key_,$sp,$FRAME+15 # rewind $key_+ vxor $tweak,$tweak,$tmp+ vcipher $out0,$out0,v28+ vcipher $out1,$out1,v28+ vxor $in3,$twk3,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk3,$tweak,$rndkey0+ vcipher $out2,$out2,v28+ vcipher $out3,$out3,v28+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vcipher $out4,$out4,v28+ vcipher $out5,$out5,v28+ lvx v24,$x00,$key_ # re-pre-load round[1]+ vand $tmp,$tmp,$eighty7++ vcipher $out0,$out0,v29+ vcipher $out1,$out1,v29+ vxor $tweak,$tweak,$tmp+ vcipher $out2,$out2,v29+ vcipher $out3,$out3,v29+ vxor $in4,$twk4,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk4,$tweak,$rndkey0+ vcipher $out4,$out4,v29+ vcipher $out5,$out5,v29+ lvx v25,$x10,$key_ # re-pre-load round[2]+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15++ vcipher $out0,$out0,v30+ vcipher $out1,$out1,v30+ vand $tmp,$tmp,$eighty7+ vcipher $out2,$out2,v30+ vcipher $out3,$out3,v30+ vxor $tweak,$tweak,$tmp+ vcipher $out4,$out4,v30+ vcipher $out5,$out5,v30+ vxor $in5,$twk5,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk5,$tweak,$rndkey0++ vcipherlast $out0,$out0,$in0+ lvx_u $in0,$x00,$inp # load next input block+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vcipherlast $out1,$out1,$in1+ lvx_u $in1,$x10,$inp+ vcipherlast $out2,$out2,$in2+ le?vperm $in0,$in0,$in0,$leperm+ lvx_u $in2,$x20,$inp+ vand $tmp,$tmp,$eighty7+ vcipherlast $out3,$out3,$in3+ le?vperm $in1,$in1,$in1,$leperm+ lvx_u $in3,$x30,$inp+ vcipherlast $out4,$out4,$in4+ le?vperm $in2,$in2,$in2,$leperm+ lvx_u $in4,$x40,$inp+ vxor $tweak,$tweak,$tmp+ vcipherlast $tmp,$out5,$in5 # last block might be needed+ # in stealing mode+ le?vperm $in3,$in3,$in3,$leperm+ lvx_u $in5,$x50,$inp+ addi $inp,$inp,0x60+ le?vperm $in4,$in4,$in4,$leperm+ le?vperm $in5,$in5,$in5,$leperm++ le?vperm $out0,$out0,$out0,$leperm+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ vxor $out0,$in0,$twk0+ le?vperm $out2,$out2,$out2,$leperm+ stvx_u $out1,$x10,$out+ vxor $out1,$in1,$twk1+ le?vperm $out3,$out3,$out3,$leperm+ stvx_u $out2,$x20,$out+ vxor $out2,$in2,$twk2+ le?vperm $out4,$out4,$out4,$leperm+ stvx_u $out3,$x30,$out+ vxor $out3,$in3,$twk3+ le?vperm $out5,$tmp,$tmp,$leperm+ stvx_u $out4,$x40,$out+ vxor $out4,$in4,$twk4+ le?stvx_u $out5,$x50,$out+ be?stvx_u $tmp, $x50,$out+ vxor $out5,$in5,$twk5+ addi $out,$out,0x60++ mtctr $rounds+ beq Loop_xts_enc6x # did $len-=96 borrow?++ addic. $len,$len,0x60+ beq Lxts_enc6x_zero+ cmpwi $len,0x20+ blt Lxts_enc6x_one+ nop+ beq Lxts_enc6x_two+ cmpwi $len,0x40+ blt Lxts_enc6x_three+ nop+ beq Lxts_enc6x_four++Lxts_enc6x_five:+ vxor $out0,$in1,$twk0+ vxor $out1,$in2,$twk1+ vxor $out2,$in3,$twk2+ vxor $out3,$in4,$twk3+ vxor $out4,$in5,$twk4++ bl _aesp8_xts_enc5x++ le?vperm $out0,$out0,$out0,$leperm+ vmr $twk0,$twk5 # unused tweak+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ le?vperm $out2,$out2,$out2,$leperm+ stvx_u $out1,$x10,$out+ le?vperm $out3,$out3,$out3,$leperm+ stvx_u $out2,$x20,$out+ vxor $tmp,$out4,$twk5 # last block prep for stealing+ le?vperm $out4,$out4,$out4,$leperm+ stvx_u $out3,$x30,$out+ stvx_u $out4,$x40,$out+ addi $out,$out,0x50+ bne Lxts_enc6x_steal+ b Lxts_enc6x_done++.align 4+Lxts_enc6x_four:+ vxor $out0,$in2,$twk0+ vxor $out1,$in3,$twk1+ vxor $out2,$in4,$twk2+ vxor $out3,$in5,$twk3+ vxor $out4,$out4,$out4++ bl _aesp8_xts_enc5x++ le?vperm $out0,$out0,$out0,$leperm+ vmr $twk0,$twk4 # unused tweak+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ le?vperm $out2,$out2,$out2,$leperm+ stvx_u $out1,$x10,$out+ vxor $tmp,$out3,$twk4 # last block prep for stealing+ le?vperm $out3,$out3,$out3,$leperm+ stvx_u $out2,$x20,$out+ stvx_u $out3,$x30,$out+ addi $out,$out,0x40+ bne Lxts_enc6x_steal+ b Lxts_enc6x_done++.align 4+Lxts_enc6x_three:+ vxor $out0,$in3,$twk0+ vxor $out1,$in4,$twk1+ vxor $out2,$in5,$twk2+ vxor $out3,$out3,$out3+ vxor $out4,$out4,$out4++ bl _aesp8_xts_enc5x++ le?vperm $out0,$out0,$out0,$leperm+ vmr $twk0,$twk3 # unused tweak+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ vxor $tmp,$out2,$twk3 # last block prep for stealing+ le?vperm $out2,$out2,$out2,$leperm+ stvx_u $out1,$x10,$out+ stvx_u $out2,$x20,$out+ addi $out,$out,0x30+ bne Lxts_enc6x_steal+ b Lxts_enc6x_done++.align 4+Lxts_enc6x_two:+ vxor $out0,$in4,$twk0+ vxor $out1,$in5,$twk1+ vxor $out2,$out2,$out2+ vxor $out3,$out3,$out3+ vxor $out4,$out4,$out4++ bl _aesp8_xts_enc5x++ le?vperm $out0,$out0,$out0,$leperm+ vmr $twk0,$twk2 # unused tweak+ vxor $tmp,$out1,$twk2 # last block prep for stealing+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ stvx_u $out1,$x10,$out+ addi $out,$out,0x20+ bne Lxts_enc6x_steal+ b Lxts_enc6x_done++.align 4+Lxts_enc6x_one:+ vxor $out0,$in5,$twk0+ nop+Loop_xts_enc1x:+ vcipher $out0,$out0,v24+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vcipher $out0,$out0,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz Loop_xts_enc1x++ add $inp,$inp,$taillen+ cmpwi $taillen,0+ vcipher $out0,$out0,v24++ subi $inp,$inp,16+ vcipher $out0,$out0,v25++ lvsr $inpperm,0,$taillen+ vcipher $out0,$out0,v26++ lvx_u $in0,0,$inp+ vcipher $out0,$out0,v27++ addi $key_,$sp,$FRAME+15 # rewind $key_+ vcipher $out0,$out0,v28+ lvx v24,$x00,$key_ # re-pre-load round[1]++ vcipher $out0,$out0,v29+ lvx v25,$x10,$key_ # re-pre-load round[2]+ vxor $twk0,$twk0,v31++ le?vperm $in0,$in0,$in0,$leperm+ vcipher $out0,$out0,v30++ vperm $in0,$in0,$in0,$inpperm+ vcipherlast $out0,$out0,$twk0++ vmr $twk0,$twk1 # unused tweak+ vxor $tmp,$out0,$twk1 # last block prep for stealing+ le?vperm $out0,$out0,$out0,$leperm+ stvx_u $out0,$x00,$out # store output+ addi $out,$out,0x10+ bne Lxts_enc6x_steal+ b Lxts_enc6x_done++.align 4+Lxts_enc6x_zero:+ cmpwi $taillen,0+ beq Lxts_enc6x_done++ add $inp,$inp,$taillen+ subi $inp,$inp,16+ lvx_u $in0,0,$inp+ lvsr $inpperm,0,$taillen # $in5 is no more+ le?vperm $in0,$in0,$in0,$leperm+ vperm $in0,$in0,$in0,$inpperm+ vxor $tmp,$tmp,$twk0+Lxts_enc6x_steal:+ vxor $in0,$in0,$twk0+ vxor $out0,$out0,$out0+ vspltisb $out1,-1+ vperm $out0,$out0,$out1,$inpperm+ vsel $out0,$in0,$tmp,$out0 # $tmp is last block, remember?++ subi r30,$out,17+ subi $out,$out,16+ mtctr $taillen+Loop_xts_enc6x_steal:+ lbzu r0,1(r30)+ stb r0,16(r30)+ bdnz Loop_xts_enc6x_steal++ li $taillen,0+ mtctr $rounds+ b Loop_xts_enc1x # one more time...++.align 4+Lxts_enc6x_done:+ ${UCMP}i $ivp,0+ beq Lxts_enc6x_ret++ vxor $tweak,$twk0,$rndkey0+ le?vperm $tweak,$tweak,$tweak,$leperm+ stvx_u $tweak,0,$ivp++Lxts_enc6x_ret:+ mtlr r11+ li r10,`$FRAME+15`+ li r11,`$FRAME+31`+ stvx $seven,r10,$sp # wipe copies of round keys+ addi r10,r10,32+ stvx $seven,r11,$sp+ addi r11,r11,32+ stvx $seven,r10,$sp+ addi r10,r10,32+ stvx $seven,r11,$sp+ addi r11,r11,32+ stvx $seven,r10,$sp+ addi r10,r10,32+ stvx $seven,r11,$sp+ addi r11,r11,32+ stvx $seven,r10,$sp+ addi r10,r10,32+ stvx $seven,r11,$sp+ addi r11,r11,32++ mtspr 256,$vrsave+ lvx v20,r10,$sp # ABI says so+ addi r10,r10,32+ lvx v21,r11,$sp+ addi r11,r11,32+ lvx v22,r10,$sp+ addi r10,r10,32+ lvx v23,r11,$sp+ addi r11,r11,32+ lvx v24,r10,$sp+ addi r10,r10,32+ lvx v25,r11,$sp+ addi r11,r11,32+ lvx v26,r10,$sp+ addi r10,r10,32+ lvx v27,r11,$sp+ addi r11,r11,32+ lvx v28,r10,$sp+ addi r10,r10,32+ lvx v29,r11,$sp+ addi r11,r11,32+ lvx v30,r10,$sp+ lvx v31,r11,$sp+ $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp)+ $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp)+ $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp)+ $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp)+ $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp)+ $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp)+ addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T`+ blr+ .long 0+ .byte 0,12,0x04,1,0x80,6,6,0+ .long 0++.align 5+_aesp8_xts_enc5x:+ vcipher $out0,$out0,v24+ vcipher $out1,$out1,v24+ vcipher $out2,$out2,v24+ vcipher $out3,$out3,v24+ vcipher $out4,$out4,v24+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vcipher $out0,$out0,v25+ vcipher $out1,$out1,v25+ vcipher $out2,$out2,v25+ vcipher $out3,$out3,v25+ vcipher $out4,$out4,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz _aesp8_xts_enc5x++ add $inp,$inp,$taillen+ cmpwi $taillen,0+ vcipher $out0,$out0,v24+ vcipher $out1,$out1,v24+ vcipher $out2,$out2,v24+ vcipher $out3,$out3,v24+ vcipher $out4,$out4,v24++ subi $inp,$inp,16+ vcipher $out0,$out0,v25+ vcipher $out1,$out1,v25+ vcipher $out2,$out2,v25+ vcipher $out3,$out3,v25+ vcipher $out4,$out4,v25+ vxor $twk0,$twk0,v31++ vcipher $out0,$out0,v26+ lvsr $inpperm,0,$taillen # $in5 is no more+ vcipher $out1,$out1,v26+ vcipher $out2,$out2,v26+ vcipher $out3,$out3,v26+ vcipher $out4,$out4,v26+ vxor $in1,$twk1,v31++ vcipher $out0,$out0,v27+ lvx_u $in0,0,$inp+ vcipher $out1,$out1,v27+ vcipher $out2,$out2,v27+ vcipher $out3,$out3,v27+ vcipher $out4,$out4,v27+ vxor $in2,$twk2,v31++ addi $key_,$sp,$FRAME+15 # rewind $key_+ vcipher $out0,$out0,v28+ vcipher $out1,$out1,v28+ vcipher $out2,$out2,v28+ vcipher $out3,$out3,v28+ vcipher $out4,$out4,v28+ lvx v24,$x00,$key_ # re-pre-load round[1]+ vxor $in3,$twk3,v31++ vcipher $out0,$out0,v29+ le?vperm $in0,$in0,$in0,$leperm+ vcipher $out1,$out1,v29+ vcipher $out2,$out2,v29+ vcipher $out3,$out3,v29+ vcipher $out4,$out4,v29+ lvx v25,$x10,$key_ # re-pre-load round[2]+ vxor $in4,$twk4,v31++ vcipher $out0,$out0,v30+ vperm $in0,$in0,$in0,$inpperm+ vcipher $out1,$out1,v30+ vcipher $out2,$out2,v30+ vcipher $out3,$out3,v30+ vcipher $out4,$out4,v30++ vcipherlast $out0,$out0,$twk0+ vcipherlast $out1,$out1,$in1+ vcipherlast $out2,$out2,$in2+ vcipherlast $out3,$out3,$in3+ vcipherlast $out4,$out4,$in4+ blr+ .long 0+ .byte 0,12,0x14,0,0,0,0,0++.align 5+_aesp8_xts_decrypt6x:+ $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)+ mflr r11+ li r7,`$FRAME+8*16+15`+ li r3,`$FRAME+8*16+31`+ $PUSH r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp)+ stvx v20,r7,$sp # ABI says so+ addi r7,r7,32+ stvx v21,r3,$sp+ addi r3,r3,32+ stvx v22,r7,$sp+ addi r7,r7,32+ stvx v23,r3,$sp+ addi r3,r3,32+ stvx v24,r7,$sp+ addi r7,r7,32+ stvx v25,r3,$sp+ addi r3,r3,32+ stvx v26,r7,$sp+ addi r7,r7,32+ stvx v27,r3,$sp+ addi r3,r3,32+ stvx v28,r7,$sp+ addi r7,r7,32+ stvx v29,r3,$sp+ addi r3,r3,32+ stvx v30,r7,$sp+ stvx v31,r3,$sp+ li r0,-1+ stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave+ li $x10,0x10+ $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp)+ li $x20,0x20+ $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp)+ li $x30,0x30+ $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp)+ li $x40,0x40+ $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp)+ li $x50,0x50+ $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp)+ li $x60,0x60+ $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp)+ li $x70,0x70+ mtspr 256,r0++ subi $rounds,$rounds,3 # -4 in total++ lvx $rndkey0,$x00,$key1 # load key schedule+ lvx v30,$x10,$key1+ addi $key1,$key1,0x20+ lvx v31,$x00,$key1+ ?vperm $rndkey0,$rndkey0,v30,$keyperm+ addi $key_,$sp,$FRAME+15+ mtctr $rounds++Load_xts_dec_key:+ ?vperm v24,v30,v31,$keyperm+ lvx v30,$x10,$key1+ addi $key1,$key1,0x20+ stvx v24,$x00,$key_ # off-load round[1]+ ?vperm v25,v31,v30,$keyperm+ lvx v31,$x00,$key1+ stvx v25,$x10,$key_ # off-load round[2]+ addi $key_,$key_,0x20+ bdnz Load_xts_dec_key++ lvx v26,$x10,$key1+ ?vperm v24,v30,v31,$keyperm+ lvx v27,$x20,$key1+ stvx v24,$x00,$key_ # off-load round[3]+ ?vperm v25,v31,v26,$keyperm+ lvx v28,$x30,$key1+ stvx v25,$x10,$key_ # off-load round[4]+ addi $key_,$sp,$FRAME+15 # rewind $key_+ ?vperm v26,v26,v27,$keyperm+ lvx v29,$x40,$key1+ ?vperm v27,v27,v28,$keyperm+ lvx v30,$x50,$key1+ ?vperm v28,v28,v29,$keyperm+ lvx v31,$x60,$key1+ ?vperm v29,v29,v30,$keyperm+ lvx $twk5,$x70,$key1 # borrow $twk5+ ?vperm v30,v30,v31,$keyperm+ lvx v24,$x00,$key_ # pre-load round[1]+ ?vperm v31,v31,$twk5,$keyperm+ lvx v25,$x10,$key_ # pre-load round[2]++ vperm $in0,$inout,$inptail,$inpperm+ subi $inp,$inp,31 # undo "caller"+ vxor $twk0,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vand $tmp,$tmp,$eighty7+ vxor $out0,$in0,$twk0+ vxor $tweak,$tweak,$tmp++ lvx_u $in1,$x10,$inp+ vxor $twk1,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in1,$in1,$in1,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out1,$in1,$twk1+ vxor $tweak,$tweak,$tmp++ lvx_u $in2,$x20,$inp+ andi. $taillen,$len,15+ vxor $twk2,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in2,$in2,$in2,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out2,$in2,$twk2+ vxor $tweak,$tweak,$tmp++ lvx_u $in3,$x30,$inp+ sub $len,$len,$taillen+ vxor $twk3,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in3,$in3,$in3,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out3,$in3,$twk3+ vxor $tweak,$tweak,$tmp++ lvx_u $in4,$x40,$inp+ subi $len,$len,0x60+ vxor $twk4,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in4,$in4,$in4,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out4,$in4,$twk4+ vxor $tweak,$tweak,$tmp++ lvx_u $in5,$x50,$inp+ addi $inp,$inp,0x60+ vxor $twk5,$tweak,$rndkey0+ vsrab $tmp,$tweak,$seven # next tweak value+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ le?vperm $in5,$in5,$in5,$leperm+ vand $tmp,$tmp,$eighty7+ vxor $out5,$in5,$twk5+ vxor $tweak,$tweak,$tmp++ vxor v31,v31,$rndkey0+ mtctr $rounds+ b Loop_xts_dec6x++.align 5+Loop_xts_dec6x:+ vncipher $out0,$out0,v24+ vncipher $out1,$out1,v24+ vncipher $out2,$out2,v24+ vncipher $out3,$out3,v24+ vncipher $out4,$out4,v24+ vncipher $out5,$out5,v24+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vncipher $out0,$out0,v25+ vncipher $out1,$out1,v25+ vncipher $out2,$out2,v25+ vncipher $out3,$out3,v25+ vncipher $out4,$out4,v25+ vncipher $out5,$out5,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz Loop_xts_dec6x++ subic $len,$len,96 # $len-=96+ vxor $in0,$twk0,v31 # xor with last round key+ vncipher $out0,$out0,v24+ vncipher $out1,$out1,v24+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk0,$tweak,$rndkey0+ vaddubm $tweak,$tweak,$tweak+ vncipher $out2,$out2,v24+ vncipher $out3,$out3,v24+ vsldoi $tmp,$tmp,$tmp,15+ vncipher $out4,$out4,v24+ vncipher $out5,$out5,v24++ subfe. r0,r0,r0 # borrow?-1:0+ vand $tmp,$tmp,$eighty7+ vncipher $out0,$out0,v25+ vncipher $out1,$out1,v25+ vxor $tweak,$tweak,$tmp+ vncipher $out2,$out2,v25+ vncipher $out3,$out3,v25+ vxor $in1,$twk1,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk1,$tweak,$rndkey0+ vncipher $out4,$out4,v25+ vncipher $out5,$out5,v25++ and r0,r0,$len+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vncipher $out0,$out0,v26+ vncipher $out1,$out1,v26+ vand $tmp,$tmp,$eighty7+ vncipher $out2,$out2,v26+ vncipher $out3,$out3,v26+ vxor $tweak,$tweak,$tmp+ vncipher $out4,$out4,v26+ vncipher $out5,$out5,v26++ add $inp,$inp,r0 # $inp is adjusted in such+ # way that at exit from the+ # loop inX-in5 are loaded+ # with last "words"+ vxor $in2,$twk2,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk2,$tweak,$rndkey0+ vaddubm $tweak,$tweak,$tweak+ vncipher $out0,$out0,v27+ vncipher $out1,$out1,v27+ vsldoi $tmp,$tmp,$tmp,15+ vncipher $out2,$out2,v27+ vncipher $out3,$out3,v27+ vand $tmp,$tmp,$eighty7+ vncipher $out4,$out4,v27+ vncipher $out5,$out5,v27++ addi $key_,$sp,$FRAME+15 # rewind $key_+ vxor $tweak,$tweak,$tmp+ vncipher $out0,$out0,v28+ vncipher $out1,$out1,v28+ vxor $in3,$twk3,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk3,$tweak,$rndkey0+ vncipher $out2,$out2,v28+ vncipher $out3,$out3,v28+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vncipher $out4,$out4,v28+ vncipher $out5,$out5,v28+ lvx v24,$x00,$key_ # re-pre-load round[1]+ vand $tmp,$tmp,$eighty7++ vncipher $out0,$out0,v29+ vncipher $out1,$out1,v29+ vxor $tweak,$tweak,$tmp+ vncipher $out2,$out2,v29+ vncipher $out3,$out3,v29+ vxor $in4,$twk4,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk4,$tweak,$rndkey0+ vncipher $out4,$out4,v29+ vncipher $out5,$out5,v29+ lvx v25,$x10,$key_ # re-pre-load round[2]+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15++ vncipher $out0,$out0,v30+ vncipher $out1,$out1,v30+ vand $tmp,$tmp,$eighty7+ vncipher $out2,$out2,v30+ vncipher $out3,$out3,v30+ vxor $tweak,$tweak,$tmp+ vncipher $out4,$out4,v30+ vncipher $out5,$out5,v30+ vxor $in5,$twk5,v31+ vsrab $tmp,$tweak,$seven # next tweak value+ vxor $twk5,$tweak,$rndkey0++ vncipherlast $out0,$out0,$in0+ lvx_u $in0,$x00,$inp # load next input block+ vaddubm $tweak,$tweak,$tweak+ vsldoi $tmp,$tmp,$tmp,15+ vncipherlast $out1,$out1,$in1+ lvx_u $in1,$x10,$inp+ vncipherlast $out2,$out2,$in2+ le?vperm $in0,$in0,$in0,$leperm+ lvx_u $in2,$x20,$inp+ vand $tmp,$tmp,$eighty7+ vncipherlast $out3,$out3,$in3+ le?vperm $in1,$in1,$in1,$leperm+ lvx_u $in3,$x30,$inp+ vncipherlast $out4,$out4,$in4+ le?vperm $in2,$in2,$in2,$leperm+ lvx_u $in4,$x40,$inp+ vxor $tweak,$tweak,$tmp+ vncipherlast $out5,$out5,$in5+ le?vperm $in3,$in3,$in3,$leperm+ lvx_u $in5,$x50,$inp+ addi $inp,$inp,0x60+ le?vperm $in4,$in4,$in4,$leperm+ le?vperm $in5,$in5,$in5,$leperm++ le?vperm $out0,$out0,$out0,$leperm+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ vxor $out0,$in0,$twk0+ le?vperm $out2,$out2,$out2,$leperm+ stvx_u $out1,$x10,$out+ vxor $out1,$in1,$twk1+ le?vperm $out3,$out3,$out3,$leperm+ stvx_u $out2,$x20,$out+ vxor $out2,$in2,$twk2+ le?vperm $out4,$out4,$out4,$leperm+ stvx_u $out3,$x30,$out+ vxor $out3,$in3,$twk3+ le?vperm $out5,$out5,$out5,$leperm+ stvx_u $out4,$x40,$out+ vxor $out4,$in4,$twk4+ stvx_u $out5,$x50,$out+ vxor $out5,$in5,$twk5+ addi $out,$out,0x60++ mtctr $rounds+ beq Loop_xts_dec6x # did $len-=96 borrow?++ addic. $len,$len,0x60+ beq Lxts_dec6x_zero+ cmpwi $len,0x20+ blt Lxts_dec6x_one+ nop+ beq Lxts_dec6x_two+ cmpwi $len,0x40+ blt Lxts_dec6x_three+ nop+ beq Lxts_dec6x_four++Lxts_dec6x_five:+ vxor $out0,$in1,$twk0+ vxor $out1,$in2,$twk1+ vxor $out2,$in3,$twk2+ vxor $out3,$in4,$twk3+ vxor $out4,$in5,$twk4++ bl _aesp8_xts_dec5x++ le?vperm $out0,$out0,$out0,$leperm+ vmr $twk0,$twk5 # unused tweak+ vxor $twk1,$tweak,$rndkey0+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ vxor $out0,$in0,$twk1+ le?vperm $out2,$out2,$out2,$leperm+ stvx_u $out1,$x10,$out+ le?vperm $out3,$out3,$out3,$leperm+ stvx_u $out2,$x20,$out+ le?vperm $out4,$out4,$out4,$leperm+ stvx_u $out3,$x30,$out+ stvx_u $out4,$x40,$out+ addi $out,$out,0x50+ bne Lxts_dec6x_steal+ b Lxts_dec6x_done++.align 4+Lxts_dec6x_four:+ vxor $out0,$in2,$twk0+ vxor $out1,$in3,$twk1+ vxor $out2,$in4,$twk2+ vxor $out3,$in5,$twk3+ vxor $out4,$out4,$out4++ bl _aesp8_xts_dec5x++ le?vperm $out0,$out0,$out0,$leperm+ vmr $twk0,$twk4 # unused tweak+ vmr $twk1,$twk5+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ vxor $out0,$in0,$twk5+ le?vperm $out2,$out2,$out2,$leperm+ stvx_u $out1,$x10,$out+ le?vperm $out3,$out3,$out3,$leperm+ stvx_u $out2,$x20,$out+ stvx_u $out3,$x30,$out+ addi $out,$out,0x40+ bne Lxts_dec6x_steal+ b Lxts_dec6x_done++.align 4+Lxts_dec6x_three:+ vxor $out0,$in3,$twk0+ vxor $out1,$in4,$twk1+ vxor $out2,$in5,$twk2+ vxor $out3,$out3,$out3+ vxor $out4,$out4,$out4++ bl _aesp8_xts_dec5x++ le?vperm $out0,$out0,$out0,$leperm+ vmr $twk0,$twk3 # unused tweak+ vmr $twk1,$twk4+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ vxor $out0,$in0,$twk4+ le?vperm $out2,$out2,$out2,$leperm+ stvx_u $out1,$x10,$out+ stvx_u $out2,$x20,$out+ addi $out,$out,0x30+ bne Lxts_dec6x_steal+ b Lxts_dec6x_done++.align 4+Lxts_dec6x_two:+ vxor $out0,$in4,$twk0+ vxor $out1,$in5,$twk1+ vxor $out2,$out2,$out2+ vxor $out3,$out3,$out3+ vxor $out4,$out4,$out4++ bl _aesp8_xts_dec5x++ le?vperm $out0,$out0,$out0,$leperm+ vmr $twk0,$twk2 # unused tweak+ vmr $twk1,$twk3+ le?vperm $out1,$out1,$out1,$leperm+ stvx_u $out0,$x00,$out # store output+ vxor $out0,$in0,$twk3+ stvx_u $out1,$x10,$out+ addi $out,$out,0x20+ bne Lxts_dec6x_steal+ b Lxts_dec6x_done++.align 4+Lxts_dec6x_one:+ vxor $out0,$in5,$twk0+ nop+Loop_xts_dec1x:+ vncipher $out0,$out0,v24+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vncipher $out0,$out0,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz Loop_xts_dec1x++ subi r0,$taillen,1+ vncipher $out0,$out0,v24++ andi. r0,r0,16+ cmpwi $taillen,0+ vncipher $out0,$out0,v25++ sub $inp,$inp,r0+ vncipher $out0,$out0,v26++ lvx_u $in0,0,$inp+ vncipher $out0,$out0,v27++ addi $key_,$sp,$FRAME+15 # rewind $key_+ vncipher $out0,$out0,v28+ lvx v24,$x00,$key_ # re-pre-load round[1]++ vncipher $out0,$out0,v29+ lvx v25,$x10,$key_ # re-pre-load round[2]+ vxor $twk0,$twk0,v31++ le?vperm $in0,$in0,$in0,$leperm+ vncipher $out0,$out0,v30++ mtctr $rounds+ vncipherlast $out0,$out0,$twk0++ vmr $twk0,$twk1 # unused tweak+ vmr $twk1,$twk2+ le?vperm $out0,$out0,$out0,$leperm+ stvx_u $out0,$x00,$out # store output+ addi $out,$out,0x10+ vxor $out0,$in0,$twk2+ bne Lxts_dec6x_steal+ b Lxts_dec6x_done++.align 4+Lxts_dec6x_zero:+ cmpwi $taillen,0+ beq Lxts_dec6x_done++ lvx_u $in0,0,$inp+ le?vperm $in0,$in0,$in0,$leperm+ vxor $out0,$in0,$twk1+Lxts_dec6x_steal:+ vncipher $out0,$out0,v24+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vncipher $out0,$out0,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz Lxts_dec6x_steal++ add $inp,$inp,$taillen+ vncipher $out0,$out0,v24++ cmpwi $taillen,0+ vncipher $out0,$out0,v25++ lvx_u $in0,0,$inp+ vncipher $out0,$out0,v26++ lvsr $inpperm,0,$taillen # $in5 is no more+ vncipher $out0,$out0,v27++ addi $key_,$sp,$FRAME+15 # rewind $key_+ vncipher $out0,$out0,v28+ lvx v24,$x00,$key_ # re-pre-load round[1]++ vncipher $out0,$out0,v29+ lvx v25,$x10,$key_ # re-pre-load round[2]+ vxor $twk1,$twk1,v31++ le?vperm $in0,$in0,$in0,$leperm+ vncipher $out0,$out0,v30++ vperm $in0,$in0,$in0,$inpperm+ vncipherlast $tmp,$out0,$twk1++ le?vperm $out0,$tmp,$tmp,$leperm+ le?stvx_u $out0,0,$out+ be?stvx_u $tmp,0,$out++ vxor $out0,$out0,$out0+ vspltisb $out1,-1+ vperm $out0,$out0,$out1,$inpperm+ vsel $out0,$in0,$tmp,$out0+ vxor $out0,$out0,$twk0++ subi r30,$out,1+ mtctr $taillen+Loop_xts_dec6x_steal:+ lbzu r0,1(r30)+ stb r0,16(r30)+ bdnz Loop_xts_dec6x_steal++ li $taillen,0+ mtctr $rounds+ b Loop_xts_dec1x # one more time...++.align 4+Lxts_dec6x_done:+ ${UCMP}i $ivp,0+ beq Lxts_dec6x_ret++ vxor $tweak,$twk0,$rndkey0+ le?vperm $tweak,$tweak,$tweak,$leperm+ stvx_u $tweak,0,$ivp++Lxts_dec6x_ret:+ mtlr r11+ li r10,`$FRAME+15`+ li r11,`$FRAME+31`+ stvx $seven,r10,$sp # wipe copies of round keys+ addi r10,r10,32+ stvx $seven,r11,$sp+ addi r11,r11,32+ stvx $seven,r10,$sp+ addi r10,r10,32+ stvx $seven,r11,$sp+ addi r11,r11,32+ stvx $seven,r10,$sp+ addi r10,r10,32+ stvx $seven,r11,$sp+ addi r11,r11,32+ stvx $seven,r10,$sp+ addi r10,r10,32+ stvx $seven,r11,$sp+ addi r11,r11,32++ mtspr 256,$vrsave+ lvx v20,r10,$sp # ABI says so+ addi r10,r10,32+ lvx v21,r11,$sp+ addi r11,r11,32+ lvx v22,r10,$sp+ addi r10,r10,32+ lvx v23,r11,$sp+ addi r11,r11,32+ lvx v24,r10,$sp+ addi r10,r10,32+ lvx v25,r11,$sp+ addi r11,r11,32+ lvx v26,r10,$sp+ addi r10,r10,32+ lvx v27,r11,$sp+ addi r11,r11,32+ lvx v28,r10,$sp+ addi r10,r10,32+ lvx v29,r11,$sp+ addi r11,r11,32+ lvx v30,r10,$sp+ lvx v31,r11,$sp+ $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp)+ $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp)+ $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp)+ $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp)+ $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp)+ $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp)+ addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T`+ blr+ .long 0+ .byte 0,12,0x04,1,0x80,6,6,0+ .long 0++.align 5+_aesp8_xts_dec5x:+ vncipher $out0,$out0,v24+ vncipher $out1,$out1,v24+ vncipher $out2,$out2,v24+ vncipher $out3,$out3,v24+ vncipher $out4,$out4,v24+ lvx v24,$x20,$key_ # round[3]+ addi $key_,$key_,0x20++ vncipher $out0,$out0,v25+ vncipher $out1,$out1,v25+ vncipher $out2,$out2,v25+ vncipher $out3,$out3,v25+ vncipher $out4,$out4,v25+ lvx v25,$x10,$key_ # round[4]+ bdnz _aesp8_xts_dec5x++ subi r0,$taillen,1+ vncipher $out0,$out0,v24+ vncipher $out1,$out1,v24+ vncipher $out2,$out2,v24+ vncipher $out3,$out3,v24+ vncipher $out4,$out4,v24++ andi. r0,r0,16+ cmpwi $taillen,0+ vncipher $out0,$out0,v25+ vncipher $out1,$out1,v25+ vncipher $out2,$out2,v25+ vncipher $out3,$out3,v25+ vncipher $out4,$out4,v25+ vxor $twk0,$twk0,v31++ sub $inp,$inp,r0+ vncipher $out0,$out0,v26+ vncipher $out1,$out1,v26+ vncipher $out2,$out2,v26+ vncipher $out3,$out3,v26+ vncipher $out4,$out4,v26+ vxor $in1,$twk1,v31++ vncipher $out0,$out0,v27+ lvx_u $in0,0,$inp+ vncipher $out1,$out1,v27+ vncipher $out2,$out2,v27+ vncipher $out3,$out3,v27+ vncipher $out4,$out4,v27+ vxor $in2,$twk2,v31++ addi $key_,$sp,$FRAME+15 # rewind $key_+ vncipher $out0,$out0,v28+ vncipher $out1,$out1,v28+ vncipher $out2,$out2,v28+ vncipher $out3,$out3,v28+ vncipher $out4,$out4,v28+ lvx v24,$x00,$key_ # re-pre-load round[1]+ vxor $in3,$twk3,v31++ vncipher $out0,$out0,v29+ le?vperm $in0,$in0,$in0,$leperm+ vncipher $out1,$out1,v29+ vncipher $out2,$out2,v29+ vncipher $out3,$out3,v29+ vncipher $out4,$out4,v29+ lvx v25,$x10,$key_ # re-pre-load round[2]+ vxor $in4,$twk4,v31++ vncipher $out0,$out0,v30+ vncipher $out1,$out1,v30+ vncipher $out2,$out2,v30+ vncipher $out3,$out3,v30+ vncipher $out4,$out4,v30++ vncipherlast $out0,$out0,$twk0+ vncipherlast $out1,$out1,$in1+ vncipherlast $out2,$out2,$in2+ vncipherlast $out3,$out3,$in3+ vncipherlast $out4,$out4,$in4+ mtctr $rounds+ blr+ .long 0+ .byte 0,12,0x14,0,0,0,0,0+___+}} }}}++my $consts=1;+foreach(split("\n",$code)) {+ s/\`([^\`]*)\`/eval($1)/geo;++ # constants table endian-specific conversion+ if ($consts && m/\.(long|byte)\s+(.+)\s+(\?[a-z]*)$/o) {+ my $conv=$3;+ my @bytes=();++ # convert to endian-agnostic format+ if ($1 eq "long") {+ foreach (split(/,\s*/,$2)) {+ my $l = /^0/?oct:int;+ push @bytes,($l>>24)&0xff,($l>>16)&0xff,($l>>8)&0xff,$l&0xff;+ }+ } else {+ @bytes = map(/^0/?oct:int,split(/,\s*/,$2));+ }++ # little-endian conversion+ if ($flavour =~ /le$/o) {+ SWITCH: for($conv) {+ /\?inv/ && do { @bytes=map($_^0xf,@bytes); last; };+ /\?rev/ && do { @bytes=reverse(@bytes); last; };+ }+ }++ #emit+ print ".byte\t",join(',',map (sprintf("0x%02x",$_),@bytes)),"\n";+ next;+ }+ $consts=0 if (m/Lconsts:/o); # end of table++ # instructions prefixed with '?' are endian-specific and need+ # to be adjusted accordingly...+ if ($flavour =~ /le$/o) { # little-endian+ s/le\?//o or+ s/be\?/#be#/o or+ s/\?lvsr/lvsl/o or+ s/\?lvsl/lvsr/o or+ s/\?(vperm\s+v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+)/$1$3$2$4/o or+ s/\?(vsldoi\s+v[0-9]+,\s*)(v[0-9]+,)\s*(v[0-9]+,\s*)([0-9]+)/$1$3$2 16-$4/o or+ s/\?(vspltw\s+v[0-9]+,\s*)(v[0-9]+,)\s*([0-9])/$1$2 3-$3/o;+ } else { # big-endian+ s/le\?/#le#/o or+ s/be\?//o or+ s/\?([a-z]+)/$1/o;+ }++ print $_,"\n";+}++close STDOUT;
@@ -12,6 +12,8 @@ # arm/sha1-armv8.pl arm/sha512-armv8.pl # arm/keccak1600-armv8.pl arm/arm-xlate.pl # arm/arm_arch.h+# ppc/aesp8-ppc.pl ppc/ghashp8-ppc.pl+# ppc/ppc-xlate.pl # # The .pl files are the generator, not the product: each one emits # assembly for a given "flavour", which is the calling convention and the@@ -150,4 +152,25 @@ .section .note.GNU-stack,"",%progbits NOTE+done++# POWER8's AES and GHASH, little-endian only. The generator emits a+# big-endian flavour from the same source, and crypton does not build for+# big-endian POWER: nothing here has been able to run that code, and an AES+# path that has never been executed is not one to check in. Adding+# "linux64" to the list below is what it would take.+#+# These two read no capability word of their own -- unlike the ARM and x86-64+# modules above -- so the entry points are all that is renamed.+for flavour in linux64le; do+ perl aesp8-ppc.pl $flavour tmp-$flavour.S+ sed -e 's/\baes_p8_/crypton_aes_p8_/g' \+ tmp-$flavour.S > aesp8-ppc-$flavour.S++ perl ghashp8-ppc.pl $flavour tmp-$flavour.S+ sed -e 's/\bgcm_init_p8/crypton_gcm_init_p8/g' \+ -e 's/\bgcm_gmult_p8/crypton_gcm_gmult_p8/g' \+ -e 's/\bgcm_ghash_p8/crypton_gcm_ghash_p8/g' \+ tmp-$flavour.S > ghashp8-ppc-$flavour.S+ rm -f tmp-$flavour.S done
@@ -0,0 +1,575 @@+.machine "any"++.abiversion 2+.text++.globl crypton_gcm_init_p8+.type crypton_gcm_init_p8,@function+.align 5+crypton_gcm_init_p8:+.localentry crypton_gcm_init_p8,0++ li 0,-4096+ li 8,0x10+ li 12,-1+ li 9,0x20+ or 0,0,0+ li 10,0x30+ .long 0x7D202699++ vspltisb 8,-16+ vspltisb 5,1+ vaddubm 8,8,8+ vxor 4,4,4+ vor 8,8,5+ vsldoi 8,8,4,15+ vsldoi 6,4,5,1+ vaddubm 8,8,8+ vspltisb 7,7+ vor 8,8,6+ vspltb 6,9,0+ vsl 9,9,5+ vsrab 6,6,7+ vand 6,6,8+ vxor 3,9,6++ vsldoi 9,3,3,8+ vsldoi 8,4,8,8+ vsldoi 11,4,9,8+ vsldoi 10,9,4,8++ .long 0x7D001F99+ .long 0x7D681F99+ li 8,0x40+ .long 0x7D291F99+ li 9,0x50+ .long 0x7D4A1F99+ li 10,0x60++ .long 0x10035CC8+ .long 0x10234CC8+ .long 0x104354C8++ .long 0x10E044C8++ vsldoi 5,1,4,8+ vsldoi 6,4,1,8+ vxor 0,0,5+ vxor 2,2,6++ vsldoi 0,0,0,8+ vxor 0,0,7++ vsldoi 6,0,0,8+ .long 0x100044C8+ vxor 6,6,2+ vxor 16,0,6++ vsldoi 17,16,16,8+ vsldoi 19,4,17,8+ vsldoi 18,17,4,8++ .long 0x7E681F99+ li 8,0x70+ .long 0x7E291F99+ li 9,0x80+ .long 0x7E4A1F99+ li 10,0x90+ .long 0x10039CC8+ .long 0x11B09CC8+ .long 0x10238CC8+ .long 0x11D08CC8+ .long 0x104394C8+ .long 0x11F094C8++ .long 0x10E044C8+ .long 0x114D44C8++ vsldoi 5,1,4,8+ vsldoi 6,4,1,8+ vsldoi 11,14,4,8+ vsldoi 9,4,14,8+ vxor 0,0,5+ vxor 2,2,6+ vxor 13,13,11+ vxor 15,15,9++ vsldoi 0,0,0,8+ vsldoi 13,13,13,8+ vxor 0,0,7+ vxor 13,13,10++ vsldoi 6,0,0,8+ vsldoi 9,13,13,8+ .long 0x100044C8+ .long 0x11AD44C8+ vxor 6,6,2+ vxor 9,9,15+ vxor 0,0,6+ vxor 13,13,9++ vsldoi 9,0,0,8+ vsldoi 17,13,13,8+ vsldoi 11,4,9,8+ vsldoi 10,9,4,8+ vsldoi 19,4,17,8+ vsldoi 18,17,4,8++ .long 0x7D681F99+ li 8,0xa0+ .long 0x7D291F99+ li 9,0xb0+ .long 0x7D4A1F99+ li 10,0xc0+ .long 0x7E681F99+ .long 0x7E291F99+ .long 0x7E4A1F99++ or 12,12,12+ blr +.long 0+.byte 0,12,0x14,0,0,0,2,0+.long 0+.size crypton_gcm_init_p8,.-crypton_gcm_init_p8+.globl crypton_gcm_gmult_p8+.type crypton_gcm_gmult_p8,@function+.align 5+crypton_gcm_gmult_p8:+.localentry crypton_gcm_gmult_p8,0++ lis 0,0xfff8+ li 8,0x10+ li 12,-1+ li 9,0x20+ or 0,0,0+ li 10,0x30+ .long 0x7C601E99++ .long 0x7D682699+ lvsl 12,0,0+ .long 0x7D292699+ vspltisb 5,0x07+ .long 0x7D4A2699+ vxor 12,12,5+ .long 0x7D002699+ vperm 3,3,3,12+ vxor 4,4,4++ .long 0x10035CC8+ .long 0x10234CC8+ .long 0x104354C8++ .long 0x10E044C8++ vsldoi 5,1,4,8+ vsldoi 6,4,1,8+ vxor 0,0,5+ vxor 2,2,6++ vsldoi 0,0,0,8+ vxor 0,0,7++ vsldoi 6,0,0,8+ .long 0x100044C8+ vxor 6,6,2+ vxor 0,0,6++ vperm 0,0,0,12+ .long 0x7C001F99++ or 12,12,12+ blr +.long 0+.byte 0,12,0x14,0,0,0,2,0+.long 0+.size crypton_gcm_gmult_p8,.-crypton_gcm_gmult_p8++.globl crypton_gcm_ghash_p8+.type crypton_gcm_ghash_p8,@function+.align 5+crypton_gcm_ghash_p8:+.localentry crypton_gcm_ghash_p8,0++ li 0,-4096+ li 8,0x10+ li 12,-1+ li 9,0x20+ or 0,0,0+ li 10,0x30+ .long 0x7C001E99++ .long 0x7D682699+ li 8,0x40+ lvsl 12,0,0+ .long 0x7D292699+ li 9,0x50+ vspltisb 5,0x07+ .long 0x7D4A2699+ li 10,0x60+ vxor 12,12,5+ .long 0x7D002699+ vperm 0,0,0,12+ vxor 4,4,4++ cmpldi 6,64+ bge .Lgcm_ghash_p8_4x++ .long 0x7C602E99+ addi 5,5,16+ subic. 6,6,16+ vperm 3,3,3,12+ vxor 3,3,0+ beq .Lshort++ .long 0x7E682699+ li 8,16+ .long 0x7E292699+ add 9,5,6+ .long 0x7E4A2699+++.align 5+.Loop_2x:+ .long 0x7E002E99+ vperm 16,16,16,12++ subic 6,6,32+ .long 0x10039CC8+ .long 0x11B05CC8+ subfe 0,0,0+ .long 0x10238CC8+ .long 0x11D04CC8+ and 0,0,6+ .long 0x104394C8+ .long 0x11F054C8+ add 5,5,0++ vxor 0,0,13+ vxor 1,1,14++ .long 0x10E044C8++ vsldoi 5,1,4,8+ vsldoi 6,4,1,8+ vxor 2,2,15+ vxor 0,0,5+ vxor 2,2,6++ vsldoi 0,0,0,8+ vxor 0,0,7+ .long 0x7C682E99+ addi 5,5,32++ vsldoi 6,0,0,8+ .long 0x100044C8+ vperm 3,3,3,12+ vxor 6,6,2+ vxor 3,3,6+ vxor 3,3,0+ cmpld 9,5+ bgt .Loop_2x++ cmplwi 6,0+ bne .Leven++.Lshort:+ .long 0x10035CC8+ .long 0x10234CC8+ .long 0x104354C8++ .long 0x10E044C8++ vsldoi 5,1,4,8+ vsldoi 6,4,1,8+ vxor 0,0,5+ vxor 2,2,6++ vsldoi 0,0,0,8+ vxor 0,0,7++ vsldoi 6,0,0,8+ .long 0x100044C8+ vxor 6,6,2++.Leven:+ vxor 0,0,6+ vperm 0,0,0,12+ .long 0x7C001F99++ or 12,12,12+ blr +.long 0+.byte 0,12,0x14,0,0,0,4,0+.long 0+.align 5+.crypton_gcm_ghash_p8_4x:+.Lgcm_ghash_p8_4x:+ stdu 1,-256(1)+ li 10,63+ li 11,79+ stvx 20,10,1+ addi 10,10,32+ stvx 21,11,1+ addi 11,11,32+ stvx 22,10,1+ addi 10,10,32+ stvx 23,11,1+ addi 11,11,32+ stvx 24,10,1+ addi 10,10,32+ stvx 25,11,1+ addi 11,11,32+ stvx 26,10,1+ addi 10,10,32+ stvx 27,11,1+ addi 11,11,32+ stvx 28,10,1+ addi 10,10,32+ stvx 29,11,1+ addi 11,11,32+ stvx 30,10,1+ li 10,0x60+ stvx 31,11,1+ li 0,-1+ stw 12,252(1)+ or 0,0,0++ lvsl 5,0,8++ li 8,0x70+ .long 0x7E292699+ li 9,0x80+ vspltisb 6,8++ li 10,0x90+ .long 0x7EE82699+ li 8,0xa0+ .long 0x7F092699+ li 9,0xb0+ .long 0x7F2A2699+ li 10,0xc0+ .long 0x7FA82699+ li 8,0x10+ .long 0x7FC92699+ li 9,0x20+ .long 0x7FEA2699+ li 10,0x30++ vsldoi 7,4,6,8+ vaddubm 18,5,7+ vaddubm 19,6,18++ srdi 6,6,4++ .long 0x7C602E99+ .long 0x7E082E99+ subic. 6,6,8+ .long 0x7EC92E99+ .long 0x7F8A2E99+ addi 5,5,0x40+ vperm 3,3,3,12+ vperm 16,16,16,12+ vperm 22,22,22,12+ vperm 28,28,28,12++ vxor 2,3,0++ .long 0x11B0BCC8+ .long 0x11D0C4C8+ .long 0x11F0CCC8++ vperm 11,17,9,18+ vperm 5,22,28,19+ vperm 10,17,9,19+ vperm 6,22,28,18+ .long 0x12B68CC8+ .long 0x12855CC8+ .long 0x137C4CC8+ .long 0x134654C8++ vxor 21,21,14+ vxor 20,20,13+ vxor 27,27,21+ vxor 26,26,15++ blt .Ltail_4x++.Loop_4x:+ .long 0x7C602E99+ .long 0x7E082E99+ subic. 6,6,4+ .long 0x7EC92E99+ .long 0x7F8A2E99+ addi 5,5,0x40+ vperm 16,16,16,12+ vperm 22,22,22,12+ vperm 28,28,28,12+ vperm 3,3,3,12++ .long 0x1002ECC8+ .long 0x1022F4C8+ .long 0x1042FCC8+ .long 0x11B0BCC8+ .long 0x11D0C4C8+ .long 0x11F0CCC8++ vxor 0,0,20+ vxor 1,1,27+ vxor 2,2,26+ vperm 5,22,28,19+ vperm 6,22,28,18++ .long 0x10E044C8+ .long 0x12855CC8+ .long 0x134654C8++ vsldoi 5,1,4,8+ vsldoi 6,4,1,8+ vxor 0,0,5+ vxor 2,2,6++ vsldoi 0,0,0,8+ vxor 0,0,7++ vsldoi 6,0,0,8+ .long 0x12B68CC8+ .long 0x137C4CC8+ .long 0x100044C8++ vxor 20,20,13+ vxor 26,26,15+ vxor 2,2,3+ vxor 21,21,14+ vxor 2,2,6+ vxor 27,27,21+ vxor 2,2,0+ bge .Loop_4x++.Ltail_4x:+ .long 0x1002ECC8+ .long 0x1022F4C8+ .long 0x1042FCC8++ vxor 0,0,20+ vxor 1,1,27++ .long 0x10E044C8++ vsldoi 5,1,4,8+ vsldoi 6,4,1,8+ vxor 2,2,26+ vxor 0,0,5+ vxor 2,2,6++ vsldoi 0,0,0,8+ vxor 0,0,7++ vsldoi 6,0,0,8+ .long 0x100044C8+ vxor 6,6,2+ vxor 0,0,6++ addic. 6,6,4+ beq .Ldone_4x++ .long 0x7C602E99+ cmpldi 6,2+ li 6,-4+ blt .Lone+ .long 0x7E082E99+ beq .Ltwo++.Lthree:+ .long 0x7EC92E99+ vperm 3,3,3,12+ vperm 16,16,16,12+ vperm 22,22,22,12++ vxor 2,3,0+ vor 29,23,23+ vor 30,24,24+ vor 31,25,25++ vperm 5,16,22,19+ vperm 6,16,22,18+ .long 0x12B08CC8+ .long 0x13764CC8+ .long 0x12855CC8+ .long 0x134654C8++ vxor 27,27,21+ b .Ltail_4x++.align 4+.Ltwo:+ vperm 3,3,3,12+ vperm 16,16,16,12++ vxor 2,3,0+ vperm 5,4,16,19+ vperm 6,4,16,18++ vsldoi 29,4,17,8+ vor 30,17,17+ vsldoi 31,17,4,8++ .long 0x12855CC8+ .long 0x13704CC8+ .long 0x134654C8++ b .Ltail_4x++.align 4+.Lone:+ vperm 3,3,3,12++ vsldoi 29,4,9,8+ vor 30,9,9+ vsldoi 31,9,4,8++ vxor 2,3,0+ vxor 20,20,20+ vxor 27,27,27+ vxor 26,26,26++ b .Ltail_4x++.Ldone_4x:+ vperm 0,0,0,12+ .long 0x7C001F99++ li 10,63+ li 11,79+ or 12,12,12+ lvx 20,10,1+ addi 10,10,32+ lvx 21,11,1+ addi 11,11,32+ lvx 22,10,1+ addi 10,10,32+ lvx 23,11,1+ addi 11,11,32+ lvx 24,10,1+ addi 10,10,32+ lvx 25,11,1+ addi 11,11,32+ lvx 26,10,1+ addi 10,10,32+ lvx 27,11,1+ addi 11,11,32+ lvx 28,10,1+ addi 10,10,32+ lvx 29,11,1+ addi 11,11,32+ lvx 30,10,1+ lvx 31,11,1+ addi 1,1,256+ blr +.long 0+.byte 0,12,0x04,0,0x80,0,4,0+.long 0+.size crypton_gcm_ghash_p8,.-crypton_gcm_ghash_p8++.byte 71,72,65,83,72,32,102,111,114,32,80,111,119,101,114,73,83,65,32,50,46,48,55,44,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0+.align 2+.align 2
@@ -0,0 +1,664 @@+#!/usr/bin/env perl+#+# ====================================================================+# Written by Andy Polyakov, @dot-asm, initially for use in the OpenSSL+# project. The module is dual licensed under OpenSSL and CRYPTOGAMS+# licenses depending on where you obtain it. For further details see+# https://github.com/dot-asm/cryptogams/.+# ====================================================================+#+# GHASH for for PowerISA v2.07.+#+# July 2014+#+# Accurate performance measurements are problematic, because it's+# always virtualized setup with possibly throttled processor.+# Relative comparison is therefore more informative. This initial+# version is ~2.1x slower than hardware-assisted AES-128-CTR, ~12x+# faster than "4-bit" integer-only compiler-generated 64-bit code.+# "Initial version" means that there is room for further improvement.++# May 2016+#+# 2x aggregated reduction improves performance by 50% (resulting+# performance on POWER8 is 1 cycle per processed byte), and 4x+# aggregated reduction - by 170% or 2.7x (resulting in 0.55 cpb).+# POWER9 delivers 0.51 cpb.++$flavour=shift;+$output =shift;++if ($flavour =~ /64/) {+ $SIZE_T=8;+ $LRSAVE=2*$SIZE_T;+ $STU="stdu";+ $POP="ld";+ $PUSH="std";+ $UCMP="cmpld";+ $SHRI="srdi";+} elsif ($flavour =~ /32/) {+ $SIZE_T=4;+ $LRSAVE=$SIZE_T;+ $STU="stwu";+ $POP="lwz";+ $PUSH="stw";+ $UCMP="cmplw";+ $SHRI="srwi";+} else { die "nonsense $flavour"; }++$sp="r1";+$FRAME=6*$SIZE_T+13*16; # 13*16 is for v20-v31 offload++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;+( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or+( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or+die "can't locate ppc-xlate.pl";++open STDOUT,"| $^X $xlate $flavour $output" || die "can't call $xlate: $!";++my ($Xip,$Htbl,$inp,$len)=map("r$_",(3..6)); # argument block++my ($Xl,$Xm,$Xh,$IN)=map("v$_",(0..3));+my ($zero,$t0,$t1,$t2,$xC2,$H,$Hh,$Hl,$lemask)=map("v$_",(4..12));+my ($Xl1,$Xm1,$Xh1,$IN1,$H2,$H2h,$H2l)=map("v$_",(13..19));+my $vrsave="r12";++$code=<<___;+.machine "any"++.text++.globl .gcm_init_p8+.align 5+.gcm_init_p8:+ li r0,-4096+ li r8,0x10+ mfspr $vrsave,256+ li r9,0x20+ mtspr 256,r0+ li r10,0x30+ lvx_u $H,0,r4 # load H++ vspltisb $xC2,-16 # 0xf0+ vspltisb $t0,1 # one+ vaddubm $xC2,$xC2,$xC2 # 0xe0+ vxor $zero,$zero,$zero+ vor $xC2,$xC2,$t0 # 0xe1+ vsldoi $xC2,$xC2,$zero,15 # 0xe1...+ vsldoi $t1,$zero,$t0,1 # ...1+ vaddubm $xC2,$xC2,$xC2 # 0xc2...+ vspltisb $t2,7+ vor $xC2,$xC2,$t1 # 0xc2....01+ vspltb $t1,$H,0 # most significant byte+ vsl $H,$H,$t0 # H<<=1+ vsrab $t1,$t1,$t2 # broadcast carry bit+ vand $t1,$t1,$xC2+ vxor $IN,$H,$t1 # twisted H++ vsldoi $H,$IN,$IN,8 # twist even more ...+ vsldoi $xC2,$zero,$xC2,8 # 0xc2.0+ vsldoi $Hl,$zero,$H,8 # ... and split+ vsldoi $Hh,$H,$zero,8++ stvx_u $xC2,0,r3 # save pre-computed table+ stvx_u $Hl,r8,r3+ li r8,0x40+ stvx_u $H, r9,r3+ li r9,0x50+ stvx_u $Hh,r10,r3+ li r10,0x60++ vpmsumd $Xl,$IN,$Hl # H.lo·H.lo+ vpmsumd $Xm,$IN,$H # H.hi·H.lo+H.lo·H.hi+ vpmsumd $Xh,$IN,$Hh # H.hi·H.hi++ vpmsumd $t2,$Xl,$xC2 # 1st reduction phase++ vsldoi $t0,$Xm,$zero,8+ vsldoi $t1,$zero,$Xm,8+ vxor $Xl,$Xl,$t0+ vxor $Xh,$Xh,$t1++ vsldoi $Xl,$Xl,$Xl,8+ vxor $Xl,$Xl,$t2++ vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase+ vpmsumd $Xl,$Xl,$xC2+ vxor $t1,$t1,$Xh+ vxor $IN1,$Xl,$t1++ vsldoi $H2,$IN1,$IN1,8+ vsldoi $H2l,$zero,$H2,8+ vsldoi $H2h,$H2,$zero,8++ stvx_u $H2l,r8,r3 # save H^2+ li r8,0x70+ stvx_u $H2,r9,r3+ li r9,0x80+ stvx_u $H2h,r10,r3+ li r10,0x90+___+{+my ($t4,$t5,$t6) = ($Hl,$H,$Hh);+$code.=<<___;+ vpmsumd $Xl,$IN,$H2l # H.lo·H^2.lo+ vpmsumd $Xl1,$IN1,$H2l # H^2.lo·H^2.lo+ vpmsumd $Xm,$IN,$H2 # H.hi·H^2.lo+H.lo·H^2.hi+ vpmsumd $Xm1,$IN1,$H2 # H^2.hi·H^2.lo+H^2.lo·H^2.hi+ vpmsumd $Xh,$IN,$H2h # H.hi·H^2.hi+ vpmsumd $Xh1,$IN1,$H2h # H^2.hi·H^2.hi++ vpmsumd $t2,$Xl,$xC2 # 1st reduction phase+ vpmsumd $t6,$Xl1,$xC2 # 1st reduction phase++ vsldoi $t0,$Xm,$zero,8+ vsldoi $t1,$zero,$Xm,8+ vsldoi $t4,$Xm1,$zero,8+ vsldoi $t5,$zero,$Xm1,8+ vxor $Xl,$Xl,$t0+ vxor $Xh,$Xh,$t1+ vxor $Xl1,$Xl1,$t4+ vxor $Xh1,$Xh1,$t5++ vsldoi $Xl,$Xl,$Xl,8+ vsldoi $Xl1,$Xl1,$Xl1,8+ vxor $Xl,$Xl,$t2+ vxor $Xl1,$Xl1,$t6++ vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase+ vsldoi $t5,$Xl1,$Xl1,8 # 2nd reduction phase+ vpmsumd $Xl,$Xl,$xC2+ vpmsumd $Xl1,$Xl1,$xC2+ vxor $t1,$t1,$Xh+ vxor $t5,$t5,$Xh1+ vxor $Xl,$Xl,$t1+ vxor $Xl1,$Xl1,$t5++ vsldoi $H,$Xl,$Xl,8+ vsldoi $H2,$Xl1,$Xl1,8+ vsldoi $Hl,$zero,$H,8+ vsldoi $Hh,$H,$zero,8+ vsldoi $H2l,$zero,$H2,8+ vsldoi $H2h,$H2,$zero,8++ stvx_u $Hl,r8,r3 # save H^3+ li r8,0xa0+ stvx_u $H,r9,r3+ li r9,0xb0+ stvx_u $Hh,r10,r3+ li r10,0xc0+ stvx_u $H2l,r8,r3 # save H^4+ stvx_u $H2,r9,r3+ stvx_u $H2h,r10,r3++ mtspr 256,$vrsave+ blr+ .long 0+ .byte 0,12,0x14,0,0,0,2,0+ .long 0+.size .gcm_init_p8,.-.gcm_init_p8+___+}+$code.=<<___;+.globl .gcm_gmult_p8+.align 5+.gcm_gmult_p8:+ lis r0,0xfff8+ li r8,0x10+ mfspr $vrsave,256+ li r9,0x20+ mtspr 256,r0+ li r10,0x30+ lvx_u $IN,0,$Xip # load Xi++ lvx_u $Hl,r8,$Htbl # load pre-computed table+ le?lvsl $lemask,r0,r0+ lvx_u $H, r9,$Htbl+ le?vspltisb $t0,0x07+ lvx_u $Hh,r10,$Htbl+ le?vxor $lemask,$lemask,$t0+ lvx_u $xC2,0,$Htbl+ le?vperm $IN,$IN,$IN,$lemask+ vxor $zero,$zero,$zero++ vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo+ vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi+ vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi++ vpmsumd $t2,$Xl,$xC2 # 1st reduction phase++ vsldoi $t0,$Xm,$zero,8+ vsldoi $t1,$zero,$Xm,8+ vxor $Xl,$Xl,$t0+ vxor $Xh,$Xh,$t1++ vsldoi $Xl,$Xl,$Xl,8+ vxor $Xl,$Xl,$t2++ vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase+ vpmsumd $Xl,$Xl,$xC2+ vxor $t1,$t1,$Xh+ vxor $Xl,$Xl,$t1++ le?vperm $Xl,$Xl,$Xl,$lemask+ stvx_u $Xl,0,$Xip # write out Xi++ mtspr 256,$vrsave+ blr+ .long 0+ .byte 0,12,0x14,0,0,0,2,0+ .long 0+.size .gcm_gmult_p8,.-.gcm_gmult_p8++.globl .gcm_ghash_p8+.align 5+.gcm_ghash_p8:+ li r0,-4096+ li r8,0x10+ mfspr $vrsave,256+ li r9,0x20+ mtspr 256,r0+ li r10,0x30+ lvx_u $Xl,0,$Xip # load Xi++ lvx_u $Hl,r8,$Htbl # load pre-computed table+ li r8,0x40+ le?lvsl $lemask,r0,r0+ lvx_u $H, r9,$Htbl+ li r9,0x50+ le?vspltisb $t0,0x07+ lvx_u $Hh,r10,$Htbl+ li r10,0x60+ le?vxor $lemask,$lemask,$t0+ lvx_u $xC2,0,$Htbl+ le?vperm $Xl,$Xl,$Xl,$lemask+ vxor $zero,$zero,$zero++ ${UCMP}i $len,64+ bge Lgcm_ghash_p8_4x++ lvx_u $IN,0,$inp+ addi $inp,$inp,16+ subic. $len,$len,16+ le?vperm $IN,$IN,$IN,$lemask+ vxor $IN,$IN,$Xl+ beq Lshort++ lvx_u $H2l,r8,$Htbl # load H^2+ li r8,16+ lvx_u $H2, r9,$Htbl+ add r9,$inp,$len # end of input+ lvx_u $H2h,r10,$Htbl+ be?b Loop_2x++.align 5+Loop_2x:+ lvx_u $IN1,0,$inp+ le?vperm $IN1,$IN1,$IN1,$lemask++ subic $len,$len,32+ vpmsumd $Xl,$IN,$H2l # H^2.lo·Xi.lo+ vpmsumd $Xl1,$IN1,$Hl # H.lo·Xi+1.lo+ subfe r0,r0,r0 # borrow?-1:0+ vpmsumd $Xm,$IN,$H2 # H^2.hi·Xi.lo+H^2.lo·Xi.hi+ vpmsumd $Xm1,$IN1,$H # H.hi·Xi+1.lo+H.lo·Xi+1.hi+ and r0,r0,$len+ vpmsumd $Xh,$IN,$H2h # H^2.hi·Xi.hi+ vpmsumd $Xh1,$IN1,$Hh # H.hi·Xi+1.hi+ add $inp,$inp,r0++ vxor $Xl,$Xl,$Xl1+ vxor $Xm,$Xm,$Xm1++ vpmsumd $t2,$Xl,$xC2 # 1st reduction phase++ vsldoi $t0,$Xm,$zero,8+ vsldoi $t1,$zero,$Xm,8+ vxor $Xh,$Xh,$Xh1+ vxor $Xl,$Xl,$t0+ vxor $Xh,$Xh,$t1++ vsldoi $Xl,$Xl,$Xl,8+ vxor $Xl,$Xl,$t2+ lvx_u $IN,r8,$inp+ addi $inp,$inp,32++ vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase+ vpmsumd $Xl,$Xl,$xC2+ le?vperm $IN,$IN,$IN,$lemask+ vxor $t1,$t1,$Xh+ vxor $IN,$IN,$t1+ vxor $IN,$IN,$Xl+ $UCMP r9,$inp+ bgt Loop_2x # done yet?++ cmplwi $len,0+ bne Leven++Lshort:+ vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo+ vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi+ vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi++ vpmsumd $t2,$Xl,$xC2 # 1st reduction phase++ vsldoi $t0,$Xm,$zero,8+ vsldoi $t1,$zero,$Xm,8+ vxor $Xl,$Xl,$t0+ vxor $Xh,$Xh,$t1++ vsldoi $Xl,$Xl,$Xl,8+ vxor $Xl,$Xl,$t2++ vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase+ vpmsumd $Xl,$Xl,$xC2+ vxor $t1,$t1,$Xh++Leven:+ vxor $Xl,$Xl,$t1+ le?vperm $Xl,$Xl,$Xl,$lemask+ stvx_u $Xl,0,$Xip # write out Xi++ mtspr 256,$vrsave+ blr+ .long 0+ .byte 0,12,0x14,0,0,0,4,0+ .long 0+___+{+my ($Xl3,$Xm2,$IN2,$H3l,$H3,$H3h,+ $Xh3,$Xm3,$IN3,$H4l,$H4,$H4h) = map("v$_",(20..31));+my $IN0=$IN;+my ($H21l,$H21h,$loperm,$hiperm) = ($Hl,$Hh,$H2l,$H2h);++$code.=<<___;+.align 5+.gcm_ghash_p8_4x:+Lgcm_ghash_p8_4x:+ $STU $sp,-$FRAME($sp)+ li r10,`15+6*$SIZE_T`+ li r11,`31+6*$SIZE_T`+ stvx v20,r10,$sp+ addi r10,r10,32+ stvx v21,r11,$sp+ addi r11,r11,32+ stvx v22,r10,$sp+ addi r10,r10,32+ stvx v23,r11,$sp+ addi r11,r11,32+ stvx v24,r10,$sp+ addi r10,r10,32+ stvx v25,r11,$sp+ addi r11,r11,32+ stvx v26,r10,$sp+ addi r10,r10,32+ stvx v27,r11,$sp+ addi r11,r11,32+ stvx v28,r10,$sp+ addi r10,r10,32+ stvx v29,r11,$sp+ addi r11,r11,32+ stvx v30,r10,$sp+ li r10,0x60+ stvx v31,r11,$sp+ li r0,-1+ stw $vrsave,`$FRAME-4`($sp) # save vrsave+ mtspr 256,r0 # preserve all AltiVec registers++ lvsl $t0,0,r8 # 0x0001..0e0f+ #lvx_u $H2l,r8,$Htbl # load H^2+ li r8,0x70+ lvx_u $H2, r9,$Htbl+ li r9,0x80+ vspltisb $t1,8 # 0x0808..0808+ #lvx_u $H2h,r10,$Htbl+ li r10,0x90+ lvx_u $H3l,r8,$Htbl # load H^3+ li r8,0xa0+ lvx_u $H3, r9,$Htbl+ li r9,0xb0+ lvx_u $H3h,r10,$Htbl+ li r10,0xc0+ lvx_u $H4l,r8,$Htbl # load H^4+ li r8,0x10+ lvx_u $H4, r9,$Htbl+ li r9,0x20+ lvx_u $H4h,r10,$Htbl+ li r10,0x30++ vsldoi $t2,$zero,$t1,8 # 0x0000..0808+ vaddubm $hiperm,$t0,$t2 # 0x0001..1617+ vaddubm $loperm,$t1,$hiperm # 0x0809..1e1f++ $SHRI $len,$len,4 # this allows to use sign bit+ # as carry+ lvx_u $IN0,0,$inp # load input+ lvx_u $IN1,r8,$inp+ subic. $len,$len,8+ lvx_u $IN2,r9,$inp+ lvx_u $IN3,r10,$inp+ addi $inp,$inp,0x40+ le?vperm $IN0,$IN0,$IN0,$lemask+ le?vperm $IN1,$IN1,$IN1,$lemask+ le?vperm $IN2,$IN2,$IN2,$lemask+ le?vperm $IN3,$IN3,$IN3,$lemask++ vxor $Xh,$IN0,$Xl++ vpmsumd $Xl1,$IN1,$H3l+ vpmsumd $Xm1,$IN1,$H3+ vpmsumd $Xh1,$IN1,$H3h++ vperm $H21l,$H2,$H,$hiperm+ vperm $t0,$IN2,$IN3,$loperm+ vperm $H21h,$H2,$H,$loperm+ vperm $t1,$IN2,$IN3,$hiperm+ vpmsumd $Xm2,$IN2,$H2 # H^2.lo·Xi+2.hi+H^2.hi·Xi+2.lo+ vpmsumd $Xl3,$t0,$H21l # H^2.lo·Xi+2.lo+H.lo·Xi+3.lo+ vpmsumd $Xm3,$IN3,$H # H.hi·Xi+3.lo +H.lo·Xi+3.hi+ vpmsumd $Xh3,$t1,$H21h # H^2.hi·Xi+2.hi+H.hi·Xi+3.hi++ vxor $Xm2,$Xm2,$Xm1+ vxor $Xl3,$Xl3,$Xl1+ vxor $Xm3,$Xm3,$Xm2+ vxor $Xh3,$Xh3,$Xh1++ blt Ltail_4x++Loop_4x:+ lvx_u $IN0,0,$inp+ lvx_u $IN1,r8,$inp+ subic. $len,$len,4+ lvx_u $IN2,r9,$inp+ lvx_u $IN3,r10,$inp+ addi $inp,$inp,0x40+ le?vperm $IN1,$IN1,$IN1,$lemask+ le?vperm $IN2,$IN2,$IN2,$lemask+ le?vperm $IN3,$IN3,$IN3,$lemask+ le?vperm $IN0,$IN0,$IN0,$lemask++ vpmsumd $Xl,$Xh,$H4l # H^4.lo·Xi.lo+ vpmsumd $Xm,$Xh,$H4 # H^4.hi·Xi.lo+H^4.lo·Xi.hi+ vpmsumd $Xh,$Xh,$H4h # H^4.hi·Xi.hi+ vpmsumd $Xl1,$IN1,$H3l+ vpmsumd $Xm1,$IN1,$H3+ vpmsumd $Xh1,$IN1,$H3h++ vxor $Xl,$Xl,$Xl3+ vxor $Xm,$Xm,$Xm3+ vxor $Xh,$Xh,$Xh3+ vperm $t0,$IN2,$IN3,$loperm+ vperm $t1,$IN2,$IN3,$hiperm++ vpmsumd $t2,$Xl,$xC2 # 1st reduction phase+ vpmsumd $Xl3,$t0,$H21l # H.lo·Xi+3.lo +H^2.lo·Xi+2.lo+ vpmsumd $Xh3,$t1,$H21h # H.hi·Xi+3.hi +H^2.hi·Xi+2.hi++ vsldoi $t0,$Xm,$zero,8+ vsldoi $t1,$zero,$Xm,8+ vxor $Xl,$Xl,$t0+ vxor $Xh,$Xh,$t1++ vsldoi $Xl,$Xl,$Xl,8+ vxor $Xl,$Xl,$t2++ vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase+ vpmsumd $Xm2,$IN2,$H2 # H^2.hi·Xi+2.lo+H^2.lo·Xi+2.hi+ vpmsumd $Xm3,$IN3,$H # H.hi·Xi+3.lo +H.lo·Xi+3.hi+ vpmsumd $Xl,$Xl,$xC2++ vxor $Xl3,$Xl3,$Xl1+ vxor $Xh3,$Xh3,$Xh1+ vxor $Xh,$Xh,$IN0+ vxor $Xm2,$Xm2,$Xm1+ vxor $Xh,$Xh,$t1+ vxor $Xm3,$Xm3,$Xm2+ vxor $Xh,$Xh,$Xl+ bge Loop_4x++Ltail_4x:+ vpmsumd $Xl,$Xh,$H4l # H^4.lo·Xi.lo+ vpmsumd $Xm,$Xh,$H4 # H^4.hi·Xi.lo+H^4.lo·Xi.hi+ vpmsumd $Xh,$Xh,$H4h # H^4.hi·Xi.hi++ vxor $Xl,$Xl,$Xl3+ vxor $Xm,$Xm,$Xm3++ vpmsumd $t2,$Xl,$xC2 # 1st reduction phase++ vsldoi $t0,$Xm,$zero,8+ vsldoi $t1,$zero,$Xm,8+ vxor $Xh,$Xh,$Xh3+ vxor $Xl,$Xl,$t0+ vxor $Xh,$Xh,$t1++ vsldoi $Xl,$Xl,$Xl,8+ vxor $Xl,$Xl,$t2++ vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase+ vpmsumd $Xl,$Xl,$xC2+ vxor $t1,$t1,$Xh+ vxor $Xl,$Xl,$t1++ addic. $len,$len,4+ beq Ldone_4x++ lvx_u $IN0,0,$inp+ ${UCMP}i $len,2+ li $len,-4+ blt Lone+ lvx_u $IN1,r8,$inp+ beq Ltwo++Lthree:+ lvx_u $IN2,r9,$inp+ le?vperm $IN0,$IN0,$IN0,$lemask+ le?vperm $IN1,$IN1,$IN1,$lemask+ le?vperm $IN2,$IN2,$IN2,$lemask++ vxor $Xh,$IN0,$Xl+ vmr $H4l,$H3l+ vmr $H4, $H3+ vmr $H4h,$H3h++ vperm $t0,$IN1,$IN2,$loperm+ vperm $t1,$IN1,$IN2,$hiperm+ vpmsumd $Xm2,$IN1,$H2 # H^2.lo·Xi+1.hi+H^2.hi·Xi+1.lo+ vpmsumd $Xm3,$IN2,$H # H.hi·Xi+2.lo +H.lo·Xi+2.hi+ vpmsumd $Xl3,$t0,$H21l # H^2.lo·Xi+1.lo+H.lo·Xi+2.lo+ vpmsumd $Xh3,$t1,$H21h # H^2.hi·Xi+1.hi+H.hi·Xi+2.hi++ vxor $Xm3,$Xm3,$Xm2+ b Ltail_4x++.align 4+Ltwo:+ le?vperm $IN0,$IN0,$IN0,$lemask+ le?vperm $IN1,$IN1,$IN1,$lemask++ vxor $Xh,$IN0,$Xl+ vperm $t0,$zero,$IN1,$loperm+ vperm $t1,$zero,$IN1,$hiperm++ vsldoi $H4l,$zero,$H2,8+ vmr $H4, $H2+ vsldoi $H4h,$H2,$zero,8++ vpmsumd $Xl3,$t0, $H21l # H.lo·Xi+1.lo+ vpmsumd $Xm3,$IN1,$H # H.hi·Xi+1.lo+H.lo·Xi+2.hi+ vpmsumd $Xh3,$t1, $H21h # H.hi·Xi+1.hi++ b Ltail_4x++.align 4+Lone:+ le?vperm $IN0,$IN0,$IN0,$lemask++ vsldoi $H4l,$zero,$H,8+ vmr $H4, $H+ vsldoi $H4h,$H,$zero,8++ vxor $Xh,$IN0,$Xl+ vxor $Xl3,$Xl3,$Xl3+ vxor $Xm3,$Xm3,$Xm3+ vxor $Xh3,$Xh3,$Xh3++ b Ltail_4x++Ldone_4x:+ le?vperm $Xl,$Xl,$Xl,$lemask+ stvx_u $Xl,0,$Xip # write out Xi++ li r10,`15+6*$SIZE_T`+ li r11,`31+6*$SIZE_T`+ mtspr 256,$vrsave+ lvx v20,r10,$sp+ addi r10,r10,32+ lvx v21,r11,$sp+ addi r11,r11,32+ lvx v22,r10,$sp+ addi r10,r10,32+ lvx v23,r11,$sp+ addi r11,r11,32+ lvx v24,r10,$sp+ addi r10,r10,32+ lvx v25,r11,$sp+ addi r11,r11,32+ lvx v26,r10,$sp+ addi r10,r10,32+ lvx v27,r11,$sp+ addi r11,r11,32+ lvx v28,r10,$sp+ addi r10,r10,32+ lvx v29,r11,$sp+ addi r11,r11,32+ lvx v30,r10,$sp+ lvx v31,r11,$sp+ addi $sp,$sp,$FRAME+ blr+ .long 0+ .byte 0,12,0x04,0,0x80,0,4,0+ .long 0+___+}+$code.=<<___;+.size .gcm_ghash_p8,.-.gcm_ghash_p8++.asciz "GHASH for PowerISA 2.07, CRYPTOGAMS by <appro\@openssl.org>"+.align 2+___++foreach (split("\n",$code)) {+ s/\`([^\`]*)\`/eval $1/geo;++ if ($flavour =~ /le$/o) { # little-endian+ s/le\?//o or+ s/be\?/#be#/o;+ } else {+ s/le\?/#le#/o or+ s/be\?//o;+ }+ print $_,"\n";+}++close STDOUT; # enforce flush
@@ -0,0 +1,352 @@+#!/usr/bin/env perl++# PowerPC assembler distiller by \@dot-asm.++################################################################+# Recognized "flavour"-s are:+#+# linux{32|64}[le] GNU assembler and ELF symbol decorations,+# with little-endian option+# linux64v2 GNU asssembler and big-endian instantiation+# of latest ELF specification+# aix{32|64} AIX assembler and symbol decorations+# osx{32|64} Mac OS X assembler and symbol decoratons++my $flavour = shift;+my $output = shift;+open STDOUT,">$output" || die "can't open $output: $!";++my %GLOBALS;+my %TYPES;+my $dotinlocallabels=($flavour=~/linux/)?1:0;++################################################################+# directives which need special treatment on different platforms+################################################################+my $type = sub {+ my ($dir,$name,$type) = @_;++ $TYPES{$name} = $type;+ if ($flavour =~ /linux/) {+ $name =~ s|^\.||;+ ".type $name,$type";+ } else {+ "";+ }+};+my $globl = sub {+ my $junk = shift;+ my $name = shift;+ my $global = \$GLOBALS{$name};+ my $type = \$TYPES{$name};+ my $ret;++ $name =~ s|^\.||;++ SWITCH: for ($flavour) {+ /aix/ && do { if (!$$type) {+ $$type = "\@function";+ }+ if ($$type =~ /function/) {+ $name = ".$name";+ }+ last;+ };+ /osx/ && do { $name = "_$name";+ last;+ };+ /linux.*(32|64(le|v2))/+ && do { $ret .= ".globl $name";+ if (!$$type) {+ $ret .= "\n.type $name,\@function";+ $$type = "\@function";+ }+ last;+ };+ /linux.*64/ && do { $ret .= ".globl $name";+ if (!$$type) {+ $ret .= "\n.type $name,\@function";+ $$type = "\@function";+ }+ if ($$type =~ /function/) {+ $ret .= "\n.section \".opd\",\"aw\"";+ $ret .= "\n.align 3";+ $ret .= "\n$name:";+ $ret .= "\n.quad .$name,.TOC.\@tocbase,0";+ $ret .= "\n.previous";+ $name = ".$name";+ }+ last;+ };+ }++ $ret = ".globl $name" if (!$ret);+ $$global = $name;+ $ret;+};+my $text = sub {+ my $ret = ($flavour =~ /aix/) ? ".csect\t.text[PR],7" : ".text";+ $ret = ".abiversion 2\n".$ret if ($flavour =~ /linux.*64(le|v2)/);+ $ret;+};+my $machine = sub {+ my $junk = shift;+ my $arch = shift;+ if ($flavour =~ /osx/)+ { $arch =~ s/\"//g;+ $arch = ($flavour=~/64/) ? "ppc970-64" : "ppc970" if ($arch eq "any");+ }+ ".machine $arch";+};+my $size = sub {+ if ($flavour =~ /linux/)+ { shift;+ my $name = shift;+ my $real = $GLOBALS{$name} ? \$GLOBALS{$name} : \$name;+ my $ret = ".size $$real,.-$$real";+ $name =~ s|^\.||;+ if ($$real ne $name) {+ $ret .= "\n.size $name,.-$$real";+ }+ $ret;+ }+ else+ { ""; }+};+my $asciz = sub {+ shift;+ my $line = join(",",@_);+ if ($line =~ /^"(.*)"$/)+ { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; }+ else+ { ""; }+};+my $quad = sub {+ shift;+ my @ret;+ my ($hi,$lo);+ for (@_) {+ if (/^0x([0-9a-f]*?)([0-9a-f]{1,8})$/io)+ { $hi=$1?"0x$1":"0"; $lo="0x$2"; }+ elsif (/^([0-9]+)$/o)+ { $hi=$1>>32; $lo=$1&0xffffffff; } # error-prone with 32-bit perl+ else+ { $hi=undef; $lo=$_; }++ if (defined($hi))+ { push(@ret,$flavour=~/le$/o?".long\t$lo,$hi":".long\t$hi,$lo"); }+ else+ { push(@ret,".quad $lo"); }+ }+ join("\n",@ret);+};++################################################################+# simplified mnemonics not handled by at least one assembler+################################################################+my $cmplw = sub {+ my $f = shift;+ my $cr = 0; $cr = shift if ($#_>1);+ # Some out-of-date 32-bit GNU assembler just can't handle cmplw...+ ($flavour =~ /linux.*32/) ?+ " .long ".sprintf "0x%x",31<<26|$cr<<23|$_[0]<<16|$_[1]<<11|64 :+ " cmplw ".join(',',$cr,@_);+};+my $bdnz = sub {+ my $f = shift;+ my $bo = $f=~/[\+\-]/ ? 16+9 : 16; # optional "to be taken" hint+ " bc $bo,0,".shift;+} if ($flavour!~/linux/);+my $bltlr = sub {+ my $f = shift;+ my $bo = $f=~/\-/ ? 12+2 : 12; # optional "not to be taken" hint+ ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints+ " .long ".sprintf "0x%x",19<<26|$bo<<21|16<<1 :+ " bclr $bo,0";+};+my $bnelr = sub {+ my $f = shift;+ my $bo = $f=~/\-/ ? 4+2 : 4; # optional "not to be taken" hint+ ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints+ " .long ".sprintf "0x%x",19<<26|$bo<<21|2<<16|16<<1 :+ " bclr $bo,2";+};+my $beqlr = sub {+ my $f = shift;+ my $bo = $f=~/-/ ? 12+2 : 12; # optional "not to be taken" hint+ ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints+ " .long ".sprintf "0x%X",19<<26|$bo<<21|2<<16|16<<1 :+ " bclr $bo,2";+};+# GNU assembler can't handle extrdi rA,rS,16,48, or when sum of last two+# arguments is 64, with "operand out of range" error.+my $extrdi = sub {+ my ($f,$ra,$rs,$n,$b) = @_;+ $b = ($b+$n)&63; $n = 64-$n;+ " rldicl $ra,$rs,$b,$n";+};+my $vmr = sub {+ my ($f,$vx,$vy) = @_;+ " vor $vx,$vy,$vy";+};++# Some ABIs specify vrsave, special-purpose register #256, as reserved+# for system use.+my $no_vrsave = ($flavour =~ /aix|linux64(le|v2)/);+my $mtspr = sub {+ my ($f,$idx,$ra) = @_;+ if ($idx == 256 && $no_vrsave) {+ " or $ra,$ra,$ra";+ } else {+ " mtspr $idx,$ra";+ }+};+my $mfspr = sub {+ my ($f,$rd,$idx) = @_;+ if ($idx == 256 && $no_vrsave) {+ " li $rd,-1";+ } else {+ " mfspr $rd,$idx";+ }+};++# PowerISA 2.06 stuff+sub vsxmem_op {+ my ($f, $vrt, $ra, $rb, $op) = @_;+ " .long ".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|($rb<<11)|($op*2+1);+}+# made-up unaligned memory reference AltiVec/VMX instructions+my $lvx_u = sub { vsxmem_op(@_, 844); }; # lxvd2x+my $stvx_u = sub { vsxmem_op(@_, 972); }; # stxvd2x+my $lvdx_u = sub { vsxmem_op(@_, 588); }; # lxsdx+my $stvdx_u = sub { vsxmem_op(@_, 716); }; # stxsdx+my $lvx_4w = sub { vsxmem_op(@_, 780); }; # lxvw4x+my $stvx_4w = sub { vsxmem_op(@_, 908); }; # stxvw4x+my $lvx_splt = sub { vsxmem_op(@_, 332); }; # lxvdsx+# VSX instruction[s] masqueraded as made-up AltiVec/VMX+my $vpermdi = sub { # xxpermdi+ my ($f, $vrt, $vra, $vrb, $dm) = @_;+ $dm = oct($dm) if ($dm =~ /^0/);+ " .long ".sprintf "0x%X",(60<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|($dm<<8)|(10<<3)|7;+};++# PowerISA 2.07 stuff+sub vcrypto_op {+ my ($f, $vrt, $vra, $vrb, $op) = @_;+ " .long ".sprintf "0x%X",(4<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|$op;+}+sub vfour {+ my ($f, $vrt, $vra, $vrb, $vrc, $op) = @_;+ " .long ".sprintf "0x%X",(4<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|($vrc<<6)|$op;+};+my $vcipher = sub { vcrypto_op(@_, 1288); };+my $vcipherlast = sub { vcrypto_op(@_, 1289); };+my $vncipher = sub { vcrypto_op(@_, 1352); };+my $vncipherlast= sub { vcrypto_op(@_, 1353); };+my $vsbox = sub { vcrypto_op(@_, 0, 1480); };+my $vshasigmad = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1730); };+my $vshasigmaw = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1666); };+my $vpmsumb = sub { vcrypto_op(@_, 1032); };+my $vpmsumd = sub { vcrypto_op(@_, 1224); };+my $vpmsubh = sub { vcrypto_op(@_, 1096); };+my $vpmsumw = sub { vcrypto_op(@_, 1160); };+# These are not really crypto, but vcrypto_op template works+my $vaddudm = sub { vcrypto_op(@_, 192); };+my $vadduqm = sub { vcrypto_op(@_, 256); };+my $vmuleuw = sub { vcrypto_op(@_, 648); };+my $vmulouw = sub { vcrypto_op(@_, 136); };+my $vrld = sub { vcrypto_op(@_, 196); };+my $vsld = sub { vcrypto_op(@_, 1476); };+my $vsrd = sub { vcrypto_op(@_, 1732); };+my $vsubudm = sub { vcrypto_op(@_, 1216); };+my $vaddcuq = sub { vcrypto_op(@_, 320); };+my $vaddeuqm = sub { vfour(@_,60); };+my $vaddecuq = sub { vfour(@_,61); };+my $vmrgew = sub { vfour(@_,0,1932); };+my $vmrgow = sub { vfour(@_,0,1676); };++my $mtsle = sub {+ my ($f, $arg) = @_;+ " .long ".sprintf "0x%X",(31<<26)|($arg<<21)|(147*2);+};++# VSX instructions masqueraded as AltiVec/VMX+my $mtvrd = sub {+ my ($f, $vrt, $ra) = @_;+ " .long ".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|(179<<1)|1;+};+my $mtvrwz = sub {+ my ($f, $vrt, $ra) = @_;+ " .long ".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|(243<<1)|1;+};+my $lvwzx_u = sub { vsxmem_op(@_, 12); }; # lxsiwzx+my $stvwx_u = sub { vsxmem_op(@_, 140); }; # stxsiwx++# PowerISA 3.0 stuff+my $maddhdu = sub { vfour(@_,49); };+my $maddld = sub { vfour(@_,51); };+my $darn = sub {+ my ($f, $rt, $l) = @_;+ " .long ".sprintf "0x%X",(31<<26)|($rt<<21)|($l<<16)|(755<<1);+};+my $iseleq = sub {+ my ($f, $rt, $ra, $rb) = @_;+ " .long ".sprintf "0x%X",(31<<26)|($rt<<21)|($ra<<16)|($rb<<11)|(2<<6)|30;+};+# VSX instruction[s] masqueraded as made-up AltiVec/VMX+my $vspltib = sub { # xxspltib+ my ($f, $vrt, $imm8) = @_;+ $imm8 = oct($imm8) if ($imm8 =~ /^0/);+ $imm8 &= 0xff;+ " .long ".sprintf "0x%X",(60<<26)|($vrt<<21)|($imm8<<11)|(360<<1)|1;+};++# PowerISA 3.0B stuff+my $addex = sub {+ my ($f, $rt, $ra, $rb, $cy) = @_; # only cy==0 is specified in 3.0B+ " .long ".sprintf "0x%X",(31<<26)|($rt<<21)|($ra<<16)|($rb<<11)|($cy<<9)|(170<<1);+};+my $vmsumudm = sub { vfour(@_,35); };++while($line=<>) {++ $line =~ s|[#!;].*$||; # get rid of asm-style comments...+ $line =~ s|/\*.*\*/||; # ... and C-style comments...+ $line =~ s|^\s+||; # ... and skip white spaces in beginning...+ $line =~ s|\s+$||; # ... and at the end++ {+ $line =~ s|\.L(\w+)|L$1|g; # common denominator for Locallabel+ $line =~ s|\bL(\w+)|\.L$1|g if ($dotinlocallabels);+ }++ {+ $line =~ s|(^[\.\w]+)\:\s*||;+ my $label = $1;+ if ($label) {+ my $xlated = ($GLOBALS{$label} or $label);+ print "$xlated:";+ if ($flavour =~ /linux.*64(le|v2)/) {+ if ($TYPES{$label} =~ /function/) {+ printf "\n.localentry %s,0\n",$xlated;+ }+ }+ }+ }++ {+ $line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||;+ my $c = $1; $c = "\t" if ($c eq "");+ my $mnemonic = $2;+ my $f = $3;+ my $opcode = eval("\$$mnemonic");+ $line =~ s/\b(c?[rf]|v|vs)([0-9]+)\b/$2/g if ($c ne "." and $flavour !~ /osx/);+ if (ref($opcode) eq 'CODE') { $line = &$opcode($f,split(/,\s*/,$line)); }+ elsif ($mnemonic) { $line = $c.$mnemonic.$f."\t".$line; }+ }++ print $line if ($line);+ print "\n";+}++close STDOUT;
@@ -0,0 +1,21 @@+Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>++Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
@@ -0,0 +1,57 @@+# BearSSL++Constant-time AES and GHASH from [BearSSL](https://bearssl.org/), vendored+here. `VERSION` holds the upstream release these files came from, and+`import.sh` fetches them again.++## Why++crypton's portable AES and GHASH are table-driven, and both index their+tables with a secret: `cbits/aes/generic.c` with a byte of the state, in+every round and in the key expansion, and `cbits/aes/gf.c` with a nibble of+the GHASH accumulator. Both are variable-time by construction, and the+cache-timing attacks on that shape of code are old and well documented.++The processors that have AES instructions do not run any of it -- crypton+asks them first. What runs it is everything else: ppc64le and s390x, where+the instructions exist but crypton has no path to them; 32-bit ARM, where+the same is true; riscv64 and loongarch64; and the boards that genuinely+have no AES instructions at all, of which the Raspberry Pi 3 and 4 are by+some distance the largest population.++BearSSL's answer is bitslicing. `aes_ct64` holds four blocks interleaved+across eight 64-bit words and computes the S-box as boolean algebra, so+there is no table and no address derived from a secret; `ghash_ctmul64`+builds the GF(2^128) multiply out of shifts, masks and integer multiplies+rather than a table of H. Both are plain C99 and assume nothing beyond+`uint64_t`.++## What is here++| file | from |+| --- | --- |+| `aes_ct64.c` | `src/symcipher/aes_ct64.c` |+| `aes_ct64_enc.c` | `src/symcipher/aes_ct64_enc.c` |+| `aes_ct64_dec.c` | `src/symcipher/aes_ct64_dec.c` |+| `ghash_ctmul64.c` | `src/hash/ghash_ctmul64.c` |+| `dec32le.c` | `src/codec/dec32le.c`, for `br_range_dec32le` |+| `LICENSE` | `LICENSE.txt` -- MIT, (c) 2016 Thomas Pornin |++`inner.h` is **crypton's, not upstream's**. Each of those five opens with+`#include "inner.h"`, and upstream's is some two thousand lines declaring+the whole library; these five want six things from it. So this one gives+those six and nothing else, which is what lets the five stay byte for byte+what upstream ships. `import.sh` does not overwrite it.++The byte-order helpers in it are written rather than copied, in their plain+portable form without upstream's unaligned-access fast paths, so that no+platform configuration comes with them.++## Keeping it honest++`cbits/tests/bearssl_diff.c` checks this against the implementation it+replaces: the FIPS-197 vectors first, so that agreement means AES and not+merely that both sides compute the same wrong thing, then a run of random+keys and blocks, then GHASH against the 4-bit table. Given any argument it+corrupts three results on purpose and the comparison has to notice -- a+differential test that cannot fail has said nothing.
@@ -0,0 +1,1 @@+0.6
@@ -0,0 +1,398 @@+/*+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>+ *+ * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the+ * "Software"), to deal in the Software without restriction, including+ * without limitation the rights to use, copy, modify, merge, publish,+ * distribute, sublicense, and/or sell copies of the Software, and to+ * permit persons to whom the Software is furnished to do so, subject to+ * the following conditions:+ *+ * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include "inner.h"++/* see inner.h */+void+br_aes_ct64_bitslice_Sbox(uint64_t *q)+{+ /*+ * This S-box implementation is a straightforward translation of+ * the circuit described by Boyar and Peralta in "A new+ * combinational logic minimization technique with applications+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).+ *+ * Note that variables x* (input) and s* (output) are numbered+ * in "reverse" order (x0 is the high bit, x7 is the low bit).+ */++ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;+ uint64_t y20, y21;+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;++ x0 = q[7];+ x1 = q[6];+ x2 = q[5];+ x3 = q[4];+ x4 = q[3];+ x5 = q[2];+ x6 = q[1];+ x7 = q[0];++ /*+ * Top linear transformation.+ */+ y14 = x3 ^ x5;+ y13 = x0 ^ x6;+ y9 = x0 ^ x3;+ y8 = x0 ^ x5;+ t0 = x1 ^ x2;+ y1 = t0 ^ x7;+ y4 = y1 ^ x3;+ y12 = y13 ^ y14;+ y2 = y1 ^ x0;+ y5 = y1 ^ x6;+ y3 = y5 ^ y8;+ t1 = x4 ^ y12;+ y15 = t1 ^ x5;+ y20 = t1 ^ x1;+ y6 = y15 ^ x7;+ y10 = y15 ^ t0;+ y11 = y20 ^ y9;+ y7 = x7 ^ y11;+ y17 = y10 ^ y11;+ y19 = y10 ^ y8;+ y16 = t0 ^ y11;+ y21 = y13 ^ y16;+ y18 = x0 ^ y16;++ /*+ * Non-linear section.+ */+ t2 = y12 & y15;+ t3 = y3 & y6;+ t4 = t3 ^ t2;+ t5 = y4 & x7;+ t6 = t5 ^ t2;+ t7 = y13 & y16;+ t8 = y5 & y1;+ t9 = t8 ^ t7;+ t10 = y2 & y7;+ t11 = t10 ^ t7;+ t12 = y9 & y11;+ t13 = y14 & y17;+ t14 = t13 ^ t12;+ t15 = y8 & y10;+ t16 = t15 ^ t12;+ t17 = t4 ^ t14;+ t18 = t6 ^ t16;+ t19 = t9 ^ t14;+ t20 = t11 ^ t16;+ t21 = t17 ^ y20;+ t22 = t18 ^ y19;+ t23 = t19 ^ y21;+ t24 = t20 ^ y18;++ t25 = t21 ^ t22;+ t26 = t21 & t23;+ t27 = t24 ^ t26;+ t28 = t25 & t27;+ t29 = t28 ^ t22;+ t30 = t23 ^ t24;+ t31 = t22 ^ t26;+ t32 = t31 & t30;+ t33 = t32 ^ t24;+ t34 = t23 ^ t33;+ t35 = t27 ^ t33;+ t36 = t24 & t35;+ t37 = t36 ^ t34;+ t38 = t27 ^ t36;+ t39 = t29 & t38;+ t40 = t25 ^ t39;++ t41 = t40 ^ t37;+ t42 = t29 ^ t33;+ t43 = t29 ^ t40;+ t44 = t33 ^ t37;+ t45 = t42 ^ t41;+ z0 = t44 & y15;+ z1 = t37 & y6;+ z2 = t33 & x7;+ z3 = t43 & y16;+ z4 = t40 & y1;+ z5 = t29 & y7;+ z6 = t42 & y11;+ z7 = t45 & y17;+ z8 = t41 & y10;+ z9 = t44 & y12;+ z10 = t37 & y3;+ z11 = t33 & y4;+ z12 = t43 & y13;+ z13 = t40 & y5;+ z14 = t29 & y2;+ z15 = t42 & y9;+ z16 = t45 & y14;+ z17 = t41 & y8;++ /*+ * Bottom linear transformation.+ */+ t46 = z15 ^ z16;+ t47 = z10 ^ z11;+ t48 = z5 ^ z13;+ t49 = z9 ^ z10;+ t50 = z2 ^ z12;+ t51 = z2 ^ z5;+ t52 = z7 ^ z8;+ t53 = z0 ^ z3;+ t54 = z6 ^ z7;+ t55 = z16 ^ z17;+ t56 = z12 ^ t48;+ t57 = t50 ^ t53;+ t58 = z4 ^ t46;+ t59 = z3 ^ t54;+ t60 = t46 ^ t57;+ t61 = z14 ^ t57;+ t62 = t52 ^ t58;+ t63 = t49 ^ t58;+ t64 = z4 ^ t59;+ t65 = t61 ^ t62;+ t66 = z1 ^ t63;+ s0 = t59 ^ t63;+ s6 = t56 ^ ~t62;+ s7 = t48 ^ ~t60;+ t67 = t64 ^ t65;+ s3 = t53 ^ t66;+ s4 = t51 ^ t66;+ s5 = t47 ^ t65;+ s1 = t64 ^ ~s3;+ s2 = t55 ^ ~t67;++ q[7] = s0;+ q[6] = s1;+ q[5] = s2;+ q[4] = s3;+ q[3] = s4;+ q[2] = s5;+ q[1] = s6;+ q[0] = s7;+}++/* see inner.h */+void+br_aes_ct64_ortho(uint64_t *q)+{+#define SWAPN(cl, ch, s, x, y) do { \+ uint64_t a, b; \+ a = (x); \+ b = (y); \+ (x) = (a & (uint64_t)cl) | ((b & (uint64_t)cl) << (s)); \+ (y) = ((a & (uint64_t)ch) >> (s)) | (b & (uint64_t)ch); \+ } while (0)++#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)++ SWAP2(q[0], q[1]);+ SWAP2(q[2], q[3]);+ SWAP2(q[4], q[5]);+ SWAP2(q[6], q[7]);++ SWAP4(q[0], q[2]);+ SWAP4(q[1], q[3]);+ SWAP4(q[4], q[6]);+ SWAP4(q[5], q[7]);++ SWAP8(q[0], q[4]);+ SWAP8(q[1], q[5]);+ SWAP8(q[2], q[6]);+ SWAP8(q[3], q[7]);+}++/* see inner.h */+void+br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w)+{+ uint64_t x0, x1, x2, x3;++ x0 = w[0];+ x1 = w[1];+ x2 = w[2];+ x3 = w[3];+ x0 |= (x0 << 16);+ x1 |= (x1 << 16);+ x2 |= (x2 << 16);+ x3 |= (x3 << 16);+ x0 &= (uint64_t)0x0000FFFF0000FFFF;+ x1 &= (uint64_t)0x0000FFFF0000FFFF;+ x2 &= (uint64_t)0x0000FFFF0000FFFF;+ x3 &= (uint64_t)0x0000FFFF0000FFFF;+ x0 |= (x0 << 8);+ x1 |= (x1 << 8);+ x2 |= (x2 << 8);+ x3 |= (x3 << 8);+ x0 &= (uint64_t)0x00FF00FF00FF00FF;+ x1 &= (uint64_t)0x00FF00FF00FF00FF;+ x2 &= (uint64_t)0x00FF00FF00FF00FF;+ x3 &= (uint64_t)0x00FF00FF00FF00FF;+ *q0 = x0 | (x2 << 8);+ *q1 = x1 | (x3 << 8);+}++/* see inner.h */+void+br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1)+{+ uint64_t x0, x1, x2, x3;++ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;+ x0 |= (x0 >> 8);+ x1 |= (x1 >> 8);+ x2 |= (x2 >> 8);+ x3 |= (x3 >> 8);+ x0 &= (uint64_t)0x0000FFFF0000FFFF;+ x1 &= (uint64_t)0x0000FFFF0000FFFF;+ x2 &= (uint64_t)0x0000FFFF0000FFFF;+ x3 &= (uint64_t)0x0000FFFF0000FFFF;+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);+}++static const unsigned char Rcon[] = {+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36+};++static uint32_t+sub_word(uint32_t x)+{+ uint64_t q[8];++ memset(q, 0, sizeof q);+ q[0] = x;+ br_aes_ct64_ortho(q);+ br_aes_ct64_bitslice_Sbox(q);+ br_aes_ct64_ortho(q);+ return (uint32_t)q[0];+}++/* see inner.h */+unsigned+br_aes_ct64_keysched(uint64_t *comp_skey, const void *key, size_t key_len)+{+ unsigned num_rounds;+ int i, j, k, nk, nkf;+ uint32_t tmp;+ uint32_t skey[60];++ switch (key_len) {+ case 16:+ num_rounds = 10;+ break;+ case 24:+ num_rounds = 12;+ break;+ case 32:+ num_rounds = 14;+ break;+ default:+ /* abort(); */+ return 0;+ }+ nk = (int)(key_len >> 2);+ nkf = (int)((num_rounds + 1) << 2);+ br_range_dec32le(skey, (key_len >> 2), key);+ tmp = skey[(key_len >> 2) - 1];+ for (i = nk, j = 0, k = 0; i < nkf; i ++) {+ if (j == 0) {+ tmp = (tmp << 24) | (tmp >> 8);+ tmp = sub_word(tmp) ^ Rcon[k];+ } else if (nk > 6 && j == 4) {+ tmp = sub_word(tmp);+ }+ tmp ^= skey[i - nk];+ skey[i] = tmp;+ if (++ j == nk) {+ j = 0;+ k ++;+ }+ }++ for (i = 0, j = 0; i < nkf; i += 4, j += 2) {+ uint64_t q[8];++ br_aes_ct64_interleave_in(&q[0], &q[4], skey + i);+ q[1] = q[0];+ q[2] = q[0];+ q[3] = q[0];+ q[5] = q[4];+ q[6] = q[4];+ q[7] = q[4];+ br_aes_ct64_ortho(q);+ comp_skey[j + 0] =+ (q[0] & (uint64_t)0x1111111111111111)+ | (q[1] & (uint64_t)0x2222222222222222)+ | (q[2] & (uint64_t)0x4444444444444444)+ | (q[3] & (uint64_t)0x8888888888888888);+ comp_skey[j + 1] =+ (q[4] & (uint64_t)0x1111111111111111)+ | (q[5] & (uint64_t)0x2222222222222222)+ | (q[6] & (uint64_t)0x4444444444444444)+ | (q[7] & (uint64_t)0x8888888888888888);+ }+ return num_rounds;+}++/* see inner.h */+void+br_aes_ct64_skey_expand(uint64_t *skey,+ unsigned num_rounds, const uint64_t *comp_skey)+{+ unsigned u, v, n;++ n = (num_rounds + 1) << 1;+ for (u = 0, v = 0; u < n; u ++, v += 4) {+ uint64_t x0, x1, x2, x3;++ x0 = x1 = x2 = x3 = comp_skey[u];+ x0 &= (uint64_t)0x1111111111111111;+ x1 &= (uint64_t)0x2222222222222222;+ x2 &= (uint64_t)0x4444444444444444;+ x3 &= (uint64_t)0x8888888888888888;+ x1 >>= 1;+ x2 >>= 2;+ x3 >>= 3;+ skey[v + 0] = (x0 << 4) - x0;+ skey[v + 1] = (x1 << 4) - x1;+ skey[v + 2] = (x2 << 4) - x2;+ skey[v + 3] = (x3 << 4) - x3;+ }+}
@@ -0,0 +1,159 @@+/*+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>+ *+ * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the+ * "Software"), to deal in the Software without restriction, including+ * without limitation the rights to use, copy, modify, merge, publish,+ * distribute, sublicense, and/or sell copies of the Software, and to+ * permit persons to whom the Software is furnished to do so, subject to+ * the following conditions:+ *+ * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include "inner.h"++/* see inner.h */+void+br_aes_ct64_bitslice_invSbox(uint64_t *q)+{+ /*+ * See br_aes_ct_bitslice_invSbox(). This is the natural extension+ * to 64-bit registers.+ */+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;++ q0 = ~q[0];+ q1 = ~q[1];+ q2 = q[2];+ q3 = q[3];+ q4 = q[4];+ q5 = ~q[5];+ q6 = ~q[6];+ q7 = q[7];+ q[7] = q1 ^ q4 ^ q6;+ q[6] = q0 ^ q3 ^ q5;+ q[5] = q7 ^ q2 ^ q4;+ q[4] = q6 ^ q1 ^ q3;+ q[3] = q5 ^ q0 ^ q2;+ q[2] = q4 ^ q7 ^ q1;+ q[1] = q3 ^ q6 ^ q0;+ q[0] = q2 ^ q5 ^ q7;++ br_aes_ct64_bitslice_Sbox(q);++ q0 = ~q[0];+ q1 = ~q[1];+ q2 = q[2];+ q3 = q[3];+ q4 = q[4];+ q5 = ~q[5];+ q6 = ~q[6];+ q7 = q[7];+ q[7] = q1 ^ q4 ^ q6;+ q[6] = q0 ^ q3 ^ q5;+ q[5] = q7 ^ q2 ^ q4;+ q[4] = q6 ^ q1 ^ q3;+ q[3] = q5 ^ q0 ^ q2;+ q[2] = q4 ^ q7 ^ q1;+ q[1] = q3 ^ q6 ^ q0;+ q[0] = q2 ^ q5 ^ q7;+}++static void+add_round_key(uint64_t *q, const uint64_t *sk)+{+ int i;++ for (i = 0; i < 8; i ++) {+ q[i] ^= sk[i];+ }+}++static void+inv_shift_rows(uint64_t *q)+{+ int i;++ for (i = 0; i < 8; i ++) {+ uint64_t x;++ x = q[i];+ q[i] = (x & (uint64_t)0x000000000000FFFF)+ | ((x & (uint64_t)0x000000000FFF0000) << 4)+ | ((x & (uint64_t)0x00000000F0000000) >> 12)+ | ((x & (uint64_t)0x000000FF00000000) << 8)+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)+ | ((x & (uint64_t)0x000F000000000000) << 12)+ | ((x & (uint64_t)0xFFF0000000000000) >> 4);+ }+}++static inline uint64_t+rotr32(uint64_t x)+{+ return (x << 32) | (x >> 32);+}++static void+inv_mix_columns(uint64_t *q)+{+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;++ q0 = q[0];+ q1 = q[1];+ q2 = q[2];+ q3 = q[3];+ q4 = q[4];+ q5 = q[5];+ q6 = q[6];+ q7 = q[7];+ r0 = (q0 >> 16) | (q0 << 48);+ r1 = (q1 >> 16) | (q1 << 48);+ r2 = (q2 >> 16) | (q2 << 48);+ r3 = (q3 >> 16) | (q3 << 48);+ r4 = (q4 >> 16) | (q4 << 48);+ r5 = (q5 >> 16) | (q5 << 48);+ r6 = (q6 >> 16) | (q6 << 48);+ r7 = (q7 >> 16) | (q7 << 48);++ q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ rotr32(q0 ^ q5 ^ q6 ^ r0 ^ r5);+ q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ rotr32(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6);+ q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ rotr32(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7);+ q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ rotr32(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7);+ q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr32(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6);+ q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr32(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7);+ q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ rotr32(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7);+ q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ rotr32(q4 ^ q5 ^ q7 ^ r4 ^ r7);+}++/* see inner.h */+void+br_aes_ct64_bitslice_decrypt(unsigned num_rounds,+ const uint64_t *skey, uint64_t *q)+{+ unsigned u;++ add_round_key(q, skey + (num_rounds << 3));+ for (u = num_rounds - 1; u > 0; u --) {+ inv_shift_rows(q);+ br_aes_ct64_bitslice_invSbox(q);+ add_round_key(q, skey + (u << 3));+ inv_mix_columns(q);+ }+ inv_shift_rows(q);+ br_aes_ct64_bitslice_invSbox(q);+ add_round_key(q, skey);+}
@@ -0,0 +1,115 @@+/*+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>+ *+ * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the+ * "Software"), to deal in the Software without restriction, including+ * without limitation the rights to use, copy, modify, merge, publish,+ * distribute, sublicense, and/or sell copies of the Software, and to+ * permit persons to whom the Software is furnished to do so, subject to+ * the following conditions:+ *+ * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include "inner.h"++static inline void+add_round_key(uint64_t *q, const uint64_t *sk)+{+ q[0] ^= sk[0];+ q[1] ^= sk[1];+ q[2] ^= sk[2];+ q[3] ^= sk[3];+ q[4] ^= sk[4];+ q[5] ^= sk[5];+ q[6] ^= sk[6];+ q[7] ^= sk[7];+}++static inline void+shift_rows(uint64_t *q)+{+ int i;++ for (i = 0; i < 8; i ++) {+ uint64_t x;++ x = q[i];+ q[i] = (x & (uint64_t)0x000000000000FFFF)+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)+ | ((x & (uint64_t)0x00000000000F0000) << 12)+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)+ | ((x & (uint64_t)0x000000FF00000000) << 8)+ | ((x & (uint64_t)0xF000000000000000) >> 12)+ | ((x & (uint64_t)0x0FFF000000000000) << 4);+ }+}++static inline uint64_t+rotr32(uint64_t x)+{+ return (x << 32) | (x >> 32);+}++static inline void+mix_columns(uint64_t *q)+{+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;++ q0 = q[0];+ q1 = q[1];+ q2 = q[2];+ q3 = q[3];+ q4 = q[4];+ q5 = q[5];+ q6 = q[6];+ q7 = q[7];+ r0 = (q0 >> 16) | (q0 << 48);+ r1 = (q1 >> 16) | (q1 << 48);+ r2 = (q2 >> 16) | (q2 << 48);+ r3 = (q3 >> 16) | (q3 << 48);+ r4 = (q4 >> 16) | (q4 << 48);+ r5 = (q5 >> 16) | (q5 << 48);+ r6 = (q6 >> 16) | (q6 << 48);+ r7 = (q7 >> 16) | (q7 << 48);++ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);+}++/* see inner.h */+void+br_aes_ct64_bitslice_encrypt(unsigned num_rounds,+ const uint64_t *skey, uint64_t *q)+{+ unsigned u;++ add_round_key(q, skey);+ for (u = 1; u < num_rounds; u ++) {+ br_aes_ct64_bitslice_Sbox(q);+ shift_rows(q);+ mix_columns(q);+ add_round_key(q, skey + (u << 3));+ }+ br_aes_ct64_bitslice_Sbox(q);+ shift_rows(q);+ add_round_key(q, skey + (num_rounds << 3));+}
@@ -0,0 +1,38 @@+/*+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>+ *+ * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the+ * "Software"), to deal in the Software without restriction, including+ * without limitation the rights to use, copy, modify, merge, publish,+ * distribute, sublicense, and/or sell copies of the Software, and to+ * permit persons to whom the Software is furnished to do so, subject to+ * the following conditions:+ *+ * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include "inner.h"++/* see inner.h */+void+br_range_dec32le(uint32_t *v, size_t num, const void *src)+{+ const unsigned char *buf;++ buf = src;+ while (num -- > 0) {+ *v ++ = br_dec32le(buf);+ buf += 4;+ }+}
@@ -0,0 +1,154 @@+/*+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>+ *+ * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the+ * "Software"), to deal in the Software without restriction, including+ * without limitation the rights to use, copy, modify, merge, publish,+ * distribute, sublicense, and/or sell copies of the Software, and to+ * permit persons to whom the Software is furnished to do so, subject to+ * the following conditions:+ *+ * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#include "inner.h"++/*+ * This is the 64-bit variant of br_ghash_ctmul32(), with 64-bit operands+ * and bit reversal of 64-bit words.+ */++static inline uint64_t+bmul64(uint64_t x, uint64_t y)+{+ uint64_t x0, x1, x2, x3;+ uint64_t y0, y1, y2, y3;+ uint64_t z0, z1, z2, z3;++ x0 = x & (uint64_t)0x1111111111111111;+ x1 = x & (uint64_t)0x2222222222222222;+ x2 = x & (uint64_t)0x4444444444444444;+ x3 = x & (uint64_t)0x8888888888888888;+ y0 = y & (uint64_t)0x1111111111111111;+ y1 = y & (uint64_t)0x2222222222222222;+ y2 = y & (uint64_t)0x4444444444444444;+ y3 = y & (uint64_t)0x8888888888888888;+ z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);+ z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);+ z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);+ z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);+ z0 &= (uint64_t)0x1111111111111111;+ z1 &= (uint64_t)0x2222222222222222;+ z2 &= (uint64_t)0x4444444444444444;+ z3 &= (uint64_t)0x8888888888888888;+ return z0 | z1 | z2 | z3;+}++static uint64_t+rev64(uint64_t x)+{+#define RMS(m, s) do { \+ x = ((x & (uint64_t)(m)) << (s)) \+ | ((x >> (s)) & (uint64_t)(m)); \+ } while (0)++ RMS(0x5555555555555555, 1);+ RMS(0x3333333333333333, 2);+ RMS(0x0F0F0F0F0F0F0F0F, 4);+ RMS(0x00FF00FF00FF00FF, 8);+ RMS(0x0000FFFF0000FFFF, 16);+ return (x << 32) | (x >> 32);++#undef RMS+}++/* see bearssl_ghash.h */+void+br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len)+{+ const unsigned char *buf, *hb;+ unsigned char *yb;+ uint64_t y0, y1;+ uint64_t h0, h1, h2, h0r, h1r, h2r;++ buf = data;+ yb = y;+ hb = h;+ y1 = br_dec64be(yb);+ y0 = br_dec64be(yb + 8);+ h1 = br_dec64be(hb);+ h0 = br_dec64be(hb + 8);+ h0r = rev64(h0);+ h1r = rev64(h1);+ h2 = h0 ^ h1;+ h2r = h0r ^ h1r;+ while (len > 0) {+ const unsigned char *src;+ unsigned char tmp[16];+ uint64_t y0r, y1r, y2, y2r;+ uint64_t z0, z1, z2, z0h, z1h, z2h;+ uint64_t v0, v1, v2, v3;++ if (len >= 16) {+ src = buf;+ buf += 16;+ len -= 16;+ } else {+ memcpy(tmp, buf, len);+ memset(tmp + len, 0, (sizeof tmp) - len);+ src = tmp;+ len = 0;+ }+ y1 ^= br_dec64be(src);+ y0 ^= br_dec64be(src + 8);++ y0r = rev64(y0);+ y1r = rev64(y1);+ y2 = y0 ^ y1;+ y2r = y0r ^ y1r;++ z0 = bmul64(y0, h0);+ z1 = bmul64(y1, h1);+ z2 = bmul64(y2, h2);+ z0h = bmul64(y0r, h0r);+ z1h = bmul64(y1r, h1r);+ z2h = bmul64(y2r, h2r);+ z2 ^= z0 ^ z1;+ z2h ^= z0h ^ z1h;+ z0h = rev64(z0h) >> 1;+ z1h = rev64(z1h) >> 1;+ z2h = rev64(z2h) >> 1;++ v0 = z0;+ v1 = z0h ^ z2;+ v2 = z1 ^ z2h;+ v3 = z1h;++ v3 = (v3 << 1) | (v2 >> 63);+ v2 = (v2 << 1) | (v1 >> 63);+ v1 = (v1 << 1) | (v0 >> 63);+ v0 = (v0 << 1);++ v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);+ v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);+ v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);+ v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);++ y0 = v2;+ y1 = v3;+ }++ br_enc64be(yb, y1);+ br_enc64be(yb + 8, y0);+}
@@ -0,0 +1,34 @@+#!/bin/sh+# Re-import the vendored parts of BearSSL.+#+# Only the five files crypton calls are kept, and they are kept unmodified,+# so that `diff` against a new release is readable. What they want from+# upstream's two-thousand-line src/inner.h is supplied by the inner.h here,+# which is crypton's and is NOT overwritten by this script. Run this from+# cbits/bearssl:+#+# ./import.sh [version]+#+# and commit the result together with the VERSION line it writes, so that+# the tree always says which upstream release it holds.+set -eu++VER=${1:-0.6}+HERE=$(cd "$(dirname "$0")" && pwd)+TMP=$(mktemp -d)+trap 'rm -rf "$TMP"' EXIT++curl -sSL "https://bearssl.org/bearssl-$VER.tar.gz" -o "$TMP/b.tgz"+tar xzf "$TMP/b.tgz" -C "$TMP"+SRC="$TMP/bearssl-$VER"++cp "$SRC/LICENSE.txt" "$HERE/LICENSE"+cp "$SRC/src/symcipher/aes_ct64.c" "$HERE/"+cp "$SRC/src/symcipher/aes_ct64_enc.c" "$HERE/"+cp "$SRC/src/symcipher/aes_ct64_dec.c" "$HERE/"+cp "$SRC/src/hash/ghash_ctmul64.c" "$HERE/"+cp "$SRC/src/codec/dec32le.c" "$HERE/"+echo "$VER" > "$HERE/VERSION"++echo "imported BearSSL $VER"+echo "now run the differential test in cbits/tests/bearssl_diff.c"
@@ -0,0 +1,92 @@+/*+ * Stands in for BearSSL's own src/inner.h.+ *+ * The five .c files beside this one are upstream's, byte for byte, and each+ * of them opens with #include "inner.h". Upstream's is some two thousand+ * lines and declares the whole library; these five want six things from it.+ * So this header gives those six and nothing else, and the upstream files+ * stay unmodified -- which is what makes `diff` against a new BearSSL+ * release readable. See README.md.+ *+ * The byte-order helpers are written here rather than copied, in their plain+ * portable form without upstream's unaligned-access fast paths, so that they+ * carry no platform configuration with them. cbits/tests/bearssl_diff.c+ * checks the whole thing against crypton's existing implementation.+ */+#ifndef CRYPTON_BEARSSL_INNER_H+#define CRYPTON_BEARSSL_INNER_H++#include <stddef.h>+#include <stdint.h>+#include <string.h>++static inline uint32_t+br_dec32le(const void *src)+{+ const unsigned char *b = src;++ return (uint32_t)b[0]+ | ((uint32_t)b[1] << 8)+ | ((uint32_t)b[2] << 16)+ | ((uint32_t)b[3] << 24);+}++static inline void+br_enc32le(void *dst, uint32_t x)+{+ unsigned char *b = dst;++ b[0] = (unsigned char)x;+ b[1] = (unsigned char)(x >> 8);+ b[2] = (unsigned char)(x >> 16);+ b[3] = (unsigned char)(x >> 24);+}++static inline uint64_t+br_dec64be(const void *src)+{+ const unsigned char *b = src;+ uint64_t x = 0;+ int i;++ for (i = 0; i < 8; i++)+ x = (x << 8) | (uint64_t)b[i];+ return x;+}++static inline void+br_enc64be(void *dst, uint64_t x)+{+ unsigned char *b = dst;+ int i;++ for (i = 7; i >= 0; i--) {+ b[i] = (unsigned char)(x & 0xff);+ x >>= 8;+ }+}++/* dec32le.c */+void br_range_dec32le(uint32_t *v, size_t num, const void *src);++/* aes_ct64.c */+void br_aes_ct64_bitslice_Sbox(uint64_t *q);+void br_aes_ct64_ortho(uint64_t *q);+void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w);+void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1);+unsigned br_aes_ct64_keysched(uint64_t *comp_skey, const void *key,+ size_t key_len);+void br_aes_ct64_skey_expand(uint64_t *skey, unsigned num_rounds,+ const uint64_t *comp_skey);++/* aes_ct64_enc.c, aes_ct64_dec.c */+void br_aes_ct64_bitslice_encrypt(unsigned num_rounds, const uint64_t *skey,+ uint64_t *q);+void br_aes_ct64_bitslice_invSbox(uint64_t *q);+void br_aes_ct64_bitslice_decrypt(unsigned num_rounds, const uint64_t *skey,+ uint64_t *q);++/* ghash_ctmul64.c */+void br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len);++#endif
@@ -38,6 +38,12 @@ #include <aes/generic.h> #include <aes/gf.h> #include <aes/x86ni.h>+#ifdef WITH_PPC8_CRYPTO+#include <aes/ppc8.h>+#endif+#ifdef WITH_GCM_FUSED+#include <aes/gcm_fused_x86.h>+#endif void crypton_aes_generic_encrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks); void crypton_aes_generic_decrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks);@@ -51,6 +57,8 @@ uint32_t spoint, aes_block *input, uint32_t nb_blocks); void crypton_aes_generic_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length); void crypton_aes_generic_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length);+void crypton_aes_bitsliced_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length);+void crypton_aes_bitsliced_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length); void crypton_aes_generic_ocb_encrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length); void crypton_aes_generic_ocb_decrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length); void crypton_aes_generic_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length);@@ -58,6 +66,18 @@ #ifdef WITH_ARMV8_CRYPTO void crypton_aes_armv8_init(aes_key *key, uint8_t *origkey, uint8_t size);+int crypton_aes_armv8_gcm_fused_dec(uint8_t *out, const block128 *ht,+ aes_key *key, const uint8_t *nonce,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *in, uint32_t inlen,+ const uint8_t *tag, uint32_t taglen,+ uint8_t *outtag);+void crypton_aes_armv8_gcm_fused(uint8_t *out, const block128 *ht,+ aes_key *key, const uint8_t *nonce,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *in, uint32_t inlen,+ uint32_t taglen, aes_key *hpkey,+ uint32_t sampleoff, uint8_t *mask); #define ARMV8_DECLS(sz) \ void crypton_aes_armv8_encrypt_block##sz(aes_block *output, aes_key *key, aes_block *input); \ void crypton_aes_armv8_decrypt_block##sz(aes_block *output, aes_key *key, aes_block *input); \@@ -193,7 +213,7 @@ typedef void (*gf_mul_f)(block128 *a, const table_4bit htable); typedef void (*gf_mul4_f)(block128 *a, const block128 *blocks, const table_4bit htable); -#if defined(WITH_AESNI) || defined(WITH_ARMV8_CRYPTO)+#if defined(WITH_AESNI) || defined(WITH_ARMV8_CRYPTO) || defined(WITH_PPC8_CRYPTO) #define GET_INIT(strength) \ ((init_f) (crypton_aes_branch_table[INIT_128 + strength])) #define GET_ECB_ENCRYPT(strength) \@@ -240,12 +260,16 @@ #define GET_ECB_DECRYPT(strength) crypton_aes_generic_decrypt_ecb #define GET_CBC_ENCRYPT(strength) crypton_aes_generic_encrypt_cbc #define GET_CBC_DECRYPT(strength) crypton_aes_generic_decrypt_cbc-#define GET_CTR_ENCRYPT(strength) crypton_aes_generic_encrypt_ctr-#define GET_C32_ENCRYPT(strength) crypton_aes_generic_encrypt_c32+/* No accelerator is compiled in, so the portable schedule is the only one+ * a key can hold and the four-block CTR is named here rather than installed+ * at run time. This is the build ppc64le, s390x, riscv64, 32-bit ARM and+ * -f-support_aesni all get, and nothing in it reads the branch table. */+#define GET_CTR_ENCRYPT(strength) crypton_aes_bitsliced_encrypt_ctr+#define GET_C32_ENCRYPT(strength) crypton_aes_bitsliced_encrypt_c32 #define GET_XTS_ENCRYPT(strength) crypton_aes_generic_encrypt_xts #define GET_XTS_DECRYPT(strength) crypton_aes_generic_decrypt_xts-#define GET_GCM_ENCRYPT(strength) crypton_aes_generic_gcm_encrypt-#define GET_GCM_DECRYPT(strength) crypton_aes_generic_gcm_decrypt+#define GET_GCM_ENCRYPT(strength) crypton_aes_bitsliced_gcm_encrypt+#define GET_GCM_DECRYPT(strength) crypton_aes_bitsliced_gcm_decrypt #define GET_OCB_ENCRYPT(strength) crypton_aes_generic_ocb_encrypt #define GET_OCB_DECRYPT(strength) crypton_aes_generic_ocb_decrypt #define GET_CCM_ENCRYPT(strength) crypton_aes_generic_ccm_encrypt@@ -257,10 +281,6 @@ #define crypton_gf_mul4(a,b,t) crypton_aes_generic_gf_mul4(a,b,t) #endif -#define CPU_AESNI 0-#define CPU_PCLMUL 1-#define CPU_OPTION_COUNT 2- static uint8_t crypton_aes_cpu_options[CPU_OPTION_COUNT] = {}; #if defined(ARCH_X86) && defined(WITH_AESNI)@@ -410,14 +430,112 @@ } #endif -uint8_t *crypton_aes_cpu_init(void)+/* Which implementation each entry of the branch table names is decided once,+ * before anything else runs.+ *+ * It used to be decided again on every crypton_aes_initkey, which meant two+ * threads taking a key at the same time were writing the whole table at the+ * same time -- a data race for as long as the program used AES, not just at+ * the start. ThreadSanitizer reports forty-two of them for eight threads+ * doing nothing but taking keys. The values written are the same ones every+ * time and the table starts out holding valid generic implementations, so+ * nothing has ever come of it; it is a race the standard gives no meaning to+ * all the same.+ *+ * A constructor runs while there is one thread, which is the cheapest way to+ * have no race at all: no flag to test, no lock to take, and one less thing+ * for crypton_aes_initkey to do per key. */+/*+ * The two CTR entries, where the portable implementation is the one that+ * will run. This is for the build that has an accelerator compiled in and+ * did not find it on the processor; a build with no accelerator at all+ * names them directly in the GET_ macros above and never reads this table.+ *+ * They cannot be the defaults. crypton_aes_generic_encrypt_c32 is not+ * overridden on AArch64 -- the ARMv8 table has no C32 of its own -- and+ * neither CCM nor OCB is overridden anywhere, so those reach the block+ * function through the branch table and work whatever is installed. A CTR+ * that read the portable schedule directly would be wrong on exactly those+ * machines. So these go in only once nothing has claimed AES.+ */+static void initialize_table_bitsliced(void) {+ crypton_aes_branch_table[ENCRYPT_CTR_128] = crypton_aes_bitsliced_encrypt_ctr;+ crypton_aes_branch_table[ENCRYPT_CTR_192] = crypton_aes_bitsliced_encrypt_ctr;+ crypton_aes_branch_table[ENCRYPT_CTR_256] = crypton_aes_bitsliced_encrypt_ctr;+ crypton_aes_branch_table[ENCRYPT_C32_128] = crypton_aes_bitsliced_encrypt_c32;+ crypton_aes_branch_table[ENCRYPT_C32_192] = crypton_aes_bitsliced_encrypt_c32;+ crypton_aes_branch_table[ENCRYPT_C32_256] = crypton_aes_bitsliced_encrypt_c32;+ crypton_aes_branch_table[ENCRYPT_GCM_128] = crypton_aes_bitsliced_gcm_encrypt;+ crypton_aes_branch_table[ENCRYPT_GCM_192] = crypton_aes_bitsliced_gcm_encrypt;+ crypton_aes_branch_table[ENCRYPT_GCM_256] = crypton_aes_bitsliced_gcm_encrypt;+ crypton_aes_branch_table[DECRYPT_GCM_128] = crypton_aes_bitsliced_gcm_decrypt;+ crypton_aes_branch_table[DECRYPT_GCM_192] = crypton_aes_bitsliced_gcm_decrypt;+ crypton_aes_branch_table[DECRYPT_GCM_256] = crypton_aes_bitsliced_gcm_decrypt;+}++#ifdef WITH_PPC8_CRYPTO+/*+ * POWER8. One function per operation rather than three: the assembly reads+ * the round count out of the key, so the same entry serves every key size.+ *+ * GCM and the 32-bit counter are left where they are. Neither has an entry+ * in the assembly, and the generic loops reach the block function and the+ * GHASH through this table, so both get the instructions anyway.+ */+static void initialize_table_ppc8(void)+{+ int sz;++ if (!crypton_aes_ppc8_available())+ return;+ /* what stops initialize_table_bitsliced below from putting its own CTR+ * in, which would read this key as a bitsliced schedule */+ crypton_aes_cpu_options[CPU_AESNI] = 1;+ crypton_aes_cpu_options[CPU_PCLMUL] = 1;++ for (sz = 0; sz < 3; sz++) {+ crypton_aes_branch_table[INIT_128 + sz] = crypton_aes_ppc8_init;+ crypton_aes_branch_table[ENCRYPT_BLOCK_128 + sz] = crypton_aes_ppc8_encrypt_block;+ crypton_aes_branch_table[DECRYPT_BLOCK_128 + sz] = crypton_aes_ppc8_decrypt_block;+ crypton_aes_branch_table[ENCRYPT_ECB_128 + sz] = crypton_aes_ppc8_encrypt_ecb;+ crypton_aes_branch_table[DECRYPT_ECB_128 + sz] = crypton_aes_ppc8_decrypt_ecb;+ crypton_aes_branch_table[ENCRYPT_CBC_128 + sz] = crypton_aes_ppc8_encrypt_cbc;+ crypton_aes_branch_table[DECRYPT_CBC_128 + sz] = crypton_aes_ppc8_decrypt_cbc;+ crypton_aes_branch_table[ENCRYPT_CTR_128 + sz] = crypton_aes_ppc8_encrypt_ctr;+ crypton_aes_branch_table[ENCRYPT_XTS_128 + sz] = crypton_aes_ppc8_encrypt_xts;+ crypton_aes_branch_table[DECRYPT_XTS_128 + sz] = crypton_aes_ppc8_decrypt_xts;+ }++ crypton_aes_branch_table[GHASH_HINIT] = crypton_aes_ppc8_hinit;+ crypton_aes_branch_table[GHASH_GF_MUL] = crypton_aes_ppc8_gf_mul;+ crypton_aes_branch_table[GHASH_GF_MUL4] = crypton_aes_ppc8_gf_mul4;+}+#endif++static void crypton_aes_cpu_setup(void)+{ #if defined(ARCH_X86) && defined(WITH_AESNI) crypton_aesni_initialize_hw(initialize_table_ni); #endif #ifdef WITH_ARMV8_CRYPTO initialize_table_armv8(); #endif+#ifdef WITH_PPC8_CRYPTO+ initialize_table_ppc8();+#endif+ if (crypton_aes_cpu_options[CPU_AESNI] == 0)+ initialize_table_bitsliced();+}++__attribute__((constructor))+static void crypton_aes_cpu_ctor(void)+{+ crypton_aes_cpu_setup();+}++uint8_t *crypton_aes_cpu_init(void)+{ return crypton_aes_cpu_options; } @@ -428,7 +546,6 @@ case 24: key->nbr = 12; key->strength = 1; break; case 32: key->nbr = 14; key->strength = 2; break; }- crypton_aes_cpu_init(); init_f _init = GET_INIT(key->strength); _init(key, origkey, size); }@@ -532,20 +649,33 @@ crypton_gf_mul4(&gcm->tag, b, gcm->htable); } -void crypton_aes_gcm_init(aes_gcm *gcm, aes_key *key, uint8_t *iv, uint32_t len)+/* The part of the state that depends on the key alone: H = encrypt_K(0^128)+ * and the table of its multiples. It is 256 of the 320 bytes, and a caller+ * that keeps a key can compute it once instead of once per message. */+void crypton_aes_gcm_key_init(aes_gcm_key *gk, aes_key *key) { block128 h;++ block128_zero(&h);+ crypton_aes_encrypt_block(&h, key, &h);+ crypton_hinit(gk->gcm.htable, &h);+#ifdef WITH_GCM_FUSED+ if (crypton_aes_cpu_options[CPU_AESNI]+ && crypton_aes_cpu_options[CPU_PCLMUL])+ crypton_gcm_fused_key_init(&gk->fused, key);+#endif+}++/* Everything else: what the nonce and the message determine. Leaves htable+ * alone, so it runs on a state whose key part is already there. */+static void gcm_message_init(aes_gcm *gcm, uint8_t *iv, uint32_t len)+{ gcm->length_aad = 0; gcm->length_input = 0; - block128_zero(&h); block128_zero(&gcm->tag); block128_zero(&gcm->iv); - /* prepare H : encrypt_K(0^128) */- crypton_aes_encrypt_block(&h, key, &h);- crypton_hinit(gcm->htable, &h);- if (len == 12) { block128_copy_bytes(&gcm->iv, iv, 12); gcm->iv.b[15] = 0x01;@@ -568,6 +698,16 @@ block128_copy_aligned(&gcm->civ, &gcm->iv); } +void crypton_aes_gcm_init(aes_gcm *gcm, aes_key *key, uint8_t *iv, uint32_t len)+{+ block128 h;++ block128_zero(&h);+ crypton_aes_encrypt_block(&h, key, &h);+ crypton_hinit(gcm->htable, &h);+ gcm_message_init(gcm, iv, len);+}+ void crypton_aes_gcm_aad(aes_gcm *gcm, uint8_t *input, uint32_t length) { gcm->length_aad += length;@@ -604,6 +744,195 @@ } } +/* One message, one call. The key part of the state comes in already built,+ * the rest is set up on the stack, and the additional data, the encryption+ * and the tag all happen before returning, so nothing crosses a language+ * boundary between them and no intermediate state is copied out. The output+ * buffer takes the ciphertext and then the tag, so it wants length + taglen+ * bytes. */+void crypton_aes_gcm_full_encrypt(uint8_t *output, const aes_gcm_key *gcmkey, aes_key *key,+ uint8_t *iv, uint32_t ivlen,+ uint8_t *aad, uint32_t aadlen,+ uint8_t *input, uint32_t length, uint32_t taglen)+{+ aes_gcm gcm;+ uint8_t tag[16];++#ifdef WITH_GCM_FUSED+ /* Short messages go the other way: the assembly below will not start+ * on anything under 288 bytes, and under about 1.5 KB the fused path+ * is ahead of it even where it does. */+ if (ivlen == 12 && length <= CRYPTON_GCM_FUSED_MAX_MESSAGE+ && crypton_aes_cpu_options[CPU_AESNI]+ && crypton_aes_cpu_options[CPU_PCLMUL]) {+ crypton_gcm_fused_encrypt(output, &gcmkey->fused, key, iv,+ aad, aadlen, input, length, taglen,+ NULL, 0, NULL);+ return;+ }+#endif+#ifdef WITH_ARMV8_CRYPTO+ /* The same on AArch64, where the framing is what costs: composing the+ * additional data, the encryption and the tag reaches each through the+ * branch table, so the running state goes back to memory between them+ * and a one-block header pays a reduction of its own. Measured on an+ * Apple M4, a 100-byte packet is 3.0x faster taken in one call.+ *+ * No length limit, unlike x86: there is no vendored assembly on this+ * side for a long message to be handed to instead, and measured+ * against the path this replaces it is never slower -- 1.25x at 1440+ * bytes, level from about 6 KB up. */+ if (ivlen == 12+ && crypton_aes_cpu_options[CPU_AESNI]+ && crypton_aes_cpu_options[CPU_PCLMUL]) {+ crypton_aes_armv8_gcm_fused(output, gcmkey->gcm.htable, key, iv,+ aad, aadlen, input, length, taglen,+ NULL, 0, NULL);+ return;+ }+#endif+ memcpy(gcm.htable, gcmkey->gcm.htable, sizeof(gcm.htable));+ gcm_message_init(&gcm, iv, ivlen);+ if (aadlen)+ crypton_aes_gcm_aad(&gcm, aad, aadlen);+ if (length)+ crypton_aes_gcm_encrypt(output, &gcm, key, input, length);+ crypton_aes_gcm_finish(tag, &gcm, key);+ memcpy(output + length, tag, taglen);+}++/* The same, and then the header protection mask. QUIC takes its sample from+ * the ciphertext, so the mask cannot be had before the encryption -- but it+ * can be had before returning, which saves a second crossing for one AES+ * block. The block itself is about a nanosecond; what it saves is the call.+ * sampleoff is where the sixteen bytes of sample start in the output. */+void crypton_aes_gcm_full_encrypt_mask(uint8_t *output, const aes_gcm_key *gcmkey, aes_key *key,+ uint8_t *iv, uint32_t ivlen,+ uint8_t *aad, uint32_t aadlen,+ uint8_t *input, uint32_t length, uint32_t taglen,+ aes_key *hpkey, uint32_t sampleoff, uint8_t *mask)+{+ block128 sample, m;++#ifdef WITH_GCM_FUSED+ /* Here the mask rides in a lane of the AES pipeline that the message+ * length leaves idle, so it costs very nearly nothing on top of the+ * encryption rather than a block of its own. */+ if (ivlen == 12 && length <= CRYPTON_GCM_FUSED_MAX_MESSAGE+ && crypton_aes_cpu_options[CPU_AESNI]+ && crypton_aes_cpu_options[CPU_PCLMUL]) {+ crypton_gcm_fused_encrypt(output, &gcmkey->fused, key, iv,+ aad, aadlen, input, length, taglen,+ hpkey, sampleoff, mask);+ return;+ }+#endif+#ifdef WITH_ARMV8_CRYPTO+ /* The same on AArch64, where the framing is what costs: composing the+ * additional data, the encryption and the tag reaches each through the+ * branch table, so the running state goes back to memory between them+ * and a one-block header pays a reduction of its own. Measured on an+ * Apple M4, a 100-byte packet is 3.3x faster taken in one call. */+ if (ivlen == 12+ && crypton_aes_cpu_options[CPU_AESNI]+ && crypton_aes_cpu_options[CPU_PCLMUL]) {+ crypton_aes_armv8_gcm_fused(output, gcmkey->gcm.htable, key, iv,+ aad, aadlen, input, length, taglen,+ hpkey, sampleoff, mask);+ return;+ }+#endif+ crypton_aes_gcm_full_encrypt(output, gcmkey, key, iv, ivlen, aad, aadlen,+ input, length, taglen);+ /* copied rather than cast: the sample lands wherever the header put it+ * and a block128 is read as 64-bit words */+ memcpy(&sample, output + sampleoff, 16);+ crypton_aes_encrypt_block(&m, hpkey, &sample);+ memcpy(mask, &m, 16);+}++/* The same the other way, with the tag checked here rather than by the+ * caller: returns 1 when it matches and 0 when it does not, comparing every+ * byte either way. The plaintext is written whatever the answer, so a caller+ * that gets 0 must not use it. */+/* Decrypt, and either compare the tag or hand it back.+ *+ * With outtag NULL this is the verifying form: the tag is compared here, a+ * byte at a time over its whole length whichever way the answer goes, and the+ * answer is the return value. With outtag not NULL the computed tag is+ * written there instead and the return value is 1 -- for a caller that holds+ * the expected tag in a form of its own and will compare it itself. */+static int gcm_full_decrypt(uint8_t *output, const aes_gcm_key *gcmkey, aes_key *key,+ uint8_t *iv, uint32_t ivlen,+ uint8_t *aad, uint32_t aadlen,+ uint8_t *input, uint32_t length,+ const uint8_t *tag, uint32_t taglen,+ uint8_t *outtag)+{+ aes_gcm gcm;+ uint8_t expected[16];+ uint32_t i;+ uint8_t diff = 0;++#ifdef WITH_GCM_FUSED+ /* The same as the encryption side, and simpler: what GHASH absorbs+ * here is the ciphertext, which is the input, so the multiplies need+ * not wait for anything. Measured on an Intel Haswell, a 100-byte+ * packet was three times the cost of encrypting one before this. */+ if (ivlen == 12 && length <= CRYPTON_GCM_FUSED_MAX_MESSAGE+ && crypton_aes_cpu_options[CPU_AESNI]+ && crypton_aes_cpu_options[CPU_PCLMUL])+ return crypton_gcm_fused_decrypt(output, &gcmkey->fused, key,+ iv, aad, aadlen, input,+ length, tag, taglen, outtag);+#endif+#ifdef WITH_ARMV8_CRYPTO+ if (ivlen == 12+ && crypton_aes_cpu_options[CPU_AESNI]+ && crypton_aes_cpu_options[CPU_PCLMUL])+ return crypton_aes_armv8_gcm_fused_dec(output, gcmkey->gcm.htable,+ key, iv, aad, aadlen,+ input, length, tag, taglen,+ outtag);+#endif+ memcpy(gcm.htable, gcmkey->gcm.htable, sizeof(gcm.htable));+ gcm_message_init(&gcm, iv, ivlen);+ if (aadlen)+ crypton_aes_gcm_aad(&gcm, aad, aadlen);+ if (length)+ crypton_aes_gcm_decrypt(output, &gcm, key, input, length);+ crypton_aes_gcm_finish(expected, &gcm, key);++ if (outtag) {+ memcpy(outtag, expected, taglen);+ return 1;+ }+ for (i = 0; i < taglen; i++)+ diff |= (uint8_t) (expected[i] ^ tag[i]);+ return diff == 0;+}++int crypton_aes_gcm_full_decrypt(uint8_t *output, const aes_gcm_key *gcmkey, aes_key *key,+ uint8_t *iv, uint32_t ivlen,+ uint8_t *aad, uint32_t aadlen,+ uint8_t *input, uint32_t length,+ const uint8_t *tag, uint32_t taglen)+{+ return gcm_full_decrypt(output, gcmkey, key, iv, ivlen, aad, aadlen,+ input, length, tag, taglen, NULL);+}++void crypton_aes_gcm_full_decrypt_tag(uint8_t *output, uint8_t *outtag,+ const aes_gcm_key *gcmkey, aes_key *key,+ uint8_t *iv, uint32_t ivlen,+ uint8_t *aad, uint32_t aadlen,+ uint8_t *input, uint32_t length,+ uint32_t taglen)+{+ (void) gcm_full_decrypt(output, gcmkey, key, iv, ivlen, aad, aadlen,+ input, length, NULL, taglen, outtag);+}+ static inline uint8_t ccm_b0_flags(uint32_t has_adata, uint32_t m, uint32_t l) { return 8*m + l + (has_adata? 64: 0);@@ -885,18 +1214,30 @@ block128_xor((block128 *) tag, &ocb->sum_aad); } +/*+ * These three reach cbits/aes/generic.c directly rather than through the+ * branch table, so they run only where the portable implementation was the+ * one installed -- which is what lets them read its schedule and hand its+ * core four blocks at a time. The CTR entries below cannot do the same:+ * they go through the branch table for the block, and so run on accelerated+ * machines too.+ */ void crypton_aes_generic_encrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks) {- for ( ; nb_blocks-- > 0; input++, output++) {- crypton_aes_generic_encrypt_block(output, key, input);- }+ aes_sched sched;++ crypton_aes_generic_schedule(&sched, key);+ crypton_aes_generic_blocks((uint8_t *) output, (const uint8_t *) input,+ nb_blocks, &sched, 0); } void crypton_aes_generic_decrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks) {- for ( ; nb_blocks-- > 0; input++, output++) {- crypton_aes_generic_decrypt_block(output, key, input);- }+ aes_sched sched;++ crypton_aes_generic_schedule(&sched, key);+ crypton_aes_generic_blocks((uint8_t *) output, (const uint8_t *) input,+ nb_blocks, &sched, 1); } void crypton_aes_generic_encrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks)@@ -912,18 +1253,35 @@ } } +/*+ * Decryption, unlike encryption, does not wait for the block before it:+ * every ciphertext block is ready at once and the chaining is a XOR+ * afterwards. So four at a pass, with the ciphertext copied aside first,+ * since the caller is allowed to decrypt in place and the next group's IV+ * is the last ciphertext block of this one.+ */ void crypton_aes_generic_decrypt_cbc(aes_block *output, aes_key *key, aes_block *ivini, aes_block *input, uint32_t nb_blocks) {- aes_block block, blocko;+ aes_sched sched; aes_block iv;+ uint8_t ct[64], plain[64]; - /* preload IV in block */+ crypton_aes_generic_schedule(&sched, key); block128_copy(&iv, ivini);- for ( ; nb_blocks-- > 0; input++, output++) {- block128_copy(&block, (block128 *) input);- crypton_aes_generic_decrypt_block(&blocko, key, &block);- block128_vxor((block128 *) output, &blocko, &iv);- block128_copy(&iv, &block);+ while (nb_blocks > 0) {+ uint32_t n = nb_blocks < 4 ? nb_blocks : 4;+ uint32_t i;++ memcpy(ct, input, n * 16);+ crypton_aes_generic_blocks(plain, ct, n, &sched, 1);+ for (i = 0; i < n; i++) {+ block128_vxor((block128 *) (output + i),+ (block128 *) (plain + 16 * i), &iv);+ block128_copy(&iv, (block128 *) (ct + 16 * i));+ }+ input += n;+ output += n;+ nb_blocks -= n; } } @@ -978,7 +1336,9 @@ void crypton_aes_generic_encrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks) {- aes_block block, tweak;+ aes_sched sched;+ aes_block tweak;+ uint8_t buf[64], tw[64]; /* load IV and encrypt it using k2 as the tweak */ block128_copy(&tweak, dataunit);@@ -988,17 +1348,34 @@ while (spoint-- > 0) crypton_aes_generic_gf_mulx(&tweak); - for ( ; nb_blocks-- > 0; input++, output++, crypton_aes_generic_gf_mulx(&tweak)) {- block128_vxor(&block, input, &tweak);- crypton_aes_encrypt_block(&block, k1, &block);- block128_vxor(output, &block, &tweak);+ crypton_aes_generic_schedule(&sched, k1);+ while (nb_blocks > 0) {+ uint32_t n = nb_blocks < 4 ? nb_blocks : 4;+ uint32_t i;++ /* the tweaks for a group depend on nothing but each other, so+ * all four are known before any block is enciphered */+ for (i = 0; i < n; i++) {+ block128_copy((block128 *) (tw + 16 * i), &tweak);+ block128_vxor((block128 *) (buf + 16 * i), input + i, &tweak);+ crypton_aes_generic_gf_mulx(&tweak);+ }+ crypton_aes_generic_blocks(buf, buf, n, &sched, 0);+ for (i = 0; i < n; i++)+ block128_vxor(output + i, (block128 *) (buf + 16 * i),+ (block128 *) (tw + 16 * i));+ input += n;+ output += n;+ nb_blocks -= n; } } void crypton_aes_generic_decrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks) {- aes_block block, tweak;+ aes_sched sched;+ aes_block tweak;+ uint8_t buf[64], tw[64]; /* load IV and encrypt it using k2 as the tweak */ block128_copy(&tweak, dataunit);@@ -1008,10 +1385,25 @@ while (spoint-- > 0) crypton_aes_generic_gf_mulx(&tweak); - for ( ; nb_blocks-- > 0; input++, output++, crypton_aes_generic_gf_mulx(&tweak)) {- block128_vxor(&block, input, &tweak);- crypton_aes_decrypt_block(&block, k1, &block);- block128_vxor(output, &block, &tweak);+ crypton_aes_generic_schedule(&sched, k1);+ while (nb_blocks > 0) {+ uint32_t n = nb_blocks < 4 ? nb_blocks : 4;+ uint32_t i;++ /* the tweaks for a group depend on nothing but each other, so+ * all four are known before any block is enciphered */+ for (i = 0; i < n; i++) {+ block128_copy((block128 *) (tw + 16 * i), &tweak);+ block128_vxor((block128 *) (buf + 16 * i), input + i, &tweak);+ crypton_aes_generic_gf_mulx(&tweak);+ }+ crypton_aes_generic_blocks(buf, buf, n, &sched, 1);+ for (i = 0; i < n; i++)+ block128_vxor(output + i, (block128 *) (buf + 16 * i),+ (block128 *) (tw + 16 * i));+ input += n;+ output += n;+ nb_blocks -= n; } } @@ -1240,6 +1632,116 @@ block128_zero(&tmp); block128_copy_bytes(&tmp, input, length); ccm_cbcmac_add(ccm, key, &tmp);+ }+}++/*+ * GCM where the portable implementation is the one that will run.+ *+ * The same shape as the two above, with two differences: the four counter+ * blocks of a group are encrypted together, which is what the bitsliced+ * core is for, and the schedule is expanded once for the message rather+ * than once per block.+ *+ * These cannot replace the generic pair. That pair also runs on an x86+ * machine that has AES-NI and no carry-less multiply, where crypton_aes.c+ * installs the AES-NI block function and leaves GCM alone -- and there the+ * key holds the AES-NI schedule, not this one. So the choice is made where+ * the rest of the portable entries are chosen.+ */+void crypton_aes_bitsliced_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length)+{+ aes_sched sched;+ aes_block out;++ crypton_aes_generic_schedule(&sched, key);+ gcm->length_input += length;+ for (; length >= 64; input += 64, output += 64, length -= 64) {+ aes_block buf[4];+ int i;++ for (i = 0; i < 4; i++) {+ block128_inc32_be(&gcm->civ);+ block128_copy(&buf[i], &gcm->civ);+ }+ crypton_aes_generic_blocks((uint8_t *) buf, (const uint8_t *) buf,+ 4, &sched, 0);+ for (i = 0; i < 4; i++)+ block128_xor(&buf[i], (block128 *) (input + 16 * i));+ gcm_ghash_add4(gcm, buf);+ for (i = 0; i < 4; i++)+ block128_copy((block128 *) (output + 16 * i), &buf[i]);+ }+ for (; length >= 16; input += 16, output += 16, length -= 16) {+ block128_inc32_be(&gcm->civ);+ crypton_aes_generic_blocks((uint8_t *) &out,+ (const uint8_t *) &gcm->civ, 1, &sched, 0);+ block128_xor(&out, (block128 *) input);+ gcm_ghash_add(gcm, &out);+ block128_copy((block128 *) output, &out);+ }+ if (length > 0) {+ aes_block tmp;+ uint32_t i;++ block128_inc32_be(&gcm->civ);+ crypton_aes_generic_blocks((uint8_t *) &out,+ (const uint8_t *) &gcm->civ, 1, &sched, 0);+ block128_zero(&tmp);+ block128_copy_bytes(&tmp, input, length);+ block128_xor_bytes(&tmp, out.b, length);+ gcm_ghash_add(gcm, &tmp);+ for (i = 0; i < length; i++)+ output[i] = tmp.b[i];+ }+}++void crypton_aes_bitsliced_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length)+{+ aes_sched sched;+ aes_block out;++ crypton_aes_generic_schedule(&sched, key);+ gcm->length_input += length;+ /* GHASH all four ciphertext blocks before writing any plaintext, since+ * output may be input */+ for (; length >= 64; input += 64, output += 64, length -= 64) {+ aes_block buf[4];+ int i;++ gcm_ghash_add4(gcm, (const block128 *) input);+ for (i = 0; i < 4; i++) {+ block128_inc32_be(&gcm->civ);+ block128_copy(&buf[i], &gcm->civ);+ }+ crypton_aes_generic_blocks((uint8_t *) buf, (const uint8_t *) buf,+ 4, &sched, 0);+ for (i = 0; i < 4; i++) {+ block128_xor(&buf[i], (block128 *) (input + 16 * i));+ block128_copy((block128 *) (output + 16 * i), &buf[i]);+ }+ }+ for (; length >= 16; input += 16, output += 16, length -= 16) {+ block128_inc32_be(&gcm->civ);+ crypton_aes_generic_blocks((uint8_t *) &out,+ (const uint8_t *) &gcm->civ, 1, &sched, 0);+ gcm_ghash_add(gcm, (block128 *) input);+ block128_xor(&out, (block128 *) input);+ block128_copy((block128 *) output, &out);+ }+ if (length > 0) {+ aes_block tmp;+ uint32_t i;++ block128_inc32_be(&gcm->civ);+ crypton_aes_generic_blocks((uint8_t *) &out,+ (const uint8_t *) &gcm->civ, 1, &sched, 0);+ block128_zero(&tmp);+ block128_copy_bytes(&tmp, input, length);+ gcm_ghash_add(gcm, &tmp);+ block128_xor_bytes(&tmp, out.b, length);+ for (i = 0; i < length; i++)+ output[i] = tmp.b[i]; } }
@@ -55,6 +55,55 @@ uint64_t length_input; } aes_gcm; +/*+ * How many powers of H a key keeps for the fused path in+ * cbits/aes/gcm_fused_x86.c. A power for every block of the message would+ * fold its whole GHASH into one reduction, which is what picotls does, but+ * then the state grows with the longest message a caller might send and a+ * server holding many keys pays it for each. A fixed count costs one+ * reduction per this many blocks and keeps the state one size. Sixteen was+ * measured against 6, 8, 32, 64, 96 and 256: above eight the choice is worth+ * about two per cent, since only messages short enough to take this path at+ * all reach a second batch. Six is worth avoiding -- at 1440 bytes it is+ * slower than not taking the path.+ */+#define CRYPTON_GCM_FUSED_POWERS 16++/*+ * Beyond this many bytes the stitched assembly in cbits/asm is faster than+ * the fused path, so longer messages go there instead. Measured on an Intel+ * Haswell: even at 1440 bytes, the assembly ahead by 12 per cent at 3 KB and+ * 20 per cent at 16 KB, and the fused path ahead by 1.9x at 100 bytes and+ * 1.16x at 1200. QUIC packets fall below this; TLS records do not.+ */+#define CRYPTON_GCM_FUSED_MAX_MESSAGE 1536++/*+ * The powers themselves, each shifted up by one bit, and beside each the+ * halves of it added together for the Karatsuba term. The two are kept+ * adjacent rather than in two arrays: a multiply wants both, and two arrays+ * put them 256 bytes apart, which is two cache lines where this is one.+ *+ * Defined on every platform so that the key state below is one size+ * everywhere; filled only where the fused path is compiled in.+ */+typedef struct {+ struct {+ aes_block h;+ aes_block r;+ } p[CRYPTON_GCM_FUSED_POWERS];+} aes_gcm_fused;++/*+ * Everything a key determines, built once by crypton_aes_gcm_key_init and+ * read by every message sent under that key: the key half of a GCM state,+ * and the powers of H the fused path reads. 832 bytes.+ */+typedef struct {+ aes_gcm gcm;+ aes_gcm_fused fused;+} aes_gcm_key;+ /* size = 4*16+4*4= 80 */ typedef struct { aes_block xi;@@ -104,6 +153,27 @@ uint32_t spoint, aes_block *input, uint32_t nb_blocks); void crypton_aes_gcm_init(aes_gcm *gcm, aes_key *key, uint8_t *iv, uint32_t len);+void crypton_aes_gcm_key_init(aes_gcm_key *gk, aes_key *key);+void crypton_aes_gcm_full_encrypt(uint8_t *output, const aes_gcm_key *gcmkey, aes_key *key,+ uint8_t *iv, uint32_t ivlen,+ uint8_t *aad, uint32_t aadlen,+ uint8_t *input, uint32_t length, uint32_t taglen);+void crypton_aes_gcm_full_encrypt_mask(uint8_t *output, const aes_gcm_key *gcmkey, aes_key *key,+ uint8_t *iv, uint32_t ivlen,+ uint8_t *aad, uint32_t aadlen,+ uint8_t *input, uint32_t length, uint32_t taglen,+ aes_key *hpkey, uint32_t sampleoff, uint8_t *mask);+int crypton_aes_gcm_full_decrypt(uint8_t *output, const aes_gcm_key *gcmkey, aes_key *key,+ uint8_t *iv, uint32_t ivlen,+ uint8_t *aad, uint32_t aadlen,+ uint8_t *input, uint32_t length,+ const uint8_t *tag, uint32_t taglen);+void crypton_aes_gcm_full_decrypt_tag(uint8_t *output, uint8_t *outtag,+ const aes_gcm_key *gcmkey, aes_key *key,+ uint8_t *iv, uint32_t ivlen,+ uint8_t *aad, uint32_t aadlen,+ uint8_t *input, uint32_t length,+ uint32_t taglen); void crypton_aes_gcm_aad(aes_gcm *gcm, uint8_t *input, uint32_t length); void crypton_aes_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length); void crypton_aes_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length);
@@ -3,6 +3,8 @@ #include "crypton_bitfn.h" +#include <string.h>+ #if (defined(__i386__)) # define UNALIGNED_ACCESS_OK #elif defined(__x86_64__)@@ -34,107 +36,119 @@ #define need_alignment(p,n) IS_ALIGNED(p,n) #endif -static inline uint32_t load_le32_aligned(const uint8_t *p)-{- return le32_to_cpu(*((uint32_t *) p)); -}+/*+ * Reading and writing a 32- or 64-bit word at a byte pointer.+ *+ * Through memcpy, not a cast to uint32_t * or uint64_t *. A cast is two+ * things the standard does not allow -- a read of the value through the+ * wrong type, and a read at an address that type is not aligned for -- and+ * this file used to do both wherever UNALIGNED_ACCESS_OK is defined, which+ * is i386 and x86-64. UndefinedBehaviorSanitizer reported seventy-eight+ * lines of it.+ *+ * Every compiler crypton is built with turns a memcpy of four or eight bytes+ * into the one load or store the cast used to be, so this is the same code+ * with none of the licence. Where the target cannot do an unaligned load,+ * the compiler is the one that knows, and it emits what the target needs --+ * which is what the byte-at-a-time versions this replaces were for.+ *+ * The _aligned names stay because nineteen files use them. They no longer+ * ask anything of the pointer.+ */ -static inline void store_le32_aligned(uint8_t *dst, const uint32_t v)+static inline uint32_t load_le32(const uint8_t *p) {- *((uint32_t *) dst) = cpu_to_le32(v);-}+ uint32_t v; -static inline void xor_le32_aligned(uint8_t *dst, const uint32_t v)-{- *((uint32_t *) dst) ^= cpu_to_le32(v);+ memcpy(&v, p, sizeof(v));+ return le32_to_cpu(v); } -static inline void store_be32_aligned(uint8_t *dst, const uint32_t v)+static inline uint64_t load_le64(const uint8_t *p) {- *((uint32_t *) dst) = cpu_to_be32(v);-}+ uint64_t v; -static inline void xor_be32_aligned(uint8_t *dst, const uint32_t v)-{- *((uint32_t *) dst) ^= cpu_to_be32(v);+ memcpy(&v, p, sizeof(v));+ return le64_to_cpu(v); } -static inline void store_le64_aligned(uint8_t *dst, const uint64_t v)+static inline uint32_t load_be32(const uint8_t *p) {- *((uint64_t *) dst) = cpu_to_le64(v);-}+ uint32_t v; -static inline void store_be64_aligned(uint8_t *dst, const uint64_t v)-{- *((uint64_t *) dst) = cpu_to_be64(v);+ memcpy(&v, p, sizeof(v));+ return be32_to_cpu(v); } -static inline void xor_be64_aligned(uint8_t *dst, const uint64_t v)+static inline uint64_t load_be64(const uint8_t *p) {- *((uint64_t *) dst) ^= cpu_to_be64(v);-}+ uint64_t v; -#ifdef UNALIGNED_ACCESS_OK-#define load_le32(a) load_le32_aligned(a)-#else-static inline uint32_t load_le32(const uint8_t *p)-{- return ((uint32_t)p[0]) | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);+ memcpy(&v, p, sizeof(v));+ return be64_to_cpu(v); }-#endif -#ifdef UNALIGNED_ACCESS_OK-#define store_le32(a, b) store_le32_aligned(a, b)-#define xor_le32(a, b) xor_le32_aligned(a, b)-#else static inline void store_le32(uint8_t *dst, const uint32_t v) {- dst[0] = v; dst[1] = v >> 8; dst[2] = v >> 16; dst[3] = v >> 24;+ uint32_t w = cpu_to_le32(v);++ memcpy(dst, &w, sizeof(w)); }+ static inline void xor_le32(uint8_t *dst, const uint32_t v) {- dst[0] ^= v; dst[1] ^= v >> 8; dst[2] ^= v >> 16; dst[3] ^= v >> 24;+ store_le32(dst, le32_to_cpu(load_le32(dst)) ^ v); }-#endif -#ifdef UNALIGNED_ACCESS_OK-#define store_be32(a, b) store_be32_aligned(a, b)-#define xor_be32(a, b) xor_be32_aligned(a, b)-#else static inline void store_be32(uint8_t *dst, const uint32_t v) {- dst[3] = v; dst[2] = v >> 8; dst[1] = v >> 16; dst[0] = v >> 24;+ uint32_t w = cpu_to_be32(v);++ memcpy(dst, &w, sizeof(w)); }+ static inline void xor_be32(uint8_t *dst, const uint32_t v) {- dst[3] ^= v; dst[2] ^= v >> 8; dst[1] ^= v >> 16; dst[0] ^= v >> 24;+ uint32_t w;++ memcpy(&w, dst, sizeof(w));+ w ^= cpu_to_be32(v);+ memcpy(dst, &w, sizeof(w)); }-#endif -#ifdef UNALIGNED_ACCESS_OK-#define store_le64(a, b) store_le64_aligned(a, b)-#else static inline void store_le64(uint8_t *dst, const uint64_t v) {- dst[0] = v ; dst[1] = v >> 8 ; dst[2] = v >> 16; dst[3] = v >> 24;- dst[4] = v >> 32; dst[5] = v >> 40; dst[6] = v >> 48; dst[7] = v >> 56;+ uint64_t w = cpu_to_le64(v);++ memcpy(dst, &w, sizeof(w)); }-#endif -#ifdef UNALIGNED_ACCESS_OK-#define store_be64(a, b) store_be64_aligned(a, b)-#define xor_be64(a, b) xor_be64_aligned(a, b)-#else static inline void store_be64(uint8_t *dst, const uint64_t v) {- dst[7] = v ; dst[6] = v >> 8 ; dst[5] = v >> 16; dst[4] = v >> 24;- dst[3] = v >> 32; dst[2] = v >> 40; dst[1] = v >> 48; dst[0] = v >> 56;+ uint64_t w = cpu_to_be64(v);++ memcpy(dst, &w, sizeof(w)); }+ static inline void xor_be64(uint8_t *dst, const uint64_t v) {- dst[7] ^= v ; dst[6] ^= v >> 8 ; dst[5] ^= v >> 16; dst[4] ^= v >> 24;- dst[3] ^= v >> 32; dst[2] ^= v >> 40; dst[1] ^= v >> 48; dst[0] ^= v >> 56;+ uint64_t w;++ memcpy(&w, dst, sizeof(w));+ w ^= cpu_to_be64(v);+ memcpy(dst, &w, sizeof(w)); }-#endif++#define load_le32_aligned(p) load_le32(p)+#define load_le64_aligned(p) load_le64(p)+#define load_be32_aligned(p) load_be32(p)+#define load_be64_aligned(p) load_be64(p)+#define store_le32_aligned(d, v) store_le32(d, v)+#define xor_le32_aligned(d, v) xor_le32(d, v)+#define store_be32_aligned(d, v) store_be32(d, v)+#define xor_be32_aligned(d, v) xor_be32(d, v)+#define store_le64_aligned(d, v) store_le64(d, v)+#define store_be64_aligned(d, v) store_be64(d, v)+#define xor_be64_aligned(d, v) xor_be64(d, v) #endif
@@ -0,0 +1,52 @@+/*+ * Asking for an AArch64 extension on one function.+ *+ * The instructions these files use are extensions, so a translation unit+ * compiled for the baseline may not emit them, and the function that does has+ * to say which extension it needs. The two compilers spell that differently+ * and did not always:+ *+ * clang target("+crypto") for as long as it matters+ * GCC 13 and up target("+crypto") as well+ * GCC before 13 target("arch=armv8-a+crypto") -- the bare "+feature" form+ * is not understood, and the extension never reaches the+ * function, so an always_inline intrinsic that needs it+ * fails to inline and the build stops+ *+ * That last case is #273: gcc 12.2 on an aarch64 Linux could not build+ * cbits/sha3_armv8.c at all. Naming the architecture as well as the+ * extension is understood by every version of both compilers, so GCC is given+ * that spelling and clang keeps the shorter one, which leaves whatever+ * baseline the caller chose alone.+ */+#ifndef CRYPTON_ARMV8_TARGET_H+#define CRYPTON_ARMV8_TARGET_H++#ifdef WITH_TARGET_ATTRIBUTES+#if defined(__arm__)+/*+ * AArch32 asks for an FPU rather than an architecture extension, and the+ * spelling differs between the compilers in ways that cannot be checked from+ * here. Rather than guess, the cabal file passes -mfpu=crypto-neon-fp-armv8+ * for the whole component on this architecture whatever this flag says, and+ * these expand to nothing. A global target option is safe because a+ * compiler emits these instructions where an intrinsic asks for them and+ * nowhere else.+ */+#define CRYPTON_TARGET_ARMV8_CRYPTO+#define CRYPTON_TARGET_ARMV8_SHA3+#elif defined(__clang__)+#define CRYPTON_TARGET_ARMV8_CRYPTO __attribute__((target("+crypto")))+#define CRYPTON_TARGET_ARMV8_SHA3 __attribute__((target("+sha3")))+#else+#define CRYPTON_TARGET_ARMV8_CRYPTO \+ __attribute__((target("arch=armv8-a+crypto")))+#define CRYPTON_TARGET_ARMV8_SHA3 \+ __attribute__((target("arch=armv8.2-a+sha3")))+#endif+#else+#define CRYPTON_TARGET_ARMV8_CRYPTO+#define CRYPTON_TARGET_ARMV8_SHA3+#endif++#endif
@@ -29,11 +29,6 @@ #define LIMB_BYTES (LIMB_BITS / 8) -/* four bits of exponent per window, so a table of sixteen and no leftover- * bits: a byte holds exactly two windows */-#define WINDOW_BITS 4-#define TABLE_SIZE (1 << WINDOW_BITS)- /* r = a - b, returning the borrow out of the top */ static inline limb_t sub_n(limb_t *r, const limb_t *a, const limb_t *b, uint32_t n) {@@ -112,9 +107,196 @@ return (limb_t) 0 - inv; } -/* t += a * b over n limbs, returning the carry. This is where nearly all of- * the time goes, so the limbs are taken eight at a time; what is left over at- * the end is taken one at a time. */+/*+ * t += a * b over n limbs, returning the carry. This is where nearly all of+ * the time goes.+ *+ * The C below takes the limbs eight at a time; what is left over at the end+ * is taken one at a time. On AArch64 the compiler writes each limb as+ * `mul`, `umulh`, `adds`, `cset`, `adds`, `adc`: the carry out of one+ * 128-bit addition leaves the flags for a general register and is added back+ * in the next, because in C each addition is a statement of its own. Two of+ * those instructions are that round trip.+ *+ * Three attempts to take them back measured worse than the C, and are+ * written down here so that they are not tried again -- one RSA-2048 CRT+ * private operation on an Apple M4, best of many:+ *+ * this loop in inline assembly, a carry chain per limb 654.7 us+ * the same with the loads hoisted out of the chain 644.5+ * the multiply interleaved with its reduction (CIOS) 604.1+ * the C below 590.1+ * what the AArch64 block does, four limbs and two chains 514.9+ * the same, with the ragged end of the row written out too 503.4+ *+ * The first two lose because a chain per limb serialises what the spare+ * `cset` lets overlap: `adds`, `adc`, `adds`, `adc` is four dependent steps+ * per limb, and a wide out-of-order core would rather have the extra+ * instruction than the dependency. The third loses because shifting the+ * accumulator down a limb each round costs more than the round trip through+ * 2n limbs that it saves. What works is neither: four limbs to an+ * iteration with the flags carrying through two long chains, one for the low+ * halves of the products and one for the high halves a place up.+ *+ * There is more still there. OpenSSL's armv8-mont.pl runs a 16-limb+ * Montgomery multiplication at about 0.98 multiply-accumulates per cycle;+ * this file was at 0.55 and the block below brings it to 0.64, where 1.0 is+ * the ceiling -- a multiply-accumulate is two instructions and the machine+ * issues two multiplies a cycle. That code cannot be borrowed: it is in+ * OpenSSL's tree only, under Apache-2.0, and CRYPTOGAMS, which this library+ * does vendor from, publishes no Montgomery generator at all. BearSSL's+ * only ARM assembly is 32-bit Thumb for Cortex-M0 to M3, with fifteen-bit+ * limbs for cores that have no fast multiplier, and Botan's AArch64 inline+ * assembly is the `mul`/`umulh`/`adds`/`adc` primitive the compiler already+ * emits.+ */+#if defined(__aarch64__) && LIMB_BITS == 64 \+ && (defined(__GNUC__) || defined(__clang__))+/*+ * Four limbs to an iteration, accumulated in two chains rather than one per+ * limb: the low halves of the four products, with the carry coming in, are+ * one run of `adds` and `adcs`, and the high halves shifted up a place are+ * another. The flags carry the whole way through each, which is what the C+ * above cannot say and what it pays for in `cset` and an extra add.+ *+ * The arrangement is the one in Go's crypto/internal/fips140/bigmod+ * (nat_arm64.s, addMulVVWx), which is BSD-3-Clause like this library --+ * cbits/LICENSE.go carries its notice. Written out here in the assembler+ * this file's compiler speaks.+ */+static inline limb_t addmul_1(limb_t *t, const limb_t *a, uint32_t n, limb_t b)+{+ uint64_t carry = 0;+ uint64_t x0, x1, x2, x3, z0, z1, z2, z3;+ uint64_t l0, l1, l2, l3, h0, h1, h2, h3;+ uint64_t blocks = n / 4, left = n % 4;++ if (blocks) {+ __asm__ volatile(+ "1:\n\t"+ "ldp %[x0], %[x1], [%[a]], #16\n\t"+ "ldp %[x2], %[x3], [%[a]], #16\n\t"+ "ldp %[z0], %[z1], [%[t]]\n\t"+ /* the low halves, one place up from the second chain, with+ * the carry that came in */+ "adds %[z0], %[z0], %[c]\n\t"+ "mul %[l1], %[x1], %[b]\n\t"+ "adcs %[z1], %[z1], %[l1]\n\t"+ "mul %[l2], %[x2], %[b]\n\t"+ "ldp %[z2], %[z3], [%[t], #16]\n\t"+ "adcs %[z2], %[z2], %[l2]\n\t"+ "mul %[l3], %[x3], %[b]\n\t"+ "adcs %[z3], %[z3], %[l3]\n\t"+ "umulh %[h3], %[x3], %[b]\n\t"+ "adc %[h3], %[h3], xzr\n\t"+ /* and the high halves, which is where this block's own carry+ * ends up */+ "mul %[l0], %[x0], %[b]\n\t"+ "adds %[z0], %[z0], %[l0]\n\t"+ "umulh %[h0], %[x0], %[b]\n\t"+ "adcs %[z1], %[z1], %[h0]\n\t"+ "umulh %[h1], %[x1], %[b]\n\t"+ "stp %[z0], %[z1], [%[t]], #16\n\t"+ "adcs %[z2], %[z2], %[h1]\n\t"+ "umulh %[h2], %[x2], %[b]\n\t"+ "adcs %[z3], %[z3], %[h2]\n\t"+ "stp %[z2], %[z3], [%[t]], #16\n\t"+ "adc %[c], %[h3], xzr\n\t"+ "subs %[k], %[k], #1\n\t"+ "b.ne 1b\n\t"+ : [a] "+r"(a), [t] "+r"(t), [c] "+r"(carry), [k] "+r"(blocks),+ [x0] "=&r"(x0), [x1] "=&r"(x1), [x2] "=&r"(x2),+ [x3] "=&r"(x3), [z0] "=&r"(z0), [z1] "=&r"(z1),+ [z2] "=&r"(z2), [z3] "=&r"(z3), [l0] "=&r"(l0),+ [l1] "=&r"(l1), [l2] "=&r"(l2), [l3] "=&r"(l3),+ [h0] "=&r"(h0), [h1] "=&r"(h1), [h2] "=&r"(h2),+ [h3] "=&r"(h3)+ : [b] "r"(b)+ : "cc", "memory");+ }+ /* What is left of the row: three limbs, two, or one, each the same two+ * chains cut short. This is not a rare case to be handed back to C --+ * mont_sqr asks for every length from n-1 down to 1, so three rows in+ * four end ragged. Only 4.7% of the limbs in a 1024-bit exponentiation+ * arrive here, but they were the dearer ones, and writing them out is+ * worth the last two per cent in the table above. The three lengths+ * are spelled out rather than run as 2+1, because chaining two short+ * blocks makes the second wait on the first: that costs two thirds of+ * the gain.+ */+ if (left == 3) {+ __asm__ volatile(+ "ldp %[x0], %[x1], [%[a]]\n\t"+ "ldr %[x2], [%[a], #16]\n\t"+ "add %[a], %[a], #24\n\t"+ "ldp %[z0], %[z1], [%[t]]\n\t"+ "ldr %[z2], [%[t], #16]\n\t"+ "adds %[z0], %[z0], %[c]\n\t"+ "mul %[l1], %[x1], %[b]\n\t"+ "adcs %[z1], %[z1], %[l1]\n\t"+ "mul %[l2], %[x2], %[b]\n\t"+ "adcs %[z2], %[z2], %[l2]\n\t"+ "umulh %[h2], %[x2], %[b]\n\t"+ "adc %[h2], %[h2], xzr\n\t"+ "mul %[l0], %[x0], %[b]\n\t"+ "adds %[z0], %[z0], %[l0]\n\t"+ "umulh %[h0], %[x0], %[b]\n\t"+ "adcs %[z1], %[z1], %[h0]\n\t"+ "umulh %[h1], %[x1], %[b]\n\t"+ "stp %[z0], %[z1], [%[t]], #16\n\t"+ "adcs %[z2], %[z2], %[h1]\n\t"+ "str %[z2], [%[t]], #8\n\t"+ "adc %[c], %[h2], xzr\n\t"+ : [a] "+r"(a), [t] "+r"(t), [c] "+r"(carry),+ [x0] "=&r"(x0), [x1] "=&r"(x1), [x2] "=&r"(x2),+ [z0] "=&r"(z0), [z1] "=&r"(z1), [z2] "=&r"(z2),+ [l0] "=&r"(l0), [l1] "=&r"(l1), [l2] "=&r"(l2),+ [h0] "=&r"(h0), [h1] "=&r"(h1), [h2] "=&r"(h2)+ : [b] "r"(b)+ : "cc", "memory");+ } else if (left == 2) {+ __asm__ volatile(+ "ldp %[x0], %[x1], [%[a]], #16\n\t"+ "ldp %[z0], %[z1], [%[t]]\n\t"+ "adds %[z0], %[z0], %[c]\n\t"+ "mul %[l1], %[x1], %[b]\n\t"+ "adcs %[z1], %[z1], %[l1]\n\t"+ "umulh %[h1], %[x1], %[b]\n\t"+ "adc %[h1], %[h1], xzr\n\t"+ "mul %[l0], %[x0], %[b]\n\t"+ "adds %[z0], %[z0], %[l0]\n\t"+ "umulh %[h0], %[x0], %[b]\n\t"+ "adcs %[z1], %[z1], %[h0]\n\t"+ "stp %[z0], %[z1], [%[t]], #16\n\t"+ "adc %[c], %[h1], xzr\n\t"+ : [a] "+r"(a), [t] "+r"(t), [c] "+r"(carry),+ [x0] "=&r"(x0), [x1] "=&r"(x1), [z0] "=&r"(z0),+ [z1] "=&r"(z1), [l0] "=&r"(l0), [l1] "=&r"(l1),+ [h0] "=&r"(h0), [h1] "=&r"(h1)+ : [b] "r"(b)+ : "cc", "memory");+ } else if (left == 1) {+ __asm__ volatile(+ "ldr %[x0], [%[a]], #8\n\t"+ "ldr %[z0], [%[t]]\n\t"+ "mul %[l0], %[x0], %[b]\n\t"+ "adds %[z0], %[z0], %[c]\n\t"+ "umulh %[h0], %[x0], %[b]\n\t"+ "adc %[h0], %[h0], xzr\n\t"+ "adds %[z0], %[z0], %[l0]\n\t"+ "str %[z0], [%[t]], #8\n\t"+ "adc %[c], %[h0], xzr\n\t"+ : [a] "+r"(a), [t] "+r"(t), [c] "+r"(carry),+ [x0] "=&r"(x0), [z0] "=&r"(z0), [l0] "=&r"(l0),+ [h0] "=&r"(h0)+ : [b] "r"(b)+ : "cc", "memory");+ }+ return carry;+}+#else+/* one limb of it, so that the loops below can say how many they take at a+ * time without saying the rest of it four times over */ #define ADDMUL_STEP(k) \ p = (dlimb_t) a[i + (k)] * b + t[i + (k)] + carry; \ t[i + (k)] = (limb_t) p; \@@ -141,6 +323,7 @@ } return carry; }+#endif /* r = t * R^-1 mod m, with t of 2n limbs and destroyed on the way */ static inline void mont_reduce(limb_t *r, limb_t *t, const limb_t *m, limb_t n0,@@ -165,14 +348,33 @@ select_n(r, r, t + n, take & 1, n); } +/* t = a * b, the low n limbs, returning the limb above them: addmul_1 with+ * nothing to add to, for the row of a product that lands on empty space. */+static inline limb_t mul_1(limb_t *t, const limb_t *a, uint32_t n, limb_t b)+{+ limb_t carry = 0;+ uint32_t i;++ for (i = 0; i < n; i++) {+ dlimb_t p = (dlimb_t) a[i] * b + carry;++ t[i] = (limb_t) p;+ carry = (limb_t) (p >> LIMB_BITS);+ }+ return carry;+}+ /* r = a * b * R^-1 mod m, with t of 2n limbs */ static inline void mont_mul(limb_t *r, const limb_t *a, const limb_t *b, const limb_t *m, limb_t n0, uint32_t n, limb_t *t) { uint32_t i; - memset(t, 0, 2 * n * sizeof(limb_t));- for (i = 0; i < n; i++)+ /* Nothing has to be cleared first. The first row lands on empty space+ * and writes t[0 .. n], and every row after it reads t[i .. i+n-1],+ * whose top limb is the one the row before it wrote. */+ t[n] = mul_1(t, a, n, b[0]);+ for (i = 1; i < n; i++) t[n + i] = addmul_1(t + i, a, n, b[i]); mont_reduce(r, t, m, n0, n); }@@ -186,8 +388,14 @@ limb_t carry = 0; uint32_t i; - memset(t, 0, 2 * n * sizeof(limb_t));- for (i = 0; i + 1 < n; i++)+ /* The first row lands on empty space here too, on t[1 .. n], and the+ * rows between them write t[1 .. 2n-2] before any of it is read. The+ * diagonal below is the only reader of the two ends. */+ t[0] = 0;+ t[2 * n - 1] = 0;+ if (n > 1)+ t[n] = mul_1(t + 1, a + 1, n - 1, a[0]);+ for (i = 1; i + 1 < n; i++) t[n + i] = addmul_1(t + i + i + 1, a + i + 1, n - 1 - i, a[i]); shl1(t, 2 * n); /* their sum is under half of what 2n limbs hold */ for (i = 0; i < n; i++) {@@ -201,15 +409,54 @@ mont_reduce(r, t, m, n0, n); } -/* r2 = R^2 mod m, by doubling+/* a = 2a mod m, for an a already under m */+static inline void dbl_mod(limb_t *a, const limb_t *m, uint32_t n, limb_t *tmp)+{+ limb_t carry = shl1(a, n);+ limb_t borrow = sub_n(tmp, a, m, n);++ select_n(a, tmp, a, (carry | (borrow ^ 1)) & 1, n);+}++/* r2 = R^2 mod m, where R is 2^(n * LIMB_BITS) *+ * Doubling the whole way there is 2n * LIMB_BITS steps, and at RSA sizes+ * that is a tenth of the exponentiation it is setting up for. Only the+ * first half of it has to be done a bit at a time.+ *+ * Write a value as 2^(lgR + d) mod m. A Montgomery squaring divides by R,+ * so it takes that to 2(lgR + d) - lgR = lgR + 2d: it doubles d. So double+ * up to R mod m, where d is zero, take one more step to make d one, and then+ * climb to d = lgR by the binary expansion of lgR -- a squaring for each bit+ * and one more doubling where the bit is set. For a 1024-bit modulus that+ * is ten squarings in place of a thousand and twenty-five doublings, and on+ * an Apple M4 that is 2.1 microseconds against 24.7.+ * * Doubling starts at the highest power of two under the modulus rather than * at one, since everything below that power is where doubling would go- * anyway: for a modulus that fills its limbs that is half the steps.+ * anyway: for a modulus that fills its limbs, that first half is one step.+ *+ * What the trip counts depend on is the modulus' length, which is what the+ * doubling loop showed as well, and nothing else about it. */-static inline void mont_r2(limb_t *r2, const limb_t *m, uint32_t n, limb_t *tmp)+/* s2n-bignum's bignum_montifier computes the same constant in assembly, on+ * both architectures, and is the faster of the two by a good margin -- the+ * C cannot form the carry chains it does. It is used where it is built,+ * and the C below is what everywhere else gets and what it is checked+ * against. It needs a scratch buffer of n limbs, which every caller+ * already passes. */+#if defined(CRYPTON_S2N_BIGNUM) && !defined(CRYPTON_NO_MONTIFIER) \+ && (defined(__x86_64__) || defined(__aarch64__)) && LIMB_BITS == 64+#define CRYPTON_MONTIFIER 1+extern void bignum_montifier(uint64_t k, uint64_t *z, const uint64_t *m,+ uint64_t *t);+#endif++static inline void mont_r2_c(limb_t *r2, const limb_t *m, limb_t n0, uint32_t n,+ limb_t *t) {- uint32_t i, k = 0, steps;+ uint32_t lgr = n * LIMB_BITS;+ uint32_t i, k = 0, msb = 0; for (i = n; i > 0 && k == 0; i--) if (m[i - 1] != 0) {@@ -225,12 +472,28 @@ if (k == 0) return; /* a modulus of nothing, which the caller rules out */ r2[(k - 1) / LIMB_BITS] = (limb_t) 1 << ((k - 1) % LIMB_BITS);- steps = 2 * n * LIMB_BITS - (k - 1);- for (i = 0; i < steps; i++) {- limb_t carry = shl1(r2, n);- limb_t borrow = sub_n(tmp, r2, m, n);- select_n(r2, tmp, r2, (carry | (borrow ^ 1)) & 1, n);+ for (i = k - 1; i < lgr; i++)+ dbl_mod(r2, m, n, t);+ /* r2 is R mod m, so d is zero and squaring would leave it there */+ dbl_mod(r2, m, n, t);+ while ((lgr >> (msb + 1)) != 0)+ msb++;+ for (i = msb; i > 0; i--) {+ mont_sqr(r2, r2, m, n0, n, t);+ if ((lgr >> (i - 1)) & 1)+ dbl_mod(r2, m, n, t); }+}++static inline void mont_r2(limb_t *r2, const limb_t *m, limb_t n0, uint32_t n,+ limb_t *t)+{+#ifdef CRYPTON_MONTIFIER+ (void) n0;+ bignum_montifier(n, r2, m, t);+#else+ mont_r2_c(r2, m, n0, n, t);+#endif } /* big-endian bytes into limbs, least significant limb first; anything above
@@ -127,23 +127,6 @@ } #endif -#ifndef ARCH_HAS_MEMORY_ZERO-static inline void memory_zero(void *ptr, uint32_t len)-{- uint32_t *ptr32 = ptr;- uint8_t *ptr8;- int i;-- for (i = 0; i < len / 4; i++)- *ptr32++ = 0;- if (len % 4) {- ptr8 = (uint8_t *) ptr32;- for (i = len % 4; i >= 0; i--)- ptr8[i] = 0;- }-}-#endif- #ifndef ARCH_HAS_ARRAY_COPY32 static inline void array_copy32(uint32_t *d, uint32_t *s, uint32_t nb) {
@@ -0,0 +1,27 @@+/*+ * Erasing memory that the compiler is entitled to decide nobody reads.+ *+ * memset on an object that is about to die -- freed, or a local going out of+ * scope -- is a store to memory nothing can observe, and an optimizer may+ * drop it. That is the whole reason explicit_bzero and memset_s exist.+ * Neither is everywhere, so this writes through a volatile pointer, which the+ * standard says cannot be elided.+ *+ * Use it wherever key material stops being needed. Plain memset is still+ * right for memory that is about to be read again.+ */+#ifndef CRYPTON_BZERO_H+#define CRYPTON_BZERO_H++#include <stddef.h>+#include <stdint.h>++static inline void crypton_bzero(void *p, size_t n)+{+ volatile uint8_t *q = (volatile uint8_t *)p;++ while (n--)+ *q++ = 0;+}++#endif
@@ -51,7 +51,7 @@ const crypton_chacha_state *in); void crypton_chacha_simd_generate(int rounds, uint8_t *dst, const crypton_chacha_state *in);-/* The counters in a group must not carry into d[13], which the block loop+/* The counters in a group must not carry into d[13], which the crypton_chacha_block loop * below handles and the vector one does not; that is one run in 2^29. */ #define CHACHA_SIMD_OK(st, n) ((st)->d[12] <= 0xffffffffU - (uint32_t) (n)) #endif@@ -89,7 +89,7 @@ * How much is worth handing over. On AArch64 the module's vector path * starts at three blocks and below that its scalar path measures level with * the C here, so there is nothing to gain; on x86-64 it is ahead from one- * block, the C there having no vector path until eight.+ * crypton_chacha_block, the C there having no vector path until eight. */ #ifndef CHACHA_ASM_MIN_BLOCKS #ifdef WITH_X86_CHACHA_ASM@@ -109,10 +109,11 @@ #define ALIGNED64(PTR) \ (((uintptr_t)(const void *)(PTR)) % 8 == 0) -static const uint8_t sigma[16] = "expand 32-byte k";-static const uint8_t tau[16] = "expand 16-byte k";+/* sixteen bytes are read; the seventeenth is the string's terminator */+static const uint8_t sigma[17] = "expand 32-byte k";+static const uint8_t tau[17] = "expand 16-byte k"; -static void chacha_core(int rounds, block *out, const crypton_chacha_state *in)+static void chacha_core(int rounds, crypton_chacha_block *out, const crypton_chacha_state *in) { uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; int i;@@ -296,7 +297,7 @@ void crypton_chacha_combine(uint8_t *dst, crypton_chacha_context *ctx, const uint8_t *src, uint32_t bytes) {- block out;+ crypton_chacha_block out; crypton_chacha_state *st; int i; @@ -384,7 +385,7 @@ } /* xor as much as needed */- for (i = 0; i < bytes; i++)+ for (i = 0; i < (int) bytes; i++) dst[i] = src[i] ^ out.b[i]; /* copy the left over in the buffer */@@ -434,7 +435,7 @@ void crypton_chacha_generate(uint8_t *dst, crypton_chacha_context *ctx, uint32_t bytes) { crypton_chacha_state *st;- block out;+ crypton_chacha_block out; int i; if (!bytes)@@ -474,7 +475,7 @@ /* xor new 64-bytes chunks and store the left over if any */ for (; bytes >= 64; bytes -= 64, dst += 64) { /* generate new chunk and update state */- chacha_core(ctx->nb_rounds, (block *) dst, st);+ chacha_core(ctx->nb_rounds, (crypton_chacha_block *) dst, st); uint32_t t0 = le32_to_cpu(st->d[12]); st->d[12] = cpu_to_le32(t0 + 1); if (st->d[12] == 0) {@@ -510,7 +511,7 @@ } /* xor as much as needed */- for (i = 0; i < bytes; i++)+ for (i = 0; i < (int) bytes; i++) dst[i] = out.b[i]; /* copy the left over in the buffer */@@ -524,9 +525,9 @@ void crypton_chacha_generate_simple_block(uint8_t *dst, crypton_chacha_state *st, uint8_t rounds) { if (ALIGNED64(dst)) {- chacha_core(rounds, (block *) dst, st);+ chacha_core(rounds, (crypton_chacha_block *) dst, st); } else {- block out;+ crypton_chacha_block out; int i; chacha_core(rounds, &out, st); for (i = 0; i < 64; ++i) {@@ -544,7 +545,7 @@ void crypton_chacha_random(uint32_t rounds, uint8_t *dst, crypton_chacha_state *st, uint32_t bytes) {- block out;+ crypton_chacha_block out; if (!bytes) return;
@@ -34,9 +34,9 @@ uint64_t q[8]; uint32_t d[16]; uint8_t b[64];-} block;+} crypton_chacha_block; -typedef block crypton_chacha_state;+typedef crypton_chacha_block crypton_chacha_state; typedef struct { crypton_chacha_state st;
@@ -0,0 +1,156 @@+/*+ * Copyright (c) 2026 Kazu Yamamoto+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ * notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ * notice, this list of conditions and the following disclaimer in the+ * documentation and/or other materials provided with the distribution.+ *+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+ * POSSIBILITY OF SUCH DAMAGE.+ */++#include <stdint.h>+#include <string.h>++#include "crypton_chacha.h"+#include "crypton_chachapoly.h"+#include "crypton_poly1305.h"++/* RFC 8439. The one-time Poly1305 key is the first 32 bytes of the ChaCha20+ * keystream at counter 0; a whole 64-byte block is generated so the counter+ * lands on 1, which is where the message starts. */+static void chachapoly_start(crypton_chacha_context *cctx, poly1305_ctx *pctx,+ const uint8_t *key,+ const uint8_t *nonce, uint32_t noncelen)+{+ uint8_t block[64];++ crypton_chacha_init(cctx, 20, 32, key, noncelen, nonce);+ crypton_chacha_generate(block, cctx, sizeof(block));+ crypton_poly1305_init(pctx, (poly1305_key *) block);+ memset(block, 0, sizeof(block));+}++/* Poly1305 over an associated or encrypted part, then zeros up to the next+ * multiple of sixteen. */+static void absorb_padded(poly1305_ctx *pctx, const uint8_t *p, uint32_t len)+{+ static const uint8_t zeros[16] = {0};+ uint32_t rem;++ if (len)+ crypton_poly1305_update(pctx, (uint8_t *) p, len);+ rem = len % 16;+ if (rem)+ crypton_poly1305_update(pctx, (uint8_t *) zeros, 16 - rem);+}++/* The two lengths, little endian, eight bytes each, which is what the tag+ * ends on. */+static void absorb_lengths(poly1305_ctx *pctx, uint32_t aadlen, uint32_t inlen)+{+ uint8_t lens[16];+ int i;++ for (i = 0; i < 8; i++)+ lens[i] = (uint8_t) (((uint64_t) aadlen) >> (8 * i));+ for (i = 0; i < 8; i++)+ lens[8 + i] = (uint8_t) (((uint64_t) inlen) >> (8 * i));+ crypton_poly1305_update(pctx, lens, sizeof(lens));+}++void crypton_chachapoly_encrypt(uint8_t *out, uint8_t *tag, uint32_t taglen,+ const uint8_t *key,+ const uint8_t *nonce, uint32_t noncelen,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *input, uint32_t inlen)+{+ crypton_chacha_context cctx;+ poly1305_ctx pctx;+ poly1305_mac mac;++ chachapoly_start(&cctx, &pctx, key, nonce, noncelen);+ absorb_padded(&pctx, aad, aadlen);+ if (inlen)+ crypton_chacha_combine(out, &cctx, input, inlen);+ /* what the tag covers is the ciphertext, which is now in out */+ absorb_padded(&pctx, out, inlen);+ absorb_lengths(&pctx, aadlen, inlen);+ crypton_poly1305_finalize(mac, &pctx);+ memcpy(tag, mac, taglen);++ memset(&cctx, 0, sizeof(cctx));+ memset(&pctx, 0, sizeof(pctx));+}++/* Shared by the two decrypting entry points: with outtag NULL the tag is+ * compared here and the answer returned, otherwise it is written there. */+static int chachapoly_decrypt(uint8_t *out, const uint8_t *tag, uint32_t taglen,+ uint8_t *outtag, const uint8_t *key,+ const uint8_t *nonce, uint32_t noncelen,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *input, uint32_t inlen)+{+ crypton_chacha_context cctx;+ poly1305_ctx pctx;+ poly1305_mac mac;+ uint8_t diff = 0;+ uint32_t i;++ chachapoly_start(&cctx, &pctx, key, nonce, noncelen);+ absorb_padded(&pctx, aad, aadlen);+ /* here the ciphertext is the input, so the tag can be taken before the+ * plaintext is written and out may alias input */+ absorb_padded(&pctx, input, inlen);+ absorb_lengths(&pctx, aadlen, inlen);+ crypton_poly1305_finalize(mac, &pctx);++ if (inlen)+ crypton_chacha_combine(out, &cctx, input, inlen);++ memset(&cctx, 0, sizeof(cctx));+ memset(&pctx, 0, sizeof(pctx));++ if (outtag) {+ memcpy(outtag, mac, taglen);+ return 1;+ }+ for (i = 0; i < taglen; i++)+ diff |= (uint8_t) (mac[i] ^ tag[i]);+ return diff == 0;+}++int crypton_chachapoly_decrypt(uint8_t *out,+ const uint8_t *tag, uint32_t taglen,+ const uint8_t *key,+ const uint8_t *nonce, uint32_t noncelen,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *input, uint32_t inlen)+{+ return chachapoly_decrypt(out, tag, taglen, NULL, key, nonce, noncelen,+ aad, aadlen, input, inlen);+}++void crypton_chachapoly_decrypt_tag(uint8_t *out, uint8_t *outtag,+ uint32_t taglen, const uint8_t *key,+ const uint8_t *nonce, uint32_t noncelen,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *input, uint32_t inlen)+{+ (void) chachapoly_decrypt(out, NULL, taglen, outtag, key, nonce,+ noncelen, aad, aadlen, input, inlen);+}
@@ -0,0 +1,62 @@+/*+ * Copyright (c) 2026 Kazu Yamamoto+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ * notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ * notice, this list of conditions and the following disclaimer in the+ * documentation and/or other materials provided with the distribution.+ *+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+ * POSSIBILITY OF SUCH DAMAGE.+ */++#ifndef CRYPTON_CHACHAPOLY_H+#define CRYPTON_CHACHAPOLY_H++#include <stdint.h>++/* ChaCha20-Poly1305 (RFC 8439) as one call.+ *+ * The pieces are the ChaCha20 and Poly1305 already here; what these do is+ * hold them together, which the Haskell above used to do at the cost of eight+ * foreign calls and the allocations between them.+ *+ * The nonce is the twelve bytes RFC 8439 defines. taglen is at most 16.+ */++void crypton_chachapoly_encrypt(uint8_t *out, uint8_t *tag, uint32_t taglen,+ const uint8_t *key,+ const uint8_t *nonce, uint32_t noncelen,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *input, uint32_t inlen);++/* Decrypt and compare, a byte at a time over the whole tag whichever way the+ * answer goes. Returns non-zero when the tag matched. */+int crypton_chachapoly_decrypt(uint8_t *out,+ const uint8_t *tag, uint32_t taglen,+ const uint8_t *key,+ const uint8_t *nonce, uint32_t noncelen,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *input, uint32_t inlen);++/* Decrypt and hand the computed tag back rather than comparing it. */+void crypton_chachapoly_decrypt_tag(uint8_t *out, uint8_t *outtag,+ uint32_t taglen, const uint8_t *key,+ const uint8_t *nonce, uint32_t noncelen,+ const uint8_t *aad, uint32_t aadlen,+ const uint8_t *input, uint32_t inlen);++#endif
@@ -32,6 +32,23 @@ #include <stdint.h> /*+ * PE has no way to say "hidden": every symbol in an object is local to the+ * image unless something exports it, which is what hidden asks for+ * elsewhere, so nothing is lost by dropping the attribute here. Saying it+ * anyway is not harmless -- the gcc that GHC 9.2 ships for Windows parses+ * the attribute, discards it and warns, and it is the only warning crypton's+ * own code produces anywhere in the CI matrix. Measured on mingw gcc 13.2.0+ * and clang 14.0.6 (the compiler GHC 9.4 and later ship): gcc warns for+ * "hidden" and is silent for "default", clang is silent for both, which is+ * why the vendored decaf and argon2 headers ask for "default" unnoticed.+ */+#if defined(_WIN32) || defined(__CYGWIN__)+#define CRYPTON_HIDDEN+#else+#define CRYPTON_HIDDEN __attribute__((visibility("hidden")))+#endif++/* * The word the assembly reads; crypton_cpu.h says what is in it. Hidden, * so that the reference to it from the assembly resolves at link time in a * shared object as well as a static one. The SHA-256 bit is set by@@ -39,10 +56,226 @@ * instructions. */ #ifdef CRYPTON_ARM_ASM-__attribute__((visibility("hidden"))) unsigned int crypton_armcap_P =+CRYPTON_HIDDEN unsigned int crypton_armcap_P = CRYPTON_ARMCAP_NEON; #endif +#if defined(__aarch64__) || defined(__arm__)+#if defined(__APPLE__)+#include <sys/sysctl.h>+#elif defined(__linux__)+#include <sys/auxv.h>+#include <asm/hwcap.h>+#elif defined(__FreeBSD__)+#include <sys/auxv.h>+#endif++/*+ * The bit positions are the ARM ELF ABI's, so every system that reports+ * through the auxiliary vector agrees on them. What differs is the tag --+ * AT_HWCAP is 16 on Linux and 25 on FreeBSD -- and that comes from each+ * system's own header, which is why no tag is written out here. Defined+ * only where the system's headers did not define them, the way compiler-rt+ * does it, so that a system which reports through the auxiliary vector+ * without shipping the ARM names still compiles.+ *+ * The two execution states do not share a word or an order. AArch64 puts+ * these in AT_HWCAP; AArch32 has filled that word with older features and+ * puts the cryptographic ones in AT_HWCAP2, starting again from bit zero.+ */+#if defined(__aarch64__)+#ifndef HWCAP_AES+#define HWCAP_AES (1 << 3)+#endif+#ifndef HWCAP_PMULL+#define HWCAP_PMULL (1 << 4)+#endif+#ifndef HWCAP_SHA1+#define HWCAP_SHA1 (1 << 5)+#endif+#ifndef HWCAP_SHA2+#define HWCAP_SHA2 (1 << 6)+#endif+#ifndef HWCAP_SHA3+#define HWCAP_SHA3 (1 << 17)+#endif+#ifndef HWCAP_SHA512+#define HWCAP_SHA512 (1 << 21)+#endif+#else+#ifndef HWCAP2_AES+#define HWCAP2_AES (1 << 0)+#endif+#ifndef HWCAP2_PMULL+#define HWCAP2_PMULL (1 << 1)+#endif+#ifndef HWCAP2_SHA1+#define HWCAP2_SHA1 (1 << 2)+#endif+#ifndef HWCAP2_SHA2+#define HWCAP2_SHA2 (1 << 3)+#endif+#endif++#if defined(__APPLE__)+static int apple_has(const char *name)+{+ int v = 0;+ size_t n = sizeof(v);++ if (sysctlbyname(name, &v, &n, NULL, 0) != 0)+ return 0;+ return v != 0;+}+#endif++/*+ * Systems still answering zero, and what each would need:+ *+ * OpenBSD, NetBSD sysctl on machdep.id_aa64isar0, which hands out the+ * ID_AA64ISAR0_EL1 fields rather than a HWCAP word, so+ * it is a different shape of answer rather than another+ * tag.+ * Windows on ARM IsProcessorFeaturePresent with+ * PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE, which covers+ * AES, PMULL, SHA-1 and SHA-256 as one bit and says+ * nothing about SHA-512 or SHA-3. An ARM64 Windows+ * guest answers 1 to it, but GHC has no native ARM64+ * Windows target: there it builds x86-64 and the+ * emulator reports AES-NI, so this file is not reached.+ *+ * Neither is written here because neither can be built and run to see it+ * work, and an untested answer about whether a machine has AES is worse+ * than the honest zero it replaces.+ */+unsigned int crypton_arm_features(void)+{+ static unsigned int features;+ static int resolved;++ if (!resolved) {+ unsigned int f = 0;+#if defined(__APPLE__)+ /* AES, PMULL, SHA-1 and SHA-256 are not optional on Apple+ * silicon. The two later ones are. */+ f = CRYPTON_ARM_AES | CRYPTON_ARM_PMULL+ | CRYPTON_ARM_SHA1 | CRYPTON_ARM_SHA2;+ if (apple_has("hw.optional.arm.FEAT_SHA512"))+ f |= CRYPTON_ARM_SHA512;+ if (apple_has("hw.optional.arm.FEAT_SHA3"))+ f |= CRYPTON_ARM_SHA3;+#elif defined(__aarch64__)+ unsigned long cap = 0;++#if defined(__linux__)+ cap = getauxval(AT_HWCAP);+#elif defined(__FreeBSD__)+ if (elf_aux_info(AT_HWCAP, &cap, sizeof(cap)) != 0)+ cap = 0;+#endif+ if (cap & HWCAP_AES) f |= CRYPTON_ARM_AES;+ if (cap & HWCAP_PMULL) f |= CRYPTON_ARM_PMULL;+ if (cap & HWCAP_SHA1) f |= CRYPTON_ARM_SHA1;+ if (cap & HWCAP_SHA2) f |= CRYPTON_ARM_SHA2;+ if (cap & HWCAP_SHA512) f |= CRYPTON_ARM_SHA512;+ if (cap & HWCAP_SHA3) f |= CRYPTON_ARM_SHA3;+#else+ /* AArch32: the second word, and nothing later than SHA-256 to+ * ask about */+ unsigned long cap = 0;++#if defined(__linux__)+ cap = getauxval(AT_HWCAP2);+#elif defined(__FreeBSD__)+ if (elf_aux_info(AT_HWCAP2, &cap, sizeof(cap)) != 0)+ cap = 0;+#endif+ if (cap & HWCAP2_AES) f |= CRYPTON_ARM_AES;+ if (cap & HWCAP2_PMULL) f |= CRYPTON_ARM_PMULL;+ if (cap & HWCAP2_SHA1) f |= CRYPTON_ARM_SHA1;+ if (cap & HWCAP2_SHA2) f |= CRYPTON_ARM_SHA2;+#endif+ features = f;+ resolved = 1;+ }+ return features;+}+#endif /* __aarch64__ || __arm__ */++#if defined(__powerpc64__) || defined(__PPC64__)+#if defined(__linux__)+#include <sys/auxv.h>+#elif defined(__FreeBSD__)+#include <sys/auxv.h>++#endif++/*+ * PPC_FEATURE2_VEC_CRYPTO, from the Power ELF ABI. Defined here only where+ * the system's headers did not, so that a system reporting through the+ * auxiliary vector without shipping the name still compiles.+ */+#ifndef PPC_FEATURE2_VEC_CRYPTO+#define PPC_FEATURE2_VEC_CRYPTO 0x02000000+#endif++unsigned int crypton_ppc_features(void)+{+ static unsigned int features;+ static int resolved;++ if (!resolved) {+ unsigned long cap = 0;++#if defined(__linux__)+ cap = getauxval(AT_HWCAP2);+#elif defined(__FreeBSD__)+ if (elf_aux_info(AT_HWCAP2, &cap, sizeof(cap)) != 0)+ cap = 0;+#endif+ features = (cap & PPC_FEATURE2_VEC_CRYPTO)+ ? CRYPTON_PPC_VCRYPTO : 0;+ resolved = 1;+ }+ return features;+}+#endif /* __powerpc64__ */++/*+ * For testing on a machine whose CPUID says less than its core executes, and+ * for nothing else: each of these makes the detection below report a+ * feature it did not find.+ *+ * CRYPTON_CPU_TESTING_ADX BMI2 and ADX+ * CRYPTON_CPU_TESTING_SHA_NI the SHA extensions+ * CRYPTON_CPU_TESTING_VAES VAES and VPCLMULQDQ, 256-bit+ *+ * A hypervisor may show a guest an older processor model than the host's so+ * that the guest can be moved to another host, and the instructions it hides+ * then still run. That is the only place this is for: forcing a path that+ * CPUID would not choose, to measure it or to test it, on a machine where the+ * instructions have been seen to execute. Anywhere they do not, the first+ * use is a SIGILL -- which is the bug #317 fixed, made on purpose.+ *+ * What the operating system has to agree to is still asked. VAES works in+ * the wide registers, so it is assumed only where AVX2 was found, which+ * means XCR0 says those are saved; the SHA extensions still want SSSE3 and+ * SSE4.1 to have been found, as the detection asks. Nothing 512-bit can be+ * assumed: whether the operating system saves that state is not something a+ * build can promise.+ *+ * The library is never built with these, and a build that has one says so.+ */+#if defined(CRYPTON_CPU_TESTING_ADX) || defined(CRYPTON_CPU_TESTING_SHA_NI) \+ || defined(CRYPTON_CPU_TESTING_VAES)+/* The code below asks for each switch by its own name, which comes from the+ * command line and so is seen everywhere in the file. It once asked for one+ * umbrella name defined beside the first function that read it -- and the+ * capability vector the assembly reads is filled earlier in the file than+ * that, so the SHA bit never reached it, without a word from the compiler. */+#warning "CRYPTON_CPU_TESTING_*: features assumed, not detected"+#endif+ #ifdef ARCH_X86 static void cpuid(uint32_t info, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) {@@ -101,7 +334,7 @@ } #ifdef CRYPTON_X86_ASM-__attribute__((visibility("hidden"))) unsigned int crypton_ia32cap_P[4];+CRYPTON_HIDDEN unsigned int crypton_ia32cap_P[4]; /* * The AVX-512 bits of leaf 7 EBX -- F, DQ, IFMA, PF, ER, CD, BW and VL,@@ -169,6 +402,16 @@ } if (!(f & CRYPTON_X86_AVX2)) leaf7_ebx &= ~(1u << 5);+ /* what the testing switches assumed, told to the assembly as+ * well: its SHA-256 reads the SHA bit here, not the word */+#ifdef CRYPTON_CPU_TESTING_SHA_NI+ if (f & CRYPTON_X86_SHA_NI)+ leaf7_ebx |= 1u << 29;+#endif+#ifdef CRYPTON_CPU_TESTING_ADX+ if (f & CRYPTON_X86_ADX)+ leaf7_ebx |= (1u << 8) | (1u << 19);+#endif crypton_ia32cap_P[2] = leaf7_ebx & ~IA32CAP_AVX512; resolved = 1;@@ -182,13 +425,23 @@ static uint32_t features = 0; if (!resolved) {- uint32_t eax, ebx, ecx, edx, leaf1, maxleaf, f = 0;+ uint32_t eax, ebx, ecx, edx, leaf1, maxleaf, family, f = 0;+ int amd; cpuid(0, &eax, &ebx, &ecx, &edx); maxleaf = eax;+ /* "AuthenticAMD" arrives as EBX, EDX, ECX in that order */+ amd = (ebx == 0x68747541 && edx == 0x69746e65+ && ecx == 0x444d4163); cpuid(1, &eax, &ebx, &ecx, &edx); leaf1 = ecx;+ /* the family is the base one, and the extended field is+ * added to it only when the base reads 0xf, which is how+ * every AMD Zen part reports */+ family = (eax >> 8) & 0xf;+ if (family == 0xf)+ family += (eax >> 20) & 0xff; if (leaf1 & (1 << 9)) f |= CRYPTON_X86_SSSE3; if (leaf1 & (1 << 1))@@ -223,7 +476,62 @@ if ((ebx & (1 << 5)) && (leaf1 & (1 << 27)) && (leaf1 & (1 << 28)) && ((xcr0() & 6) == 6)) f |= CRYPTON_X86_AVX2;+ /* BMI2 for MULX and ADX for ADCX/ADOX. Both are+ * wanted together and neither touches vector state,+ * so there is nothing to ask the operating system */+ if ((ebx & (1 << 8)) && (ebx & (1 << 19)))+ f |= CRYPTON_X86_ADX;+ /* VAES and VPCLMULQDQ, leaf 7 ECX bits 9 and 10.+ * They are wanted together -- one without the other+ * leaves half of AES-GCM narrow -- and they need the+ * wide registers, so AVX2 has to have answered first,+ * which settles the operating system's part. */+ if ((ecx & (1 << 9)) && (ecx & (1 << 10))+ && (f & CRYPTON_X86_AVX2))+ f |= CRYPTON_X86_VAES;+ /* The same two instructions in their 512-bit form,+ * which wants AVX-512 F, BW and VL as well -- and+ * three more bits of XCR0, for the mask registers and+ * the two upper halves of the vector state. A+ * machine can report the instructions and still fault+ * on them when the operating system has not said it+ * saves that state, which is what those bits are. */+ if ((f & CRYPTON_X86_VAES)+ && (ebx & (1 << 16)) && (ebx & (1u << 30))+ && (ebx & (1u << 31))+ && ((xcr0() & 0xe6) == 0xe6)+ /* Not on Zen 4, which is AMD family 19h with+ * AVX-512: there the 512-bit instructions are two+ * 256-bit passes through a 256-bit datapath, so+ * they carry the wider encoding for none of the+ * throughput, and AES-GCM measures 0.6 to 3+ * per cent slower than the 256-bit path. Zen 5+ * is family 1Ah and does have the wide datapath,+ * where the same code is half as fast again;+ * Zen 3, the other family 19h part, has no+ * AVX-512 at all and never reaches here. */+ && !(amd && family == 0x19))+ f |= CRYPTON_X86_VAES512;+ /* IFMA (bit 21) with F (16) and VL (31), and the same+ * AVX-512 state. Zen 4 is not left out here: RSA's+ * multiplication uses the 256-bit form. */+ if ((f & CRYPTON_X86_AVX2)+ && (ebx & (1 << 16)) && (ebx & (1 << 21))+ && (ebx & (1u << 31))+ && ((xcr0() & 0xe6) == 0xe6))+ f |= CRYPTON_X86_IFMA; }+#ifdef CRYPTON_CPU_TESTING_ADX+ f |= CRYPTON_X86_ADX;+#endif+#ifdef CRYPTON_CPU_TESTING_SHA_NI+ if ((leaf1 & (1 << 9)) && (leaf1 & (1 << 19)))+ f |= CRYPTON_X86_SHA_NI;+#endif+#ifdef CRYPTON_CPU_TESTING_VAES+ if (f & CRYPTON_X86_AVX2)+ f |= CRYPTON_X86_VAES;+#endif features = f; resolved = 1; }@@ -250,3 +558,110 @@ #endif #endif++/*+ * What Crypto.System.CPU reports.+ *+ * The numbers are that module's, and this answers for them. The old shape+ * was the other way round -- Haskell read crypton_aes.c's two-entry array by+ * the Enum index of its own constructors -- which tied the list of names to+ * the indices of an array that had no reason to grow, and so it never did.+ *+ * Nothing here is cached: every answer is either a static array filled by a+ * constructor, a value resolved once and remembered by the function that+ * owns it, or a runtime check that does its own remembering. Haskell calls+ * this once, for a CAF.+ */+uint8_t *crypton_aes_cpu_init(void);++#ifdef WITH_ARMV8_CRYPTO+int crypton_aes_armv8_available(void);+int crypton_aes_armv8_pmull_available(void);+#endif+#ifdef WITH_ARMV8_SHA1+extern int crypton_sha1_armv8_available(void);+#endif+#ifdef WITH_ARMV8_SHA2+extern int crypton_sha256_armv8_available(void);+#endif+#ifdef WITH_ARMV8_SHA512+extern int crypton_sha512_armv8_available(void);+#endif++/* Keep in step with Crypto/System/CPU.hs, which is where these are named.+ * 2 is missing: it was RDRAND, which crypton no longer dispatches on. The+ * number is left out rather than reused, so that the rest keep the values+ * they had. */+#define OPT_AESNI 0+#define OPT_PCLMUL 1+#define OPT_SSSE3 3+#define OPT_AVX 4+#define OPT_AVX2 5+#define OPT_SHANI 6+#define OPT_MOVBE 7+#define OPT_ADX 8+#define OPT_VAES 9+#define OPT_VAES512 10+#define OPT_NEON 11+#define OPT_ARMAES 12+#define OPT_ARMPMULL 13+#define OPT_ARMSHA1 14+#define OPT_ARMSHA2 15+#define OPT_ARMSHA512 16+#define OPT_PPCAES 17+#define OPT_PPCVPMSUM 18+#define OPT_IFMA 19++int crypton_cpu_option(unsigned int option)+{+#ifdef ARCH_X86+ uint32_t f = crypton_x86_simd_features();++ switch (option) {+ case OPT_AESNI: return crypton_aes_cpu_init()[CPU_AESNI] != 0;+ case OPT_PCLMUL: return crypton_aes_cpu_init()[CPU_PCLMUL] != 0;+ case OPT_SSSE3: return (f & CRYPTON_X86_SSSE3) != 0;+ case OPT_AVX: return (f & CRYPTON_X86_AVX) != 0;+ case OPT_AVX2: return (f & CRYPTON_X86_AVX2) != 0;+ case OPT_SHANI: return (f & CRYPTON_X86_SHA_NI) != 0;+ case OPT_MOVBE: return (f & CRYPTON_X86_MOVBE) != 0;+ case OPT_ADX: return (f & CRYPTON_X86_ADX) != 0;+ case OPT_VAES: return (f & CRYPTON_X86_VAES) != 0;+ case OPT_VAES512: return (f & CRYPTON_X86_VAES512) != 0;+ case OPT_IFMA: return (f & CRYPTON_X86_IFMA) != 0;+ default: return 0;+ }+#else+ switch (option) {+ /* NEON is not optional on AArch64, and crypton_armcap_P is set from+ * the start for it. Where there is no ARM assembly at all there is+ * nothing to say. */+#ifdef CRYPTON_ARM_ASM+ case OPT_NEON: return (crypton_armcap_P & CRYPTON_ARMCAP_NEON) != 0;+#endif+#ifdef WITH_ARMV8_CRYPTO+ /* The array rather than the check: it is what the branch table was+ * actually built from, so it says what will run, not merely what the+ * processor has. */+ case OPT_ARMAES: return crypton_aes_cpu_init()[CPU_AESNI] != 0;+ case OPT_ARMPMULL: return crypton_aes_cpu_init()[CPU_PCLMUL] != 0;+#endif+#ifdef WITH_ARMV8_SHA1+ case OPT_ARMSHA1: return crypton_sha1_armv8_available() != 0;+#endif+#ifdef WITH_ARMV8_SHA2+ case OPT_ARMSHA2: return crypton_sha256_armv8_available() != 0;+#endif+#ifdef WITH_ARMV8_SHA512+ case OPT_ARMSHA512: return crypton_sha512_armv8_available() != 0;+#endif+#ifdef WITH_PPC8_CRYPTO+ /* The array rather than the check, for the same reason as the ARM pair+ * above: it says what the branch table was built from. */+ case OPT_PPCAES: return crypton_aes_cpu_init()[CPU_AESNI] != 0;+ case OPT_PPCVPMSUM: return crypton_aes_cpu_init()[CPU_PCLMUL] != 0;+#endif+ default: return 0;+ }+#endif+}
@@ -49,6 +49,25 @@ * in, and the byte-swapping load it reads the message with */ #define CRYPTON_X86_AVX 16 #define CRYPTON_X86_MOVBE 32+/* MULX, ADCX and ADOX together: the two independent carry chains the+ * vendored s2n-bignum assembly wants. They are general-purpose register+ * instructions, so unlike the vector ones above they ask nothing of the+ * operating system. */+#define CRYPTON_X86_ADX 64+/* The AES and carry-less multiply instructions in their 256-bit form, which+ * do two blocks where the 128-bit ones do one. They are VEX-encoded and use+ * the vector registers AVX2 already needs the operating system to save, so+ * they ask nothing further of it -- but AVX2 itself is asked about, since+ * without it there is nowhere to put them. */+#define CRYPTON_X86_VAES 128+/* The same pair in their 512-bit form, four blocks to an instruction. These+ * are EVEX-encoded and need the AVX-512 state as well, which is three more+ * bits of XCR0 than AVX2 wants: the mask registers and the two upper halves+ * of the vector registers. */+#define CRYPTON_X86_VAES512 256+/* AVX-512 IFMA, the 52-bit multiply-adds, with F and VL for the 256-bit form+ * RSA uses them in: EVEX-encoded, so they want the AVX-512 state saved too. */+#define CRYPTON_X86_IFMA 512 #ifdef ARCH_X86 uint32_t crypton_x86_simd_features(void); #endif@@ -81,6 +100,64 @@ #define CRYPTON_ARMCAP_SHA256 (1 << 4) extern unsigned int crypton_armcap_P; #endif++/*+ * Which of the optional ARMv8 instruction sets this processor has.+ *+ * Asked here rather than in each file that wants one. Five files used to+ * carry the same three-way conditional -- Apple, Linux, and otherwise zero+ * -- and the "otherwise" is not a statement about the processor but about+ * which systems someone had thought of. It is what left FreeBSD running+ * the table-driven AES and the C SHA on hardware that has the+ * instructions. In one place the next system is added once.+ *+ * AArch32 answers here too. It has the same AES, PMULL, SHA-1 and SHA-256+ * instructions, reports them in a different word of the auxiliary vector,+ * and has no SHA-512 or SHA-3 to report at all -- those two are AArch64's+ * alone, so the bits exist and are never set.+ */+#if defined(__aarch64__) || defined(__arm__)+#define CRYPTON_ARM_AES (1u << 0)+#define CRYPTON_ARM_PMULL (1u << 1)+#define CRYPTON_ARM_SHA1 (1u << 2)+#define CRYPTON_ARM_SHA2 (1u << 3)+#define CRYPTON_ARM_SHA512 (1u << 4)+#define CRYPTON_ARM_SHA3 (1u << 5)+unsigned int crypton_arm_features(void);+#endif++/*+ * Which of the optional PowerISA instruction sets this processor has.+ *+ * One bit so far: the vector AES and the vector carry-less multiply that+ * PowerISA 2.07 brought and POWER8 was the first to implement. The system+ * reports it in the second capability word, as AArch32 does, and with its+ * own numbering again.+ */+#if defined(__powerpc64__) || defined(__PPC64__)+#define CRYPTON_PPC_VCRYPTO (1u << 0)+unsigned int crypton_ppc_features(void);+#endif++/*+ * The two slots of the array crypton_aes.c fills and crypton_aes_cpu_init+ * hands out. Here rather than in that file because crypton_cpu.c reads+ * them too, to answer for Crypto.System.CPU.+ */+#define CPU_AESNI 0+#define CPU_PCLMUL 1+#define CPU_OPTION_COUNT 2++/*+ * One question at a time, numbered the way Crypto.System.CPU numbers its+ * ProcessorOption rather than the way any array here is indexed. The+ * numbering is the module's to choose and this answers for it; reading an+ * array by the Haskell constructor's Enum index is what kept that type at+ * three names. Returns 1 if the processor has it and crypton was built to+ * use it, 0 otherwise -- including for anything this does not know, so an+ * older library answers a newer caller rather than failing to link.+ */+int crypton_cpu_option(unsigned int option); #ifdef USE_AESNI void crypton_aesni_initialize_hw(void (*init_table)(int, int));
@@ -23,8 +23,12 @@ */ #include <stdlib.h> #include <crypton_bignum.h>+#include <crypton_bzero.h> #include <crypton_ecc.h> #include <crypton_powm.h>+#ifdef CRYPTON_S2N_BIGNUM+#include <crypton_ecc_s2n.h>+#endif /* four bits of scalar per window, so a table of sixteen and no leftover * bits: a byte holds exactly two windows */@@ -220,12 +224,15 @@ static void ctx_free(curve_ctx *c) {+ /* crypton_bzero rather than memset: this memory is freed on the next+ * line, and a store to memory about to die is one an optimizer may+ * drop. Both buffers have held scalars. */ if (c->space != NULL) {- memset(c->space, 0, c->words * sizeof(limb_t));+ crypton_bzero(c->space, c->words * sizeof(limb_t)); free(c->space); } if (c->bytes != NULL) {- memset(c->bytes, 0, 2 * c->plen);+ crypton_bzero(c->bytes, 2 * c->plen); free(c->bytes); } c->space = NULL;@@ -284,10 +291,10 @@ ctx_free(c); return -1; }- mont_r2(c->r2, mp, n, mont_t);+ c->f.n0 = mont_n0(mp[0]);+ mont_r2(c->r2, mp, c->f.n0, n, mont_t); c->f.n = n;- c->f.n0 = mont_n0(mp[0]); c->f.p = mp; c->f.a = ma; c->f.b3 = mb3;@@ -411,6 +418,20 @@ curve_ctx c; uint32_t n, i, j; int ret = -1;++#ifdef CRYPTON_S2N_BIGNUM+ /* Two of the curves that reach here have hand-written assembly, six+ * to ten times faster than what follows; see cbits/s2n/README.md.+ * Anything else, including those two named with a different a or b,+ * goes on down. */+ {+ int s2n_ret;++ if (crypton_s2n_ecc_mul(&s2n_ret, outx, outy, px, py, k, klen,+ a, b, p, plen))+ return s2n_ret;+ }+#endif if (klen == 0 || ctx_init(&c, a, b, p, plen) != 0) return -1;
@@ -0,0 +1,204 @@+#include <string.h>++#include "crypton_ecc_s2n.h"+#include "crypton_ecc_s2n_curves.h"+#include "crypton_cpu.h"++/* P-384, Montgomery domain, six words a coordinate */+extern void p384_montjscalarmul(uint64_t *res, const uint64_t *s, const uint64_t *p);+extern void p384_montjscalarmul_alt(uint64_t *res, const uint64_t *s, const uint64_t *p);+extern void bignum_tomont_p384(uint64_t *z, const uint64_t *x);+extern void bignum_tomont_p384_alt(uint64_t *z, const uint64_t *x);+extern void bignum_deamont_p384(uint64_t *z, const uint64_t *x);+extern void bignum_deamont_p384_alt(uint64_t *z, const uint64_t *x);+extern void bignum_montmul_p384(uint64_t *z, const uint64_t *x, const uint64_t *y);+extern void bignum_montmul_p384_alt(uint64_t *z, const uint64_t *x, const uint64_t *y);+extern void bignum_montsqr_p384(uint64_t *z, const uint64_t *x);+extern void bignum_montsqr_p384_alt(uint64_t *z, const uint64_t *x);+extern void bignum_montinv_p384(uint64_t *z, const uint64_t *x);++/* P-521, ordinary values, nine words a coordinate */+extern void p521_jscalarmul(uint64_t *res, const uint64_t *s, const uint64_t *p);+extern void p521_jscalarmul_alt(uint64_t *res, const uint64_t *s, const uint64_t *p);+extern void bignum_mul_p521(uint64_t *z, const uint64_t *x, const uint64_t *y);+extern void bignum_mul_p521_alt(uint64_t *z, const uint64_t *x, const uint64_t *y);+extern void bignum_sqr_p521(uint64_t *z, const uint64_t *x);+extern void bignum_sqr_p521_alt(uint64_t *z, const uint64_t *x);+extern void bignum_inv_p521(uint64_t *z, const uint64_t *x);++/* One flavour or the other, all the way through: on x86-64 the plain form+ * wants MULX, ADCX and ADOX and _alt is the fallback, so mixing them would+ * fault on a machine without those. */+struct p384_asm {+ void (*tomont)(uint64_t *, const uint64_t *);+ void (*deamont)(uint64_t *, const uint64_t *);+ void (*montmul)(uint64_t *, const uint64_t *, const uint64_t *);+ void (*montsqr)(uint64_t *, const uint64_t *);+ void (*jscalarmul)(uint64_t *, const uint64_t *, const uint64_t *);+};+struct p521_asm {+ void (*mul)(uint64_t *, const uint64_t *, const uint64_t *);+ void (*sqr)(uint64_t *, const uint64_t *);+ void (*jscalarmul)(uint64_t *, const uint64_t *, const uint64_t *);+};++static const struct p384_asm p384_std = {+ bignum_tomont_p384, bignum_deamont_p384, bignum_montmul_p384,+ bignum_montsqr_p384, p384_montjscalarmul+};+static const struct p384_asm p384_alt = {+ bignum_tomont_p384_alt, bignum_deamont_p384_alt,+ bignum_montmul_p384_alt, bignum_montsqr_p384_alt,+ p384_montjscalarmul_alt+};+static const struct p521_asm p521_std = {+ bignum_mul_p521, bignum_sqr_p521, p521_jscalarmul+};+static const struct p521_asm p521_alt = {+ bignum_mul_p521_alt, bignum_sqr_p521_alt, p521_jscalarmul_alt+};++/* The same question as for P-256, answered the same way; see+ * cbits/p256/p256_s2n.c. */+static int use_alt(void)+{+#if defined(__aarch64__) || defined(__arm64__)+#ifdef __APPLE__+ return 1;+#else+ return 0;+#endif+#else+ return (crypton_x86_simd_features() & CRYPTON_X86_ADX) == 0;+#endif+}++#define MAXWORDS 9++static void be_to_le64(uint64_t *w, const uint8_t *b, uint32_t len)+{+ uint32_t i;++ for (i = 0; i < MAXWORDS; i++)+ w[i] = 0;+ for (i = 0; i < len; i++) {+ uint32_t pos = len - 1 - i;+ w[pos / 8] |= (uint64_t)b[i] << (8 * (pos % 8));+ }+}++static void le64_to_be(uint8_t *b, uint32_t len, const uint64_t *w)+{+ uint32_t i;++ for (i = 0; i < len; i++)+ b[len - 1 - i] = (uint8_t)(w[i / 8] >> (8 * (i % 8)));+}++static int is_zero(const uint64_t *w, int words)+{+ uint64_t acc = 0;+ int i;++ for (i = 0; i < words; i++)+ acc |= w[i];+ return acc == 0;+}++static int mul_p384(uint8_t *outx, uint8_t *outy, const uint8_t *px,+ const uint8_t *py, const uint8_t *k, uint32_t klen)+{+ const struct p384_asm *f = use_alt() ? &p384_alt : &p384_std;+ uint64_t pt[18], res[18], sc[MAXWORDS], t[MAXWORDS];+ uint64_t zi[6], zi2[6], zi3[6], num[6];+ static const uint64_t one[6] = {1, 0, 0, 0, 0, 0};++ be_to_le64(t, px, P384_PLEN);+ f->tomont(pt, t);+ be_to_le64(t, py, P384_PLEN);+ f->tomont(pt + 6, t);+ f->tomont(pt + 12, one);+ be_to_le64(sc, k, klen);++ f->jscalarmul(res, sc, pt);+ if (is_zero(res + 12, 6))+ return 1;++ /* affine again: x = X/Z^2, y = Y/Z^3, with the inverse taken in the+ * Montgomery domain so that it lands where the rest of these are */+ bignum_montinv_p384(zi, res + 12);+ f->montsqr(zi2, zi);+ f->montmul(zi3, zi2, zi);+ f->montmul(num, res, zi2);+ f->deamont(t, num);+ le64_to_be(outx, P384_PLEN, t);+ f->montmul(num, res + 6, zi3);+ f->deamont(t, num);+ le64_to_be(outy, P384_PLEN, t);+ return 0;+}++static int mul_p521(uint8_t *outx, uint8_t *outy, const uint8_t *px,+ const uint8_t *py, const uint8_t *k, uint32_t klen)+{+ const struct p521_asm *f = use_alt() ? &p521_alt : &p521_std;+ uint64_t pt[27], res[27], sc[MAXWORDS], t[MAXWORDS];+ uint64_t zi[9], zi2[9], zi3[9];+ static const uint64_t one[9] = {1, 0, 0, 0, 0, 0, 0, 0, 0};++ be_to_le64(pt, px, P521_PLEN);+ be_to_le64(pt + 9, py, P521_PLEN);+ memcpy(pt + 18, one, sizeof(one));+ be_to_le64(sc, k, klen);++ f->jscalarmul(res, sc, pt);+ if (is_zero(res + 18, 9))+ return 1;++ bignum_inv_p521(zi, res + 18);+ f->sqr(zi2, zi);+ f->mul(zi3, zi2, zi);+ f->mul(t, res, zi2);+ le64_to_be(outx, P521_PLEN, t);+ f->mul(t, res + 9, zi3);+ le64_to_be(outy, P521_PLEN, t);+ return 0;+}++int crypton_s2n_ecc_mul(int *ret, uint8_t *outx, uint8_t *outy,+ const uint8_t *px, const uint8_t *py,+ const uint8_t *k, uint32_t klen,+ const uint8_t *a, const uint8_t *b,+ const uint8_t *p, uint32_t plen)+{+ int is384;++ if (plen == P384_PLEN && memcmp(p, P384_P, plen) == 0+ && memcmp(a, P384_A, plen) == 0 && memcmp(b, P384_B, plen) == 0)+ is384 = 1;+ else if (plen == P521_PLEN && memcmp(p, P521_P, plen) == 0+ && memcmp(a, P521_A, plen) == 0+ && memcmp(b, P521_B, plen) == 0)+ is384 = 0;+ else+ return 0; /* some other curve; the C answers it */++ /* A scalar longer than the prime is not something the word arrays+ * here hold, and it is not what any caller of these two curves+ * sends, so leave it to the C rather than grow a second path. */+ if (klen == 0 || klen > plen)+ return 0;++ /* The C does not require the coordinates to be reduced -- it takes+ * whatever fits in its limbs and lets the conversion to Montgomery+ * form reduce it. Rather than carry a reduction here to match, hand+ * that case back: nothing sends one, and this way the two cannot+ * disagree about it. (A differential test against the C found this;+ * the first version of this check returned -1 and was wrong.) */+ if (memcmp(px, p, plen) >= 0 || memcmp(py, p, plen) >= 0)+ return 0;++ *ret = is384 ? mul_p384(outx, outy, px, py, k, klen)+ : mul_p521(outx, outy, px, py, k, klen);+ return 1;+}
@@ -0,0 +1,27 @@+/*+ * P-384 and P-521 through the vendored s2n-bignum assembly, for the two+ * curves it knows among the ones crypton_ecc_mul is asked about.+ *+ * s2n-bignum has no affine wrapper for these two -- only a scalar+ * multiplication on Jacobian points, Montgomery-domain for P-384 and plain+ * for P-521 -- so the conversions in and out are built here out of its own+ * field operations. See cbits/s2n/README.md.+ */+#ifndef CRYPTON_ECC_S2N_H+#define CRYPTON_ECC_S2N_H++#include <stdint.h>++/*+ * Returns 1 if this was a curve it knows and it answered, with *ret set to+ * what crypton_ecc_mul should return -- 0 and the point in outx and outy, 1+ * for the point at infinity, or -1 for arguments it will not take. Returns+ * 0 if the curve is not one of its two and nothing was written.+ */+int crypton_s2n_ecc_mul(int *ret, uint8_t *outx, uint8_t *outy,+ const uint8_t *px, const uint8_t *py,+ const uint8_t *k, uint32_t klen,+ const uint8_t *a, const uint8_t *b,+ const uint8_t *p, uint32_t plen);++#endif
@@ -0,0 +1,76 @@+/*+ * p, a and b of the two curves the vendored s2n-bignum assembly knows, as+ * big-endian bytes, which is how crypton_ecc_mul is given a curve. They are+ * here to be compared against, not computed with: a caller naming some other+ * curve with the same sizes has to go to the C.+ *+ * Generated from `openssl ecparam -name secp384r1 -param_enc explicit -text`+ * and the same for secp521r1, rather than transcribed.+ */+#ifndef CRYPTON_ECC_S2N_CURVES_H+#define CRYPTON_ECC_S2N_CURVES_H++#include <stdint.h>++#define P384_PLEN 48+static const uint8_t P384_P[48] = {+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,+ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,+ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff+};+static const uint8_t P384_A[48] = {+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,+ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,+ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xfc+};+static const uint8_t P384_B[48] = {+ 0xb3,0x31,0x2f,0xa7,0xe2,0x3e,0xe7,0xe4,+ 0x98,0x8e,0x05,0x6b,0xe3,0xf8,0x2d,0x19,+ 0x18,0x1d,0x9c,0x6e,0xfe,0x81,0x41,0x12,+ 0x03,0x14,0x08,0x8f,0x50,0x13,0x87,0x5a,+ 0xc6,0x56,0x39,0x8d,0x8a,0x2e,0xd1,0x9d,+ 0x2a,0x85,0xc8,0xed,0xd3,0xec,0x2a,0xef+};++#define P521_PLEN 66+static const uint8_t P521_P[66] = {+ 0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff+};+static const uint8_t P521_A[66] = {+ 0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,+ 0xff,0xfc+};+static const uint8_t P521_B[66] = {+ 0x00,0x51,0x95,0x3e,0xb9,0x61,0x8e,0x1c,+ 0x9a,0x1f,0x92,0x9a,0x21,0xa0,0xb6,0x85,+ 0x40,0xee,0xa2,0xda,0x72,0x5b,0x99,0xb3,+ 0x15,0xf3,0xb8,0xb4,0x89,0x91,0x8e,0xf1,+ 0x09,0xe1,0x56,0x19,0x39,0x51,0xec,0x7e,+ 0x93,0x7b,0x16,0x52,0xc0,0xbd,0x3b,0xb1,+ 0xbf,0x07,0x35,0x73,0xdf,0x88,0x3d,0x2c,+ 0x34,0xf1,0xef,0x45,0x1f,0xd4,0x6b,0x50,+ 0x3f,0x00+};++#endif
@@ -25,6 +25,8 @@ #include <stdlib.h> #include <string.h> #include <crypton_cpu.h>+#include "crypton_armv8_target.h"+#include <crypton_bzero.h> #include <crypton_f2m.h> typedef uint64_t limb_t;@@ -89,7 +91,7 @@ #define PMULL_ATTR #define PMULL_ALWAYS 1 #else-#define PMULL_ATTR __attribute__((target("+crypto")))+#define PMULL_ATTR CRYPTON_TARGET_ARMV8_CRYPTO #define PMULL_ALWAYS 0 #endif @@ -543,8 +545,10 @@ ret = 0; done:+ /* freed on the next line, so a plain memset here is a store the+ * optimizer may drop */ if (space != NULL) {- memset(space, 0, words * sizeof(limb_t));+ crypton_bzero(space, words * sizeof(limb_t)); free(space); } return ret;
@@ -48,16 +48,17 @@ #define K3 0x6ED9EBA1 #define R(a,b,c,d,f,k,s,i) (a = rol32(a + f(b,c,d) + w[i] + k, s)) -static void md4_do_chunk(struct md4_ctx *ctx, uint32_t *buf)+/* The words are read out of the block rather than the block being pointed at+ * as though it were an array of them; see crypton_md5.c. */+static void md4_do_chunk(struct md4_ctx *ctx, const uint8_t *buf) { uint32_t a, b, c, d;-#ifdef ARCH_IS_BIG_ENDIAN uint32_t w[16];- cpu_to_le32_array(w, (uint32_t *) buf, 16);-#else- uint32_t *w = buf;-#endif+ int wi; + for (wi = 0; wi < 16; wi++)+ w[wi] = load_le32(buf + 4 * wi);+ a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3]; R(a, b, c, d, f1, K1, 3, 0);@@ -125,24 +126,15 @@ if (index && len >= to_fill) { memcpy(ctx->buf + index, data, to_fill);- md4_do_chunk(ctx, (uint32_t *) ctx->buf);+ md4_do_chunk(ctx, ctx->buf); len -= to_fill; data += to_fill; index = 0; } - if (need_alignment(data, 4)) {- uint32_t tramp[16];- ASSERT_ALIGNMENT(tramp, 4);- for (; len >= 64; len -= 64, data += 64) {- memcpy(tramp, data, 64);- md4_do_chunk(ctx, tramp);- }- } else {- /* process as much 64-block as possible */- for (; len >= 64; len -= 64, data += 64)- md4_do_chunk(ctx, (uint32_t *) data);- }+ /* No trampoline: load_le32 does not ask for a boundary. */+ for (; len >= 64; len -= 64, data += 64)+ md4_do_chunk(ctx, data); /* append data into buf */ if (len)
@@ -45,15 +45,22 @@ #define f4(x, y, z) (y ^ (x | ~z)) #define R(f, a, b, c, d, i, k, s) a += f(b, c, d) + w[i] + k; a = rol32(a, s); a += b -static void md5_do_chunk(struct md5_ctx *ctx, uint32_t *buf)+/* The sixteen words are read out of the block rather than the block being+ * pointed at as though it were an array of them. A caller's pointer cast to+ * uint32_t * is a pointer the standard says may not exist unless the address+ * is aligned for it, and reading through it is undefined whether or not the+ * machine minds; UndefinedBehaviorSanitizer counted sixty-four of these.+ * load_le32 is a memcpy, which every compiler here turns into the one load+ * the cast used to be, and it takes the endianness with it -- so the two+ * arms this replaces are one. */+static void md5_do_chunk(struct md5_ctx *ctx, const uint8_t *buf) { uint32_t a, b, c, d;-#ifdef ARCH_IS_BIG_ENDIAN uint32_t w[16];- cpu_to_le32_array(w, buf, 16);-#else- uint32_t *w = buf;-#endif+ int wi;++ for (wi = 0; wi < 16; wi++)+ w[wi] = load_le32(buf + 4 * wi); a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3]; R(f1, a, b, c, d, 0, 0xd76aa478, 7);@@ -138,24 +145,16 @@ if (index && len >= to_fill) { memcpy(ctx->buf + index, data, to_fill);- md5_do_chunk(ctx, (uint32_t *) ctx->buf);+ md5_do_chunk(ctx, ctx->buf); len -= to_fill; data += to_fill; index = 0; } - if (need_alignment(data, 4)) {- uint32_t tramp[16];- ASSERT_ALIGNMENT(tramp, 4);- for (; len >= 64; len -= 64, data += 64) {- memcpy(tramp, data, 64);- md5_do_chunk(ctx, tramp);- }- } else {- /* process as much 64-block as possible */- for (; len >= 64; len -= 64, data += 64)- md5_do_chunk(ctx, (uint32_t *) data);- }+ /* No trampoline for a block that is not on a four-byte boundary: the+ * words are read with load_le32 now, which does not ask. */+ for (; len >= 64; len -= 64, data += 64)+ md5_do_chunk(ctx, data); /* append data into buf */ if (len)
@@ -0,0 +1,74 @@+/*+ * Inversion modulo an odd number through s2n-bignum, whose routine takes a+ * fixed number of division steps rather than an exponentiation: twenty to+ * thirty times less work than Fermat's little theorem at the sizes here.+ * Measured on an Apple M4, inverting modulo a curve order:+ *+ * Fermat this+ * P-256 6.02 us 0.80+ * P-384 31.3 1.20+ * P-521 63.2 2.05+ *+ * It uses no instruction beyond the base architecture on either x86-64 or+ * AArch64, so unlike the rest of the vendored assembly there is nothing to+ * ask the processor first.+ */+#include <string.h>++#include "crypton_modinv.h"++#ifdef CRYPTON_S2N_BIGNUM++extern void bignum_modinv(uint64_t k, uint64_t *z, const uint64_t *a,+ const uint64_t *b, uint64_t *t);++/* 4096 bits and no more, which covers every modulus that reaches here -- the+ * order of a curve, or a prime factor of an RSA modulus -- and keeps the+ * working space on the stack. Anything larger is handed back. */+#define MODINV_MAXWORDS 64++int crypton_modinv_sec(uint8_t *z, const uint8_t *a, const uint8_t *m,+ uint32_t len)+{+ uint64_t aw[MODINV_MAXWORDS], mw[MODINV_MAXWORDS];+ uint64_t zw[MODINV_MAXWORDS], t[3 * MODINV_MAXWORDS];+ uint32_t k = (len + 7) / 8;+ uint32_t i;++ /* An even modulus is the one case it answers without saying it+ * cannot: it returns a number that is not an inverse rather than+ * failing, so keep it away from here. Every caller's modulus is odd. */+ if (len == 0 || k > MODINV_MAXWORDS || (m[len - 1] & 1) == 0)+ return 1;++ for (i = 0; i < k; i++) {+ aw[i] = 0;+ mw[i] = 0;+ }+ for (i = 0; i < len; i++) {+ uint32_t pos = len - 1 - i;++ aw[pos / 8] |= (uint64_t)a[i] << (8 * (pos % 8));+ mw[pos / 8] |= (uint64_t)m[i] << (8 * (pos % 8));+ }++ bignum_modinv(k, zw, aw, mw, t);++ for (i = 0; i < len; i++)+ z[len - 1 - i] = (uint8_t)(zw[i / 8] >> (8 * (i % 8)));+ return 0;+}++#else++int crypton_modinv_sec(uint8_t *z, const uint8_t *a, const uint8_t *m,+ uint32_t len)+{+ (void)z;+ (void)a;+ (void)m;+ (void)len;+ return 1;+}++#endif
@@ -0,0 +1,22 @@+#ifndef CRYPTON_MODINV_H+#define CRYPTON_MODINV_H++#include <stdint.h>++/* z = a^-1 mod m, all three big-endian byte strings of len bytes.+ *+ * Returns 0 with the answer in z, and 1 without touching z when it will not+ * do this one: the assembly it needs is not built, the modulus is even, or+ * the numbers are larger than it keeps room for. A 1 is not an error, it is+ * "ask something else".+ *+ * The answer is not checked here. When a has no inverse the routine+ * underneath returns something that is not one rather than saying so, so the+ * caller has to multiply out and look -- which is what Crypto.Number.+ * ModArithmetic.inverseSafe already did for the exponentiation this+ * replaces.+ */+int crypton_modinv_sec(uint8_t *z, const uint8_t *a, const uint8_t *m,+ uint32_t len);++#endif
@@ -0,0 +1,13445 @@+/* Generated by cbits/crypton_mont.py; do not edit.+ *+ * Montgomery multiplication and squaring for AArch64 at 16, 24 and 32 limbs,+ * the halves of RSA-2048, -3072 and -4096, and squaring at 48, RSA-3072's+ * modulus. Each answers what mont_mul and mont_sqr answer. */+#ifndef CRYPTON_MONT_H+#define CRYPTON_MONT_H++#include "crypton_bignum.h"++/* (t2:t1:t0) += x * y */+#define MONT_MAC(t0, t1, t2, x, y) \+ do { \+ limb_t lo_, hi_; \+ __asm__("mul\t%0, %5, %6\n\t" \+ "umulh\t%1, %5, %6\n\t" \+ "adds\t%2, %2, %0\n\t" \+ "adcs\t%3, %3, %1\n\t" \+ "adc\t%4, %4, xzr" \+ : "=&r"(lo_), "=&r"(hi_), "+r"(t0), "+r"(t1), "+r"(t2) \+ : "r"(x), "r"(y) \+ : "cc"); \+ } while (0)++/* (s2:s1:s0) = x * y */+#define MONT_MUL(s0, s1, s2, x, y) \+ __asm__("mul\t%0, %3, %4\n\t" \+ "umulh\t%1, %3, %4\n\t" \+ "mov\t%2, xzr" \+ : "=&r"(s0), "=&r"(s1), "=r"(s2) \+ : "r"(x), "r"(y))++/* (t2:t1:t0) += (s2:s1:s0) */+#define MONT_ADD(t0, t1, t2, s0, s1, s2) \+ __asm__("adds\t%0, %0, %3\n\t" \+ "adcs\t%1, %1, %4\n\t" \+ "adc\t%2, %2, %5" \+ : "+r"(t0), "+r"(t1), "+r"(t2) \+ : "r"(s0), "r"(s1), "r"(s2) \+ : "cc")++/* (s2:s1:s0) *= 2 */+#define MONT_DBL(s0, s1, s2) \+ do { \+ s2 = (s2 << 1) | (s1 >> 63); \+ s1 = (s1 << 1) | (s0 >> 63); \+ s0 <<= 1; \+ } while (0)++/* r = a * b * R^-1 mod m, for a and b under m; t is 2n limbs of scratch */+static void crypton_mont_mul16(limb_t *r, const limb_t *a, const limb_t *b,+ const limb_t *m, limb_t n0, limb_t *t)+{+ limb_t *u = t, *z = t + 16;+ limb_t t0 = 0, t1 = 0, t2 = 0, v0, v1, v2, w0, w1, w2, borrow, take;++ /* column 0 */+ MONT_MAC(t0, t1, t2, a[0], b[0]);+ u[0] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[0], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 1 */+ MONT_MAC(t0, t1, t2, a[0], b[1]);+ MONT_MUL(v0, v1, v2, a[1], b[0]);+ MONT_MUL(w0, w1, w2, u[0], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[1] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[1], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 2 */+ MONT_MAC(t0, t1, t2, a[0], b[2]);+ MONT_MUL(v0, v1, v2, a[1], b[1]);+ MONT_MUL(w0, w1, w2, a[2], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[2]);+ MONT_MAC(v0, v1, v2, u[1], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[2] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[2], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 3 */+ MONT_MAC(t0, t1, t2, a[0], b[3]);+ MONT_MUL(v0, v1, v2, a[1], b[2]);+ MONT_MUL(w0, w1, w2, a[2], b[1]);+ MONT_MAC(t0, t1, t2, a[3], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[3]);+ MONT_MAC(w0, w1, w2, u[1], m[2]);+ MONT_MAC(t0, t1, t2, u[2], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[3] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[3], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 4 */+ MONT_MAC(t0, t1, t2, a[0], b[4]);+ MONT_MUL(v0, v1, v2, a[1], b[3]);+ MONT_MUL(w0, w1, w2, a[2], b[2]);+ MONT_MAC(t0, t1, t2, a[3], b[1]);+ MONT_MAC(v0, v1, v2, a[4], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[4]);+ MONT_MAC(t0, t1, t2, u[1], m[3]);+ MONT_MAC(v0, v1, v2, u[2], m[2]);+ MONT_MAC(w0, w1, w2, u[3], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[4] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[4], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 5 */+ MONT_MAC(t0, t1, t2, a[0], b[5]);+ MONT_MUL(v0, v1, v2, a[1], b[4]);+ MONT_MUL(w0, w1, w2, a[2], b[3]);+ MONT_MAC(t0, t1, t2, a[3], b[2]);+ MONT_MAC(v0, v1, v2, a[4], b[1]);+ MONT_MAC(w0, w1, w2, a[5], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[5]);+ MONT_MAC(v0, v1, v2, u[1], m[4]);+ MONT_MAC(w0, w1, w2, u[2], m[3]);+ MONT_MAC(t0, t1, t2, u[3], m[2]);+ MONT_MAC(v0, v1, v2, u[4], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[5] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[5], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 6 */+ MONT_MAC(t0, t1, t2, a[0], b[6]);+ MONT_MUL(v0, v1, v2, a[1], b[5]);+ MONT_MUL(w0, w1, w2, a[2], b[4]);+ MONT_MAC(t0, t1, t2, a[3], b[3]);+ MONT_MAC(v0, v1, v2, a[4], b[2]);+ MONT_MAC(w0, w1, w2, a[5], b[1]);+ MONT_MAC(t0, t1, t2, a[6], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[6]);+ MONT_MAC(w0, w1, w2, u[1], m[5]);+ MONT_MAC(t0, t1, t2, u[2], m[4]);+ MONT_MAC(v0, v1, v2, u[3], m[3]);+ MONT_MAC(w0, w1, w2, u[4], m[2]);+ MONT_MAC(t0, t1, t2, u[5], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[6] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[6], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 7 */+ MONT_MAC(t0, t1, t2, a[0], b[7]);+ MONT_MUL(v0, v1, v2, a[1], b[6]);+ MONT_MUL(w0, w1, w2, a[2], b[5]);+ MONT_MAC(t0, t1, t2, a[3], b[4]);+ MONT_MAC(v0, v1, v2, a[4], b[3]);+ MONT_MAC(w0, w1, w2, a[5], b[2]);+ MONT_MAC(t0, t1, t2, a[6], b[1]);+ MONT_MAC(v0, v1, v2, a[7], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[7]);+ MONT_MAC(t0, t1, t2, u[1], m[6]);+ MONT_MAC(v0, v1, v2, u[2], m[5]);+ MONT_MAC(w0, w1, w2, u[3], m[4]);+ MONT_MAC(t0, t1, t2, u[4], m[3]);+ MONT_MAC(v0, v1, v2, u[5], m[2]);+ MONT_MAC(w0, w1, w2, u[6], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[7] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[7], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 8 */+ MONT_MAC(t0, t1, t2, a[0], b[8]);+ MONT_MUL(v0, v1, v2, a[1], b[7]);+ MONT_MUL(w0, w1, w2, a[2], b[6]);+ MONT_MAC(t0, t1, t2, a[3], b[5]);+ MONT_MAC(v0, v1, v2, a[4], b[4]);+ MONT_MAC(w0, w1, w2, a[5], b[3]);+ MONT_MAC(t0, t1, t2, a[6], b[2]);+ MONT_MAC(v0, v1, v2, a[7], b[1]);+ MONT_MAC(w0, w1, w2, a[8], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[8]);+ MONT_MAC(v0, v1, v2, u[1], m[7]);+ MONT_MAC(w0, w1, w2, u[2], m[6]);+ MONT_MAC(t0, t1, t2, u[3], m[5]);+ MONT_MAC(v0, v1, v2, u[4], m[4]);+ MONT_MAC(w0, w1, w2, u[5], m[3]);+ MONT_MAC(t0, t1, t2, u[6], m[2]);+ MONT_MAC(v0, v1, v2, u[7], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[8] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[8], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 9 */+ MONT_MAC(t0, t1, t2, a[0], b[9]);+ MONT_MUL(v0, v1, v2, a[1], b[8]);+ MONT_MUL(w0, w1, w2, a[2], b[7]);+ MONT_MAC(t0, t1, t2, a[3], b[6]);+ MONT_MAC(v0, v1, v2, a[4], b[5]);+ MONT_MAC(w0, w1, w2, a[5], b[4]);+ MONT_MAC(t0, t1, t2, a[6], b[3]);+ MONT_MAC(v0, v1, v2, a[7], b[2]);+ MONT_MAC(w0, w1, w2, a[8], b[1]);+ MONT_MAC(t0, t1, t2, a[9], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[9]);+ MONT_MAC(w0, w1, w2, u[1], m[8]);+ MONT_MAC(t0, t1, t2, u[2], m[7]);+ MONT_MAC(v0, v1, v2, u[3], m[6]);+ MONT_MAC(w0, w1, w2, u[4], m[5]);+ MONT_MAC(t0, t1, t2, u[5], m[4]);+ MONT_MAC(v0, v1, v2, u[6], m[3]);+ MONT_MAC(w0, w1, w2, u[7], m[2]);+ MONT_MAC(t0, t1, t2, u[8], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[9] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[9], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 10 */+ MONT_MAC(t0, t1, t2, a[0], b[10]);+ MONT_MUL(v0, v1, v2, a[1], b[9]);+ MONT_MUL(w0, w1, w2, a[2], b[8]);+ MONT_MAC(t0, t1, t2, a[3], b[7]);+ MONT_MAC(v0, v1, v2, a[4], b[6]);+ MONT_MAC(w0, w1, w2, a[5], b[5]);+ MONT_MAC(t0, t1, t2, a[6], b[4]);+ MONT_MAC(v0, v1, v2, a[7], b[3]);+ MONT_MAC(w0, w1, w2, a[8], b[2]);+ MONT_MAC(t0, t1, t2, a[9], b[1]);+ MONT_MAC(v0, v1, v2, a[10], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[10]);+ MONT_MAC(t0, t1, t2, u[1], m[9]);+ MONT_MAC(v0, v1, v2, u[2], m[8]);+ MONT_MAC(w0, w1, w2, u[3], m[7]);+ MONT_MAC(t0, t1, t2, u[4], m[6]);+ MONT_MAC(v0, v1, v2, u[5], m[5]);+ MONT_MAC(w0, w1, w2, u[6], m[4]);+ MONT_MAC(t0, t1, t2, u[7], m[3]);+ MONT_MAC(v0, v1, v2, u[8], m[2]);+ MONT_MAC(w0, w1, w2, u[9], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[10] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[10], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 11 */+ MONT_MAC(t0, t1, t2, a[0], b[11]);+ MONT_MUL(v0, v1, v2, a[1], b[10]);+ MONT_MUL(w0, w1, w2, a[2], b[9]);+ MONT_MAC(t0, t1, t2, a[3], b[8]);+ MONT_MAC(v0, v1, v2, a[4], b[7]);+ MONT_MAC(w0, w1, w2, a[5], b[6]);+ MONT_MAC(t0, t1, t2, a[6], b[5]);+ MONT_MAC(v0, v1, v2, a[7], b[4]);+ MONT_MAC(w0, w1, w2, a[8], b[3]);+ MONT_MAC(t0, t1, t2, a[9], b[2]);+ MONT_MAC(v0, v1, v2, a[10], b[1]);+ MONT_MAC(w0, w1, w2, a[11], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[11]);+ MONT_MAC(v0, v1, v2, u[1], m[10]);+ MONT_MAC(w0, w1, w2, u[2], m[9]);+ MONT_MAC(t0, t1, t2, u[3], m[8]);+ MONT_MAC(v0, v1, v2, u[4], m[7]);+ MONT_MAC(w0, w1, w2, u[5], m[6]);+ MONT_MAC(t0, t1, t2, u[6], m[5]);+ MONT_MAC(v0, v1, v2, u[7], m[4]);+ MONT_MAC(w0, w1, w2, u[8], m[3]);+ MONT_MAC(t0, t1, t2, u[9], m[2]);+ MONT_MAC(v0, v1, v2, u[10], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[11] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[11], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 12 */+ MONT_MAC(t0, t1, t2, a[0], b[12]);+ MONT_MUL(v0, v1, v2, a[1], b[11]);+ MONT_MUL(w0, w1, w2, a[2], b[10]);+ MONT_MAC(t0, t1, t2, a[3], b[9]);+ MONT_MAC(v0, v1, v2, a[4], b[8]);+ MONT_MAC(w0, w1, w2, a[5], b[7]);+ MONT_MAC(t0, t1, t2, a[6], b[6]);+ MONT_MAC(v0, v1, v2, a[7], b[5]);+ MONT_MAC(w0, w1, w2, a[8], b[4]);+ MONT_MAC(t0, t1, t2, a[9], b[3]);+ MONT_MAC(v0, v1, v2, a[10], b[2]);+ MONT_MAC(w0, w1, w2, a[11], b[1]);+ MONT_MAC(t0, t1, t2, a[12], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[12]);+ MONT_MAC(w0, w1, w2, u[1], m[11]);+ MONT_MAC(t0, t1, t2, u[2], m[10]);+ MONT_MAC(v0, v1, v2, u[3], m[9]);+ MONT_MAC(w0, w1, w2, u[4], m[8]);+ MONT_MAC(t0, t1, t2, u[5], m[7]);+ MONT_MAC(v0, v1, v2, u[6], m[6]);+ MONT_MAC(w0, w1, w2, u[7], m[5]);+ MONT_MAC(t0, t1, t2, u[8], m[4]);+ MONT_MAC(v0, v1, v2, u[9], m[3]);+ MONT_MAC(w0, w1, w2, u[10], m[2]);+ MONT_MAC(t0, t1, t2, u[11], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[12] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[12], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 13 */+ MONT_MAC(t0, t1, t2, a[0], b[13]);+ MONT_MUL(v0, v1, v2, a[1], b[12]);+ MONT_MUL(w0, w1, w2, a[2], b[11]);+ MONT_MAC(t0, t1, t2, a[3], b[10]);+ MONT_MAC(v0, v1, v2, a[4], b[9]);+ MONT_MAC(w0, w1, w2, a[5], b[8]);+ MONT_MAC(t0, t1, t2, a[6], b[7]);+ MONT_MAC(v0, v1, v2, a[7], b[6]);+ MONT_MAC(w0, w1, w2, a[8], b[5]);+ MONT_MAC(t0, t1, t2, a[9], b[4]);+ MONT_MAC(v0, v1, v2, a[10], b[3]);+ MONT_MAC(w0, w1, w2, a[11], b[2]);+ MONT_MAC(t0, t1, t2, a[12], b[1]);+ MONT_MAC(v0, v1, v2, a[13], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[13]);+ MONT_MAC(t0, t1, t2, u[1], m[12]);+ MONT_MAC(v0, v1, v2, u[2], m[11]);+ MONT_MAC(w0, w1, w2, u[3], m[10]);+ MONT_MAC(t0, t1, t2, u[4], m[9]);+ MONT_MAC(v0, v1, v2, u[5], m[8]);+ MONT_MAC(w0, w1, w2, u[6], m[7]);+ MONT_MAC(t0, t1, t2, u[7], m[6]);+ MONT_MAC(v0, v1, v2, u[8], m[5]);+ MONT_MAC(w0, w1, w2, u[9], m[4]);+ MONT_MAC(t0, t1, t2, u[10], m[3]);+ MONT_MAC(v0, v1, v2, u[11], m[2]);+ MONT_MAC(w0, w1, w2, u[12], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[13] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[13], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 14 */+ MONT_MAC(t0, t1, t2, a[0], b[14]);+ MONT_MUL(v0, v1, v2, a[1], b[13]);+ MONT_MUL(w0, w1, w2, a[2], b[12]);+ MONT_MAC(t0, t1, t2, a[3], b[11]);+ MONT_MAC(v0, v1, v2, a[4], b[10]);+ MONT_MAC(w0, w1, w2, a[5], b[9]);+ MONT_MAC(t0, t1, t2, a[6], b[8]);+ MONT_MAC(v0, v1, v2, a[7], b[7]);+ MONT_MAC(w0, w1, w2, a[8], b[6]);+ MONT_MAC(t0, t1, t2, a[9], b[5]);+ MONT_MAC(v0, v1, v2, a[10], b[4]);+ MONT_MAC(w0, w1, w2, a[11], b[3]);+ MONT_MAC(t0, t1, t2, a[12], b[2]);+ MONT_MAC(v0, v1, v2, a[13], b[1]);+ MONT_MAC(w0, w1, w2, a[14], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[14]);+ MONT_MAC(v0, v1, v2, u[1], m[13]);+ MONT_MAC(w0, w1, w2, u[2], m[12]);+ MONT_MAC(t0, t1, t2, u[3], m[11]);+ MONT_MAC(v0, v1, v2, u[4], m[10]);+ MONT_MAC(w0, w1, w2, u[5], m[9]);+ MONT_MAC(t0, t1, t2, u[6], m[8]);+ MONT_MAC(v0, v1, v2, u[7], m[7]);+ MONT_MAC(w0, w1, w2, u[8], m[6]);+ MONT_MAC(t0, t1, t2, u[9], m[5]);+ MONT_MAC(v0, v1, v2, u[10], m[4]);+ MONT_MAC(w0, w1, w2, u[11], m[3]);+ MONT_MAC(t0, t1, t2, u[12], m[2]);+ MONT_MAC(v0, v1, v2, u[13], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[14] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[14], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 15 */+ MONT_MAC(t0, t1, t2, a[0], b[15]);+ MONT_MUL(v0, v1, v2, a[1], b[14]);+ MONT_MUL(w0, w1, w2, a[2], b[13]);+ MONT_MAC(t0, t1, t2, a[3], b[12]);+ MONT_MAC(v0, v1, v2, a[4], b[11]);+ MONT_MAC(w0, w1, w2, a[5], b[10]);+ MONT_MAC(t0, t1, t2, a[6], b[9]);+ MONT_MAC(v0, v1, v2, a[7], b[8]);+ MONT_MAC(w0, w1, w2, a[8], b[7]);+ MONT_MAC(t0, t1, t2, a[9], b[6]);+ MONT_MAC(v0, v1, v2, a[10], b[5]);+ MONT_MAC(w0, w1, w2, a[11], b[4]);+ MONT_MAC(t0, t1, t2, a[12], b[3]);+ MONT_MAC(v0, v1, v2, a[13], b[2]);+ MONT_MAC(w0, w1, w2, a[14], b[1]);+ MONT_MAC(t0, t1, t2, a[15], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[15]);+ MONT_MAC(w0, w1, w2, u[1], m[14]);+ MONT_MAC(t0, t1, t2, u[2], m[13]);+ MONT_MAC(v0, v1, v2, u[3], m[12]);+ MONT_MAC(w0, w1, w2, u[4], m[11]);+ MONT_MAC(t0, t1, t2, u[5], m[10]);+ MONT_MAC(v0, v1, v2, u[6], m[9]);+ MONT_MAC(w0, w1, w2, u[7], m[8]);+ MONT_MAC(t0, t1, t2, u[8], m[7]);+ MONT_MAC(v0, v1, v2, u[9], m[6]);+ MONT_MAC(w0, w1, w2, u[10], m[5]);+ MONT_MAC(t0, t1, t2, u[11], m[4]);+ MONT_MAC(v0, v1, v2, u[12], m[3]);+ MONT_MAC(w0, w1, w2, u[13], m[2]);+ MONT_MAC(t0, t1, t2, u[14], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[15] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[15], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 16 */+ MONT_MAC(t0, t1, t2, a[1], b[15]);+ MONT_MUL(v0, v1, v2, a[2], b[14]);+ MONT_MUL(w0, w1, w2, a[3], b[13]);+ MONT_MAC(t0, t1, t2, a[4], b[12]);+ MONT_MAC(v0, v1, v2, a[5], b[11]);+ MONT_MAC(w0, w1, w2, a[6], b[10]);+ MONT_MAC(t0, t1, t2, a[7], b[9]);+ MONT_MAC(v0, v1, v2, a[8], b[8]);+ MONT_MAC(w0, w1, w2, a[9], b[7]);+ MONT_MAC(t0, t1, t2, a[10], b[6]);+ MONT_MAC(v0, v1, v2, a[11], b[5]);+ MONT_MAC(w0, w1, w2, a[12], b[4]);+ MONT_MAC(t0, t1, t2, a[13], b[3]);+ MONT_MAC(v0, v1, v2, a[14], b[2]);+ MONT_MAC(w0, w1, w2, a[15], b[1]);+ MONT_MAC(t0, t1, t2, u[1], m[15]);+ MONT_MAC(v0, v1, v2, u[2], m[14]);+ MONT_MAC(w0, w1, w2, u[3], m[13]);+ MONT_MAC(t0, t1, t2, u[4], m[12]);+ MONT_MAC(v0, v1, v2, u[5], m[11]);+ MONT_MAC(w0, w1, w2, u[6], m[10]);+ MONT_MAC(t0, t1, t2, u[7], m[9]);+ MONT_MAC(v0, v1, v2, u[8], m[8]);+ MONT_MAC(w0, w1, w2, u[9], m[7]);+ MONT_MAC(t0, t1, t2, u[10], m[6]);+ MONT_MAC(v0, v1, v2, u[11], m[5]);+ MONT_MAC(w0, w1, w2, u[12], m[4]);+ MONT_MAC(t0, t1, t2, u[13], m[3]);+ MONT_MAC(v0, v1, v2, u[14], m[2]);+ MONT_MAC(w0, w1, w2, u[15], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[0] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 17 */+ MONT_MAC(t0, t1, t2, a[2], b[15]);+ MONT_MUL(v0, v1, v2, a[3], b[14]);+ MONT_MUL(w0, w1, w2, a[4], b[13]);+ MONT_MAC(t0, t1, t2, a[5], b[12]);+ MONT_MAC(v0, v1, v2, a[6], b[11]);+ MONT_MAC(w0, w1, w2, a[7], b[10]);+ MONT_MAC(t0, t1, t2, a[8], b[9]);+ MONT_MAC(v0, v1, v2, a[9], b[8]);+ MONT_MAC(w0, w1, w2, a[10], b[7]);+ MONT_MAC(t0, t1, t2, a[11], b[6]);+ MONT_MAC(v0, v1, v2, a[12], b[5]);+ MONT_MAC(w0, w1, w2, a[13], b[4]);+ MONT_MAC(t0, t1, t2, a[14], b[3]);+ MONT_MAC(v0, v1, v2, a[15], b[2]);+ MONT_MAC(w0, w1, w2, u[2], m[15]);+ MONT_MAC(t0, t1, t2, u[3], m[14]);+ MONT_MAC(v0, v1, v2, u[4], m[13]);+ MONT_MAC(w0, w1, w2, u[5], m[12]);+ MONT_MAC(t0, t1, t2, u[6], m[11]);+ MONT_MAC(v0, v1, v2, u[7], m[10]);+ MONT_MAC(w0, w1, w2, u[8], m[9]);+ MONT_MAC(t0, t1, t2, u[9], m[8]);+ MONT_MAC(v0, v1, v2, u[10], m[7]);+ MONT_MAC(w0, w1, w2, u[11], m[6]);+ MONT_MAC(t0, t1, t2, u[12], m[5]);+ MONT_MAC(v0, v1, v2, u[13], m[4]);+ MONT_MAC(w0, w1, w2, u[14], m[3]);+ MONT_MAC(t0, t1, t2, u[15], m[2]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[1] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 18 */+ MONT_MAC(t0, t1, t2, a[3], b[15]);+ MONT_MUL(v0, v1, v2, a[4], b[14]);+ MONT_MUL(w0, w1, w2, a[5], b[13]);+ MONT_MAC(t0, t1, t2, a[6], b[12]);+ MONT_MAC(v0, v1, v2, a[7], b[11]);+ MONT_MAC(w0, w1, w2, a[8], b[10]);+ MONT_MAC(t0, t1, t2, a[9], b[9]);+ MONT_MAC(v0, v1, v2, a[10], b[8]);+ MONT_MAC(w0, w1, w2, a[11], b[7]);+ MONT_MAC(t0, t1, t2, a[12], b[6]);+ MONT_MAC(v0, v1, v2, a[13], b[5]);+ MONT_MAC(w0, w1, w2, a[14], b[4]);+ MONT_MAC(t0, t1, t2, a[15], b[3]);+ MONT_MAC(v0, v1, v2, u[3], m[15]);+ MONT_MAC(w0, w1, w2, u[4], m[14]);+ MONT_MAC(t0, t1, t2, u[5], m[13]);+ MONT_MAC(v0, v1, v2, u[6], m[12]);+ MONT_MAC(w0, w1, w2, u[7], m[11]);+ MONT_MAC(t0, t1, t2, u[8], m[10]);+ MONT_MAC(v0, v1, v2, u[9], m[9]);+ MONT_MAC(w0, w1, w2, u[10], m[8]);+ MONT_MAC(t0, t1, t2, u[11], m[7]);+ MONT_MAC(v0, v1, v2, u[12], m[6]);+ MONT_MAC(w0, w1, w2, u[13], m[5]);+ MONT_MAC(t0, t1, t2, u[14], m[4]);+ MONT_MAC(v0, v1, v2, u[15], m[3]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[2] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 19 */+ MONT_MAC(t0, t1, t2, a[4], b[15]);+ MONT_MUL(v0, v1, v2, a[5], b[14]);+ MONT_MUL(w0, w1, w2, a[6], b[13]);+ MONT_MAC(t0, t1, t2, a[7], b[12]);+ MONT_MAC(v0, v1, v2, a[8], b[11]);+ MONT_MAC(w0, w1, w2, a[9], b[10]);+ MONT_MAC(t0, t1, t2, a[10], b[9]);+ MONT_MAC(v0, v1, v2, a[11], b[8]);+ MONT_MAC(w0, w1, w2, a[12], b[7]);+ MONT_MAC(t0, t1, t2, a[13], b[6]);+ MONT_MAC(v0, v1, v2, a[14], b[5]);+ MONT_MAC(w0, w1, w2, a[15], b[4]);+ MONT_MAC(t0, t1, t2, u[4], m[15]);+ MONT_MAC(v0, v1, v2, u[5], m[14]);+ MONT_MAC(w0, w1, w2, u[6], m[13]);+ MONT_MAC(t0, t1, t2, u[7], m[12]);+ MONT_MAC(v0, v1, v2, u[8], m[11]);+ MONT_MAC(w0, w1, w2, u[9], m[10]);+ MONT_MAC(t0, t1, t2, u[10], m[9]);+ MONT_MAC(v0, v1, v2, u[11], m[8]);+ MONT_MAC(w0, w1, w2, u[12], m[7]);+ MONT_MAC(t0, t1, t2, u[13], m[6]);+ MONT_MAC(v0, v1, v2, u[14], m[5]);+ MONT_MAC(w0, w1, w2, u[15], m[4]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[3] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 20 */+ MONT_MAC(t0, t1, t2, a[5], b[15]);+ MONT_MUL(v0, v1, v2, a[6], b[14]);+ MONT_MUL(w0, w1, w2, a[7], b[13]);+ MONT_MAC(t0, t1, t2, a[8], b[12]);+ MONT_MAC(v0, v1, v2, a[9], b[11]);+ MONT_MAC(w0, w1, w2, a[10], b[10]);+ MONT_MAC(t0, t1, t2, a[11], b[9]);+ MONT_MAC(v0, v1, v2, a[12], b[8]);+ MONT_MAC(w0, w1, w2, a[13], b[7]);+ MONT_MAC(t0, t1, t2, a[14], b[6]);+ MONT_MAC(v0, v1, v2, a[15], b[5]);+ MONT_MAC(w0, w1, w2, u[5], m[15]);+ MONT_MAC(t0, t1, t2, u[6], m[14]);+ MONT_MAC(v0, v1, v2, u[7], m[13]);+ MONT_MAC(w0, w1, w2, u[8], m[12]);+ MONT_MAC(t0, t1, t2, u[9], m[11]);+ MONT_MAC(v0, v1, v2, u[10], m[10]);+ MONT_MAC(w0, w1, w2, u[11], m[9]);+ MONT_MAC(t0, t1, t2, u[12], m[8]);+ MONT_MAC(v0, v1, v2, u[13], m[7]);+ MONT_MAC(w0, w1, w2, u[14], m[6]);+ MONT_MAC(t0, t1, t2, u[15], m[5]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[4] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 21 */+ MONT_MAC(t0, t1, t2, a[6], b[15]);+ MONT_MUL(v0, v1, v2, a[7], b[14]);+ MONT_MUL(w0, w1, w2, a[8], b[13]);+ MONT_MAC(t0, t1, t2, a[9], b[12]);+ MONT_MAC(v0, v1, v2, a[10], b[11]);+ MONT_MAC(w0, w1, w2, a[11], b[10]);+ MONT_MAC(t0, t1, t2, a[12], b[9]);+ MONT_MAC(v0, v1, v2, a[13], b[8]);+ MONT_MAC(w0, w1, w2, a[14], b[7]);+ MONT_MAC(t0, t1, t2, a[15], b[6]);+ MONT_MAC(v0, v1, v2, u[6], m[15]);+ MONT_MAC(w0, w1, w2, u[7], m[14]);+ MONT_MAC(t0, t1, t2, u[8], m[13]);+ MONT_MAC(v0, v1, v2, u[9], m[12]);+ MONT_MAC(w0, w1, w2, u[10], m[11]);+ MONT_MAC(t0, t1, t2, u[11], m[10]);+ MONT_MAC(v0, v1, v2, u[12], m[9]);+ MONT_MAC(w0, w1, w2, u[13], m[8]);+ MONT_MAC(t0, t1, t2, u[14], m[7]);+ MONT_MAC(v0, v1, v2, u[15], m[6]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[5] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 22 */+ MONT_MAC(t0, t1, t2, a[7], b[15]);+ MONT_MUL(v0, v1, v2, a[8], b[14]);+ MONT_MUL(w0, w1, w2, a[9], b[13]);+ MONT_MAC(t0, t1, t2, a[10], b[12]);+ MONT_MAC(v0, v1, v2, a[11], b[11]);+ MONT_MAC(w0, w1, w2, a[12], b[10]);+ MONT_MAC(t0, t1, t2, a[13], b[9]);+ MONT_MAC(v0, v1, v2, a[14], b[8]);+ MONT_MAC(w0, w1, w2, a[15], b[7]);+ MONT_MAC(t0, t1, t2, u[7], m[15]);+ MONT_MAC(v0, v1, v2, u[8], m[14]);+ MONT_MAC(w0, w1, w2, u[9], m[13]);+ MONT_MAC(t0, t1, t2, u[10], m[12]);+ MONT_MAC(v0, v1, v2, u[11], m[11]);+ MONT_MAC(w0, w1, w2, u[12], m[10]);+ MONT_MAC(t0, t1, t2, u[13], m[9]);+ MONT_MAC(v0, v1, v2, u[14], m[8]);+ MONT_MAC(w0, w1, w2, u[15], m[7]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[6] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 23 */+ MONT_MAC(t0, t1, t2, a[8], b[15]);+ MONT_MUL(v0, v1, v2, a[9], b[14]);+ MONT_MUL(w0, w1, w2, a[10], b[13]);+ MONT_MAC(t0, t1, t2, a[11], b[12]);+ MONT_MAC(v0, v1, v2, a[12], b[11]);+ MONT_MAC(w0, w1, w2, a[13], b[10]);+ MONT_MAC(t0, t1, t2, a[14], b[9]);+ MONT_MAC(v0, v1, v2, a[15], b[8]);+ MONT_MAC(w0, w1, w2, u[8], m[15]);+ MONT_MAC(t0, t1, t2, u[9], m[14]);+ MONT_MAC(v0, v1, v2, u[10], m[13]);+ MONT_MAC(w0, w1, w2, u[11], m[12]);+ MONT_MAC(t0, t1, t2, u[12], m[11]);+ MONT_MAC(v0, v1, v2, u[13], m[10]);+ MONT_MAC(w0, w1, w2, u[14], m[9]);+ MONT_MAC(t0, t1, t2, u[15], m[8]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[7] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 24 */+ MONT_MAC(t0, t1, t2, a[9], b[15]);+ MONT_MUL(v0, v1, v2, a[10], b[14]);+ MONT_MUL(w0, w1, w2, a[11], b[13]);+ MONT_MAC(t0, t1, t2, a[12], b[12]);+ MONT_MAC(v0, v1, v2, a[13], b[11]);+ MONT_MAC(w0, w1, w2, a[14], b[10]);+ MONT_MAC(t0, t1, t2, a[15], b[9]);+ MONT_MAC(v0, v1, v2, u[9], m[15]);+ MONT_MAC(w0, w1, w2, u[10], m[14]);+ MONT_MAC(t0, t1, t2, u[11], m[13]);+ MONT_MAC(v0, v1, v2, u[12], m[12]);+ MONT_MAC(w0, w1, w2, u[13], m[11]);+ MONT_MAC(t0, t1, t2, u[14], m[10]);+ MONT_MAC(v0, v1, v2, u[15], m[9]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[8] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 25 */+ MONT_MAC(t0, t1, t2, a[10], b[15]);+ MONT_MUL(v0, v1, v2, a[11], b[14]);+ MONT_MUL(w0, w1, w2, a[12], b[13]);+ MONT_MAC(t0, t1, t2, a[13], b[12]);+ MONT_MAC(v0, v1, v2, a[14], b[11]);+ MONT_MAC(w0, w1, w2, a[15], b[10]);+ MONT_MAC(t0, t1, t2, u[10], m[15]);+ MONT_MAC(v0, v1, v2, u[11], m[14]);+ MONT_MAC(w0, w1, w2, u[12], m[13]);+ MONT_MAC(t0, t1, t2, u[13], m[12]);+ MONT_MAC(v0, v1, v2, u[14], m[11]);+ MONT_MAC(w0, w1, w2, u[15], m[10]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[9] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 26 */+ MONT_MAC(t0, t1, t2, a[11], b[15]);+ MONT_MUL(v0, v1, v2, a[12], b[14]);+ MONT_MUL(w0, w1, w2, a[13], b[13]);+ MONT_MAC(t0, t1, t2, a[14], b[12]);+ MONT_MAC(v0, v1, v2, a[15], b[11]);+ MONT_MAC(w0, w1, w2, u[11], m[15]);+ MONT_MAC(t0, t1, t2, u[12], m[14]);+ MONT_MAC(v0, v1, v2, u[13], m[13]);+ MONT_MAC(w0, w1, w2, u[14], m[12]);+ MONT_MAC(t0, t1, t2, u[15], m[11]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[10] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 27 */+ MONT_MAC(t0, t1, t2, a[12], b[15]);+ MONT_MUL(v0, v1, v2, a[13], b[14]);+ MONT_MUL(w0, w1, w2, a[14], b[13]);+ MONT_MAC(t0, t1, t2, a[15], b[12]);+ MONT_MAC(v0, v1, v2, u[12], m[15]);+ MONT_MAC(w0, w1, w2, u[13], m[14]);+ MONT_MAC(t0, t1, t2, u[14], m[13]);+ MONT_MAC(v0, v1, v2, u[15], m[12]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[11] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 28 */+ MONT_MAC(t0, t1, t2, a[13], b[15]);+ MONT_MUL(v0, v1, v2, a[14], b[14]);+ MONT_MUL(w0, w1, w2, a[15], b[13]);+ MONT_MAC(t0, t1, t2, u[13], m[15]);+ MONT_MAC(v0, v1, v2, u[14], m[14]);+ MONT_MAC(w0, w1, w2, u[15], m[13]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[12] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 29 */+ MONT_MAC(t0, t1, t2, a[14], b[15]);+ MONT_MUL(v0, v1, v2, a[15], b[14]);+ MONT_MUL(w0, w1, w2, u[14], m[15]);+ MONT_MAC(t0, t1, t2, u[15], m[14]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[13] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 30 */+ MONT_MAC(t0, t1, t2, a[15], b[15]);+ MONT_MUL(v0, v1, v2, u[15], m[15]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ z[14] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ z[15] = t0;++ /* under 2m, with t1 the bit above n limbs: at most one subtraction */+ borrow = sub_n(r, z, m, 16);+ take = t1 | (borrow ^ 1);+ select_n(r, r, z, take & 1, 16);+}++/* r = a * a * R^-1 mod m, for a under m; t is 2n limbs of scratch */+static void crypton_mont_sqr16(limb_t *r, const limb_t *a,+ const limb_t *m, limb_t n0, limb_t *t)+{+ limb_t *u = t, *z = t + 16;+ limb_t t0 = 0, t1 = 0, t2 = 0, v0, v1, v2, w0, w1, w2, borrow, take;+ limb_t s0, s1, s2, c0, c1, c2;++ /* column 0 */+ MONT_MAC(t0, t1, t2, a[0], a[0]);+ u[0] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[0], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 1 */+ MONT_MUL(s0, s1, s2, a[0], a[1]);+ MONT_MAC(t0, t1, t2, u[0], m[1]);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[1] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[1], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 2 */+ MONT_MUL(s0, s1, s2, a[0], a[2]);+ MONT_MAC(t0, t1, t2, a[1], a[1]);+ MONT_MUL(v0, v1, v2, u[0], m[2]);+ MONT_MUL(w0, w1, w2, u[1], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[2] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[2], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 3 */+ MONT_MUL(s0, s1, s2, a[0], a[3]);+ MONT_MUL(c0, c1, c2, a[1], a[2]);+ MONT_MAC(t0, t1, t2, u[0], m[3]);+ MONT_MUL(v0, v1, v2, u[1], m[2]);+ MONT_MUL(w0, w1, w2, u[2], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[3] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[3], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 4 */+ MONT_MUL(s0, s1, s2, a[0], a[4]);+ MONT_MUL(c0, c1, c2, a[1], a[3]);+ MONT_MAC(t0, t1, t2, a[2], a[2]);+ MONT_MUL(v0, v1, v2, u[0], m[4]);+ MONT_MUL(w0, w1, w2, u[1], m[3]);+ MONT_MAC(t0, t1, t2, u[2], m[2]);+ MONT_MAC(v0, v1, v2, u[3], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[4] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[4], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 5 */+ MONT_MUL(s0, s1, s2, a[0], a[5]);+ MONT_MUL(c0, c1, c2, a[1], a[4]);+ MONT_MAC(s0, s1, s2, a[2], a[3]);+ MONT_MAC(t0, t1, t2, u[0], m[5]);+ MONT_MUL(v0, v1, v2, u[1], m[4]);+ MONT_MUL(w0, w1, w2, u[2], m[3]);+ MONT_MAC(t0, t1, t2, u[3], m[2]);+ MONT_MAC(v0, v1, v2, u[4], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[5] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[5], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 6 */+ MONT_MUL(s0, s1, s2, a[0], a[6]);+ MONT_MUL(c0, c1, c2, a[1], a[5]);+ MONT_MAC(s0, s1, s2, a[2], a[4]);+ MONT_MAC(t0, t1, t2, a[3], a[3]);+ MONT_MUL(v0, v1, v2, u[0], m[6]);+ MONT_MUL(w0, w1, w2, u[1], m[5]);+ MONT_MAC(t0, t1, t2, u[2], m[4]);+ MONT_MAC(v0, v1, v2, u[3], m[3]);+ MONT_MAC(w0, w1, w2, u[4], m[2]);+ MONT_MAC(t0, t1, t2, u[5], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[6] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[6], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 7 */+ MONT_MUL(s0, s1, s2, a[0], a[7]);+ MONT_MUL(c0, c1, c2, a[1], a[6]);+ MONT_MAC(s0, s1, s2, a[2], a[5]);+ MONT_MAC(c0, c1, c2, a[3], a[4]);+ MONT_MAC(t0, t1, t2, u[0], m[7]);+ MONT_MUL(v0, v1, v2, u[1], m[6]);+ MONT_MUL(w0, w1, w2, u[2], m[5]);+ MONT_MAC(t0, t1, t2, u[3], m[4]);+ MONT_MAC(v0, v1, v2, u[4], m[3]);+ MONT_MAC(w0, w1, w2, u[5], m[2]);+ MONT_MAC(t0, t1, t2, u[6], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[7] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[7], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 8 */+ MONT_MUL(s0, s1, s2, a[0], a[8]);+ MONT_MUL(c0, c1, c2, a[1], a[7]);+ MONT_MAC(s0, s1, s2, a[2], a[6]);+ MONT_MAC(c0, c1, c2, a[3], a[5]);+ MONT_MAC(t0, t1, t2, a[4], a[4]);+ MONT_MUL(v0, v1, v2, u[0], m[8]);+ MONT_MUL(w0, w1, w2, u[1], m[7]);+ MONT_MAC(t0, t1, t2, u[2], m[6]);+ MONT_MAC(v0, v1, v2, u[3], m[5]);+ MONT_MAC(w0, w1, w2, u[4], m[4]);+ MONT_MAC(t0, t1, t2, u[5], m[3]);+ MONT_MAC(v0, v1, v2, u[6], m[2]);+ MONT_MAC(w0, w1, w2, u[7], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[8] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[8], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 9 */+ MONT_MUL(s0, s1, s2, a[0], a[9]);+ MONT_MUL(c0, c1, c2, a[1], a[8]);+ MONT_MAC(s0, s1, s2, a[2], a[7]);+ MONT_MAC(c0, c1, c2, a[3], a[6]);+ MONT_MAC(s0, s1, s2, a[4], a[5]);+ MONT_MAC(t0, t1, t2, u[0], m[9]);+ MONT_MUL(v0, v1, v2, u[1], m[8]);+ MONT_MUL(w0, w1, w2, u[2], m[7]);+ MONT_MAC(t0, t1, t2, u[3], m[6]);+ MONT_MAC(v0, v1, v2, u[4], m[5]);+ MONT_MAC(w0, w1, w2, u[5], m[4]);+ MONT_MAC(t0, t1, t2, u[6], m[3]);+ MONT_MAC(v0, v1, v2, u[7], m[2]);+ MONT_MAC(w0, w1, w2, u[8], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[9] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[9], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 10 */+ MONT_MUL(s0, s1, s2, a[0], a[10]);+ MONT_MUL(c0, c1, c2, a[1], a[9]);+ MONT_MAC(s0, s1, s2, a[2], a[8]);+ MONT_MAC(c0, c1, c2, a[3], a[7]);+ MONT_MAC(s0, s1, s2, a[4], a[6]);+ MONT_MAC(t0, t1, t2, a[5], a[5]);+ MONT_MUL(v0, v1, v2, u[0], m[10]);+ MONT_MUL(w0, w1, w2, u[1], m[9]);+ MONT_MAC(t0, t1, t2, u[2], m[8]);+ MONT_MAC(v0, v1, v2, u[3], m[7]);+ MONT_MAC(w0, w1, w2, u[4], m[6]);+ MONT_MAC(t0, t1, t2, u[5], m[5]);+ MONT_MAC(v0, v1, v2, u[6], m[4]);+ MONT_MAC(w0, w1, w2, u[7], m[3]);+ MONT_MAC(t0, t1, t2, u[8], m[2]);+ MONT_MAC(v0, v1, v2, u[9], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[10] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[10], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 11 */+ MONT_MUL(s0, s1, s2, a[0], a[11]);+ MONT_MUL(c0, c1, c2, a[1], a[10]);+ MONT_MAC(s0, s1, s2, a[2], a[9]);+ MONT_MAC(c0, c1, c2, a[3], a[8]);+ MONT_MAC(s0, s1, s2, a[4], a[7]);+ MONT_MAC(c0, c1, c2, a[5], a[6]);+ MONT_MAC(t0, t1, t2, u[0], m[11]);+ MONT_MUL(v0, v1, v2, u[1], m[10]);+ MONT_MUL(w0, w1, w2, u[2], m[9]);+ MONT_MAC(t0, t1, t2, u[3], m[8]);+ MONT_MAC(v0, v1, v2, u[4], m[7]);+ MONT_MAC(w0, w1, w2, u[5], m[6]);+ MONT_MAC(t0, t1, t2, u[6], m[5]);+ MONT_MAC(v0, v1, v2, u[7], m[4]);+ MONT_MAC(w0, w1, w2, u[8], m[3]);+ MONT_MAC(t0, t1, t2, u[9], m[2]);+ MONT_MAC(v0, v1, v2, u[10], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[11] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[11], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 12 */+ MONT_MUL(s0, s1, s2, a[0], a[12]);+ MONT_MUL(c0, c1, c2, a[1], a[11]);+ MONT_MAC(s0, s1, s2, a[2], a[10]);+ MONT_MAC(c0, c1, c2, a[3], a[9]);+ MONT_MAC(s0, s1, s2, a[4], a[8]);+ MONT_MAC(c0, c1, c2, a[5], a[7]);+ MONT_MAC(t0, t1, t2, a[6], a[6]);+ MONT_MUL(v0, v1, v2, u[0], m[12]);+ MONT_MUL(w0, w1, w2, u[1], m[11]);+ MONT_MAC(t0, t1, t2, u[2], m[10]);+ MONT_MAC(v0, v1, v2, u[3], m[9]);+ MONT_MAC(w0, w1, w2, u[4], m[8]);+ MONT_MAC(t0, t1, t2, u[5], m[7]);+ MONT_MAC(v0, v1, v2, u[6], m[6]);+ MONT_MAC(w0, w1, w2, u[7], m[5]);+ MONT_MAC(t0, t1, t2, u[8], m[4]);+ MONT_MAC(v0, v1, v2, u[9], m[3]);+ MONT_MAC(w0, w1, w2, u[10], m[2]);+ MONT_MAC(t0, t1, t2, u[11], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[12] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[12], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 13 */+ MONT_MUL(s0, s1, s2, a[0], a[13]);+ MONT_MUL(c0, c1, c2, a[1], a[12]);+ MONT_MAC(s0, s1, s2, a[2], a[11]);+ MONT_MAC(c0, c1, c2, a[3], a[10]);+ MONT_MAC(s0, s1, s2, a[4], a[9]);+ MONT_MAC(c0, c1, c2, a[5], a[8]);+ MONT_MAC(s0, s1, s2, a[6], a[7]);+ MONT_MAC(t0, t1, t2, u[0], m[13]);+ MONT_MUL(v0, v1, v2, u[1], m[12]);+ MONT_MUL(w0, w1, w2, u[2], m[11]);+ MONT_MAC(t0, t1, t2, u[3], m[10]);+ MONT_MAC(v0, v1, v2, u[4], m[9]);+ MONT_MAC(w0, w1, w2, u[5], m[8]);+ MONT_MAC(t0, t1, t2, u[6], m[7]);+ MONT_MAC(v0, v1, v2, u[7], m[6]);+ MONT_MAC(w0, w1, w2, u[8], m[5]);+ MONT_MAC(t0, t1, t2, u[9], m[4]);+ MONT_MAC(v0, v1, v2, u[10], m[3]);+ MONT_MAC(w0, w1, w2, u[11], m[2]);+ MONT_MAC(t0, t1, t2, u[12], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[13] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[13], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 14 */+ MONT_MUL(s0, s1, s2, a[0], a[14]);+ MONT_MUL(c0, c1, c2, a[1], a[13]);+ MONT_MAC(s0, s1, s2, a[2], a[12]);+ MONT_MAC(c0, c1, c2, a[3], a[11]);+ MONT_MAC(s0, s1, s2, a[4], a[10]);+ MONT_MAC(c0, c1, c2, a[5], a[9]);+ MONT_MAC(s0, s1, s2, a[6], a[8]);+ MONT_MAC(t0, t1, t2, a[7], a[7]);+ MONT_MUL(v0, v1, v2, u[0], m[14]);+ MONT_MUL(w0, w1, w2, u[1], m[13]);+ MONT_MAC(t0, t1, t2, u[2], m[12]);+ MONT_MAC(v0, v1, v2, u[3], m[11]);+ MONT_MAC(w0, w1, w2, u[4], m[10]);+ MONT_MAC(t0, t1, t2, u[5], m[9]);+ MONT_MAC(v0, v1, v2, u[6], m[8]);+ MONT_MAC(w0, w1, w2, u[7], m[7]);+ MONT_MAC(t0, t1, t2, u[8], m[6]);+ MONT_MAC(v0, v1, v2, u[9], m[5]);+ MONT_MAC(w0, w1, w2, u[10], m[4]);+ MONT_MAC(t0, t1, t2, u[11], m[3]);+ MONT_MAC(v0, v1, v2, u[12], m[2]);+ MONT_MAC(w0, w1, w2, u[13], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[14] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[14], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 15 */+ MONT_MUL(s0, s1, s2, a[0], a[15]);+ MONT_MUL(c0, c1, c2, a[1], a[14]);+ MONT_MAC(s0, s1, s2, a[2], a[13]);+ MONT_MAC(c0, c1, c2, a[3], a[12]);+ MONT_MAC(s0, s1, s2, a[4], a[11]);+ MONT_MAC(c0, c1, c2, a[5], a[10]);+ MONT_MAC(s0, s1, s2, a[6], a[9]);+ MONT_MAC(c0, c1, c2, a[7], a[8]);+ MONT_MAC(t0, t1, t2, u[0], m[15]);+ MONT_MUL(v0, v1, v2, u[1], m[14]);+ MONT_MUL(w0, w1, w2, u[2], m[13]);+ MONT_MAC(t0, t1, t2, u[3], m[12]);+ MONT_MAC(v0, v1, v2, u[4], m[11]);+ MONT_MAC(w0, w1, w2, u[5], m[10]);+ MONT_MAC(t0, t1, t2, u[6], m[9]);+ MONT_MAC(v0, v1, v2, u[7], m[8]);+ MONT_MAC(w0, w1, w2, u[8], m[7]);+ MONT_MAC(t0, t1, t2, u[9], m[6]);+ MONT_MAC(v0, v1, v2, u[10], m[5]);+ MONT_MAC(w0, w1, w2, u[11], m[4]);+ MONT_MAC(t0, t1, t2, u[12], m[3]);+ MONT_MAC(v0, v1, v2, u[13], m[2]);+ MONT_MAC(w0, w1, w2, u[14], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[15] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[15], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 16 */+ MONT_MUL(s0, s1, s2, a[1], a[15]);+ MONT_MUL(c0, c1, c2, a[2], a[14]);+ MONT_MAC(s0, s1, s2, a[3], a[13]);+ MONT_MAC(c0, c1, c2, a[4], a[12]);+ MONT_MAC(s0, s1, s2, a[5], a[11]);+ MONT_MAC(c0, c1, c2, a[6], a[10]);+ MONT_MAC(s0, s1, s2, a[7], a[9]);+ MONT_MAC(t0, t1, t2, a[8], a[8]);+ MONT_MUL(v0, v1, v2, u[1], m[15]);+ MONT_MUL(w0, w1, w2, u[2], m[14]);+ MONT_MAC(t0, t1, t2, u[3], m[13]);+ MONT_MAC(v0, v1, v2, u[4], m[12]);+ MONT_MAC(w0, w1, w2, u[5], m[11]);+ MONT_MAC(t0, t1, t2, u[6], m[10]);+ MONT_MAC(v0, v1, v2, u[7], m[9]);+ MONT_MAC(w0, w1, w2, u[8], m[8]);+ MONT_MAC(t0, t1, t2, u[9], m[7]);+ MONT_MAC(v0, v1, v2, u[10], m[6]);+ MONT_MAC(w0, w1, w2, u[11], m[5]);+ MONT_MAC(t0, t1, t2, u[12], m[4]);+ MONT_MAC(v0, v1, v2, u[13], m[3]);+ MONT_MAC(w0, w1, w2, u[14], m[2]);+ MONT_MAC(t0, t1, t2, u[15], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[0] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 17 */+ MONT_MUL(s0, s1, s2, a[2], a[15]);+ MONT_MUL(c0, c1, c2, a[3], a[14]);+ MONT_MAC(s0, s1, s2, a[4], a[13]);+ MONT_MAC(c0, c1, c2, a[5], a[12]);+ MONT_MAC(s0, s1, s2, a[6], a[11]);+ MONT_MAC(c0, c1, c2, a[7], a[10]);+ MONT_MAC(s0, s1, s2, a[8], a[9]);+ MONT_MAC(t0, t1, t2, u[2], m[15]);+ MONT_MUL(v0, v1, v2, u[3], m[14]);+ MONT_MUL(w0, w1, w2, u[4], m[13]);+ MONT_MAC(t0, t1, t2, u[5], m[12]);+ MONT_MAC(v0, v1, v2, u[6], m[11]);+ MONT_MAC(w0, w1, w2, u[7], m[10]);+ MONT_MAC(t0, t1, t2, u[8], m[9]);+ MONT_MAC(v0, v1, v2, u[9], m[8]);+ MONT_MAC(w0, w1, w2, u[10], m[7]);+ MONT_MAC(t0, t1, t2, u[11], m[6]);+ MONT_MAC(v0, v1, v2, u[12], m[5]);+ MONT_MAC(w0, w1, w2, u[13], m[4]);+ MONT_MAC(t0, t1, t2, u[14], m[3]);+ MONT_MAC(v0, v1, v2, u[15], m[2]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[1] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 18 */+ MONT_MUL(s0, s1, s2, a[3], a[15]);+ MONT_MUL(c0, c1, c2, a[4], a[14]);+ MONT_MAC(s0, s1, s2, a[5], a[13]);+ MONT_MAC(c0, c1, c2, a[6], a[12]);+ MONT_MAC(s0, s1, s2, a[7], a[11]);+ MONT_MAC(c0, c1, c2, a[8], a[10]);+ MONT_MAC(t0, t1, t2, a[9], a[9]);+ MONT_MUL(v0, v1, v2, u[3], m[15]);+ MONT_MUL(w0, w1, w2, u[4], m[14]);+ MONT_MAC(t0, t1, t2, u[5], m[13]);+ MONT_MAC(v0, v1, v2, u[6], m[12]);+ MONT_MAC(w0, w1, w2, u[7], m[11]);+ MONT_MAC(t0, t1, t2, u[8], m[10]);+ MONT_MAC(v0, v1, v2, u[9], m[9]);+ MONT_MAC(w0, w1, w2, u[10], m[8]);+ MONT_MAC(t0, t1, t2, u[11], m[7]);+ MONT_MAC(v0, v1, v2, u[12], m[6]);+ MONT_MAC(w0, w1, w2, u[13], m[5]);+ MONT_MAC(t0, t1, t2, u[14], m[4]);+ MONT_MAC(v0, v1, v2, u[15], m[3]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[2] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 19 */+ MONT_MUL(s0, s1, s2, a[4], a[15]);+ MONT_MUL(c0, c1, c2, a[5], a[14]);+ MONT_MAC(s0, s1, s2, a[6], a[13]);+ MONT_MAC(c0, c1, c2, a[7], a[12]);+ MONT_MAC(s0, s1, s2, a[8], a[11]);+ MONT_MAC(c0, c1, c2, a[9], a[10]);+ MONT_MAC(t0, t1, t2, u[4], m[15]);+ MONT_MUL(v0, v1, v2, u[5], m[14]);+ MONT_MUL(w0, w1, w2, u[6], m[13]);+ MONT_MAC(t0, t1, t2, u[7], m[12]);+ MONT_MAC(v0, v1, v2, u[8], m[11]);+ MONT_MAC(w0, w1, w2, u[9], m[10]);+ MONT_MAC(t0, t1, t2, u[10], m[9]);+ MONT_MAC(v0, v1, v2, u[11], m[8]);+ MONT_MAC(w0, w1, w2, u[12], m[7]);+ MONT_MAC(t0, t1, t2, u[13], m[6]);+ MONT_MAC(v0, v1, v2, u[14], m[5]);+ MONT_MAC(w0, w1, w2, u[15], m[4]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[3] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 20 */+ MONT_MUL(s0, s1, s2, a[5], a[15]);+ MONT_MUL(c0, c1, c2, a[6], a[14]);+ MONT_MAC(s0, s1, s2, a[7], a[13]);+ MONT_MAC(c0, c1, c2, a[8], a[12]);+ MONT_MAC(s0, s1, s2, a[9], a[11]);+ MONT_MAC(t0, t1, t2, a[10], a[10]);+ MONT_MUL(v0, v1, v2, u[5], m[15]);+ MONT_MUL(w0, w1, w2, u[6], m[14]);+ MONT_MAC(t0, t1, t2, u[7], m[13]);+ MONT_MAC(v0, v1, v2, u[8], m[12]);+ MONT_MAC(w0, w1, w2, u[9], m[11]);+ MONT_MAC(t0, t1, t2, u[10], m[10]);+ MONT_MAC(v0, v1, v2, u[11], m[9]);+ MONT_MAC(w0, w1, w2, u[12], m[8]);+ MONT_MAC(t0, t1, t2, u[13], m[7]);+ MONT_MAC(v0, v1, v2, u[14], m[6]);+ MONT_MAC(w0, w1, w2, u[15], m[5]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[4] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 21 */+ MONT_MUL(s0, s1, s2, a[6], a[15]);+ MONT_MUL(c0, c1, c2, a[7], a[14]);+ MONT_MAC(s0, s1, s2, a[8], a[13]);+ MONT_MAC(c0, c1, c2, a[9], a[12]);+ MONT_MAC(s0, s1, s2, a[10], a[11]);+ MONT_MAC(t0, t1, t2, u[6], m[15]);+ MONT_MUL(v0, v1, v2, u[7], m[14]);+ MONT_MUL(w0, w1, w2, u[8], m[13]);+ MONT_MAC(t0, t1, t2, u[9], m[12]);+ MONT_MAC(v0, v1, v2, u[10], m[11]);+ MONT_MAC(w0, w1, w2, u[11], m[10]);+ MONT_MAC(t0, t1, t2, u[12], m[9]);+ MONT_MAC(v0, v1, v2, u[13], m[8]);+ MONT_MAC(w0, w1, w2, u[14], m[7]);+ MONT_MAC(t0, t1, t2, u[15], m[6]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[5] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 22 */+ MONT_MUL(s0, s1, s2, a[7], a[15]);+ MONT_MUL(c0, c1, c2, a[8], a[14]);+ MONT_MAC(s0, s1, s2, a[9], a[13]);+ MONT_MAC(c0, c1, c2, a[10], a[12]);+ MONT_MAC(t0, t1, t2, a[11], a[11]);+ MONT_MUL(v0, v1, v2, u[7], m[15]);+ MONT_MUL(w0, w1, w2, u[8], m[14]);+ MONT_MAC(t0, t1, t2, u[9], m[13]);+ MONT_MAC(v0, v1, v2, u[10], m[12]);+ MONT_MAC(w0, w1, w2, u[11], m[11]);+ MONT_MAC(t0, t1, t2, u[12], m[10]);+ MONT_MAC(v0, v1, v2, u[13], m[9]);+ MONT_MAC(w0, w1, w2, u[14], m[8]);+ MONT_MAC(t0, t1, t2, u[15], m[7]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[6] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 23 */+ MONT_MUL(s0, s1, s2, a[8], a[15]);+ MONT_MUL(c0, c1, c2, a[9], a[14]);+ MONT_MAC(s0, s1, s2, a[10], a[13]);+ MONT_MAC(c0, c1, c2, a[11], a[12]);+ MONT_MAC(t0, t1, t2, u[8], m[15]);+ MONT_MUL(v0, v1, v2, u[9], m[14]);+ MONT_MUL(w0, w1, w2, u[10], m[13]);+ MONT_MAC(t0, t1, t2, u[11], m[12]);+ MONT_MAC(v0, v1, v2, u[12], m[11]);+ MONT_MAC(w0, w1, w2, u[13], m[10]);+ MONT_MAC(t0, t1, t2, u[14], m[9]);+ MONT_MAC(v0, v1, v2, u[15], m[8]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[7] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 24 */+ MONT_MUL(s0, s1, s2, a[9], a[15]);+ MONT_MUL(c0, c1, c2, a[10], a[14]);+ MONT_MAC(s0, s1, s2, a[11], a[13]);+ MONT_MAC(t0, t1, t2, a[12], a[12]);+ MONT_MUL(v0, v1, v2, u[9], m[15]);+ MONT_MUL(w0, w1, w2, u[10], m[14]);+ MONT_MAC(t0, t1, t2, u[11], m[13]);+ MONT_MAC(v0, v1, v2, u[12], m[12]);+ MONT_MAC(w0, w1, w2, u[13], m[11]);+ MONT_MAC(t0, t1, t2, u[14], m[10]);+ MONT_MAC(v0, v1, v2, u[15], m[9]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[8] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 25 */+ MONT_MUL(s0, s1, s2, a[10], a[15]);+ MONT_MUL(c0, c1, c2, a[11], a[14]);+ MONT_MAC(s0, s1, s2, a[12], a[13]);+ MONT_MAC(t0, t1, t2, u[10], m[15]);+ MONT_MUL(v0, v1, v2, u[11], m[14]);+ MONT_MUL(w0, w1, w2, u[12], m[13]);+ MONT_MAC(t0, t1, t2, u[13], m[12]);+ MONT_MAC(v0, v1, v2, u[14], m[11]);+ MONT_MAC(w0, w1, w2, u[15], m[10]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[9] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 26 */+ MONT_MUL(s0, s1, s2, a[11], a[15]);+ MONT_MUL(c0, c1, c2, a[12], a[14]);+ MONT_MAC(t0, t1, t2, a[13], a[13]);+ MONT_MUL(v0, v1, v2, u[11], m[15]);+ MONT_MUL(w0, w1, w2, u[12], m[14]);+ MONT_MAC(t0, t1, t2, u[13], m[13]);+ MONT_MAC(v0, v1, v2, u[14], m[12]);+ MONT_MAC(w0, w1, w2, u[15], m[11]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[10] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 27 */+ MONT_MUL(s0, s1, s2, a[12], a[15]);+ MONT_MUL(c0, c1, c2, a[13], a[14]);+ MONT_MAC(t0, t1, t2, u[12], m[15]);+ MONT_MUL(v0, v1, v2, u[13], m[14]);+ MONT_MUL(w0, w1, w2, u[14], m[13]);+ MONT_MAC(t0, t1, t2, u[15], m[12]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[11] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 28 */+ MONT_MUL(s0, s1, s2, a[13], a[15]);+ MONT_MAC(t0, t1, t2, a[14], a[14]);+ MONT_MUL(v0, v1, v2, u[13], m[15]);+ MONT_MUL(w0, w1, w2, u[14], m[14]);+ MONT_MAC(t0, t1, t2, u[15], m[13]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[12] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 29 */+ MONT_MUL(s0, s1, s2, a[14], a[15]);+ MONT_MAC(t0, t1, t2, u[14], m[15]);+ MONT_MUL(v0, v1, v2, u[15], m[14]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[13] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 30 */+ MONT_MAC(t0, t1, t2, a[15], a[15]);+ MONT_MUL(v0, v1, v2, u[15], m[15]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ z[14] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ z[15] = t0;++ /* under 2m, with t1 the bit above n limbs: at most one subtraction */+ borrow = sub_n(r, z, m, 16);+ take = t1 | (borrow ^ 1);+ select_n(r, r, z, take & 1, 16);+}++/* r = a * b * R^-1 mod m, for a and b under m; t is 2n limbs of scratch */+static void crypton_mont_mul24(limb_t *r, const limb_t *a, const limb_t *b,+ const limb_t *m, limb_t n0, limb_t *t)+{+ limb_t *u = t, *z = t + 24;+ limb_t t0 = 0, t1 = 0, t2 = 0, v0, v1, v2, w0, w1, w2, borrow, take;++ /* column 0 */+ MONT_MAC(t0, t1, t2, a[0], b[0]);+ u[0] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[0], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 1 */+ MONT_MAC(t0, t1, t2, a[0], b[1]);+ MONT_MUL(v0, v1, v2, a[1], b[0]);+ MONT_MUL(w0, w1, w2, u[0], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[1] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[1], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 2 */+ MONT_MAC(t0, t1, t2, a[0], b[2]);+ MONT_MUL(v0, v1, v2, a[1], b[1]);+ MONT_MUL(w0, w1, w2, a[2], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[2]);+ MONT_MAC(v0, v1, v2, u[1], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[2] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[2], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 3 */+ MONT_MAC(t0, t1, t2, a[0], b[3]);+ MONT_MUL(v0, v1, v2, a[1], b[2]);+ MONT_MUL(w0, w1, w2, a[2], b[1]);+ MONT_MAC(t0, t1, t2, a[3], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[3]);+ MONT_MAC(w0, w1, w2, u[1], m[2]);+ MONT_MAC(t0, t1, t2, u[2], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[3] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[3], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 4 */+ MONT_MAC(t0, t1, t2, a[0], b[4]);+ MONT_MUL(v0, v1, v2, a[1], b[3]);+ MONT_MUL(w0, w1, w2, a[2], b[2]);+ MONT_MAC(t0, t1, t2, a[3], b[1]);+ MONT_MAC(v0, v1, v2, a[4], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[4]);+ MONT_MAC(t0, t1, t2, u[1], m[3]);+ MONT_MAC(v0, v1, v2, u[2], m[2]);+ MONT_MAC(w0, w1, w2, u[3], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[4] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[4], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 5 */+ MONT_MAC(t0, t1, t2, a[0], b[5]);+ MONT_MUL(v0, v1, v2, a[1], b[4]);+ MONT_MUL(w0, w1, w2, a[2], b[3]);+ MONT_MAC(t0, t1, t2, a[3], b[2]);+ MONT_MAC(v0, v1, v2, a[4], b[1]);+ MONT_MAC(w0, w1, w2, a[5], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[5]);+ MONT_MAC(v0, v1, v2, u[1], m[4]);+ MONT_MAC(w0, w1, w2, u[2], m[3]);+ MONT_MAC(t0, t1, t2, u[3], m[2]);+ MONT_MAC(v0, v1, v2, u[4], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[5] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[5], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 6 */+ MONT_MAC(t0, t1, t2, a[0], b[6]);+ MONT_MUL(v0, v1, v2, a[1], b[5]);+ MONT_MUL(w0, w1, w2, a[2], b[4]);+ MONT_MAC(t0, t1, t2, a[3], b[3]);+ MONT_MAC(v0, v1, v2, a[4], b[2]);+ MONT_MAC(w0, w1, w2, a[5], b[1]);+ MONT_MAC(t0, t1, t2, a[6], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[6]);+ MONT_MAC(w0, w1, w2, u[1], m[5]);+ MONT_MAC(t0, t1, t2, u[2], m[4]);+ MONT_MAC(v0, v1, v2, u[3], m[3]);+ MONT_MAC(w0, w1, w2, u[4], m[2]);+ MONT_MAC(t0, t1, t2, u[5], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[6] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[6], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 7 */+ MONT_MAC(t0, t1, t2, a[0], b[7]);+ MONT_MUL(v0, v1, v2, a[1], b[6]);+ MONT_MUL(w0, w1, w2, a[2], b[5]);+ MONT_MAC(t0, t1, t2, a[3], b[4]);+ MONT_MAC(v0, v1, v2, a[4], b[3]);+ MONT_MAC(w0, w1, w2, a[5], b[2]);+ MONT_MAC(t0, t1, t2, a[6], b[1]);+ MONT_MAC(v0, v1, v2, a[7], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[7]);+ MONT_MAC(t0, t1, t2, u[1], m[6]);+ MONT_MAC(v0, v1, v2, u[2], m[5]);+ MONT_MAC(w0, w1, w2, u[3], m[4]);+ MONT_MAC(t0, t1, t2, u[4], m[3]);+ MONT_MAC(v0, v1, v2, u[5], m[2]);+ MONT_MAC(w0, w1, w2, u[6], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[7] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[7], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 8 */+ MONT_MAC(t0, t1, t2, a[0], b[8]);+ MONT_MUL(v0, v1, v2, a[1], b[7]);+ MONT_MUL(w0, w1, w2, a[2], b[6]);+ MONT_MAC(t0, t1, t2, a[3], b[5]);+ MONT_MAC(v0, v1, v2, a[4], b[4]);+ MONT_MAC(w0, w1, w2, a[5], b[3]);+ MONT_MAC(t0, t1, t2, a[6], b[2]);+ MONT_MAC(v0, v1, v2, a[7], b[1]);+ MONT_MAC(w0, w1, w2, a[8], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[8]);+ MONT_MAC(v0, v1, v2, u[1], m[7]);+ MONT_MAC(w0, w1, w2, u[2], m[6]);+ MONT_MAC(t0, t1, t2, u[3], m[5]);+ MONT_MAC(v0, v1, v2, u[4], m[4]);+ MONT_MAC(w0, w1, w2, u[5], m[3]);+ MONT_MAC(t0, t1, t2, u[6], m[2]);+ MONT_MAC(v0, v1, v2, u[7], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[8] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[8], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 9 */+ MONT_MAC(t0, t1, t2, a[0], b[9]);+ MONT_MUL(v0, v1, v2, a[1], b[8]);+ MONT_MUL(w0, w1, w2, a[2], b[7]);+ MONT_MAC(t0, t1, t2, a[3], b[6]);+ MONT_MAC(v0, v1, v2, a[4], b[5]);+ MONT_MAC(w0, w1, w2, a[5], b[4]);+ MONT_MAC(t0, t1, t2, a[6], b[3]);+ MONT_MAC(v0, v1, v2, a[7], b[2]);+ MONT_MAC(w0, w1, w2, a[8], b[1]);+ MONT_MAC(t0, t1, t2, a[9], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[9]);+ MONT_MAC(w0, w1, w2, u[1], m[8]);+ MONT_MAC(t0, t1, t2, u[2], m[7]);+ MONT_MAC(v0, v1, v2, u[3], m[6]);+ MONT_MAC(w0, w1, w2, u[4], m[5]);+ MONT_MAC(t0, t1, t2, u[5], m[4]);+ MONT_MAC(v0, v1, v2, u[6], m[3]);+ MONT_MAC(w0, w1, w2, u[7], m[2]);+ MONT_MAC(t0, t1, t2, u[8], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[9] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[9], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 10 */+ MONT_MAC(t0, t1, t2, a[0], b[10]);+ MONT_MUL(v0, v1, v2, a[1], b[9]);+ MONT_MUL(w0, w1, w2, a[2], b[8]);+ MONT_MAC(t0, t1, t2, a[3], b[7]);+ MONT_MAC(v0, v1, v2, a[4], b[6]);+ MONT_MAC(w0, w1, w2, a[5], b[5]);+ MONT_MAC(t0, t1, t2, a[6], b[4]);+ MONT_MAC(v0, v1, v2, a[7], b[3]);+ MONT_MAC(w0, w1, w2, a[8], b[2]);+ MONT_MAC(t0, t1, t2, a[9], b[1]);+ MONT_MAC(v0, v1, v2, a[10], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[10]);+ MONT_MAC(t0, t1, t2, u[1], m[9]);+ MONT_MAC(v0, v1, v2, u[2], m[8]);+ MONT_MAC(w0, w1, w2, u[3], m[7]);+ MONT_MAC(t0, t1, t2, u[4], m[6]);+ MONT_MAC(v0, v1, v2, u[5], m[5]);+ MONT_MAC(w0, w1, w2, u[6], m[4]);+ MONT_MAC(t0, t1, t2, u[7], m[3]);+ MONT_MAC(v0, v1, v2, u[8], m[2]);+ MONT_MAC(w0, w1, w2, u[9], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[10] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[10], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 11 */+ MONT_MAC(t0, t1, t2, a[0], b[11]);+ MONT_MUL(v0, v1, v2, a[1], b[10]);+ MONT_MUL(w0, w1, w2, a[2], b[9]);+ MONT_MAC(t0, t1, t2, a[3], b[8]);+ MONT_MAC(v0, v1, v2, a[4], b[7]);+ MONT_MAC(w0, w1, w2, a[5], b[6]);+ MONT_MAC(t0, t1, t2, a[6], b[5]);+ MONT_MAC(v0, v1, v2, a[7], b[4]);+ MONT_MAC(w0, w1, w2, a[8], b[3]);+ MONT_MAC(t0, t1, t2, a[9], b[2]);+ MONT_MAC(v0, v1, v2, a[10], b[1]);+ MONT_MAC(w0, w1, w2, a[11], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[11]);+ MONT_MAC(v0, v1, v2, u[1], m[10]);+ MONT_MAC(w0, w1, w2, u[2], m[9]);+ MONT_MAC(t0, t1, t2, u[3], m[8]);+ MONT_MAC(v0, v1, v2, u[4], m[7]);+ MONT_MAC(w0, w1, w2, u[5], m[6]);+ MONT_MAC(t0, t1, t2, u[6], m[5]);+ MONT_MAC(v0, v1, v2, u[7], m[4]);+ MONT_MAC(w0, w1, w2, u[8], m[3]);+ MONT_MAC(t0, t1, t2, u[9], m[2]);+ MONT_MAC(v0, v1, v2, u[10], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[11] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[11], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 12 */+ MONT_MAC(t0, t1, t2, a[0], b[12]);+ MONT_MUL(v0, v1, v2, a[1], b[11]);+ MONT_MUL(w0, w1, w2, a[2], b[10]);+ MONT_MAC(t0, t1, t2, a[3], b[9]);+ MONT_MAC(v0, v1, v2, a[4], b[8]);+ MONT_MAC(w0, w1, w2, a[5], b[7]);+ MONT_MAC(t0, t1, t2, a[6], b[6]);+ MONT_MAC(v0, v1, v2, a[7], b[5]);+ MONT_MAC(w0, w1, w2, a[8], b[4]);+ MONT_MAC(t0, t1, t2, a[9], b[3]);+ MONT_MAC(v0, v1, v2, a[10], b[2]);+ MONT_MAC(w0, w1, w2, a[11], b[1]);+ MONT_MAC(t0, t1, t2, a[12], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[12]);+ MONT_MAC(w0, w1, w2, u[1], m[11]);+ MONT_MAC(t0, t1, t2, u[2], m[10]);+ MONT_MAC(v0, v1, v2, u[3], m[9]);+ MONT_MAC(w0, w1, w2, u[4], m[8]);+ MONT_MAC(t0, t1, t2, u[5], m[7]);+ MONT_MAC(v0, v1, v2, u[6], m[6]);+ MONT_MAC(w0, w1, w2, u[7], m[5]);+ MONT_MAC(t0, t1, t2, u[8], m[4]);+ MONT_MAC(v0, v1, v2, u[9], m[3]);+ MONT_MAC(w0, w1, w2, u[10], m[2]);+ MONT_MAC(t0, t1, t2, u[11], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[12] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[12], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 13 */+ MONT_MAC(t0, t1, t2, a[0], b[13]);+ MONT_MUL(v0, v1, v2, a[1], b[12]);+ MONT_MUL(w0, w1, w2, a[2], b[11]);+ MONT_MAC(t0, t1, t2, a[3], b[10]);+ MONT_MAC(v0, v1, v2, a[4], b[9]);+ MONT_MAC(w0, w1, w2, a[5], b[8]);+ MONT_MAC(t0, t1, t2, a[6], b[7]);+ MONT_MAC(v0, v1, v2, a[7], b[6]);+ MONT_MAC(w0, w1, w2, a[8], b[5]);+ MONT_MAC(t0, t1, t2, a[9], b[4]);+ MONT_MAC(v0, v1, v2, a[10], b[3]);+ MONT_MAC(w0, w1, w2, a[11], b[2]);+ MONT_MAC(t0, t1, t2, a[12], b[1]);+ MONT_MAC(v0, v1, v2, a[13], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[13]);+ MONT_MAC(t0, t1, t2, u[1], m[12]);+ MONT_MAC(v0, v1, v2, u[2], m[11]);+ MONT_MAC(w0, w1, w2, u[3], m[10]);+ MONT_MAC(t0, t1, t2, u[4], m[9]);+ MONT_MAC(v0, v1, v2, u[5], m[8]);+ MONT_MAC(w0, w1, w2, u[6], m[7]);+ MONT_MAC(t0, t1, t2, u[7], m[6]);+ MONT_MAC(v0, v1, v2, u[8], m[5]);+ MONT_MAC(w0, w1, w2, u[9], m[4]);+ MONT_MAC(t0, t1, t2, u[10], m[3]);+ MONT_MAC(v0, v1, v2, u[11], m[2]);+ MONT_MAC(w0, w1, w2, u[12], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[13] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[13], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 14 */+ MONT_MAC(t0, t1, t2, a[0], b[14]);+ MONT_MUL(v0, v1, v2, a[1], b[13]);+ MONT_MUL(w0, w1, w2, a[2], b[12]);+ MONT_MAC(t0, t1, t2, a[3], b[11]);+ MONT_MAC(v0, v1, v2, a[4], b[10]);+ MONT_MAC(w0, w1, w2, a[5], b[9]);+ MONT_MAC(t0, t1, t2, a[6], b[8]);+ MONT_MAC(v0, v1, v2, a[7], b[7]);+ MONT_MAC(w0, w1, w2, a[8], b[6]);+ MONT_MAC(t0, t1, t2, a[9], b[5]);+ MONT_MAC(v0, v1, v2, a[10], b[4]);+ MONT_MAC(w0, w1, w2, a[11], b[3]);+ MONT_MAC(t0, t1, t2, a[12], b[2]);+ MONT_MAC(v0, v1, v2, a[13], b[1]);+ MONT_MAC(w0, w1, w2, a[14], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[14]);+ MONT_MAC(v0, v1, v2, u[1], m[13]);+ MONT_MAC(w0, w1, w2, u[2], m[12]);+ MONT_MAC(t0, t1, t2, u[3], m[11]);+ MONT_MAC(v0, v1, v2, u[4], m[10]);+ MONT_MAC(w0, w1, w2, u[5], m[9]);+ MONT_MAC(t0, t1, t2, u[6], m[8]);+ MONT_MAC(v0, v1, v2, u[7], m[7]);+ MONT_MAC(w0, w1, w2, u[8], m[6]);+ MONT_MAC(t0, t1, t2, u[9], m[5]);+ MONT_MAC(v0, v1, v2, u[10], m[4]);+ MONT_MAC(w0, w1, w2, u[11], m[3]);+ MONT_MAC(t0, t1, t2, u[12], m[2]);+ MONT_MAC(v0, v1, v2, u[13], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[14] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[14], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 15 */+ MONT_MAC(t0, t1, t2, a[0], b[15]);+ MONT_MUL(v0, v1, v2, a[1], b[14]);+ MONT_MUL(w0, w1, w2, a[2], b[13]);+ MONT_MAC(t0, t1, t2, a[3], b[12]);+ MONT_MAC(v0, v1, v2, a[4], b[11]);+ MONT_MAC(w0, w1, w2, a[5], b[10]);+ MONT_MAC(t0, t1, t2, a[6], b[9]);+ MONT_MAC(v0, v1, v2, a[7], b[8]);+ MONT_MAC(w0, w1, w2, a[8], b[7]);+ MONT_MAC(t0, t1, t2, a[9], b[6]);+ MONT_MAC(v0, v1, v2, a[10], b[5]);+ MONT_MAC(w0, w1, w2, a[11], b[4]);+ MONT_MAC(t0, t1, t2, a[12], b[3]);+ MONT_MAC(v0, v1, v2, a[13], b[2]);+ MONT_MAC(w0, w1, w2, a[14], b[1]);+ MONT_MAC(t0, t1, t2, a[15], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[15]);+ MONT_MAC(w0, w1, w2, u[1], m[14]);+ MONT_MAC(t0, t1, t2, u[2], m[13]);+ MONT_MAC(v0, v1, v2, u[3], m[12]);+ MONT_MAC(w0, w1, w2, u[4], m[11]);+ MONT_MAC(t0, t1, t2, u[5], m[10]);+ MONT_MAC(v0, v1, v2, u[6], m[9]);+ MONT_MAC(w0, w1, w2, u[7], m[8]);+ MONT_MAC(t0, t1, t2, u[8], m[7]);+ MONT_MAC(v0, v1, v2, u[9], m[6]);+ MONT_MAC(w0, w1, w2, u[10], m[5]);+ MONT_MAC(t0, t1, t2, u[11], m[4]);+ MONT_MAC(v0, v1, v2, u[12], m[3]);+ MONT_MAC(w0, w1, w2, u[13], m[2]);+ MONT_MAC(t0, t1, t2, u[14], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[15] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[15], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 16 */+ MONT_MAC(t0, t1, t2, a[0], b[16]);+ MONT_MUL(v0, v1, v2, a[1], b[15]);+ MONT_MUL(w0, w1, w2, a[2], b[14]);+ MONT_MAC(t0, t1, t2, a[3], b[13]);+ MONT_MAC(v0, v1, v2, a[4], b[12]);+ MONT_MAC(w0, w1, w2, a[5], b[11]);+ MONT_MAC(t0, t1, t2, a[6], b[10]);+ MONT_MAC(v0, v1, v2, a[7], b[9]);+ MONT_MAC(w0, w1, w2, a[8], b[8]);+ MONT_MAC(t0, t1, t2, a[9], b[7]);+ MONT_MAC(v0, v1, v2, a[10], b[6]);+ MONT_MAC(w0, w1, w2, a[11], b[5]);+ MONT_MAC(t0, t1, t2, a[12], b[4]);+ MONT_MAC(v0, v1, v2, a[13], b[3]);+ MONT_MAC(w0, w1, w2, a[14], b[2]);+ MONT_MAC(t0, t1, t2, a[15], b[1]);+ MONT_MAC(v0, v1, v2, a[16], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[16]);+ MONT_MAC(t0, t1, t2, u[1], m[15]);+ MONT_MAC(v0, v1, v2, u[2], m[14]);+ MONT_MAC(w0, w1, w2, u[3], m[13]);+ MONT_MAC(t0, t1, t2, u[4], m[12]);+ MONT_MAC(v0, v1, v2, u[5], m[11]);+ MONT_MAC(w0, w1, w2, u[6], m[10]);+ MONT_MAC(t0, t1, t2, u[7], m[9]);+ MONT_MAC(v0, v1, v2, u[8], m[8]);+ MONT_MAC(w0, w1, w2, u[9], m[7]);+ MONT_MAC(t0, t1, t2, u[10], m[6]);+ MONT_MAC(v0, v1, v2, u[11], m[5]);+ MONT_MAC(w0, w1, w2, u[12], m[4]);+ MONT_MAC(t0, t1, t2, u[13], m[3]);+ MONT_MAC(v0, v1, v2, u[14], m[2]);+ MONT_MAC(w0, w1, w2, u[15], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[16] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[16], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 17 */+ MONT_MAC(t0, t1, t2, a[0], b[17]);+ MONT_MUL(v0, v1, v2, a[1], b[16]);+ MONT_MUL(w0, w1, w2, a[2], b[15]);+ MONT_MAC(t0, t1, t2, a[3], b[14]);+ MONT_MAC(v0, v1, v2, a[4], b[13]);+ MONT_MAC(w0, w1, w2, a[5], b[12]);+ MONT_MAC(t0, t1, t2, a[6], b[11]);+ MONT_MAC(v0, v1, v2, a[7], b[10]);+ MONT_MAC(w0, w1, w2, a[8], b[9]);+ MONT_MAC(t0, t1, t2, a[9], b[8]);+ MONT_MAC(v0, v1, v2, a[10], b[7]);+ MONT_MAC(w0, w1, w2, a[11], b[6]);+ MONT_MAC(t0, t1, t2, a[12], b[5]);+ MONT_MAC(v0, v1, v2, a[13], b[4]);+ MONT_MAC(w0, w1, w2, a[14], b[3]);+ MONT_MAC(t0, t1, t2, a[15], b[2]);+ MONT_MAC(v0, v1, v2, a[16], b[1]);+ MONT_MAC(w0, w1, w2, a[17], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[17]);+ MONT_MAC(v0, v1, v2, u[1], m[16]);+ MONT_MAC(w0, w1, w2, u[2], m[15]);+ MONT_MAC(t0, t1, t2, u[3], m[14]);+ MONT_MAC(v0, v1, v2, u[4], m[13]);+ MONT_MAC(w0, w1, w2, u[5], m[12]);+ MONT_MAC(t0, t1, t2, u[6], m[11]);+ MONT_MAC(v0, v1, v2, u[7], m[10]);+ MONT_MAC(w0, w1, w2, u[8], m[9]);+ MONT_MAC(t0, t1, t2, u[9], m[8]);+ MONT_MAC(v0, v1, v2, u[10], m[7]);+ MONT_MAC(w0, w1, w2, u[11], m[6]);+ MONT_MAC(t0, t1, t2, u[12], m[5]);+ MONT_MAC(v0, v1, v2, u[13], m[4]);+ MONT_MAC(w0, w1, w2, u[14], m[3]);+ MONT_MAC(t0, t1, t2, u[15], m[2]);+ MONT_MAC(v0, v1, v2, u[16], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[17] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[17], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 18 */+ MONT_MAC(t0, t1, t2, a[0], b[18]);+ MONT_MUL(v0, v1, v2, a[1], b[17]);+ MONT_MUL(w0, w1, w2, a[2], b[16]);+ MONT_MAC(t0, t1, t2, a[3], b[15]);+ MONT_MAC(v0, v1, v2, a[4], b[14]);+ MONT_MAC(w0, w1, w2, a[5], b[13]);+ MONT_MAC(t0, t1, t2, a[6], b[12]);+ MONT_MAC(v0, v1, v2, a[7], b[11]);+ MONT_MAC(w0, w1, w2, a[8], b[10]);+ MONT_MAC(t0, t1, t2, a[9], b[9]);+ MONT_MAC(v0, v1, v2, a[10], b[8]);+ MONT_MAC(w0, w1, w2, a[11], b[7]);+ MONT_MAC(t0, t1, t2, a[12], b[6]);+ MONT_MAC(v0, v1, v2, a[13], b[5]);+ MONT_MAC(w0, w1, w2, a[14], b[4]);+ MONT_MAC(t0, t1, t2, a[15], b[3]);+ MONT_MAC(v0, v1, v2, a[16], b[2]);+ MONT_MAC(w0, w1, w2, a[17], b[1]);+ MONT_MAC(t0, t1, t2, a[18], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[18]);+ MONT_MAC(w0, w1, w2, u[1], m[17]);+ MONT_MAC(t0, t1, t2, u[2], m[16]);+ MONT_MAC(v0, v1, v2, u[3], m[15]);+ MONT_MAC(w0, w1, w2, u[4], m[14]);+ MONT_MAC(t0, t1, t2, u[5], m[13]);+ MONT_MAC(v0, v1, v2, u[6], m[12]);+ MONT_MAC(w0, w1, w2, u[7], m[11]);+ MONT_MAC(t0, t1, t2, u[8], m[10]);+ MONT_MAC(v0, v1, v2, u[9], m[9]);+ MONT_MAC(w0, w1, w2, u[10], m[8]);+ MONT_MAC(t0, t1, t2, u[11], m[7]);+ MONT_MAC(v0, v1, v2, u[12], m[6]);+ MONT_MAC(w0, w1, w2, u[13], m[5]);+ MONT_MAC(t0, t1, t2, u[14], m[4]);+ MONT_MAC(v0, v1, v2, u[15], m[3]);+ MONT_MAC(w0, w1, w2, u[16], m[2]);+ MONT_MAC(t0, t1, t2, u[17], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[18] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[18], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 19 */+ MONT_MAC(t0, t1, t2, a[0], b[19]);+ MONT_MUL(v0, v1, v2, a[1], b[18]);+ MONT_MUL(w0, w1, w2, a[2], b[17]);+ MONT_MAC(t0, t1, t2, a[3], b[16]);+ MONT_MAC(v0, v1, v2, a[4], b[15]);+ MONT_MAC(w0, w1, w2, a[5], b[14]);+ MONT_MAC(t0, t1, t2, a[6], b[13]);+ MONT_MAC(v0, v1, v2, a[7], b[12]);+ MONT_MAC(w0, w1, w2, a[8], b[11]);+ MONT_MAC(t0, t1, t2, a[9], b[10]);+ MONT_MAC(v0, v1, v2, a[10], b[9]);+ MONT_MAC(w0, w1, w2, a[11], b[8]);+ MONT_MAC(t0, t1, t2, a[12], b[7]);+ MONT_MAC(v0, v1, v2, a[13], b[6]);+ MONT_MAC(w0, w1, w2, a[14], b[5]);+ MONT_MAC(t0, t1, t2, a[15], b[4]);+ MONT_MAC(v0, v1, v2, a[16], b[3]);+ MONT_MAC(w0, w1, w2, a[17], b[2]);+ MONT_MAC(t0, t1, t2, a[18], b[1]);+ MONT_MAC(v0, v1, v2, a[19], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[19]);+ MONT_MAC(t0, t1, t2, u[1], m[18]);+ MONT_MAC(v0, v1, v2, u[2], m[17]);+ MONT_MAC(w0, w1, w2, u[3], m[16]);+ MONT_MAC(t0, t1, t2, u[4], m[15]);+ MONT_MAC(v0, v1, v2, u[5], m[14]);+ MONT_MAC(w0, w1, w2, u[6], m[13]);+ MONT_MAC(t0, t1, t2, u[7], m[12]);+ MONT_MAC(v0, v1, v2, u[8], m[11]);+ MONT_MAC(w0, w1, w2, u[9], m[10]);+ MONT_MAC(t0, t1, t2, u[10], m[9]);+ MONT_MAC(v0, v1, v2, u[11], m[8]);+ MONT_MAC(w0, w1, w2, u[12], m[7]);+ MONT_MAC(t0, t1, t2, u[13], m[6]);+ MONT_MAC(v0, v1, v2, u[14], m[5]);+ MONT_MAC(w0, w1, w2, u[15], m[4]);+ MONT_MAC(t0, t1, t2, u[16], m[3]);+ MONT_MAC(v0, v1, v2, u[17], m[2]);+ MONT_MAC(w0, w1, w2, u[18], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[19] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[19], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 20 */+ MONT_MAC(t0, t1, t2, a[0], b[20]);+ MONT_MUL(v0, v1, v2, a[1], b[19]);+ MONT_MUL(w0, w1, w2, a[2], b[18]);+ MONT_MAC(t0, t1, t2, a[3], b[17]);+ MONT_MAC(v0, v1, v2, a[4], b[16]);+ MONT_MAC(w0, w1, w2, a[5], b[15]);+ MONT_MAC(t0, t1, t2, a[6], b[14]);+ MONT_MAC(v0, v1, v2, a[7], b[13]);+ MONT_MAC(w0, w1, w2, a[8], b[12]);+ MONT_MAC(t0, t1, t2, a[9], b[11]);+ MONT_MAC(v0, v1, v2, a[10], b[10]);+ MONT_MAC(w0, w1, w2, a[11], b[9]);+ MONT_MAC(t0, t1, t2, a[12], b[8]);+ MONT_MAC(v0, v1, v2, a[13], b[7]);+ MONT_MAC(w0, w1, w2, a[14], b[6]);+ MONT_MAC(t0, t1, t2, a[15], b[5]);+ MONT_MAC(v0, v1, v2, a[16], b[4]);+ MONT_MAC(w0, w1, w2, a[17], b[3]);+ MONT_MAC(t0, t1, t2, a[18], b[2]);+ MONT_MAC(v0, v1, v2, a[19], b[1]);+ MONT_MAC(w0, w1, w2, a[20], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[20]);+ MONT_MAC(v0, v1, v2, u[1], m[19]);+ MONT_MAC(w0, w1, w2, u[2], m[18]);+ MONT_MAC(t0, t1, t2, u[3], m[17]);+ MONT_MAC(v0, v1, v2, u[4], m[16]);+ MONT_MAC(w0, w1, w2, u[5], m[15]);+ MONT_MAC(t0, t1, t2, u[6], m[14]);+ MONT_MAC(v0, v1, v2, u[7], m[13]);+ MONT_MAC(w0, w1, w2, u[8], m[12]);+ MONT_MAC(t0, t1, t2, u[9], m[11]);+ MONT_MAC(v0, v1, v2, u[10], m[10]);+ MONT_MAC(w0, w1, w2, u[11], m[9]);+ MONT_MAC(t0, t1, t2, u[12], m[8]);+ MONT_MAC(v0, v1, v2, u[13], m[7]);+ MONT_MAC(w0, w1, w2, u[14], m[6]);+ MONT_MAC(t0, t1, t2, u[15], m[5]);+ MONT_MAC(v0, v1, v2, u[16], m[4]);+ MONT_MAC(w0, w1, w2, u[17], m[3]);+ MONT_MAC(t0, t1, t2, u[18], m[2]);+ MONT_MAC(v0, v1, v2, u[19], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[20] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[20], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 21 */+ MONT_MAC(t0, t1, t2, a[0], b[21]);+ MONT_MUL(v0, v1, v2, a[1], b[20]);+ MONT_MUL(w0, w1, w2, a[2], b[19]);+ MONT_MAC(t0, t1, t2, a[3], b[18]);+ MONT_MAC(v0, v1, v2, a[4], b[17]);+ MONT_MAC(w0, w1, w2, a[5], b[16]);+ MONT_MAC(t0, t1, t2, a[6], b[15]);+ MONT_MAC(v0, v1, v2, a[7], b[14]);+ MONT_MAC(w0, w1, w2, a[8], b[13]);+ MONT_MAC(t0, t1, t2, a[9], b[12]);+ MONT_MAC(v0, v1, v2, a[10], b[11]);+ MONT_MAC(w0, w1, w2, a[11], b[10]);+ MONT_MAC(t0, t1, t2, a[12], b[9]);+ MONT_MAC(v0, v1, v2, a[13], b[8]);+ MONT_MAC(w0, w1, w2, a[14], b[7]);+ MONT_MAC(t0, t1, t2, a[15], b[6]);+ MONT_MAC(v0, v1, v2, a[16], b[5]);+ MONT_MAC(w0, w1, w2, a[17], b[4]);+ MONT_MAC(t0, t1, t2, a[18], b[3]);+ MONT_MAC(v0, v1, v2, a[19], b[2]);+ MONT_MAC(w0, w1, w2, a[20], b[1]);+ MONT_MAC(t0, t1, t2, a[21], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[21]);+ MONT_MAC(w0, w1, w2, u[1], m[20]);+ MONT_MAC(t0, t1, t2, u[2], m[19]);+ MONT_MAC(v0, v1, v2, u[3], m[18]);+ MONT_MAC(w0, w1, w2, u[4], m[17]);+ MONT_MAC(t0, t1, t2, u[5], m[16]);+ MONT_MAC(v0, v1, v2, u[6], m[15]);+ MONT_MAC(w0, w1, w2, u[7], m[14]);+ MONT_MAC(t0, t1, t2, u[8], m[13]);+ MONT_MAC(v0, v1, v2, u[9], m[12]);+ MONT_MAC(w0, w1, w2, u[10], m[11]);+ MONT_MAC(t0, t1, t2, u[11], m[10]);+ MONT_MAC(v0, v1, v2, u[12], m[9]);+ MONT_MAC(w0, w1, w2, u[13], m[8]);+ MONT_MAC(t0, t1, t2, u[14], m[7]);+ MONT_MAC(v0, v1, v2, u[15], m[6]);+ MONT_MAC(w0, w1, w2, u[16], m[5]);+ MONT_MAC(t0, t1, t2, u[17], m[4]);+ MONT_MAC(v0, v1, v2, u[18], m[3]);+ MONT_MAC(w0, w1, w2, u[19], m[2]);+ MONT_MAC(t0, t1, t2, u[20], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[21] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[21], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 22 */+ MONT_MAC(t0, t1, t2, a[0], b[22]);+ MONT_MUL(v0, v1, v2, a[1], b[21]);+ MONT_MUL(w0, w1, w2, a[2], b[20]);+ MONT_MAC(t0, t1, t2, a[3], b[19]);+ MONT_MAC(v0, v1, v2, a[4], b[18]);+ MONT_MAC(w0, w1, w2, a[5], b[17]);+ MONT_MAC(t0, t1, t2, a[6], b[16]);+ MONT_MAC(v0, v1, v2, a[7], b[15]);+ MONT_MAC(w0, w1, w2, a[8], b[14]);+ MONT_MAC(t0, t1, t2, a[9], b[13]);+ MONT_MAC(v0, v1, v2, a[10], b[12]);+ MONT_MAC(w0, w1, w2, a[11], b[11]);+ MONT_MAC(t0, t1, t2, a[12], b[10]);+ MONT_MAC(v0, v1, v2, a[13], b[9]);+ MONT_MAC(w0, w1, w2, a[14], b[8]);+ MONT_MAC(t0, t1, t2, a[15], b[7]);+ MONT_MAC(v0, v1, v2, a[16], b[6]);+ MONT_MAC(w0, w1, w2, a[17], b[5]);+ MONT_MAC(t0, t1, t2, a[18], b[4]);+ MONT_MAC(v0, v1, v2, a[19], b[3]);+ MONT_MAC(w0, w1, w2, a[20], b[2]);+ MONT_MAC(t0, t1, t2, a[21], b[1]);+ MONT_MAC(v0, v1, v2, a[22], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[22]);+ MONT_MAC(t0, t1, t2, u[1], m[21]);+ MONT_MAC(v0, v1, v2, u[2], m[20]);+ MONT_MAC(w0, w1, w2, u[3], m[19]);+ MONT_MAC(t0, t1, t2, u[4], m[18]);+ MONT_MAC(v0, v1, v2, u[5], m[17]);+ MONT_MAC(w0, w1, w2, u[6], m[16]);+ MONT_MAC(t0, t1, t2, u[7], m[15]);+ MONT_MAC(v0, v1, v2, u[8], m[14]);+ MONT_MAC(w0, w1, w2, u[9], m[13]);+ MONT_MAC(t0, t1, t2, u[10], m[12]);+ MONT_MAC(v0, v1, v2, u[11], m[11]);+ MONT_MAC(w0, w1, w2, u[12], m[10]);+ MONT_MAC(t0, t1, t2, u[13], m[9]);+ MONT_MAC(v0, v1, v2, u[14], m[8]);+ MONT_MAC(w0, w1, w2, u[15], m[7]);+ MONT_MAC(t0, t1, t2, u[16], m[6]);+ MONT_MAC(v0, v1, v2, u[17], m[5]);+ MONT_MAC(w0, w1, w2, u[18], m[4]);+ MONT_MAC(t0, t1, t2, u[19], m[3]);+ MONT_MAC(v0, v1, v2, u[20], m[2]);+ MONT_MAC(w0, w1, w2, u[21], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[22] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[22], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 23 */+ MONT_MAC(t0, t1, t2, a[0], b[23]);+ MONT_MUL(v0, v1, v2, a[1], b[22]);+ MONT_MUL(w0, w1, w2, a[2], b[21]);+ MONT_MAC(t0, t1, t2, a[3], b[20]);+ MONT_MAC(v0, v1, v2, a[4], b[19]);+ MONT_MAC(w0, w1, w2, a[5], b[18]);+ MONT_MAC(t0, t1, t2, a[6], b[17]);+ MONT_MAC(v0, v1, v2, a[7], b[16]);+ MONT_MAC(w0, w1, w2, a[8], b[15]);+ MONT_MAC(t0, t1, t2, a[9], b[14]);+ MONT_MAC(v0, v1, v2, a[10], b[13]);+ MONT_MAC(w0, w1, w2, a[11], b[12]);+ MONT_MAC(t0, t1, t2, a[12], b[11]);+ MONT_MAC(v0, v1, v2, a[13], b[10]);+ MONT_MAC(w0, w1, w2, a[14], b[9]);+ MONT_MAC(t0, t1, t2, a[15], b[8]);+ MONT_MAC(v0, v1, v2, a[16], b[7]);+ MONT_MAC(w0, w1, w2, a[17], b[6]);+ MONT_MAC(t0, t1, t2, a[18], b[5]);+ MONT_MAC(v0, v1, v2, a[19], b[4]);+ MONT_MAC(w0, w1, w2, a[20], b[3]);+ MONT_MAC(t0, t1, t2, a[21], b[2]);+ MONT_MAC(v0, v1, v2, a[22], b[1]);+ MONT_MAC(w0, w1, w2, a[23], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[23]);+ MONT_MAC(v0, v1, v2, u[1], m[22]);+ MONT_MAC(w0, w1, w2, u[2], m[21]);+ MONT_MAC(t0, t1, t2, u[3], m[20]);+ MONT_MAC(v0, v1, v2, u[4], m[19]);+ MONT_MAC(w0, w1, w2, u[5], m[18]);+ MONT_MAC(t0, t1, t2, u[6], m[17]);+ MONT_MAC(v0, v1, v2, u[7], m[16]);+ MONT_MAC(w0, w1, w2, u[8], m[15]);+ MONT_MAC(t0, t1, t2, u[9], m[14]);+ MONT_MAC(v0, v1, v2, u[10], m[13]);+ MONT_MAC(w0, w1, w2, u[11], m[12]);+ MONT_MAC(t0, t1, t2, u[12], m[11]);+ MONT_MAC(v0, v1, v2, u[13], m[10]);+ MONT_MAC(w0, w1, w2, u[14], m[9]);+ MONT_MAC(t0, t1, t2, u[15], m[8]);+ MONT_MAC(v0, v1, v2, u[16], m[7]);+ MONT_MAC(w0, w1, w2, u[17], m[6]);+ MONT_MAC(t0, t1, t2, u[18], m[5]);+ MONT_MAC(v0, v1, v2, u[19], m[4]);+ MONT_MAC(w0, w1, w2, u[20], m[3]);+ MONT_MAC(t0, t1, t2, u[21], m[2]);+ MONT_MAC(v0, v1, v2, u[22], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[23] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[23], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 24 */+ MONT_MAC(t0, t1, t2, a[1], b[23]);+ MONT_MUL(v0, v1, v2, a[2], b[22]);+ MONT_MUL(w0, w1, w2, a[3], b[21]);+ MONT_MAC(t0, t1, t2, a[4], b[20]);+ MONT_MAC(v0, v1, v2, a[5], b[19]);+ MONT_MAC(w0, w1, w2, a[6], b[18]);+ MONT_MAC(t0, t1, t2, a[7], b[17]);+ MONT_MAC(v0, v1, v2, a[8], b[16]);+ MONT_MAC(w0, w1, w2, a[9], b[15]);+ MONT_MAC(t0, t1, t2, a[10], b[14]);+ MONT_MAC(v0, v1, v2, a[11], b[13]);+ MONT_MAC(w0, w1, w2, a[12], b[12]);+ MONT_MAC(t0, t1, t2, a[13], b[11]);+ MONT_MAC(v0, v1, v2, a[14], b[10]);+ MONT_MAC(w0, w1, w2, a[15], b[9]);+ MONT_MAC(t0, t1, t2, a[16], b[8]);+ MONT_MAC(v0, v1, v2, a[17], b[7]);+ MONT_MAC(w0, w1, w2, a[18], b[6]);+ MONT_MAC(t0, t1, t2, a[19], b[5]);+ MONT_MAC(v0, v1, v2, a[20], b[4]);+ MONT_MAC(w0, w1, w2, a[21], b[3]);+ MONT_MAC(t0, t1, t2, a[22], b[2]);+ MONT_MAC(v0, v1, v2, a[23], b[1]);+ MONT_MAC(w0, w1, w2, u[1], m[23]);+ MONT_MAC(t0, t1, t2, u[2], m[22]);+ MONT_MAC(v0, v1, v2, u[3], m[21]);+ MONT_MAC(w0, w1, w2, u[4], m[20]);+ MONT_MAC(t0, t1, t2, u[5], m[19]);+ MONT_MAC(v0, v1, v2, u[6], m[18]);+ MONT_MAC(w0, w1, w2, u[7], m[17]);+ MONT_MAC(t0, t1, t2, u[8], m[16]);+ MONT_MAC(v0, v1, v2, u[9], m[15]);+ MONT_MAC(w0, w1, w2, u[10], m[14]);+ MONT_MAC(t0, t1, t2, u[11], m[13]);+ MONT_MAC(v0, v1, v2, u[12], m[12]);+ MONT_MAC(w0, w1, w2, u[13], m[11]);+ MONT_MAC(t0, t1, t2, u[14], m[10]);+ MONT_MAC(v0, v1, v2, u[15], m[9]);+ MONT_MAC(w0, w1, w2, u[16], m[8]);+ MONT_MAC(t0, t1, t2, u[17], m[7]);+ MONT_MAC(v0, v1, v2, u[18], m[6]);+ MONT_MAC(w0, w1, w2, u[19], m[5]);+ MONT_MAC(t0, t1, t2, u[20], m[4]);+ MONT_MAC(v0, v1, v2, u[21], m[3]);+ MONT_MAC(w0, w1, w2, u[22], m[2]);+ MONT_MAC(t0, t1, t2, u[23], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[0] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 25 */+ MONT_MAC(t0, t1, t2, a[2], b[23]);+ MONT_MUL(v0, v1, v2, a[3], b[22]);+ MONT_MUL(w0, w1, w2, a[4], b[21]);+ MONT_MAC(t0, t1, t2, a[5], b[20]);+ MONT_MAC(v0, v1, v2, a[6], b[19]);+ MONT_MAC(w0, w1, w2, a[7], b[18]);+ MONT_MAC(t0, t1, t2, a[8], b[17]);+ MONT_MAC(v0, v1, v2, a[9], b[16]);+ MONT_MAC(w0, w1, w2, a[10], b[15]);+ MONT_MAC(t0, t1, t2, a[11], b[14]);+ MONT_MAC(v0, v1, v2, a[12], b[13]);+ MONT_MAC(w0, w1, w2, a[13], b[12]);+ MONT_MAC(t0, t1, t2, a[14], b[11]);+ MONT_MAC(v0, v1, v2, a[15], b[10]);+ MONT_MAC(w0, w1, w2, a[16], b[9]);+ MONT_MAC(t0, t1, t2, a[17], b[8]);+ MONT_MAC(v0, v1, v2, a[18], b[7]);+ MONT_MAC(w0, w1, w2, a[19], b[6]);+ MONT_MAC(t0, t1, t2, a[20], b[5]);+ MONT_MAC(v0, v1, v2, a[21], b[4]);+ MONT_MAC(w0, w1, w2, a[22], b[3]);+ MONT_MAC(t0, t1, t2, a[23], b[2]);+ MONT_MAC(v0, v1, v2, u[2], m[23]);+ MONT_MAC(w0, w1, w2, u[3], m[22]);+ MONT_MAC(t0, t1, t2, u[4], m[21]);+ MONT_MAC(v0, v1, v2, u[5], m[20]);+ MONT_MAC(w0, w1, w2, u[6], m[19]);+ MONT_MAC(t0, t1, t2, u[7], m[18]);+ MONT_MAC(v0, v1, v2, u[8], m[17]);+ MONT_MAC(w0, w1, w2, u[9], m[16]);+ MONT_MAC(t0, t1, t2, u[10], m[15]);+ MONT_MAC(v0, v1, v2, u[11], m[14]);+ MONT_MAC(w0, w1, w2, u[12], m[13]);+ MONT_MAC(t0, t1, t2, u[13], m[12]);+ MONT_MAC(v0, v1, v2, u[14], m[11]);+ MONT_MAC(w0, w1, w2, u[15], m[10]);+ MONT_MAC(t0, t1, t2, u[16], m[9]);+ MONT_MAC(v0, v1, v2, u[17], m[8]);+ MONT_MAC(w0, w1, w2, u[18], m[7]);+ MONT_MAC(t0, t1, t2, u[19], m[6]);+ MONT_MAC(v0, v1, v2, u[20], m[5]);+ MONT_MAC(w0, w1, w2, u[21], m[4]);+ MONT_MAC(t0, t1, t2, u[22], m[3]);+ MONT_MAC(v0, v1, v2, u[23], m[2]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[1] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 26 */+ MONT_MAC(t0, t1, t2, a[3], b[23]);+ MONT_MUL(v0, v1, v2, a[4], b[22]);+ MONT_MUL(w0, w1, w2, a[5], b[21]);+ MONT_MAC(t0, t1, t2, a[6], b[20]);+ MONT_MAC(v0, v1, v2, a[7], b[19]);+ MONT_MAC(w0, w1, w2, a[8], b[18]);+ MONT_MAC(t0, t1, t2, a[9], b[17]);+ MONT_MAC(v0, v1, v2, a[10], b[16]);+ MONT_MAC(w0, w1, w2, a[11], b[15]);+ MONT_MAC(t0, t1, t2, a[12], b[14]);+ MONT_MAC(v0, v1, v2, a[13], b[13]);+ MONT_MAC(w0, w1, w2, a[14], b[12]);+ MONT_MAC(t0, t1, t2, a[15], b[11]);+ MONT_MAC(v0, v1, v2, a[16], b[10]);+ MONT_MAC(w0, w1, w2, a[17], b[9]);+ MONT_MAC(t0, t1, t2, a[18], b[8]);+ MONT_MAC(v0, v1, v2, a[19], b[7]);+ MONT_MAC(w0, w1, w2, a[20], b[6]);+ MONT_MAC(t0, t1, t2, a[21], b[5]);+ MONT_MAC(v0, v1, v2, a[22], b[4]);+ MONT_MAC(w0, w1, w2, a[23], b[3]);+ MONT_MAC(t0, t1, t2, u[3], m[23]);+ MONT_MAC(v0, v1, v2, u[4], m[22]);+ MONT_MAC(w0, w1, w2, u[5], m[21]);+ MONT_MAC(t0, t1, t2, u[6], m[20]);+ MONT_MAC(v0, v1, v2, u[7], m[19]);+ MONT_MAC(w0, w1, w2, u[8], m[18]);+ MONT_MAC(t0, t1, t2, u[9], m[17]);+ MONT_MAC(v0, v1, v2, u[10], m[16]);+ MONT_MAC(w0, w1, w2, u[11], m[15]);+ MONT_MAC(t0, t1, t2, u[12], m[14]);+ MONT_MAC(v0, v1, v2, u[13], m[13]);+ MONT_MAC(w0, w1, w2, u[14], m[12]);+ MONT_MAC(t0, t1, t2, u[15], m[11]);+ MONT_MAC(v0, v1, v2, u[16], m[10]);+ MONT_MAC(w0, w1, w2, u[17], m[9]);+ MONT_MAC(t0, t1, t2, u[18], m[8]);+ MONT_MAC(v0, v1, v2, u[19], m[7]);+ MONT_MAC(w0, w1, w2, u[20], m[6]);+ MONT_MAC(t0, t1, t2, u[21], m[5]);+ MONT_MAC(v0, v1, v2, u[22], m[4]);+ MONT_MAC(w0, w1, w2, u[23], m[3]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[2] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 27 */+ MONT_MAC(t0, t1, t2, a[4], b[23]);+ MONT_MUL(v0, v1, v2, a[5], b[22]);+ MONT_MUL(w0, w1, w2, a[6], b[21]);+ MONT_MAC(t0, t1, t2, a[7], b[20]);+ MONT_MAC(v0, v1, v2, a[8], b[19]);+ MONT_MAC(w0, w1, w2, a[9], b[18]);+ MONT_MAC(t0, t1, t2, a[10], b[17]);+ MONT_MAC(v0, v1, v2, a[11], b[16]);+ MONT_MAC(w0, w1, w2, a[12], b[15]);+ MONT_MAC(t0, t1, t2, a[13], b[14]);+ MONT_MAC(v0, v1, v2, a[14], b[13]);+ MONT_MAC(w0, w1, w2, a[15], b[12]);+ MONT_MAC(t0, t1, t2, a[16], b[11]);+ MONT_MAC(v0, v1, v2, a[17], b[10]);+ MONT_MAC(w0, w1, w2, a[18], b[9]);+ MONT_MAC(t0, t1, t2, a[19], b[8]);+ MONT_MAC(v0, v1, v2, a[20], b[7]);+ MONT_MAC(w0, w1, w2, a[21], b[6]);+ MONT_MAC(t0, t1, t2, a[22], b[5]);+ MONT_MAC(v0, v1, v2, a[23], b[4]);+ MONT_MAC(w0, w1, w2, u[4], m[23]);+ MONT_MAC(t0, t1, t2, u[5], m[22]);+ MONT_MAC(v0, v1, v2, u[6], m[21]);+ MONT_MAC(w0, w1, w2, u[7], m[20]);+ MONT_MAC(t0, t1, t2, u[8], m[19]);+ MONT_MAC(v0, v1, v2, u[9], m[18]);+ MONT_MAC(w0, w1, w2, u[10], m[17]);+ MONT_MAC(t0, t1, t2, u[11], m[16]);+ MONT_MAC(v0, v1, v2, u[12], m[15]);+ MONT_MAC(w0, w1, w2, u[13], m[14]);+ MONT_MAC(t0, t1, t2, u[14], m[13]);+ MONT_MAC(v0, v1, v2, u[15], m[12]);+ MONT_MAC(w0, w1, w2, u[16], m[11]);+ MONT_MAC(t0, t1, t2, u[17], m[10]);+ MONT_MAC(v0, v1, v2, u[18], m[9]);+ MONT_MAC(w0, w1, w2, u[19], m[8]);+ MONT_MAC(t0, t1, t2, u[20], m[7]);+ MONT_MAC(v0, v1, v2, u[21], m[6]);+ MONT_MAC(w0, w1, w2, u[22], m[5]);+ MONT_MAC(t0, t1, t2, u[23], m[4]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[3] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 28 */+ MONT_MAC(t0, t1, t2, a[5], b[23]);+ MONT_MUL(v0, v1, v2, a[6], b[22]);+ MONT_MUL(w0, w1, w2, a[7], b[21]);+ MONT_MAC(t0, t1, t2, a[8], b[20]);+ MONT_MAC(v0, v1, v2, a[9], b[19]);+ MONT_MAC(w0, w1, w2, a[10], b[18]);+ MONT_MAC(t0, t1, t2, a[11], b[17]);+ MONT_MAC(v0, v1, v2, a[12], b[16]);+ MONT_MAC(w0, w1, w2, a[13], b[15]);+ MONT_MAC(t0, t1, t2, a[14], b[14]);+ MONT_MAC(v0, v1, v2, a[15], b[13]);+ MONT_MAC(w0, w1, w2, a[16], b[12]);+ MONT_MAC(t0, t1, t2, a[17], b[11]);+ MONT_MAC(v0, v1, v2, a[18], b[10]);+ MONT_MAC(w0, w1, w2, a[19], b[9]);+ MONT_MAC(t0, t1, t2, a[20], b[8]);+ MONT_MAC(v0, v1, v2, a[21], b[7]);+ MONT_MAC(w0, w1, w2, a[22], b[6]);+ MONT_MAC(t0, t1, t2, a[23], b[5]);+ MONT_MAC(v0, v1, v2, u[5], m[23]);+ MONT_MAC(w0, w1, w2, u[6], m[22]);+ MONT_MAC(t0, t1, t2, u[7], m[21]);+ MONT_MAC(v0, v1, v2, u[8], m[20]);+ MONT_MAC(w0, w1, w2, u[9], m[19]);+ MONT_MAC(t0, t1, t2, u[10], m[18]);+ MONT_MAC(v0, v1, v2, u[11], m[17]);+ MONT_MAC(w0, w1, w2, u[12], m[16]);+ MONT_MAC(t0, t1, t2, u[13], m[15]);+ MONT_MAC(v0, v1, v2, u[14], m[14]);+ MONT_MAC(w0, w1, w2, u[15], m[13]);+ MONT_MAC(t0, t1, t2, u[16], m[12]);+ MONT_MAC(v0, v1, v2, u[17], m[11]);+ MONT_MAC(w0, w1, w2, u[18], m[10]);+ MONT_MAC(t0, t1, t2, u[19], m[9]);+ MONT_MAC(v0, v1, v2, u[20], m[8]);+ MONT_MAC(w0, w1, w2, u[21], m[7]);+ MONT_MAC(t0, t1, t2, u[22], m[6]);+ MONT_MAC(v0, v1, v2, u[23], m[5]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[4] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 29 */+ MONT_MAC(t0, t1, t2, a[6], b[23]);+ MONT_MUL(v0, v1, v2, a[7], b[22]);+ MONT_MUL(w0, w1, w2, a[8], b[21]);+ MONT_MAC(t0, t1, t2, a[9], b[20]);+ MONT_MAC(v0, v1, v2, a[10], b[19]);+ MONT_MAC(w0, w1, w2, a[11], b[18]);+ MONT_MAC(t0, t1, t2, a[12], b[17]);+ MONT_MAC(v0, v1, v2, a[13], b[16]);+ MONT_MAC(w0, w1, w2, a[14], b[15]);+ MONT_MAC(t0, t1, t2, a[15], b[14]);+ MONT_MAC(v0, v1, v2, a[16], b[13]);+ MONT_MAC(w0, w1, w2, a[17], b[12]);+ MONT_MAC(t0, t1, t2, a[18], b[11]);+ MONT_MAC(v0, v1, v2, a[19], b[10]);+ MONT_MAC(w0, w1, w2, a[20], b[9]);+ MONT_MAC(t0, t1, t2, a[21], b[8]);+ MONT_MAC(v0, v1, v2, a[22], b[7]);+ MONT_MAC(w0, w1, w2, a[23], b[6]);+ MONT_MAC(t0, t1, t2, u[6], m[23]);+ MONT_MAC(v0, v1, v2, u[7], m[22]);+ MONT_MAC(w0, w1, w2, u[8], m[21]);+ MONT_MAC(t0, t1, t2, u[9], m[20]);+ MONT_MAC(v0, v1, v2, u[10], m[19]);+ MONT_MAC(w0, w1, w2, u[11], m[18]);+ MONT_MAC(t0, t1, t2, u[12], m[17]);+ MONT_MAC(v0, v1, v2, u[13], m[16]);+ MONT_MAC(w0, w1, w2, u[14], m[15]);+ MONT_MAC(t0, t1, t2, u[15], m[14]);+ MONT_MAC(v0, v1, v2, u[16], m[13]);+ MONT_MAC(w0, w1, w2, u[17], m[12]);+ MONT_MAC(t0, t1, t2, u[18], m[11]);+ MONT_MAC(v0, v1, v2, u[19], m[10]);+ MONT_MAC(w0, w1, w2, u[20], m[9]);+ MONT_MAC(t0, t1, t2, u[21], m[8]);+ MONT_MAC(v0, v1, v2, u[22], m[7]);+ MONT_MAC(w0, w1, w2, u[23], m[6]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[5] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 30 */+ MONT_MAC(t0, t1, t2, a[7], b[23]);+ MONT_MUL(v0, v1, v2, a[8], b[22]);+ MONT_MUL(w0, w1, w2, a[9], b[21]);+ MONT_MAC(t0, t1, t2, a[10], b[20]);+ MONT_MAC(v0, v1, v2, a[11], b[19]);+ MONT_MAC(w0, w1, w2, a[12], b[18]);+ MONT_MAC(t0, t1, t2, a[13], b[17]);+ MONT_MAC(v0, v1, v2, a[14], b[16]);+ MONT_MAC(w0, w1, w2, a[15], b[15]);+ MONT_MAC(t0, t1, t2, a[16], b[14]);+ MONT_MAC(v0, v1, v2, a[17], b[13]);+ MONT_MAC(w0, w1, w2, a[18], b[12]);+ MONT_MAC(t0, t1, t2, a[19], b[11]);+ MONT_MAC(v0, v1, v2, a[20], b[10]);+ MONT_MAC(w0, w1, w2, a[21], b[9]);+ MONT_MAC(t0, t1, t2, a[22], b[8]);+ MONT_MAC(v0, v1, v2, a[23], b[7]);+ MONT_MAC(w0, w1, w2, u[7], m[23]);+ MONT_MAC(t0, t1, t2, u[8], m[22]);+ MONT_MAC(v0, v1, v2, u[9], m[21]);+ MONT_MAC(w0, w1, w2, u[10], m[20]);+ MONT_MAC(t0, t1, t2, u[11], m[19]);+ MONT_MAC(v0, v1, v2, u[12], m[18]);+ MONT_MAC(w0, w1, w2, u[13], m[17]);+ MONT_MAC(t0, t1, t2, u[14], m[16]);+ MONT_MAC(v0, v1, v2, u[15], m[15]);+ MONT_MAC(w0, w1, w2, u[16], m[14]);+ MONT_MAC(t0, t1, t2, u[17], m[13]);+ MONT_MAC(v0, v1, v2, u[18], m[12]);+ MONT_MAC(w0, w1, w2, u[19], m[11]);+ MONT_MAC(t0, t1, t2, u[20], m[10]);+ MONT_MAC(v0, v1, v2, u[21], m[9]);+ MONT_MAC(w0, w1, w2, u[22], m[8]);+ MONT_MAC(t0, t1, t2, u[23], m[7]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[6] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 31 */+ MONT_MAC(t0, t1, t2, a[8], b[23]);+ MONT_MUL(v0, v1, v2, a[9], b[22]);+ MONT_MUL(w0, w1, w2, a[10], b[21]);+ MONT_MAC(t0, t1, t2, a[11], b[20]);+ MONT_MAC(v0, v1, v2, a[12], b[19]);+ MONT_MAC(w0, w1, w2, a[13], b[18]);+ MONT_MAC(t0, t1, t2, a[14], b[17]);+ MONT_MAC(v0, v1, v2, a[15], b[16]);+ MONT_MAC(w0, w1, w2, a[16], b[15]);+ MONT_MAC(t0, t1, t2, a[17], b[14]);+ MONT_MAC(v0, v1, v2, a[18], b[13]);+ MONT_MAC(w0, w1, w2, a[19], b[12]);+ MONT_MAC(t0, t1, t2, a[20], b[11]);+ MONT_MAC(v0, v1, v2, a[21], b[10]);+ MONT_MAC(w0, w1, w2, a[22], b[9]);+ MONT_MAC(t0, t1, t2, a[23], b[8]);+ MONT_MAC(v0, v1, v2, u[8], m[23]);+ MONT_MAC(w0, w1, w2, u[9], m[22]);+ MONT_MAC(t0, t1, t2, u[10], m[21]);+ MONT_MAC(v0, v1, v2, u[11], m[20]);+ MONT_MAC(w0, w1, w2, u[12], m[19]);+ MONT_MAC(t0, t1, t2, u[13], m[18]);+ MONT_MAC(v0, v1, v2, u[14], m[17]);+ MONT_MAC(w0, w1, w2, u[15], m[16]);+ MONT_MAC(t0, t1, t2, u[16], m[15]);+ MONT_MAC(v0, v1, v2, u[17], m[14]);+ MONT_MAC(w0, w1, w2, u[18], m[13]);+ MONT_MAC(t0, t1, t2, u[19], m[12]);+ MONT_MAC(v0, v1, v2, u[20], m[11]);+ MONT_MAC(w0, w1, w2, u[21], m[10]);+ MONT_MAC(t0, t1, t2, u[22], m[9]);+ MONT_MAC(v0, v1, v2, u[23], m[8]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[7] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 32 */+ MONT_MAC(t0, t1, t2, a[9], b[23]);+ MONT_MUL(v0, v1, v2, a[10], b[22]);+ MONT_MUL(w0, w1, w2, a[11], b[21]);+ MONT_MAC(t0, t1, t2, a[12], b[20]);+ MONT_MAC(v0, v1, v2, a[13], b[19]);+ MONT_MAC(w0, w1, w2, a[14], b[18]);+ MONT_MAC(t0, t1, t2, a[15], b[17]);+ MONT_MAC(v0, v1, v2, a[16], b[16]);+ MONT_MAC(w0, w1, w2, a[17], b[15]);+ MONT_MAC(t0, t1, t2, a[18], b[14]);+ MONT_MAC(v0, v1, v2, a[19], b[13]);+ MONT_MAC(w0, w1, w2, a[20], b[12]);+ MONT_MAC(t0, t1, t2, a[21], b[11]);+ MONT_MAC(v0, v1, v2, a[22], b[10]);+ MONT_MAC(w0, w1, w2, a[23], b[9]);+ MONT_MAC(t0, t1, t2, u[9], m[23]);+ MONT_MAC(v0, v1, v2, u[10], m[22]);+ MONT_MAC(w0, w1, w2, u[11], m[21]);+ MONT_MAC(t0, t1, t2, u[12], m[20]);+ MONT_MAC(v0, v1, v2, u[13], m[19]);+ MONT_MAC(w0, w1, w2, u[14], m[18]);+ MONT_MAC(t0, t1, t2, u[15], m[17]);+ MONT_MAC(v0, v1, v2, u[16], m[16]);+ MONT_MAC(w0, w1, w2, u[17], m[15]);+ MONT_MAC(t0, t1, t2, u[18], m[14]);+ MONT_MAC(v0, v1, v2, u[19], m[13]);+ MONT_MAC(w0, w1, w2, u[20], m[12]);+ MONT_MAC(t0, t1, t2, u[21], m[11]);+ MONT_MAC(v0, v1, v2, u[22], m[10]);+ MONT_MAC(w0, w1, w2, u[23], m[9]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[8] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 33 */+ MONT_MAC(t0, t1, t2, a[10], b[23]);+ MONT_MUL(v0, v1, v2, a[11], b[22]);+ MONT_MUL(w0, w1, w2, a[12], b[21]);+ MONT_MAC(t0, t1, t2, a[13], b[20]);+ MONT_MAC(v0, v1, v2, a[14], b[19]);+ MONT_MAC(w0, w1, w2, a[15], b[18]);+ MONT_MAC(t0, t1, t2, a[16], b[17]);+ MONT_MAC(v0, v1, v2, a[17], b[16]);+ MONT_MAC(w0, w1, w2, a[18], b[15]);+ MONT_MAC(t0, t1, t2, a[19], b[14]);+ MONT_MAC(v0, v1, v2, a[20], b[13]);+ MONT_MAC(w0, w1, w2, a[21], b[12]);+ MONT_MAC(t0, t1, t2, a[22], b[11]);+ MONT_MAC(v0, v1, v2, a[23], b[10]);+ MONT_MAC(w0, w1, w2, u[10], m[23]);+ MONT_MAC(t0, t1, t2, u[11], m[22]);+ MONT_MAC(v0, v1, v2, u[12], m[21]);+ MONT_MAC(w0, w1, w2, u[13], m[20]);+ MONT_MAC(t0, t1, t2, u[14], m[19]);+ MONT_MAC(v0, v1, v2, u[15], m[18]);+ MONT_MAC(w0, w1, w2, u[16], m[17]);+ MONT_MAC(t0, t1, t2, u[17], m[16]);+ MONT_MAC(v0, v1, v2, u[18], m[15]);+ MONT_MAC(w0, w1, w2, u[19], m[14]);+ MONT_MAC(t0, t1, t2, u[20], m[13]);+ MONT_MAC(v0, v1, v2, u[21], m[12]);+ MONT_MAC(w0, w1, w2, u[22], m[11]);+ MONT_MAC(t0, t1, t2, u[23], m[10]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[9] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 34 */+ MONT_MAC(t0, t1, t2, a[11], b[23]);+ MONT_MUL(v0, v1, v2, a[12], b[22]);+ MONT_MUL(w0, w1, w2, a[13], b[21]);+ MONT_MAC(t0, t1, t2, a[14], b[20]);+ MONT_MAC(v0, v1, v2, a[15], b[19]);+ MONT_MAC(w0, w1, w2, a[16], b[18]);+ MONT_MAC(t0, t1, t2, a[17], b[17]);+ MONT_MAC(v0, v1, v2, a[18], b[16]);+ MONT_MAC(w0, w1, w2, a[19], b[15]);+ MONT_MAC(t0, t1, t2, a[20], b[14]);+ MONT_MAC(v0, v1, v2, a[21], b[13]);+ MONT_MAC(w0, w1, w2, a[22], b[12]);+ MONT_MAC(t0, t1, t2, a[23], b[11]);+ MONT_MAC(v0, v1, v2, u[11], m[23]);+ MONT_MAC(w0, w1, w2, u[12], m[22]);+ MONT_MAC(t0, t1, t2, u[13], m[21]);+ MONT_MAC(v0, v1, v2, u[14], m[20]);+ MONT_MAC(w0, w1, w2, u[15], m[19]);+ MONT_MAC(t0, t1, t2, u[16], m[18]);+ MONT_MAC(v0, v1, v2, u[17], m[17]);+ MONT_MAC(w0, w1, w2, u[18], m[16]);+ MONT_MAC(t0, t1, t2, u[19], m[15]);+ MONT_MAC(v0, v1, v2, u[20], m[14]);+ MONT_MAC(w0, w1, w2, u[21], m[13]);+ MONT_MAC(t0, t1, t2, u[22], m[12]);+ MONT_MAC(v0, v1, v2, u[23], m[11]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[10] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 35 */+ MONT_MAC(t0, t1, t2, a[12], b[23]);+ MONT_MUL(v0, v1, v2, a[13], b[22]);+ MONT_MUL(w0, w1, w2, a[14], b[21]);+ MONT_MAC(t0, t1, t2, a[15], b[20]);+ MONT_MAC(v0, v1, v2, a[16], b[19]);+ MONT_MAC(w0, w1, w2, a[17], b[18]);+ MONT_MAC(t0, t1, t2, a[18], b[17]);+ MONT_MAC(v0, v1, v2, a[19], b[16]);+ MONT_MAC(w0, w1, w2, a[20], b[15]);+ MONT_MAC(t0, t1, t2, a[21], b[14]);+ MONT_MAC(v0, v1, v2, a[22], b[13]);+ MONT_MAC(w0, w1, w2, a[23], b[12]);+ MONT_MAC(t0, t1, t2, u[12], m[23]);+ MONT_MAC(v0, v1, v2, u[13], m[22]);+ MONT_MAC(w0, w1, w2, u[14], m[21]);+ MONT_MAC(t0, t1, t2, u[15], m[20]);+ MONT_MAC(v0, v1, v2, u[16], m[19]);+ MONT_MAC(w0, w1, w2, u[17], m[18]);+ MONT_MAC(t0, t1, t2, u[18], m[17]);+ MONT_MAC(v0, v1, v2, u[19], m[16]);+ MONT_MAC(w0, w1, w2, u[20], m[15]);+ MONT_MAC(t0, t1, t2, u[21], m[14]);+ MONT_MAC(v0, v1, v2, u[22], m[13]);+ MONT_MAC(w0, w1, w2, u[23], m[12]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[11] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 36 */+ MONT_MAC(t0, t1, t2, a[13], b[23]);+ MONT_MUL(v0, v1, v2, a[14], b[22]);+ MONT_MUL(w0, w1, w2, a[15], b[21]);+ MONT_MAC(t0, t1, t2, a[16], b[20]);+ MONT_MAC(v0, v1, v2, a[17], b[19]);+ MONT_MAC(w0, w1, w2, a[18], b[18]);+ MONT_MAC(t0, t1, t2, a[19], b[17]);+ MONT_MAC(v0, v1, v2, a[20], b[16]);+ MONT_MAC(w0, w1, w2, a[21], b[15]);+ MONT_MAC(t0, t1, t2, a[22], b[14]);+ MONT_MAC(v0, v1, v2, a[23], b[13]);+ MONT_MAC(w0, w1, w2, u[13], m[23]);+ MONT_MAC(t0, t1, t2, u[14], m[22]);+ MONT_MAC(v0, v1, v2, u[15], m[21]);+ MONT_MAC(w0, w1, w2, u[16], m[20]);+ MONT_MAC(t0, t1, t2, u[17], m[19]);+ MONT_MAC(v0, v1, v2, u[18], m[18]);+ MONT_MAC(w0, w1, w2, u[19], m[17]);+ MONT_MAC(t0, t1, t2, u[20], m[16]);+ MONT_MAC(v0, v1, v2, u[21], m[15]);+ MONT_MAC(w0, w1, w2, u[22], m[14]);+ MONT_MAC(t0, t1, t2, u[23], m[13]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[12] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 37 */+ MONT_MAC(t0, t1, t2, a[14], b[23]);+ MONT_MUL(v0, v1, v2, a[15], b[22]);+ MONT_MUL(w0, w1, w2, a[16], b[21]);+ MONT_MAC(t0, t1, t2, a[17], b[20]);+ MONT_MAC(v0, v1, v2, a[18], b[19]);+ MONT_MAC(w0, w1, w2, a[19], b[18]);+ MONT_MAC(t0, t1, t2, a[20], b[17]);+ MONT_MAC(v0, v1, v2, a[21], b[16]);+ MONT_MAC(w0, w1, w2, a[22], b[15]);+ MONT_MAC(t0, t1, t2, a[23], b[14]);+ MONT_MAC(v0, v1, v2, u[14], m[23]);+ MONT_MAC(w0, w1, w2, u[15], m[22]);+ MONT_MAC(t0, t1, t2, u[16], m[21]);+ MONT_MAC(v0, v1, v2, u[17], m[20]);+ MONT_MAC(w0, w1, w2, u[18], m[19]);+ MONT_MAC(t0, t1, t2, u[19], m[18]);+ MONT_MAC(v0, v1, v2, u[20], m[17]);+ MONT_MAC(w0, w1, w2, u[21], m[16]);+ MONT_MAC(t0, t1, t2, u[22], m[15]);+ MONT_MAC(v0, v1, v2, u[23], m[14]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[13] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 38 */+ MONT_MAC(t0, t1, t2, a[15], b[23]);+ MONT_MUL(v0, v1, v2, a[16], b[22]);+ MONT_MUL(w0, w1, w2, a[17], b[21]);+ MONT_MAC(t0, t1, t2, a[18], b[20]);+ MONT_MAC(v0, v1, v2, a[19], b[19]);+ MONT_MAC(w0, w1, w2, a[20], b[18]);+ MONT_MAC(t0, t1, t2, a[21], b[17]);+ MONT_MAC(v0, v1, v2, a[22], b[16]);+ MONT_MAC(w0, w1, w2, a[23], b[15]);+ MONT_MAC(t0, t1, t2, u[15], m[23]);+ MONT_MAC(v0, v1, v2, u[16], m[22]);+ MONT_MAC(w0, w1, w2, u[17], m[21]);+ MONT_MAC(t0, t1, t2, u[18], m[20]);+ MONT_MAC(v0, v1, v2, u[19], m[19]);+ MONT_MAC(w0, w1, w2, u[20], m[18]);+ MONT_MAC(t0, t1, t2, u[21], m[17]);+ MONT_MAC(v0, v1, v2, u[22], m[16]);+ MONT_MAC(w0, w1, w2, u[23], m[15]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[14] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 39 */+ MONT_MAC(t0, t1, t2, a[16], b[23]);+ MONT_MUL(v0, v1, v2, a[17], b[22]);+ MONT_MUL(w0, w1, w2, a[18], b[21]);+ MONT_MAC(t0, t1, t2, a[19], b[20]);+ MONT_MAC(v0, v1, v2, a[20], b[19]);+ MONT_MAC(w0, w1, w2, a[21], b[18]);+ MONT_MAC(t0, t1, t2, a[22], b[17]);+ MONT_MAC(v0, v1, v2, a[23], b[16]);+ MONT_MAC(w0, w1, w2, u[16], m[23]);+ MONT_MAC(t0, t1, t2, u[17], m[22]);+ MONT_MAC(v0, v1, v2, u[18], m[21]);+ MONT_MAC(w0, w1, w2, u[19], m[20]);+ MONT_MAC(t0, t1, t2, u[20], m[19]);+ MONT_MAC(v0, v1, v2, u[21], m[18]);+ MONT_MAC(w0, w1, w2, u[22], m[17]);+ MONT_MAC(t0, t1, t2, u[23], m[16]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[15] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 40 */+ MONT_MAC(t0, t1, t2, a[17], b[23]);+ MONT_MUL(v0, v1, v2, a[18], b[22]);+ MONT_MUL(w0, w1, w2, a[19], b[21]);+ MONT_MAC(t0, t1, t2, a[20], b[20]);+ MONT_MAC(v0, v1, v2, a[21], b[19]);+ MONT_MAC(w0, w1, w2, a[22], b[18]);+ MONT_MAC(t0, t1, t2, a[23], b[17]);+ MONT_MAC(v0, v1, v2, u[17], m[23]);+ MONT_MAC(w0, w1, w2, u[18], m[22]);+ MONT_MAC(t0, t1, t2, u[19], m[21]);+ MONT_MAC(v0, v1, v2, u[20], m[20]);+ MONT_MAC(w0, w1, w2, u[21], m[19]);+ MONT_MAC(t0, t1, t2, u[22], m[18]);+ MONT_MAC(v0, v1, v2, u[23], m[17]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[16] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 41 */+ MONT_MAC(t0, t1, t2, a[18], b[23]);+ MONT_MUL(v0, v1, v2, a[19], b[22]);+ MONT_MUL(w0, w1, w2, a[20], b[21]);+ MONT_MAC(t0, t1, t2, a[21], b[20]);+ MONT_MAC(v0, v1, v2, a[22], b[19]);+ MONT_MAC(w0, w1, w2, a[23], b[18]);+ MONT_MAC(t0, t1, t2, u[18], m[23]);+ MONT_MAC(v0, v1, v2, u[19], m[22]);+ MONT_MAC(w0, w1, w2, u[20], m[21]);+ MONT_MAC(t0, t1, t2, u[21], m[20]);+ MONT_MAC(v0, v1, v2, u[22], m[19]);+ MONT_MAC(w0, w1, w2, u[23], m[18]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[17] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 42 */+ MONT_MAC(t0, t1, t2, a[19], b[23]);+ MONT_MUL(v0, v1, v2, a[20], b[22]);+ MONT_MUL(w0, w1, w2, a[21], b[21]);+ MONT_MAC(t0, t1, t2, a[22], b[20]);+ MONT_MAC(v0, v1, v2, a[23], b[19]);+ MONT_MAC(w0, w1, w2, u[19], m[23]);+ MONT_MAC(t0, t1, t2, u[20], m[22]);+ MONT_MAC(v0, v1, v2, u[21], m[21]);+ MONT_MAC(w0, w1, w2, u[22], m[20]);+ MONT_MAC(t0, t1, t2, u[23], m[19]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[18] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 43 */+ MONT_MAC(t0, t1, t2, a[20], b[23]);+ MONT_MUL(v0, v1, v2, a[21], b[22]);+ MONT_MUL(w0, w1, w2, a[22], b[21]);+ MONT_MAC(t0, t1, t2, a[23], b[20]);+ MONT_MAC(v0, v1, v2, u[20], m[23]);+ MONT_MAC(w0, w1, w2, u[21], m[22]);+ MONT_MAC(t0, t1, t2, u[22], m[21]);+ MONT_MAC(v0, v1, v2, u[23], m[20]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[19] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 44 */+ MONT_MAC(t0, t1, t2, a[21], b[23]);+ MONT_MUL(v0, v1, v2, a[22], b[22]);+ MONT_MUL(w0, w1, w2, a[23], b[21]);+ MONT_MAC(t0, t1, t2, u[21], m[23]);+ MONT_MAC(v0, v1, v2, u[22], m[22]);+ MONT_MAC(w0, w1, w2, u[23], m[21]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[20] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 45 */+ MONT_MAC(t0, t1, t2, a[22], b[23]);+ MONT_MUL(v0, v1, v2, a[23], b[22]);+ MONT_MUL(w0, w1, w2, u[22], m[23]);+ MONT_MAC(t0, t1, t2, u[23], m[22]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[21] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 46 */+ MONT_MAC(t0, t1, t2, a[23], b[23]);+ MONT_MUL(v0, v1, v2, u[23], m[23]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ z[22] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ z[23] = t0;++ /* under 2m, with t1 the bit above n limbs: at most one subtraction */+ borrow = sub_n(r, z, m, 24);+ take = t1 | (borrow ^ 1);+ select_n(r, r, z, take & 1, 24);+}++/* r = a * a * R^-1 mod m, for a under m; t is 2n limbs of scratch */+static void crypton_mont_sqr24(limb_t *r, const limb_t *a,+ const limb_t *m, limb_t n0, limb_t *t)+{+ limb_t *u = t, *z = t + 24;+ limb_t t0 = 0, t1 = 0, t2 = 0, v0, v1, v2, w0, w1, w2, borrow, take;+ limb_t s0, s1, s2, c0, c1, c2;++ /* column 0 */+ MONT_MAC(t0, t1, t2, a[0], a[0]);+ u[0] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[0], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 1 */+ MONT_MUL(s0, s1, s2, a[0], a[1]);+ MONT_MAC(t0, t1, t2, u[0], m[1]);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[1] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[1], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 2 */+ MONT_MUL(s0, s1, s2, a[0], a[2]);+ MONT_MAC(t0, t1, t2, a[1], a[1]);+ MONT_MUL(v0, v1, v2, u[0], m[2]);+ MONT_MUL(w0, w1, w2, u[1], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[2] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[2], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 3 */+ MONT_MUL(s0, s1, s2, a[0], a[3]);+ MONT_MUL(c0, c1, c2, a[1], a[2]);+ MONT_MAC(t0, t1, t2, u[0], m[3]);+ MONT_MUL(v0, v1, v2, u[1], m[2]);+ MONT_MUL(w0, w1, w2, u[2], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[3] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[3], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 4 */+ MONT_MUL(s0, s1, s2, a[0], a[4]);+ MONT_MUL(c0, c1, c2, a[1], a[3]);+ MONT_MAC(t0, t1, t2, a[2], a[2]);+ MONT_MUL(v0, v1, v2, u[0], m[4]);+ MONT_MUL(w0, w1, w2, u[1], m[3]);+ MONT_MAC(t0, t1, t2, u[2], m[2]);+ MONT_MAC(v0, v1, v2, u[3], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[4] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[4], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 5 */+ MONT_MUL(s0, s1, s2, a[0], a[5]);+ MONT_MUL(c0, c1, c2, a[1], a[4]);+ MONT_MAC(s0, s1, s2, a[2], a[3]);+ MONT_MAC(t0, t1, t2, u[0], m[5]);+ MONT_MUL(v0, v1, v2, u[1], m[4]);+ MONT_MUL(w0, w1, w2, u[2], m[3]);+ MONT_MAC(t0, t1, t2, u[3], m[2]);+ MONT_MAC(v0, v1, v2, u[4], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[5] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[5], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 6 */+ MONT_MUL(s0, s1, s2, a[0], a[6]);+ MONT_MUL(c0, c1, c2, a[1], a[5]);+ MONT_MAC(s0, s1, s2, a[2], a[4]);+ MONT_MAC(t0, t1, t2, a[3], a[3]);+ MONT_MUL(v0, v1, v2, u[0], m[6]);+ MONT_MUL(w0, w1, w2, u[1], m[5]);+ MONT_MAC(t0, t1, t2, u[2], m[4]);+ MONT_MAC(v0, v1, v2, u[3], m[3]);+ MONT_MAC(w0, w1, w2, u[4], m[2]);+ MONT_MAC(t0, t1, t2, u[5], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[6] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[6], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 7 */+ MONT_MUL(s0, s1, s2, a[0], a[7]);+ MONT_MUL(c0, c1, c2, a[1], a[6]);+ MONT_MAC(s0, s1, s2, a[2], a[5]);+ MONT_MAC(c0, c1, c2, a[3], a[4]);+ MONT_MAC(t0, t1, t2, u[0], m[7]);+ MONT_MUL(v0, v1, v2, u[1], m[6]);+ MONT_MUL(w0, w1, w2, u[2], m[5]);+ MONT_MAC(t0, t1, t2, u[3], m[4]);+ MONT_MAC(v0, v1, v2, u[4], m[3]);+ MONT_MAC(w0, w1, w2, u[5], m[2]);+ MONT_MAC(t0, t1, t2, u[6], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[7] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[7], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 8 */+ MONT_MUL(s0, s1, s2, a[0], a[8]);+ MONT_MUL(c0, c1, c2, a[1], a[7]);+ MONT_MAC(s0, s1, s2, a[2], a[6]);+ MONT_MAC(c0, c1, c2, a[3], a[5]);+ MONT_MAC(t0, t1, t2, a[4], a[4]);+ MONT_MUL(v0, v1, v2, u[0], m[8]);+ MONT_MUL(w0, w1, w2, u[1], m[7]);+ MONT_MAC(t0, t1, t2, u[2], m[6]);+ MONT_MAC(v0, v1, v2, u[3], m[5]);+ MONT_MAC(w0, w1, w2, u[4], m[4]);+ MONT_MAC(t0, t1, t2, u[5], m[3]);+ MONT_MAC(v0, v1, v2, u[6], m[2]);+ MONT_MAC(w0, w1, w2, u[7], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[8] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[8], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 9 */+ MONT_MUL(s0, s1, s2, a[0], a[9]);+ MONT_MUL(c0, c1, c2, a[1], a[8]);+ MONT_MAC(s0, s1, s2, a[2], a[7]);+ MONT_MAC(c0, c1, c2, a[3], a[6]);+ MONT_MAC(s0, s1, s2, a[4], a[5]);+ MONT_MAC(t0, t1, t2, u[0], m[9]);+ MONT_MUL(v0, v1, v2, u[1], m[8]);+ MONT_MUL(w0, w1, w2, u[2], m[7]);+ MONT_MAC(t0, t1, t2, u[3], m[6]);+ MONT_MAC(v0, v1, v2, u[4], m[5]);+ MONT_MAC(w0, w1, w2, u[5], m[4]);+ MONT_MAC(t0, t1, t2, u[6], m[3]);+ MONT_MAC(v0, v1, v2, u[7], m[2]);+ MONT_MAC(w0, w1, w2, u[8], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[9] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[9], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 10 */+ MONT_MUL(s0, s1, s2, a[0], a[10]);+ MONT_MUL(c0, c1, c2, a[1], a[9]);+ MONT_MAC(s0, s1, s2, a[2], a[8]);+ MONT_MAC(c0, c1, c2, a[3], a[7]);+ MONT_MAC(s0, s1, s2, a[4], a[6]);+ MONT_MAC(t0, t1, t2, a[5], a[5]);+ MONT_MUL(v0, v1, v2, u[0], m[10]);+ MONT_MUL(w0, w1, w2, u[1], m[9]);+ MONT_MAC(t0, t1, t2, u[2], m[8]);+ MONT_MAC(v0, v1, v2, u[3], m[7]);+ MONT_MAC(w0, w1, w2, u[4], m[6]);+ MONT_MAC(t0, t1, t2, u[5], m[5]);+ MONT_MAC(v0, v1, v2, u[6], m[4]);+ MONT_MAC(w0, w1, w2, u[7], m[3]);+ MONT_MAC(t0, t1, t2, u[8], m[2]);+ MONT_MAC(v0, v1, v2, u[9], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[10] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[10], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 11 */+ MONT_MUL(s0, s1, s2, a[0], a[11]);+ MONT_MUL(c0, c1, c2, a[1], a[10]);+ MONT_MAC(s0, s1, s2, a[2], a[9]);+ MONT_MAC(c0, c1, c2, a[3], a[8]);+ MONT_MAC(s0, s1, s2, a[4], a[7]);+ MONT_MAC(c0, c1, c2, a[5], a[6]);+ MONT_MAC(t0, t1, t2, u[0], m[11]);+ MONT_MUL(v0, v1, v2, u[1], m[10]);+ MONT_MUL(w0, w1, w2, u[2], m[9]);+ MONT_MAC(t0, t1, t2, u[3], m[8]);+ MONT_MAC(v0, v1, v2, u[4], m[7]);+ MONT_MAC(w0, w1, w2, u[5], m[6]);+ MONT_MAC(t0, t1, t2, u[6], m[5]);+ MONT_MAC(v0, v1, v2, u[7], m[4]);+ MONT_MAC(w0, w1, w2, u[8], m[3]);+ MONT_MAC(t0, t1, t2, u[9], m[2]);+ MONT_MAC(v0, v1, v2, u[10], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[11] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[11], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 12 */+ MONT_MUL(s0, s1, s2, a[0], a[12]);+ MONT_MUL(c0, c1, c2, a[1], a[11]);+ MONT_MAC(s0, s1, s2, a[2], a[10]);+ MONT_MAC(c0, c1, c2, a[3], a[9]);+ MONT_MAC(s0, s1, s2, a[4], a[8]);+ MONT_MAC(c0, c1, c2, a[5], a[7]);+ MONT_MAC(t0, t1, t2, a[6], a[6]);+ MONT_MUL(v0, v1, v2, u[0], m[12]);+ MONT_MUL(w0, w1, w2, u[1], m[11]);+ MONT_MAC(t0, t1, t2, u[2], m[10]);+ MONT_MAC(v0, v1, v2, u[3], m[9]);+ MONT_MAC(w0, w1, w2, u[4], m[8]);+ MONT_MAC(t0, t1, t2, u[5], m[7]);+ MONT_MAC(v0, v1, v2, u[6], m[6]);+ MONT_MAC(w0, w1, w2, u[7], m[5]);+ MONT_MAC(t0, t1, t2, u[8], m[4]);+ MONT_MAC(v0, v1, v2, u[9], m[3]);+ MONT_MAC(w0, w1, w2, u[10], m[2]);+ MONT_MAC(t0, t1, t2, u[11], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[12] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[12], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 13 */+ MONT_MUL(s0, s1, s2, a[0], a[13]);+ MONT_MUL(c0, c1, c2, a[1], a[12]);+ MONT_MAC(s0, s1, s2, a[2], a[11]);+ MONT_MAC(c0, c1, c2, a[3], a[10]);+ MONT_MAC(s0, s1, s2, a[4], a[9]);+ MONT_MAC(c0, c1, c2, a[5], a[8]);+ MONT_MAC(s0, s1, s2, a[6], a[7]);+ MONT_MAC(t0, t1, t2, u[0], m[13]);+ MONT_MUL(v0, v1, v2, u[1], m[12]);+ MONT_MUL(w0, w1, w2, u[2], m[11]);+ MONT_MAC(t0, t1, t2, u[3], m[10]);+ MONT_MAC(v0, v1, v2, u[4], m[9]);+ MONT_MAC(w0, w1, w2, u[5], m[8]);+ MONT_MAC(t0, t1, t2, u[6], m[7]);+ MONT_MAC(v0, v1, v2, u[7], m[6]);+ MONT_MAC(w0, w1, w2, u[8], m[5]);+ MONT_MAC(t0, t1, t2, u[9], m[4]);+ MONT_MAC(v0, v1, v2, u[10], m[3]);+ MONT_MAC(w0, w1, w2, u[11], m[2]);+ MONT_MAC(t0, t1, t2, u[12], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[13] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[13], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 14 */+ MONT_MUL(s0, s1, s2, a[0], a[14]);+ MONT_MUL(c0, c1, c2, a[1], a[13]);+ MONT_MAC(s0, s1, s2, a[2], a[12]);+ MONT_MAC(c0, c1, c2, a[3], a[11]);+ MONT_MAC(s0, s1, s2, a[4], a[10]);+ MONT_MAC(c0, c1, c2, a[5], a[9]);+ MONT_MAC(s0, s1, s2, a[6], a[8]);+ MONT_MAC(t0, t1, t2, a[7], a[7]);+ MONT_MUL(v0, v1, v2, u[0], m[14]);+ MONT_MUL(w0, w1, w2, u[1], m[13]);+ MONT_MAC(t0, t1, t2, u[2], m[12]);+ MONT_MAC(v0, v1, v2, u[3], m[11]);+ MONT_MAC(w0, w1, w2, u[4], m[10]);+ MONT_MAC(t0, t1, t2, u[5], m[9]);+ MONT_MAC(v0, v1, v2, u[6], m[8]);+ MONT_MAC(w0, w1, w2, u[7], m[7]);+ MONT_MAC(t0, t1, t2, u[8], m[6]);+ MONT_MAC(v0, v1, v2, u[9], m[5]);+ MONT_MAC(w0, w1, w2, u[10], m[4]);+ MONT_MAC(t0, t1, t2, u[11], m[3]);+ MONT_MAC(v0, v1, v2, u[12], m[2]);+ MONT_MAC(w0, w1, w2, u[13], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[14] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[14], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 15 */+ MONT_MUL(s0, s1, s2, a[0], a[15]);+ MONT_MUL(c0, c1, c2, a[1], a[14]);+ MONT_MAC(s0, s1, s2, a[2], a[13]);+ MONT_MAC(c0, c1, c2, a[3], a[12]);+ MONT_MAC(s0, s1, s2, a[4], a[11]);+ MONT_MAC(c0, c1, c2, a[5], a[10]);+ MONT_MAC(s0, s1, s2, a[6], a[9]);+ MONT_MAC(c0, c1, c2, a[7], a[8]);+ MONT_MAC(t0, t1, t2, u[0], m[15]);+ MONT_MUL(v0, v1, v2, u[1], m[14]);+ MONT_MUL(w0, w1, w2, u[2], m[13]);+ MONT_MAC(t0, t1, t2, u[3], m[12]);+ MONT_MAC(v0, v1, v2, u[4], m[11]);+ MONT_MAC(w0, w1, w2, u[5], m[10]);+ MONT_MAC(t0, t1, t2, u[6], m[9]);+ MONT_MAC(v0, v1, v2, u[7], m[8]);+ MONT_MAC(w0, w1, w2, u[8], m[7]);+ MONT_MAC(t0, t1, t2, u[9], m[6]);+ MONT_MAC(v0, v1, v2, u[10], m[5]);+ MONT_MAC(w0, w1, w2, u[11], m[4]);+ MONT_MAC(t0, t1, t2, u[12], m[3]);+ MONT_MAC(v0, v1, v2, u[13], m[2]);+ MONT_MAC(w0, w1, w2, u[14], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[15] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[15], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 16 */+ MONT_MUL(s0, s1, s2, a[0], a[16]);+ MONT_MUL(c0, c1, c2, a[1], a[15]);+ MONT_MAC(s0, s1, s2, a[2], a[14]);+ MONT_MAC(c0, c1, c2, a[3], a[13]);+ MONT_MAC(s0, s1, s2, a[4], a[12]);+ MONT_MAC(c0, c1, c2, a[5], a[11]);+ MONT_MAC(s0, s1, s2, a[6], a[10]);+ MONT_MAC(c0, c1, c2, a[7], a[9]);+ MONT_MAC(t0, t1, t2, a[8], a[8]);+ MONT_MUL(v0, v1, v2, u[0], m[16]);+ MONT_MUL(w0, w1, w2, u[1], m[15]);+ MONT_MAC(t0, t1, t2, u[2], m[14]);+ MONT_MAC(v0, v1, v2, u[3], m[13]);+ MONT_MAC(w0, w1, w2, u[4], m[12]);+ MONT_MAC(t0, t1, t2, u[5], m[11]);+ MONT_MAC(v0, v1, v2, u[6], m[10]);+ MONT_MAC(w0, w1, w2, u[7], m[9]);+ MONT_MAC(t0, t1, t2, u[8], m[8]);+ MONT_MAC(v0, v1, v2, u[9], m[7]);+ MONT_MAC(w0, w1, w2, u[10], m[6]);+ MONT_MAC(t0, t1, t2, u[11], m[5]);+ MONT_MAC(v0, v1, v2, u[12], m[4]);+ MONT_MAC(w0, w1, w2, u[13], m[3]);+ MONT_MAC(t0, t1, t2, u[14], m[2]);+ MONT_MAC(v0, v1, v2, u[15], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[16] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[16], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 17 */+ MONT_MUL(s0, s1, s2, a[0], a[17]);+ MONT_MUL(c0, c1, c2, a[1], a[16]);+ MONT_MAC(s0, s1, s2, a[2], a[15]);+ MONT_MAC(c0, c1, c2, a[3], a[14]);+ MONT_MAC(s0, s1, s2, a[4], a[13]);+ MONT_MAC(c0, c1, c2, a[5], a[12]);+ MONT_MAC(s0, s1, s2, a[6], a[11]);+ MONT_MAC(c0, c1, c2, a[7], a[10]);+ MONT_MAC(s0, s1, s2, a[8], a[9]);+ MONT_MAC(t0, t1, t2, u[0], m[17]);+ MONT_MUL(v0, v1, v2, u[1], m[16]);+ MONT_MUL(w0, w1, w2, u[2], m[15]);+ MONT_MAC(t0, t1, t2, u[3], m[14]);+ MONT_MAC(v0, v1, v2, u[4], m[13]);+ MONT_MAC(w0, w1, w2, u[5], m[12]);+ MONT_MAC(t0, t1, t2, u[6], m[11]);+ MONT_MAC(v0, v1, v2, u[7], m[10]);+ MONT_MAC(w0, w1, w2, u[8], m[9]);+ MONT_MAC(t0, t1, t2, u[9], m[8]);+ MONT_MAC(v0, v1, v2, u[10], m[7]);+ MONT_MAC(w0, w1, w2, u[11], m[6]);+ MONT_MAC(t0, t1, t2, u[12], m[5]);+ MONT_MAC(v0, v1, v2, u[13], m[4]);+ MONT_MAC(w0, w1, w2, u[14], m[3]);+ MONT_MAC(t0, t1, t2, u[15], m[2]);+ MONT_MAC(v0, v1, v2, u[16], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[17] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[17], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 18 */+ MONT_MUL(s0, s1, s2, a[0], a[18]);+ MONT_MUL(c0, c1, c2, a[1], a[17]);+ MONT_MAC(s0, s1, s2, a[2], a[16]);+ MONT_MAC(c0, c1, c2, a[3], a[15]);+ MONT_MAC(s0, s1, s2, a[4], a[14]);+ MONT_MAC(c0, c1, c2, a[5], a[13]);+ MONT_MAC(s0, s1, s2, a[6], a[12]);+ MONT_MAC(c0, c1, c2, a[7], a[11]);+ MONT_MAC(s0, s1, s2, a[8], a[10]);+ MONT_MAC(t0, t1, t2, a[9], a[9]);+ MONT_MUL(v0, v1, v2, u[0], m[18]);+ MONT_MUL(w0, w1, w2, u[1], m[17]);+ MONT_MAC(t0, t1, t2, u[2], m[16]);+ MONT_MAC(v0, v1, v2, u[3], m[15]);+ MONT_MAC(w0, w1, w2, u[4], m[14]);+ MONT_MAC(t0, t1, t2, u[5], m[13]);+ MONT_MAC(v0, v1, v2, u[6], m[12]);+ MONT_MAC(w0, w1, w2, u[7], m[11]);+ MONT_MAC(t0, t1, t2, u[8], m[10]);+ MONT_MAC(v0, v1, v2, u[9], m[9]);+ MONT_MAC(w0, w1, w2, u[10], m[8]);+ MONT_MAC(t0, t1, t2, u[11], m[7]);+ MONT_MAC(v0, v1, v2, u[12], m[6]);+ MONT_MAC(w0, w1, w2, u[13], m[5]);+ MONT_MAC(t0, t1, t2, u[14], m[4]);+ MONT_MAC(v0, v1, v2, u[15], m[3]);+ MONT_MAC(w0, w1, w2, u[16], m[2]);+ MONT_MAC(t0, t1, t2, u[17], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[18] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[18], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 19 */+ MONT_MUL(s0, s1, s2, a[0], a[19]);+ MONT_MUL(c0, c1, c2, a[1], a[18]);+ MONT_MAC(s0, s1, s2, a[2], a[17]);+ MONT_MAC(c0, c1, c2, a[3], a[16]);+ MONT_MAC(s0, s1, s2, a[4], a[15]);+ MONT_MAC(c0, c1, c2, a[5], a[14]);+ MONT_MAC(s0, s1, s2, a[6], a[13]);+ MONT_MAC(c0, c1, c2, a[7], a[12]);+ MONT_MAC(s0, s1, s2, a[8], a[11]);+ MONT_MAC(c0, c1, c2, a[9], a[10]);+ MONT_MAC(t0, t1, t2, u[0], m[19]);+ MONT_MUL(v0, v1, v2, u[1], m[18]);+ MONT_MUL(w0, w1, w2, u[2], m[17]);+ MONT_MAC(t0, t1, t2, u[3], m[16]);+ MONT_MAC(v0, v1, v2, u[4], m[15]);+ MONT_MAC(w0, w1, w2, u[5], m[14]);+ MONT_MAC(t0, t1, t2, u[6], m[13]);+ MONT_MAC(v0, v1, v2, u[7], m[12]);+ MONT_MAC(w0, w1, w2, u[8], m[11]);+ MONT_MAC(t0, t1, t2, u[9], m[10]);+ MONT_MAC(v0, v1, v2, u[10], m[9]);+ MONT_MAC(w0, w1, w2, u[11], m[8]);+ MONT_MAC(t0, t1, t2, u[12], m[7]);+ MONT_MAC(v0, v1, v2, u[13], m[6]);+ MONT_MAC(w0, w1, w2, u[14], m[5]);+ MONT_MAC(t0, t1, t2, u[15], m[4]);+ MONT_MAC(v0, v1, v2, u[16], m[3]);+ MONT_MAC(w0, w1, w2, u[17], m[2]);+ MONT_MAC(t0, t1, t2, u[18], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[19] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[19], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 20 */+ MONT_MUL(s0, s1, s2, a[0], a[20]);+ MONT_MUL(c0, c1, c2, a[1], a[19]);+ MONT_MAC(s0, s1, s2, a[2], a[18]);+ MONT_MAC(c0, c1, c2, a[3], a[17]);+ MONT_MAC(s0, s1, s2, a[4], a[16]);+ MONT_MAC(c0, c1, c2, a[5], a[15]);+ MONT_MAC(s0, s1, s2, a[6], a[14]);+ MONT_MAC(c0, c1, c2, a[7], a[13]);+ MONT_MAC(s0, s1, s2, a[8], a[12]);+ MONT_MAC(c0, c1, c2, a[9], a[11]);+ MONT_MAC(t0, t1, t2, a[10], a[10]);+ MONT_MUL(v0, v1, v2, u[0], m[20]);+ MONT_MUL(w0, w1, w2, u[1], m[19]);+ MONT_MAC(t0, t1, t2, u[2], m[18]);+ MONT_MAC(v0, v1, v2, u[3], m[17]);+ MONT_MAC(w0, w1, w2, u[4], m[16]);+ MONT_MAC(t0, t1, t2, u[5], m[15]);+ MONT_MAC(v0, v1, v2, u[6], m[14]);+ MONT_MAC(w0, w1, w2, u[7], m[13]);+ MONT_MAC(t0, t1, t2, u[8], m[12]);+ MONT_MAC(v0, v1, v2, u[9], m[11]);+ MONT_MAC(w0, w1, w2, u[10], m[10]);+ MONT_MAC(t0, t1, t2, u[11], m[9]);+ MONT_MAC(v0, v1, v2, u[12], m[8]);+ MONT_MAC(w0, w1, w2, u[13], m[7]);+ MONT_MAC(t0, t1, t2, u[14], m[6]);+ MONT_MAC(v0, v1, v2, u[15], m[5]);+ MONT_MAC(w0, w1, w2, u[16], m[4]);+ MONT_MAC(t0, t1, t2, u[17], m[3]);+ MONT_MAC(v0, v1, v2, u[18], m[2]);+ MONT_MAC(w0, w1, w2, u[19], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[20] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[20], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 21 */+ MONT_MUL(s0, s1, s2, a[0], a[21]);+ MONT_MUL(c0, c1, c2, a[1], a[20]);+ MONT_MAC(s0, s1, s2, a[2], a[19]);+ MONT_MAC(c0, c1, c2, a[3], a[18]);+ MONT_MAC(s0, s1, s2, a[4], a[17]);+ MONT_MAC(c0, c1, c2, a[5], a[16]);+ MONT_MAC(s0, s1, s2, a[6], a[15]);+ MONT_MAC(c0, c1, c2, a[7], a[14]);+ MONT_MAC(s0, s1, s2, a[8], a[13]);+ MONT_MAC(c0, c1, c2, a[9], a[12]);+ MONT_MAC(s0, s1, s2, a[10], a[11]);+ MONT_MAC(t0, t1, t2, u[0], m[21]);+ MONT_MUL(v0, v1, v2, u[1], m[20]);+ MONT_MUL(w0, w1, w2, u[2], m[19]);+ MONT_MAC(t0, t1, t2, u[3], m[18]);+ MONT_MAC(v0, v1, v2, u[4], m[17]);+ MONT_MAC(w0, w1, w2, u[5], m[16]);+ MONT_MAC(t0, t1, t2, u[6], m[15]);+ MONT_MAC(v0, v1, v2, u[7], m[14]);+ MONT_MAC(w0, w1, w2, u[8], m[13]);+ MONT_MAC(t0, t1, t2, u[9], m[12]);+ MONT_MAC(v0, v1, v2, u[10], m[11]);+ MONT_MAC(w0, w1, w2, u[11], m[10]);+ MONT_MAC(t0, t1, t2, u[12], m[9]);+ MONT_MAC(v0, v1, v2, u[13], m[8]);+ MONT_MAC(w0, w1, w2, u[14], m[7]);+ MONT_MAC(t0, t1, t2, u[15], m[6]);+ MONT_MAC(v0, v1, v2, u[16], m[5]);+ MONT_MAC(w0, w1, w2, u[17], m[4]);+ MONT_MAC(t0, t1, t2, u[18], m[3]);+ MONT_MAC(v0, v1, v2, u[19], m[2]);+ MONT_MAC(w0, w1, w2, u[20], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[21] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[21], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 22 */+ MONT_MUL(s0, s1, s2, a[0], a[22]);+ MONT_MUL(c0, c1, c2, a[1], a[21]);+ MONT_MAC(s0, s1, s2, a[2], a[20]);+ MONT_MAC(c0, c1, c2, a[3], a[19]);+ MONT_MAC(s0, s1, s2, a[4], a[18]);+ MONT_MAC(c0, c1, c2, a[5], a[17]);+ MONT_MAC(s0, s1, s2, a[6], a[16]);+ MONT_MAC(c0, c1, c2, a[7], a[15]);+ MONT_MAC(s0, s1, s2, a[8], a[14]);+ MONT_MAC(c0, c1, c2, a[9], a[13]);+ MONT_MAC(s0, s1, s2, a[10], a[12]);+ MONT_MAC(t0, t1, t2, a[11], a[11]);+ MONT_MUL(v0, v1, v2, u[0], m[22]);+ MONT_MUL(w0, w1, w2, u[1], m[21]);+ MONT_MAC(t0, t1, t2, u[2], m[20]);+ MONT_MAC(v0, v1, v2, u[3], m[19]);+ MONT_MAC(w0, w1, w2, u[4], m[18]);+ MONT_MAC(t0, t1, t2, u[5], m[17]);+ MONT_MAC(v0, v1, v2, u[6], m[16]);+ MONT_MAC(w0, w1, w2, u[7], m[15]);+ MONT_MAC(t0, t1, t2, u[8], m[14]);+ MONT_MAC(v0, v1, v2, u[9], m[13]);+ MONT_MAC(w0, w1, w2, u[10], m[12]);+ MONT_MAC(t0, t1, t2, u[11], m[11]);+ MONT_MAC(v0, v1, v2, u[12], m[10]);+ MONT_MAC(w0, w1, w2, u[13], m[9]);+ MONT_MAC(t0, t1, t2, u[14], m[8]);+ MONT_MAC(v0, v1, v2, u[15], m[7]);+ MONT_MAC(w0, w1, w2, u[16], m[6]);+ MONT_MAC(t0, t1, t2, u[17], m[5]);+ MONT_MAC(v0, v1, v2, u[18], m[4]);+ MONT_MAC(w0, w1, w2, u[19], m[3]);+ MONT_MAC(t0, t1, t2, u[20], m[2]);+ MONT_MAC(v0, v1, v2, u[21], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[22] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[22], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 23 */+ MONT_MUL(s0, s1, s2, a[0], a[23]);+ MONT_MUL(c0, c1, c2, a[1], a[22]);+ MONT_MAC(s0, s1, s2, a[2], a[21]);+ MONT_MAC(c0, c1, c2, a[3], a[20]);+ MONT_MAC(s0, s1, s2, a[4], a[19]);+ MONT_MAC(c0, c1, c2, a[5], a[18]);+ MONT_MAC(s0, s1, s2, a[6], a[17]);+ MONT_MAC(c0, c1, c2, a[7], a[16]);+ MONT_MAC(s0, s1, s2, a[8], a[15]);+ MONT_MAC(c0, c1, c2, a[9], a[14]);+ MONT_MAC(s0, s1, s2, a[10], a[13]);+ MONT_MAC(c0, c1, c2, a[11], a[12]);+ MONT_MAC(t0, t1, t2, u[0], m[23]);+ MONT_MUL(v0, v1, v2, u[1], m[22]);+ MONT_MUL(w0, w1, w2, u[2], m[21]);+ MONT_MAC(t0, t1, t2, u[3], m[20]);+ MONT_MAC(v0, v1, v2, u[4], m[19]);+ MONT_MAC(w0, w1, w2, u[5], m[18]);+ MONT_MAC(t0, t1, t2, u[6], m[17]);+ MONT_MAC(v0, v1, v2, u[7], m[16]);+ MONT_MAC(w0, w1, w2, u[8], m[15]);+ MONT_MAC(t0, t1, t2, u[9], m[14]);+ MONT_MAC(v0, v1, v2, u[10], m[13]);+ MONT_MAC(w0, w1, w2, u[11], m[12]);+ MONT_MAC(t0, t1, t2, u[12], m[11]);+ MONT_MAC(v0, v1, v2, u[13], m[10]);+ MONT_MAC(w0, w1, w2, u[14], m[9]);+ MONT_MAC(t0, t1, t2, u[15], m[8]);+ MONT_MAC(v0, v1, v2, u[16], m[7]);+ MONT_MAC(w0, w1, w2, u[17], m[6]);+ MONT_MAC(t0, t1, t2, u[18], m[5]);+ MONT_MAC(v0, v1, v2, u[19], m[4]);+ MONT_MAC(w0, w1, w2, u[20], m[3]);+ MONT_MAC(t0, t1, t2, u[21], m[2]);+ MONT_MAC(v0, v1, v2, u[22], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[23] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[23], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 24 */+ MONT_MUL(s0, s1, s2, a[1], a[23]);+ MONT_MUL(c0, c1, c2, a[2], a[22]);+ MONT_MAC(s0, s1, s2, a[3], a[21]);+ MONT_MAC(c0, c1, c2, a[4], a[20]);+ MONT_MAC(s0, s1, s2, a[5], a[19]);+ MONT_MAC(c0, c1, c2, a[6], a[18]);+ MONT_MAC(s0, s1, s2, a[7], a[17]);+ MONT_MAC(c0, c1, c2, a[8], a[16]);+ MONT_MAC(s0, s1, s2, a[9], a[15]);+ MONT_MAC(c0, c1, c2, a[10], a[14]);+ MONT_MAC(s0, s1, s2, a[11], a[13]);+ MONT_MAC(t0, t1, t2, a[12], a[12]);+ MONT_MUL(v0, v1, v2, u[1], m[23]);+ MONT_MUL(w0, w1, w2, u[2], m[22]);+ MONT_MAC(t0, t1, t2, u[3], m[21]);+ MONT_MAC(v0, v1, v2, u[4], m[20]);+ MONT_MAC(w0, w1, w2, u[5], m[19]);+ MONT_MAC(t0, t1, t2, u[6], m[18]);+ MONT_MAC(v0, v1, v2, u[7], m[17]);+ MONT_MAC(w0, w1, w2, u[8], m[16]);+ MONT_MAC(t0, t1, t2, u[9], m[15]);+ MONT_MAC(v0, v1, v2, u[10], m[14]);+ MONT_MAC(w0, w1, w2, u[11], m[13]);+ MONT_MAC(t0, t1, t2, u[12], m[12]);+ MONT_MAC(v0, v1, v2, u[13], m[11]);+ MONT_MAC(w0, w1, w2, u[14], m[10]);+ MONT_MAC(t0, t1, t2, u[15], m[9]);+ MONT_MAC(v0, v1, v2, u[16], m[8]);+ MONT_MAC(w0, w1, w2, u[17], m[7]);+ MONT_MAC(t0, t1, t2, u[18], m[6]);+ MONT_MAC(v0, v1, v2, u[19], m[5]);+ MONT_MAC(w0, w1, w2, u[20], m[4]);+ MONT_MAC(t0, t1, t2, u[21], m[3]);+ MONT_MAC(v0, v1, v2, u[22], m[2]);+ MONT_MAC(w0, w1, w2, u[23], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[0] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 25 */+ MONT_MUL(s0, s1, s2, a[2], a[23]);+ MONT_MUL(c0, c1, c2, a[3], a[22]);+ MONT_MAC(s0, s1, s2, a[4], a[21]);+ MONT_MAC(c0, c1, c2, a[5], a[20]);+ MONT_MAC(s0, s1, s2, a[6], a[19]);+ MONT_MAC(c0, c1, c2, a[7], a[18]);+ MONT_MAC(s0, s1, s2, a[8], a[17]);+ MONT_MAC(c0, c1, c2, a[9], a[16]);+ MONT_MAC(s0, s1, s2, a[10], a[15]);+ MONT_MAC(c0, c1, c2, a[11], a[14]);+ MONT_MAC(s0, s1, s2, a[12], a[13]);+ MONT_MAC(t0, t1, t2, u[2], m[23]);+ MONT_MUL(v0, v1, v2, u[3], m[22]);+ MONT_MUL(w0, w1, w2, u[4], m[21]);+ MONT_MAC(t0, t1, t2, u[5], m[20]);+ MONT_MAC(v0, v1, v2, u[6], m[19]);+ MONT_MAC(w0, w1, w2, u[7], m[18]);+ MONT_MAC(t0, t1, t2, u[8], m[17]);+ MONT_MAC(v0, v1, v2, u[9], m[16]);+ MONT_MAC(w0, w1, w2, u[10], m[15]);+ MONT_MAC(t0, t1, t2, u[11], m[14]);+ MONT_MAC(v0, v1, v2, u[12], m[13]);+ MONT_MAC(w0, w1, w2, u[13], m[12]);+ MONT_MAC(t0, t1, t2, u[14], m[11]);+ MONT_MAC(v0, v1, v2, u[15], m[10]);+ MONT_MAC(w0, w1, w2, u[16], m[9]);+ MONT_MAC(t0, t1, t2, u[17], m[8]);+ MONT_MAC(v0, v1, v2, u[18], m[7]);+ MONT_MAC(w0, w1, w2, u[19], m[6]);+ MONT_MAC(t0, t1, t2, u[20], m[5]);+ MONT_MAC(v0, v1, v2, u[21], m[4]);+ MONT_MAC(w0, w1, w2, u[22], m[3]);+ MONT_MAC(t0, t1, t2, u[23], m[2]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[1] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 26 */+ MONT_MUL(s0, s1, s2, a[3], a[23]);+ MONT_MUL(c0, c1, c2, a[4], a[22]);+ MONT_MAC(s0, s1, s2, a[5], a[21]);+ MONT_MAC(c0, c1, c2, a[6], a[20]);+ MONT_MAC(s0, s1, s2, a[7], a[19]);+ MONT_MAC(c0, c1, c2, a[8], a[18]);+ MONT_MAC(s0, s1, s2, a[9], a[17]);+ MONT_MAC(c0, c1, c2, a[10], a[16]);+ MONT_MAC(s0, s1, s2, a[11], a[15]);+ MONT_MAC(c0, c1, c2, a[12], a[14]);+ MONT_MAC(t0, t1, t2, a[13], a[13]);+ MONT_MUL(v0, v1, v2, u[3], m[23]);+ MONT_MUL(w0, w1, w2, u[4], m[22]);+ MONT_MAC(t0, t1, t2, u[5], m[21]);+ MONT_MAC(v0, v1, v2, u[6], m[20]);+ MONT_MAC(w0, w1, w2, u[7], m[19]);+ MONT_MAC(t0, t1, t2, u[8], m[18]);+ MONT_MAC(v0, v1, v2, u[9], m[17]);+ MONT_MAC(w0, w1, w2, u[10], m[16]);+ MONT_MAC(t0, t1, t2, u[11], m[15]);+ MONT_MAC(v0, v1, v2, u[12], m[14]);+ MONT_MAC(w0, w1, w2, u[13], m[13]);+ MONT_MAC(t0, t1, t2, u[14], m[12]);+ MONT_MAC(v0, v1, v2, u[15], m[11]);+ MONT_MAC(w0, w1, w2, u[16], m[10]);+ MONT_MAC(t0, t1, t2, u[17], m[9]);+ MONT_MAC(v0, v1, v2, u[18], m[8]);+ MONT_MAC(w0, w1, w2, u[19], m[7]);+ MONT_MAC(t0, t1, t2, u[20], m[6]);+ MONT_MAC(v0, v1, v2, u[21], m[5]);+ MONT_MAC(w0, w1, w2, u[22], m[4]);+ MONT_MAC(t0, t1, t2, u[23], m[3]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[2] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 27 */+ MONT_MUL(s0, s1, s2, a[4], a[23]);+ MONT_MUL(c0, c1, c2, a[5], a[22]);+ MONT_MAC(s0, s1, s2, a[6], a[21]);+ MONT_MAC(c0, c1, c2, a[7], a[20]);+ MONT_MAC(s0, s1, s2, a[8], a[19]);+ MONT_MAC(c0, c1, c2, a[9], a[18]);+ MONT_MAC(s0, s1, s2, a[10], a[17]);+ MONT_MAC(c0, c1, c2, a[11], a[16]);+ MONT_MAC(s0, s1, s2, a[12], a[15]);+ MONT_MAC(c0, c1, c2, a[13], a[14]);+ MONT_MAC(t0, t1, t2, u[4], m[23]);+ MONT_MUL(v0, v1, v2, u[5], m[22]);+ MONT_MUL(w0, w1, w2, u[6], m[21]);+ MONT_MAC(t0, t1, t2, u[7], m[20]);+ MONT_MAC(v0, v1, v2, u[8], m[19]);+ MONT_MAC(w0, w1, w2, u[9], m[18]);+ MONT_MAC(t0, t1, t2, u[10], m[17]);+ MONT_MAC(v0, v1, v2, u[11], m[16]);+ MONT_MAC(w0, w1, w2, u[12], m[15]);+ MONT_MAC(t0, t1, t2, u[13], m[14]);+ MONT_MAC(v0, v1, v2, u[14], m[13]);+ MONT_MAC(w0, w1, w2, u[15], m[12]);+ MONT_MAC(t0, t1, t2, u[16], m[11]);+ MONT_MAC(v0, v1, v2, u[17], m[10]);+ MONT_MAC(w0, w1, w2, u[18], m[9]);+ MONT_MAC(t0, t1, t2, u[19], m[8]);+ MONT_MAC(v0, v1, v2, u[20], m[7]);+ MONT_MAC(w0, w1, w2, u[21], m[6]);+ MONT_MAC(t0, t1, t2, u[22], m[5]);+ MONT_MAC(v0, v1, v2, u[23], m[4]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[3] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 28 */+ MONT_MUL(s0, s1, s2, a[5], a[23]);+ MONT_MUL(c0, c1, c2, a[6], a[22]);+ MONT_MAC(s0, s1, s2, a[7], a[21]);+ MONT_MAC(c0, c1, c2, a[8], a[20]);+ MONT_MAC(s0, s1, s2, a[9], a[19]);+ MONT_MAC(c0, c1, c2, a[10], a[18]);+ MONT_MAC(s0, s1, s2, a[11], a[17]);+ MONT_MAC(c0, c1, c2, a[12], a[16]);+ MONT_MAC(s0, s1, s2, a[13], a[15]);+ MONT_MAC(t0, t1, t2, a[14], a[14]);+ MONT_MUL(v0, v1, v2, u[5], m[23]);+ MONT_MUL(w0, w1, w2, u[6], m[22]);+ MONT_MAC(t0, t1, t2, u[7], m[21]);+ MONT_MAC(v0, v1, v2, u[8], m[20]);+ MONT_MAC(w0, w1, w2, u[9], m[19]);+ MONT_MAC(t0, t1, t2, u[10], m[18]);+ MONT_MAC(v0, v1, v2, u[11], m[17]);+ MONT_MAC(w0, w1, w2, u[12], m[16]);+ MONT_MAC(t0, t1, t2, u[13], m[15]);+ MONT_MAC(v0, v1, v2, u[14], m[14]);+ MONT_MAC(w0, w1, w2, u[15], m[13]);+ MONT_MAC(t0, t1, t2, u[16], m[12]);+ MONT_MAC(v0, v1, v2, u[17], m[11]);+ MONT_MAC(w0, w1, w2, u[18], m[10]);+ MONT_MAC(t0, t1, t2, u[19], m[9]);+ MONT_MAC(v0, v1, v2, u[20], m[8]);+ MONT_MAC(w0, w1, w2, u[21], m[7]);+ MONT_MAC(t0, t1, t2, u[22], m[6]);+ MONT_MAC(v0, v1, v2, u[23], m[5]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[4] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 29 */+ MONT_MUL(s0, s1, s2, a[6], a[23]);+ MONT_MUL(c0, c1, c2, a[7], a[22]);+ MONT_MAC(s0, s1, s2, a[8], a[21]);+ MONT_MAC(c0, c1, c2, a[9], a[20]);+ MONT_MAC(s0, s1, s2, a[10], a[19]);+ MONT_MAC(c0, c1, c2, a[11], a[18]);+ MONT_MAC(s0, s1, s2, a[12], a[17]);+ MONT_MAC(c0, c1, c2, a[13], a[16]);+ MONT_MAC(s0, s1, s2, a[14], a[15]);+ MONT_MAC(t0, t1, t2, u[6], m[23]);+ MONT_MUL(v0, v1, v2, u[7], m[22]);+ MONT_MUL(w0, w1, w2, u[8], m[21]);+ MONT_MAC(t0, t1, t2, u[9], m[20]);+ MONT_MAC(v0, v1, v2, u[10], m[19]);+ MONT_MAC(w0, w1, w2, u[11], m[18]);+ MONT_MAC(t0, t1, t2, u[12], m[17]);+ MONT_MAC(v0, v1, v2, u[13], m[16]);+ MONT_MAC(w0, w1, w2, u[14], m[15]);+ MONT_MAC(t0, t1, t2, u[15], m[14]);+ MONT_MAC(v0, v1, v2, u[16], m[13]);+ MONT_MAC(w0, w1, w2, u[17], m[12]);+ MONT_MAC(t0, t1, t2, u[18], m[11]);+ MONT_MAC(v0, v1, v2, u[19], m[10]);+ MONT_MAC(w0, w1, w2, u[20], m[9]);+ MONT_MAC(t0, t1, t2, u[21], m[8]);+ MONT_MAC(v0, v1, v2, u[22], m[7]);+ MONT_MAC(w0, w1, w2, u[23], m[6]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[5] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 30 */+ MONT_MUL(s0, s1, s2, a[7], a[23]);+ MONT_MUL(c0, c1, c2, a[8], a[22]);+ MONT_MAC(s0, s1, s2, a[9], a[21]);+ MONT_MAC(c0, c1, c2, a[10], a[20]);+ MONT_MAC(s0, s1, s2, a[11], a[19]);+ MONT_MAC(c0, c1, c2, a[12], a[18]);+ MONT_MAC(s0, s1, s2, a[13], a[17]);+ MONT_MAC(c0, c1, c2, a[14], a[16]);+ MONT_MAC(t0, t1, t2, a[15], a[15]);+ MONT_MUL(v0, v1, v2, u[7], m[23]);+ MONT_MUL(w0, w1, w2, u[8], m[22]);+ MONT_MAC(t0, t1, t2, u[9], m[21]);+ MONT_MAC(v0, v1, v2, u[10], m[20]);+ MONT_MAC(w0, w1, w2, u[11], m[19]);+ MONT_MAC(t0, t1, t2, u[12], m[18]);+ MONT_MAC(v0, v1, v2, u[13], m[17]);+ MONT_MAC(w0, w1, w2, u[14], m[16]);+ MONT_MAC(t0, t1, t2, u[15], m[15]);+ MONT_MAC(v0, v1, v2, u[16], m[14]);+ MONT_MAC(w0, w1, w2, u[17], m[13]);+ MONT_MAC(t0, t1, t2, u[18], m[12]);+ MONT_MAC(v0, v1, v2, u[19], m[11]);+ MONT_MAC(w0, w1, w2, u[20], m[10]);+ MONT_MAC(t0, t1, t2, u[21], m[9]);+ MONT_MAC(v0, v1, v2, u[22], m[8]);+ MONT_MAC(w0, w1, w2, u[23], m[7]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[6] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 31 */+ MONT_MUL(s0, s1, s2, a[8], a[23]);+ MONT_MUL(c0, c1, c2, a[9], a[22]);+ MONT_MAC(s0, s1, s2, a[10], a[21]);+ MONT_MAC(c0, c1, c2, a[11], a[20]);+ MONT_MAC(s0, s1, s2, a[12], a[19]);+ MONT_MAC(c0, c1, c2, a[13], a[18]);+ MONT_MAC(s0, s1, s2, a[14], a[17]);+ MONT_MAC(c0, c1, c2, a[15], a[16]);+ MONT_MAC(t0, t1, t2, u[8], m[23]);+ MONT_MUL(v0, v1, v2, u[9], m[22]);+ MONT_MUL(w0, w1, w2, u[10], m[21]);+ MONT_MAC(t0, t1, t2, u[11], m[20]);+ MONT_MAC(v0, v1, v2, u[12], m[19]);+ MONT_MAC(w0, w1, w2, u[13], m[18]);+ MONT_MAC(t0, t1, t2, u[14], m[17]);+ MONT_MAC(v0, v1, v2, u[15], m[16]);+ MONT_MAC(w0, w1, w2, u[16], m[15]);+ MONT_MAC(t0, t1, t2, u[17], m[14]);+ MONT_MAC(v0, v1, v2, u[18], m[13]);+ MONT_MAC(w0, w1, w2, u[19], m[12]);+ MONT_MAC(t0, t1, t2, u[20], m[11]);+ MONT_MAC(v0, v1, v2, u[21], m[10]);+ MONT_MAC(w0, w1, w2, u[22], m[9]);+ MONT_MAC(t0, t1, t2, u[23], m[8]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[7] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 32 */+ MONT_MUL(s0, s1, s2, a[9], a[23]);+ MONT_MUL(c0, c1, c2, a[10], a[22]);+ MONT_MAC(s0, s1, s2, a[11], a[21]);+ MONT_MAC(c0, c1, c2, a[12], a[20]);+ MONT_MAC(s0, s1, s2, a[13], a[19]);+ MONT_MAC(c0, c1, c2, a[14], a[18]);+ MONT_MAC(s0, s1, s2, a[15], a[17]);+ MONT_MAC(t0, t1, t2, a[16], a[16]);+ MONT_MUL(v0, v1, v2, u[9], m[23]);+ MONT_MUL(w0, w1, w2, u[10], m[22]);+ MONT_MAC(t0, t1, t2, u[11], m[21]);+ MONT_MAC(v0, v1, v2, u[12], m[20]);+ MONT_MAC(w0, w1, w2, u[13], m[19]);+ MONT_MAC(t0, t1, t2, u[14], m[18]);+ MONT_MAC(v0, v1, v2, u[15], m[17]);+ MONT_MAC(w0, w1, w2, u[16], m[16]);+ MONT_MAC(t0, t1, t2, u[17], m[15]);+ MONT_MAC(v0, v1, v2, u[18], m[14]);+ MONT_MAC(w0, w1, w2, u[19], m[13]);+ MONT_MAC(t0, t1, t2, u[20], m[12]);+ MONT_MAC(v0, v1, v2, u[21], m[11]);+ MONT_MAC(w0, w1, w2, u[22], m[10]);+ MONT_MAC(t0, t1, t2, u[23], m[9]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[8] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 33 */+ MONT_MUL(s0, s1, s2, a[10], a[23]);+ MONT_MUL(c0, c1, c2, a[11], a[22]);+ MONT_MAC(s0, s1, s2, a[12], a[21]);+ MONT_MAC(c0, c1, c2, a[13], a[20]);+ MONT_MAC(s0, s1, s2, a[14], a[19]);+ MONT_MAC(c0, c1, c2, a[15], a[18]);+ MONT_MAC(s0, s1, s2, a[16], a[17]);+ MONT_MAC(t0, t1, t2, u[10], m[23]);+ MONT_MUL(v0, v1, v2, u[11], m[22]);+ MONT_MUL(w0, w1, w2, u[12], m[21]);+ MONT_MAC(t0, t1, t2, u[13], m[20]);+ MONT_MAC(v0, v1, v2, u[14], m[19]);+ MONT_MAC(w0, w1, w2, u[15], m[18]);+ MONT_MAC(t0, t1, t2, u[16], m[17]);+ MONT_MAC(v0, v1, v2, u[17], m[16]);+ MONT_MAC(w0, w1, w2, u[18], m[15]);+ MONT_MAC(t0, t1, t2, u[19], m[14]);+ MONT_MAC(v0, v1, v2, u[20], m[13]);+ MONT_MAC(w0, w1, w2, u[21], m[12]);+ MONT_MAC(t0, t1, t2, u[22], m[11]);+ MONT_MAC(v0, v1, v2, u[23], m[10]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[9] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 34 */+ MONT_MUL(s0, s1, s2, a[11], a[23]);+ MONT_MUL(c0, c1, c2, a[12], a[22]);+ MONT_MAC(s0, s1, s2, a[13], a[21]);+ MONT_MAC(c0, c1, c2, a[14], a[20]);+ MONT_MAC(s0, s1, s2, a[15], a[19]);+ MONT_MAC(c0, c1, c2, a[16], a[18]);+ MONT_MAC(t0, t1, t2, a[17], a[17]);+ MONT_MUL(v0, v1, v2, u[11], m[23]);+ MONT_MUL(w0, w1, w2, u[12], m[22]);+ MONT_MAC(t0, t1, t2, u[13], m[21]);+ MONT_MAC(v0, v1, v2, u[14], m[20]);+ MONT_MAC(w0, w1, w2, u[15], m[19]);+ MONT_MAC(t0, t1, t2, u[16], m[18]);+ MONT_MAC(v0, v1, v2, u[17], m[17]);+ MONT_MAC(w0, w1, w2, u[18], m[16]);+ MONT_MAC(t0, t1, t2, u[19], m[15]);+ MONT_MAC(v0, v1, v2, u[20], m[14]);+ MONT_MAC(w0, w1, w2, u[21], m[13]);+ MONT_MAC(t0, t1, t2, u[22], m[12]);+ MONT_MAC(v0, v1, v2, u[23], m[11]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[10] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 35 */+ MONT_MUL(s0, s1, s2, a[12], a[23]);+ MONT_MUL(c0, c1, c2, a[13], a[22]);+ MONT_MAC(s0, s1, s2, a[14], a[21]);+ MONT_MAC(c0, c1, c2, a[15], a[20]);+ MONT_MAC(s0, s1, s2, a[16], a[19]);+ MONT_MAC(c0, c1, c2, a[17], a[18]);+ MONT_MAC(t0, t1, t2, u[12], m[23]);+ MONT_MUL(v0, v1, v2, u[13], m[22]);+ MONT_MUL(w0, w1, w2, u[14], m[21]);+ MONT_MAC(t0, t1, t2, u[15], m[20]);+ MONT_MAC(v0, v1, v2, u[16], m[19]);+ MONT_MAC(w0, w1, w2, u[17], m[18]);+ MONT_MAC(t0, t1, t2, u[18], m[17]);+ MONT_MAC(v0, v1, v2, u[19], m[16]);+ MONT_MAC(w0, w1, w2, u[20], m[15]);+ MONT_MAC(t0, t1, t2, u[21], m[14]);+ MONT_MAC(v0, v1, v2, u[22], m[13]);+ MONT_MAC(w0, w1, w2, u[23], m[12]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[11] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 36 */+ MONT_MUL(s0, s1, s2, a[13], a[23]);+ MONT_MUL(c0, c1, c2, a[14], a[22]);+ MONT_MAC(s0, s1, s2, a[15], a[21]);+ MONT_MAC(c0, c1, c2, a[16], a[20]);+ MONT_MAC(s0, s1, s2, a[17], a[19]);+ MONT_MAC(t0, t1, t2, a[18], a[18]);+ MONT_MUL(v0, v1, v2, u[13], m[23]);+ MONT_MUL(w0, w1, w2, u[14], m[22]);+ MONT_MAC(t0, t1, t2, u[15], m[21]);+ MONT_MAC(v0, v1, v2, u[16], m[20]);+ MONT_MAC(w0, w1, w2, u[17], m[19]);+ MONT_MAC(t0, t1, t2, u[18], m[18]);+ MONT_MAC(v0, v1, v2, u[19], m[17]);+ MONT_MAC(w0, w1, w2, u[20], m[16]);+ MONT_MAC(t0, t1, t2, u[21], m[15]);+ MONT_MAC(v0, v1, v2, u[22], m[14]);+ MONT_MAC(w0, w1, w2, u[23], m[13]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[12] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 37 */+ MONT_MUL(s0, s1, s2, a[14], a[23]);+ MONT_MUL(c0, c1, c2, a[15], a[22]);+ MONT_MAC(s0, s1, s2, a[16], a[21]);+ MONT_MAC(c0, c1, c2, a[17], a[20]);+ MONT_MAC(s0, s1, s2, a[18], a[19]);+ MONT_MAC(t0, t1, t2, u[14], m[23]);+ MONT_MUL(v0, v1, v2, u[15], m[22]);+ MONT_MUL(w0, w1, w2, u[16], m[21]);+ MONT_MAC(t0, t1, t2, u[17], m[20]);+ MONT_MAC(v0, v1, v2, u[18], m[19]);+ MONT_MAC(w0, w1, w2, u[19], m[18]);+ MONT_MAC(t0, t1, t2, u[20], m[17]);+ MONT_MAC(v0, v1, v2, u[21], m[16]);+ MONT_MAC(w0, w1, w2, u[22], m[15]);+ MONT_MAC(t0, t1, t2, u[23], m[14]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[13] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 38 */+ MONT_MUL(s0, s1, s2, a[15], a[23]);+ MONT_MUL(c0, c1, c2, a[16], a[22]);+ MONT_MAC(s0, s1, s2, a[17], a[21]);+ MONT_MAC(c0, c1, c2, a[18], a[20]);+ MONT_MAC(t0, t1, t2, a[19], a[19]);+ MONT_MUL(v0, v1, v2, u[15], m[23]);+ MONT_MUL(w0, w1, w2, u[16], m[22]);+ MONT_MAC(t0, t1, t2, u[17], m[21]);+ MONT_MAC(v0, v1, v2, u[18], m[20]);+ MONT_MAC(w0, w1, w2, u[19], m[19]);+ MONT_MAC(t0, t1, t2, u[20], m[18]);+ MONT_MAC(v0, v1, v2, u[21], m[17]);+ MONT_MAC(w0, w1, w2, u[22], m[16]);+ MONT_MAC(t0, t1, t2, u[23], m[15]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[14] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 39 */+ MONT_MUL(s0, s1, s2, a[16], a[23]);+ MONT_MUL(c0, c1, c2, a[17], a[22]);+ MONT_MAC(s0, s1, s2, a[18], a[21]);+ MONT_MAC(c0, c1, c2, a[19], a[20]);+ MONT_MAC(t0, t1, t2, u[16], m[23]);+ MONT_MUL(v0, v1, v2, u[17], m[22]);+ MONT_MUL(w0, w1, w2, u[18], m[21]);+ MONT_MAC(t0, t1, t2, u[19], m[20]);+ MONT_MAC(v0, v1, v2, u[20], m[19]);+ MONT_MAC(w0, w1, w2, u[21], m[18]);+ MONT_MAC(t0, t1, t2, u[22], m[17]);+ MONT_MAC(v0, v1, v2, u[23], m[16]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[15] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 40 */+ MONT_MUL(s0, s1, s2, a[17], a[23]);+ MONT_MUL(c0, c1, c2, a[18], a[22]);+ MONT_MAC(s0, s1, s2, a[19], a[21]);+ MONT_MAC(t0, t1, t2, a[20], a[20]);+ MONT_MUL(v0, v1, v2, u[17], m[23]);+ MONT_MUL(w0, w1, w2, u[18], m[22]);+ MONT_MAC(t0, t1, t2, u[19], m[21]);+ MONT_MAC(v0, v1, v2, u[20], m[20]);+ MONT_MAC(w0, w1, w2, u[21], m[19]);+ MONT_MAC(t0, t1, t2, u[22], m[18]);+ MONT_MAC(v0, v1, v2, u[23], m[17]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[16] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 41 */+ MONT_MUL(s0, s1, s2, a[18], a[23]);+ MONT_MUL(c0, c1, c2, a[19], a[22]);+ MONT_MAC(s0, s1, s2, a[20], a[21]);+ MONT_MAC(t0, t1, t2, u[18], m[23]);+ MONT_MUL(v0, v1, v2, u[19], m[22]);+ MONT_MUL(w0, w1, w2, u[20], m[21]);+ MONT_MAC(t0, t1, t2, u[21], m[20]);+ MONT_MAC(v0, v1, v2, u[22], m[19]);+ MONT_MAC(w0, w1, w2, u[23], m[18]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[17] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 42 */+ MONT_MUL(s0, s1, s2, a[19], a[23]);+ MONT_MUL(c0, c1, c2, a[20], a[22]);+ MONT_MAC(t0, t1, t2, a[21], a[21]);+ MONT_MUL(v0, v1, v2, u[19], m[23]);+ MONT_MUL(w0, w1, w2, u[20], m[22]);+ MONT_MAC(t0, t1, t2, u[21], m[21]);+ MONT_MAC(v0, v1, v2, u[22], m[20]);+ MONT_MAC(w0, w1, w2, u[23], m[19]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[18] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 43 */+ MONT_MUL(s0, s1, s2, a[20], a[23]);+ MONT_MUL(c0, c1, c2, a[21], a[22]);+ MONT_MAC(t0, t1, t2, u[20], m[23]);+ MONT_MUL(v0, v1, v2, u[21], m[22]);+ MONT_MUL(w0, w1, w2, u[22], m[21]);+ MONT_MAC(t0, t1, t2, u[23], m[20]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[19] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 44 */+ MONT_MUL(s0, s1, s2, a[21], a[23]);+ MONT_MAC(t0, t1, t2, a[22], a[22]);+ MONT_MUL(v0, v1, v2, u[21], m[23]);+ MONT_MUL(w0, w1, w2, u[22], m[22]);+ MONT_MAC(t0, t1, t2, u[23], m[21]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[20] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 45 */+ MONT_MUL(s0, s1, s2, a[22], a[23]);+ MONT_MAC(t0, t1, t2, u[22], m[23]);+ MONT_MUL(v0, v1, v2, u[23], m[22]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[21] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 46 */+ MONT_MAC(t0, t1, t2, a[23], a[23]);+ MONT_MUL(v0, v1, v2, u[23], m[23]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ z[22] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ z[23] = t0;++ /* under 2m, with t1 the bit above n limbs: at most one subtraction */+ borrow = sub_n(r, z, m, 24);+ take = t1 | (borrow ^ 1);+ select_n(r, r, z, take & 1, 24);+}++/* r = a * b * R^-1 mod m, for a and b under m; t is 2n limbs of scratch */+static void crypton_mont_mul32(limb_t *r, const limb_t *a, const limb_t *b,+ const limb_t *m, limb_t n0, limb_t *t)+{+ limb_t *u = t, *z = t + 32;+ limb_t t0 = 0, t1 = 0, t2 = 0, v0, v1, v2, w0, w1, w2, borrow, take;++ /* column 0 */+ MONT_MAC(t0, t1, t2, a[0], b[0]);+ u[0] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[0], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 1 */+ MONT_MAC(t0, t1, t2, a[0], b[1]);+ MONT_MUL(v0, v1, v2, a[1], b[0]);+ MONT_MUL(w0, w1, w2, u[0], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[1] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[1], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 2 */+ MONT_MAC(t0, t1, t2, a[0], b[2]);+ MONT_MUL(v0, v1, v2, a[1], b[1]);+ MONT_MUL(w0, w1, w2, a[2], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[2]);+ MONT_MAC(v0, v1, v2, u[1], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[2] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[2], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 3 */+ MONT_MAC(t0, t1, t2, a[0], b[3]);+ MONT_MUL(v0, v1, v2, a[1], b[2]);+ MONT_MUL(w0, w1, w2, a[2], b[1]);+ MONT_MAC(t0, t1, t2, a[3], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[3]);+ MONT_MAC(w0, w1, w2, u[1], m[2]);+ MONT_MAC(t0, t1, t2, u[2], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[3] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[3], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 4 */+ MONT_MAC(t0, t1, t2, a[0], b[4]);+ MONT_MUL(v0, v1, v2, a[1], b[3]);+ MONT_MUL(w0, w1, w2, a[2], b[2]);+ MONT_MAC(t0, t1, t2, a[3], b[1]);+ MONT_MAC(v0, v1, v2, a[4], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[4]);+ MONT_MAC(t0, t1, t2, u[1], m[3]);+ MONT_MAC(v0, v1, v2, u[2], m[2]);+ MONT_MAC(w0, w1, w2, u[3], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[4] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[4], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 5 */+ MONT_MAC(t0, t1, t2, a[0], b[5]);+ MONT_MUL(v0, v1, v2, a[1], b[4]);+ MONT_MUL(w0, w1, w2, a[2], b[3]);+ MONT_MAC(t0, t1, t2, a[3], b[2]);+ MONT_MAC(v0, v1, v2, a[4], b[1]);+ MONT_MAC(w0, w1, w2, a[5], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[5]);+ MONT_MAC(v0, v1, v2, u[1], m[4]);+ MONT_MAC(w0, w1, w2, u[2], m[3]);+ MONT_MAC(t0, t1, t2, u[3], m[2]);+ MONT_MAC(v0, v1, v2, u[4], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[5] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[5], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 6 */+ MONT_MAC(t0, t1, t2, a[0], b[6]);+ MONT_MUL(v0, v1, v2, a[1], b[5]);+ MONT_MUL(w0, w1, w2, a[2], b[4]);+ MONT_MAC(t0, t1, t2, a[3], b[3]);+ MONT_MAC(v0, v1, v2, a[4], b[2]);+ MONT_MAC(w0, w1, w2, a[5], b[1]);+ MONT_MAC(t0, t1, t2, a[6], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[6]);+ MONT_MAC(w0, w1, w2, u[1], m[5]);+ MONT_MAC(t0, t1, t2, u[2], m[4]);+ MONT_MAC(v0, v1, v2, u[3], m[3]);+ MONT_MAC(w0, w1, w2, u[4], m[2]);+ MONT_MAC(t0, t1, t2, u[5], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[6] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[6], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 7 */+ MONT_MAC(t0, t1, t2, a[0], b[7]);+ MONT_MUL(v0, v1, v2, a[1], b[6]);+ MONT_MUL(w0, w1, w2, a[2], b[5]);+ MONT_MAC(t0, t1, t2, a[3], b[4]);+ MONT_MAC(v0, v1, v2, a[4], b[3]);+ MONT_MAC(w0, w1, w2, a[5], b[2]);+ MONT_MAC(t0, t1, t2, a[6], b[1]);+ MONT_MAC(v0, v1, v2, a[7], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[7]);+ MONT_MAC(t0, t1, t2, u[1], m[6]);+ MONT_MAC(v0, v1, v2, u[2], m[5]);+ MONT_MAC(w0, w1, w2, u[3], m[4]);+ MONT_MAC(t0, t1, t2, u[4], m[3]);+ MONT_MAC(v0, v1, v2, u[5], m[2]);+ MONT_MAC(w0, w1, w2, u[6], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[7] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[7], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 8 */+ MONT_MAC(t0, t1, t2, a[0], b[8]);+ MONT_MUL(v0, v1, v2, a[1], b[7]);+ MONT_MUL(w0, w1, w2, a[2], b[6]);+ MONT_MAC(t0, t1, t2, a[3], b[5]);+ MONT_MAC(v0, v1, v2, a[4], b[4]);+ MONT_MAC(w0, w1, w2, a[5], b[3]);+ MONT_MAC(t0, t1, t2, a[6], b[2]);+ MONT_MAC(v0, v1, v2, a[7], b[1]);+ MONT_MAC(w0, w1, w2, a[8], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[8]);+ MONT_MAC(v0, v1, v2, u[1], m[7]);+ MONT_MAC(w0, w1, w2, u[2], m[6]);+ MONT_MAC(t0, t1, t2, u[3], m[5]);+ MONT_MAC(v0, v1, v2, u[4], m[4]);+ MONT_MAC(w0, w1, w2, u[5], m[3]);+ MONT_MAC(t0, t1, t2, u[6], m[2]);+ MONT_MAC(v0, v1, v2, u[7], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[8] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[8], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 9 */+ MONT_MAC(t0, t1, t2, a[0], b[9]);+ MONT_MUL(v0, v1, v2, a[1], b[8]);+ MONT_MUL(w0, w1, w2, a[2], b[7]);+ MONT_MAC(t0, t1, t2, a[3], b[6]);+ MONT_MAC(v0, v1, v2, a[4], b[5]);+ MONT_MAC(w0, w1, w2, a[5], b[4]);+ MONT_MAC(t0, t1, t2, a[6], b[3]);+ MONT_MAC(v0, v1, v2, a[7], b[2]);+ MONT_MAC(w0, w1, w2, a[8], b[1]);+ MONT_MAC(t0, t1, t2, a[9], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[9]);+ MONT_MAC(w0, w1, w2, u[1], m[8]);+ MONT_MAC(t0, t1, t2, u[2], m[7]);+ MONT_MAC(v0, v1, v2, u[3], m[6]);+ MONT_MAC(w0, w1, w2, u[4], m[5]);+ MONT_MAC(t0, t1, t2, u[5], m[4]);+ MONT_MAC(v0, v1, v2, u[6], m[3]);+ MONT_MAC(w0, w1, w2, u[7], m[2]);+ MONT_MAC(t0, t1, t2, u[8], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[9] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[9], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 10 */+ MONT_MAC(t0, t1, t2, a[0], b[10]);+ MONT_MUL(v0, v1, v2, a[1], b[9]);+ MONT_MUL(w0, w1, w2, a[2], b[8]);+ MONT_MAC(t0, t1, t2, a[3], b[7]);+ MONT_MAC(v0, v1, v2, a[4], b[6]);+ MONT_MAC(w0, w1, w2, a[5], b[5]);+ MONT_MAC(t0, t1, t2, a[6], b[4]);+ MONT_MAC(v0, v1, v2, a[7], b[3]);+ MONT_MAC(w0, w1, w2, a[8], b[2]);+ MONT_MAC(t0, t1, t2, a[9], b[1]);+ MONT_MAC(v0, v1, v2, a[10], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[10]);+ MONT_MAC(t0, t1, t2, u[1], m[9]);+ MONT_MAC(v0, v1, v2, u[2], m[8]);+ MONT_MAC(w0, w1, w2, u[3], m[7]);+ MONT_MAC(t0, t1, t2, u[4], m[6]);+ MONT_MAC(v0, v1, v2, u[5], m[5]);+ MONT_MAC(w0, w1, w2, u[6], m[4]);+ MONT_MAC(t0, t1, t2, u[7], m[3]);+ MONT_MAC(v0, v1, v2, u[8], m[2]);+ MONT_MAC(w0, w1, w2, u[9], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[10] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[10], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 11 */+ MONT_MAC(t0, t1, t2, a[0], b[11]);+ MONT_MUL(v0, v1, v2, a[1], b[10]);+ MONT_MUL(w0, w1, w2, a[2], b[9]);+ MONT_MAC(t0, t1, t2, a[3], b[8]);+ MONT_MAC(v0, v1, v2, a[4], b[7]);+ MONT_MAC(w0, w1, w2, a[5], b[6]);+ MONT_MAC(t0, t1, t2, a[6], b[5]);+ MONT_MAC(v0, v1, v2, a[7], b[4]);+ MONT_MAC(w0, w1, w2, a[8], b[3]);+ MONT_MAC(t0, t1, t2, a[9], b[2]);+ MONT_MAC(v0, v1, v2, a[10], b[1]);+ MONT_MAC(w0, w1, w2, a[11], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[11]);+ MONT_MAC(v0, v1, v2, u[1], m[10]);+ MONT_MAC(w0, w1, w2, u[2], m[9]);+ MONT_MAC(t0, t1, t2, u[3], m[8]);+ MONT_MAC(v0, v1, v2, u[4], m[7]);+ MONT_MAC(w0, w1, w2, u[5], m[6]);+ MONT_MAC(t0, t1, t2, u[6], m[5]);+ MONT_MAC(v0, v1, v2, u[7], m[4]);+ MONT_MAC(w0, w1, w2, u[8], m[3]);+ MONT_MAC(t0, t1, t2, u[9], m[2]);+ MONT_MAC(v0, v1, v2, u[10], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[11] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[11], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 12 */+ MONT_MAC(t0, t1, t2, a[0], b[12]);+ MONT_MUL(v0, v1, v2, a[1], b[11]);+ MONT_MUL(w0, w1, w2, a[2], b[10]);+ MONT_MAC(t0, t1, t2, a[3], b[9]);+ MONT_MAC(v0, v1, v2, a[4], b[8]);+ MONT_MAC(w0, w1, w2, a[5], b[7]);+ MONT_MAC(t0, t1, t2, a[6], b[6]);+ MONT_MAC(v0, v1, v2, a[7], b[5]);+ MONT_MAC(w0, w1, w2, a[8], b[4]);+ MONT_MAC(t0, t1, t2, a[9], b[3]);+ MONT_MAC(v0, v1, v2, a[10], b[2]);+ MONT_MAC(w0, w1, w2, a[11], b[1]);+ MONT_MAC(t0, t1, t2, a[12], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[12]);+ MONT_MAC(w0, w1, w2, u[1], m[11]);+ MONT_MAC(t0, t1, t2, u[2], m[10]);+ MONT_MAC(v0, v1, v2, u[3], m[9]);+ MONT_MAC(w0, w1, w2, u[4], m[8]);+ MONT_MAC(t0, t1, t2, u[5], m[7]);+ MONT_MAC(v0, v1, v2, u[6], m[6]);+ MONT_MAC(w0, w1, w2, u[7], m[5]);+ MONT_MAC(t0, t1, t2, u[8], m[4]);+ MONT_MAC(v0, v1, v2, u[9], m[3]);+ MONT_MAC(w0, w1, w2, u[10], m[2]);+ MONT_MAC(t0, t1, t2, u[11], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[12] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[12], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 13 */+ MONT_MAC(t0, t1, t2, a[0], b[13]);+ MONT_MUL(v0, v1, v2, a[1], b[12]);+ MONT_MUL(w0, w1, w2, a[2], b[11]);+ MONT_MAC(t0, t1, t2, a[3], b[10]);+ MONT_MAC(v0, v1, v2, a[4], b[9]);+ MONT_MAC(w0, w1, w2, a[5], b[8]);+ MONT_MAC(t0, t1, t2, a[6], b[7]);+ MONT_MAC(v0, v1, v2, a[7], b[6]);+ MONT_MAC(w0, w1, w2, a[8], b[5]);+ MONT_MAC(t0, t1, t2, a[9], b[4]);+ MONT_MAC(v0, v1, v2, a[10], b[3]);+ MONT_MAC(w0, w1, w2, a[11], b[2]);+ MONT_MAC(t0, t1, t2, a[12], b[1]);+ MONT_MAC(v0, v1, v2, a[13], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[13]);+ MONT_MAC(t0, t1, t2, u[1], m[12]);+ MONT_MAC(v0, v1, v2, u[2], m[11]);+ MONT_MAC(w0, w1, w2, u[3], m[10]);+ MONT_MAC(t0, t1, t2, u[4], m[9]);+ MONT_MAC(v0, v1, v2, u[5], m[8]);+ MONT_MAC(w0, w1, w2, u[6], m[7]);+ MONT_MAC(t0, t1, t2, u[7], m[6]);+ MONT_MAC(v0, v1, v2, u[8], m[5]);+ MONT_MAC(w0, w1, w2, u[9], m[4]);+ MONT_MAC(t0, t1, t2, u[10], m[3]);+ MONT_MAC(v0, v1, v2, u[11], m[2]);+ MONT_MAC(w0, w1, w2, u[12], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[13] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[13], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 14 */+ MONT_MAC(t0, t1, t2, a[0], b[14]);+ MONT_MUL(v0, v1, v2, a[1], b[13]);+ MONT_MUL(w0, w1, w2, a[2], b[12]);+ MONT_MAC(t0, t1, t2, a[3], b[11]);+ MONT_MAC(v0, v1, v2, a[4], b[10]);+ MONT_MAC(w0, w1, w2, a[5], b[9]);+ MONT_MAC(t0, t1, t2, a[6], b[8]);+ MONT_MAC(v0, v1, v2, a[7], b[7]);+ MONT_MAC(w0, w1, w2, a[8], b[6]);+ MONT_MAC(t0, t1, t2, a[9], b[5]);+ MONT_MAC(v0, v1, v2, a[10], b[4]);+ MONT_MAC(w0, w1, w2, a[11], b[3]);+ MONT_MAC(t0, t1, t2, a[12], b[2]);+ MONT_MAC(v0, v1, v2, a[13], b[1]);+ MONT_MAC(w0, w1, w2, a[14], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[14]);+ MONT_MAC(v0, v1, v2, u[1], m[13]);+ MONT_MAC(w0, w1, w2, u[2], m[12]);+ MONT_MAC(t0, t1, t2, u[3], m[11]);+ MONT_MAC(v0, v1, v2, u[4], m[10]);+ MONT_MAC(w0, w1, w2, u[5], m[9]);+ MONT_MAC(t0, t1, t2, u[6], m[8]);+ MONT_MAC(v0, v1, v2, u[7], m[7]);+ MONT_MAC(w0, w1, w2, u[8], m[6]);+ MONT_MAC(t0, t1, t2, u[9], m[5]);+ MONT_MAC(v0, v1, v2, u[10], m[4]);+ MONT_MAC(w0, w1, w2, u[11], m[3]);+ MONT_MAC(t0, t1, t2, u[12], m[2]);+ MONT_MAC(v0, v1, v2, u[13], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[14] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[14], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 15 */+ MONT_MAC(t0, t1, t2, a[0], b[15]);+ MONT_MUL(v0, v1, v2, a[1], b[14]);+ MONT_MUL(w0, w1, w2, a[2], b[13]);+ MONT_MAC(t0, t1, t2, a[3], b[12]);+ MONT_MAC(v0, v1, v2, a[4], b[11]);+ MONT_MAC(w0, w1, w2, a[5], b[10]);+ MONT_MAC(t0, t1, t2, a[6], b[9]);+ MONT_MAC(v0, v1, v2, a[7], b[8]);+ MONT_MAC(w0, w1, w2, a[8], b[7]);+ MONT_MAC(t0, t1, t2, a[9], b[6]);+ MONT_MAC(v0, v1, v2, a[10], b[5]);+ MONT_MAC(w0, w1, w2, a[11], b[4]);+ MONT_MAC(t0, t1, t2, a[12], b[3]);+ MONT_MAC(v0, v1, v2, a[13], b[2]);+ MONT_MAC(w0, w1, w2, a[14], b[1]);+ MONT_MAC(t0, t1, t2, a[15], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[15]);+ MONT_MAC(w0, w1, w2, u[1], m[14]);+ MONT_MAC(t0, t1, t2, u[2], m[13]);+ MONT_MAC(v0, v1, v2, u[3], m[12]);+ MONT_MAC(w0, w1, w2, u[4], m[11]);+ MONT_MAC(t0, t1, t2, u[5], m[10]);+ MONT_MAC(v0, v1, v2, u[6], m[9]);+ MONT_MAC(w0, w1, w2, u[7], m[8]);+ MONT_MAC(t0, t1, t2, u[8], m[7]);+ MONT_MAC(v0, v1, v2, u[9], m[6]);+ MONT_MAC(w0, w1, w2, u[10], m[5]);+ MONT_MAC(t0, t1, t2, u[11], m[4]);+ MONT_MAC(v0, v1, v2, u[12], m[3]);+ MONT_MAC(w0, w1, w2, u[13], m[2]);+ MONT_MAC(t0, t1, t2, u[14], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[15] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[15], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 16 */+ MONT_MAC(t0, t1, t2, a[0], b[16]);+ MONT_MUL(v0, v1, v2, a[1], b[15]);+ MONT_MUL(w0, w1, w2, a[2], b[14]);+ MONT_MAC(t0, t1, t2, a[3], b[13]);+ MONT_MAC(v0, v1, v2, a[4], b[12]);+ MONT_MAC(w0, w1, w2, a[5], b[11]);+ MONT_MAC(t0, t1, t2, a[6], b[10]);+ MONT_MAC(v0, v1, v2, a[7], b[9]);+ MONT_MAC(w0, w1, w2, a[8], b[8]);+ MONT_MAC(t0, t1, t2, a[9], b[7]);+ MONT_MAC(v0, v1, v2, a[10], b[6]);+ MONT_MAC(w0, w1, w2, a[11], b[5]);+ MONT_MAC(t0, t1, t2, a[12], b[4]);+ MONT_MAC(v0, v1, v2, a[13], b[3]);+ MONT_MAC(w0, w1, w2, a[14], b[2]);+ MONT_MAC(t0, t1, t2, a[15], b[1]);+ MONT_MAC(v0, v1, v2, a[16], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[16]);+ MONT_MAC(t0, t1, t2, u[1], m[15]);+ MONT_MAC(v0, v1, v2, u[2], m[14]);+ MONT_MAC(w0, w1, w2, u[3], m[13]);+ MONT_MAC(t0, t1, t2, u[4], m[12]);+ MONT_MAC(v0, v1, v2, u[5], m[11]);+ MONT_MAC(w0, w1, w2, u[6], m[10]);+ MONT_MAC(t0, t1, t2, u[7], m[9]);+ MONT_MAC(v0, v1, v2, u[8], m[8]);+ MONT_MAC(w0, w1, w2, u[9], m[7]);+ MONT_MAC(t0, t1, t2, u[10], m[6]);+ MONT_MAC(v0, v1, v2, u[11], m[5]);+ MONT_MAC(w0, w1, w2, u[12], m[4]);+ MONT_MAC(t0, t1, t2, u[13], m[3]);+ MONT_MAC(v0, v1, v2, u[14], m[2]);+ MONT_MAC(w0, w1, w2, u[15], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[16] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[16], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 17 */+ MONT_MAC(t0, t1, t2, a[0], b[17]);+ MONT_MUL(v0, v1, v2, a[1], b[16]);+ MONT_MUL(w0, w1, w2, a[2], b[15]);+ MONT_MAC(t0, t1, t2, a[3], b[14]);+ MONT_MAC(v0, v1, v2, a[4], b[13]);+ MONT_MAC(w0, w1, w2, a[5], b[12]);+ MONT_MAC(t0, t1, t2, a[6], b[11]);+ MONT_MAC(v0, v1, v2, a[7], b[10]);+ MONT_MAC(w0, w1, w2, a[8], b[9]);+ MONT_MAC(t0, t1, t2, a[9], b[8]);+ MONT_MAC(v0, v1, v2, a[10], b[7]);+ MONT_MAC(w0, w1, w2, a[11], b[6]);+ MONT_MAC(t0, t1, t2, a[12], b[5]);+ MONT_MAC(v0, v1, v2, a[13], b[4]);+ MONT_MAC(w0, w1, w2, a[14], b[3]);+ MONT_MAC(t0, t1, t2, a[15], b[2]);+ MONT_MAC(v0, v1, v2, a[16], b[1]);+ MONT_MAC(w0, w1, w2, a[17], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[17]);+ MONT_MAC(v0, v1, v2, u[1], m[16]);+ MONT_MAC(w0, w1, w2, u[2], m[15]);+ MONT_MAC(t0, t1, t2, u[3], m[14]);+ MONT_MAC(v0, v1, v2, u[4], m[13]);+ MONT_MAC(w0, w1, w2, u[5], m[12]);+ MONT_MAC(t0, t1, t2, u[6], m[11]);+ MONT_MAC(v0, v1, v2, u[7], m[10]);+ MONT_MAC(w0, w1, w2, u[8], m[9]);+ MONT_MAC(t0, t1, t2, u[9], m[8]);+ MONT_MAC(v0, v1, v2, u[10], m[7]);+ MONT_MAC(w0, w1, w2, u[11], m[6]);+ MONT_MAC(t0, t1, t2, u[12], m[5]);+ MONT_MAC(v0, v1, v2, u[13], m[4]);+ MONT_MAC(w0, w1, w2, u[14], m[3]);+ MONT_MAC(t0, t1, t2, u[15], m[2]);+ MONT_MAC(v0, v1, v2, u[16], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[17] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[17], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 18 */+ MONT_MAC(t0, t1, t2, a[0], b[18]);+ MONT_MUL(v0, v1, v2, a[1], b[17]);+ MONT_MUL(w0, w1, w2, a[2], b[16]);+ MONT_MAC(t0, t1, t2, a[3], b[15]);+ MONT_MAC(v0, v1, v2, a[4], b[14]);+ MONT_MAC(w0, w1, w2, a[5], b[13]);+ MONT_MAC(t0, t1, t2, a[6], b[12]);+ MONT_MAC(v0, v1, v2, a[7], b[11]);+ MONT_MAC(w0, w1, w2, a[8], b[10]);+ MONT_MAC(t0, t1, t2, a[9], b[9]);+ MONT_MAC(v0, v1, v2, a[10], b[8]);+ MONT_MAC(w0, w1, w2, a[11], b[7]);+ MONT_MAC(t0, t1, t2, a[12], b[6]);+ MONT_MAC(v0, v1, v2, a[13], b[5]);+ MONT_MAC(w0, w1, w2, a[14], b[4]);+ MONT_MAC(t0, t1, t2, a[15], b[3]);+ MONT_MAC(v0, v1, v2, a[16], b[2]);+ MONT_MAC(w0, w1, w2, a[17], b[1]);+ MONT_MAC(t0, t1, t2, a[18], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[18]);+ MONT_MAC(w0, w1, w2, u[1], m[17]);+ MONT_MAC(t0, t1, t2, u[2], m[16]);+ MONT_MAC(v0, v1, v2, u[3], m[15]);+ MONT_MAC(w0, w1, w2, u[4], m[14]);+ MONT_MAC(t0, t1, t2, u[5], m[13]);+ MONT_MAC(v0, v1, v2, u[6], m[12]);+ MONT_MAC(w0, w1, w2, u[7], m[11]);+ MONT_MAC(t0, t1, t2, u[8], m[10]);+ MONT_MAC(v0, v1, v2, u[9], m[9]);+ MONT_MAC(w0, w1, w2, u[10], m[8]);+ MONT_MAC(t0, t1, t2, u[11], m[7]);+ MONT_MAC(v0, v1, v2, u[12], m[6]);+ MONT_MAC(w0, w1, w2, u[13], m[5]);+ MONT_MAC(t0, t1, t2, u[14], m[4]);+ MONT_MAC(v0, v1, v2, u[15], m[3]);+ MONT_MAC(w0, w1, w2, u[16], m[2]);+ MONT_MAC(t0, t1, t2, u[17], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[18] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[18], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 19 */+ MONT_MAC(t0, t1, t2, a[0], b[19]);+ MONT_MUL(v0, v1, v2, a[1], b[18]);+ MONT_MUL(w0, w1, w2, a[2], b[17]);+ MONT_MAC(t0, t1, t2, a[3], b[16]);+ MONT_MAC(v0, v1, v2, a[4], b[15]);+ MONT_MAC(w0, w1, w2, a[5], b[14]);+ MONT_MAC(t0, t1, t2, a[6], b[13]);+ MONT_MAC(v0, v1, v2, a[7], b[12]);+ MONT_MAC(w0, w1, w2, a[8], b[11]);+ MONT_MAC(t0, t1, t2, a[9], b[10]);+ MONT_MAC(v0, v1, v2, a[10], b[9]);+ MONT_MAC(w0, w1, w2, a[11], b[8]);+ MONT_MAC(t0, t1, t2, a[12], b[7]);+ MONT_MAC(v0, v1, v2, a[13], b[6]);+ MONT_MAC(w0, w1, w2, a[14], b[5]);+ MONT_MAC(t0, t1, t2, a[15], b[4]);+ MONT_MAC(v0, v1, v2, a[16], b[3]);+ MONT_MAC(w0, w1, w2, a[17], b[2]);+ MONT_MAC(t0, t1, t2, a[18], b[1]);+ MONT_MAC(v0, v1, v2, a[19], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[19]);+ MONT_MAC(t0, t1, t2, u[1], m[18]);+ MONT_MAC(v0, v1, v2, u[2], m[17]);+ MONT_MAC(w0, w1, w2, u[3], m[16]);+ MONT_MAC(t0, t1, t2, u[4], m[15]);+ MONT_MAC(v0, v1, v2, u[5], m[14]);+ MONT_MAC(w0, w1, w2, u[6], m[13]);+ MONT_MAC(t0, t1, t2, u[7], m[12]);+ MONT_MAC(v0, v1, v2, u[8], m[11]);+ MONT_MAC(w0, w1, w2, u[9], m[10]);+ MONT_MAC(t0, t1, t2, u[10], m[9]);+ MONT_MAC(v0, v1, v2, u[11], m[8]);+ MONT_MAC(w0, w1, w2, u[12], m[7]);+ MONT_MAC(t0, t1, t2, u[13], m[6]);+ MONT_MAC(v0, v1, v2, u[14], m[5]);+ MONT_MAC(w0, w1, w2, u[15], m[4]);+ MONT_MAC(t0, t1, t2, u[16], m[3]);+ MONT_MAC(v0, v1, v2, u[17], m[2]);+ MONT_MAC(w0, w1, w2, u[18], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[19] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[19], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 20 */+ MONT_MAC(t0, t1, t2, a[0], b[20]);+ MONT_MUL(v0, v1, v2, a[1], b[19]);+ MONT_MUL(w0, w1, w2, a[2], b[18]);+ MONT_MAC(t0, t1, t2, a[3], b[17]);+ MONT_MAC(v0, v1, v2, a[4], b[16]);+ MONT_MAC(w0, w1, w2, a[5], b[15]);+ MONT_MAC(t0, t1, t2, a[6], b[14]);+ MONT_MAC(v0, v1, v2, a[7], b[13]);+ MONT_MAC(w0, w1, w2, a[8], b[12]);+ MONT_MAC(t0, t1, t2, a[9], b[11]);+ MONT_MAC(v0, v1, v2, a[10], b[10]);+ MONT_MAC(w0, w1, w2, a[11], b[9]);+ MONT_MAC(t0, t1, t2, a[12], b[8]);+ MONT_MAC(v0, v1, v2, a[13], b[7]);+ MONT_MAC(w0, w1, w2, a[14], b[6]);+ MONT_MAC(t0, t1, t2, a[15], b[5]);+ MONT_MAC(v0, v1, v2, a[16], b[4]);+ MONT_MAC(w0, w1, w2, a[17], b[3]);+ MONT_MAC(t0, t1, t2, a[18], b[2]);+ MONT_MAC(v0, v1, v2, a[19], b[1]);+ MONT_MAC(w0, w1, w2, a[20], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[20]);+ MONT_MAC(v0, v1, v2, u[1], m[19]);+ MONT_MAC(w0, w1, w2, u[2], m[18]);+ MONT_MAC(t0, t1, t2, u[3], m[17]);+ MONT_MAC(v0, v1, v2, u[4], m[16]);+ MONT_MAC(w0, w1, w2, u[5], m[15]);+ MONT_MAC(t0, t1, t2, u[6], m[14]);+ MONT_MAC(v0, v1, v2, u[7], m[13]);+ MONT_MAC(w0, w1, w2, u[8], m[12]);+ MONT_MAC(t0, t1, t2, u[9], m[11]);+ MONT_MAC(v0, v1, v2, u[10], m[10]);+ MONT_MAC(w0, w1, w2, u[11], m[9]);+ MONT_MAC(t0, t1, t2, u[12], m[8]);+ MONT_MAC(v0, v1, v2, u[13], m[7]);+ MONT_MAC(w0, w1, w2, u[14], m[6]);+ MONT_MAC(t0, t1, t2, u[15], m[5]);+ MONT_MAC(v0, v1, v2, u[16], m[4]);+ MONT_MAC(w0, w1, w2, u[17], m[3]);+ MONT_MAC(t0, t1, t2, u[18], m[2]);+ MONT_MAC(v0, v1, v2, u[19], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[20] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[20], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 21 */+ MONT_MAC(t0, t1, t2, a[0], b[21]);+ MONT_MUL(v0, v1, v2, a[1], b[20]);+ MONT_MUL(w0, w1, w2, a[2], b[19]);+ MONT_MAC(t0, t1, t2, a[3], b[18]);+ MONT_MAC(v0, v1, v2, a[4], b[17]);+ MONT_MAC(w0, w1, w2, a[5], b[16]);+ MONT_MAC(t0, t1, t2, a[6], b[15]);+ MONT_MAC(v0, v1, v2, a[7], b[14]);+ MONT_MAC(w0, w1, w2, a[8], b[13]);+ MONT_MAC(t0, t1, t2, a[9], b[12]);+ MONT_MAC(v0, v1, v2, a[10], b[11]);+ MONT_MAC(w0, w1, w2, a[11], b[10]);+ MONT_MAC(t0, t1, t2, a[12], b[9]);+ MONT_MAC(v0, v1, v2, a[13], b[8]);+ MONT_MAC(w0, w1, w2, a[14], b[7]);+ MONT_MAC(t0, t1, t2, a[15], b[6]);+ MONT_MAC(v0, v1, v2, a[16], b[5]);+ MONT_MAC(w0, w1, w2, a[17], b[4]);+ MONT_MAC(t0, t1, t2, a[18], b[3]);+ MONT_MAC(v0, v1, v2, a[19], b[2]);+ MONT_MAC(w0, w1, w2, a[20], b[1]);+ MONT_MAC(t0, t1, t2, a[21], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[21]);+ MONT_MAC(w0, w1, w2, u[1], m[20]);+ MONT_MAC(t0, t1, t2, u[2], m[19]);+ MONT_MAC(v0, v1, v2, u[3], m[18]);+ MONT_MAC(w0, w1, w2, u[4], m[17]);+ MONT_MAC(t0, t1, t2, u[5], m[16]);+ MONT_MAC(v0, v1, v2, u[6], m[15]);+ MONT_MAC(w0, w1, w2, u[7], m[14]);+ MONT_MAC(t0, t1, t2, u[8], m[13]);+ MONT_MAC(v0, v1, v2, u[9], m[12]);+ MONT_MAC(w0, w1, w2, u[10], m[11]);+ MONT_MAC(t0, t1, t2, u[11], m[10]);+ MONT_MAC(v0, v1, v2, u[12], m[9]);+ MONT_MAC(w0, w1, w2, u[13], m[8]);+ MONT_MAC(t0, t1, t2, u[14], m[7]);+ MONT_MAC(v0, v1, v2, u[15], m[6]);+ MONT_MAC(w0, w1, w2, u[16], m[5]);+ MONT_MAC(t0, t1, t2, u[17], m[4]);+ MONT_MAC(v0, v1, v2, u[18], m[3]);+ MONT_MAC(w0, w1, w2, u[19], m[2]);+ MONT_MAC(t0, t1, t2, u[20], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[21] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[21], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 22 */+ MONT_MAC(t0, t1, t2, a[0], b[22]);+ MONT_MUL(v0, v1, v2, a[1], b[21]);+ MONT_MUL(w0, w1, w2, a[2], b[20]);+ MONT_MAC(t0, t1, t2, a[3], b[19]);+ MONT_MAC(v0, v1, v2, a[4], b[18]);+ MONT_MAC(w0, w1, w2, a[5], b[17]);+ MONT_MAC(t0, t1, t2, a[6], b[16]);+ MONT_MAC(v0, v1, v2, a[7], b[15]);+ MONT_MAC(w0, w1, w2, a[8], b[14]);+ MONT_MAC(t0, t1, t2, a[9], b[13]);+ MONT_MAC(v0, v1, v2, a[10], b[12]);+ MONT_MAC(w0, w1, w2, a[11], b[11]);+ MONT_MAC(t0, t1, t2, a[12], b[10]);+ MONT_MAC(v0, v1, v2, a[13], b[9]);+ MONT_MAC(w0, w1, w2, a[14], b[8]);+ MONT_MAC(t0, t1, t2, a[15], b[7]);+ MONT_MAC(v0, v1, v2, a[16], b[6]);+ MONT_MAC(w0, w1, w2, a[17], b[5]);+ MONT_MAC(t0, t1, t2, a[18], b[4]);+ MONT_MAC(v0, v1, v2, a[19], b[3]);+ MONT_MAC(w0, w1, w2, a[20], b[2]);+ MONT_MAC(t0, t1, t2, a[21], b[1]);+ MONT_MAC(v0, v1, v2, a[22], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[22]);+ MONT_MAC(t0, t1, t2, u[1], m[21]);+ MONT_MAC(v0, v1, v2, u[2], m[20]);+ MONT_MAC(w0, w1, w2, u[3], m[19]);+ MONT_MAC(t0, t1, t2, u[4], m[18]);+ MONT_MAC(v0, v1, v2, u[5], m[17]);+ MONT_MAC(w0, w1, w2, u[6], m[16]);+ MONT_MAC(t0, t1, t2, u[7], m[15]);+ MONT_MAC(v0, v1, v2, u[8], m[14]);+ MONT_MAC(w0, w1, w2, u[9], m[13]);+ MONT_MAC(t0, t1, t2, u[10], m[12]);+ MONT_MAC(v0, v1, v2, u[11], m[11]);+ MONT_MAC(w0, w1, w2, u[12], m[10]);+ MONT_MAC(t0, t1, t2, u[13], m[9]);+ MONT_MAC(v0, v1, v2, u[14], m[8]);+ MONT_MAC(w0, w1, w2, u[15], m[7]);+ MONT_MAC(t0, t1, t2, u[16], m[6]);+ MONT_MAC(v0, v1, v2, u[17], m[5]);+ MONT_MAC(w0, w1, w2, u[18], m[4]);+ MONT_MAC(t0, t1, t2, u[19], m[3]);+ MONT_MAC(v0, v1, v2, u[20], m[2]);+ MONT_MAC(w0, w1, w2, u[21], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[22] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[22], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 23 */+ MONT_MAC(t0, t1, t2, a[0], b[23]);+ MONT_MUL(v0, v1, v2, a[1], b[22]);+ MONT_MUL(w0, w1, w2, a[2], b[21]);+ MONT_MAC(t0, t1, t2, a[3], b[20]);+ MONT_MAC(v0, v1, v2, a[4], b[19]);+ MONT_MAC(w0, w1, w2, a[5], b[18]);+ MONT_MAC(t0, t1, t2, a[6], b[17]);+ MONT_MAC(v0, v1, v2, a[7], b[16]);+ MONT_MAC(w0, w1, w2, a[8], b[15]);+ MONT_MAC(t0, t1, t2, a[9], b[14]);+ MONT_MAC(v0, v1, v2, a[10], b[13]);+ MONT_MAC(w0, w1, w2, a[11], b[12]);+ MONT_MAC(t0, t1, t2, a[12], b[11]);+ MONT_MAC(v0, v1, v2, a[13], b[10]);+ MONT_MAC(w0, w1, w2, a[14], b[9]);+ MONT_MAC(t0, t1, t2, a[15], b[8]);+ MONT_MAC(v0, v1, v2, a[16], b[7]);+ MONT_MAC(w0, w1, w2, a[17], b[6]);+ MONT_MAC(t0, t1, t2, a[18], b[5]);+ MONT_MAC(v0, v1, v2, a[19], b[4]);+ MONT_MAC(w0, w1, w2, a[20], b[3]);+ MONT_MAC(t0, t1, t2, a[21], b[2]);+ MONT_MAC(v0, v1, v2, a[22], b[1]);+ MONT_MAC(w0, w1, w2, a[23], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[23]);+ MONT_MAC(v0, v1, v2, u[1], m[22]);+ MONT_MAC(w0, w1, w2, u[2], m[21]);+ MONT_MAC(t0, t1, t2, u[3], m[20]);+ MONT_MAC(v0, v1, v2, u[4], m[19]);+ MONT_MAC(w0, w1, w2, u[5], m[18]);+ MONT_MAC(t0, t1, t2, u[6], m[17]);+ MONT_MAC(v0, v1, v2, u[7], m[16]);+ MONT_MAC(w0, w1, w2, u[8], m[15]);+ MONT_MAC(t0, t1, t2, u[9], m[14]);+ MONT_MAC(v0, v1, v2, u[10], m[13]);+ MONT_MAC(w0, w1, w2, u[11], m[12]);+ MONT_MAC(t0, t1, t2, u[12], m[11]);+ MONT_MAC(v0, v1, v2, u[13], m[10]);+ MONT_MAC(w0, w1, w2, u[14], m[9]);+ MONT_MAC(t0, t1, t2, u[15], m[8]);+ MONT_MAC(v0, v1, v2, u[16], m[7]);+ MONT_MAC(w0, w1, w2, u[17], m[6]);+ MONT_MAC(t0, t1, t2, u[18], m[5]);+ MONT_MAC(v0, v1, v2, u[19], m[4]);+ MONT_MAC(w0, w1, w2, u[20], m[3]);+ MONT_MAC(t0, t1, t2, u[21], m[2]);+ MONT_MAC(v0, v1, v2, u[22], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[23] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[23], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 24 */+ MONT_MAC(t0, t1, t2, a[0], b[24]);+ MONT_MUL(v0, v1, v2, a[1], b[23]);+ MONT_MUL(w0, w1, w2, a[2], b[22]);+ MONT_MAC(t0, t1, t2, a[3], b[21]);+ MONT_MAC(v0, v1, v2, a[4], b[20]);+ MONT_MAC(w0, w1, w2, a[5], b[19]);+ MONT_MAC(t0, t1, t2, a[6], b[18]);+ MONT_MAC(v0, v1, v2, a[7], b[17]);+ MONT_MAC(w0, w1, w2, a[8], b[16]);+ MONT_MAC(t0, t1, t2, a[9], b[15]);+ MONT_MAC(v0, v1, v2, a[10], b[14]);+ MONT_MAC(w0, w1, w2, a[11], b[13]);+ MONT_MAC(t0, t1, t2, a[12], b[12]);+ MONT_MAC(v0, v1, v2, a[13], b[11]);+ MONT_MAC(w0, w1, w2, a[14], b[10]);+ MONT_MAC(t0, t1, t2, a[15], b[9]);+ MONT_MAC(v0, v1, v2, a[16], b[8]);+ MONT_MAC(w0, w1, w2, a[17], b[7]);+ MONT_MAC(t0, t1, t2, a[18], b[6]);+ MONT_MAC(v0, v1, v2, a[19], b[5]);+ MONT_MAC(w0, w1, w2, a[20], b[4]);+ MONT_MAC(t0, t1, t2, a[21], b[3]);+ MONT_MAC(v0, v1, v2, a[22], b[2]);+ MONT_MAC(w0, w1, w2, a[23], b[1]);+ MONT_MAC(t0, t1, t2, a[24], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[24]);+ MONT_MAC(w0, w1, w2, u[1], m[23]);+ MONT_MAC(t0, t1, t2, u[2], m[22]);+ MONT_MAC(v0, v1, v2, u[3], m[21]);+ MONT_MAC(w0, w1, w2, u[4], m[20]);+ MONT_MAC(t0, t1, t2, u[5], m[19]);+ MONT_MAC(v0, v1, v2, u[6], m[18]);+ MONT_MAC(w0, w1, w2, u[7], m[17]);+ MONT_MAC(t0, t1, t2, u[8], m[16]);+ MONT_MAC(v0, v1, v2, u[9], m[15]);+ MONT_MAC(w0, w1, w2, u[10], m[14]);+ MONT_MAC(t0, t1, t2, u[11], m[13]);+ MONT_MAC(v0, v1, v2, u[12], m[12]);+ MONT_MAC(w0, w1, w2, u[13], m[11]);+ MONT_MAC(t0, t1, t2, u[14], m[10]);+ MONT_MAC(v0, v1, v2, u[15], m[9]);+ MONT_MAC(w0, w1, w2, u[16], m[8]);+ MONT_MAC(t0, t1, t2, u[17], m[7]);+ MONT_MAC(v0, v1, v2, u[18], m[6]);+ MONT_MAC(w0, w1, w2, u[19], m[5]);+ MONT_MAC(t0, t1, t2, u[20], m[4]);+ MONT_MAC(v0, v1, v2, u[21], m[3]);+ MONT_MAC(w0, w1, w2, u[22], m[2]);+ MONT_MAC(t0, t1, t2, u[23], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[24] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[24], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 25 */+ MONT_MAC(t0, t1, t2, a[0], b[25]);+ MONT_MUL(v0, v1, v2, a[1], b[24]);+ MONT_MUL(w0, w1, w2, a[2], b[23]);+ MONT_MAC(t0, t1, t2, a[3], b[22]);+ MONT_MAC(v0, v1, v2, a[4], b[21]);+ MONT_MAC(w0, w1, w2, a[5], b[20]);+ MONT_MAC(t0, t1, t2, a[6], b[19]);+ MONT_MAC(v0, v1, v2, a[7], b[18]);+ MONT_MAC(w0, w1, w2, a[8], b[17]);+ MONT_MAC(t0, t1, t2, a[9], b[16]);+ MONT_MAC(v0, v1, v2, a[10], b[15]);+ MONT_MAC(w0, w1, w2, a[11], b[14]);+ MONT_MAC(t0, t1, t2, a[12], b[13]);+ MONT_MAC(v0, v1, v2, a[13], b[12]);+ MONT_MAC(w0, w1, w2, a[14], b[11]);+ MONT_MAC(t0, t1, t2, a[15], b[10]);+ MONT_MAC(v0, v1, v2, a[16], b[9]);+ MONT_MAC(w0, w1, w2, a[17], b[8]);+ MONT_MAC(t0, t1, t2, a[18], b[7]);+ MONT_MAC(v0, v1, v2, a[19], b[6]);+ MONT_MAC(w0, w1, w2, a[20], b[5]);+ MONT_MAC(t0, t1, t2, a[21], b[4]);+ MONT_MAC(v0, v1, v2, a[22], b[3]);+ MONT_MAC(w0, w1, w2, a[23], b[2]);+ MONT_MAC(t0, t1, t2, a[24], b[1]);+ MONT_MAC(v0, v1, v2, a[25], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[25]);+ MONT_MAC(t0, t1, t2, u[1], m[24]);+ MONT_MAC(v0, v1, v2, u[2], m[23]);+ MONT_MAC(w0, w1, w2, u[3], m[22]);+ MONT_MAC(t0, t1, t2, u[4], m[21]);+ MONT_MAC(v0, v1, v2, u[5], m[20]);+ MONT_MAC(w0, w1, w2, u[6], m[19]);+ MONT_MAC(t0, t1, t2, u[7], m[18]);+ MONT_MAC(v0, v1, v2, u[8], m[17]);+ MONT_MAC(w0, w1, w2, u[9], m[16]);+ MONT_MAC(t0, t1, t2, u[10], m[15]);+ MONT_MAC(v0, v1, v2, u[11], m[14]);+ MONT_MAC(w0, w1, w2, u[12], m[13]);+ MONT_MAC(t0, t1, t2, u[13], m[12]);+ MONT_MAC(v0, v1, v2, u[14], m[11]);+ MONT_MAC(w0, w1, w2, u[15], m[10]);+ MONT_MAC(t0, t1, t2, u[16], m[9]);+ MONT_MAC(v0, v1, v2, u[17], m[8]);+ MONT_MAC(w0, w1, w2, u[18], m[7]);+ MONT_MAC(t0, t1, t2, u[19], m[6]);+ MONT_MAC(v0, v1, v2, u[20], m[5]);+ MONT_MAC(w0, w1, w2, u[21], m[4]);+ MONT_MAC(t0, t1, t2, u[22], m[3]);+ MONT_MAC(v0, v1, v2, u[23], m[2]);+ MONT_MAC(w0, w1, w2, u[24], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[25] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[25], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 26 */+ MONT_MAC(t0, t1, t2, a[0], b[26]);+ MONT_MUL(v0, v1, v2, a[1], b[25]);+ MONT_MUL(w0, w1, w2, a[2], b[24]);+ MONT_MAC(t0, t1, t2, a[3], b[23]);+ MONT_MAC(v0, v1, v2, a[4], b[22]);+ MONT_MAC(w0, w1, w2, a[5], b[21]);+ MONT_MAC(t0, t1, t2, a[6], b[20]);+ MONT_MAC(v0, v1, v2, a[7], b[19]);+ MONT_MAC(w0, w1, w2, a[8], b[18]);+ MONT_MAC(t0, t1, t2, a[9], b[17]);+ MONT_MAC(v0, v1, v2, a[10], b[16]);+ MONT_MAC(w0, w1, w2, a[11], b[15]);+ MONT_MAC(t0, t1, t2, a[12], b[14]);+ MONT_MAC(v0, v1, v2, a[13], b[13]);+ MONT_MAC(w0, w1, w2, a[14], b[12]);+ MONT_MAC(t0, t1, t2, a[15], b[11]);+ MONT_MAC(v0, v1, v2, a[16], b[10]);+ MONT_MAC(w0, w1, w2, a[17], b[9]);+ MONT_MAC(t0, t1, t2, a[18], b[8]);+ MONT_MAC(v0, v1, v2, a[19], b[7]);+ MONT_MAC(w0, w1, w2, a[20], b[6]);+ MONT_MAC(t0, t1, t2, a[21], b[5]);+ MONT_MAC(v0, v1, v2, a[22], b[4]);+ MONT_MAC(w0, w1, w2, a[23], b[3]);+ MONT_MAC(t0, t1, t2, a[24], b[2]);+ MONT_MAC(v0, v1, v2, a[25], b[1]);+ MONT_MAC(w0, w1, w2, a[26], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[26]);+ MONT_MAC(v0, v1, v2, u[1], m[25]);+ MONT_MAC(w0, w1, w2, u[2], m[24]);+ MONT_MAC(t0, t1, t2, u[3], m[23]);+ MONT_MAC(v0, v1, v2, u[4], m[22]);+ MONT_MAC(w0, w1, w2, u[5], m[21]);+ MONT_MAC(t0, t1, t2, u[6], m[20]);+ MONT_MAC(v0, v1, v2, u[7], m[19]);+ MONT_MAC(w0, w1, w2, u[8], m[18]);+ MONT_MAC(t0, t1, t2, u[9], m[17]);+ MONT_MAC(v0, v1, v2, u[10], m[16]);+ MONT_MAC(w0, w1, w2, u[11], m[15]);+ MONT_MAC(t0, t1, t2, u[12], m[14]);+ MONT_MAC(v0, v1, v2, u[13], m[13]);+ MONT_MAC(w0, w1, w2, u[14], m[12]);+ MONT_MAC(t0, t1, t2, u[15], m[11]);+ MONT_MAC(v0, v1, v2, u[16], m[10]);+ MONT_MAC(w0, w1, w2, u[17], m[9]);+ MONT_MAC(t0, t1, t2, u[18], m[8]);+ MONT_MAC(v0, v1, v2, u[19], m[7]);+ MONT_MAC(w0, w1, w2, u[20], m[6]);+ MONT_MAC(t0, t1, t2, u[21], m[5]);+ MONT_MAC(v0, v1, v2, u[22], m[4]);+ MONT_MAC(w0, w1, w2, u[23], m[3]);+ MONT_MAC(t0, t1, t2, u[24], m[2]);+ MONT_MAC(v0, v1, v2, u[25], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[26] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[26], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 27 */+ MONT_MAC(t0, t1, t2, a[0], b[27]);+ MONT_MUL(v0, v1, v2, a[1], b[26]);+ MONT_MUL(w0, w1, w2, a[2], b[25]);+ MONT_MAC(t0, t1, t2, a[3], b[24]);+ MONT_MAC(v0, v1, v2, a[4], b[23]);+ MONT_MAC(w0, w1, w2, a[5], b[22]);+ MONT_MAC(t0, t1, t2, a[6], b[21]);+ MONT_MAC(v0, v1, v2, a[7], b[20]);+ MONT_MAC(w0, w1, w2, a[8], b[19]);+ MONT_MAC(t0, t1, t2, a[9], b[18]);+ MONT_MAC(v0, v1, v2, a[10], b[17]);+ MONT_MAC(w0, w1, w2, a[11], b[16]);+ MONT_MAC(t0, t1, t2, a[12], b[15]);+ MONT_MAC(v0, v1, v2, a[13], b[14]);+ MONT_MAC(w0, w1, w2, a[14], b[13]);+ MONT_MAC(t0, t1, t2, a[15], b[12]);+ MONT_MAC(v0, v1, v2, a[16], b[11]);+ MONT_MAC(w0, w1, w2, a[17], b[10]);+ MONT_MAC(t0, t1, t2, a[18], b[9]);+ MONT_MAC(v0, v1, v2, a[19], b[8]);+ MONT_MAC(w0, w1, w2, a[20], b[7]);+ MONT_MAC(t0, t1, t2, a[21], b[6]);+ MONT_MAC(v0, v1, v2, a[22], b[5]);+ MONT_MAC(w0, w1, w2, a[23], b[4]);+ MONT_MAC(t0, t1, t2, a[24], b[3]);+ MONT_MAC(v0, v1, v2, a[25], b[2]);+ MONT_MAC(w0, w1, w2, a[26], b[1]);+ MONT_MAC(t0, t1, t2, a[27], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[27]);+ MONT_MAC(w0, w1, w2, u[1], m[26]);+ MONT_MAC(t0, t1, t2, u[2], m[25]);+ MONT_MAC(v0, v1, v2, u[3], m[24]);+ MONT_MAC(w0, w1, w2, u[4], m[23]);+ MONT_MAC(t0, t1, t2, u[5], m[22]);+ MONT_MAC(v0, v1, v2, u[6], m[21]);+ MONT_MAC(w0, w1, w2, u[7], m[20]);+ MONT_MAC(t0, t1, t2, u[8], m[19]);+ MONT_MAC(v0, v1, v2, u[9], m[18]);+ MONT_MAC(w0, w1, w2, u[10], m[17]);+ MONT_MAC(t0, t1, t2, u[11], m[16]);+ MONT_MAC(v0, v1, v2, u[12], m[15]);+ MONT_MAC(w0, w1, w2, u[13], m[14]);+ MONT_MAC(t0, t1, t2, u[14], m[13]);+ MONT_MAC(v0, v1, v2, u[15], m[12]);+ MONT_MAC(w0, w1, w2, u[16], m[11]);+ MONT_MAC(t0, t1, t2, u[17], m[10]);+ MONT_MAC(v0, v1, v2, u[18], m[9]);+ MONT_MAC(w0, w1, w2, u[19], m[8]);+ MONT_MAC(t0, t1, t2, u[20], m[7]);+ MONT_MAC(v0, v1, v2, u[21], m[6]);+ MONT_MAC(w0, w1, w2, u[22], m[5]);+ MONT_MAC(t0, t1, t2, u[23], m[4]);+ MONT_MAC(v0, v1, v2, u[24], m[3]);+ MONT_MAC(w0, w1, w2, u[25], m[2]);+ MONT_MAC(t0, t1, t2, u[26], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[27] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[27], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 28 */+ MONT_MAC(t0, t1, t2, a[0], b[28]);+ MONT_MUL(v0, v1, v2, a[1], b[27]);+ MONT_MUL(w0, w1, w2, a[2], b[26]);+ MONT_MAC(t0, t1, t2, a[3], b[25]);+ MONT_MAC(v0, v1, v2, a[4], b[24]);+ MONT_MAC(w0, w1, w2, a[5], b[23]);+ MONT_MAC(t0, t1, t2, a[6], b[22]);+ MONT_MAC(v0, v1, v2, a[7], b[21]);+ MONT_MAC(w0, w1, w2, a[8], b[20]);+ MONT_MAC(t0, t1, t2, a[9], b[19]);+ MONT_MAC(v0, v1, v2, a[10], b[18]);+ MONT_MAC(w0, w1, w2, a[11], b[17]);+ MONT_MAC(t0, t1, t2, a[12], b[16]);+ MONT_MAC(v0, v1, v2, a[13], b[15]);+ MONT_MAC(w0, w1, w2, a[14], b[14]);+ MONT_MAC(t0, t1, t2, a[15], b[13]);+ MONT_MAC(v0, v1, v2, a[16], b[12]);+ MONT_MAC(w0, w1, w2, a[17], b[11]);+ MONT_MAC(t0, t1, t2, a[18], b[10]);+ MONT_MAC(v0, v1, v2, a[19], b[9]);+ MONT_MAC(w0, w1, w2, a[20], b[8]);+ MONT_MAC(t0, t1, t2, a[21], b[7]);+ MONT_MAC(v0, v1, v2, a[22], b[6]);+ MONT_MAC(w0, w1, w2, a[23], b[5]);+ MONT_MAC(t0, t1, t2, a[24], b[4]);+ MONT_MAC(v0, v1, v2, a[25], b[3]);+ MONT_MAC(w0, w1, w2, a[26], b[2]);+ MONT_MAC(t0, t1, t2, a[27], b[1]);+ MONT_MAC(v0, v1, v2, a[28], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[28]);+ MONT_MAC(t0, t1, t2, u[1], m[27]);+ MONT_MAC(v0, v1, v2, u[2], m[26]);+ MONT_MAC(w0, w1, w2, u[3], m[25]);+ MONT_MAC(t0, t1, t2, u[4], m[24]);+ MONT_MAC(v0, v1, v2, u[5], m[23]);+ MONT_MAC(w0, w1, w2, u[6], m[22]);+ MONT_MAC(t0, t1, t2, u[7], m[21]);+ MONT_MAC(v0, v1, v2, u[8], m[20]);+ MONT_MAC(w0, w1, w2, u[9], m[19]);+ MONT_MAC(t0, t1, t2, u[10], m[18]);+ MONT_MAC(v0, v1, v2, u[11], m[17]);+ MONT_MAC(w0, w1, w2, u[12], m[16]);+ MONT_MAC(t0, t1, t2, u[13], m[15]);+ MONT_MAC(v0, v1, v2, u[14], m[14]);+ MONT_MAC(w0, w1, w2, u[15], m[13]);+ MONT_MAC(t0, t1, t2, u[16], m[12]);+ MONT_MAC(v0, v1, v2, u[17], m[11]);+ MONT_MAC(w0, w1, w2, u[18], m[10]);+ MONT_MAC(t0, t1, t2, u[19], m[9]);+ MONT_MAC(v0, v1, v2, u[20], m[8]);+ MONT_MAC(w0, w1, w2, u[21], m[7]);+ MONT_MAC(t0, t1, t2, u[22], m[6]);+ MONT_MAC(v0, v1, v2, u[23], m[5]);+ MONT_MAC(w0, w1, w2, u[24], m[4]);+ MONT_MAC(t0, t1, t2, u[25], m[3]);+ MONT_MAC(v0, v1, v2, u[26], m[2]);+ MONT_MAC(w0, w1, w2, u[27], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[28] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[28], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 29 */+ MONT_MAC(t0, t1, t2, a[0], b[29]);+ MONT_MUL(v0, v1, v2, a[1], b[28]);+ MONT_MUL(w0, w1, w2, a[2], b[27]);+ MONT_MAC(t0, t1, t2, a[3], b[26]);+ MONT_MAC(v0, v1, v2, a[4], b[25]);+ MONT_MAC(w0, w1, w2, a[5], b[24]);+ MONT_MAC(t0, t1, t2, a[6], b[23]);+ MONT_MAC(v0, v1, v2, a[7], b[22]);+ MONT_MAC(w0, w1, w2, a[8], b[21]);+ MONT_MAC(t0, t1, t2, a[9], b[20]);+ MONT_MAC(v0, v1, v2, a[10], b[19]);+ MONT_MAC(w0, w1, w2, a[11], b[18]);+ MONT_MAC(t0, t1, t2, a[12], b[17]);+ MONT_MAC(v0, v1, v2, a[13], b[16]);+ MONT_MAC(w0, w1, w2, a[14], b[15]);+ MONT_MAC(t0, t1, t2, a[15], b[14]);+ MONT_MAC(v0, v1, v2, a[16], b[13]);+ MONT_MAC(w0, w1, w2, a[17], b[12]);+ MONT_MAC(t0, t1, t2, a[18], b[11]);+ MONT_MAC(v0, v1, v2, a[19], b[10]);+ MONT_MAC(w0, w1, w2, a[20], b[9]);+ MONT_MAC(t0, t1, t2, a[21], b[8]);+ MONT_MAC(v0, v1, v2, a[22], b[7]);+ MONT_MAC(w0, w1, w2, a[23], b[6]);+ MONT_MAC(t0, t1, t2, a[24], b[5]);+ MONT_MAC(v0, v1, v2, a[25], b[4]);+ MONT_MAC(w0, w1, w2, a[26], b[3]);+ MONT_MAC(t0, t1, t2, a[27], b[2]);+ MONT_MAC(v0, v1, v2, a[28], b[1]);+ MONT_MAC(w0, w1, w2, a[29], b[0]);+ MONT_MAC(t0, t1, t2, u[0], m[29]);+ MONT_MAC(v0, v1, v2, u[1], m[28]);+ MONT_MAC(w0, w1, w2, u[2], m[27]);+ MONT_MAC(t0, t1, t2, u[3], m[26]);+ MONT_MAC(v0, v1, v2, u[4], m[25]);+ MONT_MAC(w0, w1, w2, u[5], m[24]);+ MONT_MAC(t0, t1, t2, u[6], m[23]);+ MONT_MAC(v0, v1, v2, u[7], m[22]);+ MONT_MAC(w0, w1, w2, u[8], m[21]);+ MONT_MAC(t0, t1, t2, u[9], m[20]);+ MONT_MAC(v0, v1, v2, u[10], m[19]);+ MONT_MAC(w0, w1, w2, u[11], m[18]);+ MONT_MAC(t0, t1, t2, u[12], m[17]);+ MONT_MAC(v0, v1, v2, u[13], m[16]);+ MONT_MAC(w0, w1, w2, u[14], m[15]);+ MONT_MAC(t0, t1, t2, u[15], m[14]);+ MONT_MAC(v0, v1, v2, u[16], m[13]);+ MONT_MAC(w0, w1, w2, u[17], m[12]);+ MONT_MAC(t0, t1, t2, u[18], m[11]);+ MONT_MAC(v0, v1, v2, u[19], m[10]);+ MONT_MAC(w0, w1, w2, u[20], m[9]);+ MONT_MAC(t0, t1, t2, u[21], m[8]);+ MONT_MAC(v0, v1, v2, u[22], m[7]);+ MONT_MAC(w0, w1, w2, u[23], m[6]);+ MONT_MAC(t0, t1, t2, u[24], m[5]);+ MONT_MAC(v0, v1, v2, u[25], m[4]);+ MONT_MAC(w0, w1, w2, u[26], m[3]);+ MONT_MAC(t0, t1, t2, u[27], m[2]);+ MONT_MAC(v0, v1, v2, u[28], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[29] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[29], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 30 */+ MONT_MAC(t0, t1, t2, a[0], b[30]);+ MONT_MUL(v0, v1, v2, a[1], b[29]);+ MONT_MUL(w0, w1, w2, a[2], b[28]);+ MONT_MAC(t0, t1, t2, a[3], b[27]);+ MONT_MAC(v0, v1, v2, a[4], b[26]);+ MONT_MAC(w0, w1, w2, a[5], b[25]);+ MONT_MAC(t0, t1, t2, a[6], b[24]);+ MONT_MAC(v0, v1, v2, a[7], b[23]);+ MONT_MAC(w0, w1, w2, a[8], b[22]);+ MONT_MAC(t0, t1, t2, a[9], b[21]);+ MONT_MAC(v0, v1, v2, a[10], b[20]);+ MONT_MAC(w0, w1, w2, a[11], b[19]);+ MONT_MAC(t0, t1, t2, a[12], b[18]);+ MONT_MAC(v0, v1, v2, a[13], b[17]);+ MONT_MAC(w0, w1, w2, a[14], b[16]);+ MONT_MAC(t0, t1, t2, a[15], b[15]);+ MONT_MAC(v0, v1, v2, a[16], b[14]);+ MONT_MAC(w0, w1, w2, a[17], b[13]);+ MONT_MAC(t0, t1, t2, a[18], b[12]);+ MONT_MAC(v0, v1, v2, a[19], b[11]);+ MONT_MAC(w0, w1, w2, a[20], b[10]);+ MONT_MAC(t0, t1, t2, a[21], b[9]);+ MONT_MAC(v0, v1, v2, a[22], b[8]);+ MONT_MAC(w0, w1, w2, a[23], b[7]);+ MONT_MAC(t0, t1, t2, a[24], b[6]);+ MONT_MAC(v0, v1, v2, a[25], b[5]);+ MONT_MAC(w0, w1, w2, a[26], b[4]);+ MONT_MAC(t0, t1, t2, a[27], b[3]);+ MONT_MAC(v0, v1, v2, a[28], b[2]);+ MONT_MAC(w0, w1, w2, a[29], b[1]);+ MONT_MAC(t0, t1, t2, a[30], b[0]);+ MONT_MAC(v0, v1, v2, u[0], m[30]);+ MONT_MAC(w0, w1, w2, u[1], m[29]);+ MONT_MAC(t0, t1, t2, u[2], m[28]);+ MONT_MAC(v0, v1, v2, u[3], m[27]);+ MONT_MAC(w0, w1, w2, u[4], m[26]);+ MONT_MAC(t0, t1, t2, u[5], m[25]);+ MONT_MAC(v0, v1, v2, u[6], m[24]);+ MONT_MAC(w0, w1, w2, u[7], m[23]);+ MONT_MAC(t0, t1, t2, u[8], m[22]);+ MONT_MAC(v0, v1, v2, u[9], m[21]);+ MONT_MAC(w0, w1, w2, u[10], m[20]);+ MONT_MAC(t0, t1, t2, u[11], m[19]);+ MONT_MAC(v0, v1, v2, u[12], m[18]);+ MONT_MAC(w0, w1, w2, u[13], m[17]);+ MONT_MAC(t0, t1, t2, u[14], m[16]);+ MONT_MAC(v0, v1, v2, u[15], m[15]);+ MONT_MAC(w0, w1, w2, u[16], m[14]);+ MONT_MAC(t0, t1, t2, u[17], m[13]);+ MONT_MAC(v0, v1, v2, u[18], m[12]);+ MONT_MAC(w0, w1, w2, u[19], m[11]);+ MONT_MAC(t0, t1, t2, u[20], m[10]);+ MONT_MAC(v0, v1, v2, u[21], m[9]);+ MONT_MAC(w0, w1, w2, u[22], m[8]);+ MONT_MAC(t0, t1, t2, u[23], m[7]);+ MONT_MAC(v0, v1, v2, u[24], m[6]);+ MONT_MAC(w0, w1, w2, u[25], m[5]);+ MONT_MAC(t0, t1, t2, u[26], m[4]);+ MONT_MAC(v0, v1, v2, u[27], m[3]);+ MONT_MAC(w0, w1, w2, u[28], m[2]);+ MONT_MAC(t0, t1, t2, u[29], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[30] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[30], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 31 */+ MONT_MAC(t0, t1, t2, a[0], b[31]);+ MONT_MUL(v0, v1, v2, a[1], b[30]);+ MONT_MUL(w0, w1, w2, a[2], b[29]);+ MONT_MAC(t0, t1, t2, a[3], b[28]);+ MONT_MAC(v0, v1, v2, a[4], b[27]);+ MONT_MAC(w0, w1, w2, a[5], b[26]);+ MONT_MAC(t0, t1, t2, a[6], b[25]);+ MONT_MAC(v0, v1, v2, a[7], b[24]);+ MONT_MAC(w0, w1, w2, a[8], b[23]);+ MONT_MAC(t0, t1, t2, a[9], b[22]);+ MONT_MAC(v0, v1, v2, a[10], b[21]);+ MONT_MAC(w0, w1, w2, a[11], b[20]);+ MONT_MAC(t0, t1, t2, a[12], b[19]);+ MONT_MAC(v0, v1, v2, a[13], b[18]);+ MONT_MAC(w0, w1, w2, a[14], b[17]);+ MONT_MAC(t0, t1, t2, a[15], b[16]);+ MONT_MAC(v0, v1, v2, a[16], b[15]);+ MONT_MAC(w0, w1, w2, a[17], b[14]);+ MONT_MAC(t0, t1, t2, a[18], b[13]);+ MONT_MAC(v0, v1, v2, a[19], b[12]);+ MONT_MAC(w0, w1, w2, a[20], b[11]);+ MONT_MAC(t0, t1, t2, a[21], b[10]);+ MONT_MAC(v0, v1, v2, a[22], b[9]);+ MONT_MAC(w0, w1, w2, a[23], b[8]);+ MONT_MAC(t0, t1, t2, a[24], b[7]);+ MONT_MAC(v0, v1, v2, a[25], b[6]);+ MONT_MAC(w0, w1, w2, a[26], b[5]);+ MONT_MAC(t0, t1, t2, a[27], b[4]);+ MONT_MAC(v0, v1, v2, a[28], b[3]);+ MONT_MAC(w0, w1, w2, a[29], b[2]);+ MONT_MAC(t0, t1, t2, a[30], b[1]);+ MONT_MAC(v0, v1, v2, a[31], b[0]);+ MONT_MAC(w0, w1, w2, u[0], m[31]);+ MONT_MAC(t0, t1, t2, u[1], m[30]);+ MONT_MAC(v0, v1, v2, u[2], m[29]);+ MONT_MAC(w0, w1, w2, u[3], m[28]);+ MONT_MAC(t0, t1, t2, u[4], m[27]);+ MONT_MAC(v0, v1, v2, u[5], m[26]);+ MONT_MAC(w0, w1, w2, u[6], m[25]);+ MONT_MAC(t0, t1, t2, u[7], m[24]);+ MONT_MAC(v0, v1, v2, u[8], m[23]);+ MONT_MAC(w0, w1, w2, u[9], m[22]);+ MONT_MAC(t0, t1, t2, u[10], m[21]);+ MONT_MAC(v0, v1, v2, u[11], m[20]);+ MONT_MAC(w0, w1, w2, u[12], m[19]);+ MONT_MAC(t0, t1, t2, u[13], m[18]);+ MONT_MAC(v0, v1, v2, u[14], m[17]);+ MONT_MAC(w0, w1, w2, u[15], m[16]);+ MONT_MAC(t0, t1, t2, u[16], m[15]);+ MONT_MAC(v0, v1, v2, u[17], m[14]);+ MONT_MAC(w0, w1, w2, u[18], m[13]);+ MONT_MAC(t0, t1, t2, u[19], m[12]);+ MONT_MAC(v0, v1, v2, u[20], m[11]);+ MONT_MAC(w0, w1, w2, u[21], m[10]);+ MONT_MAC(t0, t1, t2, u[22], m[9]);+ MONT_MAC(v0, v1, v2, u[23], m[8]);+ MONT_MAC(w0, w1, w2, u[24], m[7]);+ MONT_MAC(t0, t1, t2, u[25], m[6]);+ MONT_MAC(v0, v1, v2, u[26], m[5]);+ MONT_MAC(w0, w1, w2, u[27], m[4]);+ MONT_MAC(t0, t1, t2, u[28], m[3]);+ MONT_MAC(v0, v1, v2, u[29], m[2]);+ MONT_MAC(w0, w1, w2, u[30], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ u[31] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[31], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 32 */+ MONT_MAC(t0, t1, t2, a[1], b[31]);+ MONT_MUL(v0, v1, v2, a[2], b[30]);+ MONT_MUL(w0, w1, w2, a[3], b[29]);+ MONT_MAC(t0, t1, t2, a[4], b[28]);+ MONT_MAC(v0, v1, v2, a[5], b[27]);+ MONT_MAC(w0, w1, w2, a[6], b[26]);+ MONT_MAC(t0, t1, t2, a[7], b[25]);+ MONT_MAC(v0, v1, v2, a[8], b[24]);+ MONT_MAC(w0, w1, w2, a[9], b[23]);+ MONT_MAC(t0, t1, t2, a[10], b[22]);+ MONT_MAC(v0, v1, v2, a[11], b[21]);+ MONT_MAC(w0, w1, w2, a[12], b[20]);+ MONT_MAC(t0, t1, t2, a[13], b[19]);+ MONT_MAC(v0, v1, v2, a[14], b[18]);+ MONT_MAC(w0, w1, w2, a[15], b[17]);+ MONT_MAC(t0, t1, t2, a[16], b[16]);+ MONT_MAC(v0, v1, v2, a[17], b[15]);+ MONT_MAC(w0, w1, w2, a[18], b[14]);+ MONT_MAC(t0, t1, t2, a[19], b[13]);+ MONT_MAC(v0, v1, v2, a[20], b[12]);+ MONT_MAC(w0, w1, w2, a[21], b[11]);+ MONT_MAC(t0, t1, t2, a[22], b[10]);+ MONT_MAC(v0, v1, v2, a[23], b[9]);+ MONT_MAC(w0, w1, w2, a[24], b[8]);+ MONT_MAC(t0, t1, t2, a[25], b[7]);+ MONT_MAC(v0, v1, v2, a[26], b[6]);+ MONT_MAC(w0, w1, w2, a[27], b[5]);+ MONT_MAC(t0, t1, t2, a[28], b[4]);+ MONT_MAC(v0, v1, v2, a[29], b[3]);+ MONT_MAC(w0, w1, w2, a[30], b[2]);+ MONT_MAC(t0, t1, t2, a[31], b[1]);+ MONT_MAC(v0, v1, v2, u[1], m[31]);+ MONT_MAC(w0, w1, w2, u[2], m[30]);+ MONT_MAC(t0, t1, t2, u[3], m[29]);+ MONT_MAC(v0, v1, v2, u[4], m[28]);+ MONT_MAC(w0, w1, w2, u[5], m[27]);+ MONT_MAC(t0, t1, t2, u[6], m[26]);+ MONT_MAC(v0, v1, v2, u[7], m[25]);+ MONT_MAC(w0, w1, w2, u[8], m[24]);+ MONT_MAC(t0, t1, t2, u[9], m[23]);+ MONT_MAC(v0, v1, v2, u[10], m[22]);+ MONT_MAC(w0, w1, w2, u[11], m[21]);+ MONT_MAC(t0, t1, t2, u[12], m[20]);+ MONT_MAC(v0, v1, v2, u[13], m[19]);+ MONT_MAC(w0, w1, w2, u[14], m[18]);+ MONT_MAC(t0, t1, t2, u[15], m[17]);+ MONT_MAC(v0, v1, v2, u[16], m[16]);+ MONT_MAC(w0, w1, w2, u[17], m[15]);+ MONT_MAC(t0, t1, t2, u[18], m[14]);+ MONT_MAC(v0, v1, v2, u[19], m[13]);+ MONT_MAC(w0, w1, w2, u[20], m[12]);+ MONT_MAC(t0, t1, t2, u[21], m[11]);+ MONT_MAC(v0, v1, v2, u[22], m[10]);+ MONT_MAC(w0, w1, w2, u[23], m[9]);+ MONT_MAC(t0, t1, t2, u[24], m[8]);+ MONT_MAC(v0, v1, v2, u[25], m[7]);+ MONT_MAC(w0, w1, w2, u[26], m[6]);+ MONT_MAC(t0, t1, t2, u[27], m[5]);+ MONT_MAC(v0, v1, v2, u[28], m[4]);+ MONT_MAC(w0, w1, w2, u[29], m[3]);+ MONT_MAC(t0, t1, t2, u[30], m[2]);+ MONT_MAC(v0, v1, v2, u[31], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[0] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 33 */+ MONT_MAC(t0, t1, t2, a[2], b[31]);+ MONT_MUL(v0, v1, v2, a[3], b[30]);+ MONT_MUL(w0, w1, w2, a[4], b[29]);+ MONT_MAC(t0, t1, t2, a[5], b[28]);+ MONT_MAC(v0, v1, v2, a[6], b[27]);+ MONT_MAC(w0, w1, w2, a[7], b[26]);+ MONT_MAC(t0, t1, t2, a[8], b[25]);+ MONT_MAC(v0, v1, v2, a[9], b[24]);+ MONT_MAC(w0, w1, w2, a[10], b[23]);+ MONT_MAC(t0, t1, t2, a[11], b[22]);+ MONT_MAC(v0, v1, v2, a[12], b[21]);+ MONT_MAC(w0, w1, w2, a[13], b[20]);+ MONT_MAC(t0, t1, t2, a[14], b[19]);+ MONT_MAC(v0, v1, v2, a[15], b[18]);+ MONT_MAC(w0, w1, w2, a[16], b[17]);+ MONT_MAC(t0, t1, t2, a[17], b[16]);+ MONT_MAC(v0, v1, v2, a[18], b[15]);+ MONT_MAC(w0, w1, w2, a[19], b[14]);+ MONT_MAC(t0, t1, t2, a[20], b[13]);+ MONT_MAC(v0, v1, v2, a[21], b[12]);+ MONT_MAC(w0, w1, w2, a[22], b[11]);+ MONT_MAC(t0, t1, t2, a[23], b[10]);+ MONT_MAC(v0, v1, v2, a[24], b[9]);+ MONT_MAC(w0, w1, w2, a[25], b[8]);+ MONT_MAC(t0, t1, t2, a[26], b[7]);+ MONT_MAC(v0, v1, v2, a[27], b[6]);+ MONT_MAC(w0, w1, w2, a[28], b[5]);+ MONT_MAC(t0, t1, t2, a[29], b[4]);+ MONT_MAC(v0, v1, v2, a[30], b[3]);+ MONT_MAC(w0, w1, w2, a[31], b[2]);+ MONT_MAC(t0, t1, t2, u[2], m[31]);+ MONT_MAC(v0, v1, v2, u[3], m[30]);+ MONT_MAC(w0, w1, w2, u[4], m[29]);+ MONT_MAC(t0, t1, t2, u[5], m[28]);+ MONT_MAC(v0, v1, v2, u[6], m[27]);+ MONT_MAC(w0, w1, w2, u[7], m[26]);+ MONT_MAC(t0, t1, t2, u[8], m[25]);+ MONT_MAC(v0, v1, v2, u[9], m[24]);+ MONT_MAC(w0, w1, w2, u[10], m[23]);+ MONT_MAC(t0, t1, t2, u[11], m[22]);+ MONT_MAC(v0, v1, v2, u[12], m[21]);+ MONT_MAC(w0, w1, w2, u[13], m[20]);+ MONT_MAC(t0, t1, t2, u[14], m[19]);+ MONT_MAC(v0, v1, v2, u[15], m[18]);+ MONT_MAC(w0, w1, w2, u[16], m[17]);+ MONT_MAC(t0, t1, t2, u[17], m[16]);+ MONT_MAC(v0, v1, v2, u[18], m[15]);+ MONT_MAC(w0, w1, w2, u[19], m[14]);+ MONT_MAC(t0, t1, t2, u[20], m[13]);+ MONT_MAC(v0, v1, v2, u[21], m[12]);+ MONT_MAC(w0, w1, w2, u[22], m[11]);+ MONT_MAC(t0, t1, t2, u[23], m[10]);+ MONT_MAC(v0, v1, v2, u[24], m[9]);+ MONT_MAC(w0, w1, w2, u[25], m[8]);+ MONT_MAC(t0, t1, t2, u[26], m[7]);+ MONT_MAC(v0, v1, v2, u[27], m[6]);+ MONT_MAC(w0, w1, w2, u[28], m[5]);+ MONT_MAC(t0, t1, t2, u[29], m[4]);+ MONT_MAC(v0, v1, v2, u[30], m[3]);+ MONT_MAC(w0, w1, w2, u[31], m[2]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[1] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 34 */+ MONT_MAC(t0, t1, t2, a[3], b[31]);+ MONT_MUL(v0, v1, v2, a[4], b[30]);+ MONT_MUL(w0, w1, w2, a[5], b[29]);+ MONT_MAC(t0, t1, t2, a[6], b[28]);+ MONT_MAC(v0, v1, v2, a[7], b[27]);+ MONT_MAC(w0, w1, w2, a[8], b[26]);+ MONT_MAC(t0, t1, t2, a[9], b[25]);+ MONT_MAC(v0, v1, v2, a[10], b[24]);+ MONT_MAC(w0, w1, w2, a[11], b[23]);+ MONT_MAC(t0, t1, t2, a[12], b[22]);+ MONT_MAC(v0, v1, v2, a[13], b[21]);+ MONT_MAC(w0, w1, w2, a[14], b[20]);+ MONT_MAC(t0, t1, t2, a[15], b[19]);+ MONT_MAC(v0, v1, v2, a[16], b[18]);+ MONT_MAC(w0, w1, w2, a[17], b[17]);+ MONT_MAC(t0, t1, t2, a[18], b[16]);+ MONT_MAC(v0, v1, v2, a[19], b[15]);+ MONT_MAC(w0, w1, w2, a[20], b[14]);+ MONT_MAC(t0, t1, t2, a[21], b[13]);+ MONT_MAC(v0, v1, v2, a[22], b[12]);+ MONT_MAC(w0, w1, w2, a[23], b[11]);+ MONT_MAC(t0, t1, t2, a[24], b[10]);+ MONT_MAC(v0, v1, v2, a[25], b[9]);+ MONT_MAC(w0, w1, w2, a[26], b[8]);+ MONT_MAC(t0, t1, t2, a[27], b[7]);+ MONT_MAC(v0, v1, v2, a[28], b[6]);+ MONT_MAC(w0, w1, w2, a[29], b[5]);+ MONT_MAC(t0, t1, t2, a[30], b[4]);+ MONT_MAC(v0, v1, v2, a[31], b[3]);+ MONT_MAC(w0, w1, w2, u[3], m[31]);+ MONT_MAC(t0, t1, t2, u[4], m[30]);+ MONT_MAC(v0, v1, v2, u[5], m[29]);+ MONT_MAC(w0, w1, w2, u[6], m[28]);+ MONT_MAC(t0, t1, t2, u[7], m[27]);+ MONT_MAC(v0, v1, v2, u[8], m[26]);+ MONT_MAC(w0, w1, w2, u[9], m[25]);+ MONT_MAC(t0, t1, t2, u[10], m[24]);+ MONT_MAC(v0, v1, v2, u[11], m[23]);+ MONT_MAC(w0, w1, w2, u[12], m[22]);+ MONT_MAC(t0, t1, t2, u[13], m[21]);+ MONT_MAC(v0, v1, v2, u[14], m[20]);+ MONT_MAC(w0, w1, w2, u[15], m[19]);+ MONT_MAC(t0, t1, t2, u[16], m[18]);+ MONT_MAC(v0, v1, v2, u[17], m[17]);+ MONT_MAC(w0, w1, w2, u[18], m[16]);+ MONT_MAC(t0, t1, t2, u[19], m[15]);+ MONT_MAC(v0, v1, v2, u[20], m[14]);+ MONT_MAC(w0, w1, w2, u[21], m[13]);+ MONT_MAC(t0, t1, t2, u[22], m[12]);+ MONT_MAC(v0, v1, v2, u[23], m[11]);+ MONT_MAC(w0, w1, w2, u[24], m[10]);+ MONT_MAC(t0, t1, t2, u[25], m[9]);+ MONT_MAC(v0, v1, v2, u[26], m[8]);+ MONT_MAC(w0, w1, w2, u[27], m[7]);+ MONT_MAC(t0, t1, t2, u[28], m[6]);+ MONT_MAC(v0, v1, v2, u[29], m[5]);+ MONT_MAC(w0, w1, w2, u[30], m[4]);+ MONT_MAC(t0, t1, t2, u[31], m[3]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[2] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 35 */+ MONT_MAC(t0, t1, t2, a[4], b[31]);+ MONT_MUL(v0, v1, v2, a[5], b[30]);+ MONT_MUL(w0, w1, w2, a[6], b[29]);+ MONT_MAC(t0, t1, t2, a[7], b[28]);+ MONT_MAC(v0, v1, v2, a[8], b[27]);+ MONT_MAC(w0, w1, w2, a[9], b[26]);+ MONT_MAC(t0, t1, t2, a[10], b[25]);+ MONT_MAC(v0, v1, v2, a[11], b[24]);+ MONT_MAC(w0, w1, w2, a[12], b[23]);+ MONT_MAC(t0, t1, t2, a[13], b[22]);+ MONT_MAC(v0, v1, v2, a[14], b[21]);+ MONT_MAC(w0, w1, w2, a[15], b[20]);+ MONT_MAC(t0, t1, t2, a[16], b[19]);+ MONT_MAC(v0, v1, v2, a[17], b[18]);+ MONT_MAC(w0, w1, w2, a[18], b[17]);+ MONT_MAC(t0, t1, t2, a[19], b[16]);+ MONT_MAC(v0, v1, v2, a[20], b[15]);+ MONT_MAC(w0, w1, w2, a[21], b[14]);+ MONT_MAC(t0, t1, t2, a[22], b[13]);+ MONT_MAC(v0, v1, v2, a[23], b[12]);+ MONT_MAC(w0, w1, w2, a[24], b[11]);+ MONT_MAC(t0, t1, t2, a[25], b[10]);+ MONT_MAC(v0, v1, v2, a[26], b[9]);+ MONT_MAC(w0, w1, w2, a[27], b[8]);+ MONT_MAC(t0, t1, t2, a[28], b[7]);+ MONT_MAC(v0, v1, v2, a[29], b[6]);+ MONT_MAC(w0, w1, w2, a[30], b[5]);+ MONT_MAC(t0, t1, t2, a[31], b[4]);+ MONT_MAC(v0, v1, v2, u[4], m[31]);+ MONT_MAC(w0, w1, w2, u[5], m[30]);+ MONT_MAC(t0, t1, t2, u[6], m[29]);+ MONT_MAC(v0, v1, v2, u[7], m[28]);+ MONT_MAC(w0, w1, w2, u[8], m[27]);+ MONT_MAC(t0, t1, t2, u[9], m[26]);+ MONT_MAC(v0, v1, v2, u[10], m[25]);+ MONT_MAC(w0, w1, w2, u[11], m[24]);+ MONT_MAC(t0, t1, t2, u[12], m[23]);+ MONT_MAC(v0, v1, v2, u[13], m[22]);+ MONT_MAC(w0, w1, w2, u[14], m[21]);+ MONT_MAC(t0, t1, t2, u[15], m[20]);+ MONT_MAC(v0, v1, v2, u[16], m[19]);+ MONT_MAC(w0, w1, w2, u[17], m[18]);+ MONT_MAC(t0, t1, t2, u[18], m[17]);+ MONT_MAC(v0, v1, v2, u[19], m[16]);+ MONT_MAC(w0, w1, w2, u[20], m[15]);+ MONT_MAC(t0, t1, t2, u[21], m[14]);+ MONT_MAC(v0, v1, v2, u[22], m[13]);+ MONT_MAC(w0, w1, w2, u[23], m[12]);+ MONT_MAC(t0, t1, t2, u[24], m[11]);+ MONT_MAC(v0, v1, v2, u[25], m[10]);+ MONT_MAC(w0, w1, w2, u[26], m[9]);+ MONT_MAC(t0, t1, t2, u[27], m[8]);+ MONT_MAC(v0, v1, v2, u[28], m[7]);+ MONT_MAC(w0, w1, w2, u[29], m[6]);+ MONT_MAC(t0, t1, t2, u[30], m[5]);+ MONT_MAC(v0, v1, v2, u[31], m[4]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[3] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 36 */+ MONT_MAC(t0, t1, t2, a[5], b[31]);+ MONT_MUL(v0, v1, v2, a[6], b[30]);+ MONT_MUL(w0, w1, w2, a[7], b[29]);+ MONT_MAC(t0, t1, t2, a[8], b[28]);+ MONT_MAC(v0, v1, v2, a[9], b[27]);+ MONT_MAC(w0, w1, w2, a[10], b[26]);+ MONT_MAC(t0, t1, t2, a[11], b[25]);+ MONT_MAC(v0, v1, v2, a[12], b[24]);+ MONT_MAC(w0, w1, w2, a[13], b[23]);+ MONT_MAC(t0, t1, t2, a[14], b[22]);+ MONT_MAC(v0, v1, v2, a[15], b[21]);+ MONT_MAC(w0, w1, w2, a[16], b[20]);+ MONT_MAC(t0, t1, t2, a[17], b[19]);+ MONT_MAC(v0, v1, v2, a[18], b[18]);+ MONT_MAC(w0, w1, w2, a[19], b[17]);+ MONT_MAC(t0, t1, t2, a[20], b[16]);+ MONT_MAC(v0, v1, v2, a[21], b[15]);+ MONT_MAC(w0, w1, w2, a[22], b[14]);+ MONT_MAC(t0, t1, t2, a[23], b[13]);+ MONT_MAC(v0, v1, v2, a[24], b[12]);+ MONT_MAC(w0, w1, w2, a[25], b[11]);+ MONT_MAC(t0, t1, t2, a[26], b[10]);+ MONT_MAC(v0, v1, v2, a[27], b[9]);+ MONT_MAC(w0, w1, w2, a[28], b[8]);+ MONT_MAC(t0, t1, t2, a[29], b[7]);+ MONT_MAC(v0, v1, v2, a[30], b[6]);+ MONT_MAC(w0, w1, w2, a[31], b[5]);+ MONT_MAC(t0, t1, t2, u[5], m[31]);+ MONT_MAC(v0, v1, v2, u[6], m[30]);+ MONT_MAC(w0, w1, w2, u[7], m[29]);+ MONT_MAC(t0, t1, t2, u[8], m[28]);+ MONT_MAC(v0, v1, v2, u[9], m[27]);+ MONT_MAC(w0, w1, w2, u[10], m[26]);+ MONT_MAC(t0, t1, t2, u[11], m[25]);+ MONT_MAC(v0, v1, v2, u[12], m[24]);+ MONT_MAC(w0, w1, w2, u[13], m[23]);+ MONT_MAC(t0, t1, t2, u[14], m[22]);+ MONT_MAC(v0, v1, v2, u[15], m[21]);+ MONT_MAC(w0, w1, w2, u[16], m[20]);+ MONT_MAC(t0, t1, t2, u[17], m[19]);+ MONT_MAC(v0, v1, v2, u[18], m[18]);+ MONT_MAC(w0, w1, w2, u[19], m[17]);+ MONT_MAC(t0, t1, t2, u[20], m[16]);+ MONT_MAC(v0, v1, v2, u[21], m[15]);+ MONT_MAC(w0, w1, w2, u[22], m[14]);+ MONT_MAC(t0, t1, t2, u[23], m[13]);+ MONT_MAC(v0, v1, v2, u[24], m[12]);+ MONT_MAC(w0, w1, w2, u[25], m[11]);+ MONT_MAC(t0, t1, t2, u[26], m[10]);+ MONT_MAC(v0, v1, v2, u[27], m[9]);+ MONT_MAC(w0, w1, w2, u[28], m[8]);+ MONT_MAC(t0, t1, t2, u[29], m[7]);+ MONT_MAC(v0, v1, v2, u[30], m[6]);+ MONT_MAC(w0, w1, w2, u[31], m[5]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[4] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 37 */+ MONT_MAC(t0, t1, t2, a[6], b[31]);+ MONT_MUL(v0, v1, v2, a[7], b[30]);+ MONT_MUL(w0, w1, w2, a[8], b[29]);+ MONT_MAC(t0, t1, t2, a[9], b[28]);+ MONT_MAC(v0, v1, v2, a[10], b[27]);+ MONT_MAC(w0, w1, w2, a[11], b[26]);+ MONT_MAC(t0, t1, t2, a[12], b[25]);+ MONT_MAC(v0, v1, v2, a[13], b[24]);+ MONT_MAC(w0, w1, w2, a[14], b[23]);+ MONT_MAC(t0, t1, t2, a[15], b[22]);+ MONT_MAC(v0, v1, v2, a[16], b[21]);+ MONT_MAC(w0, w1, w2, a[17], b[20]);+ MONT_MAC(t0, t1, t2, a[18], b[19]);+ MONT_MAC(v0, v1, v2, a[19], b[18]);+ MONT_MAC(w0, w1, w2, a[20], b[17]);+ MONT_MAC(t0, t1, t2, a[21], b[16]);+ MONT_MAC(v0, v1, v2, a[22], b[15]);+ MONT_MAC(w0, w1, w2, a[23], b[14]);+ MONT_MAC(t0, t1, t2, a[24], b[13]);+ MONT_MAC(v0, v1, v2, a[25], b[12]);+ MONT_MAC(w0, w1, w2, a[26], b[11]);+ MONT_MAC(t0, t1, t2, a[27], b[10]);+ MONT_MAC(v0, v1, v2, a[28], b[9]);+ MONT_MAC(w0, w1, w2, a[29], b[8]);+ MONT_MAC(t0, t1, t2, a[30], b[7]);+ MONT_MAC(v0, v1, v2, a[31], b[6]);+ MONT_MAC(w0, w1, w2, u[6], m[31]);+ MONT_MAC(t0, t1, t2, u[7], m[30]);+ MONT_MAC(v0, v1, v2, u[8], m[29]);+ MONT_MAC(w0, w1, w2, u[9], m[28]);+ MONT_MAC(t0, t1, t2, u[10], m[27]);+ MONT_MAC(v0, v1, v2, u[11], m[26]);+ MONT_MAC(w0, w1, w2, u[12], m[25]);+ MONT_MAC(t0, t1, t2, u[13], m[24]);+ MONT_MAC(v0, v1, v2, u[14], m[23]);+ MONT_MAC(w0, w1, w2, u[15], m[22]);+ MONT_MAC(t0, t1, t2, u[16], m[21]);+ MONT_MAC(v0, v1, v2, u[17], m[20]);+ MONT_MAC(w0, w1, w2, u[18], m[19]);+ MONT_MAC(t0, t1, t2, u[19], m[18]);+ MONT_MAC(v0, v1, v2, u[20], m[17]);+ MONT_MAC(w0, w1, w2, u[21], m[16]);+ MONT_MAC(t0, t1, t2, u[22], m[15]);+ MONT_MAC(v0, v1, v2, u[23], m[14]);+ MONT_MAC(w0, w1, w2, u[24], m[13]);+ MONT_MAC(t0, t1, t2, u[25], m[12]);+ MONT_MAC(v0, v1, v2, u[26], m[11]);+ MONT_MAC(w0, w1, w2, u[27], m[10]);+ MONT_MAC(t0, t1, t2, u[28], m[9]);+ MONT_MAC(v0, v1, v2, u[29], m[8]);+ MONT_MAC(w0, w1, w2, u[30], m[7]);+ MONT_MAC(t0, t1, t2, u[31], m[6]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[5] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 38 */+ MONT_MAC(t0, t1, t2, a[7], b[31]);+ MONT_MUL(v0, v1, v2, a[8], b[30]);+ MONT_MUL(w0, w1, w2, a[9], b[29]);+ MONT_MAC(t0, t1, t2, a[10], b[28]);+ MONT_MAC(v0, v1, v2, a[11], b[27]);+ MONT_MAC(w0, w1, w2, a[12], b[26]);+ MONT_MAC(t0, t1, t2, a[13], b[25]);+ MONT_MAC(v0, v1, v2, a[14], b[24]);+ MONT_MAC(w0, w1, w2, a[15], b[23]);+ MONT_MAC(t0, t1, t2, a[16], b[22]);+ MONT_MAC(v0, v1, v2, a[17], b[21]);+ MONT_MAC(w0, w1, w2, a[18], b[20]);+ MONT_MAC(t0, t1, t2, a[19], b[19]);+ MONT_MAC(v0, v1, v2, a[20], b[18]);+ MONT_MAC(w0, w1, w2, a[21], b[17]);+ MONT_MAC(t0, t1, t2, a[22], b[16]);+ MONT_MAC(v0, v1, v2, a[23], b[15]);+ MONT_MAC(w0, w1, w2, a[24], b[14]);+ MONT_MAC(t0, t1, t2, a[25], b[13]);+ MONT_MAC(v0, v1, v2, a[26], b[12]);+ MONT_MAC(w0, w1, w2, a[27], b[11]);+ MONT_MAC(t0, t1, t2, a[28], b[10]);+ MONT_MAC(v0, v1, v2, a[29], b[9]);+ MONT_MAC(w0, w1, w2, a[30], b[8]);+ MONT_MAC(t0, t1, t2, a[31], b[7]);+ MONT_MAC(v0, v1, v2, u[7], m[31]);+ MONT_MAC(w0, w1, w2, u[8], m[30]);+ MONT_MAC(t0, t1, t2, u[9], m[29]);+ MONT_MAC(v0, v1, v2, u[10], m[28]);+ MONT_MAC(w0, w1, w2, u[11], m[27]);+ MONT_MAC(t0, t1, t2, u[12], m[26]);+ MONT_MAC(v0, v1, v2, u[13], m[25]);+ MONT_MAC(w0, w1, w2, u[14], m[24]);+ MONT_MAC(t0, t1, t2, u[15], m[23]);+ MONT_MAC(v0, v1, v2, u[16], m[22]);+ MONT_MAC(w0, w1, w2, u[17], m[21]);+ MONT_MAC(t0, t1, t2, u[18], m[20]);+ MONT_MAC(v0, v1, v2, u[19], m[19]);+ MONT_MAC(w0, w1, w2, u[20], m[18]);+ MONT_MAC(t0, t1, t2, u[21], m[17]);+ MONT_MAC(v0, v1, v2, u[22], m[16]);+ MONT_MAC(w0, w1, w2, u[23], m[15]);+ MONT_MAC(t0, t1, t2, u[24], m[14]);+ MONT_MAC(v0, v1, v2, u[25], m[13]);+ MONT_MAC(w0, w1, w2, u[26], m[12]);+ MONT_MAC(t0, t1, t2, u[27], m[11]);+ MONT_MAC(v0, v1, v2, u[28], m[10]);+ MONT_MAC(w0, w1, w2, u[29], m[9]);+ MONT_MAC(t0, t1, t2, u[30], m[8]);+ MONT_MAC(v0, v1, v2, u[31], m[7]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[6] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 39 */+ MONT_MAC(t0, t1, t2, a[8], b[31]);+ MONT_MUL(v0, v1, v2, a[9], b[30]);+ MONT_MUL(w0, w1, w2, a[10], b[29]);+ MONT_MAC(t0, t1, t2, a[11], b[28]);+ MONT_MAC(v0, v1, v2, a[12], b[27]);+ MONT_MAC(w0, w1, w2, a[13], b[26]);+ MONT_MAC(t0, t1, t2, a[14], b[25]);+ MONT_MAC(v0, v1, v2, a[15], b[24]);+ MONT_MAC(w0, w1, w2, a[16], b[23]);+ MONT_MAC(t0, t1, t2, a[17], b[22]);+ MONT_MAC(v0, v1, v2, a[18], b[21]);+ MONT_MAC(w0, w1, w2, a[19], b[20]);+ MONT_MAC(t0, t1, t2, a[20], b[19]);+ MONT_MAC(v0, v1, v2, a[21], b[18]);+ MONT_MAC(w0, w1, w2, a[22], b[17]);+ MONT_MAC(t0, t1, t2, a[23], b[16]);+ MONT_MAC(v0, v1, v2, a[24], b[15]);+ MONT_MAC(w0, w1, w2, a[25], b[14]);+ MONT_MAC(t0, t1, t2, a[26], b[13]);+ MONT_MAC(v0, v1, v2, a[27], b[12]);+ MONT_MAC(w0, w1, w2, a[28], b[11]);+ MONT_MAC(t0, t1, t2, a[29], b[10]);+ MONT_MAC(v0, v1, v2, a[30], b[9]);+ MONT_MAC(w0, w1, w2, a[31], b[8]);+ MONT_MAC(t0, t1, t2, u[8], m[31]);+ MONT_MAC(v0, v1, v2, u[9], m[30]);+ MONT_MAC(w0, w1, w2, u[10], m[29]);+ MONT_MAC(t0, t1, t2, u[11], m[28]);+ MONT_MAC(v0, v1, v2, u[12], m[27]);+ MONT_MAC(w0, w1, w2, u[13], m[26]);+ MONT_MAC(t0, t1, t2, u[14], m[25]);+ MONT_MAC(v0, v1, v2, u[15], m[24]);+ MONT_MAC(w0, w1, w2, u[16], m[23]);+ MONT_MAC(t0, t1, t2, u[17], m[22]);+ MONT_MAC(v0, v1, v2, u[18], m[21]);+ MONT_MAC(w0, w1, w2, u[19], m[20]);+ MONT_MAC(t0, t1, t2, u[20], m[19]);+ MONT_MAC(v0, v1, v2, u[21], m[18]);+ MONT_MAC(w0, w1, w2, u[22], m[17]);+ MONT_MAC(t0, t1, t2, u[23], m[16]);+ MONT_MAC(v0, v1, v2, u[24], m[15]);+ MONT_MAC(w0, w1, w2, u[25], m[14]);+ MONT_MAC(t0, t1, t2, u[26], m[13]);+ MONT_MAC(v0, v1, v2, u[27], m[12]);+ MONT_MAC(w0, w1, w2, u[28], m[11]);+ MONT_MAC(t0, t1, t2, u[29], m[10]);+ MONT_MAC(v0, v1, v2, u[30], m[9]);+ MONT_MAC(w0, w1, w2, u[31], m[8]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[7] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 40 */+ MONT_MAC(t0, t1, t2, a[9], b[31]);+ MONT_MUL(v0, v1, v2, a[10], b[30]);+ MONT_MUL(w0, w1, w2, a[11], b[29]);+ MONT_MAC(t0, t1, t2, a[12], b[28]);+ MONT_MAC(v0, v1, v2, a[13], b[27]);+ MONT_MAC(w0, w1, w2, a[14], b[26]);+ MONT_MAC(t0, t1, t2, a[15], b[25]);+ MONT_MAC(v0, v1, v2, a[16], b[24]);+ MONT_MAC(w0, w1, w2, a[17], b[23]);+ MONT_MAC(t0, t1, t2, a[18], b[22]);+ MONT_MAC(v0, v1, v2, a[19], b[21]);+ MONT_MAC(w0, w1, w2, a[20], b[20]);+ MONT_MAC(t0, t1, t2, a[21], b[19]);+ MONT_MAC(v0, v1, v2, a[22], b[18]);+ MONT_MAC(w0, w1, w2, a[23], b[17]);+ MONT_MAC(t0, t1, t2, a[24], b[16]);+ MONT_MAC(v0, v1, v2, a[25], b[15]);+ MONT_MAC(w0, w1, w2, a[26], b[14]);+ MONT_MAC(t0, t1, t2, a[27], b[13]);+ MONT_MAC(v0, v1, v2, a[28], b[12]);+ MONT_MAC(w0, w1, w2, a[29], b[11]);+ MONT_MAC(t0, t1, t2, a[30], b[10]);+ MONT_MAC(v0, v1, v2, a[31], b[9]);+ MONT_MAC(w0, w1, w2, u[9], m[31]);+ MONT_MAC(t0, t1, t2, u[10], m[30]);+ MONT_MAC(v0, v1, v2, u[11], m[29]);+ MONT_MAC(w0, w1, w2, u[12], m[28]);+ MONT_MAC(t0, t1, t2, u[13], m[27]);+ MONT_MAC(v0, v1, v2, u[14], m[26]);+ MONT_MAC(w0, w1, w2, u[15], m[25]);+ MONT_MAC(t0, t1, t2, u[16], m[24]);+ MONT_MAC(v0, v1, v2, u[17], m[23]);+ MONT_MAC(w0, w1, w2, u[18], m[22]);+ MONT_MAC(t0, t1, t2, u[19], m[21]);+ MONT_MAC(v0, v1, v2, u[20], m[20]);+ MONT_MAC(w0, w1, w2, u[21], m[19]);+ MONT_MAC(t0, t1, t2, u[22], m[18]);+ MONT_MAC(v0, v1, v2, u[23], m[17]);+ MONT_MAC(w0, w1, w2, u[24], m[16]);+ MONT_MAC(t0, t1, t2, u[25], m[15]);+ MONT_MAC(v0, v1, v2, u[26], m[14]);+ MONT_MAC(w0, w1, w2, u[27], m[13]);+ MONT_MAC(t0, t1, t2, u[28], m[12]);+ MONT_MAC(v0, v1, v2, u[29], m[11]);+ MONT_MAC(w0, w1, w2, u[30], m[10]);+ MONT_MAC(t0, t1, t2, u[31], m[9]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[8] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 41 */+ MONT_MAC(t0, t1, t2, a[10], b[31]);+ MONT_MUL(v0, v1, v2, a[11], b[30]);+ MONT_MUL(w0, w1, w2, a[12], b[29]);+ MONT_MAC(t0, t1, t2, a[13], b[28]);+ MONT_MAC(v0, v1, v2, a[14], b[27]);+ MONT_MAC(w0, w1, w2, a[15], b[26]);+ MONT_MAC(t0, t1, t2, a[16], b[25]);+ MONT_MAC(v0, v1, v2, a[17], b[24]);+ MONT_MAC(w0, w1, w2, a[18], b[23]);+ MONT_MAC(t0, t1, t2, a[19], b[22]);+ MONT_MAC(v0, v1, v2, a[20], b[21]);+ MONT_MAC(w0, w1, w2, a[21], b[20]);+ MONT_MAC(t0, t1, t2, a[22], b[19]);+ MONT_MAC(v0, v1, v2, a[23], b[18]);+ MONT_MAC(w0, w1, w2, a[24], b[17]);+ MONT_MAC(t0, t1, t2, a[25], b[16]);+ MONT_MAC(v0, v1, v2, a[26], b[15]);+ MONT_MAC(w0, w1, w2, a[27], b[14]);+ MONT_MAC(t0, t1, t2, a[28], b[13]);+ MONT_MAC(v0, v1, v2, a[29], b[12]);+ MONT_MAC(w0, w1, w2, a[30], b[11]);+ MONT_MAC(t0, t1, t2, a[31], b[10]);+ MONT_MAC(v0, v1, v2, u[10], m[31]);+ MONT_MAC(w0, w1, w2, u[11], m[30]);+ MONT_MAC(t0, t1, t2, u[12], m[29]);+ MONT_MAC(v0, v1, v2, u[13], m[28]);+ MONT_MAC(w0, w1, w2, u[14], m[27]);+ MONT_MAC(t0, t1, t2, u[15], m[26]);+ MONT_MAC(v0, v1, v2, u[16], m[25]);+ MONT_MAC(w0, w1, w2, u[17], m[24]);+ MONT_MAC(t0, t1, t2, u[18], m[23]);+ MONT_MAC(v0, v1, v2, u[19], m[22]);+ MONT_MAC(w0, w1, w2, u[20], m[21]);+ MONT_MAC(t0, t1, t2, u[21], m[20]);+ MONT_MAC(v0, v1, v2, u[22], m[19]);+ MONT_MAC(w0, w1, w2, u[23], m[18]);+ MONT_MAC(t0, t1, t2, u[24], m[17]);+ MONT_MAC(v0, v1, v2, u[25], m[16]);+ MONT_MAC(w0, w1, w2, u[26], m[15]);+ MONT_MAC(t0, t1, t2, u[27], m[14]);+ MONT_MAC(v0, v1, v2, u[28], m[13]);+ MONT_MAC(w0, w1, w2, u[29], m[12]);+ MONT_MAC(t0, t1, t2, u[30], m[11]);+ MONT_MAC(v0, v1, v2, u[31], m[10]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[9] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 42 */+ MONT_MAC(t0, t1, t2, a[11], b[31]);+ MONT_MUL(v0, v1, v2, a[12], b[30]);+ MONT_MUL(w0, w1, w2, a[13], b[29]);+ MONT_MAC(t0, t1, t2, a[14], b[28]);+ MONT_MAC(v0, v1, v2, a[15], b[27]);+ MONT_MAC(w0, w1, w2, a[16], b[26]);+ MONT_MAC(t0, t1, t2, a[17], b[25]);+ MONT_MAC(v0, v1, v2, a[18], b[24]);+ MONT_MAC(w0, w1, w2, a[19], b[23]);+ MONT_MAC(t0, t1, t2, a[20], b[22]);+ MONT_MAC(v0, v1, v2, a[21], b[21]);+ MONT_MAC(w0, w1, w2, a[22], b[20]);+ MONT_MAC(t0, t1, t2, a[23], b[19]);+ MONT_MAC(v0, v1, v2, a[24], b[18]);+ MONT_MAC(w0, w1, w2, a[25], b[17]);+ MONT_MAC(t0, t1, t2, a[26], b[16]);+ MONT_MAC(v0, v1, v2, a[27], b[15]);+ MONT_MAC(w0, w1, w2, a[28], b[14]);+ MONT_MAC(t0, t1, t2, a[29], b[13]);+ MONT_MAC(v0, v1, v2, a[30], b[12]);+ MONT_MAC(w0, w1, w2, a[31], b[11]);+ MONT_MAC(t0, t1, t2, u[11], m[31]);+ MONT_MAC(v0, v1, v2, u[12], m[30]);+ MONT_MAC(w0, w1, w2, u[13], m[29]);+ MONT_MAC(t0, t1, t2, u[14], m[28]);+ MONT_MAC(v0, v1, v2, u[15], m[27]);+ MONT_MAC(w0, w1, w2, u[16], m[26]);+ MONT_MAC(t0, t1, t2, u[17], m[25]);+ MONT_MAC(v0, v1, v2, u[18], m[24]);+ MONT_MAC(w0, w1, w2, u[19], m[23]);+ MONT_MAC(t0, t1, t2, u[20], m[22]);+ MONT_MAC(v0, v1, v2, u[21], m[21]);+ MONT_MAC(w0, w1, w2, u[22], m[20]);+ MONT_MAC(t0, t1, t2, u[23], m[19]);+ MONT_MAC(v0, v1, v2, u[24], m[18]);+ MONT_MAC(w0, w1, w2, u[25], m[17]);+ MONT_MAC(t0, t1, t2, u[26], m[16]);+ MONT_MAC(v0, v1, v2, u[27], m[15]);+ MONT_MAC(w0, w1, w2, u[28], m[14]);+ MONT_MAC(t0, t1, t2, u[29], m[13]);+ MONT_MAC(v0, v1, v2, u[30], m[12]);+ MONT_MAC(w0, w1, w2, u[31], m[11]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[10] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 43 */+ MONT_MAC(t0, t1, t2, a[12], b[31]);+ MONT_MUL(v0, v1, v2, a[13], b[30]);+ MONT_MUL(w0, w1, w2, a[14], b[29]);+ MONT_MAC(t0, t1, t2, a[15], b[28]);+ MONT_MAC(v0, v1, v2, a[16], b[27]);+ MONT_MAC(w0, w1, w2, a[17], b[26]);+ MONT_MAC(t0, t1, t2, a[18], b[25]);+ MONT_MAC(v0, v1, v2, a[19], b[24]);+ MONT_MAC(w0, w1, w2, a[20], b[23]);+ MONT_MAC(t0, t1, t2, a[21], b[22]);+ MONT_MAC(v0, v1, v2, a[22], b[21]);+ MONT_MAC(w0, w1, w2, a[23], b[20]);+ MONT_MAC(t0, t1, t2, a[24], b[19]);+ MONT_MAC(v0, v1, v2, a[25], b[18]);+ MONT_MAC(w0, w1, w2, a[26], b[17]);+ MONT_MAC(t0, t1, t2, a[27], b[16]);+ MONT_MAC(v0, v1, v2, a[28], b[15]);+ MONT_MAC(w0, w1, w2, a[29], b[14]);+ MONT_MAC(t0, t1, t2, a[30], b[13]);+ MONT_MAC(v0, v1, v2, a[31], b[12]);+ MONT_MAC(w0, w1, w2, u[12], m[31]);+ MONT_MAC(t0, t1, t2, u[13], m[30]);+ MONT_MAC(v0, v1, v2, u[14], m[29]);+ MONT_MAC(w0, w1, w2, u[15], m[28]);+ MONT_MAC(t0, t1, t2, u[16], m[27]);+ MONT_MAC(v0, v1, v2, u[17], m[26]);+ MONT_MAC(w0, w1, w2, u[18], m[25]);+ MONT_MAC(t0, t1, t2, u[19], m[24]);+ MONT_MAC(v0, v1, v2, u[20], m[23]);+ MONT_MAC(w0, w1, w2, u[21], m[22]);+ MONT_MAC(t0, t1, t2, u[22], m[21]);+ MONT_MAC(v0, v1, v2, u[23], m[20]);+ MONT_MAC(w0, w1, w2, u[24], m[19]);+ MONT_MAC(t0, t1, t2, u[25], m[18]);+ MONT_MAC(v0, v1, v2, u[26], m[17]);+ MONT_MAC(w0, w1, w2, u[27], m[16]);+ MONT_MAC(t0, t1, t2, u[28], m[15]);+ MONT_MAC(v0, v1, v2, u[29], m[14]);+ MONT_MAC(w0, w1, w2, u[30], m[13]);+ MONT_MAC(t0, t1, t2, u[31], m[12]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[11] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 44 */+ MONT_MAC(t0, t1, t2, a[13], b[31]);+ MONT_MUL(v0, v1, v2, a[14], b[30]);+ MONT_MUL(w0, w1, w2, a[15], b[29]);+ MONT_MAC(t0, t1, t2, a[16], b[28]);+ MONT_MAC(v0, v1, v2, a[17], b[27]);+ MONT_MAC(w0, w1, w2, a[18], b[26]);+ MONT_MAC(t0, t1, t2, a[19], b[25]);+ MONT_MAC(v0, v1, v2, a[20], b[24]);+ MONT_MAC(w0, w1, w2, a[21], b[23]);+ MONT_MAC(t0, t1, t2, a[22], b[22]);+ MONT_MAC(v0, v1, v2, a[23], b[21]);+ MONT_MAC(w0, w1, w2, a[24], b[20]);+ MONT_MAC(t0, t1, t2, a[25], b[19]);+ MONT_MAC(v0, v1, v2, a[26], b[18]);+ MONT_MAC(w0, w1, w2, a[27], b[17]);+ MONT_MAC(t0, t1, t2, a[28], b[16]);+ MONT_MAC(v0, v1, v2, a[29], b[15]);+ MONT_MAC(w0, w1, w2, a[30], b[14]);+ MONT_MAC(t0, t1, t2, a[31], b[13]);+ MONT_MAC(v0, v1, v2, u[13], m[31]);+ MONT_MAC(w0, w1, w2, u[14], m[30]);+ MONT_MAC(t0, t1, t2, u[15], m[29]);+ MONT_MAC(v0, v1, v2, u[16], m[28]);+ MONT_MAC(w0, w1, w2, u[17], m[27]);+ MONT_MAC(t0, t1, t2, u[18], m[26]);+ MONT_MAC(v0, v1, v2, u[19], m[25]);+ MONT_MAC(w0, w1, w2, u[20], m[24]);+ MONT_MAC(t0, t1, t2, u[21], m[23]);+ MONT_MAC(v0, v1, v2, u[22], m[22]);+ MONT_MAC(w0, w1, w2, u[23], m[21]);+ MONT_MAC(t0, t1, t2, u[24], m[20]);+ MONT_MAC(v0, v1, v2, u[25], m[19]);+ MONT_MAC(w0, w1, w2, u[26], m[18]);+ MONT_MAC(t0, t1, t2, u[27], m[17]);+ MONT_MAC(v0, v1, v2, u[28], m[16]);+ MONT_MAC(w0, w1, w2, u[29], m[15]);+ MONT_MAC(t0, t1, t2, u[30], m[14]);+ MONT_MAC(v0, v1, v2, u[31], m[13]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[12] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 45 */+ MONT_MAC(t0, t1, t2, a[14], b[31]);+ MONT_MUL(v0, v1, v2, a[15], b[30]);+ MONT_MUL(w0, w1, w2, a[16], b[29]);+ MONT_MAC(t0, t1, t2, a[17], b[28]);+ MONT_MAC(v0, v1, v2, a[18], b[27]);+ MONT_MAC(w0, w1, w2, a[19], b[26]);+ MONT_MAC(t0, t1, t2, a[20], b[25]);+ MONT_MAC(v0, v1, v2, a[21], b[24]);+ MONT_MAC(w0, w1, w2, a[22], b[23]);+ MONT_MAC(t0, t1, t2, a[23], b[22]);+ MONT_MAC(v0, v1, v2, a[24], b[21]);+ MONT_MAC(w0, w1, w2, a[25], b[20]);+ MONT_MAC(t0, t1, t2, a[26], b[19]);+ MONT_MAC(v0, v1, v2, a[27], b[18]);+ MONT_MAC(w0, w1, w2, a[28], b[17]);+ MONT_MAC(t0, t1, t2, a[29], b[16]);+ MONT_MAC(v0, v1, v2, a[30], b[15]);+ MONT_MAC(w0, w1, w2, a[31], b[14]);+ MONT_MAC(t0, t1, t2, u[14], m[31]);+ MONT_MAC(v0, v1, v2, u[15], m[30]);+ MONT_MAC(w0, w1, w2, u[16], m[29]);+ MONT_MAC(t0, t1, t2, u[17], m[28]);+ MONT_MAC(v0, v1, v2, u[18], m[27]);+ MONT_MAC(w0, w1, w2, u[19], m[26]);+ MONT_MAC(t0, t1, t2, u[20], m[25]);+ MONT_MAC(v0, v1, v2, u[21], m[24]);+ MONT_MAC(w0, w1, w2, u[22], m[23]);+ MONT_MAC(t0, t1, t2, u[23], m[22]);+ MONT_MAC(v0, v1, v2, u[24], m[21]);+ MONT_MAC(w0, w1, w2, u[25], m[20]);+ MONT_MAC(t0, t1, t2, u[26], m[19]);+ MONT_MAC(v0, v1, v2, u[27], m[18]);+ MONT_MAC(w0, w1, w2, u[28], m[17]);+ MONT_MAC(t0, t1, t2, u[29], m[16]);+ MONT_MAC(v0, v1, v2, u[30], m[15]);+ MONT_MAC(w0, w1, w2, u[31], m[14]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[13] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 46 */+ MONT_MAC(t0, t1, t2, a[15], b[31]);+ MONT_MUL(v0, v1, v2, a[16], b[30]);+ MONT_MUL(w0, w1, w2, a[17], b[29]);+ MONT_MAC(t0, t1, t2, a[18], b[28]);+ MONT_MAC(v0, v1, v2, a[19], b[27]);+ MONT_MAC(w0, w1, w2, a[20], b[26]);+ MONT_MAC(t0, t1, t2, a[21], b[25]);+ MONT_MAC(v0, v1, v2, a[22], b[24]);+ MONT_MAC(w0, w1, w2, a[23], b[23]);+ MONT_MAC(t0, t1, t2, a[24], b[22]);+ MONT_MAC(v0, v1, v2, a[25], b[21]);+ MONT_MAC(w0, w1, w2, a[26], b[20]);+ MONT_MAC(t0, t1, t2, a[27], b[19]);+ MONT_MAC(v0, v1, v2, a[28], b[18]);+ MONT_MAC(w0, w1, w2, a[29], b[17]);+ MONT_MAC(t0, t1, t2, a[30], b[16]);+ MONT_MAC(v0, v1, v2, a[31], b[15]);+ MONT_MAC(w0, w1, w2, u[15], m[31]);+ MONT_MAC(t0, t1, t2, u[16], m[30]);+ MONT_MAC(v0, v1, v2, u[17], m[29]);+ MONT_MAC(w0, w1, w2, u[18], m[28]);+ MONT_MAC(t0, t1, t2, u[19], m[27]);+ MONT_MAC(v0, v1, v2, u[20], m[26]);+ MONT_MAC(w0, w1, w2, u[21], m[25]);+ MONT_MAC(t0, t1, t2, u[22], m[24]);+ MONT_MAC(v0, v1, v2, u[23], m[23]);+ MONT_MAC(w0, w1, w2, u[24], m[22]);+ MONT_MAC(t0, t1, t2, u[25], m[21]);+ MONT_MAC(v0, v1, v2, u[26], m[20]);+ MONT_MAC(w0, w1, w2, u[27], m[19]);+ MONT_MAC(t0, t1, t2, u[28], m[18]);+ MONT_MAC(v0, v1, v2, u[29], m[17]);+ MONT_MAC(w0, w1, w2, u[30], m[16]);+ MONT_MAC(t0, t1, t2, u[31], m[15]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[14] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 47 */+ MONT_MAC(t0, t1, t2, a[16], b[31]);+ MONT_MUL(v0, v1, v2, a[17], b[30]);+ MONT_MUL(w0, w1, w2, a[18], b[29]);+ MONT_MAC(t0, t1, t2, a[19], b[28]);+ MONT_MAC(v0, v1, v2, a[20], b[27]);+ MONT_MAC(w0, w1, w2, a[21], b[26]);+ MONT_MAC(t0, t1, t2, a[22], b[25]);+ MONT_MAC(v0, v1, v2, a[23], b[24]);+ MONT_MAC(w0, w1, w2, a[24], b[23]);+ MONT_MAC(t0, t1, t2, a[25], b[22]);+ MONT_MAC(v0, v1, v2, a[26], b[21]);+ MONT_MAC(w0, w1, w2, a[27], b[20]);+ MONT_MAC(t0, t1, t2, a[28], b[19]);+ MONT_MAC(v0, v1, v2, a[29], b[18]);+ MONT_MAC(w0, w1, w2, a[30], b[17]);+ MONT_MAC(t0, t1, t2, a[31], b[16]);+ MONT_MAC(v0, v1, v2, u[16], m[31]);+ MONT_MAC(w0, w1, w2, u[17], m[30]);+ MONT_MAC(t0, t1, t2, u[18], m[29]);+ MONT_MAC(v0, v1, v2, u[19], m[28]);+ MONT_MAC(w0, w1, w2, u[20], m[27]);+ MONT_MAC(t0, t1, t2, u[21], m[26]);+ MONT_MAC(v0, v1, v2, u[22], m[25]);+ MONT_MAC(w0, w1, w2, u[23], m[24]);+ MONT_MAC(t0, t1, t2, u[24], m[23]);+ MONT_MAC(v0, v1, v2, u[25], m[22]);+ MONT_MAC(w0, w1, w2, u[26], m[21]);+ MONT_MAC(t0, t1, t2, u[27], m[20]);+ MONT_MAC(v0, v1, v2, u[28], m[19]);+ MONT_MAC(w0, w1, w2, u[29], m[18]);+ MONT_MAC(t0, t1, t2, u[30], m[17]);+ MONT_MAC(v0, v1, v2, u[31], m[16]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[15] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 48 */+ MONT_MAC(t0, t1, t2, a[17], b[31]);+ MONT_MUL(v0, v1, v2, a[18], b[30]);+ MONT_MUL(w0, w1, w2, a[19], b[29]);+ MONT_MAC(t0, t1, t2, a[20], b[28]);+ MONT_MAC(v0, v1, v2, a[21], b[27]);+ MONT_MAC(w0, w1, w2, a[22], b[26]);+ MONT_MAC(t0, t1, t2, a[23], b[25]);+ MONT_MAC(v0, v1, v2, a[24], b[24]);+ MONT_MAC(w0, w1, w2, a[25], b[23]);+ MONT_MAC(t0, t1, t2, a[26], b[22]);+ MONT_MAC(v0, v1, v2, a[27], b[21]);+ MONT_MAC(w0, w1, w2, a[28], b[20]);+ MONT_MAC(t0, t1, t2, a[29], b[19]);+ MONT_MAC(v0, v1, v2, a[30], b[18]);+ MONT_MAC(w0, w1, w2, a[31], b[17]);+ MONT_MAC(t0, t1, t2, u[17], m[31]);+ MONT_MAC(v0, v1, v2, u[18], m[30]);+ MONT_MAC(w0, w1, w2, u[19], m[29]);+ MONT_MAC(t0, t1, t2, u[20], m[28]);+ MONT_MAC(v0, v1, v2, u[21], m[27]);+ MONT_MAC(w0, w1, w2, u[22], m[26]);+ MONT_MAC(t0, t1, t2, u[23], m[25]);+ MONT_MAC(v0, v1, v2, u[24], m[24]);+ MONT_MAC(w0, w1, w2, u[25], m[23]);+ MONT_MAC(t0, t1, t2, u[26], m[22]);+ MONT_MAC(v0, v1, v2, u[27], m[21]);+ MONT_MAC(w0, w1, w2, u[28], m[20]);+ MONT_MAC(t0, t1, t2, u[29], m[19]);+ MONT_MAC(v0, v1, v2, u[30], m[18]);+ MONT_MAC(w0, w1, w2, u[31], m[17]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[16] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 49 */+ MONT_MAC(t0, t1, t2, a[18], b[31]);+ MONT_MUL(v0, v1, v2, a[19], b[30]);+ MONT_MUL(w0, w1, w2, a[20], b[29]);+ MONT_MAC(t0, t1, t2, a[21], b[28]);+ MONT_MAC(v0, v1, v2, a[22], b[27]);+ MONT_MAC(w0, w1, w2, a[23], b[26]);+ MONT_MAC(t0, t1, t2, a[24], b[25]);+ MONT_MAC(v0, v1, v2, a[25], b[24]);+ MONT_MAC(w0, w1, w2, a[26], b[23]);+ MONT_MAC(t0, t1, t2, a[27], b[22]);+ MONT_MAC(v0, v1, v2, a[28], b[21]);+ MONT_MAC(w0, w1, w2, a[29], b[20]);+ MONT_MAC(t0, t1, t2, a[30], b[19]);+ MONT_MAC(v0, v1, v2, a[31], b[18]);+ MONT_MAC(w0, w1, w2, u[18], m[31]);+ MONT_MAC(t0, t1, t2, u[19], m[30]);+ MONT_MAC(v0, v1, v2, u[20], m[29]);+ MONT_MAC(w0, w1, w2, u[21], m[28]);+ MONT_MAC(t0, t1, t2, u[22], m[27]);+ MONT_MAC(v0, v1, v2, u[23], m[26]);+ MONT_MAC(w0, w1, w2, u[24], m[25]);+ MONT_MAC(t0, t1, t2, u[25], m[24]);+ MONT_MAC(v0, v1, v2, u[26], m[23]);+ MONT_MAC(w0, w1, w2, u[27], m[22]);+ MONT_MAC(t0, t1, t2, u[28], m[21]);+ MONT_MAC(v0, v1, v2, u[29], m[20]);+ MONT_MAC(w0, w1, w2, u[30], m[19]);+ MONT_MAC(t0, t1, t2, u[31], m[18]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[17] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 50 */+ MONT_MAC(t0, t1, t2, a[19], b[31]);+ MONT_MUL(v0, v1, v2, a[20], b[30]);+ MONT_MUL(w0, w1, w2, a[21], b[29]);+ MONT_MAC(t0, t1, t2, a[22], b[28]);+ MONT_MAC(v0, v1, v2, a[23], b[27]);+ MONT_MAC(w0, w1, w2, a[24], b[26]);+ MONT_MAC(t0, t1, t2, a[25], b[25]);+ MONT_MAC(v0, v1, v2, a[26], b[24]);+ MONT_MAC(w0, w1, w2, a[27], b[23]);+ MONT_MAC(t0, t1, t2, a[28], b[22]);+ MONT_MAC(v0, v1, v2, a[29], b[21]);+ MONT_MAC(w0, w1, w2, a[30], b[20]);+ MONT_MAC(t0, t1, t2, a[31], b[19]);+ MONT_MAC(v0, v1, v2, u[19], m[31]);+ MONT_MAC(w0, w1, w2, u[20], m[30]);+ MONT_MAC(t0, t1, t2, u[21], m[29]);+ MONT_MAC(v0, v1, v2, u[22], m[28]);+ MONT_MAC(w0, w1, w2, u[23], m[27]);+ MONT_MAC(t0, t1, t2, u[24], m[26]);+ MONT_MAC(v0, v1, v2, u[25], m[25]);+ MONT_MAC(w0, w1, w2, u[26], m[24]);+ MONT_MAC(t0, t1, t2, u[27], m[23]);+ MONT_MAC(v0, v1, v2, u[28], m[22]);+ MONT_MAC(w0, w1, w2, u[29], m[21]);+ MONT_MAC(t0, t1, t2, u[30], m[20]);+ MONT_MAC(v0, v1, v2, u[31], m[19]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[18] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 51 */+ MONT_MAC(t0, t1, t2, a[20], b[31]);+ MONT_MUL(v0, v1, v2, a[21], b[30]);+ MONT_MUL(w0, w1, w2, a[22], b[29]);+ MONT_MAC(t0, t1, t2, a[23], b[28]);+ MONT_MAC(v0, v1, v2, a[24], b[27]);+ MONT_MAC(w0, w1, w2, a[25], b[26]);+ MONT_MAC(t0, t1, t2, a[26], b[25]);+ MONT_MAC(v0, v1, v2, a[27], b[24]);+ MONT_MAC(w0, w1, w2, a[28], b[23]);+ MONT_MAC(t0, t1, t2, a[29], b[22]);+ MONT_MAC(v0, v1, v2, a[30], b[21]);+ MONT_MAC(w0, w1, w2, a[31], b[20]);+ MONT_MAC(t0, t1, t2, u[20], m[31]);+ MONT_MAC(v0, v1, v2, u[21], m[30]);+ MONT_MAC(w0, w1, w2, u[22], m[29]);+ MONT_MAC(t0, t1, t2, u[23], m[28]);+ MONT_MAC(v0, v1, v2, u[24], m[27]);+ MONT_MAC(w0, w1, w2, u[25], m[26]);+ MONT_MAC(t0, t1, t2, u[26], m[25]);+ MONT_MAC(v0, v1, v2, u[27], m[24]);+ MONT_MAC(w0, w1, w2, u[28], m[23]);+ MONT_MAC(t0, t1, t2, u[29], m[22]);+ MONT_MAC(v0, v1, v2, u[30], m[21]);+ MONT_MAC(w0, w1, w2, u[31], m[20]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[19] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 52 */+ MONT_MAC(t0, t1, t2, a[21], b[31]);+ MONT_MUL(v0, v1, v2, a[22], b[30]);+ MONT_MUL(w0, w1, w2, a[23], b[29]);+ MONT_MAC(t0, t1, t2, a[24], b[28]);+ MONT_MAC(v0, v1, v2, a[25], b[27]);+ MONT_MAC(w0, w1, w2, a[26], b[26]);+ MONT_MAC(t0, t1, t2, a[27], b[25]);+ MONT_MAC(v0, v1, v2, a[28], b[24]);+ MONT_MAC(w0, w1, w2, a[29], b[23]);+ MONT_MAC(t0, t1, t2, a[30], b[22]);+ MONT_MAC(v0, v1, v2, a[31], b[21]);+ MONT_MAC(w0, w1, w2, u[21], m[31]);+ MONT_MAC(t0, t1, t2, u[22], m[30]);+ MONT_MAC(v0, v1, v2, u[23], m[29]);+ MONT_MAC(w0, w1, w2, u[24], m[28]);+ MONT_MAC(t0, t1, t2, u[25], m[27]);+ MONT_MAC(v0, v1, v2, u[26], m[26]);+ MONT_MAC(w0, w1, w2, u[27], m[25]);+ MONT_MAC(t0, t1, t2, u[28], m[24]);+ MONT_MAC(v0, v1, v2, u[29], m[23]);+ MONT_MAC(w0, w1, w2, u[30], m[22]);+ MONT_MAC(t0, t1, t2, u[31], m[21]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[20] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 53 */+ MONT_MAC(t0, t1, t2, a[22], b[31]);+ MONT_MUL(v0, v1, v2, a[23], b[30]);+ MONT_MUL(w0, w1, w2, a[24], b[29]);+ MONT_MAC(t0, t1, t2, a[25], b[28]);+ MONT_MAC(v0, v1, v2, a[26], b[27]);+ MONT_MAC(w0, w1, w2, a[27], b[26]);+ MONT_MAC(t0, t1, t2, a[28], b[25]);+ MONT_MAC(v0, v1, v2, a[29], b[24]);+ MONT_MAC(w0, w1, w2, a[30], b[23]);+ MONT_MAC(t0, t1, t2, a[31], b[22]);+ MONT_MAC(v0, v1, v2, u[22], m[31]);+ MONT_MAC(w0, w1, w2, u[23], m[30]);+ MONT_MAC(t0, t1, t2, u[24], m[29]);+ MONT_MAC(v0, v1, v2, u[25], m[28]);+ MONT_MAC(w0, w1, w2, u[26], m[27]);+ MONT_MAC(t0, t1, t2, u[27], m[26]);+ MONT_MAC(v0, v1, v2, u[28], m[25]);+ MONT_MAC(w0, w1, w2, u[29], m[24]);+ MONT_MAC(t0, t1, t2, u[30], m[23]);+ MONT_MAC(v0, v1, v2, u[31], m[22]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[21] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 54 */+ MONT_MAC(t0, t1, t2, a[23], b[31]);+ MONT_MUL(v0, v1, v2, a[24], b[30]);+ MONT_MUL(w0, w1, w2, a[25], b[29]);+ MONT_MAC(t0, t1, t2, a[26], b[28]);+ MONT_MAC(v0, v1, v2, a[27], b[27]);+ MONT_MAC(w0, w1, w2, a[28], b[26]);+ MONT_MAC(t0, t1, t2, a[29], b[25]);+ MONT_MAC(v0, v1, v2, a[30], b[24]);+ MONT_MAC(w0, w1, w2, a[31], b[23]);+ MONT_MAC(t0, t1, t2, u[23], m[31]);+ MONT_MAC(v0, v1, v2, u[24], m[30]);+ MONT_MAC(w0, w1, w2, u[25], m[29]);+ MONT_MAC(t0, t1, t2, u[26], m[28]);+ MONT_MAC(v0, v1, v2, u[27], m[27]);+ MONT_MAC(w0, w1, w2, u[28], m[26]);+ MONT_MAC(t0, t1, t2, u[29], m[25]);+ MONT_MAC(v0, v1, v2, u[30], m[24]);+ MONT_MAC(w0, w1, w2, u[31], m[23]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[22] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 55 */+ MONT_MAC(t0, t1, t2, a[24], b[31]);+ MONT_MUL(v0, v1, v2, a[25], b[30]);+ MONT_MUL(w0, w1, w2, a[26], b[29]);+ MONT_MAC(t0, t1, t2, a[27], b[28]);+ MONT_MAC(v0, v1, v2, a[28], b[27]);+ MONT_MAC(w0, w1, w2, a[29], b[26]);+ MONT_MAC(t0, t1, t2, a[30], b[25]);+ MONT_MAC(v0, v1, v2, a[31], b[24]);+ MONT_MAC(w0, w1, w2, u[24], m[31]);+ MONT_MAC(t0, t1, t2, u[25], m[30]);+ MONT_MAC(v0, v1, v2, u[26], m[29]);+ MONT_MAC(w0, w1, w2, u[27], m[28]);+ MONT_MAC(t0, t1, t2, u[28], m[27]);+ MONT_MAC(v0, v1, v2, u[29], m[26]);+ MONT_MAC(w0, w1, w2, u[30], m[25]);+ MONT_MAC(t0, t1, t2, u[31], m[24]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[23] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 56 */+ MONT_MAC(t0, t1, t2, a[25], b[31]);+ MONT_MUL(v0, v1, v2, a[26], b[30]);+ MONT_MUL(w0, w1, w2, a[27], b[29]);+ MONT_MAC(t0, t1, t2, a[28], b[28]);+ MONT_MAC(v0, v1, v2, a[29], b[27]);+ MONT_MAC(w0, w1, w2, a[30], b[26]);+ MONT_MAC(t0, t1, t2, a[31], b[25]);+ MONT_MAC(v0, v1, v2, u[25], m[31]);+ MONT_MAC(w0, w1, w2, u[26], m[30]);+ MONT_MAC(t0, t1, t2, u[27], m[29]);+ MONT_MAC(v0, v1, v2, u[28], m[28]);+ MONT_MAC(w0, w1, w2, u[29], m[27]);+ MONT_MAC(t0, t1, t2, u[30], m[26]);+ MONT_MAC(v0, v1, v2, u[31], m[25]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[24] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 57 */+ MONT_MAC(t0, t1, t2, a[26], b[31]);+ MONT_MUL(v0, v1, v2, a[27], b[30]);+ MONT_MUL(w0, w1, w2, a[28], b[29]);+ MONT_MAC(t0, t1, t2, a[29], b[28]);+ MONT_MAC(v0, v1, v2, a[30], b[27]);+ MONT_MAC(w0, w1, w2, a[31], b[26]);+ MONT_MAC(t0, t1, t2, u[26], m[31]);+ MONT_MAC(v0, v1, v2, u[27], m[30]);+ MONT_MAC(w0, w1, w2, u[28], m[29]);+ MONT_MAC(t0, t1, t2, u[29], m[28]);+ MONT_MAC(v0, v1, v2, u[30], m[27]);+ MONT_MAC(w0, w1, w2, u[31], m[26]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[25] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 58 */+ MONT_MAC(t0, t1, t2, a[27], b[31]);+ MONT_MUL(v0, v1, v2, a[28], b[30]);+ MONT_MUL(w0, w1, w2, a[29], b[29]);+ MONT_MAC(t0, t1, t2, a[30], b[28]);+ MONT_MAC(v0, v1, v2, a[31], b[27]);+ MONT_MAC(w0, w1, w2, u[27], m[31]);+ MONT_MAC(t0, t1, t2, u[28], m[30]);+ MONT_MAC(v0, v1, v2, u[29], m[29]);+ MONT_MAC(w0, w1, w2, u[30], m[28]);+ MONT_MAC(t0, t1, t2, u[31], m[27]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[26] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 59 */+ MONT_MAC(t0, t1, t2, a[28], b[31]);+ MONT_MUL(v0, v1, v2, a[29], b[30]);+ MONT_MUL(w0, w1, w2, a[30], b[29]);+ MONT_MAC(t0, t1, t2, a[31], b[28]);+ MONT_MAC(v0, v1, v2, u[28], m[31]);+ MONT_MAC(w0, w1, w2, u[29], m[30]);+ MONT_MAC(t0, t1, t2, u[30], m[29]);+ MONT_MAC(v0, v1, v2, u[31], m[28]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[27] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 60 */+ MONT_MAC(t0, t1, t2, a[29], b[31]);+ MONT_MUL(v0, v1, v2, a[30], b[30]);+ MONT_MUL(w0, w1, w2, a[31], b[29]);+ MONT_MAC(t0, t1, t2, u[29], m[31]);+ MONT_MAC(v0, v1, v2, u[30], m[30]);+ MONT_MAC(w0, w1, w2, u[31], m[29]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[28] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 61 */+ MONT_MAC(t0, t1, t2, a[30], b[31]);+ MONT_MUL(v0, v1, v2, a[31], b[30]);+ MONT_MUL(w0, w1, w2, u[30], m[31]);+ MONT_MAC(t0, t1, t2, u[31], m[30]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ z[29] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 62 */+ MONT_MAC(t0, t1, t2, a[31], b[31]);+ MONT_MUL(v0, v1, v2, u[31], m[31]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ z[30] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ z[31] = t0;++ /* under 2m, with t1 the bit above n limbs: at most one subtraction */+ borrow = sub_n(r, z, m, 32);+ take = t1 | (borrow ^ 1);+ select_n(r, r, z, take & 1, 32);+}++/* r = a * a * R^-1 mod m, for a under m; t is 2n limbs of scratch */+static void crypton_mont_sqr32(limb_t *r, const limb_t *a,+ const limb_t *m, limb_t n0, limb_t *t)+{+ limb_t *u = t, *z = t + 32;+ limb_t t0 = 0, t1 = 0, t2 = 0, v0, v1, v2, w0, w1, w2, borrow, take;+ limb_t s0, s1, s2, c0, c1, c2;++ /* column 0 */+ MONT_MAC(t0, t1, t2, a[0], a[0]);+ u[0] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[0], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 1 */+ MONT_MUL(s0, s1, s2, a[0], a[1]);+ MONT_MAC(t0, t1, t2, u[0], m[1]);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[1] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[1], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 2 */+ MONT_MUL(s0, s1, s2, a[0], a[2]);+ MONT_MAC(t0, t1, t2, a[1], a[1]);+ MONT_MUL(v0, v1, v2, u[0], m[2]);+ MONT_MUL(w0, w1, w2, u[1], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[2] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[2], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 3 */+ MONT_MUL(s0, s1, s2, a[0], a[3]);+ MONT_MUL(c0, c1, c2, a[1], a[2]);+ MONT_MAC(t0, t1, t2, u[0], m[3]);+ MONT_MUL(v0, v1, v2, u[1], m[2]);+ MONT_MUL(w0, w1, w2, u[2], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[3] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[3], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 4 */+ MONT_MUL(s0, s1, s2, a[0], a[4]);+ MONT_MUL(c0, c1, c2, a[1], a[3]);+ MONT_MAC(t0, t1, t2, a[2], a[2]);+ MONT_MUL(v0, v1, v2, u[0], m[4]);+ MONT_MUL(w0, w1, w2, u[1], m[3]);+ MONT_MAC(t0, t1, t2, u[2], m[2]);+ MONT_MAC(v0, v1, v2, u[3], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[4] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[4], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 5 */+ MONT_MUL(s0, s1, s2, a[0], a[5]);+ MONT_MUL(c0, c1, c2, a[1], a[4]);+ MONT_MAC(s0, s1, s2, a[2], a[3]);+ MONT_MAC(t0, t1, t2, u[0], m[5]);+ MONT_MUL(v0, v1, v2, u[1], m[4]);+ MONT_MUL(w0, w1, w2, u[2], m[3]);+ MONT_MAC(t0, t1, t2, u[3], m[2]);+ MONT_MAC(v0, v1, v2, u[4], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[5] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[5], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 6 */+ MONT_MUL(s0, s1, s2, a[0], a[6]);+ MONT_MUL(c0, c1, c2, a[1], a[5]);+ MONT_MAC(s0, s1, s2, a[2], a[4]);+ MONT_MAC(t0, t1, t2, a[3], a[3]);+ MONT_MUL(v0, v1, v2, u[0], m[6]);+ MONT_MUL(w0, w1, w2, u[1], m[5]);+ MONT_MAC(t0, t1, t2, u[2], m[4]);+ MONT_MAC(v0, v1, v2, u[3], m[3]);+ MONT_MAC(w0, w1, w2, u[4], m[2]);+ MONT_MAC(t0, t1, t2, u[5], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[6] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[6], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 7 */+ MONT_MUL(s0, s1, s2, a[0], a[7]);+ MONT_MUL(c0, c1, c2, a[1], a[6]);+ MONT_MAC(s0, s1, s2, a[2], a[5]);+ MONT_MAC(c0, c1, c2, a[3], a[4]);+ MONT_MAC(t0, t1, t2, u[0], m[7]);+ MONT_MUL(v0, v1, v2, u[1], m[6]);+ MONT_MUL(w0, w1, w2, u[2], m[5]);+ MONT_MAC(t0, t1, t2, u[3], m[4]);+ MONT_MAC(v0, v1, v2, u[4], m[3]);+ MONT_MAC(w0, w1, w2, u[5], m[2]);+ MONT_MAC(t0, t1, t2, u[6], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[7] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[7], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 8 */+ MONT_MUL(s0, s1, s2, a[0], a[8]);+ MONT_MUL(c0, c1, c2, a[1], a[7]);+ MONT_MAC(s0, s1, s2, a[2], a[6]);+ MONT_MAC(c0, c1, c2, a[3], a[5]);+ MONT_MAC(t0, t1, t2, a[4], a[4]);+ MONT_MUL(v0, v1, v2, u[0], m[8]);+ MONT_MUL(w0, w1, w2, u[1], m[7]);+ MONT_MAC(t0, t1, t2, u[2], m[6]);+ MONT_MAC(v0, v1, v2, u[3], m[5]);+ MONT_MAC(w0, w1, w2, u[4], m[4]);+ MONT_MAC(t0, t1, t2, u[5], m[3]);+ MONT_MAC(v0, v1, v2, u[6], m[2]);+ MONT_MAC(w0, w1, w2, u[7], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[8] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[8], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 9 */+ MONT_MUL(s0, s1, s2, a[0], a[9]);+ MONT_MUL(c0, c1, c2, a[1], a[8]);+ MONT_MAC(s0, s1, s2, a[2], a[7]);+ MONT_MAC(c0, c1, c2, a[3], a[6]);+ MONT_MAC(s0, s1, s2, a[4], a[5]);+ MONT_MAC(t0, t1, t2, u[0], m[9]);+ MONT_MUL(v0, v1, v2, u[1], m[8]);+ MONT_MUL(w0, w1, w2, u[2], m[7]);+ MONT_MAC(t0, t1, t2, u[3], m[6]);+ MONT_MAC(v0, v1, v2, u[4], m[5]);+ MONT_MAC(w0, w1, w2, u[5], m[4]);+ MONT_MAC(t0, t1, t2, u[6], m[3]);+ MONT_MAC(v0, v1, v2, u[7], m[2]);+ MONT_MAC(w0, w1, w2, u[8], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[9] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[9], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 10 */+ MONT_MUL(s0, s1, s2, a[0], a[10]);+ MONT_MUL(c0, c1, c2, a[1], a[9]);+ MONT_MAC(s0, s1, s2, a[2], a[8]);+ MONT_MAC(c0, c1, c2, a[3], a[7]);+ MONT_MAC(s0, s1, s2, a[4], a[6]);+ MONT_MAC(t0, t1, t2, a[5], a[5]);+ MONT_MUL(v0, v1, v2, u[0], m[10]);+ MONT_MUL(w0, w1, w2, u[1], m[9]);+ MONT_MAC(t0, t1, t2, u[2], m[8]);+ MONT_MAC(v0, v1, v2, u[3], m[7]);+ MONT_MAC(w0, w1, w2, u[4], m[6]);+ MONT_MAC(t0, t1, t2, u[5], m[5]);+ MONT_MAC(v0, v1, v2, u[6], m[4]);+ MONT_MAC(w0, w1, w2, u[7], m[3]);+ MONT_MAC(t0, t1, t2, u[8], m[2]);+ MONT_MAC(v0, v1, v2, u[9], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[10] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[10], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 11 */+ MONT_MUL(s0, s1, s2, a[0], a[11]);+ MONT_MUL(c0, c1, c2, a[1], a[10]);+ MONT_MAC(s0, s1, s2, a[2], a[9]);+ MONT_MAC(c0, c1, c2, a[3], a[8]);+ MONT_MAC(s0, s1, s2, a[4], a[7]);+ MONT_MAC(c0, c1, c2, a[5], a[6]);+ MONT_MAC(t0, t1, t2, u[0], m[11]);+ MONT_MUL(v0, v1, v2, u[1], m[10]);+ MONT_MUL(w0, w1, w2, u[2], m[9]);+ MONT_MAC(t0, t1, t2, u[3], m[8]);+ MONT_MAC(v0, v1, v2, u[4], m[7]);+ MONT_MAC(w0, w1, w2, u[5], m[6]);+ MONT_MAC(t0, t1, t2, u[6], m[5]);+ MONT_MAC(v0, v1, v2, u[7], m[4]);+ MONT_MAC(w0, w1, w2, u[8], m[3]);+ MONT_MAC(t0, t1, t2, u[9], m[2]);+ MONT_MAC(v0, v1, v2, u[10], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[11] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[11], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 12 */+ MONT_MUL(s0, s1, s2, a[0], a[12]);+ MONT_MUL(c0, c1, c2, a[1], a[11]);+ MONT_MAC(s0, s1, s2, a[2], a[10]);+ MONT_MAC(c0, c1, c2, a[3], a[9]);+ MONT_MAC(s0, s1, s2, a[4], a[8]);+ MONT_MAC(c0, c1, c2, a[5], a[7]);+ MONT_MAC(t0, t1, t2, a[6], a[6]);+ MONT_MUL(v0, v1, v2, u[0], m[12]);+ MONT_MUL(w0, w1, w2, u[1], m[11]);+ MONT_MAC(t0, t1, t2, u[2], m[10]);+ MONT_MAC(v0, v1, v2, u[3], m[9]);+ MONT_MAC(w0, w1, w2, u[4], m[8]);+ MONT_MAC(t0, t1, t2, u[5], m[7]);+ MONT_MAC(v0, v1, v2, u[6], m[6]);+ MONT_MAC(w0, w1, w2, u[7], m[5]);+ MONT_MAC(t0, t1, t2, u[8], m[4]);+ MONT_MAC(v0, v1, v2, u[9], m[3]);+ MONT_MAC(w0, w1, w2, u[10], m[2]);+ MONT_MAC(t0, t1, t2, u[11], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[12] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[12], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 13 */+ MONT_MUL(s0, s1, s2, a[0], a[13]);+ MONT_MUL(c0, c1, c2, a[1], a[12]);+ MONT_MAC(s0, s1, s2, a[2], a[11]);+ MONT_MAC(c0, c1, c2, a[3], a[10]);+ MONT_MAC(s0, s1, s2, a[4], a[9]);+ MONT_MAC(c0, c1, c2, a[5], a[8]);+ MONT_MAC(s0, s1, s2, a[6], a[7]);+ MONT_MAC(t0, t1, t2, u[0], m[13]);+ MONT_MUL(v0, v1, v2, u[1], m[12]);+ MONT_MUL(w0, w1, w2, u[2], m[11]);+ MONT_MAC(t0, t1, t2, u[3], m[10]);+ MONT_MAC(v0, v1, v2, u[4], m[9]);+ MONT_MAC(w0, w1, w2, u[5], m[8]);+ MONT_MAC(t0, t1, t2, u[6], m[7]);+ MONT_MAC(v0, v1, v2, u[7], m[6]);+ MONT_MAC(w0, w1, w2, u[8], m[5]);+ MONT_MAC(t0, t1, t2, u[9], m[4]);+ MONT_MAC(v0, v1, v2, u[10], m[3]);+ MONT_MAC(w0, w1, w2, u[11], m[2]);+ MONT_MAC(t0, t1, t2, u[12], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[13] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[13], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 14 */+ MONT_MUL(s0, s1, s2, a[0], a[14]);+ MONT_MUL(c0, c1, c2, a[1], a[13]);+ MONT_MAC(s0, s1, s2, a[2], a[12]);+ MONT_MAC(c0, c1, c2, a[3], a[11]);+ MONT_MAC(s0, s1, s2, a[4], a[10]);+ MONT_MAC(c0, c1, c2, a[5], a[9]);+ MONT_MAC(s0, s1, s2, a[6], a[8]);+ MONT_MAC(t0, t1, t2, a[7], a[7]);+ MONT_MUL(v0, v1, v2, u[0], m[14]);+ MONT_MUL(w0, w1, w2, u[1], m[13]);+ MONT_MAC(t0, t1, t2, u[2], m[12]);+ MONT_MAC(v0, v1, v2, u[3], m[11]);+ MONT_MAC(w0, w1, w2, u[4], m[10]);+ MONT_MAC(t0, t1, t2, u[5], m[9]);+ MONT_MAC(v0, v1, v2, u[6], m[8]);+ MONT_MAC(w0, w1, w2, u[7], m[7]);+ MONT_MAC(t0, t1, t2, u[8], m[6]);+ MONT_MAC(v0, v1, v2, u[9], m[5]);+ MONT_MAC(w0, w1, w2, u[10], m[4]);+ MONT_MAC(t0, t1, t2, u[11], m[3]);+ MONT_MAC(v0, v1, v2, u[12], m[2]);+ MONT_MAC(w0, w1, w2, u[13], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[14] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[14], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 15 */+ MONT_MUL(s0, s1, s2, a[0], a[15]);+ MONT_MUL(c0, c1, c2, a[1], a[14]);+ MONT_MAC(s0, s1, s2, a[2], a[13]);+ MONT_MAC(c0, c1, c2, a[3], a[12]);+ MONT_MAC(s0, s1, s2, a[4], a[11]);+ MONT_MAC(c0, c1, c2, a[5], a[10]);+ MONT_MAC(s0, s1, s2, a[6], a[9]);+ MONT_MAC(c0, c1, c2, a[7], a[8]);+ MONT_MAC(t0, t1, t2, u[0], m[15]);+ MONT_MUL(v0, v1, v2, u[1], m[14]);+ MONT_MUL(w0, w1, w2, u[2], m[13]);+ MONT_MAC(t0, t1, t2, u[3], m[12]);+ MONT_MAC(v0, v1, v2, u[4], m[11]);+ MONT_MAC(w0, w1, w2, u[5], m[10]);+ MONT_MAC(t0, t1, t2, u[6], m[9]);+ MONT_MAC(v0, v1, v2, u[7], m[8]);+ MONT_MAC(w0, w1, w2, u[8], m[7]);+ MONT_MAC(t0, t1, t2, u[9], m[6]);+ MONT_MAC(v0, v1, v2, u[10], m[5]);+ MONT_MAC(w0, w1, w2, u[11], m[4]);+ MONT_MAC(t0, t1, t2, u[12], m[3]);+ MONT_MAC(v0, v1, v2, u[13], m[2]);+ MONT_MAC(w0, w1, w2, u[14], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[15] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[15], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 16 */+ MONT_MUL(s0, s1, s2, a[0], a[16]);+ MONT_MUL(c0, c1, c2, a[1], a[15]);+ MONT_MAC(s0, s1, s2, a[2], a[14]);+ MONT_MAC(c0, c1, c2, a[3], a[13]);+ MONT_MAC(s0, s1, s2, a[4], a[12]);+ MONT_MAC(c0, c1, c2, a[5], a[11]);+ MONT_MAC(s0, s1, s2, a[6], a[10]);+ MONT_MAC(c0, c1, c2, a[7], a[9]);+ MONT_MAC(t0, t1, t2, a[8], a[8]);+ MONT_MUL(v0, v1, v2, u[0], m[16]);+ MONT_MUL(w0, w1, w2, u[1], m[15]);+ MONT_MAC(t0, t1, t2, u[2], m[14]);+ MONT_MAC(v0, v1, v2, u[3], m[13]);+ MONT_MAC(w0, w1, w2, u[4], m[12]);+ MONT_MAC(t0, t1, t2, u[5], m[11]);+ MONT_MAC(v0, v1, v2, u[6], m[10]);+ MONT_MAC(w0, w1, w2, u[7], m[9]);+ MONT_MAC(t0, t1, t2, u[8], m[8]);+ MONT_MAC(v0, v1, v2, u[9], m[7]);+ MONT_MAC(w0, w1, w2, u[10], m[6]);+ MONT_MAC(t0, t1, t2, u[11], m[5]);+ MONT_MAC(v0, v1, v2, u[12], m[4]);+ MONT_MAC(w0, w1, w2, u[13], m[3]);+ MONT_MAC(t0, t1, t2, u[14], m[2]);+ MONT_MAC(v0, v1, v2, u[15], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[16] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[16], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 17 */+ MONT_MUL(s0, s1, s2, a[0], a[17]);+ MONT_MUL(c0, c1, c2, a[1], a[16]);+ MONT_MAC(s0, s1, s2, a[2], a[15]);+ MONT_MAC(c0, c1, c2, a[3], a[14]);+ MONT_MAC(s0, s1, s2, a[4], a[13]);+ MONT_MAC(c0, c1, c2, a[5], a[12]);+ MONT_MAC(s0, s1, s2, a[6], a[11]);+ MONT_MAC(c0, c1, c2, a[7], a[10]);+ MONT_MAC(s0, s1, s2, a[8], a[9]);+ MONT_MAC(t0, t1, t2, u[0], m[17]);+ MONT_MUL(v0, v1, v2, u[1], m[16]);+ MONT_MUL(w0, w1, w2, u[2], m[15]);+ MONT_MAC(t0, t1, t2, u[3], m[14]);+ MONT_MAC(v0, v1, v2, u[4], m[13]);+ MONT_MAC(w0, w1, w2, u[5], m[12]);+ MONT_MAC(t0, t1, t2, u[6], m[11]);+ MONT_MAC(v0, v1, v2, u[7], m[10]);+ MONT_MAC(w0, w1, w2, u[8], m[9]);+ MONT_MAC(t0, t1, t2, u[9], m[8]);+ MONT_MAC(v0, v1, v2, u[10], m[7]);+ MONT_MAC(w0, w1, w2, u[11], m[6]);+ MONT_MAC(t0, t1, t2, u[12], m[5]);+ MONT_MAC(v0, v1, v2, u[13], m[4]);+ MONT_MAC(w0, w1, w2, u[14], m[3]);+ MONT_MAC(t0, t1, t2, u[15], m[2]);+ MONT_MAC(v0, v1, v2, u[16], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[17] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[17], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 18 */+ MONT_MUL(s0, s1, s2, a[0], a[18]);+ MONT_MUL(c0, c1, c2, a[1], a[17]);+ MONT_MAC(s0, s1, s2, a[2], a[16]);+ MONT_MAC(c0, c1, c2, a[3], a[15]);+ MONT_MAC(s0, s1, s2, a[4], a[14]);+ MONT_MAC(c0, c1, c2, a[5], a[13]);+ MONT_MAC(s0, s1, s2, a[6], a[12]);+ MONT_MAC(c0, c1, c2, a[7], a[11]);+ MONT_MAC(s0, s1, s2, a[8], a[10]);+ MONT_MAC(t0, t1, t2, a[9], a[9]);+ MONT_MUL(v0, v1, v2, u[0], m[18]);+ MONT_MUL(w0, w1, w2, u[1], m[17]);+ MONT_MAC(t0, t1, t2, u[2], m[16]);+ MONT_MAC(v0, v1, v2, u[3], m[15]);+ MONT_MAC(w0, w1, w2, u[4], m[14]);+ MONT_MAC(t0, t1, t2, u[5], m[13]);+ MONT_MAC(v0, v1, v2, u[6], m[12]);+ MONT_MAC(w0, w1, w2, u[7], m[11]);+ MONT_MAC(t0, t1, t2, u[8], m[10]);+ MONT_MAC(v0, v1, v2, u[9], m[9]);+ MONT_MAC(w0, w1, w2, u[10], m[8]);+ MONT_MAC(t0, t1, t2, u[11], m[7]);+ MONT_MAC(v0, v1, v2, u[12], m[6]);+ MONT_MAC(w0, w1, w2, u[13], m[5]);+ MONT_MAC(t0, t1, t2, u[14], m[4]);+ MONT_MAC(v0, v1, v2, u[15], m[3]);+ MONT_MAC(w0, w1, w2, u[16], m[2]);+ MONT_MAC(t0, t1, t2, u[17], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[18] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[18], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 19 */+ MONT_MUL(s0, s1, s2, a[0], a[19]);+ MONT_MUL(c0, c1, c2, a[1], a[18]);+ MONT_MAC(s0, s1, s2, a[2], a[17]);+ MONT_MAC(c0, c1, c2, a[3], a[16]);+ MONT_MAC(s0, s1, s2, a[4], a[15]);+ MONT_MAC(c0, c1, c2, a[5], a[14]);+ MONT_MAC(s0, s1, s2, a[6], a[13]);+ MONT_MAC(c0, c1, c2, a[7], a[12]);+ MONT_MAC(s0, s1, s2, a[8], a[11]);+ MONT_MAC(c0, c1, c2, a[9], a[10]);+ MONT_MAC(t0, t1, t2, u[0], m[19]);+ MONT_MUL(v0, v1, v2, u[1], m[18]);+ MONT_MUL(w0, w1, w2, u[2], m[17]);+ MONT_MAC(t0, t1, t2, u[3], m[16]);+ MONT_MAC(v0, v1, v2, u[4], m[15]);+ MONT_MAC(w0, w1, w2, u[5], m[14]);+ MONT_MAC(t0, t1, t2, u[6], m[13]);+ MONT_MAC(v0, v1, v2, u[7], m[12]);+ MONT_MAC(w0, w1, w2, u[8], m[11]);+ MONT_MAC(t0, t1, t2, u[9], m[10]);+ MONT_MAC(v0, v1, v2, u[10], m[9]);+ MONT_MAC(w0, w1, w2, u[11], m[8]);+ MONT_MAC(t0, t1, t2, u[12], m[7]);+ MONT_MAC(v0, v1, v2, u[13], m[6]);+ MONT_MAC(w0, w1, w2, u[14], m[5]);+ MONT_MAC(t0, t1, t2, u[15], m[4]);+ MONT_MAC(v0, v1, v2, u[16], m[3]);+ MONT_MAC(w0, w1, w2, u[17], m[2]);+ MONT_MAC(t0, t1, t2, u[18], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[19] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[19], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 20 */+ MONT_MUL(s0, s1, s2, a[0], a[20]);+ MONT_MUL(c0, c1, c2, a[1], a[19]);+ MONT_MAC(s0, s1, s2, a[2], a[18]);+ MONT_MAC(c0, c1, c2, a[3], a[17]);+ MONT_MAC(s0, s1, s2, a[4], a[16]);+ MONT_MAC(c0, c1, c2, a[5], a[15]);+ MONT_MAC(s0, s1, s2, a[6], a[14]);+ MONT_MAC(c0, c1, c2, a[7], a[13]);+ MONT_MAC(s0, s1, s2, a[8], a[12]);+ MONT_MAC(c0, c1, c2, a[9], a[11]);+ MONT_MAC(t0, t1, t2, a[10], a[10]);+ MONT_MUL(v0, v1, v2, u[0], m[20]);+ MONT_MUL(w0, w1, w2, u[1], m[19]);+ MONT_MAC(t0, t1, t2, u[2], m[18]);+ MONT_MAC(v0, v1, v2, u[3], m[17]);+ MONT_MAC(w0, w1, w2, u[4], m[16]);+ MONT_MAC(t0, t1, t2, u[5], m[15]);+ MONT_MAC(v0, v1, v2, u[6], m[14]);+ MONT_MAC(w0, w1, w2, u[7], m[13]);+ MONT_MAC(t0, t1, t2, u[8], m[12]);+ MONT_MAC(v0, v1, v2, u[9], m[11]);+ MONT_MAC(w0, w1, w2, u[10], m[10]);+ MONT_MAC(t0, t1, t2, u[11], m[9]);+ MONT_MAC(v0, v1, v2, u[12], m[8]);+ MONT_MAC(w0, w1, w2, u[13], m[7]);+ MONT_MAC(t0, t1, t2, u[14], m[6]);+ MONT_MAC(v0, v1, v2, u[15], m[5]);+ MONT_MAC(w0, w1, w2, u[16], m[4]);+ MONT_MAC(t0, t1, t2, u[17], m[3]);+ MONT_MAC(v0, v1, v2, u[18], m[2]);+ MONT_MAC(w0, w1, w2, u[19], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[20] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[20], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 21 */+ MONT_MUL(s0, s1, s2, a[0], a[21]);+ MONT_MUL(c0, c1, c2, a[1], a[20]);+ MONT_MAC(s0, s1, s2, a[2], a[19]);+ MONT_MAC(c0, c1, c2, a[3], a[18]);+ MONT_MAC(s0, s1, s2, a[4], a[17]);+ MONT_MAC(c0, c1, c2, a[5], a[16]);+ MONT_MAC(s0, s1, s2, a[6], a[15]);+ MONT_MAC(c0, c1, c2, a[7], a[14]);+ MONT_MAC(s0, s1, s2, a[8], a[13]);+ MONT_MAC(c0, c1, c2, a[9], a[12]);+ MONT_MAC(s0, s1, s2, a[10], a[11]);+ MONT_MAC(t0, t1, t2, u[0], m[21]);+ MONT_MUL(v0, v1, v2, u[1], m[20]);+ MONT_MUL(w0, w1, w2, u[2], m[19]);+ MONT_MAC(t0, t1, t2, u[3], m[18]);+ MONT_MAC(v0, v1, v2, u[4], m[17]);+ MONT_MAC(w0, w1, w2, u[5], m[16]);+ MONT_MAC(t0, t1, t2, u[6], m[15]);+ MONT_MAC(v0, v1, v2, u[7], m[14]);+ MONT_MAC(w0, w1, w2, u[8], m[13]);+ MONT_MAC(t0, t1, t2, u[9], m[12]);+ MONT_MAC(v0, v1, v2, u[10], m[11]);+ MONT_MAC(w0, w1, w2, u[11], m[10]);+ MONT_MAC(t0, t1, t2, u[12], m[9]);+ MONT_MAC(v0, v1, v2, u[13], m[8]);+ MONT_MAC(w0, w1, w2, u[14], m[7]);+ MONT_MAC(t0, t1, t2, u[15], m[6]);+ MONT_MAC(v0, v1, v2, u[16], m[5]);+ MONT_MAC(w0, w1, w2, u[17], m[4]);+ MONT_MAC(t0, t1, t2, u[18], m[3]);+ MONT_MAC(v0, v1, v2, u[19], m[2]);+ MONT_MAC(w0, w1, w2, u[20], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[21] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[21], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 22 */+ MONT_MUL(s0, s1, s2, a[0], a[22]);+ MONT_MUL(c0, c1, c2, a[1], a[21]);+ MONT_MAC(s0, s1, s2, a[2], a[20]);+ MONT_MAC(c0, c1, c2, a[3], a[19]);+ MONT_MAC(s0, s1, s2, a[4], a[18]);+ MONT_MAC(c0, c1, c2, a[5], a[17]);+ MONT_MAC(s0, s1, s2, a[6], a[16]);+ MONT_MAC(c0, c1, c2, a[7], a[15]);+ MONT_MAC(s0, s1, s2, a[8], a[14]);+ MONT_MAC(c0, c1, c2, a[9], a[13]);+ MONT_MAC(s0, s1, s2, a[10], a[12]);+ MONT_MAC(t0, t1, t2, a[11], a[11]);+ MONT_MUL(v0, v1, v2, u[0], m[22]);+ MONT_MUL(w0, w1, w2, u[1], m[21]);+ MONT_MAC(t0, t1, t2, u[2], m[20]);+ MONT_MAC(v0, v1, v2, u[3], m[19]);+ MONT_MAC(w0, w1, w2, u[4], m[18]);+ MONT_MAC(t0, t1, t2, u[5], m[17]);+ MONT_MAC(v0, v1, v2, u[6], m[16]);+ MONT_MAC(w0, w1, w2, u[7], m[15]);+ MONT_MAC(t0, t1, t2, u[8], m[14]);+ MONT_MAC(v0, v1, v2, u[9], m[13]);+ MONT_MAC(w0, w1, w2, u[10], m[12]);+ MONT_MAC(t0, t1, t2, u[11], m[11]);+ MONT_MAC(v0, v1, v2, u[12], m[10]);+ MONT_MAC(w0, w1, w2, u[13], m[9]);+ MONT_MAC(t0, t1, t2, u[14], m[8]);+ MONT_MAC(v0, v1, v2, u[15], m[7]);+ MONT_MAC(w0, w1, w2, u[16], m[6]);+ MONT_MAC(t0, t1, t2, u[17], m[5]);+ MONT_MAC(v0, v1, v2, u[18], m[4]);+ MONT_MAC(w0, w1, w2, u[19], m[3]);+ MONT_MAC(t0, t1, t2, u[20], m[2]);+ MONT_MAC(v0, v1, v2, u[21], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[22] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[22], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 23 */+ MONT_MUL(s0, s1, s2, a[0], a[23]);+ MONT_MUL(c0, c1, c2, a[1], a[22]);+ MONT_MAC(s0, s1, s2, a[2], a[21]);+ MONT_MAC(c0, c1, c2, a[3], a[20]);+ MONT_MAC(s0, s1, s2, a[4], a[19]);+ MONT_MAC(c0, c1, c2, a[5], a[18]);+ MONT_MAC(s0, s1, s2, a[6], a[17]);+ MONT_MAC(c0, c1, c2, a[7], a[16]);+ MONT_MAC(s0, s1, s2, a[8], a[15]);+ MONT_MAC(c0, c1, c2, a[9], a[14]);+ MONT_MAC(s0, s1, s2, a[10], a[13]);+ MONT_MAC(c0, c1, c2, a[11], a[12]);+ MONT_MAC(t0, t1, t2, u[0], m[23]);+ MONT_MUL(v0, v1, v2, u[1], m[22]);+ MONT_MUL(w0, w1, w2, u[2], m[21]);+ MONT_MAC(t0, t1, t2, u[3], m[20]);+ MONT_MAC(v0, v1, v2, u[4], m[19]);+ MONT_MAC(w0, w1, w2, u[5], m[18]);+ MONT_MAC(t0, t1, t2, u[6], m[17]);+ MONT_MAC(v0, v1, v2, u[7], m[16]);+ MONT_MAC(w0, w1, w2, u[8], m[15]);+ MONT_MAC(t0, t1, t2, u[9], m[14]);+ MONT_MAC(v0, v1, v2, u[10], m[13]);+ MONT_MAC(w0, w1, w2, u[11], m[12]);+ MONT_MAC(t0, t1, t2, u[12], m[11]);+ MONT_MAC(v0, v1, v2, u[13], m[10]);+ MONT_MAC(w0, w1, w2, u[14], m[9]);+ MONT_MAC(t0, t1, t2, u[15], m[8]);+ MONT_MAC(v0, v1, v2, u[16], m[7]);+ MONT_MAC(w0, w1, w2, u[17], m[6]);+ MONT_MAC(t0, t1, t2, u[18], m[5]);+ MONT_MAC(v0, v1, v2, u[19], m[4]);+ MONT_MAC(w0, w1, w2, u[20], m[3]);+ MONT_MAC(t0, t1, t2, u[21], m[2]);+ MONT_MAC(v0, v1, v2, u[22], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[23] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[23], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 24 */+ MONT_MUL(s0, s1, s2, a[0], a[24]);+ MONT_MUL(c0, c1, c2, a[1], a[23]);+ MONT_MAC(s0, s1, s2, a[2], a[22]);+ MONT_MAC(c0, c1, c2, a[3], a[21]);+ MONT_MAC(s0, s1, s2, a[4], a[20]);+ MONT_MAC(c0, c1, c2, a[5], a[19]);+ MONT_MAC(s0, s1, s2, a[6], a[18]);+ MONT_MAC(c0, c1, c2, a[7], a[17]);+ MONT_MAC(s0, s1, s2, a[8], a[16]);+ MONT_MAC(c0, c1, c2, a[9], a[15]);+ MONT_MAC(s0, s1, s2, a[10], a[14]);+ MONT_MAC(c0, c1, c2, a[11], a[13]);+ MONT_MAC(t0, t1, t2, a[12], a[12]);+ MONT_MUL(v0, v1, v2, u[0], m[24]);+ MONT_MUL(w0, w1, w2, u[1], m[23]);+ MONT_MAC(t0, t1, t2, u[2], m[22]);+ MONT_MAC(v0, v1, v2, u[3], m[21]);+ MONT_MAC(w0, w1, w2, u[4], m[20]);+ MONT_MAC(t0, t1, t2, u[5], m[19]);+ MONT_MAC(v0, v1, v2, u[6], m[18]);+ MONT_MAC(w0, w1, w2, u[7], m[17]);+ MONT_MAC(t0, t1, t2, u[8], m[16]);+ MONT_MAC(v0, v1, v2, u[9], m[15]);+ MONT_MAC(w0, w1, w2, u[10], m[14]);+ MONT_MAC(t0, t1, t2, u[11], m[13]);+ MONT_MAC(v0, v1, v2, u[12], m[12]);+ MONT_MAC(w0, w1, w2, u[13], m[11]);+ MONT_MAC(t0, t1, t2, u[14], m[10]);+ MONT_MAC(v0, v1, v2, u[15], m[9]);+ MONT_MAC(w0, w1, w2, u[16], m[8]);+ MONT_MAC(t0, t1, t2, u[17], m[7]);+ MONT_MAC(v0, v1, v2, u[18], m[6]);+ MONT_MAC(w0, w1, w2, u[19], m[5]);+ MONT_MAC(t0, t1, t2, u[20], m[4]);+ MONT_MAC(v0, v1, v2, u[21], m[3]);+ MONT_MAC(w0, w1, w2, u[22], m[2]);+ MONT_MAC(t0, t1, t2, u[23], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[24] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[24], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 25 */+ MONT_MUL(s0, s1, s2, a[0], a[25]);+ MONT_MUL(c0, c1, c2, a[1], a[24]);+ MONT_MAC(s0, s1, s2, a[2], a[23]);+ MONT_MAC(c0, c1, c2, a[3], a[22]);+ MONT_MAC(s0, s1, s2, a[4], a[21]);+ MONT_MAC(c0, c1, c2, a[5], a[20]);+ MONT_MAC(s0, s1, s2, a[6], a[19]);+ MONT_MAC(c0, c1, c2, a[7], a[18]);+ MONT_MAC(s0, s1, s2, a[8], a[17]);+ MONT_MAC(c0, c1, c2, a[9], a[16]);+ MONT_MAC(s0, s1, s2, a[10], a[15]);+ MONT_MAC(c0, c1, c2, a[11], a[14]);+ MONT_MAC(s0, s1, s2, a[12], a[13]);+ MONT_MAC(t0, t1, t2, u[0], m[25]);+ MONT_MUL(v0, v1, v2, u[1], m[24]);+ MONT_MUL(w0, w1, w2, u[2], m[23]);+ MONT_MAC(t0, t1, t2, u[3], m[22]);+ MONT_MAC(v0, v1, v2, u[4], m[21]);+ MONT_MAC(w0, w1, w2, u[5], m[20]);+ MONT_MAC(t0, t1, t2, u[6], m[19]);+ MONT_MAC(v0, v1, v2, u[7], m[18]);+ MONT_MAC(w0, w1, w2, u[8], m[17]);+ MONT_MAC(t0, t1, t2, u[9], m[16]);+ MONT_MAC(v0, v1, v2, u[10], m[15]);+ MONT_MAC(w0, w1, w2, u[11], m[14]);+ MONT_MAC(t0, t1, t2, u[12], m[13]);+ MONT_MAC(v0, v1, v2, u[13], m[12]);+ MONT_MAC(w0, w1, w2, u[14], m[11]);+ MONT_MAC(t0, t1, t2, u[15], m[10]);+ MONT_MAC(v0, v1, v2, u[16], m[9]);+ MONT_MAC(w0, w1, w2, u[17], m[8]);+ MONT_MAC(t0, t1, t2, u[18], m[7]);+ MONT_MAC(v0, v1, v2, u[19], m[6]);+ MONT_MAC(w0, w1, w2, u[20], m[5]);+ MONT_MAC(t0, t1, t2, u[21], m[4]);+ MONT_MAC(v0, v1, v2, u[22], m[3]);+ MONT_MAC(w0, w1, w2, u[23], m[2]);+ MONT_MAC(t0, t1, t2, u[24], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[25] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[25], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 26 */+ MONT_MUL(s0, s1, s2, a[0], a[26]);+ MONT_MUL(c0, c1, c2, a[1], a[25]);+ MONT_MAC(s0, s1, s2, a[2], a[24]);+ MONT_MAC(c0, c1, c2, a[3], a[23]);+ MONT_MAC(s0, s1, s2, a[4], a[22]);+ MONT_MAC(c0, c1, c2, a[5], a[21]);+ MONT_MAC(s0, s1, s2, a[6], a[20]);+ MONT_MAC(c0, c1, c2, a[7], a[19]);+ MONT_MAC(s0, s1, s2, a[8], a[18]);+ MONT_MAC(c0, c1, c2, a[9], a[17]);+ MONT_MAC(s0, s1, s2, a[10], a[16]);+ MONT_MAC(c0, c1, c2, a[11], a[15]);+ MONT_MAC(s0, s1, s2, a[12], a[14]);+ MONT_MAC(t0, t1, t2, a[13], a[13]);+ MONT_MUL(v0, v1, v2, u[0], m[26]);+ MONT_MUL(w0, w1, w2, u[1], m[25]);+ MONT_MAC(t0, t1, t2, u[2], m[24]);+ MONT_MAC(v0, v1, v2, u[3], m[23]);+ MONT_MAC(w0, w1, w2, u[4], m[22]);+ MONT_MAC(t0, t1, t2, u[5], m[21]);+ MONT_MAC(v0, v1, v2, u[6], m[20]);+ MONT_MAC(w0, w1, w2, u[7], m[19]);+ MONT_MAC(t0, t1, t2, u[8], m[18]);+ MONT_MAC(v0, v1, v2, u[9], m[17]);+ MONT_MAC(w0, w1, w2, u[10], m[16]);+ MONT_MAC(t0, t1, t2, u[11], m[15]);+ MONT_MAC(v0, v1, v2, u[12], m[14]);+ MONT_MAC(w0, w1, w2, u[13], m[13]);+ MONT_MAC(t0, t1, t2, u[14], m[12]);+ MONT_MAC(v0, v1, v2, u[15], m[11]);+ MONT_MAC(w0, w1, w2, u[16], m[10]);+ MONT_MAC(t0, t1, t2, u[17], m[9]);+ MONT_MAC(v0, v1, v2, u[18], m[8]);+ MONT_MAC(w0, w1, w2, u[19], m[7]);+ MONT_MAC(t0, t1, t2, u[20], m[6]);+ MONT_MAC(v0, v1, v2, u[21], m[5]);+ MONT_MAC(w0, w1, w2, u[22], m[4]);+ MONT_MAC(t0, t1, t2, u[23], m[3]);+ MONT_MAC(v0, v1, v2, u[24], m[2]);+ MONT_MAC(w0, w1, w2, u[25], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[26] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[26], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 27 */+ MONT_MUL(s0, s1, s2, a[0], a[27]);+ MONT_MUL(c0, c1, c2, a[1], a[26]);+ MONT_MAC(s0, s1, s2, a[2], a[25]);+ MONT_MAC(c0, c1, c2, a[3], a[24]);+ MONT_MAC(s0, s1, s2, a[4], a[23]);+ MONT_MAC(c0, c1, c2, a[5], a[22]);+ MONT_MAC(s0, s1, s2, a[6], a[21]);+ MONT_MAC(c0, c1, c2, a[7], a[20]);+ MONT_MAC(s0, s1, s2, a[8], a[19]);+ MONT_MAC(c0, c1, c2, a[9], a[18]);+ MONT_MAC(s0, s1, s2, a[10], a[17]);+ MONT_MAC(c0, c1, c2, a[11], a[16]);+ MONT_MAC(s0, s1, s2, a[12], a[15]);+ MONT_MAC(c0, c1, c2, a[13], a[14]);+ MONT_MAC(t0, t1, t2, u[0], m[27]);+ MONT_MUL(v0, v1, v2, u[1], m[26]);+ MONT_MUL(w0, w1, w2, u[2], m[25]);+ MONT_MAC(t0, t1, t2, u[3], m[24]);+ MONT_MAC(v0, v1, v2, u[4], m[23]);+ MONT_MAC(w0, w1, w2, u[5], m[22]);+ MONT_MAC(t0, t1, t2, u[6], m[21]);+ MONT_MAC(v0, v1, v2, u[7], m[20]);+ MONT_MAC(w0, w1, w2, u[8], m[19]);+ MONT_MAC(t0, t1, t2, u[9], m[18]);+ MONT_MAC(v0, v1, v2, u[10], m[17]);+ MONT_MAC(w0, w1, w2, u[11], m[16]);+ MONT_MAC(t0, t1, t2, u[12], m[15]);+ MONT_MAC(v0, v1, v2, u[13], m[14]);+ MONT_MAC(w0, w1, w2, u[14], m[13]);+ MONT_MAC(t0, t1, t2, u[15], m[12]);+ MONT_MAC(v0, v1, v2, u[16], m[11]);+ MONT_MAC(w0, w1, w2, u[17], m[10]);+ MONT_MAC(t0, t1, t2, u[18], m[9]);+ MONT_MAC(v0, v1, v2, u[19], m[8]);+ MONT_MAC(w0, w1, w2, u[20], m[7]);+ MONT_MAC(t0, t1, t2, u[21], m[6]);+ MONT_MAC(v0, v1, v2, u[22], m[5]);+ MONT_MAC(w0, w1, w2, u[23], m[4]);+ MONT_MAC(t0, t1, t2, u[24], m[3]);+ MONT_MAC(v0, v1, v2, u[25], m[2]);+ MONT_MAC(w0, w1, w2, u[26], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[27] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[27], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 28 */+ MONT_MUL(s0, s1, s2, a[0], a[28]);+ MONT_MUL(c0, c1, c2, a[1], a[27]);+ MONT_MAC(s0, s1, s2, a[2], a[26]);+ MONT_MAC(c0, c1, c2, a[3], a[25]);+ MONT_MAC(s0, s1, s2, a[4], a[24]);+ MONT_MAC(c0, c1, c2, a[5], a[23]);+ MONT_MAC(s0, s1, s2, a[6], a[22]);+ MONT_MAC(c0, c1, c2, a[7], a[21]);+ MONT_MAC(s0, s1, s2, a[8], a[20]);+ MONT_MAC(c0, c1, c2, a[9], a[19]);+ MONT_MAC(s0, s1, s2, a[10], a[18]);+ MONT_MAC(c0, c1, c2, a[11], a[17]);+ MONT_MAC(s0, s1, s2, a[12], a[16]);+ MONT_MAC(c0, c1, c2, a[13], a[15]);+ MONT_MAC(t0, t1, t2, a[14], a[14]);+ MONT_MUL(v0, v1, v2, u[0], m[28]);+ MONT_MUL(w0, w1, w2, u[1], m[27]);+ MONT_MAC(t0, t1, t2, u[2], m[26]);+ MONT_MAC(v0, v1, v2, u[3], m[25]);+ MONT_MAC(w0, w1, w2, u[4], m[24]);+ MONT_MAC(t0, t1, t2, u[5], m[23]);+ MONT_MAC(v0, v1, v2, u[6], m[22]);+ MONT_MAC(w0, w1, w2, u[7], m[21]);+ MONT_MAC(t0, t1, t2, u[8], m[20]);+ MONT_MAC(v0, v1, v2, u[9], m[19]);+ MONT_MAC(w0, w1, w2, u[10], m[18]);+ MONT_MAC(t0, t1, t2, u[11], m[17]);+ MONT_MAC(v0, v1, v2, u[12], m[16]);+ MONT_MAC(w0, w1, w2, u[13], m[15]);+ MONT_MAC(t0, t1, t2, u[14], m[14]);+ MONT_MAC(v0, v1, v2, u[15], m[13]);+ MONT_MAC(w0, w1, w2, u[16], m[12]);+ MONT_MAC(t0, t1, t2, u[17], m[11]);+ MONT_MAC(v0, v1, v2, u[18], m[10]);+ MONT_MAC(w0, w1, w2, u[19], m[9]);+ MONT_MAC(t0, t1, t2, u[20], m[8]);+ MONT_MAC(v0, v1, v2, u[21], m[7]);+ MONT_MAC(w0, w1, w2, u[22], m[6]);+ MONT_MAC(t0, t1, t2, u[23], m[5]);+ MONT_MAC(v0, v1, v2, u[24], m[4]);+ MONT_MAC(w0, w1, w2, u[25], m[3]);+ MONT_MAC(t0, t1, t2, u[26], m[2]);+ MONT_MAC(v0, v1, v2, u[27], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[28] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[28], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 29 */+ MONT_MUL(s0, s1, s2, a[0], a[29]);+ MONT_MUL(c0, c1, c2, a[1], a[28]);+ MONT_MAC(s0, s1, s2, a[2], a[27]);+ MONT_MAC(c0, c1, c2, a[3], a[26]);+ MONT_MAC(s0, s1, s2, a[4], a[25]);+ MONT_MAC(c0, c1, c2, a[5], a[24]);+ MONT_MAC(s0, s1, s2, a[6], a[23]);+ MONT_MAC(c0, c1, c2, a[7], a[22]);+ MONT_MAC(s0, s1, s2, a[8], a[21]);+ MONT_MAC(c0, c1, c2, a[9], a[20]);+ MONT_MAC(s0, s1, s2, a[10], a[19]);+ MONT_MAC(c0, c1, c2, a[11], a[18]);+ MONT_MAC(s0, s1, s2, a[12], a[17]);+ MONT_MAC(c0, c1, c2, a[13], a[16]);+ MONT_MAC(s0, s1, s2, a[14], a[15]);+ MONT_MAC(t0, t1, t2, u[0], m[29]);+ MONT_MUL(v0, v1, v2, u[1], m[28]);+ MONT_MUL(w0, w1, w2, u[2], m[27]);+ MONT_MAC(t0, t1, t2, u[3], m[26]);+ MONT_MAC(v0, v1, v2, u[4], m[25]);+ MONT_MAC(w0, w1, w2, u[5], m[24]);+ MONT_MAC(t0, t1, t2, u[6], m[23]);+ MONT_MAC(v0, v1, v2, u[7], m[22]);+ MONT_MAC(w0, w1, w2, u[8], m[21]);+ MONT_MAC(t0, t1, t2, u[9], m[20]);+ MONT_MAC(v0, v1, v2, u[10], m[19]);+ MONT_MAC(w0, w1, w2, u[11], m[18]);+ MONT_MAC(t0, t1, t2, u[12], m[17]);+ MONT_MAC(v0, v1, v2, u[13], m[16]);+ MONT_MAC(w0, w1, w2, u[14], m[15]);+ MONT_MAC(t0, t1, t2, u[15], m[14]);+ MONT_MAC(v0, v1, v2, u[16], m[13]);+ MONT_MAC(w0, w1, w2, u[17], m[12]);+ MONT_MAC(t0, t1, t2, u[18], m[11]);+ MONT_MAC(v0, v1, v2, u[19], m[10]);+ MONT_MAC(w0, w1, w2, u[20], m[9]);+ MONT_MAC(t0, t1, t2, u[21], m[8]);+ MONT_MAC(v0, v1, v2, u[22], m[7]);+ MONT_MAC(w0, w1, w2, u[23], m[6]);+ MONT_MAC(t0, t1, t2, u[24], m[5]);+ MONT_MAC(v0, v1, v2, u[25], m[4]);+ MONT_MAC(w0, w1, w2, u[26], m[3]);+ MONT_MAC(t0, t1, t2, u[27], m[2]);+ MONT_MAC(v0, v1, v2, u[28], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[29] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[29], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 30 */+ MONT_MUL(s0, s1, s2, a[0], a[30]);+ MONT_MUL(c0, c1, c2, a[1], a[29]);+ MONT_MAC(s0, s1, s2, a[2], a[28]);+ MONT_MAC(c0, c1, c2, a[3], a[27]);+ MONT_MAC(s0, s1, s2, a[4], a[26]);+ MONT_MAC(c0, c1, c2, a[5], a[25]);+ MONT_MAC(s0, s1, s2, a[6], a[24]);+ MONT_MAC(c0, c1, c2, a[7], a[23]);+ MONT_MAC(s0, s1, s2, a[8], a[22]);+ MONT_MAC(c0, c1, c2, a[9], a[21]);+ MONT_MAC(s0, s1, s2, a[10], a[20]);+ MONT_MAC(c0, c1, c2, a[11], a[19]);+ MONT_MAC(s0, s1, s2, a[12], a[18]);+ MONT_MAC(c0, c1, c2, a[13], a[17]);+ MONT_MAC(s0, s1, s2, a[14], a[16]);+ MONT_MAC(t0, t1, t2, a[15], a[15]);+ MONT_MUL(v0, v1, v2, u[0], m[30]);+ MONT_MUL(w0, w1, w2, u[1], m[29]);+ MONT_MAC(t0, t1, t2, u[2], m[28]);+ MONT_MAC(v0, v1, v2, u[3], m[27]);+ MONT_MAC(w0, w1, w2, u[4], m[26]);+ MONT_MAC(t0, t1, t2, u[5], m[25]);+ MONT_MAC(v0, v1, v2, u[6], m[24]);+ MONT_MAC(w0, w1, w2, u[7], m[23]);+ MONT_MAC(t0, t1, t2, u[8], m[22]);+ MONT_MAC(v0, v1, v2, u[9], m[21]);+ MONT_MAC(w0, w1, w2, u[10], m[20]);+ MONT_MAC(t0, t1, t2, u[11], m[19]);+ MONT_MAC(v0, v1, v2, u[12], m[18]);+ MONT_MAC(w0, w1, w2, u[13], m[17]);+ MONT_MAC(t0, t1, t2, u[14], m[16]);+ MONT_MAC(v0, v1, v2, u[15], m[15]);+ MONT_MAC(w0, w1, w2, u[16], m[14]);+ MONT_MAC(t0, t1, t2, u[17], m[13]);+ MONT_MAC(v0, v1, v2, u[18], m[12]);+ MONT_MAC(w0, w1, w2, u[19], m[11]);+ MONT_MAC(t0, t1, t2, u[20], m[10]);+ MONT_MAC(v0, v1, v2, u[21], m[9]);+ MONT_MAC(w0, w1, w2, u[22], m[8]);+ MONT_MAC(t0, t1, t2, u[23], m[7]);+ MONT_MAC(v0, v1, v2, u[24], m[6]);+ MONT_MAC(w0, w1, w2, u[25], m[5]);+ MONT_MAC(t0, t1, t2, u[26], m[4]);+ MONT_MAC(v0, v1, v2, u[27], m[3]);+ MONT_MAC(w0, w1, w2, u[28], m[2]);+ MONT_MAC(t0, t1, t2, u[29], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[30] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[30], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 31 */+ MONT_MUL(s0, s1, s2, a[0], a[31]);+ MONT_MUL(c0, c1, c2, a[1], a[30]);+ MONT_MAC(s0, s1, s2, a[2], a[29]);+ MONT_MAC(c0, c1, c2, a[3], a[28]);+ MONT_MAC(s0, s1, s2, a[4], a[27]);+ MONT_MAC(c0, c1, c2, a[5], a[26]);+ MONT_MAC(s0, s1, s2, a[6], a[25]);+ MONT_MAC(c0, c1, c2, a[7], a[24]);+ MONT_MAC(s0, s1, s2, a[8], a[23]);+ MONT_MAC(c0, c1, c2, a[9], a[22]);+ MONT_MAC(s0, s1, s2, a[10], a[21]);+ MONT_MAC(c0, c1, c2, a[11], a[20]);+ MONT_MAC(s0, s1, s2, a[12], a[19]);+ MONT_MAC(c0, c1, c2, a[13], a[18]);+ MONT_MAC(s0, s1, s2, a[14], a[17]);+ MONT_MAC(c0, c1, c2, a[15], a[16]);+ MONT_MAC(t0, t1, t2, u[0], m[31]);+ MONT_MUL(v0, v1, v2, u[1], m[30]);+ MONT_MUL(w0, w1, w2, u[2], m[29]);+ MONT_MAC(t0, t1, t2, u[3], m[28]);+ MONT_MAC(v0, v1, v2, u[4], m[27]);+ MONT_MAC(w0, w1, w2, u[5], m[26]);+ MONT_MAC(t0, t1, t2, u[6], m[25]);+ MONT_MAC(v0, v1, v2, u[7], m[24]);+ MONT_MAC(w0, w1, w2, u[8], m[23]);+ MONT_MAC(t0, t1, t2, u[9], m[22]);+ MONT_MAC(v0, v1, v2, u[10], m[21]);+ MONT_MAC(w0, w1, w2, u[11], m[20]);+ MONT_MAC(t0, t1, t2, u[12], m[19]);+ MONT_MAC(v0, v1, v2, u[13], m[18]);+ MONT_MAC(w0, w1, w2, u[14], m[17]);+ MONT_MAC(t0, t1, t2, u[15], m[16]);+ MONT_MAC(v0, v1, v2, u[16], m[15]);+ MONT_MAC(w0, w1, w2, u[17], m[14]);+ MONT_MAC(t0, t1, t2, u[18], m[13]);+ MONT_MAC(v0, v1, v2, u[19], m[12]);+ MONT_MAC(w0, w1, w2, u[20], m[11]);+ MONT_MAC(t0, t1, t2, u[21], m[10]);+ MONT_MAC(v0, v1, v2, u[22], m[9]);+ MONT_MAC(w0, w1, w2, u[23], m[8]);+ MONT_MAC(t0, t1, t2, u[24], m[7]);+ MONT_MAC(v0, v1, v2, u[25], m[6]);+ MONT_MAC(w0, w1, w2, u[26], m[5]);+ MONT_MAC(t0, t1, t2, u[27], m[4]);+ MONT_MAC(v0, v1, v2, u[28], m[3]);+ MONT_MAC(w0, w1, w2, u[29], m[2]);+ MONT_MAC(t0, t1, t2, u[30], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[31] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[31], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 32 */+ MONT_MUL(s0, s1, s2, a[1], a[31]);+ MONT_MUL(c0, c1, c2, a[2], a[30]);+ MONT_MAC(s0, s1, s2, a[3], a[29]);+ MONT_MAC(c0, c1, c2, a[4], a[28]);+ MONT_MAC(s0, s1, s2, a[5], a[27]);+ MONT_MAC(c0, c1, c2, a[6], a[26]);+ MONT_MAC(s0, s1, s2, a[7], a[25]);+ MONT_MAC(c0, c1, c2, a[8], a[24]);+ MONT_MAC(s0, s1, s2, a[9], a[23]);+ MONT_MAC(c0, c1, c2, a[10], a[22]);+ MONT_MAC(s0, s1, s2, a[11], a[21]);+ MONT_MAC(c0, c1, c2, a[12], a[20]);+ MONT_MAC(s0, s1, s2, a[13], a[19]);+ MONT_MAC(c0, c1, c2, a[14], a[18]);+ MONT_MAC(s0, s1, s2, a[15], a[17]);+ MONT_MAC(t0, t1, t2, a[16], a[16]);+ MONT_MUL(v0, v1, v2, u[1], m[31]);+ MONT_MUL(w0, w1, w2, u[2], m[30]);+ MONT_MAC(t0, t1, t2, u[3], m[29]);+ MONT_MAC(v0, v1, v2, u[4], m[28]);+ MONT_MAC(w0, w1, w2, u[5], m[27]);+ MONT_MAC(t0, t1, t2, u[6], m[26]);+ MONT_MAC(v0, v1, v2, u[7], m[25]);+ MONT_MAC(w0, w1, w2, u[8], m[24]);+ MONT_MAC(t0, t1, t2, u[9], m[23]);+ MONT_MAC(v0, v1, v2, u[10], m[22]);+ MONT_MAC(w0, w1, w2, u[11], m[21]);+ MONT_MAC(t0, t1, t2, u[12], m[20]);+ MONT_MAC(v0, v1, v2, u[13], m[19]);+ MONT_MAC(w0, w1, w2, u[14], m[18]);+ MONT_MAC(t0, t1, t2, u[15], m[17]);+ MONT_MAC(v0, v1, v2, u[16], m[16]);+ MONT_MAC(w0, w1, w2, u[17], m[15]);+ MONT_MAC(t0, t1, t2, u[18], m[14]);+ MONT_MAC(v0, v1, v2, u[19], m[13]);+ MONT_MAC(w0, w1, w2, u[20], m[12]);+ MONT_MAC(t0, t1, t2, u[21], m[11]);+ MONT_MAC(v0, v1, v2, u[22], m[10]);+ MONT_MAC(w0, w1, w2, u[23], m[9]);+ MONT_MAC(t0, t1, t2, u[24], m[8]);+ MONT_MAC(v0, v1, v2, u[25], m[7]);+ MONT_MAC(w0, w1, w2, u[26], m[6]);+ MONT_MAC(t0, t1, t2, u[27], m[5]);+ MONT_MAC(v0, v1, v2, u[28], m[4]);+ MONT_MAC(w0, w1, w2, u[29], m[3]);+ MONT_MAC(t0, t1, t2, u[30], m[2]);+ MONT_MAC(v0, v1, v2, u[31], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[0] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 33 */+ MONT_MUL(s0, s1, s2, a[2], a[31]);+ MONT_MUL(c0, c1, c2, a[3], a[30]);+ MONT_MAC(s0, s1, s2, a[4], a[29]);+ MONT_MAC(c0, c1, c2, a[5], a[28]);+ MONT_MAC(s0, s1, s2, a[6], a[27]);+ MONT_MAC(c0, c1, c2, a[7], a[26]);+ MONT_MAC(s0, s1, s2, a[8], a[25]);+ MONT_MAC(c0, c1, c2, a[9], a[24]);+ MONT_MAC(s0, s1, s2, a[10], a[23]);+ MONT_MAC(c0, c1, c2, a[11], a[22]);+ MONT_MAC(s0, s1, s2, a[12], a[21]);+ MONT_MAC(c0, c1, c2, a[13], a[20]);+ MONT_MAC(s0, s1, s2, a[14], a[19]);+ MONT_MAC(c0, c1, c2, a[15], a[18]);+ MONT_MAC(s0, s1, s2, a[16], a[17]);+ MONT_MAC(t0, t1, t2, u[2], m[31]);+ MONT_MUL(v0, v1, v2, u[3], m[30]);+ MONT_MUL(w0, w1, w2, u[4], m[29]);+ MONT_MAC(t0, t1, t2, u[5], m[28]);+ MONT_MAC(v0, v1, v2, u[6], m[27]);+ MONT_MAC(w0, w1, w2, u[7], m[26]);+ MONT_MAC(t0, t1, t2, u[8], m[25]);+ MONT_MAC(v0, v1, v2, u[9], m[24]);+ MONT_MAC(w0, w1, w2, u[10], m[23]);+ MONT_MAC(t0, t1, t2, u[11], m[22]);+ MONT_MAC(v0, v1, v2, u[12], m[21]);+ MONT_MAC(w0, w1, w2, u[13], m[20]);+ MONT_MAC(t0, t1, t2, u[14], m[19]);+ MONT_MAC(v0, v1, v2, u[15], m[18]);+ MONT_MAC(w0, w1, w2, u[16], m[17]);+ MONT_MAC(t0, t1, t2, u[17], m[16]);+ MONT_MAC(v0, v1, v2, u[18], m[15]);+ MONT_MAC(w0, w1, w2, u[19], m[14]);+ MONT_MAC(t0, t1, t2, u[20], m[13]);+ MONT_MAC(v0, v1, v2, u[21], m[12]);+ MONT_MAC(w0, w1, w2, u[22], m[11]);+ MONT_MAC(t0, t1, t2, u[23], m[10]);+ MONT_MAC(v0, v1, v2, u[24], m[9]);+ MONT_MAC(w0, w1, w2, u[25], m[8]);+ MONT_MAC(t0, t1, t2, u[26], m[7]);+ MONT_MAC(v0, v1, v2, u[27], m[6]);+ MONT_MAC(w0, w1, w2, u[28], m[5]);+ MONT_MAC(t0, t1, t2, u[29], m[4]);+ MONT_MAC(v0, v1, v2, u[30], m[3]);+ MONT_MAC(w0, w1, w2, u[31], m[2]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[1] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 34 */+ MONT_MUL(s0, s1, s2, a[3], a[31]);+ MONT_MUL(c0, c1, c2, a[4], a[30]);+ MONT_MAC(s0, s1, s2, a[5], a[29]);+ MONT_MAC(c0, c1, c2, a[6], a[28]);+ MONT_MAC(s0, s1, s2, a[7], a[27]);+ MONT_MAC(c0, c1, c2, a[8], a[26]);+ MONT_MAC(s0, s1, s2, a[9], a[25]);+ MONT_MAC(c0, c1, c2, a[10], a[24]);+ MONT_MAC(s0, s1, s2, a[11], a[23]);+ MONT_MAC(c0, c1, c2, a[12], a[22]);+ MONT_MAC(s0, s1, s2, a[13], a[21]);+ MONT_MAC(c0, c1, c2, a[14], a[20]);+ MONT_MAC(s0, s1, s2, a[15], a[19]);+ MONT_MAC(c0, c1, c2, a[16], a[18]);+ MONT_MAC(t0, t1, t2, a[17], a[17]);+ MONT_MUL(v0, v1, v2, u[3], m[31]);+ MONT_MUL(w0, w1, w2, u[4], m[30]);+ MONT_MAC(t0, t1, t2, u[5], m[29]);+ MONT_MAC(v0, v1, v2, u[6], m[28]);+ MONT_MAC(w0, w1, w2, u[7], m[27]);+ MONT_MAC(t0, t1, t2, u[8], m[26]);+ MONT_MAC(v0, v1, v2, u[9], m[25]);+ MONT_MAC(w0, w1, w2, u[10], m[24]);+ MONT_MAC(t0, t1, t2, u[11], m[23]);+ MONT_MAC(v0, v1, v2, u[12], m[22]);+ MONT_MAC(w0, w1, w2, u[13], m[21]);+ MONT_MAC(t0, t1, t2, u[14], m[20]);+ MONT_MAC(v0, v1, v2, u[15], m[19]);+ MONT_MAC(w0, w1, w2, u[16], m[18]);+ MONT_MAC(t0, t1, t2, u[17], m[17]);+ MONT_MAC(v0, v1, v2, u[18], m[16]);+ MONT_MAC(w0, w1, w2, u[19], m[15]);+ MONT_MAC(t0, t1, t2, u[20], m[14]);+ MONT_MAC(v0, v1, v2, u[21], m[13]);+ MONT_MAC(w0, w1, w2, u[22], m[12]);+ MONT_MAC(t0, t1, t2, u[23], m[11]);+ MONT_MAC(v0, v1, v2, u[24], m[10]);+ MONT_MAC(w0, w1, w2, u[25], m[9]);+ MONT_MAC(t0, t1, t2, u[26], m[8]);+ MONT_MAC(v0, v1, v2, u[27], m[7]);+ MONT_MAC(w0, w1, w2, u[28], m[6]);+ MONT_MAC(t0, t1, t2, u[29], m[5]);+ MONT_MAC(v0, v1, v2, u[30], m[4]);+ MONT_MAC(w0, w1, w2, u[31], m[3]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[2] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 35 */+ MONT_MUL(s0, s1, s2, a[4], a[31]);+ MONT_MUL(c0, c1, c2, a[5], a[30]);+ MONT_MAC(s0, s1, s2, a[6], a[29]);+ MONT_MAC(c0, c1, c2, a[7], a[28]);+ MONT_MAC(s0, s1, s2, a[8], a[27]);+ MONT_MAC(c0, c1, c2, a[9], a[26]);+ MONT_MAC(s0, s1, s2, a[10], a[25]);+ MONT_MAC(c0, c1, c2, a[11], a[24]);+ MONT_MAC(s0, s1, s2, a[12], a[23]);+ MONT_MAC(c0, c1, c2, a[13], a[22]);+ MONT_MAC(s0, s1, s2, a[14], a[21]);+ MONT_MAC(c0, c1, c2, a[15], a[20]);+ MONT_MAC(s0, s1, s2, a[16], a[19]);+ MONT_MAC(c0, c1, c2, a[17], a[18]);+ MONT_MAC(t0, t1, t2, u[4], m[31]);+ MONT_MUL(v0, v1, v2, u[5], m[30]);+ MONT_MUL(w0, w1, w2, u[6], m[29]);+ MONT_MAC(t0, t1, t2, u[7], m[28]);+ MONT_MAC(v0, v1, v2, u[8], m[27]);+ MONT_MAC(w0, w1, w2, u[9], m[26]);+ MONT_MAC(t0, t1, t2, u[10], m[25]);+ MONT_MAC(v0, v1, v2, u[11], m[24]);+ MONT_MAC(w0, w1, w2, u[12], m[23]);+ MONT_MAC(t0, t1, t2, u[13], m[22]);+ MONT_MAC(v0, v1, v2, u[14], m[21]);+ MONT_MAC(w0, w1, w2, u[15], m[20]);+ MONT_MAC(t0, t1, t2, u[16], m[19]);+ MONT_MAC(v0, v1, v2, u[17], m[18]);+ MONT_MAC(w0, w1, w2, u[18], m[17]);+ MONT_MAC(t0, t1, t2, u[19], m[16]);+ MONT_MAC(v0, v1, v2, u[20], m[15]);+ MONT_MAC(w0, w1, w2, u[21], m[14]);+ MONT_MAC(t0, t1, t2, u[22], m[13]);+ MONT_MAC(v0, v1, v2, u[23], m[12]);+ MONT_MAC(w0, w1, w2, u[24], m[11]);+ MONT_MAC(t0, t1, t2, u[25], m[10]);+ MONT_MAC(v0, v1, v2, u[26], m[9]);+ MONT_MAC(w0, w1, w2, u[27], m[8]);+ MONT_MAC(t0, t1, t2, u[28], m[7]);+ MONT_MAC(v0, v1, v2, u[29], m[6]);+ MONT_MAC(w0, w1, w2, u[30], m[5]);+ MONT_MAC(t0, t1, t2, u[31], m[4]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[3] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 36 */+ MONT_MUL(s0, s1, s2, a[5], a[31]);+ MONT_MUL(c0, c1, c2, a[6], a[30]);+ MONT_MAC(s0, s1, s2, a[7], a[29]);+ MONT_MAC(c0, c1, c2, a[8], a[28]);+ MONT_MAC(s0, s1, s2, a[9], a[27]);+ MONT_MAC(c0, c1, c2, a[10], a[26]);+ MONT_MAC(s0, s1, s2, a[11], a[25]);+ MONT_MAC(c0, c1, c2, a[12], a[24]);+ MONT_MAC(s0, s1, s2, a[13], a[23]);+ MONT_MAC(c0, c1, c2, a[14], a[22]);+ MONT_MAC(s0, s1, s2, a[15], a[21]);+ MONT_MAC(c0, c1, c2, a[16], a[20]);+ MONT_MAC(s0, s1, s2, a[17], a[19]);+ MONT_MAC(t0, t1, t2, a[18], a[18]);+ MONT_MUL(v0, v1, v2, u[5], m[31]);+ MONT_MUL(w0, w1, w2, u[6], m[30]);+ MONT_MAC(t0, t1, t2, u[7], m[29]);+ MONT_MAC(v0, v1, v2, u[8], m[28]);+ MONT_MAC(w0, w1, w2, u[9], m[27]);+ MONT_MAC(t0, t1, t2, u[10], m[26]);+ MONT_MAC(v0, v1, v2, u[11], m[25]);+ MONT_MAC(w0, w1, w2, u[12], m[24]);+ MONT_MAC(t0, t1, t2, u[13], m[23]);+ MONT_MAC(v0, v1, v2, u[14], m[22]);+ MONT_MAC(w0, w1, w2, u[15], m[21]);+ MONT_MAC(t0, t1, t2, u[16], m[20]);+ MONT_MAC(v0, v1, v2, u[17], m[19]);+ MONT_MAC(w0, w1, w2, u[18], m[18]);+ MONT_MAC(t0, t1, t2, u[19], m[17]);+ MONT_MAC(v0, v1, v2, u[20], m[16]);+ MONT_MAC(w0, w1, w2, u[21], m[15]);+ MONT_MAC(t0, t1, t2, u[22], m[14]);+ MONT_MAC(v0, v1, v2, u[23], m[13]);+ MONT_MAC(w0, w1, w2, u[24], m[12]);+ MONT_MAC(t0, t1, t2, u[25], m[11]);+ MONT_MAC(v0, v1, v2, u[26], m[10]);+ MONT_MAC(w0, w1, w2, u[27], m[9]);+ MONT_MAC(t0, t1, t2, u[28], m[8]);+ MONT_MAC(v0, v1, v2, u[29], m[7]);+ MONT_MAC(w0, w1, w2, u[30], m[6]);+ MONT_MAC(t0, t1, t2, u[31], m[5]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[4] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 37 */+ MONT_MUL(s0, s1, s2, a[6], a[31]);+ MONT_MUL(c0, c1, c2, a[7], a[30]);+ MONT_MAC(s0, s1, s2, a[8], a[29]);+ MONT_MAC(c0, c1, c2, a[9], a[28]);+ MONT_MAC(s0, s1, s2, a[10], a[27]);+ MONT_MAC(c0, c1, c2, a[11], a[26]);+ MONT_MAC(s0, s1, s2, a[12], a[25]);+ MONT_MAC(c0, c1, c2, a[13], a[24]);+ MONT_MAC(s0, s1, s2, a[14], a[23]);+ MONT_MAC(c0, c1, c2, a[15], a[22]);+ MONT_MAC(s0, s1, s2, a[16], a[21]);+ MONT_MAC(c0, c1, c2, a[17], a[20]);+ MONT_MAC(s0, s1, s2, a[18], a[19]);+ MONT_MAC(t0, t1, t2, u[6], m[31]);+ MONT_MUL(v0, v1, v2, u[7], m[30]);+ MONT_MUL(w0, w1, w2, u[8], m[29]);+ MONT_MAC(t0, t1, t2, u[9], m[28]);+ MONT_MAC(v0, v1, v2, u[10], m[27]);+ MONT_MAC(w0, w1, w2, u[11], m[26]);+ MONT_MAC(t0, t1, t2, u[12], m[25]);+ MONT_MAC(v0, v1, v2, u[13], m[24]);+ MONT_MAC(w0, w1, w2, u[14], m[23]);+ MONT_MAC(t0, t1, t2, u[15], m[22]);+ MONT_MAC(v0, v1, v2, u[16], m[21]);+ MONT_MAC(w0, w1, w2, u[17], m[20]);+ MONT_MAC(t0, t1, t2, u[18], m[19]);+ MONT_MAC(v0, v1, v2, u[19], m[18]);+ MONT_MAC(w0, w1, w2, u[20], m[17]);+ MONT_MAC(t0, t1, t2, u[21], m[16]);+ MONT_MAC(v0, v1, v2, u[22], m[15]);+ MONT_MAC(w0, w1, w2, u[23], m[14]);+ MONT_MAC(t0, t1, t2, u[24], m[13]);+ MONT_MAC(v0, v1, v2, u[25], m[12]);+ MONT_MAC(w0, w1, w2, u[26], m[11]);+ MONT_MAC(t0, t1, t2, u[27], m[10]);+ MONT_MAC(v0, v1, v2, u[28], m[9]);+ MONT_MAC(w0, w1, w2, u[29], m[8]);+ MONT_MAC(t0, t1, t2, u[30], m[7]);+ MONT_MAC(v0, v1, v2, u[31], m[6]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[5] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 38 */+ MONT_MUL(s0, s1, s2, a[7], a[31]);+ MONT_MUL(c0, c1, c2, a[8], a[30]);+ MONT_MAC(s0, s1, s2, a[9], a[29]);+ MONT_MAC(c0, c1, c2, a[10], a[28]);+ MONT_MAC(s0, s1, s2, a[11], a[27]);+ MONT_MAC(c0, c1, c2, a[12], a[26]);+ MONT_MAC(s0, s1, s2, a[13], a[25]);+ MONT_MAC(c0, c1, c2, a[14], a[24]);+ MONT_MAC(s0, s1, s2, a[15], a[23]);+ MONT_MAC(c0, c1, c2, a[16], a[22]);+ MONT_MAC(s0, s1, s2, a[17], a[21]);+ MONT_MAC(c0, c1, c2, a[18], a[20]);+ MONT_MAC(t0, t1, t2, a[19], a[19]);+ MONT_MUL(v0, v1, v2, u[7], m[31]);+ MONT_MUL(w0, w1, w2, u[8], m[30]);+ MONT_MAC(t0, t1, t2, u[9], m[29]);+ MONT_MAC(v0, v1, v2, u[10], m[28]);+ MONT_MAC(w0, w1, w2, u[11], m[27]);+ MONT_MAC(t0, t1, t2, u[12], m[26]);+ MONT_MAC(v0, v1, v2, u[13], m[25]);+ MONT_MAC(w0, w1, w2, u[14], m[24]);+ MONT_MAC(t0, t1, t2, u[15], m[23]);+ MONT_MAC(v0, v1, v2, u[16], m[22]);+ MONT_MAC(w0, w1, w2, u[17], m[21]);+ MONT_MAC(t0, t1, t2, u[18], m[20]);+ MONT_MAC(v0, v1, v2, u[19], m[19]);+ MONT_MAC(w0, w1, w2, u[20], m[18]);+ MONT_MAC(t0, t1, t2, u[21], m[17]);+ MONT_MAC(v0, v1, v2, u[22], m[16]);+ MONT_MAC(w0, w1, w2, u[23], m[15]);+ MONT_MAC(t0, t1, t2, u[24], m[14]);+ MONT_MAC(v0, v1, v2, u[25], m[13]);+ MONT_MAC(w0, w1, w2, u[26], m[12]);+ MONT_MAC(t0, t1, t2, u[27], m[11]);+ MONT_MAC(v0, v1, v2, u[28], m[10]);+ MONT_MAC(w0, w1, w2, u[29], m[9]);+ MONT_MAC(t0, t1, t2, u[30], m[8]);+ MONT_MAC(v0, v1, v2, u[31], m[7]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[6] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 39 */+ MONT_MUL(s0, s1, s2, a[8], a[31]);+ MONT_MUL(c0, c1, c2, a[9], a[30]);+ MONT_MAC(s0, s1, s2, a[10], a[29]);+ MONT_MAC(c0, c1, c2, a[11], a[28]);+ MONT_MAC(s0, s1, s2, a[12], a[27]);+ MONT_MAC(c0, c1, c2, a[13], a[26]);+ MONT_MAC(s0, s1, s2, a[14], a[25]);+ MONT_MAC(c0, c1, c2, a[15], a[24]);+ MONT_MAC(s0, s1, s2, a[16], a[23]);+ MONT_MAC(c0, c1, c2, a[17], a[22]);+ MONT_MAC(s0, s1, s2, a[18], a[21]);+ MONT_MAC(c0, c1, c2, a[19], a[20]);+ MONT_MAC(t0, t1, t2, u[8], m[31]);+ MONT_MUL(v0, v1, v2, u[9], m[30]);+ MONT_MUL(w0, w1, w2, u[10], m[29]);+ MONT_MAC(t0, t1, t2, u[11], m[28]);+ MONT_MAC(v0, v1, v2, u[12], m[27]);+ MONT_MAC(w0, w1, w2, u[13], m[26]);+ MONT_MAC(t0, t1, t2, u[14], m[25]);+ MONT_MAC(v0, v1, v2, u[15], m[24]);+ MONT_MAC(w0, w1, w2, u[16], m[23]);+ MONT_MAC(t0, t1, t2, u[17], m[22]);+ MONT_MAC(v0, v1, v2, u[18], m[21]);+ MONT_MAC(w0, w1, w2, u[19], m[20]);+ MONT_MAC(t0, t1, t2, u[20], m[19]);+ MONT_MAC(v0, v1, v2, u[21], m[18]);+ MONT_MAC(w0, w1, w2, u[22], m[17]);+ MONT_MAC(t0, t1, t2, u[23], m[16]);+ MONT_MAC(v0, v1, v2, u[24], m[15]);+ MONT_MAC(w0, w1, w2, u[25], m[14]);+ MONT_MAC(t0, t1, t2, u[26], m[13]);+ MONT_MAC(v0, v1, v2, u[27], m[12]);+ MONT_MAC(w0, w1, w2, u[28], m[11]);+ MONT_MAC(t0, t1, t2, u[29], m[10]);+ MONT_MAC(v0, v1, v2, u[30], m[9]);+ MONT_MAC(w0, w1, w2, u[31], m[8]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[7] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 40 */+ MONT_MUL(s0, s1, s2, a[9], a[31]);+ MONT_MUL(c0, c1, c2, a[10], a[30]);+ MONT_MAC(s0, s1, s2, a[11], a[29]);+ MONT_MAC(c0, c1, c2, a[12], a[28]);+ MONT_MAC(s0, s1, s2, a[13], a[27]);+ MONT_MAC(c0, c1, c2, a[14], a[26]);+ MONT_MAC(s0, s1, s2, a[15], a[25]);+ MONT_MAC(c0, c1, c2, a[16], a[24]);+ MONT_MAC(s0, s1, s2, a[17], a[23]);+ MONT_MAC(c0, c1, c2, a[18], a[22]);+ MONT_MAC(s0, s1, s2, a[19], a[21]);+ MONT_MAC(t0, t1, t2, a[20], a[20]);+ MONT_MUL(v0, v1, v2, u[9], m[31]);+ MONT_MUL(w0, w1, w2, u[10], m[30]);+ MONT_MAC(t0, t1, t2, u[11], m[29]);+ MONT_MAC(v0, v1, v2, u[12], m[28]);+ MONT_MAC(w0, w1, w2, u[13], m[27]);+ MONT_MAC(t0, t1, t2, u[14], m[26]);+ MONT_MAC(v0, v1, v2, u[15], m[25]);+ MONT_MAC(w0, w1, w2, u[16], m[24]);+ MONT_MAC(t0, t1, t2, u[17], m[23]);+ MONT_MAC(v0, v1, v2, u[18], m[22]);+ MONT_MAC(w0, w1, w2, u[19], m[21]);+ MONT_MAC(t0, t1, t2, u[20], m[20]);+ MONT_MAC(v0, v1, v2, u[21], m[19]);+ MONT_MAC(w0, w1, w2, u[22], m[18]);+ MONT_MAC(t0, t1, t2, u[23], m[17]);+ MONT_MAC(v0, v1, v2, u[24], m[16]);+ MONT_MAC(w0, w1, w2, u[25], m[15]);+ MONT_MAC(t0, t1, t2, u[26], m[14]);+ MONT_MAC(v0, v1, v2, u[27], m[13]);+ MONT_MAC(w0, w1, w2, u[28], m[12]);+ MONT_MAC(t0, t1, t2, u[29], m[11]);+ MONT_MAC(v0, v1, v2, u[30], m[10]);+ MONT_MAC(w0, w1, w2, u[31], m[9]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[8] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 41 */+ MONT_MUL(s0, s1, s2, a[10], a[31]);+ MONT_MUL(c0, c1, c2, a[11], a[30]);+ MONT_MAC(s0, s1, s2, a[12], a[29]);+ MONT_MAC(c0, c1, c2, a[13], a[28]);+ MONT_MAC(s0, s1, s2, a[14], a[27]);+ MONT_MAC(c0, c1, c2, a[15], a[26]);+ MONT_MAC(s0, s1, s2, a[16], a[25]);+ MONT_MAC(c0, c1, c2, a[17], a[24]);+ MONT_MAC(s0, s1, s2, a[18], a[23]);+ MONT_MAC(c0, c1, c2, a[19], a[22]);+ MONT_MAC(s0, s1, s2, a[20], a[21]);+ MONT_MAC(t0, t1, t2, u[10], m[31]);+ MONT_MUL(v0, v1, v2, u[11], m[30]);+ MONT_MUL(w0, w1, w2, u[12], m[29]);+ MONT_MAC(t0, t1, t2, u[13], m[28]);+ MONT_MAC(v0, v1, v2, u[14], m[27]);+ MONT_MAC(w0, w1, w2, u[15], m[26]);+ MONT_MAC(t0, t1, t2, u[16], m[25]);+ MONT_MAC(v0, v1, v2, u[17], m[24]);+ MONT_MAC(w0, w1, w2, u[18], m[23]);+ MONT_MAC(t0, t1, t2, u[19], m[22]);+ MONT_MAC(v0, v1, v2, u[20], m[21]);+ MONT_MAC(w0, w1, w2, u[21], m[20]);+ MONT_MAC(t0, t1, t2, u[22], m[19]);+ MONT_MAC(v0, v1, v2, u[23], m[18]);+ MONT_MAC(w0, w1, w2, u[24], m[17]);+ MONT_MAC(t0, t1, t2, u[25], m[16]);+ MONT_MAC(v0, v1, v2, u[26], m[15]);+ MONT_MAC(w0, w1, w2, u[27], m[14]);+ MONT_MAC(t0, t1, t2, u[28], m[13]);+ MONT_MAC(v0, v1, v2, u[29], m[12]);+ MONT_MAC(w0, w1, w2, u[30], m[11]);+ MONT_MAC(t0, t1, t2, u[31], m[10]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[9] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 42 */+ MONT_MUL(s0, s1, s2, a[11], a[31]);+ MONT_MUL(c0, c1, c2, a[12], a[30]);+ MONT_MAC(s0, s1, s2, a[13], a[29]);+ MONT_MAC(c0, c1, c2, a[14], a[28]);+ MONT_MAC(s0, s1, s2, a[15], a[27]);+ MONT_MAC(c0, c1, c2, a[16], a[26]);+ MONT_MAC(s0, s1, s2, a[17], a[25]);+ MONT_MAC(c0, c1, c2, a[18], a[24]);+ MONT_MAC(s0, s1, s2, a[19], a[23]);+ MONT_MAC(c0, c1, c2, a[20], a[22]);+ MONT_MAC(t0, t1, t2, a[21], a[21]);+ MONT_MUL(v0, v1, v2, u[11], m[31]);+ MONT_MUL(w0, w1, w2, u[12], m[30]);+ MONT_MAC(t0, t1, t2, u[13], m[29]);+ MONT_MAC(v0, v1, v2, u[14], m[28]);+ MONT_MAC(w0, w1, w2, u[15], m[27]);+ MONT_MAC(t0, t1, t2, u[16], m[26]);+ MONT_MAC(v0, v1, v2, u[17], m[25]);+ MONT_MAC(w0, w1, w2, u[18], m[24]);+ MONT_MAC(t0, t1, t2, u[19], m[23]);+ MONT_MAC(v0, v1, v2, u[20], m[22]);+ MONT_MAC(w0, w1, w2, u[21], m[21]);+ MONT_MAC(t0, t1, t2, u[22], m[20]);+ MONT_MAC(v0, v1, v2, u[23], m[19]);+ MONT_MAC(w0, w1, w2, u[24], m[18]);+ MONT_MAC(t0, t1, t2, u[25], m[17]);+ MONT_MAC(v0, v1, v2, u[26], m[16]);+ MONT_MAC(w0, w1, w2, u[27], m[15]);+ MONT_MAC(t0, t1, t2, u[28], m[14]);+ MONT_MAC(v0, v1, v2, u[29], m[13]);+ MONT_MAC(w0, w1, w2, u[30], m[12]);+ MONT_MAC(t0, t1, t2, u[31], m[11]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[10] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 43 */+ MONT_MUL(s0, s1, s2, a[12], a[31]);+ MONT_MUL(c0, c1, c2, a[13], a[30]);+ MONT_MAC(s0, s1, s2, a[14], a[29]);+ MONT_MAC(c0, c1, c2, a[15], a[28]);+ MONT_MAC(s0, s1, s2, a[16], a[27]);+ MONT_MAC(c0, c1, c2, a[17], a[26]);+ MONT_MAC(s0, s1, s2, a[18], a[25]);+ MONT_MAC(c0, c1, c2, a[19], a[24]);+ MONT_MAC(s0, s1, s2, a[20], a[23]);+ MONT_MAC(c0, c1, c2, a[21], a[22]);+ MONT_MAC(t0, t1, t2, u[12], m[31]);+ MONT_MUL(v0, v1, v2, u[13], m[30]);+ MONT_MUL(w0, w1, w2, u[14], m[29]);+ MONT_MAC(t0, t1, t2, u[15], m[28]);+ MONT_MAC(v0, v1, v2, u[16], m[27]);+ MONT_MAC(w0, w1, w2, u[17], m[26]);+ MONT_MAC(t0, t1, t2, u[18], m[25]);+ MONT_MAC(v0, v1, v2, u[19], m[24]);+ MONT_MAC(w0, w1, w2, u[20], m[23]);+ MONT_MAC(t0, t1, t2, u[21], m[22]);+ MONT_MAC(v0, v1, v2, u[22], m[21]);+ MONT_MAC(w0, w1, w2, u[23], m[20]);+ MONT_MAC(t0, t1, t2, u[24], m[19]);+ MONT_MAC(v0, v1, v2, u[25], m[18]);+ MONT_MAC(w0, w1, w2, u[26], m[17]);+ MONT_MAC(t0, t1, t2, u[27], m[16]);+ MONT_MAC(v0, v1, v2, u[28], m[15]);+ MONT_MAC(w0, w1, w2, u[29], m[14]);+ MONT_MAC(t0, t1, t2, u[30], m[13]);+ MONT_MAC(v0, v1, v2, u[31], m[12]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[11] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 44 */+ MONT_MUL(s0, s1, s2, a[13], a[31]);+ MONT_MUL(c0, c1, c2, a[14], a[30]);+ MONT_MAC(s0, s1, s2, a[15], a[29]);+ MONT_MAC(c0, c1, c2, a[16], a[28]);+ MONT_MAC(s0, s1, s2, a[17], a[27]);+ MONT_MAC(c0, c1, c2, a[18], a[26]);+ MONT_MAC(s0, s1, s2, a[19], a[25]);+ MONT_MAC(c0, c1, c2, a[20], a[24]);+ MONT_MAC(s0, s1, s2, a[21], a[23]);+ MONT_MAC(t0, t1, t2, a[22], a[22]);+ MONT_MUL(v0, v1, v2, u[13], m[31]);+ MONT_MUL(w0, w1, w2, u[14], m[30]);+ MONT_MAC(t0, t1, t2, u[15], m[29]);+ MONT_MAC(v0, v1, v2, u[16], m[28]);+ MONT_MAC(w0, w1, w2, u[17], m[27]);+ MONT_MAC(t0, t1, t2, u[18], m[26]);+ MONT_MAC(v0, v1, v2, u[19], m[25]);+ MONT_MAC(w0, w1, w2, u[20], m[24]);+ MONT_MAC(t0, t1, t2, u[21], m[23]);+ MONT_MAC(v0, v1, v2, u[22], m[22]);+ MONT_MAC(w0, w1, w2, u[23], m[21]);+ MONT_MAC(t0, t1, t2, u[24], m[20]);+ MONT_MAC(v0, v1, v2, u[25], m[19]);+ MONT_MAC(w0, w1, w2, u[26], m[18]);+ MONT_MAC(t0, t1, t2, u[27], m[17]);+ MONT_MAC(v0, v1, v2, u[28], m[16]);+ MONT_MAC(w0, w1, w2, u[29], m[15]);+ MONT_MAC(t0, t1, t2, u[30], m[14]);+ MONT_MAC(v0, v1, v2, u[31], m[13]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[12] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 45 */+ MONT_MUL(s0, s1, s2, a[14], a[31]);+ MONT_MUL(c0, c1, c2, a[15], a[30]);+ MONT_MAC(s0, s1, s2, a[16], a[29]);+ MONT_MAC(c0, c1, c2, a[17], a[28]);+ MONT_MAC(s0, s1, s2, a[18], a[27]);+ MONT_MAC(c0, c1, c2, a[19], a[26]);+ MONT_MAC(s0, s1, s2, a[20], a[25]);+ MONT_MAC(c0, c1, c2, a[21], a[24]);+ MONT_MAC(s0, s1, s2, a[22], a[23]);+ MONT_MAC(t0, t1, t2, u[14], m[31]);+ MONT_MUL(v0, v1, v2, u[15], m[30]);+ MONT_MUL(w0, w1, w2, u[16], m[29]);+ MONT_MAC(t0, t1, t2, u[17], m[28]);+ MONT_MAC(v0, v1, v2, u[18], m[27]);+ MONT_MAC(w0, w1, w2, u[19], m[26]);+ MONT_MAC(t0, t1, t2, u[20], m[25]);+ MONT_MAC(v0, v1, v2, u[21], m[24]);+ MONT_MAC(w0, w1, w2, u[22], m[23]);+ MONT_MAC(t0, t1, t2, u[23], m[22]);+ MONT_MAC(v0, v1, v2, u[24], m[21]);+ MONT_MAC(w0, w1, w2, u[25], m[20]);+ MONT_MAC(t0, t1, t2, u[26], m[19]);+ MONT_MAC(v0, v1, v2, u[27], m[18]);+ MONT_MAC(w0, w1, w2, u[28], m[17]);+ MONT_MAC(t0, t1, t2, u[29], m[16]);+ MONT_MAC(v0, v1, v2, u[30], m[15]);+ MONT_MAC(w0, w1, w2, u[31], m[14]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[13] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 46 */+ MONT_MUL(s0, s1, s2, a[15], a[31]);+ MONT_MUL(c0, c1, c2, a[16], a[30]);+ MONT_MAC(s0, s1, s2, a[17], a[29]);+ MONT_MAC(c0, c1, c2, a[18], a[28]);+ MONT_MAC(s0, s1, s2, a[19], a[27]);+ MONT_MAC(c0, c1, c2, a[20], a[26]);+ MONT_MAC(s0, s1, s2, a[21], a[25]);+ MONT_MAC(c0, c1, c2, a[22], a[24]);+ MONT_MAC(t0, t1, t2, a[23], a[23]);+ MONT_MUL(v0, v1, v2, u[15], m[31]);+ MONT_MUL(w0, w1, w2, u[16], m[30]);+ MONT_MAC(t0, t1, t2, u[17], m[29]);+ MONT_MAC(v0, v1, v2, u[18], m[28]);+ MONT_MAC(w0, w1, w2, u[19], m[27]);+ MONT_MAC(t0, t1, t2, u[20], m[26]);+ MONT_MAC(v0, v1, v2, u[21], m[25]);+ MONT_MAC(w0, w1, w2, u[22], m[24]);+ MONT_MAC(t0, t1, t2, u[23], m[23]);+ MONT_MAC(v0, v1, v2, u[24], m[22]);+ MONT_MAC(w0, w1, w2, u[25], m[21]);+ MONT_MAC(t0, t1, t2, u[26], m[20]);+ MONT_MAC(v0, v1, v2, u[27], m[19]);+ MONT_MAC(w0, w1, w2, u[28], m[18]);+ MONT_MAC(t0, t1, t2, u[29], m[17]);+ MONT_MAC(v0, v1, v2, u[30], m[16]);+ MONT_MAC(w0, w1, w2, u[31], m[15]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[14] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 47 */+ MONT_MUL(s0, s1, s2, a[16], a[31]);+ MONT_MUL(c0, c1, c2, a[17], a[30]);+ MONT_MAC(s0, s1, s2, a[18], a[29]);+ MONT_MAC(c0, c1, c2, a[19], a[28]);+ MONT_MAC(s0, s1, s2, a[20], a[27]);+ MONT_MAC(c0, c1, c2, a[21], a[26]);+ MONT_MAC(s0, s1, s2, a[22], a[25]);+ MONT_MAC(c0, c1, c2, a[23], a[24]);+ MONT_MAC(t0, t1, t2, u[16], m[31]);+ MONT_MUL(v0, v1, v2, u[17], m[30]);+ MONT_MUL(w0, w1, w2, u[18], m[29]);+ MONT_MAC(t0, t1, t2, u[19], m[28]);+ MONT_MAC(v0, v1, v2, u[20], m[27]);+ MONT_MAC(w0, w1, w2, u[21], m[26]);+ MONT_MAC(t0, t1, t2, u[22], m[25]);+ MONT_MAC(v0, v1, v2, u[23], m[24]);+ MONT_MAC(w0, w1, w2, u[24], m[23]);+ MONT_MAC(t0, t1, t2, u[25], m[22]);+ MONT_MAC(v0, v1, v2, u[26], m[21]);+ MONT_MAC(w0, w1, w2, u[27], m[20]);+ MONT_MAC(t0, t1, t2, u[28], m[19]);+ MONT_MAC(v0, v1, v2, u[29], m[18]);+ MONT_MAC(w0, w1, w2, u[30], m[17]);+ MONT_MAC(t0, t1, t2, u[31], m[16]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[15] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 48 */+ MONT_MUL(s0, s1, s2, a[17], a[31]);+ MONT_MUL(c0, c1, c2, a[18], a[30]);+ MONT_MAC(s0, s1, s2, a[19], a[29]);+ MONT_MAC(c0, c1, c2, a[20], a[28]);+ MONT_MAC(s0, s1, s2, a[21], a[27]);+ MONT_MAC(c0, c1, c2, a[22], a[26]);+ MONT_MAC(s0, s1, s2, a[23], a[25]);+ MONT_MAC(t0, t1, t2, a[24], a[24]);+ MONT_MUL(v0, v1, v2, u[17], m[31]);+ MONT_MUL(w0, w1, w2, u[18], m[30]);+ MONT_MAC(t0, t1, t2, u[19], m[29]);+ MONT_MAC(v0, v1, v2, u[20], m[28]);+ MONT_MAC(w0, w1, w2, u[21], m[27]);+ MONT_MAC(t0, t1, t2, u[22], m[26]);+ MONT_MAC(v0, v1, v2, u[23], m[25]);+ MONT_MAC(w0, w1, w2, u[24], m[24]);+ MONT_MAC(t0, t1, t2, u[25], m[23]);+ MONT_MAC(v0, v1, v2, u[26], m[22]);+ MONT_MAC(w0, w1, w2, u[27], m[21]);+ MONT_MAC(t0, t1, t2, u[28], m[20]);+ MONT_MAC(v0, v1, v2, u[29], m[19]);+ MONT_MAC(w0, w1, w2, u[30], m[18]);+ MONT_MAC(t0, t1, t2, u[31], m[17]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[16] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 49 */+ MONT_MUL(s0, s1, s2, a[18], a[31]);+ MONT_MUL(c0, c1, c2, a[19], a[30]);+ MONT_MAC(s0, s1, s2, a[20], a[29]);+ MONT_MAC(c0, c1, c2, a[21], a[28]);+ MONT_MAC(s0, s1, s2, a[22], a[27]);+ MONT_MAC(c0, c1, c2, a[23], a[26]);+ MONT_MAC(s0, s1, s2, a[24], a[25]);+ MONT_MAC(t0, t1, t2, u[18], m[31]);+ MONT_MUL(v0, v1, v2, u[19], m[30]);+ MONT_MUL(w0, w1, w2, u[20], m[29]);+ MONT_MAC(t0, t1, t2, u[21], m[28]);+ MONT_MAC(v0, v1, v2, u[22], m[27]);+ MONT_MAC(w0, w1, w2, u[23], m[26]);+ MONT_MAC(t0, t1, t2, u[24], m[25]);+ MONT_MAC(v0, v1, v2, u[25], m[24]);+ MONT_MAC(w0, w1, w2, u[26], m[23]);+ MONT_MAC(t0, t1, t2, u[27], m[22]);+ MONT_MAC(v0, v1, v2, u[28], m[21]);+ MONT_MAC(w0, w1, w2, u[29], m[20]);+ MONT_MAC(t0, t1, t2, u[30], m[19]);+ MONT_MAC(v0, v1, v2, u[31], m[18]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[17] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 50 */+ MONT_MUL(s0, s1, s2, a[19], a[31]);+ MONT_MUL(c0, c1, c2, a[20], a[30]);+ MONT_MAC(s0, s1, s2, a[21], a[29]);+ MONT_MAC(c0, c1, c2, a[22], a[28]);+ MONT_MAC(s0, s1, s2, a[23], a[27]);+ MONT_MAC(c0, c1, c2, a[24], a[26]);+ MONT_MAC(t0, t1, t2, a[25], a[25]);+ MONT_MUL(v0, v1, v2, u[19], m[31]);+ MONT_MUL(w0, w1, w2, u[20], m[30]);+ MONT_MAC(t0, t1, t2, u[21], m[29]);+ MONT_MAC(v0, v1, v2, u[22], m[28]);+ MONT_MAC(w0, w1, w2, u[23], m[27]);+ MONT_MAC(t0, t1, t2, u[24], m[26]);+ MONT_MAC(v0, v1, v2, u[25], m[25]);+ MONT_MAC(w0, w1, w2, u[26], m[24]);+ MONT_MAC(t0, t1, t2, u[27], m[23]);+ MONT_MAC(v0, v1, v2, u[28], m[22]);+ MONT_MAC(w0, w1, w2, u[29], m[21]);+ MONT_MAC(t0, t1, t2, u[30], m[20]);+ MONT_MAC(v0, v1, v2, u[31], m[19]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[18] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 51 */+ MONT_MUL(s0, s1, s2, a[20], a[31]);+ MONT_MUL(c0, c1, c2, a[21], a[30]);+ MONT_MAC(s0, s1, s2, a[22], a[29]);+ MONT_MAC(c0, c1, c2, a[23], a[28]);+ MONT_MAC(s0, s1, s2, a[24], a[27]);+ MONT_MAC(c0, c1, c2, a[25], a[26]);+ MONT_MAC(t0, t1, t2, u[20], m[31]);+ MONT_MUL(v0, v1, v2, u[21], m[30]);+ MONT_MUL(w0, w1, w2, u[22], m[29]);+ MONT_MAC(t0, t1, t2, u[23], m[28]);+ MONT_MAC(v0, v1, v2, u[24], m[27]);+ MONT_MAC(w0, w1, w2, u[25], m[26]);+ MONT_MAC(t0, t1, t2, u[26], m[25]);+ MONT_MAC(v0, v1, v2, u[27], m[24]);+ MONT_MAC(w0, w1, w2, u[28], m[23]);+ MONT_MAC(t0, t1, t2, u[29], m[22]);+ MONT_MAC(v0, v1, v2, u[30], m[21]);+ MONT_MAC(w0, w1, w2, u[31], m[20]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[19] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 52 */+ MONT_MUL(s0, s1, s2, a[21], a[31]);+ MONT_MUL(c0, c1, c2, a[22], a[30]);+ MONT_MAC(s0, s1, s2, a[23], a[29]);+ MONT_MAC(c0, c1, c2, a[24], a[28]);+ MONT_MAC(s0, s1, s2, a[25], a[27]);+ MONT_MAC(t0, t1, t2, a[26], a[26]);+ MONT_MUL(v0, v1, v2, u[21], m[31]);+ MONT_MUL(w0, w1, w2, u[22], m[30]);+ MONT_MAC(t0, t1, t2, u[23], m[29]);+ MONT_MAC(v0, v1, v2, u[24], m[28]);+ MONT_MAC(w0, w1, w2, u[25], m[27]);+ MONT_MAC(t0, t1, t2, u[26], m[26]);+ MONT_MAC(v0, v1, v2, u[27], m[25]);+ MONT_MAC(w0, w1, w2, u[28], m[24]);+ MONT_MAC(t0, t1, t2, u[29], m[23]);+ MONT_MAC(v0, v1, v2, u[30], m[22]);+ MONT_MAC(w0, w1, w2, u[31], m[21]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[20] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 53 */+ MONT_MUL(s0, s1, s2, a[22], a[31]);+ MONT_MUL(c0, c1, c2, a[23], a[30]);+ MONT_MAC(s0, s1, s2, a[24], a[29]);+ MONT_MAC(c0, c1, c2, a[25], a[28]);+ MONT_MAC(s0, s1, s2, a[26], a[27]);+ MONT_MAC(t0, t1, t2, u[22], m[31]);+ MONT_MUL(v0, v1, v2, u[23], m[30]);+ MONT_MUL(w0, w1, w2, u[24], m[29]);+ MONT_MAC(t0, t1, t2, u[25], m[28]);+ MONT_MAC(v0, v1, v2, u[26], m[27]);+ MONT_MAC(w0, w1, w2, u[27], m[26]);+ MONT_MAC(t0, t1, t2, u[28], m[25]);+ MONT_MAC(v0, v1, v2, u[29], m[24]);+ MONT_MAC(w0, w1, w2, u[30], m[23]);+ MONT_MAC(t0, t1, t2, u[31], m[22]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[21] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 54 */+ MONT_MUL(s0, s1, s2, a[23], a[31]);+ MONT_MUL(c0, c1, c2, a[24], a[30]);+ MONT_MAC(s0, s1, s2, a[25], a[29]);+ MONT_MAC(c0, c1, c2, a[26], a[28]);+ MONT_MAC(t0, t1, t2, a[27], a[27]);+ MONT_MUL(v0, v1, v2, u[23], m[31]);+ MONT_MUL(w0, w1, w2, u[24], m[30]);+ MONT_MAC(t0, t1, t2, u[25], m[29]);+ MONT_MAC(v0, v1, v2, u[26], m[28]);+ MONT_MAC(w0, w1, w2, u[27], m[27]);+ MONT_MAC(t0, t1, t2, u[28], m[26]);+ MONT_MAC(v0, v1, v2, u[29], m[25]);+ MONT_MAC(w0, w1, w2, u[30], m[24]);+ MONT_MAC(t0, t1, t2, u[31], m[23]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[22] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 55 */+ MONT_MUL(s0, s1, s2, a[24], a[31]);+ MONT_MUL(c0, c1, c2, a[25], a[30]);+ MONT_MAC(s0, s1, s2, a[26], a[29]);+ MONT_MAC(c0, c1, c2, a[27], a[28]);+ MONT_MAC(t0, t1, t2, u[24], m[31]);+ MONT_MUL(v0, v1, v2, u[25], m[30]);+ MONT_MUL(w0, w1, w2, u[26], m[29]);+ MONT_MAC(t0, t1, t2, u[27], m[28]);+ MONT_MAC(v0, v1, v2, u[28], m[27]);+ MONT_MAC(w0, w1, w2, u[29], m[26]);+ MONT_MAC(t0, t1, t2, u[30], m[25]);+ MONT_MAC(v0, v1, v2, u[31], m[24]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[23] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 56 */+ MONT_MUL(s0, s1, s2, a[25], a[31]);+ MONT_MUL(c0, c1, c2, a[26], a[30]);+ MONT_MAC(s0, s1, s2, a[27], a[29]);+ MONT_MAC(t0, t1, t2, a[28], a[28]);+ MONT_MUL(v0, v1, v2, u[25], m[31]);+ MONT_MUL(w0, w1, w2, u[26], m[30]);+ MONT_MAC(t0, t1, t2, u[27], m[29]);+ MONT_MAC(v0, v1, v2, u[28], m[28]);+ MONT_MAC(w0, w1, w2, u[29], m[27]);+ MONT_MAC(t0, t1, t2, u[30], m[26]);+ MONT_MAC(v0, v1, v2, u[31], m[25]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[24] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 57 */+ MONT_MUL(s0, s1, s2, a[26], a[31]);+ MONT_MUL(c0, c1, c2, a[27], a[30]);+ MONT_MAC(s0, s1, s2, a[28], a[29]);+ MONT_MAC(t0, t1, t2, u[26], m[31]);+ MONT_MUL(v0, v1, v2, u[27], m[30]);+ MONT_MUL(w0, w1, w2, u[28], m[29]);+ MONT_MAC(t0, t1, t2, u[29], m[28]);+ MONT_MAC(v0, v1, v2, u[30], m[27]);+ MONT_MAC(w0, w1, w2, u[31], m[26]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[25] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 58 */+ MONT_MUL(s0, s1, s2, a[27], a[31]);+ MONT_MUL(c0, c1, c2, a[28], a[30]);+ MONT_MAC(t0, t1, t2, a[29], a[29]);+ MONT_MUL(v0, v1, v2, u[27], m[31]);+ MONT_MUL(w0, w1, w2, u[28], m[30]);+ MONT_MAC(t0, t1, t2, u[29], m[29]);+ MONT_MAC(v0, v1, v2, u[30], m[28]);+ MONT_MAC(w0, w1, w2, u[31], m[27]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[26] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 59 */+ MONT_MUL(s0, s1, s2, a[28], a[31]);+ MONT_MUL(c0, c1, c2, a[29], a[30]);+ MONT_MAC(t0, t1, t2, u[28], m[31]);+ MONT_MUL(v0, v1, v2, u[29], m[30]);+ MONT_MUL(w0, w1, w2, u[30], m[29]);+ MONT_MAC(t0, t1, t2, u[31], m[28]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[27] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 60 */+ MONT_MUL(s0, s1, s2, a[29], a[31]);+ MONT_MAC(t0, t1, t2, a[30], a[30]);+ MONT_MUL(v0, v1, v2, u[29], m[31]);+ MONT_MUL(w0, w1, w2, u[30], m[30]);+ MONT_MAC(t0, t1, t2, u[31], m[29]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[28] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 61 */+ MONT_MUL(s0, s1, s2, a[30], a[31]);+ MONT_MAC(t0, t1, t2, u[30], m[31]);+ MONT_MUL(v0, v1, v2, u[31], m[30]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[29] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 62 */+ MONT_MAC(t0, t1, t2, a[31], a[31]);+ MONT_MUL(v0, v1, v2, u[31], m[31]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ z[30] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ z[31] = t0;++ /* under 2m, with t1 the bit above n limbs: at most one subtraction */+ borrow = sub_n(r, z, m, 32);+ take = t1 | (borrow ^ 1);+ select_n(r, r, z, take & 1, 32);+}++/* r = a * a * R^-1 mod m, for a under m; t is 2n limbs of scratch */+static void crypton_mont_sqr48(limb_t *r, const limb_t *a,+ const limb_t *m, limb_t n0, limb_t *t)+{+ limb_t *u = t, *z = t + 48;+ limb_t t0 = 0, t1 = 0, t2 = 0, v0, v1, v2, w0, w1, w2, borrow, take;+ limb_t s0, s1, s2, c0, c1, c2;++ /* column 0 */+ MONT_MAC(t0, t1, t2, a[0], a[0]);+ u[0] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[0], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 1 */+ MONT_MUL(s0, s1, s2, a[0], a[1]);+ MONT_MAC(t0, t1, t2, u[0], m[1]);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[1] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[1], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 2 */+ MONT_MUL(s0, s1, s2, a[0], a[2]);+ MONT_MAC(t0, t1, t2, a[1], a[1]);+ MONT_MUL(v0, v1, v2, u[0], m[2]);+ MONT_MUL(w0, w1, w2, u[1], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[2] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[2], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 3 */+ MONT_MUL(s0, s1, s2, a[0], a[3]);+ MONT_MUL(c0, c1, c2, a[1], a[2]);+ MONT_MAC(t0, t1, t2, u[0], m[3]);+ MONT_MUL(v0, v1, v2, u[1], m[2]);+ MONT_MUL(w0, w1, w2, u[2], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[3] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[3], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 4 */+ MONT_MUL(s0, s1, s2, a[0], a[4]);+ MONT_MUL(c0, c1, c2, a[1], a[3]);+ MONT_MAC(t0, t1, t2, a[2], a[2]);+ MONT_MUL(v0, v1, v2, u[0], m[4]);+ MONT_MUL(w0, w1, w2, u[1], m[3]);+ MONT_MAC(t0, t1, t2, u[2], m[2]);+ MONT_MAC(v0, v1, v2, u[3], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[4] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[4], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 5 */+ MONT_MUL(s0, s1, s2, a[0], a[5]);+ MONT_MUL(c0, c1, c2, a[1], a[4]);+ MONT_MAC(s0, s1, s2, a[2], a[3]);+ MONT_MAC(t0, t1, t2, u[0], m[5]);+ MONT_MUL(v0, v1, v2, u[1], m[4]);+ MONT_MUL(w0, w1, w2, u[2], m[3]);+ MONT_MAC(t0, t1, t2, u[3], m[2]);+ MONT_MAC(v0, v1, v2, u[4], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[5] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[5], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 6 */+ MONT_MUL(s0, s1, s2, a[0], a[6]);+ MONT_MUL(c0, c1, c2, a[1], a[5]);+ MONT_MAC(s0, s1, s2, a[2], a[4]);+ MONT_MAC(t0, t1, t2, a[3], a[3]);+ MONT_MUL(v0, v1, v2, u[0], m[6]);+ MONT_MUL(w0, w1, w2, u[1], m[5]);+ MONT_MAC(t0, t1, t2, u[2], m[4]);+ MONT_MAC(v0, v1, v2, u[3], m[3]);+ MONT_MAC(w0, w1, w2, u[4], m[2]);+ MONT_MAC(t0, t1, t2, u[5], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[6] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[6], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 7 */+ MONT_MUL(s0, s1, s2, a[0], a[7]);+ MONT_MUL(c0, c1, c2, a[1], a[6]);+ MONT_MAC(s0, s1, s2, a[2], a[5]);+ MONT_MAC(c0, c1, c2, a[3], a[4]);+ MONT_MAC(t0, t1, t2, u[0], m[7]);+ MONT_MUL(v0, v1, v2, u[1], m[6]);+ MONT_MUL(w0, w1, w2, u[2], m[5]);+ MONT_MAC(t0, t1, t2, u[3], m[4]);+ MONT_MAC(v0, v1, v2, u[4], m[3]);+ MONT_MAC(w0, w1, w2, u[5], m[2]);+ MONT_MAC(t0, t1, t2, u[6], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[7] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[7], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 8 */+ MONT_MUL(s0, s1, s2, a[0], a[8]);+ MONT_MUL(c0, c1, c2, a[1], a[7]);+ MONT_MAC(s0, s1, s2, a[2], a[6]);+ MONT_MAC(c0, c1, c2, a[3], a[5]);+ MONT_MAC(t0, t1, t2, a[4], a[4]);+ MONT_MUL(v0, v1, v2, u[0], m[8]);+ MONT_MUL(w0, w1, w2, u[1], m[7]);+ MONT_MAC(t0, t1, t2, u[2], m[6]);+ MONT_MAC(v0, v1, v2, u[3], m[5]);+ MONT_MAC(w0, w1, w2, u[4], m[4]);+ MONT_MAC(t0, t1, t2, u[5], m[3]);+ MONT_MAC(v0, v1, v2, u[6], m[2]);+ MONT_MAC(w0, w1, w2, u[7], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[8] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[8], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 9 */+ MONT_MUL(s0, s1, s2, a[0], a[9]);+ MONT_MUL(c0, c1, c2, a[1], a[8]);+ MONT_MAC(s0, s1, s2, a[2], a[7]);+ MONT_MAC(c0, c1, c2, a[3], a[6]);+ MONT_MAC(s0, s1, s2, a[4], a[5]);+ MONT_MAC(t0, t1, t2, u[0], m[9]);+ MONT_MUL(v0, v1, v2, u[1], m[8]);+ MONT_MUL(w0, w1, w2, u[2], m[7]);+ MONT_MAC(t0, t1, t2, u[3], m[6]);+ MONT_MAC(v0, v1, v2, u[4], m[5]);+ MONT_MAC(w0, w1, w2, u[5], m[4]);+ MONT_MAC(t0, t1, t2, u[6], m[3]);+ MONT_MAC(v0, v1, v2, u[7], m[2]);+ MONT_MAC(w0, w1, w2, u[8], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[9] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[9], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 10 */+ MONT_MUL(s0, s1, s2, a[0], a[10]);+ MONT_MUL(c0, c1, c2, a[1], a[9]);+ MONT_MAC(s0, s1, s2, a[2], a[8]);+ MONT_MAC(c0, c1, c2, a[3], a[7]);+ MONT_MAC(s0, s1, s2, a[4], a[6]);+ MONT_MAC(t0, t1, t2, a[5], a[5]);+ MONT_MUL(v0, v1, v2, u[0], m[10]);+ MONT_MUL(w0, w1, w2, u[1], m[9]);+ MONT_MAC(t0, t1, t2, u[2], m[8]);+ MONT_MAC(v0, v1, v2, u[3], m[7]);+ MONT_MAC(w0, w1, w2, u[4], m[6]);+ MONT_MAC(t0, t1, t2, u[5], m[5]);+ MONT_MAC(v0, v1, v2, u[6], m[4]);+ MONT_MAC(w0, w1, w2, u[7], m[3]);+ MONT_MAC(t0, t1, t2, u[8], m[2]);+ MONT_MAC(v0, v1, v2, u[9], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[10] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[10], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 11 */+ MONT_MUL(s0, s1, s2, a[0], a[11]);+ MONT_MUL(c0, c1, c2, a[1], a[10]);+ MONT_MAC(s0, s1, s2, a[2], a[9]);+ MONT_MAC(c0, c1, c2, a[3], a[8]);+ MONT_MAC(s0, s1, s2, a[4], a[7]);+ MONT_MAC(c0, c1, c2, a[5], a[6]);+ MONT_MAC(t0, t1, t2, u[0], m[11]);+ MONT_MUL(v0, v1, v2, u[1], m[10]);+ MONT_MUL(w0, w1, w2, u[2], m[9]);+ MONT_MAC(t0, t1, t2, u[3], m[8]);+ MONT_MAC(v0, v1, v2, u[4], m[7]);+ MONT_MAC(w0, w1, w2, u[5], m[6]);+ MONT_MAC(t0, t1, t2, u[6], m[5]);+ MONT_MAC(v0, v1, v2, u[7], m[4]);+ MONT_MAC(w0, w1, w2, u[8], m[3]);+ MONT_MAC(t0, t1, t2, u[9], m[2]);+ MONT_MAC(v0, v1, v2, u[10], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[11] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[11], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 12 */+ MONT_MUL(s0, s1, s2, a[0], a[12]);+ MONT_MUL(c0, c1, c2, a[1], a[11]);+ MONT_MAC(s0, s1, s2, a[2], a[10]);+ MONT_MAC(c0, c1, c2, a[3], a[9]);+ MONT_MAC(s0, s1, s2, a[4], a[8]);+ MONT_MAC(c0, c1, c2, a[5], a[7]);+ MONT_MAC(t0, t1, t2, a[6], a[6]);+ MONT_MUL(v0, v1, v2, u[0], m[12]);+ MONT_MUL(w0, w1, w2, u[1], m[11]);+ MONT_MAC(t0, t1, t2, u[2], m[10]);+ MONT_MAC(v0, v1, v2, u[3], m[9]);+ MONT_MAC(w0, w1, w2, u[4], m[8]);+ MONT_MAC(t0, t1, t2, u[5], m[7]);+ MONT_MAC(v0, v1, v2, u[6], m[6]);+ MONT_MAC(w0, w1, w2, u[7], m[5]);+ MONT_MAC(t0, t1, t2, u[8], m[4]);+ MONT_MAC(v0, v1, v2, u[9], m[3]);+ MONT_MAC(w0, w1, w2, u[10], m[2]);+ MONT_MAC(t0, t1, t2, u[11], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[12] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[12], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 13 */+ MONT_MUL(s0, s1, s2, a[0], a[13]);+ MONT_MUL(c0, c1, c2, a[1], a[12]);+ MONT_MAC(s0, s1, s2, a[2], a[11]);+ MONT_MAC(c0, c1, c2, a[3], a[10]);+ MONT_MAC(s0, s1, s2, a[4], a[9]);+ MONT_MAC(c0, c1, c2, a[5], a[8]);+ MONT_MAC(s0, s1, s2, a[6], a[7]);+ MONT_MAC(t0, t1, t2, u[0], m[13]);+ MONT_MUL(v0, v1, v2, u[1], m[12]);+ MONT_MUL(w0, w1, w2, u[2], m[11]);+ MONT_MAC(t0, t1, t2, u[3], m[10]);+ MONT_MAC(v0, v1, v2, u[4], m[9]);+ MONT_MAC(w0, w1, w2, u[5], m[8]);+ MONT_MAC(t0, t1, t2, u[6], m[7]);+ MONT_MAC(v0, v1, v2, u[7], m[6]);+ MONT_MAC(w0, w1, w2, u[8], m[5]);+ MONT_MAC(t0, t1, t2, u[9], m[4]);+ MONT_MAC(v0, v1, v2, u[10], m[3]);+ MONT_MAC(w0, w1, w2, u[11], m[2]);+ MONT_MAC(t0, t1, t2, u[12], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[13] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[13], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 14 */+ MONT_MUL(s0, s1, s2, a[0], a[14]);+ MONT_MUL(c0, c1, c2, a[1], a[13]);+ MONT_MAC(s0, s1, s2, a[2], a[12]);+ MONT_MAC(c0, c1, c2, a[3], a[11]);+ MONT_MAC(s0, s1, s2, a[4], a[10]);+ MONT_MAC(c0, c1, c2, a[5], a[9]);+ MONT_MAC(s0, s1, s2, a[6], a[8]);+ MONT_MAC(t0, t1, t2, a[7], a[7]);+ MONT_MUL(v0, v1, v2, u[0], m[14]);+ MONT_MUL(w0, w1, w2, u[1], m[13]);+ MONT_MAC(t0, t1, t2, u[2], m[12]);+ MONT_MAC(v0, v1, v2, u[3], m[11]);+ MONT_MAC(w0, w1, w2, u[4], m[10]);+ MONT_MAC(t0, t1, t2, u[5], m[9]);+ MONT_MAC(v0, v1, v2, u[6], m[8]);+ MONT_MAC(w0, w1, w2, u[7], m[7]);+ MONT_MAC(t0, t1, t2, u[8], m[6]);+ MONT_MAC(v0, v1, v2, u[9], m[5]);+ MONT_MAC(w0, w1, w2, u[10], m[4]);+ MONT_MAC(t0, t1, t2, u[11], m[3]);+ MONT_MAC(v0, v1, v2, u[12], m[2]);+ MONT_MAC(w0, w1, w2, u[13], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[14] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[14], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 15 */+ MONT_MUL(s0, s1, s2, a[0], a[15]);+ MONT_MUL(c0, c1, c2, a[1], a[14]);+ MONT_MAC(s0, s1, s2, a[2], a[13]);+ MONT_MAC(c0, c1, c2, a[3], a[12]);+ MONT_MAC(s0, s1, s2, a[4], a[11]);+ MONT_MAC(c0, c1, c2, a[5], a[10]);+ MONT_MAC(s0, s1, s2, a[6], a[9]);+ MONT_MAC(c0, c1, c2, a[7], a[8]);+ MONT_MAC(t0, t1, t2, u[0], m[15]);+ MONT_MUL(v0, v1, v2, u[1], m[14]);+ MONT_MUL(w0, w1, w2, u[2], m[13]);+ MONT_MAC(t0, t1, t2, u[3], m[12]);+ MONT_MAC(v0, v1, v2, u[4], m[11]);+ MONT_MAC(w0, w1, w2, u[5], m[10]);+ MONT_MAC(t0, t1, t2, u[6], m[9]);+ MONT_MAC(v0, v1, v2, u[7], m[8]);+ MONT_MAC(w0, w1, w2, u[8], m[7]);+ MONT_MAC(t0, t1, t2, u[9], m[6]);+ MONT_MAC(v0, v1, v2, u[10], m[5]);+ MONT_MAC(w0, w1, w2, u[11], m[4]);+ MONT_MAC(t0, t1, t2, u[12], m[3]);+ MONT_MAC(v0, v1, v2, u[13], m[2]);+ MONT_MAC(w0, w1, w2, u[14], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[15] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[15], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 16 */+ MONT_MUL(s0, s1, s2, a[0], a[16]);+ MONT_MUL(c0, c1, c2, a[1], a[15]);+ MONT_MAC(s0, s1, s2, a[2], a[14]);+ MONT_MAC(c0, c1, c2, a[3], a[13]);+ MONT_MAC(s0, s1, s2, a[4], a[12]);+ MONT_MAC(c0, c1, c2, a[5], a[11]);+ MONT_MAC(s0, s1, s2, a[6], a[10]);+ MONT_MAC(c0, c1, c2, a[7], a[9]);+ MONT_MAC(t0, t1, t2, a[8], a[8]);+ MONT_MUL(v0, v1, v2, u[0], m[16]);+ MONT_MUL(w0, w1, w2, u[1], m[15]);+ MONT_MAC(t0, t1, t2, u[2], m[14]);+ MONT_MAC(v0, v1, v2, u[3], m[13]);+ MONT_MAC(w0, w1, w2, u[4], m[12]);+ MONT_MAC(t0, t1, t2, u[5], m[11]);+ MONT_MAC(v0, v1, v2, u[6], m[10]);+ MONT_MAC(w0, w1, w2, u[7], m[9]);+ MONT_MAC(t0, t1, t2, u[8], m[8]);+ MONT_MAC(v0, v1, v2, u[9], m[7]);+ MONT_MAC(w0, w1, w2, u[10], m[6]);+ MONT_MAC(t0, t1, t2, u[11], m[5]);+ MONT_MAC(v0, v1, v2, u[12], m[4]);+ MONT_MAC(w0, w1, w2, u[13], m[3]);+ MONT_MAC(t0, t1, t2, u[14], m[2]);+ MONT_MAC(v0, v1, v2, u[15], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[16] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[16], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 17 */+ MONT_MUL(s0, s1, s2, a[0], a[17]);+ MONT_MUL(c0, c1, c2, a[1], a[16]);+ MONT_MAC(s0, s1, s2, a[2], a[15]);+ MONT_MAC(c0, c1, c2, a[3], a[14]);+ MONT_MAC(s0, s1, s2, a[4], a[13]);+ MONT_MAC(c0, c1, c2, a[5], a[12]);+ MONT_MAC(s0, s1, s2, a[6], a[11]);+ MONT_MAC(c0, c1, c2, a[7], a[10]);+ MONT_MAC(s0, s1, s2, a[8], a[9]);+ MONT_MAC(t0, t1, t2, u[0], m[17]);+ MONT_MUL(v0, v1, v2, u[1], m[16]);+ MONT_MUL(w0, w1, w2, u[2], m[15]);+ MONT_MAC(t0, t1, t2, u[3], m[14]);+ MONT_MAC(v0, v1, v2, u[4], m[13]);+ MONT_MAC(w0, w1, w2, u[5], m[12]);+ MONT_MAC(t0, t1, t2, u[6], m[11]);+ MONT_MAC(v0, v1, v2, u[7], m[10]);+ MONT_MAC(w0, w1, w2, u[8], m[9]);+ MONT_MAC(t0, t1, t2, u[9], m[8]);+ MONT_MAC(v0, v1, v2, u[10], m[7]);+ MONT_MAC(w0, w1, w2, u[11], m[6]);+ MONT_MAC(t0, t1, t2, u[12], m[5]);+ MONT_MAC(v0, v1, v2, u[13], m[4]);+ MONT_MAC(w0, w1, w2, u[14], m[3]);+ MONT_MAC(t0, t1, t2, u[15], m[2]);+ MONT_MAC(v0, v1, v2, u[16], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[17] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[17], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 18 */+ MONT_MUL(s0, s1, s2, a[0], a[18]);+ MONT_MUL(c0, c1, c2, a[1], a[17]);+ MONT_MAC(s0, s1, s2, a[2], a[16]);+ MONT_MAC(c0, c1, c2, a[3], a[15]);+ MONT_MAC(s0, s1, s2, a[4], a[14]);+ MONT_MAC(c0, c1, c2, a[5], a[13]);+ MONT_MAC(s0, s1, s2, a[6], a[12]);+ MONT_MAC(c0, c1, c2, a[7], a[11]);+ MONT_MAC(s0, s1, s2, a[8], a[10]);+ MONT_MAC(t0, t1, t2, a[9], a[9]);+ MONT_MUL(v0, v1, v2, u[0], m[18]);+ MONT_MUL(w0, w1, w2, u[1], m[17]);+ MONT_MAC(t0, t1, t2, u[2], m[16]);+ MONT_MAC(v0, v1, v2, u[3], m[15]);+ MONT_MAC(w0, w1, w2, u[4], m[14]);+ MONT_MAC(t0, t1, t2, u[5], m[13]);+ MONT_MAC(v0, v1, v2, u[6], m[12]);+ MONT_MAC(w0, w1, w2, u[7], m[11]);+ MONT_MAC(t0, t1, t2, u[8], m[10]);+ MONT_MAC(v0, v1, v2, u[9], m[9]);+ MONT_MAC(w0, w1, w2, u[10], m[8]);+ MONT_MAC(t0, t1, t2, u[11], m[7]);+ MONT_MAC(v0, v1, v2, u[12], m[6]);+ MONT_MAC(w0, w1, w2, u[13], m[5]);+ MONT_MAC(t0, t1, t2, u[14], m[4]);+ MONT_MAC(v0, v1, v2, u[15], m[3]);+ MONT_MAC(w0, w1, w2, u[16], m[2]);+ MONT_MAC(t0, t1, t2, u[17], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[18] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[18], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 19 */+ MONT_MUL(s0, s1, s2, a[0], a[19]);+ MONT_MUL(c0, c1, c2, a[1], a[18]);+ MONT_MAC(s0, s1, s2, a[2], a[17]);+ MONT_MAC(c0, c1, c2, a[3], a[16]);+ MONT_MAC(s0, s1, s2, a[4], a[15]);+ MONT_MAC(c0, c1, c2, a[5], a[14]);+ MONT_MAC(s0, s1, s2, a[6], a[13]);+ MONT_MAC(c0, c1, c2, a[7], a[12]);+ MONT_MAC(s0, s1, s2, a[8], a[11]);+ MONT_MAC(c0, c1, c2, a[9], a[10]);+ MONT_MAC(t0, t1, t2, u[0], m[19]);+ MONT_MUL(v0, v1, v2, u[1], m[18]);+ MONT_MUL(w0, w1, w2, u[2], m[17]);+ MONT_MAC(t0, t1, t2, u[3], m[16]);+ MONT_MAC(v0, v1, v2, u[4], m[15]);+ MONT_MAC(w0, w1, w2, u[5], m[14]);+ MONT_MAC(t0, t1, t2, u[6], m[13]);+ MONT_MAC(v0, v1, v2, u[7], m[12]);+ MONT_MAC(w0, w1, w2, u[8], m[11]);+ MONT_MAC(t0, t1, t2, u[9], m[10]);+ MONT_MAC(v0, v1, v2, u[10], m[9]);+ MONT_MAC(w0, w1, w2, u[11], m[8]);+ MONT_MAC(t0, t1, t2, u[12], m[7]);+ MONT_MAC(v0, v1, v2, u[13], m[6]);+ MONT_MAC(w0, w1, w2, u[14], m[5]);+ MONT_MAC(t0, t1, t2, u[15], m[4]);+ MONT_MAC(v0, v1, v2, u[16], m[3]);+ MONT_MAC(w0, w1, w2, u[17], m[2]);+ MONT_MAC(t0, t1, t2, u[18], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[19] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[19], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 20 */+ MONT_MUL(s0, s1, s2, a[0], a[20]);+ MONT_MUL(c0, c1, c2, a[1], a[19]);+ MONT_MAC(s0, s1, s2, a[2], a[18]);+ MONT_MAC(c0, c1, c2, a[3], a[17]);+ MONT_MAC(s0, s1, s2, a[4], a[16]);+ MONT_MAC(c0, c1, c2, a[5], a[15]);+ MONT_MAC(s0, s1, s2, a[6], a[14]);+ MONT_MAC(c0, c1, c2, a[7], a[13]);+ MONT_MAC(s0, s1, s2, a[8], a[12]);+ MONT_MAC(c0, c1, c2, a[9], a[11]);+ MONT_MAC(t0, t1, t2, a[10], a[10]);+ MONT_MUL(v0, v1, v2, u[0], m[20]);+ MONT_MUL(w0, w1, w2, u[1], m[19]);+ MONT_MAC(t0, t1, t2, u[2], m[18]);+ MONT_MAC(v0, v1, v2, u[3], m[17]);+ MONT_MAC(w0, w1, w2, u[4], m[16]);+ MONT_MAC(t0, t1, t2, u[5], m[15]);+ MONT_MAC(v0, v1, v2, u[6], m[14]);+ MONT_MAC(w0, w1, w2, u[7], m[13]);+ MONT_MAC(t0, t1, t2, u[8], m[12]);+ MONT_MAC(v0, v1, v2, u[9], m[11]);+ MONT_MAC(w0, w1, w2, u[10], m[10]);+ MONT_MAC(t0, t1, t2, u[11], m[9]);+ MONT_MAC(v0, v1, v2, u[12], m[8]);+ MONT_MAC(w0, w1, w2, u[13], m[7]);+ MONT_MAC(t0, t1, t2, u[14], m[6]);+ MONT_MAC(v0, v1, v2, u[15], m[5]);+ MONT_MAC(w0, w1, w2, u[16], m[4]);+ MONT_MAC(t0, t1, t2, u[17], m[3]);+ MONT_MAC(v0, v1, v2, u[18], m[2]);+ MONT_MAC(w0, w1, w2, u[19], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[20] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[20], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 21 */+ MONT_MUL(s0, s1, s2, a[0], a[21]);+ MONT_MUL(c0, c1, c2, a[1], a[20]);+ MONT_MAC(s0, s1, s2, a[2], a[19]);+ MONT_MAC(c0, c1, c2, a[3], a[18]);+ MONT_MAC(s0, s1, s2, a[4], a[17]);+ MONT_MAC(c0, c1, c2, a[5], a[16]);+ MONT_MAC(s0, s1, s2, a[6], a[15]);+ MONT_MAC(c0, c1, c2, a[7], a[14]);+ MONT_MAC(s0, s1, s2, a[8], a[13]);+ MONT_MAC(c0, c1, c2, a[9], a[12]);+ MONT_MAC(s0, s1, s2, a[10], a[11]);+ MONT_MAC(t0, t1, t2, u[0], m[21]);+ MONT_MUL(v0, v1, v2, u[1], m[20]);+ MONT_MUL(w0, w1, w2, u[2], m[19]);+ MONT_MAC(t0, t1, t2, u[3], m[18]);+ MONT_MAC(v0, v1, v2, u[4], m[17]);+ MONT_MAC(w0, w1, w2, u[5], m[16]);+ MONT_MAC(t0, t1, t2, u[6], m[15]);+ MONT_MAC(v0, v1, v2, u[7], m[14]);+ MONT_MAC(w0, w1, w2, u[8], m[13]);+ MONT_MAC(t0, t1, t2, u[9], m[12]);+ MONT_MAC(v0, v1, v2, u[10], m[11]);+ MONT_MAC(w0, w1, w2, u[11], m[10]);+ MONT_MAC(t0, t1, t2, u[12], m[9]);+ MONT_MAC(v0, v1, v2, u[13], m[8]);+ MONT_MAC(w0, w1, w2, u[14], m[7]);+ MONT_MAC(t0, t1, t2, u[15], m[6]);+ MONT_MAC(v0, v1, v2, u[16], m[5]);+ MONT_MAC(w0, w1, w2, u[17], m[4]);+ MONT_MAC(t0, t1, t2, u[18], m[3]);+ MONT_MAC(v0, v1, v2, u[19], m[2]);+ MONT_MAC(w0, w1, w2, u[20], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[21] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[21], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 22 */+ MONT_MUL(s0, s1, s2, a[0], a[22]);+ MONT_MUL(c0, c1, c2, a[1], a[21]);+ MONT_MAC(s0, s1, s2, a[2], a[20]);+ MONT_MAC(c0, c1, c2, a[3], a[19]);+ MONT_MAC(s0, s1, s2, a[4], a[18]);+ MONT_MAC(c0, c1, c2, a[5], a[17]);+ MONT_MAC(s0, s1, s2, a[6], a[16]);+ MONT_MAC(c0, c1, c2, a[7], a[15]);+ MONT_MAC(s0, s1, s2, a[8], a[14]);+ MONT_MAC(c0, c1, c2, a[9], a[13]);+ MONT_MAC(s0, s1, s2, a[10], a[12]);+ MONT_MAC(t0, t1, t2, a[11], a[11]);+ MONT_MUL(v0, v1, v2, u[0], m[22]);+ MONT_MUL(w0, w1, w2, u[1], m[21]);+ MONT_MAC(t0, t1, t2, u[2], m[20]);+ MONT_MAC(v0, v1, v2, u[3], m[19]);+ MONT_MAC(w0, w1, w2, u[4], m[18]);+ MONT_MAC(t0, t1, t2, u[5], m[17]);+ MONT_MAC(v0, v1, v2, u[6], m[16]);+ MONT_MAC(w0, w1, w2, u[7], m[15]);+ MONT_MAC(t0, t1, t2, u[8], m[14]);+ MONT_MAC(v0, v1, v2, u[9], m[13]);+ MONT_MAC(w0, w1, w2, u[10], m[12]);+ MONT_MAC(t0, t1, t2, u[11], m[11]);+ MONT_MAC(v0, v1, v2, u[12], m[10]);+ MONT_MAC(w0, w1, w2, u[13], m[9]);+ MONT_MAC(t0, t1, t2, u[14], m[8]);+ MONT_MAC(v0, v1, v2, u[15], m[7]);+ MONT_MAC(w0, w1, w2, u[16], m[6]);+ MONT_MAC(t0, t1, t2, u[17], m[5]);+ MONT_MAC(v0, v1, v2, u[18], m[4]);+ MONT_MAC(w0, w1, w2, u[19], m[3]);+ MONT_MAC(t0, t1, t2, u[20], m[2]);+ MONT_MAC(v0, v1, v2, u[21], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[22] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[22], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 23 */+ MONT_MUL(s0, s1, s2, a[0], a[23]);+ MONT_MUL(c0, c1, c2, a[1], a[22]);+ MONT_MAC(s0, s1, s2, a[2], a[21]);+ MONT_MAC(c0, c1, c2, a[3], a[20]);+ MONT_MAC(s0, s1, s2, a[4], a[19]);+ MONT_MAC(c0, c1, c2, a[5], a[18]);+ MONT_MAC(s0, s1, s2, a[6], a[17]);+ MONT_MAC(c0, c1, c2, a[7], a[16]);+ MONT_MAC(s0, s1, s2, a[8], a[15]);+ MONT_MAC(c0, c1, c2, a[9], a[14]);+ MONT_MAC(s0, s1, s2, a[10], a[13]);+ MONT_MAC(c0, c1, c2, a[11], a[12]);+ MONT_MAC(t0, t1, t2, u[0], m[23]);+ MONT_MUL(v0, v1, v2, u[1], m[22]);+ MONT_MUL(w0, w1, w2, u[2], m[21]);+ MONT_MAC(t0, t1, t2, u[3], m[20]);+ MONT_MAC(v0, v1, v2, u[4], m[19]);+ MONT_MAC(w0, w1, w2, u[5], m[18]);+ MONT_MAC(t0, t1, t2, u[6], m[17]);+ MONT_MAC(v0, v1, v2, u[7], m[16]);+ MONT_MAC(w0, w1, w2, u[8], m[15]);+ MONT_MAC(t0, t1, t2, u[9], m[14]);+ MONT_MAC(v0, v1, v2, u[10], m[13]);+ MONT_MAC(w0, w1, w2, u[11], m[12]);+ MONT_MAC(t0, t1, t2, u[12], m[11]);+ MONT_MAC(v0, v1, v2, u[13], m[10]);+ MONT_MAC(w0, w1, w2, u[14], m[9]);+ MONT_MAC(t0, t1, t2, u[15], m[8]);+ MONT_MAC(v0, v1, v2, u[16], m[7]);+ MONT_MAC(w0, w1, w2, u[17], m[6]);+ MONT_MAC(t0, t1, t2, u[18], m[5]);+ MONT_MAC(v0, v1, v2, u[19], m[4]);+ MONT_MAC(w0, w1, w2, u[20], m[3]);+ MONT_MAC(t0, t1, t2, u[21], m[2]);+ MONT_MAC(v0, v1, v2, u[22], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[23] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[23], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 24 */+ MONT_MUL(s0, s1, s2, a[0], a[24]);+ MONT_MUL(c0, c1, c2, a[1], a[23]);+ MONT_MAC(s0, s1, s2, a[2], a[22]);+ MONT_MAC(c0, c1, c2, a[3], a[21]);+ MONT_MAC(s0, s1, s2, a[4], a[20]);+ MONT_MAC(c0, c1, c2, a[5], a[19]);+ MONT_MAC(s0, s1, s2, a[6], a[18]);+ MONT_MAC(c0, c1, c2, a[7], a[17]);+ MONT_MAC(s0, s1, s2, a[8], a[16]);+ MONT_MAC(c0, c1, c2, a[9], a[15]);+ MONT_MAC(s0, s1, s2, a[10], a[14]);+ MONT_MAC(c0, c1, c2, a[11], a[13]);+ MONT_MAC(t0, t1, t2, a[12], a[12]);+ MONT_MUL(v0, v1, v2, u[0], m[24]);+ MONT_MUL(w0, w1, w2, u[1], m[23]);+ MONT_MAC(t0, t1, t2, u[2], m[22]);+ MONT_MAC(v0, v1, v2, u[3], m[21]);+ MONT_MAC(w0, w1, w2, u[4], m[20]);+ MONT_MAC(t0, t1, t2, u[5], m[19]);+ MONT_MAC(v0, v1, v2, u[6], m[18]);+ MONT_MAC(w0, w1, w2, u[7], m[17]);+ MONT_MAC(t0, t1, t2, u[8], m[16]);+ MONT_MAC(v0, v1, v2, u[9], m[15]);+ MONT_MAC(w0, w1, w2, u[10], m[14]);+ MONT_MAC(t0, t1, t2, u[11], m[13]);+ MONT_MAC(v0, v1, v2, u[12], m[12]);+ MONT_MAC(w0, w1, w2, u[13], m[11]);+ MONT_MAC(t0, t1, t2, u[14], m[10]);+ MONT_MAC(v0, v1, v2, u[15], m[9]);+ MONT_MAC(w0, w1, w2, u[16], m[8]);+ MONT_MAC(t0, t1, t2, u[17], m[7]);+ MONT_MAC(v0, v1, v2, u[18], m[6]);+ MONT_MAC(w0, w1, w2, u[19], m[5]);+ MONT_MAC(t0, t1, t2, u[20], m[4]);+ MONT_MAC(v0, v1, v2, u[21], m[3]);+ MONT_MAC(w0, w1, w2, u[22], m[2]);+ MONT_MAC(t0, t1, t2, u[23], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[24] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[24], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 25 */+ MONT_MUL(s0, s1, s2, a[0], a[25]);+ MONT_MUL(c0, c1, c2, a[1], a[24]);+ MONT_MAC(s0, s1, s2, a[2], a[23]);+ MONT_MAC(c0, c1, c2, a[3], a[22]);+ MONT_MAC(s0, s1, s2, a[4], a[21]);+ MONT_MAC(c0, c1, c2, a[5], a[20]);+ MONT_MAC(s0, s1, s2, a[6], a[19]);+ MONT_MAC(c0, c1, c2, a[7], a[18]);+ MONT_MAC(s0, s1, s2, a[8], a[17]);+ MONT_MAC(c0, c1, c2, a[9], a[16]);+ MONT_MAC(s0, s1, s2, a[10], a[15]);+ MONT_MAC(c0, c1, c2, a[11], a[14]);+ MONT_MAC(s0, s1, s2, a[12], a[13]);+ MONT_MAC(t0, t1, t2, u[0], m[25]);+ MONT_MUL(v0, v1, v2, u[1], m[24]);+ MONT_MUL(w0, w1, w2, u[2], m[23]);+ MONT_MAC(t0, t1, t2, u[3], m[22]);+ MONT_MAC(v0, v1, v2, u[4], m[21]);+ MONT_MAC(w0, w1, w2, u[5], m[20]);+ MONT_MAC(t0, t1, t2, u[6], m[19]);+ MONT_MAC(v0, v1, v2, u[7], m[18]);+ MONT_MAC(w0, w1, w2, u[8], m[17]);+ MONT_MAC(t0, t1, t2, u[9], m[16]);+ MONT_MAC(v0, v1, v2, u[10], m[15]);+ MONT_MAC(w0, w1, w2, u[11], m[14]);+ MONT_MAC(t0, t1, t2, u[12], m[13]);+ MONT_MAC(v0, v1, v2, u[13], m[12]);+ MONT_MAC(w0, w1, w2, u[14], m[11]);+ MONT_MAC(t0, t1, t2, u[15], m[10]);+ MONT_MAC(v0, v1, v2, u[16], m[9]);+ MONT_MAC(w0, w1, w2, u[17], m[8]);+ MONT_MAC(t0, t1, t2, u[18], m[7]);+ MONT_MAC(v0, v1, v2, u[19], m[6]);+ MONT_MAC(w0, w1, w2, u[20], m[5]);+ MONT_MAC(t0, t1, t2, u[21], m[4]);+ MONT_MAC(v0, v1, v2, u[22], m[3]);+ MONT_MAC(w0, w1, w2, u[23], m[2]);+ MONT_MAC(t0, t1, t2, u[24], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[25] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[25], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 26 */+ MONT_MUL(s0, s1, s2, a[0], a[26]);+ MONT_MUL(c0, c1, c2, a[1], a[25]);+ MONT_MAC(s0, s1, s2, a[2], a[24]);+ MONT_MAC(c0, c1, c2, a[3], a[23]);+ MONT_MAC(s0, s1, s2, a[4], a[22]);+ MONT_MAC(c0, c1, c2, a[5], a[21]);+ MONT_MAC(s0, s1, s2, a[6], a[20]);+ MONT_MAC(c0, c1, c2, a[7], a[19]);+ MONT_MAC(s0, s1, s2, a[8], a[18]);+ MONT_MAC(c0, c1, c2, a[9], a[17]);+ MONT_MAC(s0, s1, s2, a[10], a[16]);+ MONT_MAC(c0, c1, c2, a[11], a[15]);+ MONT_MAC(s0, s1, s2, a[12], a[14]);+ MONT_MAC(t0, t1, t2, a[13], a[13]);+ MONT_MUL(v0, v1, v2, u[0], m[26]);+ MONT_MUL(w0, w1, w2, u[1], m[25]);+ MONT_MAC(t0, t1, t2, u[2], m[24]);+ MONT_MAC(v0, v1, v2, u[3], m[23]);+ MONT_MAC(w0, w1, w2, u[4], m[22]);+ MONT_MAC(t0, t1, t2, u[5], m[21]);+ MONT_MAC(v0, v1, v2, u[6], m[20]);+ MONT_MAC(w0, w1, w2, u[7], m[19]);+ MONT_MAC(t0, t1, t2, u[8], m[18]);+ MONT_MAC(v0, v1, v2, u[9], m[17]);+ MONT_MAC(w0, w1, w2, u[10], m[16]);+ MONT_MAC(t0, t1, t2, u[11], m[15]);+ MONT_MAC(v0, v1, v2, u[12], m[14]);+ MONT_MAC(w0, w1, w2, u[13], m[13]);+ MONT_MAC(t0, t1, t2, u[14], m[12]);+ MONT_MAC(v0, v1, v2, u[15], m[11]);+ MONT_MAC(w0, w1, w2, u[16], m[10]);+ MONT_MAC(t0, t1, t2, u[17], m[9]);+ MONT_MAC(v0, v1, v2, u[18], m[8]);+ MONT_MAC(w0, w1, w2, u[19], m[7]);+ MONT_MAC(t0, t1, t2, u[20], m[6]);+ MONT_MAC(v0, v1, v2, u[21], m[5]);+ MONT_MAC(w0, w1, w2, u[22], m[4]);+ MONT_MAC(t0, t1, t2, u[23], m[3]);+ MONT_MAC(v0, v1, v2, u[24], m[2]);+ MONT_MAC(w0, w1, w2, u[25], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[26] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[26], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 27 */+ MONT_MUL(s0, s1, s2, a[0], a[27]);+ MONT_MUL(c0, c1, c2, a[1], a[26]);+ MONT_MAC(s0, s1, s2, a[2], a[25]);+ MONT_MAC(c0, c1, c2, a[3], a[24]);+ MONT_MAC(s0, s1, s2, a[4], a[23]);+ MONT_MAC(c0, c1, c2, a[5], a[22]);+ MONT_MAC(s0, s1, s2, a[6], a[21]);+ MONT_MAC(c0, c1, c2, a[7], a[20]);+ MONT_MAC(s0, s1, s2, a[8], a[19]);+ MONT_MAC(c0, c1, c2, a[9], a[18]);+ MONT_MAC(s0, s1, s2, a[10], a[17]);+ MONT_MAC(c0, c1, c2, a[11], a[16]);+ MONT_MAC(s0, s1, s2, a[12], a[15]);+ MONT_MAC(c0, c1, c2, a[13], a[14]);+ MONT_MAC(t0, t1, t2, u[0], m[27]);+ MONT_MUL(v0, v1, v2, u[1], m[26]);+ MONT_MUL(w0, w1, w2, u[2], m[25]);+ MONT_MAC(t0, t1, t2, u[3], m[24]);+ MONT_MAC(v0, v1, v2, u[4], m[23]);+ MONT_MAC(w0, w1, w2, u[5], m[22]);+ MONT_MAC(t0, t1, t2, u[6], m[21]);+ MONT_MAC(v0, v1, v2, u[7], m[20]);+ MONT_MAC(w0, w1, w2, u[8], m[19]);+ MONT_MAC(t0, t1, t2, u[9], m[18]);+ MONT_MAC(v0, v1, v2, u[10], m[17]);+ MONT_MAC(w0, w1, w2, u[11], m[16]);+ MONT_MAC(t0, t1, t2, u[12], m[15]);+ MONT_MAC(v0, v1, v2, u[13], m[14]);+ MONT_MAC(w0, w1, w2, u[14], m[13]);+ MONT_MAC(t0, t1, t2, u[15], m[12]);+ MONT_MAC(v0, v1, v2, u[16], m[11]);+ MONT_MAC(w0, w1, w2, u[17], m[10]);+ MONT_MAC(t0, t1, t2, u[18], m[9]);+ MONT_MAC(v0, v1, v2, u[19], m[8]);+ MONT_MAC(w0, w1, w2, u[20], m[7]);+ MONT_MAC(t0, t1, t2, u[21], m[6]);+ MONT_MAC(v0, v1, v2, u[22], m[5]);+ MONT_MAC(w0, w1, w2, u[23], m[4]);+ MONT_MAC(t0, t1, t2, u[24], m[3]);+ MONT_MAC(v0, v1, v2, u[25], m[2]);+ MONT_MAC(w0, w1, w2, u[26], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[27] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[27], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 28 */+ MONT_MUL(s0, s1, s2, a[0], a[28]);+ MONT_MUL(c0, c1, c2, a[1], a[27]);+ MONT_MAC(s0, s1, s2, a[2], a[26]);+ MONT_MAC(c0, c1, c2, a[3], a[25]);+ MONT_MAC(s0, s1, s2, a[4], a[24]);+ MONT_MAC(c0, c1, c2, a[5], a[23]);+ MONT_MAC(s0, s1, s2, a[6], a[22]);+ MONT_MAC(c0, c1, c2, a[7], a[21]);+ MONT_MAC(s0, s1, s2, a[8], a[20]);+ MONT_MAC(c0, c1, c2, a[9], a[19]);+ MONT_MAC(s0, s1, s2, a[10], a[18]);+ MONT_MAC(c0, c1, c2, a[11], a[17]);+ MONT_MAC(s0, s1, s2, a[12], a[16]);+ MONT_MAC(c0, c1, c2, a[13], a[15]);+ MONT_MAC(t0, t1, t2, a[14], a[14]);+ MONT_MUL(v0, v1, v2, u[0], m[28]);+ MONT_MUL(w0, w1, w2, u[1], m[27]);+ MONT_MAC(t0, t1, t2, u[2], m[26]);+ MONT_MAC(v0, v1, v2, u[3], m[25]);+ MONT_MAC(w0, w1, w2, u[4], m[24]);+ MONT_MAC(t0, t1, t2, u[5], m[23]);+ MONT_MAC(v0, v1, v2, u[6], m[22]);+ MONT_MAC(w0, w1, w2, u[7], m[21]);+ MONT_MAC(t0, t1, t2, u[8], m[20]);+ MONT_MAC(v0, v1, v2, u[9], m[19]);+ MONT_MAC(w0, w1, w2, u[10], m[18]);+ MONT_MAC(t0, t1, t2, u[11], m[17]);+ MONT_MAC(v0, v1, v2, u[12], m[16]);+ MONT_MAC(w0, w1, w2, u[13], m[15]);+ MONT_MAC(t0, t1, t2, u[14], m[14]);+ MONT_MAC(v0, v1, v2, u[15], m[13]);+ MONT_MAC(w0, w1, w2, u[16], m[12]);+ MONT_MAC(t0, t1, t2, u[17], m[11]);+ MONT_MAC(v0, v1, v2, u[18], m[10]);+ MONT_MAC(w0, w1, w2, u[19], m[9]);+ MONT_MAC(t0, t1, t2, u[20], m[8]);+ MONT_MAC(v0, v1, v2, u[21], m[7]);+ MONT_MAC(w0, w1, w2, u[22], m[6]);+ MONT_MAC(t0, t1, t2, u[23], m[5]);+ MONT_MAC(v0, v1, v2, u[24], m[4]);+ MONT_MAC(w0, w1, w2, u[25], m[3]);+ MONT_MAC(t0, t1, t2, u[26], m[2]);+ MONT_MAC(v0, v1, v2, u[27], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[28] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[28], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 29 */+ MONT_MUL(s0, s1, s2, a[0], a[29]);+ MONT_MUL(c0, c1, c2, a[1], a[28]);+ MONT_MAC(s0, s1, s2, a[2], a[27]);+ MONT_MAC(c0, c1, c2, a[3], a[26]);+ MONT_MAC(s0, s1, s2, a[4], a[25]);+ MONT_MAC(c0, c1, c2, a[5], a[24]);+ MONT_MAC(s0, s1, s2, a[6], a[23]);+ MONT_MAC(c0, c1, c2, a[7], a[22]);+ MONT_MAC(s0, s1, s2, a[8], a[21]);+ MONT_MAC(c0, c1, c2, a[9], a[20]);+ MONT_MAC(s0, s1, s2, a[10], a[19]);+ MONT_MAC(c0, c1, c2, a[11], a[18]);+ MONT_MAC(s0, s1, s2, a[12], a[17]);+ MONT_MAC(c0, c1, c2, a[13], a[16]);+ MONT_MAC(s0, s1, s2, a[14], a[15]);+ MONT_MAC(t0, t1, t2, u[0], m[29]);+ MONT_MUL(v0, v1, v2, u[1], m[28]);+ MONT_MUL(w0, w1, w2, u[2], m[27]);+ MONT_MAC(t0, t1, t2, u[3], m[26]);+ MONT_MAC(v0, v1, v2, u[4], m[25]);+ MONT_MAC(w0, w1, w2, u[5], m[24]);+ MONT_MAC(t0, t1, t2, u[6], m[23]);+ MONT_MAC(v0, v1, v2, u[7], m[22]);+ MONT_MAC(w0, w1, w2, u[8], m[21]);+ MONT_MAC(t0, t1, t2, u[9], m[20]);+ MONT_MAC(v0, v1, v2, u[10], m[19]);+ MONT_MAC(w0, w1, w2, u[11], m[18]);+ MONT_MAC(t0, t1, t2, u[12], m[17]);+ MONT_MAC(v0, v1, v2, u[13], m[16]);+ MONT_MAC(w0, w1, w2, u[14], m[15]);+ MONT_MAC(t0, t1, t2, u[15], m[14]);+ MONT_MAC(v0, v1, v2, u[16], m[13]);+ MONT_MAC(w0, w1, w2, u[17], m[12]);+ MONT_MAC(t0, t1, t2, u[18], m[11]);+ MONT_MAC(v0, v1, v2, u[19], m[10]);+ MONT_MAC(w0, w1, w2, u[20], m[9]);+ MONT_MAC(t0, t1, t2, u[21], m[8]);+ MONT_MAC(v0, v1, v2, u[22], m[7]);+ MONT_MAC(w0, w1, w2, u[23], m[6]);+ MONT_MAC(t0, t1, t2, u[24], m[5]);+ MONT_MAC(v0, v1, v2, u[25], m[4]);+ MONT_MAC(w0, w1, w2, u[26], m[3]);+ MONT_MAC(t0, t1, t2, u[27], m[2]);+ MONT_MAC(v0, v1, v2, u[28], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[29] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[29], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 30 */+ MONT_MUL(s0, s1, s2, a[0], a[30]);+ MONT_MUL(c0, c1, c2, a[1], a[29]);+ MONT_MAC(s0, s1, s2, a[2], a[28]);+ MONT_MAC(c0, c1, c2, a[3], a[27]);+ MONT_MAC(s0, s1, s2, a[4], a[26]);+ MONT_MAC(c0, c1, c2, a[5], a[25]);+ MONT_MAC(s0, s1, s2, a[6], a[24]);+ MONT_MAC(c0, c1, c2, a[7], a[23]);+ MONT_MAC(s0, s1, s2, a[8], a[22]);+ MONT_MAC(c0, c1, c2, a[9], a[21]);+ MONT_MAC(s0, s1, s2, a[10], a[20]);+ MONT_MAC(c0, c1, c2, a[11], a[19]);+ MONT_MAC(s0, s1, s2, a[12], a[18]);+ MONT_MAC(c0, c1, c2, a[13], a[17]);+ MONT_MAC(s0, s1, s2, a[14], a[16]);+ MONT_MAC(t0, t1, t2, a[15], a[15]);+ MONT_MUL(v0, v1, v2, u[0], m[30]);+ MONT_MUL(w0, w1, w2, u[1], m[29]);+ MONT_MAC(t0, t1, t2, u[2], m[28]);+ MONT_MAC(v0, v1, v2, u[3], m[27]);+ MONT_MAC(w0, w1, w2, u[4], m[26]);+ MONT_MAC(t0, t1, t2, u[5], m[25]);+ MONT_MAC(v0, v1, v2, u[6], m[24]);+ MONT_MAC(w0, w1, w2, u[7], m[23]);+ MONT_MAC(t0, t1, t2, u[8], m[22]);+ MONT_MAC(v0, v1, v2, u[9], m[21]);+ MONT_MAC(w0, w1, w2, u[10], m[20]);+ MONT_MAC(t0, t1, t2, u[11], m[19]);+ MONT_MAC(v0, v1, v2, u[12], m[18]);+ MONT_MAC(w0, w1, w2, u[13], m[17]);+ MONT_MAC(t0, t1, t2, u[14], m[16]);+ MONT_MAC(v0, v1, v2, u[15], m[15]);+ MONT_MAC(w0, w1, w2, u[16], m[14]);+ MONT_MAC(t0, t1, t2, u[17], m[13]);+ MONT_MAC(v0, v1, v2, u[18], m[12]);+ MONT_MAC(w0, w1, w2, u[19], m[11]);+ MONT_MAC(t0, t1, t2, u[20], m[10]);+ MONT_MAC(v0, v1, v2, u[21], m[9]);+ MONT_MAC(w0, w1, w2, u[22], m[8]);+ MONT_MAC(t0, t1, t2, u[23], m[7]);+ MONT_MAC(v0, v1, v2, u[24], m[6]);+ MONT_MAC(w0, w1, w2, u[25], m[5]);+ MONT_MAC(t0, t1, t2, u[26], m[4]);+ MONT_MAC(v0, v1, v2, u[27], m[3]);+ MONT_MAC(w0, w1, w2, u[28], m[2]);+ MONT_MAC(t0, t1, t2, u[29], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[30] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[30], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 31 */+ MONT_MUL(s0, s1, s2, a[0], a[31]);+ MONT_MUL(c0, c1, c2, a[1], a[30]);+ MONT_MAC(s0, s1, s2, a[2], a[29]);+ MONT_MAC(c0, c1, c2, a[3], a[28]);+ MONT_MAC(s0, s1, s2, a[4], a[27]);+ MONT_MAC(c0, c1, c2, a[5], a[26]);+ MONT_MAC(s0, s1, s2, a[6], a[25]);+ MONT_MAC(c0, c1, c2, a[7], a[24]);+ MONT_MAC(s0, s1, s2, a[8], a[23]);+ MONT_MAC(c0, c1, c2, a[9], a[22]);+ MONT_MAC(s0, s1, s2, a[10], a[21]);+ MONT_MAC(c0, c1, c2, a[11], a[20]);+ MONT_MAC(s0, s1, s2, a[12], a[19]);+ MONT_MAC(c0, c1, c2, a[13], a[18]);+ MONT_MAC(s0, s1, s2, a[14], a[17]);+ MONT_MAC(c0, c1, c2, a[15], a[16]);+ MONT_MAC(t0, t1, t2, u[0], m[31]);+ MONT_MUL(v0, v1, v2, u[1], m[30]);+ MONT_MUL(w0, w1, w2, u[2], m[29]);+ MONT_MAC(t0, t1, t2, u[3], m[28]);+ MONT_MAC(v0, v1, v2, u[4], m[27]);+ MONT_MAC(w0, w1, w2, u[5], m[26]);+ MONT_MAC(t0, t1, t2, u[6], m[25]);+ MONT_MAC(v0, v1, v2, u[7], m[24]);+ MONT_MAC(w0, w1, w2, u[8], m[23]);+ MONT_MAC(t0, t1, t2, u[9], m[22]);+ MONT_MAC(v0, v1, v2, u[10], m[21]);+ MONT_MAC(w0, w1, w2, u[11], m[20]);+ MONT_MAC(t0, t1, t2, u[12], m[19]);+ MONT_MAC(v0, v1, v2, u[13], m[18]);+ MONT_MAC(w0, w1, w2, u[14], m[17]);+ MONT_MAC(t0, t1, t2, u[15], m[16]);+ MONT_MAC(v0, v1, v2, u[16], m[15]);+ MONT_MAC(w0, w1, w2, u[17], m[14]);+ MONT_MAC(t0, t1, t2, u[18], m[13]);+ MONT_MAC(v0, v1, v2, u[19], m[12]);+ MONT_MAC(w0, w1, w2, u[20], m[11]);+ MONT_MAC(t0, t1, t2, u[21], m[10]);+ MONT_MAC(v0, v1, v2, u[22], m[9]);+ MONT_MAC(w0, w1, w2, u[23], m[8]);+ MONT_MAC(t0, t1, t2, u[24], m[7]);+ MONT_MAC(v0, v1, v2, u[25], m[6]);+ MONT_MAC(w0, w1, w2, u[26], m[5]);+ MONT_MAC(t0, t1, t2, u[27], m[4]);+ MONT_MAC(v0, v1, v2, u[28], m[3]);+ MONT_MAC(w0, w1, w2, u[29], m[2]);+ MONT_MAC(t0, t1, t2, u[30], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[31] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[31], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 32 */+ MONT_MUL(s0, s1, s2, a[0], a[32]);+ MONT_MUL(c0, c1, c2, a[1], a[31]);+ MONT_MAC(s0, s1, s2, a[2], a[30]);+ MONT_MAC(c0, c1, c2, a[3], a[29]);+ MONT_MAC(s0, s1, s2, a[4], a[28]);+ MONT_MAC(c0, c1, c2, a[5], a[27]);+ MONT_MAC(s0, s1, s2, a[6], a[26]);+ MONT_MAC(c0, c1, c2, a[7], a[25]);+ MONT_MAC(s0, s1, s2, a[8], a[24]);+ MONT_MAC(c0, c1, c2, a[9], a[23]);+ MONT_MAC(s0, s1, s2, a[10], a[22]);+ MONT_MAC(c0, c1, c2, a[11], a[21]);+ MONT_MAC(s0, s1, s2, a[12], a[20]);+ MONT_MAC(c0, c1, c2, a[13], a[19]);+ MONT_MAC(s0, s1, s2, a[14], a[18]);+ MONT_MAC(c0, c1, c2, a[15], a[17]);+ MONT_MAC(t0, t1, t2, a[16], a[16]);+ MONT_MUL(v0, v1, v2, u[0], m[32]);+ MONT_MUL(w0, w1, w2, u[1], m[31]);+ MONT_MAC(t0, t1, t2, u[2], m[30]);+ MONT_MAC(v0, v1, v2, u[3], m[29]);+ MONT_MAC(w0, w1, w2, u[4], m[28]);+ MONT_MAC(t0, t1, t2, u[5], m[27]);+ MONT_MAC(v0, v1, v2, u[6], m[26]);+ MONT_MAC(w0, w1, w2, u[7], m[25]);+ MONT_MAC(t0, t1, t2, u[8], m[24]);+ MONT_MAC(v0, v1, v2, u[9], m[23]);+ MONT_MAC(w0, w1, w2, u[10], m[22]);+ MONT_MAC(t0, t1, t2, u[11], m[21]);+ MONT_MAC(v0, v1, v2, u[12], m[20]);+ MONT_MAC(w0, w1, w2, u[13], m[19]);+ MONT_MAC(t0, t1, t2, u[14], m[18]);+ MONT_MAC(v0, v1, v2, u[15], m[17]);+ MONT_MAC(w0, w1, w2, u[16], m[16]);+ MONT_MAC(t0, t1, t2, u[17], m[15]);+ MONT_MAC(v0, v1, v2, u[18], m[14]);+ MONT_MAC(w0, w1, w2, u[19], m[13]);+ MONT_MAC(t0, t1, t2, u[20], m[12]);+ MONT_MAC(v0, v1, v2, u[21], m[11]);+ MONT_MAC(w0, w1, w2, u[22], m[10]);+ MONT_MAC(t0, t1, t2, u[23], m[9]);+ MONT_MAC(v0, v1, v2, u[24], m[8]);+ MONT_MAC(w0, w1, w2, u[25], m[7]);+ MONT_MAC(t0, t1, t2, u[26], m[6]);+ MONT_MAC(v0, v1, v2, u[27], m[5]);+ MONT_MAC(w0, w1, w2, u[28], m[4]);+ MONT_MAC(t0, t1, t2, u[29], m[3]);+ MONT_MAC(v0, v1, v2, u[30], m[2]);+ MONT_MAC(w0, w1, w2, u[31], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[32] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[32], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 33 */+ MONT_MUL(s0, s1, s2, a[0], a[33]);+ MONT_MUL(c0, c1, c2, a[1], a[32]);+ MONT_MAC(s0, s1, s2, a[2], a[31]);+ MONT_MAC(c0, c1, c2, a[3], a[30]);+ MONT_MAC(s0, s1, s2, a[4], a[29]);+ MONT_MAC(c0, c1, c2, a[5], a[28]);+ MONT_MAC(s0, s1, s2, a[6], a[27]);+ MONT_MAC(c0, c1, c2, a[7], a[26]);+ MONT_MAC(s0, s1, s2, a[8], a[25]);+ MONT_MAC(c0, c1, c2, a[9], a[24]);+ MONT_MAC(s0, s1, s2, a[10], a[23]);+ MONT_MAC(c0, c1, c2, a[11], a[22]);+ MONT_MAC(s0, s1, s2, a[12], a[21]);+ MONT_MAC(c0, c1, c2, a[13], a[20]);+ MONT_MAC(s0, s1, s2, a[14], a[19]);+ MONT_MAC(c0, c1, c2, a[15], a[18]);+ MONT_MAC(s0, s1, s2, a[16], a[17]);+ MONT_MAC(t0, t1, t2, u[0], m[33]);+ MONT_MUL(v0, v1, v2, u[1], m[32]);+ MONT_MUL(w0, w1, w2, u[2], m[31]);+ MONT_MAC(t0, t1, t2, u[3], m[30]);+ MONT_MAC(v0, v1, v2, u[4], m[29]);+ MONT_MAC(w0, w1, w2, u[5], m[28]);+ MONT_MAC(t0, t1, t2, u[6], m[27]);+ MONT_MAC(v0, v1, v2, u[7], m[26]);+ MONT_MAC(w0, w1, w2, u[8], m[25]);+ MONT_MAC(t0, t1, t2, u[9], m[24]);+ MONT_MAC(v0, v1, v2, u[10], m[23]);+ MONT_MAC(w0, w1, w2, u[11], m[22]);+ MONT_MAC(t0, t1, t2, u[12], m[21]);+ MONT_MAC(v0, v1, v2, u[13], m[20]);+ MONT_MAC(w0, w1, w2, u[14], m[19]);+ MONT_MAC(t0, t1, t2, u[15], m[18]);+ MONT_MAC(v0, v1, v2, u[16], m[17]);+ MONT_MAC(w0, w1, w2, u[17], m[16]);+ MONT_MAC(t0, t1, t2, u[18], m[15]);+ MONT_MAC(v0, v1, v2, u[19], m[14]);+ MONT_MAC(w0, w1, w2, u[20], m[13]);+ MONT_MAC(t0, t1, t2, u[21], m[12]);+ MONT_MAC(v0, v1, v2, u[22], m[11]);+ MONT_MAC(w0, w1, w2, u[23], m[10]);+ MONT_MAC(t0, t1, t2, u[24], m[9]);+ MONT_MAC(v0, v1, v2, u[25], m[8]);+ MONT_MAC(w0, w1, w2, u[26], m[7]);+ MONT_MAC(t0, t1, t2, u[27], m[6]);+ MONT_MAC(v0, v1, v2, u[28], m[5]);+ MONT_MAC(w0, w1, w2, u[29], m[4]);+ MONT_MAC(t0, t1, t2, u[30], m[3]);+ MONT_MAC(v0, v1, v2, u[31], m[2]);+ MONT_MAC(w0, w1, w2, u[32], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[33] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[33], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 34 */+ MONT_MUL(s0, s1, s2, a[0], a[34]);+ MONT_MUL(c0, c1, c2, a[1], a[33]);+ MONT_MAC(s0, s1, s2, a[2], a[32]);+ MONT_MAC(c0, c1, c2, a[3], a[31]);+ MONT_MAC(s0, s1, s2, a[4], a[30]);+ MONT_MAC(c0, c1, c2, a[5], a[29]);+ MONT_MAC(s0, s1, s2, a[6], a[28]);+ MONT_MAC(c0, c1, c2, a[7], a[27]);+ MONT_MAC(s0, s1, s2, a[8], a[26]);+ MONT_MAC(c0, c1, c2, a[9], a[25]);+ MONT_MAC(s0, s1, s2, a[10], a[24]);+ MONT_MAC(c0, c1, c2, a[11], a[23]);+ MONT_MAC(s0, s1, s2, a[12], a[22]);+ MONT_MAC(c0, c1, c2, a[13], a[21]);+ MONT_MAC(s0, s1, s2, a[14], a[20]);+ MONT_MAC(c0, c1, c2, a[15], a[19]);+ MONT_MAC(s0, s1, s2, a[16], a[18]);+ MONT_MAC(t0, t1, t2, a[17], a[17]);+ MONT_MUL(v0, v1, v2, u[0], m[34]);+ MONT_MUL(w0, w1, w2, u[1], m[33]);+ MONT_MAC(t0, t1, t2, u[2], m[32]);+ MONT_MAC(v0, v1, v2, u[3], m[31]);+ MONT_MAC(w0, w1, w2, u[4], m[30]);+ MONT_MAC(t0, t1, t2, u[5], m[29]);+ MONT_MAC(v0, v1, v2, u[6], m[28]);+ MONT_MAC(w0, w1, w2, u[7], m[27]);+ MONT_MAC(t0, t1, t2, u[8], m[26]);+ MONT_MAC(v0, v1, v2, u[9], m[25]);+ MONT_MAC(w0, w1, w2, u[10], m[24]);+ MONT_MAC(t0, t1, t2, u[11], m[23]);+ MONT_MAC(v0, v1, v2, u[12], m[22]);+ MONT_MAC(w0, w1, w2, u[13], m[21]);+ MONT_MAC(t0, t1, t2, u[14], m[20]);+ MONT_MAC(v0, v1, v2, u[15], m[19]);+ MONT_MAC(w0, w1, w2, u[16], m[18]);+ MONT_MAC(t0, t1, t2, u[17], m[17]);+ MONT_MAC(v0, v1, v2, u[18], m[16]);+ MONT_MAC(w0, w1, w2, u[19], m[15]);+ MONT_MAC(t0, t1, t2, u[20], m[14]);+ MONT_MAC(v0, v1, v2, u[21], m[13]);+ MONT_MAC(w0, w1, w2, u[22], m[12]);+ MONT_MAC(t0, t1, t2, u[23], m[11]);+ MONT_MAC(v0, v1, v2, u[24], m[10]);+ MONT_MAC(w0, w1, w2, u[25], m[9]);+ MONT_MAC(t0, t1, t2, u[26], m[8]);+ MONT_MAC(v0, v1, v2, u[27], m[7]);+ MONT_MAC(w0, w1, w2, u[28], m[6]);+ MONT_MAC(t0, t1, t2, u[29], m[5]);+ MONT_MAC(v0, v1, v2, u[30], m[4]);+ MONT_MAC(w0, w1, w2, u[31], m[3]);+ MONT_MAC(t0, t1, t2, u[32], m[2]);+ MONT_MAC(v0, v1, v2, u[33], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[34] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[34], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 35 */+ MONT_MUL(s0, s1, s2, a[0], a[35]);+ MONT_MUL(c0, c1, c2, a[1], a[34]);+ MONT_MAC(s0, s1, s2, a[2], a[33]);+ MONT_MAC(c0, c1, c2, a[3], a[32]);+ MONT_MAC(s0, s1, s2, a[4], a[31]);+ MONT_MAC(c0, c1, c2, a[5], a[30]);+ MONT_MAC(s0, s1, s2, a[6], a[29]);+ MONT_MAC(c0, c1, c2, a[7], a[28]);+ MONT_MAC(s0, s1, s2, a[8], a[27]);+ MONT_MAC(c0, c1, c2, a[9], a[26]);+ MONT_MAC(s0, s1, s2, a[10], a[25]);+ MONT_MAC(c0, c1, c2, a[11], a[24]);+ MONT_MAC(s0, s1, s2, a[12], a[23]);+ MONT_MAC(c0, c1, c2, a[13], a[22]);+ MONT_MAC(s0, s1, s2, a[14], a[21]);+ MONT_MAC(c0, c1, c2, a[15], a[20]);+ MONT_MAC(s0, s1, s2, a[16], a[19]);+ MONT_MAC(c0, c1, c2, a[17], a[18]);+ MONT_MAC(t0, t1, t2, u[0], m[35]);+ MONT_MUL(v0, v1, v2, u[1], m[34]);+ MONT_MUL(w0, w1, w2, u[2], m[33]);+ MONT_MAC(t0, t1, t2, u[3], m[32]);+ MONT_MAC(v0, v1, v2, u[4], m[31]);+ MONT_MAC(w0, w1, w2, u[5], m[30]);+ MONT_MAC(t0, t1, t2, u[6], m[29]);+ MONT_MAC(v0, v1, v2, u[7], m[28]);+ MONT_MAC(w0, w1, w2, u[8], m[27]);+ MONT_MAC(t0, t1, t2, u[9], m[26]);+ MONT_MAC(v0, v1, v2, u[10], m[25]);+ MONT_MAC(w0, w1, w2, u[11], m[24]);+ MONT_MAC(t0, t1, t2, u[12], m[23]);+ MONT_MAC(v0, v1, v2, u[13], m[22]);+ MONT_MAC(w0, w1, w2, u[14], m[21]);+ MONT_MAC(t0, t1, t2, u[15], m[20]);+ MONT_MAC(v0, v1, v2, u[16], m[19]);+ MONT_MAC(w0, w1, w2, u[17], m[18]);+ MONT_MAC(t0, t1, t2, u[18], m[17]);+ MONT_MAC(v0, v1, v2, u[19], m[16]);+ MONT_MAC(w0, w1, w2, u[20], m[15]);+ MONT_MAC(t0, t1, t2, u[21], m[14]);+ MONT_MAC(v0, v1, v2, u[22], m[13]);+ MONT_MAC(w0, w1, w2, u[23], m[12]);+ MONT_MAC(t0, t1, t2, u[24], m[11]);+ MONT_MAC(v0, v1, v2, u[25], m[10]);+ MONT_MAC(w0, w1, w2, u[26], m[9]);+ MONT_MAC(t0, t1, t2, u[27], m[8]);+ MONT_MAC(v0, v1, v2, u[28], m[7]);+ MONT_MAC(w0, w1, w2, u[29], m[6]);+ MONT_MAC(t0, t1, t2, u[30], m[5]);+ MONT_MAC(v0, v1, v2, u[31], m[4]);+ MONT_MAC(w0, w1, w2, u[32], m[3]);+ MONT_MAC(t0, t1, t2, u[33], m[2]);+ MONT_MAC(v0, v1, v2, u[34], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[35] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[35], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 36 */+ MONT_MUL(s0, s1, s2, a[0], a[36]);+ MONT_MUL(c0, c1, c2, a[1], a[35]);+ MONT_MAC(s0, s1, s2, a[2], a[34]);+ MONT_MAC(c0, c1, c2, a[3], a[33]);+ MONT_MAC(s0, s1, s2, a[4], a[32]);+ MONT_MAC(c0, c1, c2, a[5], a[31]);+ MONT_MAC(s0, s1, s2, a[6], a[30]);+ MONT_MAC(c0, c1, c2, a[7], a[29]);+ MONT_MAC(s0, s1, s2, a[8], a[28]);+ MONT_MAC(c0, c1, c2, a[9], a[27]);+ MONT_MAC(s0, s1, s2, a[10], a[26]);+ MONT_MAC(c0, c1, c2, a[11], a[25]);+ MONT_MAC(s0, s1, s2, a[12], a[24]);+ MONT_MAC(c0, c1, c2, a[13], a[23]);+ MONT_MAC(s0, s1, s2, a[14], a[22]);+ MONT_MAC(c0, c1, c2, a[15], a[21]);+ MONT_MAC(s0, s1, s2, a[16], a[20]);+ MONT_MAC(c0, c1, c2, a[17], a[19]);+ MONT_MAC(t0, t1, t2, a[18], a[18]);+ MONT_MUL(v0, v1, v2, u[0], m[36]);+ MONT_MUL(w0, w1, w2, u[1], m[35]);+ MONT_MAC(t0, t1, t2, u[2], m[34]);+ MONT_MAC(v0, v1, v2, u[3], m[33]);+ MONT_MAC(w0, w1, w2, u[4], m[32]);+ MONT_MAC(t0, t1, t2, u[5], m[31]);+ MONT_MAC(v0, v1, v2, u[6], m[30]);+ MONT_MAC(w0, w1, w2, u[7], m[29]);+ MONT_MAC(t0, t1, t2, u[8], m[28]);+ MONT_MAC(v0, v1, v2, u[9], m[27]);+ MONT_MAC(w0, w1, w2, u[10], m[26]);+ MONT_MAC(t0, t1, t2, u[11], m[25]);+ MONT_MAC(v0, v1, v2, u[12], m[24]);+ MONT_MAC(w0, w1, w2, u[13], m[23]);+ MONT_MAC(t0, t1, t2, u[14], m[22]);+ MONT_MAC(v0, v1, v2, u[15], m[21]);+ MONT_MAC(w0, w1, w2, u[16], m[20]);+ MONT_MAC(t0, t1, t2, u[17], m[19]);+ MONT_MAC(v0, v1, v2, u[18], m[18]);+ MONT_MAC(w0, w1, w2, u[19], m[17]);+ MONT_MAC(t0, t1, t2, u[20], m[16]);+ MONT_MAC(v0, v1, v2, u[21], m[15]);+ MONT_MAC(w0, w1, w2, u[22], m[14]);+ MONT_MAC(t0, t1, t2, u[23], m[13]);+ MONT_MAC(v0, v1, v2, u[24], m[12]);+ MONT_MAC(w0, w1, w2, u[25], m[11]);+ MONT_MAC(t0, t1, t2, u[26], m[10]);+ MONT_MAC(v0, v1, v2, u[27], m[9]);+ MONT_MAC(w0, w1, w2, u[28], m[8]);+ MONT_MAC(t0, t1, t2, u[29], m[7]);+ MONT_MAC(v0, v1, v2, u[30], m[6]);+ MONT_MAC(w0, w1, w2, u[31], m[5]);+ MONT_MAC(t0, t1, t2, u[32], m[4]);+ MONT_MAC(v0, v1, v2, u[33], m[3]);+ MONT_MAC(w0, w1, w2, u[34], m[2]);+ MONT_MAC(t0, t1, t2, u[35], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[36] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[36], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 37 */+ MONT_MUL(s0, s1, s2, a[0], a[37]);+ MONT_MUL(c0, c1, c2, a[1], a[36]);+ MONT_MAC(s0, s1, s2, a[2], a[35]);+ MONT_MAC(c0, c1, c2, a[3], a[34]);+ MONT_MAC(s0, s1, s2, a[4], a[33]);+ MONT_MAC(c0, c1, c2, a[5], a[32]);+ MONT_MAC(s0, s1, s2, a[6], a[31]);+ MONT_MAC(c0, c1, c2, a[7], a[30]);+ MONT_MAC(s0, s1, s2, a[8], a[29]);+ MONT_MAC(c0, c1, c2, a[9], a[28]);+ MONT_MAC(s0, s1, s2, a[10], a[27]);+ MONT_MAC(c0, c1, c2, a[11], a[26]);+ MONT_MAC(s0, s1, s2, a[12], a[25]);+ MONT_MAC(c0, c1, c2, a[13], a[24]);+ MONT_MAC(s0, s1, s2, a[14], a[23]);+ MONT_MAC(c0, c1, c2, a[15], a[22]);+ MONT_MAC(s0, s1, s2, a[16], a[21]);+ MONT_MAC(c0, c1, c2, a[17], a[20]);+ MONT_MAC(s0, s1, s2, a[18], a[19]);+ MONT_MAC(t0, t1, t2, u[0], m[37]);+ MONT_MUL(v0, v1, v2, u[1], m[36]);+ MONT_MUL(w0, w1, w2, u[2], m[35]);+ MONT_MAC(t0, t1, t2, u[3], m[34]);+ MONT_MAC(v0, v1, v2, u[4], m[33]);+ MONT_MAC(w0, w1, w2, u[5], m[32]);+ MONT_MAC(t0, t1, t2, u[6], m[31]);+ MONT_MAC(v0, v1, v2, u[7], m[30]);+ MONT_MAC(w0, w1, w2, u[8], m[29]);+ MONT_MAC(t0, t1, t2, u[9], m[28]);+ MONT_MAC(v0, v1, v2, u[10], m[27]);+ MONT_MAC(w0, w1, w2, u[11], m[26]);+ MONT_MAC(t0, t1, t2, u[12], m[25]);+ MONT_MAC(v0, v1, v2, u[13], m[24]);+ MONT_MAC(w0, w1, w2, u[14], m[23]);+ MONT_MAC(t0, t1, t2, u[15], m[22]);+ MONT_MAC(v0, v1, v2, u[16], m[21]);+ MONT_MAC(w0, w1, w2, u[17], m[20]);+ MONT_MAC(t0, t1, t2, u[18], m[19]);+ MONT_MAC(v0, v1, v2, u[19], m[18]);+ MONT_MAC(w0, w1, w2, u[20], m[17]);+ MONT_MAC(t0, t1, t2, u[21], m[16]);+ MONT_MAC(v0, v1, v2, u[22], m[15]);+ MONT_MAC(w0, w1, w2, u[23], m[14]);+ MONT_MAC(t0, t1, t2, u[24], m[13]);+ MONT_MAC(v0, v1, v2, u[25], m[12]);+ MONT_MAC(w0, w1, w2, u[26], m[11]);+ MONT_MAC(t0, t1, t2, u[27], m[10]);+ MONT_MAC(v0, v1, v2, u[28], m[9]);+ MONT_MAC(w0, w1, w2, u[29], m[8]);+ MONT_MAC(t0, t1, t2, u[30], m[7]);+ MONT_MAC(v0, v1, v2, u[31], m[6]);+ MONT_MAC(w0, w1, w2, u[32], m[5]);+ MONT_MAC(t0, t1, t2, u[33], m[4]);+ MONT_MAC(v0, v1, v2, u[34], m[3]);+ MONT_MAC(w0, w1, w2, u[35], m[2]);+ MONT_MAC(t0, t1, t2, u[36], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[37] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[37], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 38 */+ MONT_MUL(s0, s1, s2, a[0], a[38]);+ MONT_MUL(c0, c1, c2, a[1], a[37]);+ MONT_MAC(s0, s1, s2, a[2], a[36]);+ MONT_MAC(c0, c1, c2, a[3], a[35]);+ MONT_MAC(s0, s1, s2, a[4], a[34]);+ MONT_MAC(c0, c1, c2, a[5], a[33]);+ MONT_MAC(s0, s1, s2, a[6], a[32]);+ MONT_MAC(c0, c1, c2, a[7], a[31]);+ MONT_MAC(s0, s1, s2, a[8], a[30]);+ MONT_MAC(c0, c1, c2, a[9], a[29]);+ MONT_MAC(s0, s1, s2, a[10], a[28]);+ MONT_MAC(c0, c1, c2, a[11], a[27]);+ MONT_MAC(s0, s1, s2, a[12], a[26]);+ MONT_MAC(c0, c1, c2, a[13], a[25]);+ MONT_MAC(s0, s1, s2, a[14], a[24]);+ MONT_MAC(c0, c1, c2, a[15], a[23]);+ MONT_MAC(s0, s1, s2, a[16], a[22]);+ MONT_MAC(c0, c1, c2, a[17], a[21]);+ MONT_MAC(s0, s1, s2, a[18], a[20]);+ MONT_MAC(t0, t1, t2, a[19], a[19]);+ MONT_MUL(v0, v1, v2, u[0], m[38]);+ MONT_MUL(w0, w1, w2, u[1], m[37]);+ MONT_MAC(t0, t1, t2, u[2], m[36]);+ MONT_MAC(v0, v1, v2, u[3], m[35]);+ MONT_MAC(w0, w1, w2, u[4], m[34]);+ MONT_MAC(t0, t1, t2, u[5], m[33]);+ MONT_MAC(v0, v1, v2, u[6], m[32]);+ MONT_MAC(w0, w1, w2, u[7], m[31]);+ MONT_MAC(t0, t1, t2, u[8], m[30]);+ MONT_MAC(v0, v1, v2, u[9], m[29]);+ MONT_MAC(w0, w1, w2, u[10], m[28]);+ MONT_MAC(t0, t1, t2, u[11], m[27]);+ MONT_MAC(v0, v1, v2, u[12], m[26]);+ MONT_MAC(w0, w1, w2, u[13], m[25]);+ MONT_MAC(t0, t1, t2, u[14], m[24]);+ MONT_MAC(v0, v1, v2, u[15], m[23]);+ MONT_MAC(w0, w1, w2, u[16], m[22]);+ MONT_MAC(t0, t1, t2, u[17], m[21]);+ MONT_MAC(v0, v1, v2, u[18], m[20]);+ MONT_MAC(w0, w1, w2, u[19], m[19]);+ MONT_MAC(t0, t1, t2, u[20], m[18]);+ MONT_MAC(v0, v1, v2, u[21], m[17]);+ MONT_MAC(w0, w1, w2, u[22], m[16]);+ MONT_MAC(t0, t1, t2, u[23], m[15]);+ MONT_MAC(v0, v1, v2, u[24], m[14]);+ MONT_MAC(w0, w1, w2, u[25], m[13]);+ MONT_MAC(t0, t1, t2, u[26], m[12]);+ MONT_MAC(v0, v1, v2, u[27], m[11]);+ MONT_MAC(w0, w1, w2, u[28], m[10]);+ MONT_MAC(t0, t1, t2, u[29], m[9]);+ MONT_MAC(v0, v1, v2, u[30], m[8]);+ MONT_MAC(w0, w1, w2, u[31], m[7]);+ MONT_MAC(t0, t1, t2, u[32], m[6]);+ MONT_MAC(v0, v1, v2, u[33], m[5]);+ MONT_MAC(w0, w1, w2, u[34], m[4]);+ MONT_MAC(t0, t1, t2, u[35], m[3]);+ MONT_MAC(v0, v1, v2, u[36], m[2]);+ MONT_MAC(w0, w1, w2, u[37], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[38] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[38], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 39 */+ MONT_MUL(s0, s1, s2, a[0], a[39]);+ MONT_MUL(c0, c1, c2, a[1], a[38]);+ MONT_MAC(s0, s1, s2, a[2], a[37]);+ MONT_MAC(c0, c1, c2, a[3], a[36]);+ MONT_MAC(s0, s1, s2, a[4], a[35]);+ MONT_MAC(c0, c1, c2, a[5], a[34]);+ MONT_MAC(s0, s1, s2, a[6], a[33]);+ MONT_MAC(c0, c1, c2, a[7], a[32]);+ MONT_MAC(s0, s1, s2, a[8], a[31]);+ MONT_MAC(c0, c1, c2, a[9], a[30]);+ MONT_MAC(s0, s1, s2, a[10], a[29]);+ MONT_MAC(c0, c1, c2, a[11], a[28]);+ MONT_MAC(s0, s1, s2, a[12], a[27]);+ MONT_MAC(c0, c1, c2, a[13], a[26]);+ MONT_MAC(s0, s1, s2, a[14], a[25]);+ MONT_MAC(c0, c1, c2, a[15], a[24]);+ MONT_MAC(s0, s1, s2, a[16], a[23]);+ MONT_MAC(c0, c1, c2, a[17], a[22]);+ MONT_MAC(s0, s1, s2, a[18], a[21]);+ MONT_MAC(c0, c1, c2, a[19], a[20]);+ MONT_MAC(t0, t1, t2, u[0], m[39]);+ MONT_MUL(v0, v1, v2, u[1], m[38]);+ MONT_MUL(w0, w1, w2, u[2], m[37]);+ MONT_MAC(t0, t1, t2, u[3], m[36]);+ MONT_MAC(v0, v1, v2, u[4], m[35]);+ MONT_MAC(w0, w1, w2, u[5], m[34]);+ MONT_MAC(t0, t1, t2, u[6], m[33]);+ MONT_MAC(v0, v1, v2, u[7], m[32]);+ MONT_MAC(w0, w1, w2, u[8], m[31]);+ MONT_MAC(t0, t1, t2, u[9], m[30]);+ MONT_MAC(v0, v1, v2, u[10], m[29]);+ MONT_MAC(w0, w1, w2, u[11], m[28]);+ MONT_MAC(t0, t1, t2, u[12], m[27]);+ MONT_MAC(v0, v1, v2, u[13], m[26]);+ MONT_MAC(w0, w1, w2, u[14], m[25]);+ MONT_MAC(t0, t1, t2, u[15], m[24]);+ MONT_MAC(v0, v1, v2, u[16], m[23]);+ MONT_MAC(w0, w1, w2, u[17], m[22]);+ MONT_MAC(t0, t1, t2, u[18], m[21]);+ MONT_MAC(v0, v1, v2, u[19], m[20]);+ MONT_MAC(w0, w1, w2, u[20], m[19]);+ MONT_MAC(t0, t1, t2, u[21], m[18]);+ MONT_MAC(v0, v1, v2, u[22], m[17]);+ MONT_MAC(w0, w1, w2, u[23], m[16]);+ MONT_MAC(t0, t1, t2, u[24], m[15]);+ MONT_MAC(v0, v1, v2, u[25], m[14]);+ MONT_MAC(w0, w1, w2, u[26], m[13]);+ MONT_MAC(t0, t1, t2, u[27], m[12]);+ MONT_MAC(v0, v1, v2, u[28], m[11]);+ MONT_MAC(w0, w1, w2, u[29], m[10]);+ MONT_MAC(t0, t1, t2, u[30], m[9]);+ MONT_MAC(v0, v1, v2, u[31], m[8]);+ MONT_MAC(w0, w1, w2, u[32], m[7]);+ MONT_MAC(t0, t1, t2, u[33], m[6]);+ MONT_MAC(v0, v1, v2, u[34], m[5]);+ MONT_MAC(w0, w1, w2, u[35], m[4]);+ MONT_MAC(t0, t1, t2, u[36], m[3]);+ MONT_MAC(v0, v1, v2, u[37], m[2]);+ MONT_MAC(w0, w1, w2, u[38], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[39] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[39], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 40 */+ MONT_MUL(s0, s1, s2, a[0], a[40]);+ MONT_MUL(c0, c1, c2, a[1], a[39]);+ MONT_MAC(s0, s1, s2, a[2], a[38]);+ MONT_MAC(c0, c1, c2, a[3], a[37]);+ MONT_MAC(s0, s1, s2, a[4], a[36]);+ MONT_MAC(c0, c1, c2, a[5], a[35]);+ MONT_MAC(s0, s1, s2, a[6], a[34]);+ MONT_MAC(c0, c1, c2, a[7], a[33]);+ MONT_MAC(s0, s1, s2, a[8], a[32]);+ MONT_MAC(c0, c1, c2, a[9], a[31]);+ MONT_MAC(s0, s1, s2, a[10], a[30]);+ MONT_MAC(c0, c1, c2, a[11], a[29]);+ MONT_MAC(s0, s1, s2, a[12], a[28]);+ MONT_MAC(c0, c1, c2, a[13], a[27]);+ MONT_MAC(s0, s1, s2, a[14], a[26]);+ MONT_MAC(c0, c1, c2, a[15], a[25]);+ MONT_MAC(s0, s1, s2, a[16], a[24]);+ MONT_MAC(c0, c1, c2, a[17], a[23]);+ MONT_MAC(s0, s1, s2, a[18], a[22]);+ MONT_MAC(c0, c1, c2, a[19], a[21]);+ MONT_MAC(t0, t1, t2, a[20], a[20]);+ MONT_MUL(v0, v1, v2, u[0], m[40]);+ MONT_MUL(w0, w1, w2, u[1], m[39]);+ MONT_MAC(t0, t1, t2, u[2], m[38]);+ MONT_MAC(v0, v1, v2, u[3], m[37]);+ MONT_MAC(w0, w1, w2, u[4], m[36]);+ MONT_MAC(t0, t1, t2, u[5], m[35]);+ MONT_MAC(v0, v1, v2, u[6], m[34]);+ MONT_MAC(w0, w1, w2, u[7], m[33]);+ MONT_MAC(t0, t1, t2, u[8], m[32]);+ MONT_MAC(v0, v1, v2, u[9], m[31]);+ MONT_MAC(w0, w1, w2, u[10], m[30]);+ MONT_MAC(t0, t1, t2, u[11], m[29]);+ MONT_MAC(v0, v1, v2, u[12], m[28]);+ MONT_MAC(w0, w1, w2, u[13], m[27]);+ MONT_MAC(t0, t1, t2, u[14], m[26]);+ MONT_MAC(v0, v1, v2, u[15], m[25]);+ MONT_MAC(w0, w1, w2, u[16], m[24]);+ MONT_MAC(t0, t1, t2, u[17], m[23]);+ MONT_MAC(v0, v1, v2, u[18], m[22]);+ MONT_MAC(w0, w1, w2, u[19], m[21]);+ MONT_MAC(t0, t1, t2, u[20], m[20]);+ MONT_MAC(v0, v1, v2, u[21], m[19]);+ MONT_MAC(w0, w1, w2, u[22], m[18]);+ MONT_MAC(t0, t1, t2, u[23], m[17]);+ MONT_MAC(v0, v1, v2, u[24], m[16]);+ MONT_MAC(w0, w1, w2, u[25], m[15]);+ MONT_MAC(t0, t1, t2, u[26], m[14]);+ MONT_MAC(v0, v1, v2, u[27], m[13]);+ MONT_MAC(w0, w1, w2, u[28], m[12]);+ MONT_MAC(t0, t1, t2, u[29], m[11]);+ MONT_MAC(v0, v1, v2, u[30], m[10]);+ MONT_MAC(w0, w1, w2, u[31], m[9]);+ MONT_MAC(t0, t1, t2, u[32], m[8]);+ MONT_MAC(v0, v1, v2, u[33], m[7]);+ MONT_MAC(w0, w1, w2, u[34], m[6]);+ MONT_MAC(t0, t1, t2, u[35], m[5]);+ MONT_MAC(v0, v1, v2, u[36], m[4]);+ MONT_MAC(w0, w1, w2, u[37], m[3]);+ MONT_MAC(t0, t1, t2, u[38], m[2]);+ MONT_MAC(v0, v1, v2, u[39], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[40] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[40], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 41 */+ MONT_MUL(s0, s1, s2, a[0], a[41]);+ MONT_MUL(c0, c1, c2, a[1], a[40]);+ MONT_MAC(s0, s1, s2, a[2], a[39]);+ MONT_MAC(c0, c1, c2, a[3], a[38]);+ MONT_MAC(s0, s1, s2, a[4], a[37]);+ MONT_MAC(c0, c1, c2, a[5], a[36]);+ MONT_MAC(s0, s1, s2, a[6], a[35]);+ MONT_MAC(c0, c1, c2, a[7], a[34]);+ MONT_MAC(s0, s1, s2, a[8], a[33]);+ MONT_MAC(c0, c1, c2, a[9], a[32]);+ MONT_MAC(s0, s1, s2, a[10], a[31]);+ MONT_MAC(c0, c1, c2, a[11], a[30]);+ MONT_MAC(s0, s1, s2, a[12], a[29]);+ MONT_MAC(c0, c1, c2, a[13], a[28]);+ MONT_MAC(s0, s1, s2, a[14], a[27]);+ MONT_MAC(c0, c1, c2, a[15], a[26]);+ MONT_MAC(s0, s1, s2, a[16], a[25]);+ MONT_MAC(c0, c1, c2, a[17], a[24]);+ MONT_MAC(s0, s1, s2, a[18], a[23]);+ MONT_MAC(c0, c1, c2, a[19], a[22]);+ MONT_MAC(s0, s1, s2, a[20], a[21]);+ MONT_MAC(t0, t1, t2, u[0], m[41]);+ MONT_MUL(v0, v1, v2, u[1], m[40]);+ MONT_MUL(w0, w1, w2, u[2], m[39]);+ MONT_MAC(t0, t1, t2, u[3], m[38]);+ MONT_MAC(v0, v1, v2, u[4], m[37]);+ MONT_MAC(w0, w1, w2, u[5], m[36]);+ MONT_MAC(t0, t1, t2, u[6], m[35]);+ MONT_MAC(v0, v1, v2, u[7], m[34]);+ MONT_MAC(w0, w1, w2, u[8], m[33]);+ MONT_MAC(t0, t1, t2, u[9], m[32]);+ MONT_MAC(v0, v1, v2, u[10], m[31]);+ MONT_MAC(w0, w1, w2, u[11], m[30]);+ MONT_MAC(t0, t1, t2, u[12], m[29]);+ MONT_MAC(v0, v1, v2, u[13], m[28]);+ MONT_MAC(w0, w1, w2, u[14], m[27]);+ MONT_MAC(t0, t1, t2, u[15], m[26]);+ MONT_MAC(v0, v1, v2, u[16], m[25]);+ MONT_MAC(w0, w1, w2, u[17], m[24]);+ MONT_MAC(t0, t1, t2, u[18], m[23]);+ MONT_MAC(v0, v1, v2, u[19], m[22]);+ MONT_MAC(w0, w1, w2, u[20], m[21]);+ MONT_MAC(t0, t1, t2, u[21], m[20]);+ MONT_MAC(v0, v1, v2, u[22], m[19]);+ MONT_MAC(w0, w1, w2, u[23], m[18]);+ MONT_MAC(t0, t1, t2, u[24], m[17]);+ MONT_MAC(v0, v1, v2, u[25], m[16]);+ MONT_MAC(w0, w1, w2, u[26], m[15]);+ MONT_MAC(t0, t1, t2, u[27], m[14]);+ MONT_MAC(v0, v1, v2, u[28], m[13]);+ MONT_MAC(w0, w1, w2, u[29], m[12]);+ MONT_MAC(t0, t1, t2, u[30], m[11]);+ MONT_MAC(v0, v1, v2, u[31], m[10]);+ MONT_MAC(w0, w1, w2, u[32], m[9]);+ MONT_MAC(t0, t1, t2, u[33], m[8]);+ MONT_MAC(v0, v1, v2, u[34], m[7]);+ MONT_MAC(w0, w1, w2, u[35], m[6]);+ MONT_MAC(t0, t1, t2, u[36], m[5]);+ MONT_MAC(v0, v1, v2, u[37], m[4]);+ MONT_MAC(w0, w1, w2, u[38], m[3]);+ MONT_MAC(t0, t1, t2, u[39], m[2]);+ MONT_MAC(v0, v1, v2, u[40], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[41] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[41], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 42 */+ MONT_MUL(s0, s1, s2, a[0], a[42]);+ MONT_MUL(c0, c1, c2, a[1], a[41]);+ MONT_MAC(s0, s1, s2, a[2], a[40]);+ MONT_MAC(c0, c1, c2, a[3], a[39]);+ MONT_MAC(s0, s1, s2, a[4], a[38]);+ MONT_MAC(c0, c1, c2, a[5], a[37]);+ MONT_MAC(s0, s1, s2, a[6], a[36]);+ MONT_MAC(c0, c1, c2, a[7], a[35]);+ MONT_MAC(s0, s1, s2, a[8], a[34]);+ MONT_MAC(c0, c1, c2, a[9], a[33]);+ MONT_MAC(s0, s1, s2, a[10], a[32]);+ MONT_MAC(c0, c1, c2, a[11], a[31]);+ MONT_MAC(s0, s1, s2, a[12], a[30]);+ MONT_MAC(c0, c1, c2, a[13], a[29]);+ MONT_MAC(s0, s1, s2, a[14], a[28]);+ MONT_MAC(c0, c1, c2, a[15], a[27]);+ MONT_MAC(s0, s1, s2, a[16], a[26]);+ MONT_MAC(c0, c1, c2, a[17], a[25]);+ MONT_MAC(s0, s1, s2, a[18], a[24]);+ MONT_MAC(c0, c1, c2, a[19], a[23]);+ MONT_MAC(s0, s1, s2, a[20], a[22]);+ MONT_MAC(t0, t1, t2, a[21], a[21]);+ MONT_MUL(v0, v1, v2, u[0], m[42]);+ MONT_MUL(w0, w1, w2, u[1], m[41]);+ MONT_MAC(t0, t1, t2, u[2], m[40]);+ MONT_MAC(v0, v1, v2, u[3], m[39]);+ MONT_MAC(w0, w1, w2, u[4], m[38]);+ MONT_MAC(t0, t1, t2, u[5], m[37]);+ MONT_MAC(v0, v1, v2, u[6], m[36]);+ MONT_MAC(w0, w1, w2, u[7], m[35]);+ MONT_MAC(t0, t1, t2, u[8], m[34]);+ MONT_MAC(v0, v1, v2, u[9], m[33]);+ MONT_MAC(w0, w1, w2, u[10], m[32]);+ MONT_MAC(t0, t1, t2, u[11], m[31]);+ MONT_MAC(v0, v1, v2, u[12], m[30]);+ MONT_MAC(w0, w1, w2, u[13], m[29]);+ MONT_MAC(t0, t1, t2, u[14], m[28]);+ MONT_MAC(v0, v1, v2, u[15], m[27]);+ MONT_MAC(w0, w1, w2, u[16], m[26]);+ MONT_MAC(t0, t1, t2, u[17], m[25]);+ MONT_MAC(v0, v1, v2, u[18], m[24]);+ MONT_MAC(w0, w1, w2, u[19], m[23]);+ MONT_MAC(t0, t1, t2, u[20], m[22]);+ MONT_MAC(v0, v1, v2, u[21], m[21]);+ MONT_MAC(w0, w1, w2, u[22], m[20]);+ MONT_MAC(t0, t1, t2, u[23], m[19]);+ MONT_MAC(v0, v1, v2, u[24], m[18]);+ MONT_MAC(w0, w1, w2, u[25], m[17]);+ MONT_MAC(t0, t1, t2, u[26], m[16]);+ MONT_MAC(v0, v1, v2, u[27], m[15]);+ MONT_MAC(w0, w1, w2, u[28], m[14]);+ MONT_MAC(t0, t1, t2, u[29], m[13]);+ MONT_MAC(v0, v1, v2, u[30], m[12]);+ MONT_MAC(w0, w1, w2, u[31], m[11]);+ MONT_MAC(t0, t1, t2, u[32], m[10]);+ MONT_MAC(v0, v1, v2, u[33], m[9]);+ MONT_MAC(w0, w1, w2, u[34], m[8]);+ MONT_MAC(t0, t1, t2, u[35], m[7]);+ MONT_MAC(v0, v1, v2, u[36], m[6]);+ MONT_MAC(w0, w1, w2, u[37], m[5]);+ MONT_MAC(t0, t1, t2, u[38], m[4]);+ MONT_MAC(v0, v1, v2, u[39], m[3]);+ MONT_MAC(w0, w1, w2, u[40], m[2]);+ MONT_MAC(t0, t1, t2, u[41], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[42] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[42], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 43 */+ MONT_MUL(s0, s1, s2, a[0], a[43]);+ MONT_MUL(c0, c1, c2, a[1], a[42]);+ MONT_MAC(s0, s1, s2, a[2], a[41]);+ MONT_MAC(c0, c1, c2, a[3], a[40]);+ MONT_MAC(s0, s1, s2, a[4], a[39]);+ MONT_MAC(c0, c1, c2, a[5], a[38]);+ MONT_MAC(s0, s1, s2, a[6], a[37]);+ MONT_MAC(c0, c1, c2, a[7], a[36]);+ MONT_MAC(s0, s1, s2, a[8], a[35]);+ MONT_MAC(c0, c1, c2, a[9], a[34]);+ MONT_MAC(s0, s1, s2, a[10], a[33]);+ MONT_MAC(c0, c1, c2, a[11], a[32]);+ MONT_MAC(s0, s1, s2, a[12], a[31]);+ MONT_MAC(c0, c1, c2, a[13], a[30]);+ MONT_MAC(s0, s1, s2, a[14], a[29]);+ MONT_MAC(c0, c1, c2, a[15], a[28]);+ MONT_MAC(s0, s1, s2, a[16], a[27]);+ MONT_MAC(c0, c1, c2, a[17], a[26]);+ MONT_MAC(s0, s1, s2, a[18], a[25]);+ MONT_MAC(c0, c1, c2, a[19], a[24]);+ MONT_MAC(s0, s1, s2, a[20], a[23]);+ MONT_MAC(c0, c1, c2, a[21], a[22]);+ MONT_MAC(t0, t1, t2, u[0], m[43]);+ MONT_MUL(v0, v1, v2, u[1], m[42]);+ MONT_MUL(w0, w1, w2, u[2], m[41]);+ MONT_MAC(t0, t1, t2, u[3], m[40]);+ MONT_MAC(v0, v1, v2, u[4], m[39]);+ MONT_MAC(w0, w1, w2, u[5], m[38]);+ MONT_MAC(t0, t1, t2, u[6], m[37]);+ MONT_MAC(v0, v1, v2, u[7], m[36]);+ MONT_MAC(w0, w1, w2, u[8], m[35]);+ MONT_MAC(t0, t1, t2, u[9], m[34]);+ MONT_MAC(v0, v1, v2, u[10], m[33]);+ MONT_MAC(w0, w1, w2, u[11], m[32]);+ MONT_MAC(t0, t1, t2, u[12], m[31]);+ MONT_MAC(v0, v1, v2, u[13], m[30]);+ MONT_MAC(w0, w1, w2, u[14], m[29]);+ MONT_MAC(t0, t1, t2, u[15], m[28]);+ MONT_MAC(v0, v1, v2, u[16], m[27]);+ MONT_MAC(w0, w1, w2, u[17], m[26]);+ MONT_MAC(t0, t1, t2, u[18], m[25]);+ MONT_MAC(v0, v1, v2, u[19], m[24]);+ MONT_MAC(w0, w1, w2, u[20], m[23]);+ MONT_MAC(t0, t1, t2, u[21], m[22]);+ MONT_MAC(v0, v1, v2, u[22], m[21]);+ MONT_MAC(w0, w1, w2, u[23], m[20]);+ MONT_MAC(t0, t1, t2, u[24], m[19]);+ MONT_MAC(v0, v1, v2, u[25], m[18]);+ MONT_MAC(w0, w1, w2, u[26], m[17]);+ MONT_MAC(t0, t1, t2, u[27], m[16]);+ MONT_MAC(v0, v1, v2, u[28], m[15]);+ MONT_MAC(w0, w1, w2, u[29], m[14]);+ MONT_MAC(t0, t1, t2, u[30], m[13]);+ MONT_MAC(v0, v1, v2, u[31], m[12]);+ MONT_MAC(w0, w1, w2, u[32], m[11]);+ MONT_MAC(t0, t1, t2, u[33], m[10]);+ MONT_MAC(v0, v1, v2, u[34], m[9]);+ MONT_MAC(w0, w1, w2, u[35], m[8]);+ MONT_MAC(t0, t1, t2, u[36], m[7]);+ MONT_MAC(v0, v1, v2, u[37], m[6]);+ MONT_MAC(w0, w1, w2, u[38], m[5]);+ MONT_MAC(t0, t1, t2, u[39], m[4]);+ MONT_MAC(v0, v1, v2, u[40], m[3]);+ MONT_MAC(w0, w1, w2, u[41], m[2]);+ MONT_MAC(t0, t1, t2, u[42], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[43] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[43], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 44 */+ MONT_MUL(s0, s1, s2, a[0], a[44]);+ MONT_MUL(c0, c1, c2, a[1], a[43]);+ MONT_MAC(s0, s1, s2, a[2], a[42]);+ MONT_MAC(c0, c1, c2, a[3], a[41]);+ MONT_MAC(s0, s1, s2, a[4], a[40]);+ MONT_MAC(c0, c1, c2, a[5], a[39]);+ MONT_MAC(s0, s1, s2, a[6], a[38]);+ MONT_MAC(c0, c1, c2, a[7], a[37]);+ MONT_MAC(s0, s1, s2, a[8], a[36]);+ MONT_MAC(c0, c1, c2, a[9], a[35]);+ MONT_MAC(s0, s1, s2, a[10], a[34]);+ MONT_MAC(c0, c1, c2, a[11], a[33]);+ MONT_MAC(s0, s1, s2, a[12], a[32]);+ MONT_MAC(c0, c1, c2, a[13], a[31]);+ MONT_MAC(s0, s1, s2, a[14], a[30]);+ MONT_MAC(c0, c1, c2, a[15], a[29]);+ MONT_MAC(s0, s1, s2, a[16], a[28]);+ MONT_MAC(c0, c1, c2, a[17], a[27]);+ MONT_MAC(s0, s1, s2, a[18], a[26]);+ MONT_MAC(c0, c1, c2, a[19], a[25]);+ MONT_MAC(s0, s1, s2, a[20], a[24]);+ MONT_MAC(c0, c1, c2, a[21], a[23]);+ MONT_MAC(t0, t1, t2, a[22], a[22]);+ MONT_MUL(v0, v1, v2, u[0], m[44]);+ MONT_MUL(w0, w1, w2, u[1], m[43]);+ MONT_MAC(t0, t1, t2, u[2], m[42]);+ MONT_MAC(v0, v1, v2, u[3], m[41]);+ MONT_MAC(w0, w1, w2, u[4], m[40]);+ MONT_MAC(t0, t1, t2, u[5], m[39]);+ MONT_MAC(v0, v1, v2, u[6], m[38]);+ MONT_MAC(w0, w1, w2, u[7], m[37]);+ MONT_MAC(t0, t1, t2, u[8], m[36]);+ MONT_MAC(v0, v1, v2, u[9], m[35]);+ MONT_MAC(w0, w1, w2, u[10], m[34]);+ MONT_MAC(t0, t1, t2, u[11], m[33]);+ MONT_MAC(v0, v1, v2, u[12], m[32]);+ MONT_MAC(w0, w1, w2, u[13], m[31]);+ MONT_MAC(t0, t1, t2, u[14], m[30]);+ MONT_MAC(v0, v1, v2, u[15], m[29]);+ MONT_MAC(w0, w1, w2, u[16], m[28]);+ MONT_MAC(t0, t1, t2, u[17], m[27]);+ MONT_MAC(v0, v1, v2, u[18], m[26]);+ MONT_MAC(w0, w1, w2, u[19], m[25]);+ MONT_MAC(t0, t1, t2, u[20], m[24]);+ MONT_MAC(v0, v1, v2, u[21], m[23]);+ MONT_MAC(w0, w1, w2, u[22], m[22]);+ MONT_MAC(t0, t1, t2, u[23], m[21]);+ MONT_MAC(v0, v1, v2, u[24], m[20]);+ MONT_MAC(w0, w1, w2, u[25], m[19]);+ MONT_MAC(t0, t1, t2, u[26], m[18]);+ MONT_MAC(v0, v1, v2, u[27], m[17]);+ MONT_MAC(w0, w1, w2, u[28], m[16]);+ MONT_MAC(t0, t1, t2, u[29], m[15]);+ MONT_MAC(v0, v1, v2, u[30], m[14]);+ MONT_MAC(w0, w1, w2, u[31], m[13]);+ MONT_MAC(t0, t1, t2, u[32], m[12]);+ MONT_MAC(v0, v1, v2, u[33], m[11]);+ MONT_MAC(w0, w1, w2, u[34], m[10]);+ MONT_MAC(t0, t1, t2, u[35], m[9]);+ MONT_MAC(v0, v1, v2, u[36], m[8]);+ MONT_MAC(w0, w1, w2, u[37], m[7]);+ MONT_MAC(t0, t1, t2, u[38], m[6]);+ MONT_MAC(v0, v1, v2, u[39], m[5]);+ MONT_MAC(w0, w1, w2, u[40], m[4]);+ MONT_MAC(t0, t1, t2, u[41], m[3]);+ MONT_MAC(v0, v1, v2, u[42], m[2]);+ MONT_MAC(w0, w1, w2, u[43], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[44] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[44], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 45 */+ MONT_MUL(s0, s1, s2, a[0], a[45]);+ MONT_MUL(c0, c1, c2, a[1], a[44]);+ MONT_MAC(s0, s1, s2, a[2], a[43]);+ MONT_MAC(c0, c1, c2, a[3], a[42]);+ MONT_MAC(s0, s1, s2, a[4], a[41]);+ MONT_MAC(c0, c1, c2, a[5], a[40]);+ MONT_MAC(s0, s1, s2, a[6], a[39]);+ MONT_MAC(c0, c1, c2, a[7], a[38]);+ MONT_MAC(s0, s1, s2, a[8], a[37]);+ MONT_MAC(c0, c1, c2, a[9], a[36]);+ MONT_MAC(s0, s1, s2, a[10], a[35]);+ MONT_MAC(c0, c1, c2, a[11], a[34]);+ MONT_MAC(s0, s1, s2, a[12], a[33]);+ MONT_MAC(c0, c1, c2, a[13], a[32]);+ MONT_MAC(s0, s1, s2, a[14], a[31]);+ MONT_MAC(c0, c1, c2, a[15], a[30]);+ MONT_MAC(s0, s1, s2, a[16], a[29]);+ MONT_MAC(c0, c1, c2, a[17], a[28]);+ MONT_MAC(s0, s1, s2, a[18], a[27]);+ MONT_MAC(c0, c1, c2, a[19], a[26]);+ MONT_MAC(s0, s1, s2, a[20], a[25]);+ MONT_MAC(c0, c1, c2, a[21], a[24]);+ MONT_MAC(s0, s1, s2, a[22], a[23]);+ MONT_MAC(t0, t1, t2, u[0], m[45]);+ MONT_MUL(v0, v1, v2, u[1], m[44]);+ MONT_MUL(w0, w1, w2, u[2], m[43]);+ MONT_MAC(t0, t1, t2, u[3], m[42]);+ MONT_MAC(v0, v1, v2, u[4], m[41]);+ MONT_MAC(w0, w1, w2, u[5], m[40]);+ MONT_MAC(t0, t1, t2, u[6], m[39]);+ MONT_MAC(v0, v1, v2, u[7], m[38]);+ MONT_MAC(w0, w1, w2, u[8], m[37]);+ MONT_MAC(t0, t1, t2, u[9], m[36]);+ MONT_MAC(v0, v1, v2, u[10], m[35]);+ MONT_MAC(w0, w1, w2, u[11], m[34]);+ MONT_MAC(t0, t1, t2, u[12], m[33]);+ MONT_MAC(v0, v1, v2, u[13], m[32]);+ MONT_MAC(w0, w1, w2, u[14], m[31]);+ MONT_MAC(t0, t1, t2, u[15], m[30]);+ MONT_MAC(v0, v1, v2, u[16], m[29]);+ MONT_MAC(w0, w1, w2, u[17], m[28]);+ MONT_MAC(t0, t1, t2, u[18], m[27]);+ MONT_MAC(v0, v1, v2, u[19], m[26]);+ MONT_MAC(w0, w1, w2, u[20], m[25]);+ MONT_MAC(t0, t1, t2, u[21], m[24]);+ MONT_MAC(v0, v1, v2, u[22], m[23]);+ MONT_MAC(w0, w1, w2, u[23], m[22]);+ MONT_MAC(t0, t1, t2, u[24], m[21]);+ MONT_MAC(v0, v1, v2, u[25], m[20]);+ MONT_MAC(w0, w1, w2, u[26], m[19]);+ MONT_MAC(t0, t1, t2, u[27], m[18]);+ MONT_MAC(v0, v1, v2, u[28], m[17]);+ MONT_MAC(w0, w1, w2, u[29], m[16]);+ MONT_MAC(t0, t1, t2, u[30], m[15]);+ MONT_MAC(v0, v1, v2, u[31], m[14]);+ MONT_MAC(w0, w1, w2, u[32], m[13]);+ MONT_MAC(t0, t1, t2, u[33], m[12]);+ MONT_MAC(v0, v1, v2, u[34], m[11]);+ MONT_MAC(w0, w1, w2, u[35], m[10]);+ MONT_MAC(t0, t1, t2, u[36], m[9]);+ MONT_MAC(v0, v1, v2, u[37], m[8]);+ MONT_MAC(w0, w1, w2, u[38], m[7]);+ MONT_MAC(t0, t1, t2, u[39], m[6]);+ MONT_MAC(v0, v1, v2, u[40], m[5]);+ MONT_MAC(w0, w1, w2, u[41], m[4]);+ MONT_MAC(t0, t1, t2, u[42], m[3]);+ MONT_MAC(v0, v1, v2, u[43], m[2]);+ MONT_MAC(w0, w1, w2, u[44], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[45] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[45], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 46 */+ MONT_MUL(s0, s1, s2, a[0], a[46]);+ MONT_MUL(c0, c1, c2, a[1], a[45]);+ MONT_MAC(s0, s1, s2, a[2], a[44]);+ MONT_MAC(c0, c1, c2, a[3], a[43]);+ MONT_MAC(s0, s1, s2, a[4], a[42]);+ MONT_MAC(c0, c1, c2, a[5], a[41]);+ MONT_MAC(s0, s1, s2, a[6], a[40]);+ MONT_MAC(c0, c1, c2, a[7], a[39]);+ MONT_MAC(s0, s1, s2, a[8], a[38]);+ MONT_MAC(c0, c1, c2, a[9], a[37]);+ MONT_MAC(s0, s1, s2, a[10], a[36]);+ MONT_MAC(c0, c1, c2, a[11], a[35]);+ MONT_MAC(s0, s1, s2, a[12], a[34]);+ MONT_MAC(c0, c1, c2, a[13], a[33]);+ MONT_MAC(s0, s1, s2, a[14], a[32]);+ MONT_MAC(c0, c1, c2, a[15], a[31]);+ MONT_MAC(s0, s1, s2, a[16], a[30]);+ MONT_MAC(c0, c1, c2, a[17], a[29]);+ MONT_MAC(s0, s1, s2, a[18], a[28]);+ MONT_MAC(c0, c1, c2, a[19], a[27]);+ MONT_MAC(s0, s1, s2, a[20], a[26]);+ MONT_MAC(c0, c1, c2, a[21], a[25]);+ MONT_MAC(s0, s1, s2, a[22], a[24]);+ MONT_MAC(t0, t1, t2, a[23], a[23]);+ MONT_MUL(v0, v1, v2, u[0], m[46]);+ MONT_MUL(w0, w1, w2, u[1], m[45]);+ MONT_MAC(t0, t1, t2, u[2], m[44]);+ MONT_MAC(v0, v1, v2, u[3], m[43]);+ MONT_MAC(w0, w1, w2, u[4], m[42]);+ MONT_MAC(t0, t1, t2, u[5], m[41]);+ MONT_MAC(v0, v1, v2, u[6], m[40]);+ MONT_MAC(w0, w1, w2, u[7], m[39]);+ MONT_MAC(t0, t1, t2, u[8], m[38]);+ MONT_MAC(v0, v1, v2, u[9], m[37]);+ MONT_MAC(w0, w1, w2, u[10], m[36]);+ MONT_MAC(t0, t1, t2, u[11], m[35]);+ MONT_MAC(v0, v1, v2, u[12], m[34]);+ MONT_MAC(w0, w1, w2, u[13], m[33]);+ MONT_MAC(t0, t1, t2, u[14], m[32]);+ MONT_MAC(v0, v1, v2, u[15], m[31]);+ MONT_MAC(w0, w1, w2, u[16], m[30]);+ MONT_MAC(t0, t1, t2, u[17], m[29]);+ MONT_MAC(v0, v1, v2, u[18], m[28]);+ MONT_MAC(w0, w1, w2, u[19], m[27]);+ MONT_MAC(t0, t1, t2, u[20], m[26]);+ MONT_MAC(v0, v1, v2, u[21], m[25]);+ MONT_MAC(w0, w1, w2, u[22], m[24]);+ MONT_MAC(t0, t1, t2, u[23], m[23]);+ MONT_MAC(v0, v1, v2, u[24], m[22]);+ MONT_MAC(w0, w1, w2, u[25], m[21]);+ MONT_MAC(t0, t1, t2, u[26], m[20]);+ MONT_MAC(v0, v1, v2, u[27], m[19]);+ MONT_MAC(w0, w1, w2, u[28], m[18]);+ MONT_MAC(t0, t1, t2, u[29], m[17]);+ MONT_MAC(v0, v1, v2, u[30], m[16]);+ MONT_MAC(w0, w1, w2, u[31], m[15]);+ MONT_MAC(t0, t1, t2, u[32], m[14]);+ MONT_MAC(v0, v1, v2, u[33], m[13]);+ MONT_MAC(w0, w1, w2, u[34], m[12]);+ MONT_MAC(t0, t1, t2, u[35], m[11]);+ MONT_MAC(v0, v1, v2, u[36], m[10]);+ MONT_MAC(w0, w1, w2, u[37], m[9]);+ MONT_MAC(t0, t1, t2, u[38], m[8]);+ MONT_MAC(v0, v1, v2, u[39], m[7]);+ MONT_MAC(w0, w1, w2, u[40], m[6]);+ MONT_MAC(t0, t1, t2, u[41], m[5]);+ MONT_MAC(v0, v1, v2, u[42], m[4]);+ MONT_MAC(w0, w1, w2, u[43], m[3]);+ MONT_MAC(t0, t1, t2, u[44], m[2]);+ MONT_MAC(v0, v1, v2, u[45], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[46] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[46], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 47 */+ MONT_MUL(s0, s1, s2, a[0], a[47]);+ MONT_MUL(c0, c1, c2, a[1], a[46]);+ MONT_MAC(s0, s1, s2, a[2], a[45]);+ MONT_MAC(c0, c1, c2, a[3], a[44]);+ MONT_MAC(s0, s1, s2, a[4], a[43]);+ MONT_MAC(c0, c1, c2, a[5], a[42]);+ MONT_MAC(s0, s1, s2, a[6], a[41]);+ MONT_MAC(c0, c1, c2, a[7], a[40]);+ MONT_MAC(s0, s1, s2, a[8], a[39]);+ MONT_MAC(c0, c1, c2, a[9], a[38]);+ MONT_MAC(s0, s1, s2, a[10], a[37]);+ MONT_MAC(c0, c1, c2, a[11], a[36]);+ MONT_MAC(s0, s1, s2, a[12], a[35]);+ MONT_MAC(c0, c1, c2, a[13], a[34]);+ MONT_MAC(s0, s1, s2, a[14], a[33]);+ MONT_MAC(c0, c1, c2, a[15], a[32]);+ MONT_MAC(s0, s1, s2, a[16], a[31]);+ MONT_MAC(c0, c1, c2, a[17], a[30]);+ MONT_MAC(s0, s1, s2, a[18], a[29]);+ MONT_MAC(c0, c1, c2, a[19], a[28]);+ MONT_MAC(s0, s1, s2, a[20], a[27]);+ MONT_MAC(c0, c1, c2, a[21], a[26]);+ MONT_MAC(s0, s1, s2, a[22], a[25]);+ MONT_MAC(c0, c1, c2, a[23], a[24]);+ MONT_MAC(t0, t1, t2, u[0], m[47]);+ MONT_MUL(v0, v1, v2, u[1], m[46]);+ MONT_MUL(w0, w1, w2, u[2], m[45]);+ MONT_MAC(t0, t1, t2, u[3], m[44]);+ MONT_MAC(v0, v1, v2, u[4], m[43]);+ MONT_MAC(w0, w1, w2, u[5], m[42]);+ MONT_MAC(t0, t1, t2, u[6], m[41]);+ MONT_MAC(v0, v1, v2, u[7], m[40]);+ MONT_MAC(w0, w1, w2, u[8], m[39]);+ MONT_MAC(t0, t1, t2, u[9], m[38]);+ MONT_MAC(v0, v1, v2, u[10], m[37]);+ MONT_MAC(w0, w1, w2, u[11], m[36]);+ MONT_MAC(t0, t1, t2, u[12], m[35]);+ MONT_MAC(v0, v1, v2, u[13], m[34]);+ MONT_MAC(w0, w1, w2, u[14], m[33]);+ MONT_MAC(t0, t1, t2, u[15], m[32]);+ MONT_MAC(v0, v1, v2, u[16], m[31]);+ MONT_MAC(w0, w1, w2, u[17], m[30]);+ MONT_MAC(t0, t1, t2, u[18], m[29]);+ MONT_MAC(v0, v1, v2, u[19], m[28]);+ MONT_MAC(w0, w1, w2, u[20], m[27]);+ MONT_MAC(t0, t1, t2, u[21], m[26]);+ MONT_MAC(v0, v1, v2, u[22], m[25]);+ MONT_MAC(w0, w1, w2, u[23], m[24]);+ MONT_MAC(t0, t1, t2, u[24], m[23]);+ MONT_MAC(v0, v1, v2, u[25], m[22]);+ MONT_MAC(w0, w1, w2, u[26], m[21]);+ MONT_MAC(t0, t1, t2, u[27], m[20]);+ MONT_MAC(v0, v1, v2, u[28], m[19]);+ MONT_MAC(w0, w1, w2, u[29], m[18]);+ MONT_MAC(t0, t1, t2, u[30], m[17]);+ MONT_MAC(v0, v1, v2, u[31], m[16]);+ MONT_MAC(w0, w1, w2, u[32], m[15]);+ MONT_MAC(t0, t1, t2, u[33], m[14]);+ MONT_MAC(v0, v1, v2, u[34], m[13]);+ MONT_MAC(w0, w1, w2, u[35], m[12]);+ MONT_MAC(t0, t1, t2, u[36], m[11]);+ MONT_MAC(v0, v1, v2, u[37], m[10]);+ MONT_MAC(w0, w1, w2, u[38], m[9]);+ MONT_MAC(t0, t1, t2, u[39], m[8]);+ MONT_MAC(v0, v1, v2, u[40], m[7]);+ MONT_MAC(w0, w1, w2, u[41], m[6]);+ MONT_MAC(t0, t1, t2, u[42], m[5]);+ MONT_MAC(v0, v1, v2, u[43], m[4]);+ MONT_MAC(w0, w1, w2, u[44], m[3]);+ MONT_MAC(t0, t1, t2, u[45], m[2]);+ MONT_MAC(v0, v1, v2, u[46], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ u[47] = t0 * n0;+ MONT_MAC(t0, t1, t2, u[47], m[0]);+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 48 */+ MONT_MUL(s0, s1, s2, a[1], a[47]);+ MONT_MUL(c0, c1, c2, a[2], a[46]);+ MONT_MAC(s0, s1, s2, a[3], a[45]);+ MONT_MAC(c0, c1, c2, a[4], a[44]);+ MONT_MAC(s0, s1, s2, a[5], a[43]);+ MONT_MAC(c0, c1, c2, a[6], a[42]);+ MONT_MAC(s0, s1, s2, a[7], a[41]);+ MONT_MAC(c0, c1, c2, a[8], a[40]);+ MONT_MAC(s0, s1, s2, a[9], a[39]);+ MONT_MAC(c0, c1, c2, a[10], a[38]);+ MONT_MAC(s0, s1, s2, a[11], a[37]);+ MONT_MAC(c0, c1, c2, a[12], a[36]);+ MONT_MAC(s0, s1, s2, a[13], a[35]);+ MONT_MAC(c0, c1, c2, a[14], a[34]);+ MONT_MAC(s0, s1, s2, a[15], a[33]);+ MONT_MAC(c0, c1, c2, a[16], a[32]);+ MONT_MAC(s0, s1, s2, a[17], a[31]);+ MONT_MAC(c0, c1, c2, a[18], a[30]);+ MONT_MAC(s0, s1, s2, a[19], a[29]);+ MONT_MAC(c0, c1, c2, a[20], a[28]);+ MONT_MAC(s0, s1, s2, a[21], a[27]);+ MONT_MAC(c0, c1, c2, a[22], a[26]);+ MONT_MAC(s0, s1, s2, a[23], a[25]);+ MONT_MAC(t0, t1, t2, a[24], a[24]);+ MONT_MUL(v0, v1, v2, u[1], m[47]);+ MONT_MUL(w0, w1, w2, u[2], m[46]);+ MONT_MAC(t0, t1, t2, u[3], m[45]);+ MONT_MAC(v0, v1, v2, u[4], m[44]);+ MONT_MAC(w0, w1, w2, u[5], m[43]);+ MONT_MAC(t0, t1, t2, u[6], m[42]);+ MONT_MAC(v0, v1, v2, u[7], m[41]);+ MONT_MAC(w0, w1, w2, u[8], m[40]);+ MONT_MAC(t0, t1, t2, u[9], m[39]);+ MONT_MAC(v0, v1, v2, u[10], m[38]);+ MONT_MAC(w0, w1, w2, u[11], m[37]);+ MONT_MAC(t0, t1, t2, u[12], m[36]);+ MONT_MAC(v0, v1, v2, u[13], m[35]);+ MONT_MAC(w0, w1, w2, u[14], m[34]);+ MONT_MAC(t0, t1, t2, u[15], m[33]);+ MONT_MAC(v0, v1, v2, u[16], m[32]);+ MONT_MAC(w0, w1, w2, u[17], m[31]);+ MONT_MAC(t0, t1, t2, u[18], m[30]);+ MONT_MAC(v0, v1, v2, u[19], m[29]);+ MONT_MAC(w0, w1, w2, u[20], m[28]);+ MONT_MAC(t0, t1, t2, u[21], m[27]);+ MONT_MAC(v0, v1, v2, u[22], m[26]);+ MONT_MAC(w0, w1, w2, u[23], m[25]);+ MONT_MAC(t0, t1, t2, u[24], m[24]);+ MONT_MAC(v0, v1, v2, u[25], m[23]);+ MONT_MAC(w0, w1, w2, u[26], m[22]);+ MONT_MAC(t0, t1, t2, u[27], m[21]);+ MONT_MAC(v0, v1, v2, u[28], m[20]);+ MONT_MAC(w0, w1, w2, u[29], m[19]);+ MONT_MAC(t0, t1, t2, u[30], m[18]);+ MONT_MAC(v0, v1, v2, u[31], m[17]);+ MONT_MAC(w0, w1, w2, u[32], m[16]);+ MONT_MAC(t0, t1, t2, u[33], m[15]);+ MONT_MAC(v0, v1, v2, u[34], m[14]);+ MONT_MAC(w0, w1, w2, u[35], m[13]);+ MONT_MAC(t0, t1, t2, u[36], m[12]);+ MONT_MAC(v0, v1, v2, u[37], m[11]);+ MONT_MAC(w0, w1, w2, u[38], m[10]);+ MONT_MAC(t0, t1, t2, u[39], m[9]);+ MONT_MAC(v0, v1, v2, u[40], m[8]);+ MONT_MAC(w0, w1, w2, u[41], m[7]);+ MONT_MAC(t0, t1, t2, u[42], m[6]);+ MONT_MAC(v0, v1, v2, u[43], m[5]);+ MONT_MAC(w0, w1, w2, u[44], m[4]);+ MONT_MAC(t0, t1, t2, u[45], m[3]);+ MONT_MAC(v0, v1, v2, u[46], m[2]);+ MONT_MAC(w0, w1, w2, u[47], m[1]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[0] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 49 */+ MONT_MUL(s0, s1, s2, a[2], a[47]);+ MONT_MUL(c0, c1, c2, a[3], a[46]);+ MONT_MAC(s0, s1, s2, a[4], a[45]);+ MONT_MAC(c0, c1, c2, a[5], a[44]);+ MONT_MAC(s0, s1, s2, a[6], a[43]);+ MONT_MAC(c0, c1, c2, a[7], a[42]);+ MONT_MAC(s0, s1, s2, a[8], a[41]);+ MONT_MAC(c0, c1, c2, a[9], a[40]);+ MONT_MAC(s0, s1, s2, a[10], a[39]);+ MONT_MAC(c0, c1, c2, a[11], a[38]);+ MONT_MAC(s0, s1, s2, a[12], a[37]);+ MONT_MAC(c0, c1, c2, a[13], a[36]);+ MONT_MAC(s0, s1, s2, a[14], a[35]);+ MONT_MAC(c0, c1, c2, a[15], a[34]);+ MONT_MAC(s0, s1, s2, a[16], a[33]);+ MONT_MAC(c0, c1, c2, a[17], a[32]);+ MONT_MAC(s0, s1, s2, a[18], a[31]);+ MONT_MAC(c0, c1, c2, a[19], a[30]);+ MONT_MAC(s0, s1, s2, a[20], a[29]);+ MONT_MAC(c0, c1, c2, a[21], a[28]);+ MONT_MAC(s0, s1, s2, a[22], a[27]);+ MONT_MAC(c0, c1, c2, a[23], a[26]);+ MONT_MAC(s0, s1, s2, a[24], a[25]);+ MONT_MAC(t0, t1, t2, u[2], m[47]);+ MONT_MUL(v0, v1, v2, u[3], m[46]);+ MONT_MUL(w0, w1, w2, u[4], m[45]);+ MONT_MAC(t0, t1, t2, u[5], m[44]);+ MONT_MAC(v0, v1, v2, u[6], m[43]);+ MONT_MAC(w0, w1, w2, u[7], m[42]);+ MONT_MAC(t0, t1, t2, u[8], m[41]);+ MONT_MAC(v0, v1, v2, u[9], m[40]);+ MONT_MAC(w0, w1, w2, u[10], m[39]);+ MONT_MAC(t0, t1, t2, u[11], m[38]);+ MONT_MAC(v0, v1, v2, u[12], m[37]);+ MONT_MAC(w0, w1, w2, u[13], m[36]);+ MONT_MAC(t0, t1, t2, u[14], m[35]);+ MONT_MAC(v0, v1, v2, u[15], m[34]);+ MONT_MAC(w0, w1, w2, u[16], m[33]);+ MONT_MAC(t0, t1, t2, u[17], m[32]);+ MONT_MAC(v0, v1, v2, u[18], m[31]);+ MONT_MAC(w0, w1, w2, u[19], m[30]);+ MONT_MAC(t0, t1, t2, u[20], m[29]);+ MONT_MAC(v0, v1, v2, u[21], m[28]);+ MONT_MAC(w0, w1, w2, u[22], m[27]);+ MONT_MAC(t0, t1, t2, u[23], m[26]);+ MONT_MAC(v0, v1, v2, u[24], m[25]);+ MONT_MAC(w0, w1, w2, u[25], m[24]);+ MONT_MAC(t0, t1, t2, u[26], m[23]);+ MONT_MAC(v0, v1, v2, u[27], m[22]);+ MONT_MAC(w0, w1, w2, u[28], m[21]);+ MONT_MAC(t0, t1, t2, u[29], m[20]);+ MONT_MAC(v0, v1, v2, u[30], m[19]);+ MONT_MAC(w0, w1, w2, u[31], m[18]);+ MONT_MAC(t0, t1, t2, u[32], m[17]);+ MONT_MAC(v0, v1, v2, u[33], m[16]);+ MONT_MAC(w0, w1, w2, u[34], m[15]);+ MONT_MAC(t0, t1, t2, u[35], m[14]);+ MONT_MAC(v0, v1, v2, u[36], m[13]);+ MONT_MAC(w0, w1, w2, u[37], m[12]);+ MONT_MAC(t0, t1, t2, u[38], m[11]);+ MONT_MAC(v0, v1, v2, u[39], m[10]);+ MONT_MAC(w0, w1, w2, u[40], m[9]);+ MONT_MAC(t0, t1, t2, u[41], m[8]);+ MONT_MAC(v0, v1, v2, u[42], m[7]);+ MONT_MAC(w0, w1, w2, u[43], m[6]);+ MONT_MAC(t0, t1, t2, u[44], m[5]);+ MONT_MAC(v0, v1, v2, u[45], m[4]);+ MONT_MAC(w0, w1, w2, u[46], m[3]);+ MONT_MAC(t0, t1, t2, u[47], m[2]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[1] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 50 */+ MONT_MUL(s0, s1, s2, a[3], a[47]);+ MONT_MUL(c0, c1, c2, a[4], a[46]);+ MONT_MAC(s0, s1, s2, a[5], a[45]);+ MONT_MAC(c0, c1, c2, a[6], a[44]);+ MONT_MAC(s0, s1, s2, a[7], a[43]);+ MONT_MAC(c0, c1, c2, a[8], a[42]);+ MONT_MAC(s0, s1, s2, a[9], a[41]);+ MONT_MAC(c0, c1, c2, a[10], a[40]);+ MONT_MAC(s0, s1, s2, a[11], a[39]);+ MONT_MAC(c0, c1, c2, a[12], a[38]);+ MONT_MAC(s0, s1, s2, a[13], a[37]);+ MONT_MAC(c0, c1, c2, a[14], a[36]);+ MONT_MAC(s0, s1, s2, a[15], a[35]);+ MONT_MAC(c0, c1, c2, a[16], a[34]);+ MONT_MAC(s0, s1, s2, a[17], a[33]);+ MONT_MAC(c0, c1, c2, a[18], a[32]);+ MONT_MAC(s0, s1, s2, a[19], a[31]);+ MONT_MAC(c0, c1, c2, a[20], a[30]);+ MONT_MAC(s0, s1, s2, a[21], a[29]);+ MONT_MAC(c0, c1, c2, a[22], a[28]);+ MONT_MAC(s0, s1, s2, a[23], a[27]);+ MONT_MAC(c0, c1, c2, a[24], a[26]);+ MONT_MAC(t0, t1, t2, a[25], a[25]);+ MONT_MUL(v0, v1, v2, u[3], m[47]);+ MONT_MUL(w0, w1, w2, u[4], m[46]);+ MONT_MAC(t0, t1, t2, u[5], m[45]);+ MONT_MAC(v0, v1, v2, u[6], m[44]);+ MONT_MAC(w0, w1, w2, u[7], m[43]);+ MONT_MAC(t0, t1, t2, u[8], m[42]);+ MONT_MAC(v0, v1, v2, u[9], m[41]);+ MONT_MAC(w0, w1, w2, u[10], m[40]);+ MONT_MAC(t0, t1, t2, u[11], m[39]);+ MONT_MAC(v0, v1, v2, u[12], m[38]);+ MONT_MAC(w0, w1, w2, u[13], m[37]);+ MONT_MAC(t0, t1, t2, u[14], m[36]);+ MONT_MAC(v0, v1, v2, u[15], m[35]);+ MONT_MAC(w0, w1, w2, u[16], m[34]);+ MONT_MAC(t0, t1, t2, u[17], m[33]);+ MONT_MAC(v0, v1, v2, u[18], m[32]);+ MONT_MAC(w0, w1, w2, u[19], m[31]);+ MONT_MAC(t0, t1, t2, u[20], m[30]);+ MONT_MAC(v0, v1, v2, u[21], m[29]);+ MONT_MAC(w0, w1, w2, u[22], m[28]);+ MONT_MAC(t0, t1, t2, u[23], m[27]);+ MONT_MAC(v0, v1, v2, u[24], m[26]);+ MONT_MAC(w0, w1, w2, u[25], m[25]);+ MONT_MAC(t0, t1, t2, u[26], m[24]);+ MONT_MAC(v0, v1, v2, u[27], m[23]);+ MONT_MAC(w0, w1, w2, u[28], m[22]);+ MONT_MAC(t0, t1, t2, u[29], m[21]);+ MONT_MAC(v0, v1, v2, u[30], m[20]);+ MONT_MAC(w0, w1, w2, u[31], m[19]);+ MONT_MAC(t0, t1, t2, u[32], m[18]);+ MONT_MAC(v0, v1, v2, u[33], m[17]);+ MONT_MAC(w0, w1, w2, u[34], m[16]);+ MONT_MAC(t0, t1, t2, u[35], m[15]);+ MONT_MAC(v0, v1, v2, u[36], m[14]);+ MONT_MAC(w0, w1, w2, u[37], m[13]);+ MONT_MAC(t0, t1, t2, u[38], m[12]);+ MONT_MAC(v0, v1, v2, u[39], m[11]);+ MONT_MAC(w0, w1, w2, u[40], m[10]);+ MONT_MAC(t0, t1, t2, u[41], m[9]);+ MONT_MAC(v0, v1, v2, u[42], m[8]);+ MONT_MAC(w0, w1, w2, u[43], m[7]);+ MONT_MAC(t0, t1, t2, u[44], m[6]);+ MONT_MAC(v0, v1, v2, u[45], m[5]);+ MONT_MAC(w0, w1, w2, u[46], m[4]);+ MONT_MAC(t0, t1, t2, u[47], m[3]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[2] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 51 */+ MONT_MUL(s0, s1, s2, a[4], a[47]);+ MONT_MUL(c0, c1, c2, a[5], a[46]);+ MONT_MAC(s0, s1, s2, a[6], a[45]);+ MONT_MAC(c0, c1, c2, a[7], a[44]);+ MONT_MAC(s0, s1, s2, a[8], a[43]);+ MONT_MAC(c0, c1, c2, a[9], a[42]);+ MONT_MAC(s0, s1, s2, a[10], a[41]);+ MONT_MAC(c0, c1, c2, a[11], a[40]);+ MONT_MAC(s0, s1, s2, a[12], a[39]);+ MONT_MAC(c0, c1, c2, a[13], a[38]);+ MONT_MAC(s0, s1, s2, a[14], a[37]);+ MONT_MAC(c0, c1, c2, a[15], a[36]);+ MONT_MAC(s0, s1, s2, a[16], a[35]);+ MONT_MAC(c0, c1, c2, a[17], a[34]);+ MONT_MAC(s0, s1, s2, a[18], a[33]);+ MONT_MAC(c0, c1, c2, a[19], a[32]);+ MONT_MAC(s0, s1, s2, a[20], a[31]);+ MONT_MAC(c0, c1, c2, a[21], a[30]);+ MONT_MAC(s0, s1, s2, a[22], a[29]);+ MONT_MAC(c0, c1, c2, a[23], a[28]);+ MONT_MAC(s0, s1, s2, a[24], a[27]);+ MONT_MAC(c0, c1, c2, a[25], a[26]);+ MONT_MAC(t0, t1, t2, u[4], m[47]);+ MONT_MUL(v0, v1, v2, u[5], m[46]);+ MONT_MUL(w0, w1, w2, u[6], m[45]);+ MONT_MAC(t0, t1, t2, u[7], m[44]);+ MONT_MAC(v0, v1, v2, u[8], m[43]);+ MONT_MAC(w0, w1, w2, u[9], m[42]);+ MONT_MAC(t0, t1, t2, u[10], m[41]);+ MONT_MAC(v0, v1, v2, u[11], m[40]);+ MONT_MAC(w0, w1, w2, u[12], m[39]);+ MONT_MAC(t0, t1, t2, u[13], m[38]);+ MONT_MAC(v0, v1, v2, u[14], m[37]);+ MONT_MAC(w0, w1, w2, u[15], m[36]);+ MONT_MAC(t0, t1, t2, u[16], m[35]);+ MONT_MAC(v0, v1, v2, u[17], m[34]);+ MONT_MAC(w0, w1, w2, u[18], m[33]);+ MONT_MAC(t0, t1, t2, u[19], m[32]);+ MONT_MAC(v0, v1, v2, u[20], m[31]);+ MONT_MAC(w0, w1, w2, u[21], m[30]);+ MONT_MAC(t0, t1, t2, u[22], m[29]);+ MONT_MAC(v0, v1, v2, u[23], m[28]);+ MONT_MAC(w0, w1, w2, u[24], m[27]);+ MONT_MAC(t0, t1, t2, u[25], m[26]);+ MONT_MAC(v0, v1, v2, u[26], m[25]);+ MONT_MAC(w0, w1, w2, u[27], m[24]);+ MONT_MAC(t0, t1, t2, u[28], m[23]);+ MONT_MAC(v0, v1, v2, u[29], m[22]);+ MONT_MAC(w0, w1, w2, u[30], m[21]);+ MONT_MAC(t0, t1, t2, u[31], m[20]);+ MONT_MAC(v0, v1, v2, u[32], m[19]);+ MONT_MAC(w0, w1, w2, u[33], m[18]);+ MONT_MAC(t0, t1, t2, u[34], m[17]);+ MONT_MAC(v0, v1, v2, u[35], m[16]);+ MONT_MAC(w0, w1, w2, u[36], m[15]);+ MONT_MAC(t0, t1, t2, u[37], m[14]);+ MONT_MAC(v0, v1, v2, u[38], m[13]);+ MONT_MAC(w0, w1, w2, u[39], m[12]);+ MONT_MAC(t0, t1, t2, u[40], m[11]);+ MONT_MAC(v0, v1, v2, u[41], m[10]);+ MONT_MAC(w0, w1, w2, u[42], m[9]);+ MONT_MAC(t0, t1, t2, u[43], m[8]);+ MONT_MAC(v0, v1, v2, u[44], m[7]);+ MONT_MAC(w0, w1, w2, u[45], m[6]);+ MONT_MAC(t0, t1, t2, u[46], m[5]);+ MONT_MAC(v0, v1, v2, u[47], m[4]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[3] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 52 */+ MONT_MUL(s0, s1, s2, a[5], a[47]);+ MONT_MUL(c0, c1, c2, a[6], a[46]);+ MONT_MAC(s0, s1, s2, a[7], a[45]);+ MONT_MAC(c0, c1, c2, a[8], a[44]);+ MONT_MAC(s0, s1, s2, a[9], a[43]);+ MONT_MAC(c0, c1, c2, a[10], a[42]);+ MONT_MAC(s0, s1, s2, a[11], a[41]);+ MONT_MAC(c0, c1, c2, a[12], a[40]);+ MONT_MAC(s0, s1, s2, a[13], a[39]);+ MONT_MAC(c0, c1, c2, a[14], a[38]);+ MONT_MAC(s0, s1, s2, a[15], a[37]);+ MONT_MAC(c0, c1, c2, a[16], a[36]);+ MONT_MAC(s0, s1, s2, a[17], a[35]);+ MONT_MAC(c0, c1, c2, a[18], a[34]);+ MONT_MAC(s0, s1, s2, a[19], a[33]);+ MONT_MAC(c0, c1, c2, a[20], a[32]);+ MONT_MAC(s0, s1, s2, a[21], a[31]);+ MONT_MAC(c0, c1, c2, a[22], a[30]);+ MONT_MAC(s0, s1, s2, a[23], a[29]);+ MONT_MAC(c0, c1, c2, a[24], a[28]);+ MONT_MAC(s0, s1, s2, a[25], a[27]);+ MONT_MAC(t0, t1, t2, a[26], a[26]);+ MONT_MUL(v0, v1, v2, u[5], m[47]);+ MONT_MUL(w0, w1, w2, u[6], m[46]);+ MONT_MAC(t0, t1, t2, u[7], m[45]);+ MONT_MAC(v0, v1, v2, u[8], m[44]);+ MONT_MAC(w0, w1, w2, u[9], m[43]);+ MONT_MAC(t0, t1, t2, u[10], m[42]);+ MONT_MAC(v0, v1, v2, u[11], m[41]);+ MONT_MAC(w0, w1, w2, u[12], m[40]);+ MONT_MAC(t0, t1, t2, u[13], m[39]);+ MONT_MAC(v0, v1, v2, u[14], m[38]);+ MONT_MAC(w0, w1, w2, u[15], m[37]);+ MONT_MAC(t0, t1, t2, u[16], m[36]);+ MONT_MAC(v0, v1, v2, u[17], m[35]);+ MONT_MAC(w0, w1, w2, u[18], m[34]);+ MONT_MAC(t0, t1, t2, u[19], m[33]);+ MONT_MAC(v0, v1, v2, u[20], m[32]);+ MONT_MAC(w0, w1, w2, u[21], m[31]);+ MONT_MAC(t0, t1, t2, u[22], m[30]);+ MONT_MAC(v0, v1, v2, u[23], m[29]);+ MONT_MAC(w0, w1, w2, u[24], m[28]);+ MONT_MAC(t0, t1, t2, u[25], m[27]);+ MONT_MAC(v0, v1, v2, u[26], m[26]);+ MONT_MAC(w0, w1, w2, u[27], m[25]);+ MONT_MAC(t0, t1, t2, u[28], m[24]);+ MONT_MAC(v0, v1, v2, u[29], m[23]);+ MONT_MAC(w0, w1, w2, u[30], m[22]);+ MONT_MAC(t0, t1, t2, u[31], m[21]);+ MONT_MAC(v0, v1, v2, u[32], m[20]);+ MONT_MAC(w0, w1, w2, u[33], m[19]);+ MONT_MAC(t0, t1, t2, u[34], m[18]);+ MONT_MAC(v0, v1, v2, u[35], m[17]);+ MONT_MAC(w0, w1, w2, u[36], m[16]);+ MONT_MAC(t0, t1, t2, u[37], m[15]);+ MONT_MAC(v0, v1, v2, u[38], m[14]);+ MONT_MAC(w0, w1, w2, u[39], m[13]);+ MONT_MAC(t0, t1, t2, u[40], m[12]);+ MONT_MAC(v0, v1, v2, u[41], m[11]);+ MONT_MAC(w0, w1, w2, u[42], m[10]);+ MONT_MAC(t0, t1, t2, u[43], m[9]);+ MONT_MAC(v0, v1, v2, u[44], m[8]);+ MONT_MAC(w0, w1, w2, u[45], m[7]);+ MONT_MAC(t0, t1, t2, u[46], m[6]);+ MONT_MAC(v0, v1, v2, u[47], m[5]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[4] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 53 */+ MONT_MUL(s0, s1, s2, a[6], a[47]);+ MONT_MUL(c0, c1, c2, a[7], a[46]);+ MONT_MAC(s0, s1, s2, a[8], a[45]);+ MONT_MAC(c0, c1, c2, a[9], a[44]);+ MONT_MAC(s0, s1, s2, a[10], a[43]);+ MONT_MAC(c0, c1, c2, a[11], a[42]);+ MONT_MAC(s0, s1, s2, a[12], a[41]);+ MONT_MAC(c0, c1, c2, a[13], a[40]);+ MONT_MAC(s0, s1, s2, a[14], a[39]);+ MONT_MAC(c0, c1, c2, a[15], a[38]);+ MONT_MAC(s0, s1, s2, a[16], a[37]);+ MONT_MAC(c0, c1, c2, a[17], a[36]);+ MONT_MAC(s0, s1, s2, a[18], a[35]);+ MONT_MAC(c0, c1, c2, a[19], a[34]);+ MONT_MAC(s0, s1, s2, a[20], a[33]);+ MONT_MAC(c0, c1, c2, a[21], a[32]);+ MONT_MAC(s0, s1, s2, a[22], a[31]);+ MONT_MAC(c0, c1, c2, a[23], a[30]);+ MONT_MAC(s0, s1, s2, a[24], a[29]);+ MONT_MAC(c0, c1, c2, a[25], a[28]);+ MONT_MAC(s0, s1, s2, a[26], a[27]);+ MONT_MAC(t0, t1, t2, u[6], m[47]);+ MONT_MUL(v0, v1, v2, u[7], m[46]);+ MONT_MUL(w0, w1, w2, u[8], m[45]);+ MONT_MAC(t0, t1, t2, u[9], m[44]);+ MONT_MAC(v0, v1, v2, u[10], m[43]);+ MONT_MAC(w0, w1, w2, u[11], m[42]);+ MONT_MAC(t0, t1, t2, u[12], m[41]);+ MONT_MAC(v0, v1, v2, u[13], m[40]);+ MONT_MAC(w0, w1, w2, u[14], m[39]);+ MONT_MAC(t0, t1, t2, u[15], m[38]);+ MONT_MAC(v0, v1, v2, u[16], m[37]);+ MONT_MAC(w0, w1, w2, u[17], m[36]);+ MONT_MAC(t0, t1, t2, u[18], m[35]);+ MONT_MAC(v0, v1, v2, u[19], m[34]);+ MONT_MAC(w0, w1, w2, u[20], m[33]);+ MONT_MAC(t0, t1, t2, u[21], m[32]);+ MONT_MAC(v0, v1, v2, u[22], m[31]);+ MONT_MAC(w0, w1, w2, u[23], m[30]);+ MONT_MAC(t0, t1, t2, u[24], m[29]);+ MONT_MAC(v0, v1, v2, u[25], m[28]);+ MONT_MAC(w0, w1, w2, u[26], m[27]);+ MONT_MAC(t0, t1, t2, u[27], m[26]);+ MONT_MAC(v0, v1, v2, u[28], m[25]);+ MONT_MAC(w0, w1, w2, u[29], m[24]);+ MONT_MAC(t0, t1, t2, u[30], m[23]);+ MONT_MAC(v0, v1, v2, u[31], m[22]);+ MONT_MAC(w0, w1, w2, u[32], m[21]);+ MONT_MAC(t0, t1, t2, u[33], m[20]);+ MONT_MAC(v0, v1, v2, u[34], m[19]);+ MONT_MAC(w0, w1, w2, u[35], m[18]);+ MONT_MAC(t0, t1, t2, u[36], m[17]);+ MONT_MAC(v0, v1, v2, u[37], m[16]);+ MONT_MAC(w0, w1, w2, u[38], m[15]);+ MONT_MAC(t0, t1, t2, u[39], m[14]);+ MONT_MAC(v0, v1, v2, u[40], m[13]);+ MONT_MAC(w0, w1, w2, u[41], m[12]);+ MONT_MAC(t0, t1, t2, u[42], m[11]);+ MONT_MAC(v0, v1, v2, u[43], m[10]);+ MONT_MAC(w0, w1, w2, u[44], m[9]);+ MONT_MAC(t0, t1, t2, u[45], m[8]);+ MONT_MAC(v0, v1, v2, u[46], m[7]);+ MONT_MAC(w0, w1, w2, u[47], m[6]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[5] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 54 */+ MONT_MUL(s0, s1, s2, a[7], a[47]);+ MONT_MUL(c0, c1, c2, a[8], a[46]);+ MONT_MAC(s0, s1, s2, a[9], a[45]);+ MONT_MAC(c0, c1, c2, a[10], a[44]);+ MONT_MAC(s0, s1, s2, a[11], a[43]);+ MONT_MAC(c0, c1, c2, a[12], a[42]);+ MONT_MAC(s0, s1, s2, a[13], a[41]);+ MONT_MAC(c0, c1, c2, a[14], a[40]);+ MONT_MAC(s0, s1, s2, a[15], a[39]);+ MONT_MAC(c0, c1, c2, a[16], a[38]);+ MONT_MAC(s0, s1, s2, a[17], a[37]);+ MONT_MAC(c0, c1, c2, a[18], a[36]);+ MONT_MAC(s0, s1, s2, a[19], a[35]);+ MONT_MAC(c0, c1, c2, a[20], a[34]);+ MONT_MAC(s0, s1, s2, a[21], a[33]);+ MONT_MAC(c0, c1, c2, a[22], a[32]);+ MONT_MAC(s0, s1, s2, a[23], a[31]);+ MONT_MAC(c0, c1, c2, a[24], a[30]);+ MONT_MAC(s0, s1, s2, a[25], a[29]);+ MONT_MAC(c0, c1, c2, a[26], a[28]);+ MONT_MAC(t0, t1, t2, a[27], a[27]);+ MONT_MUL(v0, v1, v2, u[7], m[47]);+ MONT_MUL(w0, w1, w2, u[8], m[46]);+ MONT_MAC(t0, t1, t2, u[9], m[45]);+ MONT_MAC(v0, v1, v2, u[10], m[44]);+ MONT_MAC(w0, w1, w2, u[11], m[43]);+ MONT_MAC(t0, t1, t2, u[12], m[42]);+ MONT_MAC(v0, v1, v2, u[13], m[41]);+ MONT_MAC(w0, w1, w2, u[14], m[40]);+ MONT_MAC(t0, t1, t2, u[15], m[39]);+ MONT_MAC(v0, v1, v2, u[16], m[38]);+ MONT_MAC(w0, w1, w2, u[17], m[37]);+ MONT_MAC(t0, t1, t2, u[18], m[36]);+ MONT_MAC(v0, v1, v2, u[19], m[35]);+ MONT_MAC(w0, w1, w2, u[20], m[34]);+ MONT_MAC(t0, t1, t2, u[21], m[33]);+ MONT_MAC(v0, v1, v2, u[22], m[32]);+ MONT_MAC(w0, w1, w2, u[23], m[31]);+ MONT_MAC(t0, t1, t2, u[24], m[30]);+ MONT_MAC(v0, v1, v2, u[25], m[29]);+ MONT_MAC(w0, w1, w2, u[26], m[28]);+ MONT_MAC(t0, t1, t2, u[27], m[27]);+ MONT_MAC(v0, v1, v2, u[28], m[26]);+ MONT_MAC(w0, w1, w2, u[29], m[25]);+ MONT_MAC(t0, t1, t2, u[30], m[24]);+ MONT_MAC(v0, v1, v2, u[31], m[23]);+ MONT_MAC(w0, w1, w2, u[32], m[22]);+ MONT_MAC(t0, t1, t2, u[33], m[21]);+ MONT_MAC(v0, v1, v2, u[34], m[20]);+ MONT_MAC(w0, w1, w2, u[35], m[19]);+ MONT_MAC(t0, t1, t2, u[36], m[18]);+ MONT_MAC(v0, v1, v2, u[37], m[17]);+ MONT_MAC(w0, w1, w2, u[38], m[16]);+ MONT_MAC(t0, t1, t2, u[39], m[15]);+ MONT_MAC(v0, v1, v2, u[40], m[14]);+ MONT_MAC(w0, w1, w2, u[41], m[13]);+ MONT_MAC(t0, t1, t2, u[42], m[12]);+ MONT_MAC(v0, v1, v2, u[43], m[11]);+ MONT_MAC(w0, w1, w2, u[44], m[10]);+ MONT_MAC(t0, t1, t2, u[45], m[9]);+ MONT_MAC(v0, v1, v2, u[46], m[8]);+ MONT_MAC(w0, w1, w2, u[47], m[7]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[6] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 55 */+ MONT_MUL(s0, s1, s2, a[8], a[47]);+ MONT_MUL(c0, c1, c2, a[9], a[46]);+ MONT_MAC(s0, s1, s2, a[10], a[45]);+ MONT_MAC(c0, c1, c2, a[11], a[44]);+ MONT_MAC(s0, s1, s2, a[12], a[43]);+ MONT_MAC(c0, c1, c2, a[13], a[42]);+ MONT_MAC(s0, s1, s2, a[14], a[41]);+ MONT_MAC(c0, c1, c2, a[15], a[40]);+ MONT_MAC(s0, s1, s2, a[16], a[39]);+ MONT_MAC(c0, c1, c2, a[17], a[38]);+ MONT_MAC(s0, s1, s2, a[18], a[37]);+ MONT_MAC(c0, c1, c2, a[19], a[36]);+ MONT_MAC(s0, s1, s2, a[20], a[35]);+ MONT_MAC(c0, c1, c2, a[21], a[34]);+ MONT_MAC(s0, s1, s2, a[22], a[33]);+ MONT_MAC(c0, c1, c2, a[23], a[32]);+ MONT_MAC(s0, s1, s2, a[24], a[31]);+ MONT_MAC(c0, c1, c2, a[25], a[30]);+ MONT_MAC(s0, s1, s2, a[26], a[29]);+ MONT_MAC(c0, c1, c2, a[27], a[28]);+ MONT_MAC(t0, t1, t2, u[8], m[47]);+ MONT_MUL(v0, v1, v2, u[9], m[46]);+ MONT_MUL(w0, w1, w2, u[10], m[45]);+ MONT_MAC(t0, t1, t2, u[11], m[44]);+ MONT_MAC(v0, v1, v2, u[12], m[43]);+ MONT_MAC(w0, w1, w2, u[13], m[42]);+ MONT_MAC(t0, t1, t2, u[14], m[41]);+ MONT_MAC(v0, v1, v2, u[15], m[40]);+ MONT_MAC(w0, w1, w2, u[16], m[39]);+ MONT_MAC(t0, t1, t2, u[17], m[38]);+ MONT_MAC(v0, v1, v2, u[18], m[37]);+ MONT_MAC(w0, w1, w2, u[19], m[36]);+ MONT_MAC(t0, t1, t2, u[20], m[35]);+ MONT_MAC(v0, v1, v2, u[21], m[34]);+ MONT_MAC(w0, w1, w2, u[22], m[33]);+ MONT_MAC(t0, t1, t2, u[23], m[32]);+ MONT_MAC(v0, v1, v2, u[24], m[31]);+ MONT_MAC(w0, w1, w2, u[25], m[30]);+ MONT_MAC(t0, t1, t2, u[26], m[29]);+ MONT_MAC(v0, v1, v2, u[27], m[28]);+ MONT_MAC(w0, w1, w2, u[28], m[27]);+ MONT_MAC(t0, t1, t2, u[29], m[26]);+ MONT_MAC(v0, v1, v2, u[30], m[25]);+ MONT_MAC(w0, w1, w2, u[31], m[24]);+ MONT_MAC(t0, t1, t2, u[32], m[23]);+ MONT_MAC(v0, v1, v2, u[33], m[22]);+ MONT_MAC(w0, w1, w2, u[34], m[21]);+ MONT_MAC(t0, t1, t2, u[35], m[20]);+ MONT_MAC(v0, v1, v2, u[36], m[19]);+ MONT_MAC(w0, w1, w2, u[37], m[18]);+ MONT_MAC(t0, t1, t2, u[38], m[17]);+ MONT_MAC(v0, v1, v2, u[39], m[16]);+ MONT_MAC(w0, w1, w2, u[40], m[15]);+ MONT_MAC(t0, t1, t2, u[41], m[14]);+ MONT_MAC(v0, v1, v2, u[42], m[13]);+ MONT_MAC(w0, w1, w2, u[43], m[12]);+ MONT_MAC(t0, t1, t2, u[44], m[11]);+ MONT_MAC(v0, v1, v2, u[45], m[10]);+ MONT_MAC(w0, w1, w2, u[46], m[9]);+ MONT_MAC(t0, t1, t2, u[47], m[8]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[7] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 56 */+ MONT_MUL(s0, s1, s2, a[9], a[47]);+ MONT_MUL(c0, c1, c2, a[10], a[46]);+ MONT_MAC(s0, s1, s2, a[11], a[45]);+ MONT_MAC(c0, c1, c2, a[12], a[44]);+ MONT_MAC(s0, s1, s2, a[13], a[43]);+ MONT_MAC(c0, c1, c2, a[14], a[42]);+ MONT_MAC(s0, s1, s2, a[15], a[41]);+ MONT_MAC(c0, c1, c2, a[16], a[40]);+ MONT_MAC(s0, s1, s2, a[17], a[39]);+ MONT_MAC(c0, c1, c2, a[18], a[38]);+ MONT_MAC(s0, s1, s2, a[19], a[37]);+ MONT_MAC(c0, c1, c2, a[20], a[36]);+ MONT_MAC(s0, s1, s2, a[21], a[35]);+ MONT_MAC(c0, c1, c2, a[22], a[34]);+ MONT_MAC(s0, s1, s2, a[23], a[33]);+ MONT_MAC(c0, c1, c2, a[24], a[32]);+ MONT_MAC(s0, s1, s2, a[25], a[31]);+ MONT_MAC(c0, c1, c2, a[26], a[30]);+ MONT_MAC(s0, s1, s2, a[27], a[29]);+ MONT_MAC(t0, t1, t2, a[28], a[28]);+ MONT_MUL(v0, v1, v2, u[9], m[47]);+ MONT_MUL(w0, w1, w2, u[10], m[46]);+ MONT_MAC(t0, t1, t2, u[11], m[45]);+ MONT_MAC(v0, v1, v2, u[12], m[44]);+ MONT_MAC(w0, w1, w2, u[13], m[43]);+ MONT_MAC(t0, t1, t2, u[14], m[42]);+ MONT_MAC(v0, v1, v2, u[15], m[41]);+ MONT_MAC(w0, w1, w2, u[16], m[40]);+ MONT_MAC(t0, t1, t2, u[17], m[39]);+ MONT_MAC(v0, v1, v2, u[18], m[38]);+ MONT_MAC(w0, w1, w2, u[19], m[37]);+ MONT_MAC(t0, t1, t2, u[20], m[36]);+ MONT_MAC(v0, v1, v2, u[21], m[35]);+ MONT_MAC(w0, w1, w2, u[22], m[34]);+ MONT_MAC(t0, t1, t2, u[23], m[33]);+ MONT_MAC(v0, v1, v2, u[24], m[32]);+ MONT_MAC(w0, w1, w2, u[25], m[31]);+ MONT_MAC(t0, t1, t2, u[26], m[30]);+ MONT_MAC(v0, v1, v2, u[27], m[29]);+ MONT_MAC(w0, w1, w2, u[28], m[28]);+ MONT_MAC(t0, t1, t2, u[29], m[27]);+ MONT_MAC(v0, v1, v2, u[30], m[26]);+ MONT_MAC(w0, w1, w2, u[31], m[25]);+ MONT_MAC(t0, t1, t2, u[32], m[24]);+ MONT_MAC(v0, v1, v2, u[33], m[23]);+ MONT_MAC(w0, w1, w2, u[34], m[22]);+ MONT_MAC(t0, t1, t2, u[35], m[21]);+ MONT_MAC(v0, v1, v2, u[36], m[20]);+ MONT_MAC(w0, w1, w2, u[37], m[19]);+ MONT_MAC(t0, t1, t2, u[38], m[18]);+ MONT_MAC(v0, v1, v2, u[39], m[17]);+ MONT_MAC(w0, w1, w2, u[40], m[16]);+ MONT_MAC(t0, t1, t2, u[41], m[15]);+ MONT_MAC(v0, v1, v2, u[42], m[14]);+ MONT_MAC(w0, w1, w2, u[43], m[13]);+ MONT_MAC(t0, t1, t2, u[44], m[12]);+ MONT_MAC(v0, v1, v2, u[45], m[11]);+ MONT_MAC(w0, w1, w2, u[46], m[10]);+ MONT_MAC(t0, t1, t2, u[47], m[9]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[8] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 57 */+ MONT_MUL(s0, s1, s2, a[10], a[47]);+ MONT_MUL(c0, c1, c2, a[11], a[46]);+ MONT_MAC(s0, s1, s2, a[12], a[45]);+ MONT_MAC(c0, c1, c2, a[13], a[44]);+ MONT_MAC(s0, s1, s2, a[14], a[43]);+ MONT_MAC(c0, c1, c2, a[15], a[42]);+ MONT_MAC(s0, s1, s2, a[16], a[41]);+ MONT_MAC(c0, c1, c2, a[17], a[40]);+ MONT_MAC(s0, s1, s2, a[18], a[39]);+ MONT_MAC(c0, c1, c2, a[19], a[38]);+ MONT_MAC(s0, s1, s2, a[20], a[37]);+ MONT_MAC(c0, c1, c2, a[21], a[36]);+ MONT_MAC(s0, s1, s2, a[22], a[35]);+ MONT_MAC(c0, c1, c2, a[23], a[34]);+ MONT_MAC(s0, s1, s2, a[24], a[33]);+ MONT_MAC(c0, c1, c2, a[25], a[32]);+ MONT_MAC(s0, s1, s2, a[26], a[31]);+ MONT_MAC(c0, c1, c2, a[27], a[30]);+ MONT_MAC(s0, s1, s2, a[28], a[29]);+ MONT_MAC(t0, t1, t2, u[10], m[47]);+ MONT_MUL(v0, v1, v2, u[11], m[46]);+ MONT_MUL(w0, w1, w2, u[12], m[45]);+ MONT_MAC(t0, t1, t2, u[13], m[44]);+ MONT_MAC(v0, v1, v2, u[14], m[43]);+ MONT_MAC(w0, w1, w2, u[15], m[42]);+ MONT_MAC(t0, t1, t2, u[16], m[41]);+ MONT_MAC(v0, v1, v2, u[17], m[40]);+ MONT_MAC(w0, w1, w2, u[18], m[39]);+ MONT_MAC(t0, t1, t2, u[19], m[38]);+ MONT_MAC(v0, v1, v2, u[20], m[37]);+ MONT_MAC(w0, w1, w2, u[21], m[36]);+ MONT_MAC(t0, t1, t2, u[22], m[35]);+ MONT_MAC(v0, v1, v2, u[23], m[34]);+ MONT_MAC(w0, w1, w2, u[24], m[33]);+ MONT_MAC(t0, t1, t2, u[25], m[32]);+ MONT_MAC(v0, v1, v2, u[26], m[31]);+ MONT_MAC(w0, w1, w2, u[27], m[30]);+ MONT_MAC(t0, t1, t2, u[28], m[29]);+ MONT_MAC(v0, v1, v2, u[29], m[28]);+ MONT_MAC(w0, w1, w2, u[30], m[27]);+ MONT_MAC(t0, t1, t2, u[31], m[26]);+ MONT_MAC(v0, v1, v2, u[32], m[25]);+ MONT_MAC(w0, w1, w2, u[33], m[24]);+ MONT_MAC(t0, t1, t2, u[34], m[23]);+ MONT_MAC(v0, v1, v2, u[35], m[22]);+ MONT_MAC(w0, w1, w2, u[36], m[21]);+ MONT_MAC(t0, t1, t2, u[37], m[20]);+ MONT_MAC(v0, v1, v2, u[38], m[19]);+ MONT_MAC(w0, w1, w2, u[39], m[18]);+ MONT_MAC(t0, t1, t2, u[40], m[17]);+ MONT_MAC(v0, v1, v2, u[41], m[16]);+ MONT_MAC(w0, w1, w2, u[42], m[15]);+ MONT_MAC(t0, t1, t2, u[43], m[14]);+ MONT_MAC(v0, v1, v2, u[44], m[13]);+ MONT_MAC(w0, w1, w2, u[45], m[12]);+ MONT_MAC(t0, t1, t2, u[46], m[11]);+ MONT_MAC(v0, v1, v2, u[47], m[10]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[9] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 58 */+ MONT_MUL(s0, s1, s2, a[11], a[47]);+ MONT_MUL(c0, c1, c2, a[12], a[46]);+ MONT_MAC(s0, s1, s2, a[13], a[45]);+ MONT_MAC(c0, c1, c2, a[14], a[44]);+ MONT_MAC(s0, s1, s2, a[15], a[43]);+ MONT_MAC(c0, c1, c2, a[16], a[42]);+ MONT_MAC(s0, s1, s2, a[17], a[41]);+ MONT_MAC(c0, c1, c2, a[18], a[40]);+ MONT_MAC(s0, s1, s2, a[19], a[39]);+ MONT_MAC(c0, c1, c2, a[20], a[38]);+ MONT_MAC(s0, s1, s2, a[21], a[37]);+ MONT_MAC(c0, c1, c2, a[22], a[36]);+ MONT_MAC(s0, s1, s2, a[23], a[35]);+ MONT_MAC(c0, c1, c2, a[24], a[34]);+ MONT_MAC(s0, s1, s2, a[25], a[33]);+ MONT_MAC(c0, c1, c2, a[26], a[32]);+ MONT_MAC(s0, s1, s2, a[27], a[31]);+ MONT_MAC(c0, c1, c2, a[28], a[30]);+ MONT_MAC(t0, t1, t2, a[29], a[29]);+ MONT_MUL(v0, v1, v2, u[11], m[47]);+ MONT_MUL(w0, w1, w2, u[12], m[46]);+ MONT_MAC(t0, t1, t2, u[13], m[45]);+ MONT_MAC(v0, v1, v2, u[14], m[44]);+ MONT_MAC(w0, w1, w2, u[15], m[43]);+ MONT_MAC(t0, t1, t2, u[16], m[42]);+ MONT_MAC(v0, v1, v2, u[17], m[41]);+ MONT_MAC(w0, w1, w2, u[18], m[40]);+ MONT_MAC(t0, t1, t2, u[19], m[39]);+ MONT_MAC(v0, v1, v2, u[20], m[38]);+ MONT_MAC(w0, w1, w2, u[21], m[37]);+ MONT_MAC(t0, t1, t2, u[22], m[36]);+ MONT_MAC(v0, v1, v2, u[23], m[35]);+ MONT_MAC(w0, w1, w2, u[24], m[34]);+ MONT_MAC(t0, t1, t2, u[25], m[33]);+ MONT_MAC(v0, v1, v2, u[26], m[32]);+ MONT_MAC(w0, w1, w2, u[27], m[31]);+ MONT_MAC(t0, t1, t2, u[28], m[30]);+ MONT_MAC(v0, v1, v2, u[29], m[29]);+ MONT_MAC(w0, w1, w2, u[30], m[28]);+ MONT_MAC(t0, t1, t2, u[31], m[27]);+ MONT_MAC(v0, v1, v2, u[32], m[26]);+ MONT_MAC(w0, w1, w2, u[33], m[25]);+ MONT_MAC(t0, t1, t2, u[34], m[24]);+ MONT_MAC(v0, v1, v2, u[35], m[23]);+ MONT_MAC(w0, w1, w2, u[36], m[22]);+ MONT_MAC(t0, t1, t2, u[37], m[21]);+ MONT_MAC(v0, v1, v2, u[38], m[20]);+ MONT_MAC(w0, w1, w2, u[39], m[19]);+ MONT_MAC(t0, t1, t2, u[40], m[18]);+ MONT_MAC(v0, v1, v2, u[41], m[17]);+ MONT_MAC(w0, w1, w2, u[42], m[16]);+ MONT_MAC(t0, t1, t2, u[43], m[15]);+ MONT_MAC(v0, v1, v2, u[44], m[14]);+ MONT_MAC(w0, w1, w2, u[45], m[13]);+ MONT_MAC(t0, t1, t2, u[46], m[12]);+ MONT_MAC(v0, v1, v2, u[47], m[11]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[10] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 59 */+ MONT_MUL(s0, s1, s2, a[12], a[47]);+ MONT_MUL(c0, c1, c2, a[13], a[46]);+ MONT_MAC(s0, s1, s2, a[14], a[45]);+ MONT_MAC(c0, c1, c2, a[15], a[44]);+ MONT_MAC(s0, s1, s2, a[16], a[43]);+ MONT_MAC(c0, c1, c2, a[17], a[42]);+ MONT_MAC(s0, s1, s2, a[18], a[41]);+ MONT_MAC(c0, c1, c2, a[19], a[40]);+ MONT_MAC(s0, s1, s2, a[20], a[39]);+ MONT_MAC(c0, c1, c2, a[21], a[38]);+ MONT_MAC(s0, s1, s2, a[22], a[37]);+ MONT_MAC(c0, c1, c2, a[23], a[36]);+ MONT_MAC(s0, s1, s2, a[24], a[35]);+ MONT_MAC(c0, c1, c2, a[25], a[34]);+ MONT_MAC(s0, s1, s2, a[26], a[33]);+ MONT_MAC(c0, c1, c2, a[27], a[32]);+ MONT_MAC(s0, s1, s2, a[28], a[31]);+ MONT_MAC(c0, c1, c2, a[29], a[30]);+ MONT_MAC(t0, t1, t2, u[12], m[47]);+ MONT_MUL(v0, v1, v2, u[13], m[46]);+ MONT_MUL(w0, w1, w2, u[14], m[45]);+ MONT_MAC(t0, t1, t2, u[15], m[44]);+ MONT_MAC(v0, v1, v2, u[16], m[43]);+ MONT_MAC(w0, w1, w2, u[17], m[42]);+ MONT_MAC(t0, t1, t2, u[18], m[41]);+ MONT_MAC(v0, v1, v2, u[19], m[40]);+ MONT_MAC(w0, w1, w2, u[20], m[39]);+ MONT_MAC(t0, t1, t2, u[21], m[38]);+ MONT_MAC(v0, v1, v2, u[22], m[37]);+ MONT_MAC(w0, w1, w2, u[23], m[36]);+ MONT_MAC(t0, t1, t2, u[24], m[35]);+ MONT_MAC(v0, v1, v2, u[25], m[34]);+ MONT_MAC(w0, w1, w2, u[26], m[33]);+ MONT_MAC(t0, t1, t2, u[27], m[32]);+ MONT_MAC(v0, v1, v2, u[28], m[31]);+ MONT_MAC(w0, w1, w2, u[29], m[30]);+ MONT_MAC(t0, t1, t2, u[30], m[29]);+ MONT_MAC(v0, v1, v2, u[31], m[28]);+ MONT_MAC(w0, w1, w2, u[32], m[27]);+ MONT_MAC(t0, t1, t2, u[33], m[26]);+ MONT_MAC(v0, v1, v2, u[34], m[25]);+ MONT_MAC(w0, w1, w2, u[35], m[24]);+ MONT_MAC(t0, t1, t2, u[36], m[23]);+ MONT_MAC(v0, v1, v2, u[37], m[22]);+ MONT_MAC(w0, w1, w2, u[38], m[21]);+ MONT_MAC(t0, t1, t2, u[39], m[20]);+ MONT_MAC(v0, v1, v2, u[40], m[19]);+ MONT_MAC(w0, w1, w2, u[41], m[18]);+ MONT_MAC(t0, t1, t2, u[42], m[17]);+ MONT_MAC(v0, v1, v2, u[43], m[16]);+ MONT_MAC(w0, w1, w2, u[44], m[15]);+ MONT_MAC(t0, t1, t2, u[45], m[14]);+ MONT_MAC(v0, v1, v2, u[46], m[13]);+ MONT_MAC(w0, w1, w2, u[47], m[12]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[11] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 60 */+ MONT_MUL(s0, s1, s2, a[13], a[47]);+ MONT_MUL(c0, c1, c2, a[14], a[46]);+ MONT_MAC(s0, s1, s2, a[15], a[45]);+ MONT_MAC(c0, c1, c2, a[16], a[44]);+ MONT_MAC(s0, s1, s2, a[17], a[43]);+ MONT_MAC(c0, c1, c2, a[18], a[42]);+ MONT_MAC(s0, s1, s2, a[19], a[41]);+ MONT_MAC(c0, c1, c2, a[20], a[40]);+ MONT_MAC(s0, s1, s2, a[21], a[39]);+ MONT_MAC(c0, c1, c2, a[22], a[38]);+ MONT_MAC(s0, s1, s2, a[23], a[37]);+ MONT_MAC(c0, c1, c2, a[24], a[36]);+ MONT_MAC(s0, s1, s2, a[25], a[35]);+ MONT_MAC(c0, c1, c2, a[26], a[34]);+ MONT_MAC(s0, s1, s2, a[27], a[33]);+ MONT_MAC(c0, c1, c2, a[28], a[32]);+ MONT_MAC(s0, s1, s2, a[29], a[31]);+ MONT_MAC(t0, t1, t2, a[30], a[30]);+ MONT_MUL(v0, v1, v2, u[13], m[47]);+ MONT_MUL(w0, w1, w2, u[14], m[46]);+ MONT_MAC(t0, t1, t2, u[15], m[45]);+ MONT_MAC(v0, v1, v2, u[16], m[44]);+ MONT_MAC(w0, w1, w2, u[17], m[43]);+ MONT_MAC(t0, t1, t2, u[18], m[42]);+ MONT_MAC(v0, v1, v2, u[19], m[41]);+ MONT_MAC(w0, w1, w2, u[20], m[40]);+ MONT_MAC(t0, t1, t2, u[21], m[39]);+ MONT_MAC(v0, v1, v2, u[22], m[38]);+ MONT_MAC(w0, w1, w2, u[23], m[37]);+ MONT_MAC(t0, t1, t2, u[24], m[36]);+ MONT_MAC(v0, v1, v2, u[25], m[35]);+ MONT_MAC(w0, w1, w2, u[26], m[34]);+ MONT_MAC(t0, t1, t2, u[27], m[33]);+ MONT_MAC(v0, v1, v2, u[28], m[32]);+ MONT_MAC(w0, w1, w2, u[29], m[31]);+ MONT_MAC(t0, t1, t2, u[30], m[30]);+ MONT_MAC(v0, v1, v2, u[31], m[29]);+ MONT_MAC(w0, w1, w2, u[32], m[28]);+ MONT_MAC(t0, t1, t2, u[33], m[27]);+ MONT_MAC(v0, v1, v2, u[34], m[26]);+ MONT_MAC(w0, w1, w2, u[35], m[25]);+ MONT_MAC(t0, t1, t2, u[36], m[24]);+ MONT_MAC(v0, v1, v2, u[37], m[23]);+ MONT_MAC(w0, w1, w2, u[38], m[22]);+ MONT_MAC(t0, t1, t2, u[39], m[21]);+ MONT_MAC(v0, v1, v2, u[40], m[20]);+ MONT_MAC(w0, w1, w2, u[41], m[19]);+ MONT_MAC(t0, t1, t2, u[42], m[18]);+ MONT_MAC(v0, v1, v2, u[43], m[17]);+ MONT_MAC(w0, w1, w2, u[44], m[16]);+ MONT_MAC(t0, t1, t2, u[45], m[15]);+ MONT_MAC(v0, v1, v2, u[46], m[14]);+ MONT_MAC(w0, w1, w2, u[47], m[13]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[12] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 61 */+ MONT_MUL(s0, s1, s2, a[14], a[47]);+ MONT_MUL(c0, c1, c2, a[15], a[46]);+ MONT_MAC(s0, s1, s2, a[16], a[45]);+ MONT_MAC(c0, c1, c2, a[17], a[44]);+ MONT_MAC(s0, s1, s2, a[18], a[43]);+ MONT_MAC(c0, c1, c2, a[19], a[42]);+ MONT_MAC(s0, s1, s2, a[20], a[41]);+ MONT_MAC(c0, c1, c2, a[21], a[40]);+ MONT_MAC(s0, s1, s2, a[22], a[39]);+ MONT_MAC(c0, c1, c2, a[23], a[38]);+ MONT_MAC(s0, s1, s2, a[24], a[37]);+ MONT_MAC(c0, c1, c2, a[25], a[36]);+ MONT_MAC(s0, s1, s2, a[26], a[35]);+ MONT_MAC(c0, c1, c2, a[27], a[34]);+ MONT_MAC(s0, s1, s2, a[28], a[33]);+ MONT_MAC(c0, c1, c2, a[29], a[32]);+ MONT_MAC(s0, s1, s2, a[30], a[31]);+ MONT_MAC(t0, t1, t2, u[14], m[47]);+ MONT_MUL(v0, v1, v2, u[15], m[46]);+ MONT_MUL(w0, w1, w2, u[16], m[45]);+ MONT_MAC(t0, t1, t2, u[17], m[44]);+ MONT_MAC(v0, v1, v2, u[18], m[43]);+ MONT_MAC(w0, w1, w2, u[19], m[42]);+ MONT_MAC(t0, t1, t2, u[20], m[41]);+ MONT_MAC(v0, v1, v2, u[21], m[40]);+ MONT_MAC(w0, w1, w2, u[22], m[39]);+ MONT_MAC(t0, t1, t2, u[23], m[38]);+ MONT_MAC(v0, v1, v2, u[24], m[37]);+ MONT_MAC(w0, w1, w2, u[25], m[36]);+ MONT_MAC(t0, t1, t2, u[26], m[35]);+ MONT_MAC(v0, v1, v2, u[27], m[34]);+ MONT_MAC(w0, w1, w2, u[28], m[33]);+ MONT_MAC(t0, t1, t2, u[29], m[32]);+ MONT_MAC(v0, v1, v2, u[30], m[31]);+ MONT_MAC(w0, w1, w2, u[31], m[30]);+ MONT_MAC(t0, t1, t2, u[32], m[29]);+ MONT_MAC(v0, v1, v2, u[33], m[28]);+ MONT_MAC(w0, w1, w2, u[34], m[27]);+ MONT_MAC(t0, t1, t2, u[35], m[26]);+ MONT_MAC(v0, v1, v2, u[36], m[25]);+ MONT_MAC(w0, w1, w2, u[37], m[24]);+ MONT_MAC(t0, t1, t2, u[38], m[23]);+ MONT_MAC(v0, v1, v2, u[39], m[22]);+ MONT_MAC(w0, w1, w2, u[40], m[21]);+ MONT_MAC(t0, t1, t2, u[41], m[20]);+ MONT_MAC(v0, v1, v2, u[42], m[19]);+ MONT_MAC(w0, w1, w2, u[43], m[18]);+ MONT_MAC(t0, t1, t2, u[44], m[17]);+ MONT_MAC(v0, v1, v2, u[45], m[16]);+ MONT_MAC(w0, w1, w2, u[46], m[15]);+ MONT_MAC(t0, t1, t2, u[47], m[14]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[13] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 62 */+ MONT_MUL(s0, s1, s2, a[15], a[47]);+ MONT_MUL(c0, c1, c2, a[16], a[46]);+ MONT_MAC(s0, s1, s2, a[17], a[45]);+ MONT_MAC(c0, c1, c2, a[18], a[44]);+ MONT_MAC(s0, s1, s2, a[19], a[43]);+ MONT_MAC(c0, c1, c2, a[20], a[42]);+ MONT_MAC(s0, s1, s2, a[21], a[41]);+ MONT_MAC(c0, c1, c2, a[22], a[40]);+ MONT_MAC(s0, s1, s2, a[23], a[39]);+ MONT_MAC(c0, c1, c2, a[24], a[38]);+ MONT_MAC(s0, s1, s2, a[25], a[37]);+ MONT_MAC(c0, c1, c2, a[26], a[36]);+ MONT_MAC(s0, s1, s2, a[27], a[35]);+ MONT_MAC(c0, c1, c2, a[28], a[34]);+ MONT_MAC(s0, s1, s2, a[29], a[33]);+ MONT_MAC(c0, c1, c2, a[30], a[32]);+ MONT_MAC(t0, t1, t2, a[31], a[31]);+ MONT_MUL(v0, v1, v2, u[15], m[47]);+ MONT_MUL(w0, w1, w2, u[16], m[46]);+ MONT_MAC(t0, t1, t2, u[17], m[45]);+ MONT_MAC(v0, v1, v2, u[18], m[44]);+ MONT_MAC(w0, w1, w2, u[19], m[43]);+ MONT_MAC(t0, t1, t2, u[20], m[42]);+ MONT_MAC(v0, v1, v2, u[21], m[41]);+ MONT_MAC(w0, w1, w2, u[22], m[40]);+ MONT_MAC(t0, t1, t2, u[23], m[39]);+ MONT_MAC(v0, v1, v2, u[24], m[38]);+ MONT_MAC(w0, w1, w2, u[25], m[37]);+ MONT_MAC(t0, t1, t2, u[26], m[36]);+ MONT_MAC(v0, v1, v2, u[27], m[35]);+ MONT_MAC(w0, w1, w2, u[28], m[34]);+ MONT_MAC(t0, t1, t2, u[29], m[33]);+ MONT_MAC(v0, v1, v2, u[30], m[32]);+ MONT_MAC(w0, w1, w2, u[31], m[31]);+ MONT_MAC(t0, t1, t2, u[32], m[30]);+ MONT_MAC(v0, v1, v2, u[33], m[29]);+ MONT_MAC(w0, w1, w2, u[34], m[28]);+ MONT_MAC(t0, t1, t2, u[35], m[27]);+ MONT_MAC(v0, v1, v2, u[36], m[26]);+ MONT_MAC(w0, w1, w2, u[37], m[25]);+ MONT_MAC(t0, t1, t2, u[38], m[24]);+ MONT_MAC(v0, v1, v2, u[39], m[23]);+ MONT_MAC(w0, w1, w2, u[40], m[22]);+ MONT_MAC(t0, t1, t2, u[41], m[21]);+ MONT_MAC(v0, v1, v2, u[42], m[20]);+ MONT_MAC(w0, w1, w2, u[43], m[19]);+ MONT_MAC(t0, t1, t2, u[44], m[18]);+ MONT_MAC(v0, v1, v2, u[45], m[17]);+ MONT_MAC(w0, w1, w2, u[46], m[16]);+ MONT_MAC(t0, t1, t2, u[47], m[15]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[14] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 63 */+ MONT_MUL(s0, s1, s2, a[16], a[47]);+ MONT_MUL(c0, c1, c2, a[17], a[46]);+ MONT_MAC(s0, s1, s2, a[18], a[45]);+ MONT_MAC(c0, c1, c2, a[19], a[44]);+ MONT_MAC(s0, s1, s2, a[20], a[43]);+ MONT_MAC(c0, c1, c2, a[21], a[42]);+ MONT_MAC(s0, s1, s2, a[22], a[41]);+ MONT_MAC(c0, c1, c2, a[23], a[40]);+ MONT_MAC(s0, s1, s2, a[24], a[39]);+ MONT_MAC(c0, c1, c2, a[25], a[38]);+ MONT_MAC(s0, s1, s2, a[26], a[37]);+ MONT_MAC(c0, c1, c2, a[27], a[36]);+ MONT_MAC(s0, s1, s2, a[28], a[35]);+ MONT_MAC(c0, c1, c2, a[29], a[34]);+ MONT_MAC(s0, s1, s2, a[30], a[33]);+ MONT_MAC(c0, c1, c2, a[31], a[32]);+ MONT_MAC(t0, t1, t2, u[16], m[47]);+ MONT_MUL(v0, v1, v2, u[17], m[46]);+ MONT_MUL(w0, w1, w2, u[18], m[45]);+ MONT_MAC(t0, t1, t2, u[19], m[44]);+ MONT_MAC(v0, v1, v2, u[20], m[43]);+ MONT_MAC(w0, w1, w2, u[21], m[42]);+ MONT_MAC(t0, t1, t2, u[22], m[41]);+ MONT_MAC(v0, v1, v2, u[23], m[40]);+ MONT_MAC(w0, w1, w2, u[24], m[39]);+ MONT_MAC(t0, t1, t2, u[25], m[38]);+ MONT_MAC(v0, v1, v2, u[26], m[37]);+ MONT_MAC(w0, w1, w2, u[27], m[36]);+ MONT_MAC(t0, t1, t2, u[28], m[35]);+ MONT_MAC(v0, v1, v2, u[29], m[34]);+ MONT_MAC(w0, w1, w2, u[30], m[33]);+ MONT_MAC(t0, t1, t2, u[31], m[32]);+ MONT_MAC(v0, v1, v2, u[32], m[31]);+ MONT_MAC(w0, w1, w2, u[33], m[30]);+ MONT_MAC(t0, t1, t2, u[34], m[29]);+ MONT_MAC(v0, v1, v2, u[35], m[28]);+ MONT_MAC(w0, w1, w2, u[36], m[27]);+ MONT_MAC(t0, t1, t2, u[37], m[26]);+ MONT_MAC(v0, v1, v2, u[38], m[25]);+ MONT_MAC(w0, w1, w2, u[39], m[24]);+ MONT_MAC(t0, t1, t2, u[40], m[23]);+ MONT_MAC(v0, v1, v2, u[41], m[22]);+ MONT_MAC(w0, w1, w2, u[42], m[21]);+ MONT_MAC(t0, t1, t2, u[43], m[20]);+ MONT_MAC(v0, v1, v2, u[44], m[19]);+ MONT_MAC(w0, w1, w2, u[45], m[18]);+ MONT_MAC(t0, t1, t2, u[46], m[17]);+ MONT_MAC(v0, v1, v2, u[47], m[16]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[15] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 64 */+ MONT_MUL(s0, s1, s2, a[17], a[47]);+ MONT_MUL(c0, c1, c2, a[18], a[46]);+ MONT_MAC(s0, s1, s2, a[19], a[45]);+ MONT_MAC(c0, c1, c2, a[20], a[44]);+ MONT_MAC(s0, s1, s2, a[21], a[43]);+ MONT_MAC(c0, c1, c2, a[22], a[42]);+ MONT_MAC(s0, s1, s2, a[23], a[41]);+ MONT_MAC(c0, c1, c2, a[24], a[40]);+ MONT_MAC(s0, s1, s2, a[25], a[39]);+ MONT_MAC(c0, c1, c2, a[26], a[38]);+ MONT_MAC(s0, s1, s2, a[27], a[37]);+ MONT_MAC(c0, c1, c2, a[28], a[36]);+ MONT_MAC(s0, s1, s2, a[29], a[35]);+ MONT_MAC(c0, c1, c2, a[30], a[34]);+ MONT_MAC(s0, s1, s2, a[31], a[33]);+ MONT_MAC(t0, t1, t2, a[32], a[32]);+ MONT_MUL(v0, v1, v2, u[17], m[47]);+ MONT_MUL(w0, w1, w2, u[18], m[46]);+ MONT_MAC(t0, t1, t2, u[19], m[45]);+ MONT_MAC(v0, v1, v2, u[20], m[44]);+ MONT_MAC(w0, w1, w2, u[21], m[43]);+ MONT_MAC(t0, t1, t2, u[22], m[42]);+ MONT_MAC(v0, v1, v2, u[23], m[41]);+ MONT_MAC(w0, w1, w2, u[24], m[40]);+ MONT_MAC(t0, t1, t2, u[25], m[39]);+ MONT_MAC(v0, v1, v2, u[26], m[38]);+ MONT_MAC(w0, w1, w2, u[27], m[37]);+ MONT_MAC(t0, t1, t2, u[28], m[36]);+ MONT_MAC(v0, v1, v2, u[29], m[35]);+ MONT_MAC(w0, w1, w2, u[30], m[34]);+ MONT_MAC(t0, t1, t2, u[31], m[33]);+ MONT_MAC(v0, v1, v2, u[32], m[32]);+ MONT_MAC(w0, w1, w2, u[33], m[31]);+ MONT_MAC(t0, t1, t2, u[34], m[30]);+ MONT_MAC(v0, v1, v2, u[35], m[29]);+ MONT_MAC(w0, w1, w2, u[36], m[28]);+ MONT_MAC(t0, t1, t2, u[37], m[27]);+ MONT_MAC(v0, v1, v2, u[38], m[26]);+ MONT_MAC(w0, w1, w2, u[39], m[25]);+ MONT_MAC(t0, t1, t2, u[40], m[24]);+ MONT_MAC(v0, v1, v2, u[41], m[23]);+ MONT_MAC(w0, w1, w2, u[42], m[22]);+ MONT_MAC(t0, t1, t2, u[43], m[21]);+ MONT_MAC(v0, v1, v2, u[44], m[20]);+ MONT_MAC(w0, w1, w2, u[45], m[19]);+ MONT_MAC(t0, t1, t2, u[46], m[18]);+ MONT_MAC(v0, v1, v2, u[47], m[17]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[16] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 65 */+ MONT_MUL(s0, s1, s2, a[18], a[47]);+ MONT_MUL(c0, c1, c2, a[19], a[46]);+ MONT_MAC(s0, s1, s2, a[20], a[45]);+ MONT_MAC(c0, c1, c2, a[21], a[44]);+ MONT_MAC(s0, s1, s2, a[22], a[43]);+ MONT_MAC(c0, c1, c2, a[23], a[42]);+ MONT_MAC(s0, s1, s2, a[24], a[41]);+ MONT_MAC(c0, c1, c2, a[25], a[40]);+ MONT_MAC(s0, s1, s2, a[26], a[39]);+ MONT_MAC(c0, c1, c2, a[27], a[38]);+ MONT_MAC(s0, s1, s2, a[28], a[37]);+ MONT_MAC(c0, c1, c2, a[29], a[36]);+ MONT_MAC(s0, s1, s2, a[30], a[35]);+ MONT_MAC(c0, c1, c2, a[31], a[34]);+ MONT_MAC(s0, s1, s2, a[32], a[33]);+ MONT_MAC(t0, t1, t2, u[18], m[47]);+ MONT_MUL(v0, v1, v2, u[19], m[46]);+ MONT_MUL(w0, w1, w2, u[20], m[45]);+ MONT_MAC(t0, t1, t2, u[21], m[44]);+ MONT_MAC(v0, v1, v2, u[22], m[43]);+ MONT_MAC(w0, w1, w2, u[23], m[42]);+ MONT_MAC(t0, t1, t2, u[24], m[41]);+ MONT_MAC(v0, v1, v2, u[25], m[40]);+ MONT_MAC(w0, w1, w2, u[26], m[39]);+ MONT_MAC(t0, t1, t2, u[27], m[38]);+ MONT_MAC(v0, v1, v2, u[28], m[37]);+ MONT_MAC(w0, w1, w2, u[29], m[36]);+ MONT_MAC(t0, t1, t2, u[30], m[35]);+ MONT_MAC(v0, v1, v2, u[31], m[34]);+ MONT_MAC(w0, w1, w2, u[32], m[33]);+ MONT_MAC(t0, t1, t2, u[33], m[32]);+ MONT_MAC(v0, v1, v2, u[34], m[31]);+ MONT_MAC(w0, w1, w2, u[35], m[30]);+ MONT_MAC(t0, t1, t2, u[36], m[29]);+ MONT_MAC(v0, v1, v2, u[37], m[28]);+ MONT_MAC(w0, w1, w2, u[38], m[27]);+ MONT_MAC(t0, t1, t2, u[39], m[26]);+ MONT_MAC(v0, v1, v2, u[40], m[25]);+ MONT_MAC(w0, w1, w2, u[41], m[24]);+ MONT_MAC(t0, t1, t2, u[42], m[23]);+ MONT_MAC(v0, v1, v2, u[43], m[22]);+ MONT_MAC(w0, w1, w2, u[44], m[21]);+ MONT_MAC(t0, t1, t2, u[45], m[20]);+ MONT_MAC(v0, v1, v2, u[46], m[19]);+ MONT_MAC(w0, w1, w2, u[47], m[18]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[17] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 66 */+ MONT_MUL(s0, s1, s2, a[19], a[47]);+ MONT_MUL(c0, c1, c2, a[20], a[46]);+ MONT_MAC(s0, s1, s2, a[21], a[45]);+ MONT_MAC(c0, c1, c2, a[22], a[44]);+ MONT_MAC(s0, s1, s2, a[23], a[43]);+ MONT_MAC(c0, c1, c2, a[24], a[42]);+ MONT_MAC(s0, s1, s2, a[25], a[41]);+ MONT_MAC(c0, c1, c2, a[26], a[40]);+ MONT_MAC(s0, s1, s2, a[27], a[39]);+ MONT_MAC(c0, c1, c2, a[28], a[38]);+ MONT_MAC(s0, s1, s2, a[29], a[37]);+ MONT_MAC(c0, c1, c2, a[30], a[36]);+ MONT_MAC(s0, s1, s2, a[31], a[35]);+ MONT_MAC(c0, c1, c2, a[32], a[34]);+ MONT_MAC(t0, t1, t2, a[33], a[33]);+ MONT_MUL(v0, v1, v2, u[19], m[47]);+ MONT_MUL(w0, w1, w2, u[20], m[46]);+ MONT_MAC(t0, t1, t2, u[21], m[45]);+ MONT_MAC(v0, v1, v2, u[22], m[44]);+ MONT_MAC(w0, w1, w2, u[23], m[43]);+ MONT_MAC(t0, t1, t2, u[24], m[42]);+ MONT_MAC(v0, v1, v2, u[25], m[41]);+ MONT_MAC(w0, w1, w2, u[26], m[40]);+ MONT_MAC(t0, t1, t2, u[27], m[39]);+ MONT_MAC(v0, v1, v2, u[28], m[38]);+ MONT_MAC(w0, w1, w2, u[29], m[37]);+ MONT_MAC(t0, t1, t2, u[30], m[36]);+ MONT_MAC(v0, v1, v2, u[31], m[35]);+ MONT_MAC(w0, w1, w2, u[32], m[34]);+ MONT_MAC(t0, t1, t2, u[33], m[33]);+ MONT_MAC(v0, v1, v2, u[34], m[32]);+ MONT_MAC(w0, w1, w2, u[35], m[31]);+ MONT_MAC(t0, t1, t2, u[36], m[30]);+ MONT_MAC(v0, v1, v2, u[37], m[29]);+ MONT_MAC(w0, w1, w2, u[38], m[28]);+ MONT_MAC(t0, t1, t2, u[39], m[27]);+ MONT_MAC(v0, v1, v2, u[40], m[26]);+ MONT_MAC(w0, w1, w2, u[41], m[25]);+ MONT_MAC(t0, t1, t2, u[42], m[24]);+ MONT_MAC(v0, v1, v2, u[43], m[23]);+ MONT_MAC(w0, w1, w2, u[44], m[22]);+ MONT_MAC(t0, t1, t2, u[45], m[21]);+ MONT_MAC(v0, v1, v2, u[46], m[20]);+ MONT_MAC(w0, w1, w2, u[47], m[19]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[18] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 67 */+ MONT_MUL(s0, s1, s2, a[20], a[47]);+ MONT_MUL(c0, c1, c2, a[21], a[46]);+ MONT_MAC(s0, s1, s2, a[22], a[45]);+ MONT_MAC(c0, c1, c2, a[23], a[44]);+ MONT_MAC(s0, s1, s2, a[24], a[43]);+ MONT_MAC(c0, c1, c2, a[25], a[42]);+ MONT_MAC(s0, s1, s2, a[26], a[41]);+ MONT_MAC(c0, c1, c2, a[27], a[40]);+ MONT_MAC(s0, s1, s2, a[28], a[39]);+ MONT_MAC(c0, c1, c2, a[29], a[38]);+ MONT_MAC(s0, s1, s2, a[30], a[37]);+ MONT_MAC(c0, c1, c2, a[31], a[36]);+ MONT_MAC(s0, s1, s2, a[32], a[35]);+ MONT_MAC(c0, c1, c2, a[33], a[34]);+ MONT_MAC(t0, t1, t2, u[20], m[47]);+ MONT_MUL(v0, v1, v2, u[21], m[46]);+ MONT_MUL(w0, w1, w2, u[22], m[45]);+ MONT_MAC(t0, t1, t2, u[23], m[44]);+ MONT_MAC(v0, v1, v2, u[24], m[43]);+ MONT_MAC(w0, w1, w2, u[25], m[42]);+ MONT_MAC(t0, t1, t2, u[26], m[41]);+ MONT_MAC(v0, v1, v2, u[27], m[40]);+ MONT_MAC(w0, w1, w2, u[28], m[39]);+ MONT_MAC(t0, t1, t2, u[29], m[38]);+ MONT_MAC(v0, v1, v2, u[30], m[37]);+ MONT_MAC(w0, w1, w2, u[31], m[36]);+ MONT_MAC(t0, t1, t2, u[32], m[35]);+ MONT_MAC(v0, v1, v2, u[33], m[34]);+ MONT_MAC(w0, w1, w2, u[34], m[33]);+ MONT_MAC(t0, t1, t2, u[35], m[32]);+ MONT_MAC(v0, v1, v2, u[36], m[31]);+ MONT_MAC(w0, w1, w2, u[37], m[30]);+ MONT_MAC(t0, t1, t2, u[38], m[29]);+ MONT_MAC(v0, v1, v2, u[39], m[28]);+ MONT_MAC(w0, w1, w2, u[40], m[27]);+ MONT_MAC(t0, t1, t2, u[41], m[26]);+ MONT_MAC(v0, v1, v2, u[42], m[25]);+ MONT_MAC(w0, w1, w2, u[43], m[24]);+ MONT_MAC(t0, t1, t2, u[44], m[23]);+ MONT_MAC(v0, v1, v2, u[45], m[22]);+ MONT_MAC(w0, w1, w2, u[46], m[21]);+ MONT_MAC(t0, t1, t2, u[47], m[20]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[19] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 68 */+ MONT_MUL(s0, s1, s2, a[21], a[47]);+ MONT_MUL(c0, c1, c2, a[22], a[46]);+ MONT_MAC(s0, s1, s2, a[23], a[45]);+ MONT_MAC(c0, c1, c2, a[24], a[44]);+ MONT_MAC(s0, s1, s2, a[25], a[43]);+ MONT_MAC(c0, c1, c2, a[26], a[42]);+ MONT_MAC(s0, s1, s2, a[27], a[41]);+ MONT_MAC(c0, c1, c2, a[28], a[40]);+ MONT_MAC(s0, s1, s2, a[29], a[39]);+ MONT_MAC(c0, c1, c2, a[30], a[38]);+ MONT_MAC(s0, s1, s2, a[31], a[37]);+ MONT_MAC(c0, c1, c2, a[32], a[36]);+ MONT_MAC(s0, s1, s2, a[33], a[35]);+ MONT_MAC(t0, t1, t2, a[34], a[34]);+ MONT_MUL(v0, v1, v2, u[21], m[47]);+ MONT_MUL(w0, w1, w2, u[22], m[46]);+ MONT_MAC(t0, t1, t2, u[23], m[45]);+ MONT_MAC(v0, v1, v2, u[24], m[44]);+ MONT_MAC(w0, w1, w2, u[25], m[43]);+ MONT_MAC(t0, t1, t2, u[26], m[42]);+ MONT_MAC(v0, v1, v2, u[27], m[41]);+ MONT_MAC(w0, w1, w2, u[28], m[40]);+ MONT_MAC(t0, t1, t2, u[29], m[39]);+ MONT_MAC(v0, v1, v2, u[30], m[38]);+ MONT_MAC(w0, w1, w2, u[31], m[37]);+ MONT_MAC(t0, t1, t2, u[32], m[36]);+ MONT_MAC(v0, v1, v2, u[33], m[35]);+ MONT_MAC(w0, w1, w2, u[34], m[34]);+ MONT_MAC(t0, t1, t2, u[35], m[33]);+ MONT_MAC(v0, v1, v2, u[36], m[32]);+ MONT_MAC(w0, w1, w2, u[37], m[31]);+ MONT_MAC(t0, t1, t2, u[38], m[30]);+ MONT_MAC(v0, v1, v2, u[39], m[29]);+ MONT_MAC(w0, w1, w2, u[40], m[28]);+ MONT_MAC(t0, t1, t2, u[41], m[27]);+ MONT_MAC(v0, v1, v2, u[42], m[26]);+ MONT_MAC(w0, w1, w2, u[43], m[25]);+ MONT_MAC(t0, t1, t2, u[44], m[24]);+ MONT_MAC(v0, v1, v2, u[45], m[23]);+ MONT_MAC(w0, w1, w2, u[46], m[22]);+ MONT_MAC(t0, t1, t2, u[47], m[21]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[20] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 69 */+ MONT_MUL(s0, s1, s2, a[22], a[47]);+ MONT_MUL(c0, c1, c2, a[23], a[46]);+ MONT_MAC(s0, s1, s2, a[24], a[45]);+ MONT_MAC(c0, c1, c2, a[25], a[44]);+ MONT_MAC(s0, s1, s2, a[26], a[43]);+ MONT_MAC(c0, c1, c2, a[27], a[42]);+ MONT_MAC(s0, s1, s2, a[28], a[41]);+ MONT_MAC(c0, c1, c2, a[29], a[40]);+ MONT_MAC(s0, s1, s2, a[30], a[39]);+ MONT_MAC(c0, c1, c2, a[31], a[38]);+ MONT_MAC(s0, s1, s2, a[32], a[37]);+ MONT_MAC(c0, c1, c2, a[33], a[36]);+ MONT_MAC(s0, s1, s2, a[34], a[35]);+ MONT_MAC(t0, t1, t2, u[22], m[47]);+ MONT_MUL(v0, v1, v2, u[23], m[46]);+ MONT_MUL(w0, w1, w2, u[24], m[45]);+ MONT_MAC(t0, t1, t2, u[25], m[44]);+ MONT_MAC(v0, v1, v2, u[26], m[43]);+ MONT_MAC(w0, w1, w2, u[27], m[42]);+ MONT_MAC(t0, t1, t2, u[28], m[41]);+ MONT_MAC(v0, v1, v2, u[29], m[40]);+ MONT_MAC(w0, w1, w2, u[30], m[39]);+ MONT_MAC(t0, t1, t2, u[31], m[38]);+ MONT_MAC(v0, v1, v2, u[32], m[37]);+ MONT_MAC(w0, w1, w2, u[33], m[36]);+ MONT_MAC(t0, t1, t2, u[34], m[35]);+ MONT_MAC(v0, v1, v2, u[35], m[34]);+ MONT_MAC(w0, w1, w2, u[36], m[33]);+ MONT_MAC(t0, t1, t2, u[37], m[32]);+ MONT_MAC(v0, v1, v2, u[38], m[31]);+ MONT_MAC(w0, w1, w2, u[39], m[30]);+ MONT_MAC(t0, t1, t2, u[40], m[29]);+ MONT_MAC(v0, v1, v2, u[41], m[28]);+ MONT_MAC(w0, w1, w2, u[42], m[27]);+ MONT_MAC(t0, t1, t2, u[43], m[26]);+ MONT_MAC(v0, v1, v2, u[44], m[25]);+ MONT_MAC(w0, w1, w2, u[45], m[24]);+ MONT_MAC(t0, t1, t2, u[46], m[23]);+ MONT_MAC(v0, v1, v2, u[47], m[22]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[21] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 70 */+ MONT_MUL(s0, s1, s2, a[23], a[47]);+ MONT_MUL(c0, c1, c2, a[24], a[46]);+ MONT_MAC(s0, s1, s2, a[25], a[45]);+ MONT_MAC(c0, c1, c2, a[26], a[44]);+ MONT_MAC(s0, s1, s2, a[27], a[43]);+ MONT_MAC(c0, c1, c2, a[28], a[42]);+ MONT_MAC(s0, s1, s2, a[29], a[41]);+ MONT_MAC(c0, c1, c2, a[30], a[40]);+ MONT_MAC(s0, s1, s2, a[31], a[39]);+ MONT_MAC(c0, c1, c2, a[32], a[38]);+ MONT_MAC(s0, s1, s2, a[33], a[37]);+ MONT_MAC(c0, c1, c2, a[34], a[36]);+ MONT_MAC(t0, t1, t2, a[35], a[35]);+ MONT_MUL(v0, v1, v2, u[23], m[47]);+ MONT_MUL(w0, w1, w2, u[24], m[46]);+ MONT_MAC(t0, t1, t2, u[25], m[45]);+ MONT_MAC(v0, v1, v2, u[26], m[44]);+ MONT_MAC(w0, w1, w2, u[27], m[43]);+ MONT_MAC(t0, t1, t2, u[28], m[42]);+ MONT_MAC(v0, v1, v2, u[29], m[41]);+ MONT_MAC(w0, w1, w2, u[30], m[40]);+ MONT_MAC(t0, t1, t2, u[31], m[39]);+ MONT_MAC(v0, v1, v2, u[32], m[38]);+ MONT_MAC(w0, w1, w2, u[33], m[37]);+ MONT_MAC(t0, t1, t2, u[34], m[36]);+ MONT_MAC(v0, v1, v2, u[35], m[35]);+ MONT_MAC(w0, w1, w2, u[36], m[34]);+ MONT_MAC(t0, t1, t2, u[37], m[33]);+ MONT_MAC(v0, v1, v2, u[38], m[32]);+ MONT_MAC(w0, w1, w2, u[39], m[31]);+ MONT_MAC(t0, t1, t2, u[40], m[30]);+ MONT_MAC(v0, v1, v2, u[41], m[29]);+ MONT_MAC(w0, w1, w2, u[42], m[28]);+ MONT_MAC(t0, t1, t2, u[43], m[27]);+ MONT_MAC(v0, v1, v2, u[44], m[26]);+ MONT_MAC(w0, w1, w2, u[45], m[25]);+ MONT_MAC(t0, t1, t2, u[46], m[24]);+ MONT_MAC(v0, v1, v2, u[47], m[23]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[22] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 71 */+ MONT_MUL(s0, s1, s2, a[24], a[47]);+ MONT_MUL(c0, c1, c2, a[25], a[46]);+ MONT_MAC(s0, s1, s2, a[26], a[45]);+ MONT_MAC(c0, c1, c2, a[27], a[44]);+ MONT_MAC(s0, s1, s2, a[28], a[43]);+ MONT_MAC(c0, c1, c2, a[29], a[42]);+ MONT_MAC(s0, s1, s2, a[30], a[41]);+ MONT_MAC(c0, c1, c2, a[31], a[40]);+ MONT_MAC(s0, s1, s2, a[32], a[39]);+ MONT_MAC(c0, c1, c2, a[33], a[38]);+ MONT_MAC(s0, s1, s2, a[34], a[37]);+ MONT_MAC(c0, c1, c2, a[35], a[36]);+ MONT_MAC(t0, t1, t2, u[24], m[47]);+ MONT_MUL(v0, v1, v2, u[25], m[46]);+ MONT_MUL(w0, w1, w2, u[26], m[45]);+ MONT_MAC(t0, t1, t2, u[27], m[44]);+ MONT_MAC(v0, v1, v2, u[28], m[43]);+ MONT_MAC(w0, w1, w2, u[29], m[42]);+ MONT_MAC(t0, t1, t2, u[30], m[41]);+ MONT_MAC(v0, v1, v2, u[31], m[40]);+ MONT_MAC(w0, w1, w2, u[32], m[39]);+ MONT_MAC(t0, t1, t2, u[33], m[38]);+ MONT_MAC(v0, v1, v2, u[34], m[37]);+ MONT_MAC(w0, w1, w2, u[35], m[36]);+ MONT_MAC(t0, t1, t2, u[36], m[35]);+ MONT_MAC(v0, v1, v2, u[37], m[34]);+ MONT_MAC(w0, w1, w2, u[38], m[33]);+ MONT_MAC(t0, t1, t2, u[39], m[32]);+ MONT_MAC(v0, v1, v2, u[40], m[31]);+ MONT_MAC(w0, w1, w2, u[41], m[30]);+ MONT_MAC(t0, t1, t2, u[42], m[29]);+ MONT_MAC(v0, v1, v2, u[43], m[28]);+ MONT_MAC(w0, w1, w2, u[44], m[27]);+ MONT_MAC(t0, t1, t2, u[45], m[26]);+ MONT_MAC(v0, v1, v2, u[46], m[25]);+ MONT_MAC(w0, w1, w2, u[47], m[24]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[23] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 72 */+ MONT_MUL(s0, s1, s2, a[25], a[47]);+ MONT_MUL(c0, c1, c2, a[26], a[46]);+ MONT_MAC(s0, s1, s2, a[27], a[45]);+ MONT_MAC(c0, c1, c2, a[28], a[44]);+ MONT_MAC(s0, s1, s2, a[29], a[43]);+ MONT_MAC(c0, c1, c2, a[30], a[42]);+ MONT_MAC(s0, s1, s2, a[31], a[41]);+ MONT_MAC(c0, c1, c2, a[32], a[40]);+ MONT_MAC(s0, s1, s2, a[33], a[39]);+ MONT_MAC(c0, c1, c2, a[34], a[38]);+ MONT_MAC(s0, s1, s2, a[35], a[37]);+ MONT_MAC(t0, t1, t2, a[36], a[36]);+ MONT_MUL(v0, v1, v2, u[25], m[47]);+ MONT_MUL(w0, w1, w2, u[26], m[46]);+ MONT_MAC(t0, t1, t2, u[27], m[45]);+ MONT_MAC(v0, v1, v2, u[28], m[44]);+ MONT_MAC(w0, w1, w2, u[29], m[43]);+ MONT_MAC(t0, t1, t2, u[30], m[42]);+ MONT_MAC(v0, v1, v2, u[31], m[41]);+ MONT_MAC(w0, w1, w2, u[32], m[40]);+ MONT_MAC(t0, t1, t2, u[33], m[39]);+ MONT_MAC(v0, v1, v2, u[34], m[38]);+ MONT_MAC(w0, w1, w2, u[35], m[37]);+ MONT_MAC(t0, t1, t2, u[36], m[36]);+ MONT_MAC(v0, v1, v2, u[37], m[35]);+ MONT_MAC(w0, w1, w2, u[38], m[34]);+ MONT_MAC(t0, t1, t2, u[39], m[33]);+ MONT_MAC(v0, v1, v2, u[40], m[32]);+ MONT_MAC(w0, w1, w2, u[41], m[31]);+ MONT_MAC(t0, t1, t2, u[42], m[30]);+ MONT_MAC(v0, v1, v2, u[43], m[29]);+ MONT_MAC(w0, w1, w2, u[44], m[28]);+ MONT_MAC(t0, t1, t2, u[45], m[27]);+ MONT_MAC(v0, v1, v2, u[46], m[26]);+ MONT_MAC(w0, w1, w2, u[47], m[25]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[24] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 73 */+ MONT_MUL(s0, s1, s2, a[26], a[47]);+ MONT_MUL(c0, c1, c2, a[27], a[46]);+ MONT_MAC(s0, s1, s2, a[28], a[45]);+ MONT_MAC(c0, c1, c2, a[29], a[44]);+ MONT_MAC(s0, s1, s2, a[30], a[43]);+ MONT_MAC(c0, c1, c2, a[31], a[42]);+ MONT_MAC(s0, s1, s2, a[32], a[41]);+ MONT_MAC(c0, c1, c2, a[33], a[40]);+ MONT_MAC(s0, s1, s2, a[34], a[39]);+ MONT_MAC(c0, c1, c2, a[35], a[38]);+ MONT_MAC(s0, s1, s2, a[36], a[37]);+ MONT_MAC(t0, t1, t2, u[26], m[47]);+ MONT_MUL(v0, v1, v2, u[27], m[46]);+ MONT_MUL(w0, w1, w2, u[28], m[45]);+ MONT_MAC(t0, t1, t2, u[29], m[44]);+ MONT_MAC(v0, v1, v2, u[30], m[43]);+ MONT_MAC(w0, w1, w2, u[31], m[42]);+ MONT_MAC(t0, t1, t2, u[32], m[41]);+ MONT_MAC(v0, v1, v2, u[33], m[40]);+ MONT_MAC(w0, w1, w2, u[34], m[39]);+ MONT_MAC(t0, t1, t2, u[35], m[38]);+ MONT_MAC(v0, v1, v2, u[36], m[37]);+ MONT_MAC(w0, w1, w2, u[37], m[36]);+ MONT_MAC(t0, t1, t2, u[38], m[35]);+ MONT_MAC(v0, v1, v2, u[39], m[34]);+ MONT_MAC(w0, w1, w2, u[40], m[33]);+ MONT_MAC(t0, t1, t2, u[41], m[32]);+ MONT_MAC(v0, v1, v2, u[42], m[31]);+ MONT_MAC(w0, w1, w2, u[43], m[30]);+ MONT_MAC(t0, t1, t2, u[44], m[29]);+ MONT_MAC(v0, v1, v2, u[45], m[28]);+ MONT_MAC(w0, w1, w2, u[46], m[27]);+ MONT_MAC(t0, t1, t2, u[47], m[26]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[25] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 74 */+ MONT_MUL(s0, s1, s2, a[27], a[47]);+ MONT_MUL(c0, c1, c2, a[28], a[46]);+ MONT_MAC(s0, s1, s2, a[29], a[45]);+ MONT_MAC(c0, c1, c2, a[30], a[44]);+ MONT_MAC(s0, s1, s2, a[31], a[43]);+ MONT_MAC(c0, c1, c2, a[32], a[42]);+ MONT_MAC(s0, s1, s2, a[33], a[41]);+ MONT_MAC(c0, c1, c2, a[34], a[40]);+ MONT_MAC(s0, s1, s2, a[35], a[39]);+ MONT_MAC(c0, c1, c2, a[36], a[38]);+ MONT_MAC(t0, t1, t2, a[37], a[37]);+ MONT_MUL(v0, v1, v2, u[27], m[47]);+ MONT_MUL(w0, w1, w2, u[28], m[46]);+ MONT_MAC(t0, t1, t2, u[29], m[45]);+ MONT_MAC(v0, v1, v2, u[30], m[44]);+ MONT_MAC(w0, w1, w2, u[31], m[43]);+ MONT_MAC(t0, t1, t2, u[32], m[42]);+ MONT_MAC(v0, v1, v2, u[33], m[41]);+ MONT_MAC(w0, w1, w2, u[34], m[40]);+ MONT_MAC(t0, t1, t2, u[35], m[39]);+ MONT_MAC(v0, v1, v2, u[36], m[38]);+ MONT_MAC(w0, w1, w2, u[37], m[37]);+ MONT_MAC(t0, t1, t2, u[38], m[36]);+ MONT_MAC(v0, v1, v2, u[39], m[35]);+ MONT_MAC(w0, w1, w2, u[40], m[34]);+ MONT_MAC(t0, t1, t2, u[41], m[33]);+ MONT_MAC(v0, v1, v2, u[42], m[32]);+ MONT_MAC(w0, w1, w2, u[43], m[31]);+ MONT_MAC(t0, t1, t2, u[44], m[30]);+ MONT_MAC(v0, v1, v2, u[45], m[29]);+ MONT_MAC(w0, w1, w2, u[46], m[28]);+ MONT_MAC(t0, t1, t2, u[47], m[27]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[26] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 75 */+ MONT_MUL(s0, s1, s2, a[28], a[47]);+ MONT_MUL(c0, c1, c2, a[29], a[46]);+ MONT_MAC(s0, s1, s2, a[30], a[45]);+ MONT_MAC(c0, c1, c2, a[31], a[44]);+ MONT_MAC(s0, s1, s2, a[32], a[43]);+ MONT_MAC(c0, c1, c2, a[33], a[42]);+ MONT_MAC(s0, s1, s2, a[34], a[41]);+ MONT_MAC(c0, c1, c2, a[35], a[40]);+ MONT_MAC(s0, s1, s2, a[36], a[39]);+ MONT_MAC(c0, c1, c2, a[37], a[38]);+ MONT_MAC(t0, t1, t2, u[28], m[47]);+ MONT_MUL(v0, v1, v2, u[29], m[46]);+ MONT_MUL(w0, w1, w2, u[30], m[45]);+ MONT_MAC(t0, t1, t2, u[31], m[44]);+ MONT_MAC(v0, v1, v2, u[32], m[43]);+ MONT_MAC(w0, w1, w2, u[33], m[42]);+ MONT_MAC(t0, t1, t2, u[34], m[41]);+ MONT_MAC(v0, v1, v2, u[35], m[40]);+ MONT_MAC(w0, w1, w2, u[36], m[39]);+ MONT_MAC(t0, t1, t2, u[37], m[38]);+ MONT_MAC(v0, v1, v2, u[38], m[37]);+ MONT_MAC(w0, w1, w2, u[39], m[36]);+ MONT_MAC(t0, t1, t2, u[40], m[35]);+ MONT_MAC(v0, v1, v2, u[41], m[34]);+ MONT_MAC(w0, w1, w2, u[42], m[33]);+ MONT_MAC(t0, t1, t2, u[43], m[32]);+ MONT_MAC(v0, v1, v2, u[44], m[31]);+ MONT_MAC(w0, w1, w2, u[45], m[30]);+ MONT_MAC(t0, t1, t2, u[46], m[29]);+ MONT_MAC(v0, v1, v2, u[47], m[28]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[27] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 76 */+ MONT_MUL(s0, s1, s2, a[29], a[47]);+ MONT_MUL(c0, c1, c2, a[30], a[46]);+ MONT_MAC(s0, s1, s2, a[31], a[45]);+ MONT_MAC(c0, c1, c2, a[32], a[44]);+ MONT_MAC(s0, s1, s2, a[33], a[43]);+ MONT_MAC(c0, c1, c2, a[34], a[42]);+ MONT_MAC(s0, s1, s2, a[35], a[41]);+ MONT_MAC(c0, c1, c2, a[36], a[40]);+ MONT_MAC(s0, s1, s2, a[37], a[39]);+ MONT_MAC(t0, t1, t2, a[38], a[38]);+ MONT_MUL(v0, v1, v2, u[29], m[47]);+ MONT_MUL(w0, w1, w2, u[30], m[46]);+ MONT_MAC(t0, t1, t2, u[31], m[45]);+ MONT_MAC(v0, v1, v2, u[32], m[44]);+ MONT_MAC(w0, w1, w2, u[33], m[43]);+ MONT_MAC(t0, t1, t2, u[34], m[42]);+ MONT_MAC(v0, v1, v2, u[35], m[41]);+ MONT_MAC(w0, w1, w2, u[36], m[40]);+ MONT_MAC(t0, t1, t2, u[37], m[39]);+ MONT_MAC(v0, v1, v2, u[38], m[38]);+ MONT_MAC(w0, w1, w2, u[39], m[37]);+ MONT_MAC(t0, t1, t2, u[40], m[36]);+ MONT_MAC(v0, v1, v2, u[41], m[35]);+ MONT_MAC(w0, w1, w2, u[42], m[34]);+ MONT_MAC(t0, t1, t2, u[43], m[33]);+ MONT_MAC(v0, v1, v2, u[44], m[32]);+ MONT_MAC(w0, w1, w2, u[45], m[31]);+ MONT_MAC(t0, t1, t2, u[46], m[30]);+ MONT_MAC(v0, v1, v2, u[47], m[29]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[28] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 77 */+ MONT_MUL(s0, s1, s2, a[30], a[47]);+ MONT_MUL(c0, c1, c2, a[31], a[46]);+ MONT_MAC(s0, s1, s2, a[32], a[45]);+ MONT_MAC(c0, c1, c2, a[33], a[44]);+ MONT_MAC(s0, s1, s2, a[34], a[43]);+ MONT_MAC(c0, c1, c2, a[35], a[42]);+ MONT_MAC(s0, s1, s2, a[36], a[41]);+ MONT_MAC(c0, c1, c2, a[37], a[40]);+ MONT_MAC(s0, s1, s2, a[38], a[39]);+ MONT_MAC(t0, t1, t2, u[30], m[47]);+ MONT_MUL(v0, v1, v2, u[31], m[46]);+ MONT_MUL(w0, w1, w2, u[32], m[45]);+ MONT_MAC(t0, t1, t2, u[33], m[44]);+ MONT_MAC(v0, v1, v2, u[34], m[43]);+ MONT_MAC(w0, w1, w2, u[35], m[42]);+ MONT_MAC(t0, t1, t2, u[36], m[41]);+ MONT_MAC(v0, v1, v2, u[37], m[40]);+ MONT_MAC(w0, w1, w2, u[38], m[39]);+ MONT_MAC(t0, t1, t2, u[39], m[38]);+ MONT_MAC(v0, v1, v2, u[40], m[37]);+ MONT_MAC(w0, w1, w2, u[41], m[36]);+ MONT_MAC(t0, t1, t2, u[42], m[35]);+ MONT_MAC(v0, v1, v2, u[43], m[34]);+ MONT_MAC(w0, w1, w2, u[44], m[33]);+ MONT_MAC(t0, t1, t2, u[45], m[32]);+ MONT_MAC(v0, v1, v2, u[46], m[31]);+ MONT_MAC(w0, w1, w2, u[47], m[30]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[29] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 78 */+ MONT_MUL(s0, s1, s2, a[31], a[47]);+ MONT_MUL(c0, c1, c2, a[32], a[46]);+ MONT_MAC(s0, s1, s2, a[33], a[45]);+ MONT_MAC(c0, c1, c2, a[34], a[44]);+ MONT_MAC(s0, s1, s2, a[35], a[43]);+ MONT_MAC(c0, c1, c2, a[36], a[42]);+ MONT_MAC(s0, s1, s2, a[37], a[41]);+ MONT_MAC(c0, c1, c2, a[38], a[40]);+ MONT_MAC(t0, t1, t2, a[39], a[39]);+ MONT_MUL(v0, v1, v2, u[31], m[47]);+ MONT_MUL(w0, w1, w2, u[32], m[46]);+ MONT_MAC(t0, t1, t2, u[33], m[45]);+ MONT_MAC(v0, v1, v2, u[34], m[44]);+ MONT_MAC(w0, w1, w2, u[35], m[43]);+ MONT_MAC(t0, t1, t2, u[36], m[42]);+ MONT_MAC(v0, v1, v2, u[37], m[41]);+ MONT_MAC(w0, w1, w2, u[38], m[40]);+ MONT_MAC(t0, t1, t2, u[39], m[39]);+ MONT_MAC(v0, v1, v2, u[40], m[38]);+ MONT_MAC(w0, w1, w2, u[41], m[37]);+ MONT_MAC(t0, t1, t2, u[42], m[36]);+ MONT_MAC(v0, v1, v2, u[43], m[35]);+ MONT_MAC(w0, w1, w2, u[44], m[34]);+ MONT_MAC(t0, t1, t2, u[45], m[33]);+ MONT_MAC(v0, v1, v2, u[46], m[32]);+ MONT_MAC(w0, w1, w2, u[47], m[31]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[30] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 79 */+ MONT_MUL(s0, s1, s2, a[32], a[47]);+ MONT_MUL(c0, c1, c2, a[33], a[46]);+ MONT_MAC(s0, s1, s2, a[34], a[45]);+ MONT_MAC(c0, c1, c2, a[35], a[44]);+ MONT_MAC(s0, s1, s2, a[36], a[43]);+ MONT_MAC(c0, c1, c2, a[37], a[42]);+ MONT_MAC(s0, s1, s2, a[38], a[41]);+ MONT_MAC(c0, c1, c2, a[39], a[40]);+ MONT_MAC(t0, t1, t2, u[32], m[47]);+ MONT_MUL(v0, v1, v2, u[33], m[46]);+ MONT_MUL(w0, w1, w2, u[34], m[45]);+ MONT_MAC(t0, t1, t2, u[35], m[44]);+ MONT_MAC(v0, v1, v2, u[36], m[43]);+ MONT_MAC(w0, w1, w2, u[37], m[42]);+ MONT_MAC(t0, t1, t2, u[38], m[41]);+ MONT_MAC(v0, v1, v2, u[39], m[40]);+ MONT_MAC(w0, w1, w2, u[40], m[39]);+ MONT_MAC(t0, t1, t2, u[41], m[38]);+ MONT_MAC(v0, v1, v2, u[42], m[37]);+ MONT_MAC(w0, w1, w2, u[43], m[36]);+ MONT_MAC(t0, t1, t2, u[44], m[35]);+ MONT_MAC(v0, v1, v2, u[45], m[34]);+ MONT_MAC(w0, w1, w2, u[46], m[33]);+ MONT_MAC(t0, t1, t2, u[47], m[32]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[31] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 80 */+ MONT_MUL(s0, s1, s2, a[33], a[47]);+ MONT_MUL(c0, c1, c2, a[34], a[46]);+ MONT_MAC(s0, s1, s2, a[35], a[45]);+ MONT_MAC(c0, c1, c2, a[36], a[44]);+ MONT_MAC(s0, s1, s2, a[37], a[43]);+ MONT_MAC(c0, c1, c2, a[38], a[42]);+ MONT_MAC(s0, s1, s2, a[39], a[41]);+ MONT_MAC(t0, t1, t2, a[40], a[40]);+ MONT_MUL(v0, v1, v2, u[33], m[47]);+ MONT_MUL(w0, w1, w2, u[34], m[46]);+ MONT_MAC(t0, t1, t2, u[35], m[45]);+ MONT_MAC(v0, v1, v2, u[36], m[44]);+ MONT_MAC(w0, w1, w2, u[37], m[43]);+ MONT_MAC(t0, t1, t2, u[38], m[42]);+ MONT_MAC(v0, v1, v2, u[39], m[41]);+ MONT_MAC(w0, w1, w2, u[40], m[40]);+ MONT_MAC(t0, t1, t2, u[41], m[39]);+ MONT_MAC(v0, v1, v2, u[42], m[38]);+ MONT_MAC(w0, w1, w2, u[43], m[37]);+ MONT_MAC(t0, t1, t2, u[44], m[36]);+ MONT_MAC(v0, v1, v2, u[45], m[35]);+ MONT_MAC(w0, w1, w2, u[46], m[34]);+ MONT_MAC(t0, t1, t2, u[47], m[33]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[32] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 81 */+ MONT_MUL(s0, s1, s2, a[34], a[47]);+ MONT_MUL(c0, c1, c2, a[35], a[46]);+ MONT_MAC(s0, s1, s2, a[36], a[45]);+ MONT_MAC(c0, c1, c2, a[37], a[44]);+ MONT_MAC(s0, s1, s2, a[38], a[43]);+ MONT_MAC(c0, c1, c2, a[39], a[42]);+ MONT_MAC(s0, s1, s2, a[40], a[41]);+ MONT_MAC(t0, t1, t2, u[34], m[47]);+ MONT_MUL(v0, v1, v2, u[35], m[46]);+ MONT_MUL(w0, w1, w2, u[36], m[45]);+ MONT_MAC(t0, t1, t2, u[37], m[44]);+ MONT_MAC(v0, v1, v2, u[38], m[43]);+ MONT_MAC(w0, w1, w2, u[39], m[42]);+ MONT_MAC(t0, t1, t2, u[40], m[41]);+ MONT_MAC(v0, v1, v2, u[41], m[40]);+ MONT_MAC(w0, w1, w2, u[42], m[39]);+ MONT_MAC(t0, t1, t2, u[43], m[38]);+ MONT_MAC(v0, v1, v2, u[44], m[37]);+ MONT_MAC(w0, w1, w2, u[45], m[36]);+ MONT_MAC(t0, t1, t2, u[46], m[35]);+ MONT_MAC(v0, v1, v2, u[47], m[34]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[33] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 82 */+ MONT_MUL(s0, s1, s2, a[35], a[47]);+ MONT_MUL(c0, c1, c2, a[36], a[46]);+ MONT_MAC(s0, s1, s2, a[37], a[45]);+ MONT_MAC(c0, c1, c2, a[38], a[44]);+ MONT_MAC(s0, s1, s2, a[39], a[43]);+ MONT_MAC(c0, c1, c2, a[40], a[42]);+ MONT_MAC(t0, t1, t2, a[41], a[41]);+ MONT_MUL(v0, v1, v2, u[35], m[47]);+ MONT_MUL(w0, w1, w2, u[36], m[46]);+ MONT_MAC(t0, t1, t2, u[37], m[45]);+ MONT_MAC(v0, v1, v2, u[38], m[44]);+ MONT_MAC(w0, w1, w2, u[39], m[43]);+ MONT_MAC(t0, t1, t2, u[40], m[42]);+ MONT_MAC(v0, v1, v2, u[41], m[41]);+ MONT_MAC(w0, w1, w2, u[42], m[40]);+ MONT_MAC(t0, t1, t2, u[43], m[39]);+ MONT_MAC(v0, v1, v2, u[44], m[38]);+ MONT_MAC(w0, w1, w2, u[45], m[37]);+ MONT_MAC(t0, t1, t2, u[46], m[36]);+ MONT_MAC(v0, v1, v2, u[47], m[35]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[34] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 83 */+ MONT_MUL(s0, s1, s2, a[36], a[47]);+ MONT_MUL(c0, c1, c2, a[37], a[46]);+ MONT_MAC(s0, s1, s2, a[38], a[45]);+ MONT_MAC(c0, c1, c2, a[39], a[44]);+ MONT_MAC(s0, s1, s2, a[40], a[43]);+ MONT_MAC(c0, c1, c2, a[41], a[42]);+ MONT_MAC(t0, t1, t2, u[36], m[47]);+ MONT_MUL(v0, v1, v2, u[37], m[46]);+ MONT_MUL(w0, w1, w2, u[38], m[45]);+ MONT_MAC(t0, t1, t2, u[39], m[44]);+ MONT_MAC(v0, v1, v2, u[40], m[43]);+ MONT_MAC(w0, w1, w2, u[41], m[42]);+ MONT_MAC(t0, t1, t2, u[42], m[41]);+ MONT_MAC(v0, v1, v2, u[43], m[40]);+ MONT_MAC(w0, w1, w2, u[44], m[39]);+ MONT_MAC(t0, t1, t2, u[45], m[38]);+ MONT_MAC(v0, v1, v2, u[46], m[37]);+ MONT_MAC(w0, w1, w2, u[47], m[36]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[35] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 84 */+ MONT_MUL(s0, s1, s2, a[37], a[47]);+ MONT_MUL(c0, c1, c2, a[38], a[46]);+ MONT_MAC(s0, s1, s2, a[39], a[45]);+ MONT_MAC(c0, c1, c2, a[40], a[44]);+ MONT_MAC(s0, s1, s2, a[41], a[43]);+ MONT_MAC(t0, t1, t2, a[42], a[42]);+ MONT_MUL(v0, v1, v2, u[37], m[47]);+ MONT_MUL(w0, w1, w2, u[38], m[46]);+ MONT_MAC(t0, t1, t2, u[39], m[45]);+ MONT_MAC(v0, v1, v2, u[40], m[44]);+ MONT_MAC(w0, w1, w2, u[41], m[43]);+ MONT_MAC(t0, t1, t2, u[42], m[42]);+ MONT_MAC(v0, v1, v2, u[43], m[41]);+ MONT_MAC(w0, w1, w2, u[44], m[40]);+ MONT_MAC(t0, t1, t2, u[45], m[39]);+ MONT_MAC(v0, v1, v2, u[46], m[38]);+ MONT_MAC(w0, w1, w2, u[47], m[37]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[36] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 85 */+ MONT_MUL(s0, s1, s2, a[38], a[47]);+ MONT_MUL(c0, c1, c2, a[39], a[46]);+ MONT_MAC(s0, s1, s2, a[40], a[45]);+ MONT_MAC(c0, c1, c2, a[41], a[44]);+ MONT_MAC(s0, s1, s2, a[42], a[43]);+ MONT_MAC(t0, t1, t2, u[38], m[47]);+ MONT_MUL(v0, v1, v2, u[39], m[46]);+ MONT_MUL(w0, w1, w2, u[40], m[45]);+ MONT_MAC(t0, t1, t2, u[41], m[44]);+ MONT_MAC(v0, v1, v2, u[42], m[43]);+ MONT_MAC(w0, w1, w2, u[43], m[42]);+ MONT_MAC(t0, t1, t2, u[44], m[41]);+ MONT_MAC(v0, v1, v2, u[45], m[40]);+ MONT_MAC(w0, w1, w2, u[46], m[39]);+ MONT_MAC(t0, t1, t2, u[47], m[38]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[37] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 86 */+ MONT_MUL(s0, s1, s2, a[39], a[47]);+ MONT_MUL(c0, c1, c2, a[40], a[46]);+ MONT_MAC(s0, s1, s2, a[41], a[45]);+ MONT_MAC(c0, c1, c2, a[42], a[44]);+ MONT_MAC(t0, t1, t2, a[43], a[43]);+ MONT_MUL(v0, v1, v2, u[39], m[47]);+ MONT_MUL(w0, w1, w2, u[40], m[46]);+ MONT_MAC(t0, t1, t2, u[41], m[45]);+ MONT_MAC(v0, v1, v2, u[42], m[44]);+ MONT_MAC(w0, w1, w2, u[43], m[43]);+ MONT_MAC(t0, t1, t2, u[44], m[42]);+ MONT_MAC(v0, v1, v2, u[45], m[41]);+ MONT_MAC(w0, w1, w2, u[46], m[40]);+ MONT_MAC(t0, t1, t2, u[47], m[39]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[38] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 87 */+ MONT_MUL(s0, s1, s2, a[40], a[47]);+ MONT_MUL(c0, c1, c2, a[41], a[46]);+ MONT_MAC(s0, s1, s2, a[42], a[45]);+ MONT_MAC(c0, c1, c2, a[43], a[44]);+ MONT_MAC(t0, t1, t2, u[40], m[47]);+ MONT_MUL(v0, v1, v2, u[41], m[46]);+ MONT_MUL(w0, w1, w2, u[42], m[45]);+ MONT_MAC(t0, t1, t2, u[43], m[44]);+ MONT_MAC(v0, v1, v2, u[44], m[43]);+ MONT_MAC(w0, w1, w2, u[45], m[42]);+ MONT_MAC(t0, t1, t2, u[46], m[41]);+ MONT_MAC(v0, v1, v2, u[47], m[40]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[39] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 88 */+ MONT_MUL(s0, s1, s2, a[41], a[47]);+ MONT_MUL(c0, c1, c2, a[42], a[46]);+ MONT_MAC(s0, s1, s2, a[43], a[45]);+ MONT_MAC(t0, t1, t2, a[44], a[44]);+ MONT_MUL(v0, v1, v2, u[41], m[47]);+ MONT_MUL(w0, w1, w2, u[42], m[46]);+ MONT_MAC(t0, t1, t2, u[43], m[45]);+ MONT_MAC(v0, v1, v2, u[44], m[44]);+ MONT_MAC(w0, w1, w2, u[45], m[43]);+ MONT_MAC(t0, t1, t2, u[46], m[42]);+ MONT_MAC(v0, v1, v2, u[47], m[41]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[40] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 89 */+ MONT_MUL(s0, s1, s2, a[42], a[47]);+ MONT_MUL(c0, c1, c2, a[43], a[46]);+ MONT_MAC(s0, s1, s2, a[44], a[45]);+ MONT_MAC(t0, t1, t2, u[42], m[47]);+ MONT_MUL(v0, v1, v2, u[43], m[46]);+ MONT_MUL(w0, w1, w2, u[44], m[45]);+ MONT_MAC(t0, t1, t2, u[45], m[44]);+ MONT_MAC(v0, v1, v2, u[46], m[43]);+ MONT_MAC(w0, w1, w2, u[47], m[42]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[41] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 90 */+ MONT_MUL(s0, s1, s2, a[43], a[47]);+ MONT_MUL(c0, c1, c2, a[44], a[46]);+ MONT_MAC(t0, t1, t2, a[45], a[45]);+ MONT_MUL(v0, v1, v2, u[43], m[47]);+ MONT_MUL(w0, w1, w2, u[44], m[46]);+ MONT_MAC(t0, t1, t2, u[45], m[45]);+ MONT_MAC(v0, v1, v2, u[46], m[44]);+ MONT_MAC(w0, w1, w2, u[47], m[43]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[42] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 91 */+ MONT_MUL(s0, s1, s2, a[44], a[47]);+ MONT_MUL(c0, c1, c2, a[45], a[46]);+ MONT_MAC(t0, t1, t2, u[44], m[47]);+ MONT_MUL(v0, v1, v2, u[45], m[46]);+ MONT_MUL(w0, w1, w2, u[46], m[45]);+ MONT_MAC(t0, t1, t2, u[47], m[44]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_ADD(s0, s1, s2, c0, c1, c2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[43] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 92 */+ MONT_MUL(s0, s1, s2, a[45], a[47]);+ MONT_MAC(t0, t1, t2, a[46], a[46]);+ MONT_MUL(v0, v1, v2, u[45], m[47]);+ MONT_MUL(w0, w1, w2, u[46], m[46]);+ MONT_MAC(t0, t1, t2, u[47], m[45]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_ADD(t0, t1, t2, w0, w1, w2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[44] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 93 */+ MONT_MUL(s0, s1, s2, a[46], a[47]);+ MONT_MAC(t0, t1, t2, u[46], m[47]);+ MONT_MUL(v0, v1, v2, u[47], m[46]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ MONT_DBL(s0, s1, s2);+ MONT_ADD(t0, t1, t2, s0, s1, s2);+ z[45] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ /* column 94 */+ MONT_MAC(t0, t1, t2, a[47], a[47]);+ MONT_MUL(v0, v1, v2, u[47], m[47]);+ MONT_ADD(t0, t1, t2, v0, v1, v2);+ z[46] = t0;+ t0 = t1;+ t1 = t2;+ t2 = 0;+ z[47] = t0;++ /* under 2m, with t1 the bit above n limbs: at most one subtraction */+ borrow = sub_n(r, z, m, 48);+ take = t1 | (borrow ^ 1);+ select_n(r, r, z, take & 1, 48);+}++#endif
@@ -0,0 +1,173 @@+#!/usr/bin/env python3+"""Generate cbits/crypton_mont.h: Montgomery multiplication and squaring for+AArch64 at the limb counts of RSA's CRT halves, fully unrolled and+product-scanning.++Usage: python3 cbits/crypton_mont.py > cbits/crypton_mont.h++The result is a column at a time, with the reduction folded into the same+scan (the FIPS method), so the running sum stays in registers instead of+going through memory a row at a time. A column's products are spread over+three accumulators and added together at its end, since one accumulator's+carry chain is what holds the core back, not its multipliers. In a square,+each product off the diagonal is summed once, doubled, and added in.+"""++SIZES = (16, 24, 32)+# Squaring at 48 too, RSA-3072's modulus, for the verification that is+# seventeen squarings. Its multiplication, at twice the code, is left out.+SQR_ONLY = (48,)++HEADER = """\+/* Generated by cbits/crypton_mont.py; do not edit.+ *+ * Montgomery multiplication and squaring for AArch64 at 16, 24 and 32 limbs,+ * the halves of RSA-2048, -3072 and -4096, and squaring at 48, RSA-3072's+ * modulus. Each answers what mont_mul and mont_sqr answer. */+#ifndef CRYPTON_MONT_H+#define CRYPTON_MONT_H++#include "crypton_bignum.h"++/* (t2:t1:t0) += x * y */+#define MONT_MAC(t0, t1, t2, x, y) \\+ do { \\+ limb_t lo_, hi_; \\+ __asm__("mul\\t%0, %5, %6\\n\\t" \\+ "umulh\\t%1, %5, %6\\n\\t" \\+ "adds\\t%2, %2, %0\\n\\t" \\+ "adcs\\t%3, %3, %1\\n\\t" \\+ "adc\\t%4, %4, xzr" \\+ : "=&r"(lo_), "=&r"(hi_), "+r"(t0), "+r"(t1), "+r"(t2) \\+ : "r"(x), "r"(y) \\+ : "cc"); \\+ } while (0)++/* (s2:s1:s0) = x * y */+#define MONT_MUL(s0, s1, s2, x, y) \\+ __asm__("mul\\t%0, %3, %4\\n\\t" \\+ "umulh\\t%1, %3, %4\\n\\t" \\+ "mov\\t%2, xzr" \\+ : "=&r"(s0), "=&r"(s1), "=r"(s2) \\+ : "r"(x), "r"(y))++/* (t2:t1:t0) += (s2:s1:s0) */+#define MONT_ADD(t0, t1, t2, s0, s1, s2) \\+ __asm__("adds\\t%0, %0, %3\\n\\t" \\+ "adcs\\t%1, %1, %4\\n\\t" \\+ "adc\\t%2, %2, %5" \\+ : "+r"(t0), "+r"(t1), "+r"(t2) \\+ : "r"(s0), "r"(s1), "r"(s2) \\+ : "cc")++/* (s2:s1:s0) *= 2 */+#define MONT_DBL(s0, s1, s2) \\+ do { \\+ s2 = (s2 << 1) | (s1 >> 63); \\+ s1 = (s1 << 1) | (s0 >> 63); \\+ s0 <<= 1; \\+ } while (0)+"""++FOOTER = """\+#endif+"""+++class Column:+ """Products added to accumulators, each set up by its first product."""++ def __init__(self, w):+ self.w = w+ self.started = set()++ def add(self, acc, x, y):+ if acc == "t" or acc in self.started:+ self.w(f"\tMONT_MAC({acc}0, {acc}1, {acc}2, {x}, {y});")+ else:+ self.w(f"\tMONT_MUL({acc}0, {acc}1, {acc}2, {x}, {y});")+ self.started.add(acc)++ def fold(self, into, acc):+ if acc in self.started:+ self.w(f"\tMONT_ADD({into}0, {into}1, {into}2, {acc}0, {acc}1, {acc}2);")+++def column(w, singles, cross):+ """singles are added once, cross twice: s and c take the cross products,+ t, v and w take the rest, and all of them end up in t."""+ col = Column(w)+ for k, (x, y) in enumerate(cross):+ col.add("s" if k % 2 == 0 else "c", x, y)+ for k, (x, y) in enumerate(singles):+ col.add("tvw"[k % 3], x, y)+ col.fold("t", "v")+ col.fold("t", "w")+ if cross:+ col.fold("s", "c")+ w("\tMONT_DBL(s0, s1, s2);")+ w("\tMONT_ADD(t0, t1, t2, s0, s1, s2);")+++def gen(n, square):+ out = []+ w = out.append+ name = f"crypton_mont_{'sqr' if square else 'mul'}{n}"+ args = "const limb_t *a," if square else "const limb_t *a, const limb_t *b,"+ if square:+ w(f"/* r = a * a * R^-1 mod m, for a under m; t is 2n limbs of scratch */")+ else:+ w(f"/* r = a * b * R^-1 mod m, for a and b under m; t is 2n limbs of scratch */")+ w(f"static void {name}(limb_t *r, {args}")+ w(f"{' ' * len(f'static void {name}(')}const limb_t *m, limb_t n0, limb_t *t)")+ w("{")+ w(f"\tlimb_t *u = t, *z = t + {n};")+ w("\tlimb_t t0 = 0, t1 = 0, t2 = 0, v0, v1, v2, w0, w1, w2, borrow, take;")+ if square:+ w("\tlimb_t s0, s1, s2, c0, c1, c2;")+ w("")+ for i in range(2 * n - 1):+ w(f"\t/* column {i} */")+ singles, cross = [], []+ for j in range(max(0, i - n + 1), min(i, n - 1) + 1):+ k = i - j+ if not square:+ singles.append((f"a[{j}]", f"b[{k}]"))+ elif j < k:+ cross.append((f"a[{j}]", f"a[{k}]"))+ elif j == k:+ singles.append((f"a[{j}]", f"a[{j}]"))+ for j in range(max(0, i - n + 1), min(i, n)):+ singles.append((f"u[{j}]", f"m[{i - j}]"))+ column(w, singles, cross)+ if i < n:+ w(f"\tu[{i}] = t0 * n0;")+ w(f"\tMONT_MAC(t0, t1, t2, u[{i}], m[0]);")+ else:+ w(f"\tz[{i - n}] = t0;")+ w("\tt0 = t1;")+ w("\tt1 = t2;")+ w("\tt2 = 0;")+ w(f"\tz[{n - 1}] = t0;")+ w("")+ w("\t/* under 2m, with t1 the bit above n limbs: at most one subtraction */")+ w(f"\tborrow = sub_n(r, z, m, {n});")+ w("\ttake = t1 | (borrow ^ 1);")+ w(f"\tselect_n(r, r, z, take & 1, {n});")+ w("}")+ w("")+ return "\n".join(out)+++def main():+ print(HEADER)+ for n in SIZES:+ print(gen(n, False))+ print(gen(n, True))+ for n in SQR_ONLY:+ print(gen(n, True))+ print(FOOTER, end="")+++if __name__ == "__main__":+ main()
@@ -46,6 +46,7 @@ /* Internal function/type names for hash-specific things. */ #define HMAC_CTX(_name) HMAC_ ## _name ## _ctx+#define DIGEST_FITS(_name) pbkdf2_ ## _name ## _digest_fits_in_a_block #define HMAC_INIT(_name) HMAC_ ## _name ## _init #define HMAC_UPDATE(_name) HMAC_ ## _name ## _update #define HMAC_FINAL(_name) HMAC_ ## _name ## _final@@ -79,6 +80,16 @@ */ #define DECL_PBKDF2(_name, _blocksz, _hashsz, _ctx, \ _init, _update, _xform, _final, _xcpy, _xtract, _xxor) \+ /* HMAC_INIT below shortens a key longer than the block by hashing it, \+ * which writes _hashsz bytes into a buffer of _blocksz. An instantiation \+ * whose digest is larger than its block would overflow that buffer, and \+ * would do it before any check inside the function could say so -- which \+ * is where the check used to be. Refuse such an instantiation here \+ * instead, in front of the person writing it. The three below are \+ * SHA-1, SHA-256 and SHA-512, whose digests are 20, 32 and 64 bytes \+ * against blocks of 64, 64 and 128. */ \+ typedef char DIGEST_FITS(_name)[(_hashsz) <= (_blocksz) ? 1 : -1]; \+ \ typedef struct { \ _ctx inner; \ _ctx outer; \@@ -101,9 +112,6 @@ nkey = _hashsz; \ } \ \- /* Standard doesn't cover case where blocksz < hashsz. */ \- assert(nkey <= _blocksz); \- \ /* Right zero-pad short keys. */ \ if (k != key) \ memcpy(k, key, nkey); \@@ -192,7 +200,16 @@ uint8_t *out, size_t nout) \ { \ assert(iterations); \- assert(out && nout); \+ assert(out); \+ \+ /* Zero bytes of derived key is zero bytes of work. RFC 8018 asks for a \+ * positive dkLen and the loop below would write a block regardless, so \+ * this used to be `assert(out && nout)` -- which aborts the process, in \+ * a library built without NDEBUG, on a length the caller chose. \+ * Crypto.KDF.PBKDF2's own tryGenerate returns an empty result for this, \+ * so return and let the two agree. */ \+ if (nout == 0) \+ return; \ \ /* Starting point for inner loop. */ \ HMAC_CTX(_name) ctx; \
@@ -20,21 +20,536 @@ #include <stdlib.h> #include <crypton_bignum.h> #include <crypton_powm.h>+#include <crypton_bzero.h> -/* four bits of exponent per window, so a table of sixteen and no leftover- * bits: a byte holds exactly two windows */-#define WINDOW_BITS 4+/* On AArch64, multiplication and squaring at the RSA half sizes go through+ * generated code that scans a column at a time with the reduction folded in;+ * see cbits/crypton_mont.py. CRYPTON_NO_MONT_FIXED keeps mont_mul and+ * mont_sqr, to compare. */+#if defined(__aarch64__) && LIMB_BITS == 64 && !defined(CRYPTON_NO_MONT_FIXED) \+ && (defined(__GNUC__) || defined(__clang__))+#define CRYPTON_MONT_FIXED 1+#include <crypton_mont.h>+#endif++/*+ * At RSA sizes on x86-64, the Montgomery multiplication below is the whole+ * cost, and s2n-bignum's is twice as fast because the C cannot form the two+ * carry chains ADCX and ADOX give. The window, the table and its masked+ * scan are unchanged: only the multiply and the square are swapped, and+ * only for the sizes s2n-bignum has a Karatsuba multiplication for.+ *+ * Not on AArch64, where the C measures 5% faster than the assembly.+ * See cbits/s2n/README.md.+ */+/* Not on macOS, where crypton.cabal leaves these files out: Apple's assembler+ * cannot assemble bignum_emontredc_8n. See the note beside them there. */+#if defined(CRYPTON_S2N_BIGNUM) && defined(__x86_64__) && !defined(__APPLE__)+#define CRYPTON_POWM_S2N 1+#include <crypton_cpu.h>++extern void bignum_kmul_16_32(uint64_t *z, const uint64_t *x,+ const uint64_t *y, uint64_t *t);+extern void bignum_ksqr_16_32(uint64_t *z, const uint64_t *x, uint64_t *t);+extern void bignum_kmul_32_64(uint64_t *z, const uint64_t *x,+ const uint64_t *y, uint64_t *t);+extern void bignum_ksqr_32_64(uint64_t *z, const uint64_t *x, uint64_t *t);+extern uint64_t bignum_emontredc_8n(uint64_t k, uint64_t *z,+ const uint64_t *m, uint64_t w);+extern void bignum_mul(uint64_t k, uint64_t *z, uint64_t m, const uint64_t *x,+ uint64_t n, const uint64_t *y);+extern void bignum_sqr(uint64_t k, uint64_t *z, uint64_t n, const uint64_t *x);+extern void bignum_sqr_8_16(uint64_t *z, const uint64_t *x);+extern void bignum_mul_8_16(uint64_t *z, const uint64_t *x, const uint64_t *y);++/* 16 limbs is 1024 bits and 32 is 2048: the halves a CRT exponentiation+ * works in for RSA-2048 and RSA-4096, and the whole thing without CRT. 24+ * is 1536, the half of RSA-3072, which has no Karatsuba routine of its own:+ * its multiplication is the 32-limb one with the operands padded, and its+ * square is built from 8-limb pieces, which measured faster on a whole+ * exponentiation than the padded square. Both are still nearly twice the+ * C, since the C cannot form ADCX and ADOX's two carry chains at any size.+ *+ * 48 and 64 are 3072 and 4096 bits: finite-field Diffie-Hellman over the+ * RFC 7919 groups of those sizes, and RSA without CRT. There is no+ * Karatsuba routine at either, and padding to the next would be wasteful,+ * so the multiplication is s2n-bignum's schoolbook one of any size --+ * plain MUL and ADC, no ADX -- and the reduction is the same ADX one. Not+ * the gain the Karatsuba sizes have, and still well ahead of the C.+ *+ * The reduction wants ADX, so the answer is a run-time one. */+static int powm_s2n_usable(uint32_t n)+{+ return (n == 16 || n == 24 || n == 32 || n == 48 || n == 64)+ && (crypton_x86_simd_features() & CRYPTON_X86_ADX) != 0;+}++/* The scratch the routines ask for, in limbs. kmul_16_32 and kmul_32_64+ * want three times their operand. A 24-limb operand padded to 32 wants the+ * 32-limb routine's 64-limb product and its 96 limbs of its own, and the two+ * padded operands besides. */+#define POWM_S2N_PAD_Z 0+#define POWM_S2N_PAD_T 64+#define POWM_S2N_PAD_X (64 + 96)+#define POWM_S2N_PAD_Y (64 + 96 + 32)+static uint32_t powm_s2n_scratch(uint32_t n)+{+ return n == 24 ? 64 + 96 + 32 + 32 : 3 * n;+}++/* a 24-limb operand in the low limbs of 32, the rest zero: zeroed every+ * time rather than once, so that nothing else writing the scratch can+ * leave a high limb behind */+static void powm_s2n_pad(limb_t *to, const limb_t *from)+{+ memcpy(to, from, 24 * sizeof(limb_t));+ memset(to + 24, 0, 8 * sizeof(limb_t));+}++/* bignum_emontredc_8n leaves the result in the top half of z with one more+ * bit as its return value, and what is there is under twice the modulus --+ * the same place mont_reduce ends up, and finished the same way. */+static void powm_s2n_finish(limb_t *r, limb_t *z, const limb_t *m,+ limb_t carry, uint32_t n)+{+ limb_t borrow = sub_n(r, z + n, m, n);+ limb_t take = carry | (borrow ^ 1);++ select_n(r, r, z + n, take & 1, n);+}++static void powm_s2n_mul(limb_t *r, const limb_t *a, const limb_t *b,+ const limb_t *m, limb_t n0, uint32_t n, limb_t *z,+ limb_t *scratch)+{+ if (n == 24) {+ /* the product of two 24-limb numbers is 48 limbs, so the top+ * sixteen of the 64 written are zero and the reduction reads+ * only what it should */+ z = scratch + POWM_S2N_PAD_Z;+ powm_s2n_pad(scratch + POWM_S2N_PAD_X, a);+ powm_s2n_pad(scratch + POWM_S2N_PAD_Y, b);+ bignum_kmul_32_64(z, scratch + POWM_S2N_PAD_X,+ scratch + POWM_S2N_PAD_Y,+ scratch + POWM_S2N_PAD_T);+ } else if (n == 48 || n == 64)+ bignum_mul(2 * n, z, n, a, n, b);+ else if (n == 16)+ bignum_kmul_16_32(z, a, b, scratch);+ else+ bignum_kmul_32_64(z, a, b, scratch);+ powm_s2n_finish(r, z, m, bignum_emontredc_8n(n, z, m, n0), n);+}++/* a^2 for a of 24 limbs, from three 8-limb squares and three 8-limb+ * products: a = a0 + a1 X + a2 X^2 with X = 2^512, and the cross terms, at+ * X to X^3 in c, go in doubled. c is 48 limbs of scratch. */+static void powm_s2n_sqr24(limb_t *z, const limb_t *a, limb_t *c)+{+ limb_t k;+ uint32_t i;++ bignum_sqr_8_16(z, a);+ bignum_sqr_8_16(z + 16, a + 8);+ bignum_sqr_8_16(z + 32, a + 16);+ bignum_mul_8_16(c, a, a + 8);+ bignum_mul_8_16(c + 16, a + 8, a + 16);+ bignum_mul_8_16(c + 32, a, a + 16);+ k = add_n(c + 8, c + 8, c + 32, 16);+ for (i = 24; i < 32; i++) {+ c[i] += k;+ k = c[i] < k;+ }+ k = shl1(c, 32);+ k += add_n(z + 8, z + 8, c, 32);+ for (i = 40; i < 48; i++) {+ z[i] += k;+ k = z[i] < k;+ }+}++static void powm_s2n_sqr(limb_t *r, const limb_t *a, const limb_t *m,+ limb_t n0, uint32_t n, limb_t *z, limb_t *scratch)+{+ if (n == 24) {+ z = scratch + POWM_S2N_PAD_Z;+ powm_s2n_sqr24(z, a, scratch + POWM_S2N_PAD_T);+ } else if (n == 48 || n == 64)+ bignum_sqr(2 * n, z, n, a);+ else if (n == 16)+ bignum_ksqr_16_32(z, a, scratch);+ else+ bignum_ksqr_32_64(z, a, scratch);+ powm_s2n_finish(r, z, m, bignum_emontredc_8n(n, z, m, n0), n);+}+#else+static uint32_t powm_s2n_scratch(uint32_t n)+{+ (void) n;+ return 0;+}+#endif++/* One or the other, decided once per call */+static void powm_mul(limb_t *r, const limb_t *a, const limb_t *b,+ const limb_t *m, limb_t n0, uint32_t n, limb_t *t,+ limb_t *scratch, int s2n)+{+#ifdef CRYPTON_POWM_S2N+ if (s2n) {+ powm_s2n_mul(r, a, b, m, n0, n, t, scratch);+ return;+ }+#else+ (void)scratch;+ (void)s2n;+#endif+#ifdef CRYPTON_MONT_FIXED+ switch (n) {+ case 16: crypton_mont_mul16(r, a, b, m, n0, t); return;+ case 24: crypton_mont_mul24(r, a, b, m, n0, t); return;+ case 32: crypton_mont_mul32(r, a, b, m, n0, t); return;+ }+#endif+ mont_mul(r, a, b, m, n0, n, t);+}++static void powm_sqr(limb_t *r, const limb_t *a, const limb_t *m, limb_t n0,+ uint32_t n, limb_t *t, limb_t *scratch, int s2n)+{+#ifdef CRYPTON_POWM_S2N+ if (s2n) {+ powm_s2n_sqr(r, a, m, n0, n, t, scratch);+ return;+ }+#else+ (void)scratch;+ (void)s2n;+#endif+#ifdef CRYPTON_MONT_FIXED+ switch (n) {+ case 16: crypton_mont_sqr16(r, a, m, n0, t); return;+ case 24: crypton_mont_sqr24(r, a, m, n0, t); return;+ case 32: crypton_mont_sqr32(r, a, m, n0, t); return;+ case 48: crypton_mont_sqr48(r, a, m, n0, t); return;+ }+#endif+ mont_sqr(r, a, m, n0, n, t);+}++/* Four bits of exponent per window, so a table of sixteen.+ *+ * Five was written and measured and is not here. A wider window saves+ * multiplications -- 205 of them against 256 at 1024 bits, with the same+ * 1024 squarings -- and pays for it in the masked scan of a table twice as+ * long. When that was first measured the scan was the scalar one, and five+ * came out 3.5% better on an Apple M4, about 1% worse on an older x86-64 and+ * 7% worse where s2n-bignum's multiplication runs, since that makes the scan+ * the expensive half. The conclusion written here was that what would make+ * a wider window pay is a cheaper scan.+ *+ * The cheaper scan arrived twenty-one minutes later, in the AVX2 form above,+ * and nobody measured the window again. Measured since, on the machine the+ * x86-64 table is measured on and with both builds raced in one run: five is+ * 0.6% worse than four, beside 0.5% between two builds that differ in+ * nothing. So the cheaper scan did not turn it round -- the window stays at+ * four, and now for a reason that was checked after the scan rather than+ * before it.+ *+ * The width is POWM_WINDOW_BITS so that it can be measured rather than+ * argued about. It had to be renamed to be settable at all: WINDOW_BITS was+ * defined here, in cbits/crypton_ecc.c and in cbits/crypton_bignum.h, all+ * three to four, and a redefinition to the same value is silent -- so+ * -DWINDOW_BITS=5 was overridden by the header and three builds meant to+ * differ did not. cbits/tests/powm builds the walk at four, five and six+ * and requires the same answers of all three. */+#ifndef POWM_WINDOW_BITS+#define POWM_WINDOW_BITS 4+#endif+#define WINDOW_BITS POWM_WINDOW_BITS #define TABLE_SIZE (1 << WINDOW_BITS) +/* Window number k counting from the bottom, where the bottom window holds+ * the exponent's least significant WINDOW_BITS bits. The exponent is+ * big-endian bytes, and a window may straddle a byte boundary once the width+ * stops dividing eight, so this reads the two bytes it can fall across.+ *+ * Which window is being read is the loop counter, not the exponent, so the+ * shifts and the index here are public.+ */+static limb_t exp_window(const uint8_t *exp, uint32_t explen, uint32_t k)+{+ uint32_t lo = k * WINDOW_BITS; /* bit offset from the bottom */+ uint32_t byte = lo / 8, off = lo % 8;+ uint32_t v;++ if (byte >= explen)+ return 0;+ v = exp[explen - 1 - byte];+ if (off + WINDOW_BITS > 8 && byte + 1 < explen)+ v |= (uint32_t) exp[explen - 2 - byte] << 8;+ return (v >> off) & (TABLE_SIZE - 1);+}++/* The masked scan of the table: every entry is read and a mask keeps the one+ * wanted, so that the address stream does not follow the exponent. At+ * RSA-2048's CRT size that is two kilobytes read per window, and the window+ * loop runs 256 times per exponentiation, which is why it is worth a vector+ * register: removing the scan altogether measures 11% of an exponentiation+ * where s2n-bignum's multiplication runs, and the AVX2 form below gets+ * essentially all of it. */+static void scan_table(limb_t *sel, const limb_t *table, uint32_t n, limb_t w)+{+ uint32_t k, l;++ memset(sel, 0, n * sizeof(limb_t));+ for (k = 0; k < TABLE_SIZE; k++) {+ limb_t mask = eq_mask(k, w);++ for (l = 0; l < n; l++)+ sel[l] |= table[k * n + l] & mask;+ }+}++#if defined(__x86_64__) && defined(WITH_TARGET_ATTRIBUTES) && LIMB_BITS == 64+#define CRYPTON_POWM_SCAN_AVX2 1+#include <crypton_cpu.h>+#include <immintrin.h>++/* The same scan four limbs at a time. The sixteen masks are worked out+ * once; after that each register of the answer is one pass over the table's+ * column, reading every entry exactly as the scalar form does. */+__attribute__((target("avx2")))+static void scan_table_avx2(limb_t *sel, const limb_t *table, uint32_t n,+ limb_t w)+{+ __m256i masks[TABLE_SIZE];+ uint32_t k, l;++ for (k = 0; k < TABLE_SIZE; k++)+ masks[k] = _mm256_cmpeq_epi64(+ _mm256_set1_epi64x((long long) k),+ _mm256_set1_epi64x((long long) w));++ for (l = 0; l + 4 <= n; l += 4) {+ __m256i acc = _mm256_setzero_si256();++ for (k = 0; k < TABLE_SIZE; k++) {+ __m256i v = _mm256_loadu_si256(+ (const __m256i *) (table + k * n + l));++ acc = _mm256_or_si256(acc,+ _mm256_and_si256(v, masks[k]));+ }+ _mm256_storeu_si256((__m256i *) (sel + l), acc);+ }++ /* a modulus whose limbs do not come in fours ends here */+ for (; l < n; l++) {+ limb_t v = 0;++ for (k = 0; k < TABLE_SIZE; k++)+ v |= table[k * n + l] & eq_mask(k, w);+ sel[l] = v;+ }+}+#endif++/* Modular exponentiation for an exponent that is not a secret.+ *+ * RSA verification raises a signature to the public exponent, which is in+ * the public key and is usually 65537. crypton_powm_sec below hides the+ * exponent and pays for it twice: a table of sixteen powers built before the+ * walk begins, and every entry of that table read at every window. For a+ * seventeen-bit exponent the table alone costs more than the exponentiation.+ *+ * So this one reads the exponent's bits and branches on them, squaring at+ * every step and multiplying where a bit is set. It is for public exponents+ * only, and nothing in this library may call it with a secret.+ *+ * It declines -- returning 1 without touching out -- in three cases, so a+ * caller must have something to fall back to.+ *+ * The first is a long exponent. Walking it a bit at a time costs about one+ * and a half multiplications per bit where a windowed walk costs a quarter+ * less, and the table that buys the difference pays for itself after some+ * sixty-odd bits. Past that the caller's own exponentiation is the better+ * algorithm and this one would have to grow a table to compete, which is+ * the thing it exists not to have. RSA public exponents are seventeen+ * bits; the bound is set well above them and well below where a Diffie-+ * Hellman or DSA exponent starts.+ *+ * The second and third are a machine and a size where GMP, which the+ * caller has, was measured the faster; see powm_pub_wanted.+ *+ * Define CRYPTON_POWM_PUB_ALWAYS to make it accept anyway: the differential+ * test builds that way, so that this arithmetic is exercised on the+ * machines the assembly never reaches.+ */+#define POWM_PUB_MAX_EXP_BYTES 8++/* Which sizes this is worth taking at is not which sizes the assembly runs+ * at. Against GMP, which is what the caller has, on an EPYC 7763 with ADX+ * on both sides: ahead at 2048 bits, and behind everywhere else measured --+ * slightly at 1024, by more at 1536, and by more again at 3072 and 4096,+ * which is the size where GMP's own setup and multiplication are the better+ * pair. So 2048 alone, which is RSA-2048's modulus and the size nearly+ * every RSA public key has. It once took every size the assembly ran at,+ * on the strength of 2048 alone, and was slower than GMP at 1024. */+static int powm_pub_wanted(uint32_t n)+{+#if defined(CRYPTON_POWM_PUB_ALWAYS)+ return n > 0;+#elif defined(CRYPTON_POWM_S2N)+ return n == 32 && powm_s2n_usable(n);+#elif defined(CRYPTON_MONT_FIXED)+ /* AArch64: the generated code is ahead of GMP at 2048 bits. At the+ * other RSA sizes Linux's GMP is level with the C or ahead of it. The+ * GMP GHC builds into itself on macOS is compiled without -O, and is+ * behind the C from 1024 to 4096 bits on the same M4 */+#if defined(__APPLE__)+ return n >= 16 && n <= 64;+#else+ return n == 32;+#endif+#else+ (void) n;+ return 0;+#endif+}++int crypton_powm_window_bits(void)+{+ return WINDOW_BITS;+}++int crypton_powm_pub(uint8_t *out,+ const uint8_t *base, uint32_t baselen,+ const uint8_t *exp, uint32_t explen,+ const uint8_t *mod, uint32_t modlen)+{+ return crypton_powm_pub_r2(out, base, baselen, exp, explen, mod, modlen, NULL);+}++int crypton_powm_r2(uint8_t *out, const uint8_t *mod, uint32_t modlen)+{+ uint32_t n = (modlen + LIMB_BYTES - 1) / LIMB_BYTES;+ limb_t *space, *m, *r2, *t;++ if (modlen == 0 || n == 0 || (mod[modlen - 1] & 1) == 0 || !powm_pub_wanted(n))+ return 1;+ space = calloc(5 * n, sizeof(limb_t));+ if (space == NULL)+ return 1;+ m = space;+ r2 = m + n;+ t = r2 + n;+ if (from_be(m, n, mod, modlen) != 0) {+ free(space);+ return 1;+ }+ mont_r2(r2, m, mont_n0(m[0]), n, t);+ to_be(out, modlen, r2, n);+ free(space);+ return 0;+}++int crypton_powm_pub_r2(uint8_t *out,+ const uint8_t *base, uint32_t baselen,+ const uint8_t *exp, uint32_t explen,+ const uint8_t *mod, uint32_t modlen,+ const uint8_t *r2be)+{+ uint32_t n = (modlen + LIMB_BYTES - 1) / LIMB_BYTES;+ uint32_t words = (6 + 2) * n + powm_s2n_scratch(n);+ limb_t *space, *m, *r2, *acc, *tmp, *bm, *one, *t, *scratch, n0;+ uint32_t top, i;+ int s2n = 0;++ if (modlen == 0 || n == 0 || (mod[modlen - 1] & 1) == 0)+ return 1;+ if (explen > POWM_PUB_MAX_EXP_BYTES)+ return 1;+ if (!powm_pub_wanted(n))+ return 1;+#ifdef CRYPTON_POWM_S2N+ s2n = powm_s2n_usable(n);+#endif++ /* the exponent's top set bit, counted from the bottom. An exponent of+ * zero is left to the caller, whose answer for it is already right. */+ top = explen * 8;+ while (top > 0 &&+ ((exp[explen - 1 - (top - 1) / 8] >> ((top - 1) % 8)) & 1) == 0)+ top--;+ if (top == 0)+ return 1;++ space = calloc(words, sizeof(limb_t));+ if (space == NULL)+ return 1;+ m = space;+ r2 = m + n;+ acc = r2 + n;+ tmp = acc + n;+ bm = tmp + n;+ one = bm + n;+ t = one + n;+ scratch = t + 2 * n;++ if (from_be(m, n, mod, modlen) != 0)+ goto fail;+ n0 = mont_n0(m[0]);+ if (r2be == NULL)+ mont_r2(r2, m, n0, n, t);+ else if (from_be(r2, n, r2be, modlen) != 0)+ goto fail;++ /* the base into Montgomery form. The accumulator starts there rather+ * than at one, because the exponent's top bit is a one by+ * construction and the first squaring would be of one. */+ if (from_be(tmp, n, base, baselen) != 0)+ goto fail;+ powm_mul(bm, tmp, r2, m, n0, n, t, scratch, s2n);+ memcpy(acc, bm, n * sizeof(limb_t));++ for (i = top - 1; i > 0; i--) {+ limb_t *swap;++ powm_sqr(tmp, acc, m, n0, n, t, scratch, s2n);+ swap = acc; acc = tmp; tmp = swap;+ if ((exp[explen - 1 - (i - 1) / 8] >> ((i - 1) % 8)) & 1) {+ powm_mul(tmp, acc, bm, m, n0, n, t, scratch, s2n);+ swap = acc; acc = tmp; tmp = swap;+ }+ }++ /* out of Montgomery form */+ one[0] = 1;+ powm_mul(tmp, acc, one, m, n0, n, t, scratch, s2n);+ to_be(out, modlen, tmp, n);++ free(space);+ return 0;++fail:+ free(space);+ return 1;+}+ int crypton_powm_sec(uint8_t *out, const uint8_t *base, uint32_t baselen, const uint8_t *exp, uint32_t explen, const uint8_t *mod, uint32_t modlen) { uint32_t n = (modlen + LIMB_BYTES - 1) / LIMB_BYTES;- uint32_t words = (TABLE_SIZE + 7) * n;- limb_t *space, *m, *r2, *acc, *sel, *prod, *table, *t, n0;+ uint32_t words = (TABLE_SIZE + 7) * n + powm_s2n_scratch(n);+ limb_t *space, *m, *r2, *acc, *sel, *prod, *table, *t, *scratch, n0; uint32_t i, j, k;+ int s2n = 0;+#ifdef CRYPTON_POWM_SCAN_AVX2+ int avx2 = (crypton_x86_simd_features() & CRYPTON_X86_AVX2) != 0;+#endif if (modlen == 0 || n == 0 || (mod[modlen - 1] & 1) == 0) return 1;@@ -50,62 +565,78 @@ prod = sel + n; t = prod + n; table = t + 2 * n;+ scratch = table + TABLE_SIZE * n; +#ifdef CRYPTON_POWM_S2N+ s2n = powm_s2n_usable(n);+#endif+ if (from_be(m, n, mod, modlen) != 0) goto fail;- mont_r2(r2, m, n, t); n0 = mont_n0(m[0]);+ mont_r2(r2, m, n0, n, t); /* table[k] = base^k in Montgomery form, and table[0] = 1 there */ memset(table, 0, n * sizeof(limb_t)); table[0] = 1;- mont_mul(acc, table, r2, m, n0, n, t);+ powm_mul(acc, table, r2, m, n0, n, t, scratch, s2n); memcpy(table, acc, n * sizeof(limb_t)); if (from_be(sel, n, base, baselen) != 0) goto fail;- mont_mul(table + n, sel, r2, m, n0, n, t);+ powm_mul(table + n, sel, r2, m, n0, n, t, scratch, s2n); for (k = 2; k < TABLE_SIZE; k++)- mont_mul(table + k * n, table + (k - 1) * n, table + n, m, n0, n, t);+ powm_mul(table + k * n, table + (k - 1) * n, table + n, m, n0, n,+ t, scratch, s2n); memcpy(acc, table, n * sizeof(limb_t)); - for (i = explen * 2; i > 0; i--) {- uint32_t nib = i - 1;- limb_t w = (exp[explen - 1 - nib / 2] >> (4 * (nib % 2))) & 0xf;+ for (i = (explen * 8 + WINDOW_BITS - 1) / WINDOW_BITS; i > 0; i--) {+ limb_t w = exp_window(exp, explen, i - 1); + /* squaring into the other buffer and swapping the two saves a+ * copy of the modulus' width every time; which of the three+ * buffers a pointer names is nobody's secret */ for (j = 0; j < WINDOW_BITS; j++) {- mont_sqr(sel, acc, m, n0, n, t);- memcpy(acc, sel, n * sizeof(limb_t));+ limb_t *swap;++ powm_sqr(sel, acc, m, n0, n, t, scratch, s2n);+ swap = acc;+ acc = sel;+ sel = swap; } - /* every entry is read, and a mask keeps the one wanted */- memset(sel, 0, n * sizeof(limb_t));- for (k = 0; k < TABLE_SIZE; k++) {- limb_t mask = eq_mask(k, w);- uint32_t l;+#ifdef CRYPTON_POWM_SCAN_AVX2+ if (avx2)+ scan_table_avx2(sel, table, n, w);+ else+#endif+ scan_table(sel, table, n, w);+ powm_mul(prod, acc, sel, m, n0, n, t, scratch, s2n);+ {+ limb_t *swap = acc; - for (l = 0; l < n; l++)- sel[l] |= table[k * n + l] & mask;+ acc = prod;+ prod = swap; }- mont_mul(prod, acc, sel, m, n0, n, t);- memcpy(acc, prod, n * sizeof(limb_t)); } /* out of Montgomery form */ memset(sel, 0, n * sizeof(limb_t)); sel[0] = 1;- mont_mul(prod, acc, sel, m, n0, n, t);+ powm_mul(prod, acc, sel, m, n0, n, t, scratch, s2n); to_be(out, modlen, prod, n); /* nothing here is the caller's secret, but the exponent's bits passed- * through the accumulators */- memset(space, 0, words * sizeof(limb_t));+ * through the accumulators. crypton_bzero rather than memset, since+ * this memory is freed on the next line and a store to memory about to+ * die is one an optimizer may drop. */+ crypton_bzero(space, words * sizeof(limb_t)); free(space); return 0; fail:- memset(space, 0, words * sizeof(limb_t));+ crypton_bzero(space, words * sizeof(limb_t)); free(space); return 1; }
@@ -20,4 +20,53 @@ const uint8_t *exp, uint32_t explen, const uint8_t *mod, uint32_t modlen); +/* The same, for an exponent that is not a secret: it reads the exponent's+ * bits and branches on them. Nothing in this library may call it with a+ * secret exponent.+ *+ * It declines -- returning 1 with out untouched -- whenever it is not the+ * faster of the two things the caller could do: for an exponent of more+ * than eight bytes, where a windowed walk is the better algorithm;+ * everywhere the vendored assembly's Montgomery multiplication does not+ * run; and at every modulus size but 2048 bits, where GMP was measured the+ * faster even with the assembly. So a caller must have something to fall+ * back to.+ */+int crypton_powm_pub(uint8_t *out,+ const uint8_t *base, uint32_t baselen,+ const uint8_t *exp, uint32_t explen,+ const uint8_t *mod, uint32_t modlen);++/* crypton_powm_pub with R^2 mod m given, big-endian in modlen bytes, as+ * crypton_powm_r2 computes it; NULL computes it here as crypton_powm_pub does.+ * A caller verifying under one key many times keeps it. */+int crypton_powm_pub_r2(uint8_t *out,+ const uint8_t *base, uint32_t baselen,+ const uint8_t *exp, uint32_t explen,+ const uint8_t *mod, uint32_t modlen,+ const uint8_t *r2be);++/* R^2 mod m for crypton_powm_pub_r2, or nonzero where crypton_powm_pub would+ * decline this modulus, so that nothing is kept for it. */+int crypton_powm_r2(uint8_t *out, const uint8_t *mod, uint32_t modlen);++/* Two secure exponentiations at once, as the halves of an RSA private-key+ * operation by CRT are: each as crypton_powm_sec, with the same contract.+ *+ * Only on x86-64 with AVX-512 IFMA, for two moduli of 128, 192 or 256 bytes+ * and two exponents of the same length. It declines everywhere else --+ * returning nonzero with both outputs untouched -- so a caller must have+ * crypton_powm_sec to fall back to. */+int crypton_powm_sec_x2(uint8_t *out1, const uint8_t *base1, uint32_t baselen1,+ const uint8_t *exp1, uint32_t explen1,+ const uint8_t *mod1, uint32_t modlen1,+ uint8_t *out2, const uint8_t *base2, uint32_t baselen2,+ const uint8_t *exp2, uint32_t explen2,+ const uint8_t *mod2, uint32_t modlen2);++/* The window the secure exponentiation walks the exponent in, so that a+ * build which did not take -DPOWM_WINDOW_BITS cannot pass for one that+ * did. */+int crypton_powm_window_bits(void);+ #endif
@@ -0,0 +1,187 @@+/* Two secure exponentiations at once with AVX-512 IFMA, the CRT halves of+ * RSA-2048, -3072 and -4096: crypton_powm_sec's walk with a five-bit window,+ * over the multiplication generated by cbits/crypton_powm_ifma.py. */+#include <stdlib.h>+#include <string.h>+#include <crypton_bignum.h>+#include <crypton_bzero.h>+#include <crypton_powm.h>++#if defined(__x86_64__) && (defined(__GNUC__) || defined(__clang__))+#include <crypton_cpu.h>+#include "crypton_powm_ifma.h"++#define WIN 5++typedef void (*amm_fn)(uint64_t *, const uint64_t *, const uint64_t *, const uint64_t *,+ uint64_t, uint64_t *, const uint64_t *, const uint64_t *,+ const uint64_t *, uint64_t);+typedef void (*sel_fn)(uint64_t *, const uint64_t *, uint64_t, uint64_t *,+ const uint64_t *, uint64_t);++/* limbs of 64 bits to digits of 52, d of them; the rest of the w words zero */+static void to_digits(uint64_t *dg, uint32_t w, const limb_t *l, uint32_t n, uint32_t d)+{+ uint32_t i;++ memset(dg, 0, w * sizeof(uint64_t));+ for (i = 0; i < d; i++) {+ uint32_t bit = 52 * i, li = bit / 64, sh = bit % 64;+ uint64_t v = li < n ? l[li] >> sh : 0;++ if (sh > 12 && li + 1 < n)+ v |= l[li + 1] << (64 - sh);+ dg[i] = v & IFMA_MASK52;+ }+}++static void from_digits(limb_t *l, uint32_t n, const uint64_t *dg, uint32_t d)+{+ uint32_t i;++ memset(l, 0, n * sizeof(limb_t));+ for (i = 0; i < d; i++) {+ uint32_t bit = 52 * i, li = bit / 64, sh = bit % 64;++ if (li < n)+ l[li] |= dg[i] << sh;+ if (sh > 12 && li + 1 < n)+ l[li + 1] |= dg[i] >> (64 - sh);+ }+}++/* Window k from the bottom of a big-endian exponent of len bytes. Which+ * window is read is the loop counter's business, not the exponent's. */+static uint64_t window(const uint8_t *e, uint32_t len, uint32_t k)+{+ uint64_t v = 0;+ uint32_t j;++ for (j = 0; j < WIN; j++) {+ uint32_t bit = k * WIN + j;++ if (bit < 8 * len)+ v |= (uint64_t) ((e[len - 1 - bit / 8] >> (bit % 8)) & 1) << j;+ }+ return v;+}++/* m and k0 in digits, and R^2 mod m for R = 2^(52d): crypton's R^2 is for+ * 2^(64n), so it is doubled the rest of the way */+static int setup(const uint8_t *mod, uint32_t modlen, uint32_t n, uint32_t d, uint32_t w,+ limb_t *ml, uint64_t *md, uint64_t *rr, uint64_t *k0, limb_t *t)+{+ limb_t *r2 = t + 4 * n;+ uint32_t j;++ if (from_be(ml, n, mod, modlen) != 0 || (ml[0] & 1) == 0)+ return 1;+ *k0 = mont_n0(ml[0]);+ mont_r2(r2, ml, *k0, n, t);+ for (j = 0; j < 2 * (52 * d - 64 * n); j++)+ dbl_mod(r2, ml, n, t);+ to_digits(md, w, ml, n, d);+ to_digits(rr, w, r2, n, d);+ return 0;+}++int crypton_powm_sec_x2(uint8_t *out1, const uint8_t *base1, uint32_t baselen1,+ const uint8_t *exp1, uint32_t explen1,+ const uint8_t *mod1, uint32_t modlen1,+ uint8_t *out2, const uint8_t *base2, uint32_t baselen2,+ const uint8_t *exp2, uint32_t explen2,+ const uint8_t *mod2, uint32_t modlen2)+{+ uint32_t n, d, w, nwin, k, j;+ amm_fn amm;+ sel_fn sel;+ uint64_t *space, *m1, *m2, *rr1, *rr2, *x1, *x2, *s1, *s2, *one, *t1, *t2, k1, k2;+ limb_t *l1, *l2, *lt, *lt2;+ size_t words;++ if (modlen1 != modlen2 || explen1 != explen2)+ return 1;+ if ((crypton_x86_simd_features() & CRYPTON_X86_IFMA) == 0)+ return 1;+ switch (modlen1) {+ case 128: d = 20; amm = ifma_amm20_x2; sel = ifma_sel5; break;+ case 192: d = 30; amm = ifma_amm30_x2; sel = ifma_sel8; break;+ case 256: d = 40; amm = ifma_amm40_x2; sel = ifma_sel10; break;+ default: return 1;+ }+ n = modlen1 / 8;+ w = 4 * ((d + 3) / 4);++ /* nine numbers in digits, two tables of 32, and limbs for the setup */+ words = (size_t) w * (9 + 2 * 32) + (size_t) n * 12;+ space = calloc(words, sizeof(uint64_t));+ if (space == NULL)+ return 1;+ m1 = space; m2 = m1 + w; rr1 = m2 + w; rr2 = rr1 + w;+ x1 = rr2 + w; x2 = x1 + w; s1 = x2 + w; s2 = s1 + w; one = s2 + w;+ t1 = one + w; t2 = t1 + 32 * w;+ l1 = (limb_t *)(t2 + 32 * w); l2 = l1 + n; lt = l2 + n; lt2 = lt + n;++ if (setup(mod1, modlen1, n, d, w, l1, m1, rr1, &k1, lt) != 0+ || setup(mod2, modlen2, n, d, w, l2, m2, rr2, &k2, lt) != 0)+ goto fail;++ /* the bases, under their moduli as the contract says, into digits */+ if (from_be(lt, n, base1, baselen1) != 0 || from_be(lt2, n, base2, baselen2) != 0)+ goto fail;+ to_digits(s1, w, lt, n, d);+ to_digits(s2, w, lt2, n, d);++ /* table[0] = R and table[1] = b R in Montgomery form, table[k] = b^k R */+ one[0] = 1;+ amm(t1, one, rr1, m1, k1, t2, one, rr2, m2, k2);+ amm(t1 + w, s1, rr1, m1, k1, t2 + w, s2, rr2, m2, k2);+ for (k = 2; k < 32; k++)+ amm(t1 + k * w, t1 + (k - 1) * w, t1 + w, m1, k1,+ t2 + k * w, t2 + (k - 1) * w, t2 + w, m2, k2);++ memcpy(x1, t1, w * sizeof(uint64_t));+ memcpy(x2, t2, w * sizeof(uint64_t));+ nwin = (8 * explen1 + WIN - 1) / WIN;+ for (k = nwin; k > 0; k--) {+ for (j = 0; j < WIN; j++)+ amm(x1, x1, x1, m1, k1, x2, x2, x2, m2, k2);+ sel(s1, t1, window(exp1, explen1, k - 1), s2, t2, window(exp2, explen2, k - 1));+ amm(x1, x1, s1, m1, k1, x2, x2, s2, m2, k2);+ }++ /* out of Montgomery form, then under m with one masked subtraction */+ amm(x1, x1, one, m1, k1, x2, x2, one, m2, k2);+ from_digits(lt, n, x1, d);+ select_n(lt, lt2, lt, sub_n(lt2, lt, l1, n) ^ 1, n);+ to_be(out1, modlen1, lt, n);+ from_digits(lt, n, x2, d);+ select_n(lt, lt2, lt, sub_n(lt2, lt, l2, n) ^ 1, n);+ to_be(out2, modlen2, lt, n);++ crypton_bzero(space, words * sizeof(uint64_t));+ free(space);+ return 0;++fail:+ crypton_bzero(space, words * sizeof(uint64_t));+ free(space);+ return 1;+}++#else++int crypton_powm_sec_x2(uint8_t *out1, const uint8_t *base1, uint32_t baselen1,+ const uint8_t *exp1, uint32_t explen1,+ const uint8_t *mod1, uint32_t modlen1,+ uint8_t *out2, const uint8_t *base2, uint32_t baselen2,+ const uint8_t *exp2, uint32_t explen2,+ const uint8_t *mod2, uint32_t modlen2)+{+ (void) out1; (void) base1; (void) baselen1; (void) exp1; (void) explen1;+ (void) mod1; (void) modlen1; (void) out2; (void) base2; (void) baselen2;+ (void) exp2; (void) explen2; (void) mod2; (void) modlen2;+ return 1;+}++#endif
@@ -0,0 +1,513 @@+/* Generated by cbits/crypton_powm_ifma.py; do not edit.+ *+ * Almost-Montgomery multiplication in radix 2^52, two at once: r = a b+ * 2^-52D mod m, under 2m for a and b under 2m. Digits are 52 bits in 64-bit+ * words, each number padded with zero words to a whole number of 256-bit+ * registers. m is read from memory; at 20 digits a is held in registers,+ * above that it is read from memory too. */+#ifndef CRYPTON_POWM_IFMA_H+#define CRYPTON_POWM_IFMA_H++#include <stdint.h>+#include <immintrin.h>++#define IFMA_MASK52 ((UINT64_C(1) << 52) - 1)+#define IFMA_TARGET __attribute__((target("avx2,avx512f,avx512vl,avx512ifma")))++/* 20 lanes to 52-bit digits: what is above 52 bits moves up a lane,+ * and the one-bit carries that can then remain are resolved together */+IFMA_TARGET static inline void ifma_norm5(uint64_t *r, __m256i X0, __m256i X1, __m256i X2, __m256i X3, __m256i X4)+{+ const __m256i mk = _mm256_set1_epi64x((long long) IFMA_MASK52), one = _mm256_set1_epi64x(1);+ const __m256i zero = _mm256_setzero_si256();+ uint64_t g = 0, p = 0, c;+ __m256i C0 = _mm256_srli_epi64(X0, 52);+ __m256i C1 = _mm256_srli_epi64(X1, 52);+ __m256i C2 = _mm256_srli_epi64(X2, 52);+ __m256i C3 = _mm256_srli_epi64(X3, 52);+ __m256i C4 = _mm256_srli_epi64(X4, 52);+ X0 = _mm256_add_epi64(_mm256_and_si256(X0, mk), _mm256_alignr_epi64(C0, zero, 3));+ X1 = _mm256_add_epi64(_mm256_and_si256(X1, mk), _mm256_alignr_epi64(C1, C0, 3));+ X2 = _mm256_add_epi64(_mm256_and_si256(X2, mk), _mm256_alignr_epi64(C2, C1, 3));+ X3 = _mm256_add_epi64(_mm256_and_si256(X3, mk), _mm256_alignr_epi64(C3, C2, 3));+ X4 = _mm256_add_epi64(_mm256_and_si256(X4, mk), _mm256_alignr_epi64(C4, C3, 3));+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X0, mk) << 0;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X0, mk) << 0;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X1, mk) << 4;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X1, mk) << 4;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X2, mk) << 8;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X2, mk) << 8;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X3, mk) << 12;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X3, mk) << 12;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X4, mk) << 16;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X4, mk) << 16;+ c = ((g << 1) + p) ^ p;+ X0 = _mm256_and_si256(_mm256_mask_add_epi64(X0, (__mmask8)(c >> 0 & 15), X0, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 0), X0);+ X1 = _mm256_and_si256(_mm256_mask_add_epi64(X1, (__mmask8)(c >> 4 & 15), X1, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 4), X1);+ X2 = _mm256_and_si256(_mm256_mask_add_epi64(X2, (__mmask8)(c >> 8 & 15), X2, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 8), X2);+ X3 = _mm256_and_si256(_mm256_mask_add_epi64(X3, (__mmask8)(c >> 12 & 15), X3, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 12), X3);+ X4 = _mm256_and_si256(_mm256_mask_add_epi64(X4, (__mmask8)(c >> 16 & 15), X4, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 16), X4);+}++/* both tables' entries k1 and k2 of 32, every entry read and a mask keeping+ * one; entries are 20 words apart */+IFMA_TARGET static void ifma_sel5(uint64_t *o1, const uint64_t *t1, uint64_t k1,+ uint64_t *o2, const uint64_t *t2, uint64_t k2)+{+ const __m256i one = _mm256_set1_epi64x(1);+ __m256i v1 = _mm256_set1_epi64x((long long) k1), v2 = _mm256_set1_epi64x((long long) k2);+ __m256i kv = _mm256_setzero_si256();+ __m256i P0 = kv, Q0 = kv, P1 = kv, Q1 = kv, P2 = kv, Q2 = kv, P3 = kv, Q3 = kv, P4 = kv, Q4 = kv;+ int k;+ for (k = 0; k < 32; k++) {+ __mmask8 s1 = _mm256_cmpeq_epi64_mask(v1, kv), s2 = _mm256_cmpeq_epi64_mask(v2, kv);+ const uint64_t *e1 = t1 + 20 * k, *e2 = t2 + 20 * k;+ P0 = _mm256_mask_loadu_epi64(P0, s1, e1 + 0); Q0 = _mm256_mask_loadu_epi64(Q0, s2, e2 + 0);+ P1 = _mm256_mask_loadu_epi64(P1, s1, e1 + 4); Q1 = _mm256_mask_loadu_epi64(Q1, s2, e2 + 4);+ P2 = _mm256_mask_loadu_epi64(P2, s1, e1 + 8); Q2 = _mm256_mask_loadu_epi64(Q2, s2, e2 + 8);+ P3 = _mm256_mask_loadu_epi64(P3, s1, e1 + 12); Q3 = _mm256_mask_loadu_epi64(Q3, s2, e2 + 12);+ P4 = _mm256_mask_loadu_epi64(P4, s1, e1 + 16); Q4 = _mm256_mask_loadu_epi64(Q4, s2, e2 + 16);+ kv = _mm256_add_epi64(kv, one);+ }+ _mm256_storeu_si256((__m256i *)(o1 + 0), P0); _mm256_storeu_si256((__m256i *)(o2 + 0), Q0);+ _mm256_storeu_si256((__m256i *)(o1 + 4), P1); _mm256_storeu_si256((__m256i *)(o2 + 4), Q1);+ _mm256_storeu_si256((__m256i *)(o1 + 8), P2); _mm256_storeu_si256((__m256i *)(o2 + 8), Q2);+ _mm256_storeu_si256((__m256i *)(o1 + 12), P3); _mm256_storeu_si256((__m256i *)(o2 + 12), Q3);+ _mm256_storeu_si256((__m256i *)(o1 + 16), P4); _mm256_storeu_si256((__m256i *)(o2 + 16), Q4);+}++/* 32 lanes to 52-bit digits: what is above 52 bits moves up a lane,+ * and the one-bit carries that can then remain are resolved together */+IFMA_TARGET static inline void ifma_norm8(uint64_t *r, __m256i X0, __m256i X1, __m256i X2, __m256i X3, __m256i X4, __m256i X5, __m256i X6, __m256i X7)+{+ const __m256i mk = _mm256_set1_epi64x((long long) IFMA_MASK52), one = _mm256_set1_epi64x(1);+ const __m256i zero = _mm256_setzero_si256();+ uint64_t g = 0, p = 0, c;+ __m256i C0 = _mm256_srli_epi64(X0, 52);+ __m256i C1 = _mm256_srli_epi64(X1, 52);+ __m256i C2 = _mm256_srli_epi64(X2, 52);+ __m256i C3 = _mm256_srli_epi64(X3, 52);+ __m256i C4 = _mm256_srli_epi64(X4, 52);+ __m256i C5 = _mm256_srli_epi64(X5, 52);+ __m256i C6 = _mm256_srli_epi64(X6, 52);+ __m256i C7 = _mm256_srli_epi64(X7, 52);+ X0 = _mm256_add_epi64(_mm256_and_si256(X0, mk), _mm256_alignr_epi64(C0, zero, 3));+ X1 = _mm256_add_epi64(_mm256_and_si256(X1, mk), _mm256_alignr_epi64(C1, C0, 3));+ X2 = _mm256_add_epi64(_mm256_and_si256(X2, mk), _mm256_alignr_epi64(C2, C1, 3));+ X3 = _mm256_add_epi64(_mm256_and_si256(X3, mk), _mm256_alignr_epi64(C3, C2, 3));+ X4 = _mm256_add_epi64(_mm256_and_si256(X4, mk), _mm256_alignr_epi64(C4, C3, 3));+ X5 = _mm256_add_epi64(_mm256_and_si256(X5, mk), _mm256_alignr_epi64(C5, C4, 3));+ X6 = _mm256_add_epi64(_mm256_and_si256(X6, mk), _mm256_alignr_epi64(C6, C5, 3));+ X7 = _mm256_add_epi64(_mm256_and_si256(X7, mk), _mm256_alignr_epi64(C7, C6, 3));+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X0, mk) << 0;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X0, mk) << 0;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X1, mk) << 4;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X1, mk) << 4;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X2, mk) << 8;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X2, mk) << 8;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X3, mk) << 12;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X3, mk) << 12;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X4, mk) << 16;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X4, mk) << 16;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X5, mk) << 20;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X5, mk) << 20;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X6, mk) << 24;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X6, mk) << 24;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X7, mk) << 28;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X7, mk) << 28;+ c = ((g << 1) + p) ^ p;+ X0 = _mm256_and_si256(_mm256_mask_add_epi64(X0, (__mmask8)(c >> 0 & 15), X0, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 0), X0);+ X1 = _mm256_and_si256(_mm256_mask_add_epi64(X1, (__mmask8)(c >> 4 & 15), X1, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 4), X1);+ X2 = _mm256_and_si256(_mm256_mask_add_epi64(X2, (__mmask8)(c >> 8 & 15), X2, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 8), X2);+ X3 = _mm256_and_si256(_mm256_mask_add_epi64(X3, (__mmask8)(c >> 12 & 15), X3, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 12), X3);+ X4 = _mm256_and_si256(_mm256_mask_add_epi64(X4, (__mmask8)(c >> 16 & 15), X4, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 16), X4);+ X5 = _mm256_and_si256(_mm256_mask_add_epi64(X5, (__mmask8)(c >> 20 & 15), X5, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 20), X5);+ X6 = _mm256_and_si256(_mm256_mask_add_epi64(X6, (__mmask8)(c >> 24 & 15), X6, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 24), X6);+ X7 = _mm256_and_si256(_mm256_mask_add_epi64(X7, (__mmask8)(c >> 28 & 15), X7, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 28), X7);+}++/* both tables' entries k1 and k2 of 32, every entry read and a mask keeping+ * one; entries are 32 words apart */+IFMA_TARGET static void ifma_sel8(uint64_t *o1, const uint64_t *t1, uint64_t k1,+ uint64_t *o2, const uint64_t *t2, uint64_t k2)+{+ const __m256i one = _mm256_set1_epi64x(1);+ __m256i v1 = _mm256_set1_epi64x((long long) k1), v2 = _mm256_set1_epi64x((long long) k2);+ __m256i kv = _mm256_setzero_si256();+ __m256i P0 = kv, Q0 = kv, P1 = kv, Q1 = kv, P2 = kv, Q2 = kv, P3 = kv, Q3 = kv, P4 = kv, Q4 = kv, P5 = kv, Q5 = kv, P6 = kv, Q6 = kv, P7 = kv, Q7 = kv;+ int k;+ for (k = 0; k < 32; k++) {+ __mmask8 s1 = _mm256_cmpeq_epi64_mask(v1, kv), s2 = _mm256_cmpeq_epi64_mask(v2, kv);+ const uint64_t *e1 = t1 + 32 * k, *e2 = t2 + 32 * k;+ P0 = _mm256_mask_loadu_epi64(P0, s1, e1 + 0); Q0 = _mm256_mask_loadu_epi64(Q0, s2, e2 + 0);+ P1 = _mm256_mask_loadu_epi64(P1, s1, e1 + 4); Q1 = _mm256_mask_loadu_epi64(Q1, s2, e2 + 4);+ P2 = _mm256_mask_loadu_epi64(P2, s1, e1 + 8); Q2 = _mm256_mask_loadu_epi64(Q2, s2, e2 + 8);+ P3 = _mm256_mask_loadu_epi64(P3, s1, e1 + 12); Q3 = _mm256_mask_loadu_epi64(Q3, s2, e2 + 12);+ P4 = _mm256_mask_loadu_epi64(P4, s1, e1 + 16); Q4 = _mm256_mask_loadu_epi64(Q4, s2, e2 + 16);+ P5 = _mm256_mask_loadu_epi64(P5, s1, e1 + 20); Q5 = _mm256_mask_loadu_epi64(Q5, s2, e2 + 20);+ P6 = _mm256_mask_loadu_epi64(P6, s1, e1 + 24); Q6 = _mm256_mask_loadu_epi64(Q6, s2, e2 + 24);+ P7 = _mm256_mask_loadu_epi64(P7, s1, e1 + 28); Q7 = _mm256_mask_loadu_epi64(Q7, s2, e2 + 28);+ kv = _mm256_add_epi64(kv, one);+ }+ _mm256_storeu_si256((__m256i *)(o1 + 0), P0); _mm256_storeu_si256((__m256i *)(o2 + 0), Q0);+ _mm256_storeu_si256((__m256i *)(o1 + 4), P1); _mm256_storeu_si256((__m256i *)(o2 + 4), Q1);+ _mm256_storeu_si256((__m256i *)(o1 + 8), P2); _mm256_storeu_si256((__m256i *)(o2 + 8), Q2);+ _mm256_storeu_si256((__m256i *)(o1 + 12), P3); _mm256_storeu_si256((__m256i *)(o2 + 12), Q3);+ _mm256_storeu_si256((__m256i *)(o1 + 16), P4); _mm256_storeu_si256((__m256i *)(o2 + 16), Q4);+ _mm256_storeu_si256((__m256i *)(o1 + 20), P5); _mm256_storeu_si256((__m256i *)(o2 + 20), Q5);+ _mm256_storeu_si256((__m256i *)(o1 + 24), P6); _mm256_storeu_si256((__m256i *)(o2 + 24), Q6);+ _mm256_storeu_si256((__m256i *)(o1 + 28), P7); _mm256_storeu_si256((__m256i *)(o2 + 28), Q7);+}++/* 40 lanes to 52-bit digits: what is above 52 bits moves up a lane,+ * and the one-bit carries that can then remain are resolved together */+IFMA_TARGET static inline void ifma_norm10(uint64_t *r, __m256i X0, __m256i X1, __m256i X2, __m256i X3, __m256i X4, __m256i X5, __m256i X6, __m256i X7, __m256i X8, __m256i X9)+{+ const __m256i mk = _mm256_set1_epi64x((long long) IFMA_MASK52), one = _mm256_set1_epi64x(1);+ const __m256i zero = _mm256_setzero_si256();+ uint64_t g = 0, p = 0, c;+ __m256i C0 = _mm256_srli_epi64(X0, 52);+ __m256i C1 = _mm256_srli_epi64(X1, 52);+ __m256i C2 = _mm256_srli_epi64(X2, 52);+ __m256i C3 = _mm256_srli_epi64(X3, 52);+ __m256i C4 = _mm256_srli_epi64(X4, 52);+ __m256i C5 = _mm256_srli_epi64(X5, 52);+ __m256i C6 = _mm256_srli_epi64(X6, 52);+ __m256i C7 = _mm256_srli_epi64(X7, 52);+ __m256i C8 = _mm256_srli_epi64(X8, 52);+ __m256i C9 = _mm256_srli_epi64(X9, 52);+ X0 = _mm256_add_epi64(_mm256_and_si256(X0, mk), _mm256_alignr_epi64(C0, zero, 3));+ X1 = _mm256_add_epi64(_mm256_and_si256(X1, mk), _mm256_alignr_epi64(C1, C0, 3));+ X2 = _mm256_add_epi64(_mm256_and_si256(X2, mk), _mm256_alignr_epi64(C2, C1, 3));+ X3 = _mm256_add_epi64(_mm256_and_si256(X3, mk), _mm256_alignr_epi64(C3, C2, 3));+ X4 = _mm256_add_epi64(_mm256_and_si256(X4, mk), _mm256_alignr_epi64(C4, C3, 3));+ X5 = _mm256_add_epi64(_mm256_and_si256(X5, mk), _mm256_alignr_epi64(C5, C4, 3));+ X6 = _mm256_add_epi64(_mm256_and_si256(X6, mk), _mm256_alignr_epi64(C6, C5, 3));+ X7 = _mm256_add_epi64(_mm256_and_si256(X7, mk), _mm256_alignr_epi64(C7, C6, 3));+ X8 = _mm256_add_epi64(_mm256_and_si256(X8, mk), _mm256_alignr_epi64(C8, C7, 3));+ X9 = _mm256_add_epi64(_mm256_and_si256(X9, mk), _mm256_alignr_epi64(C9, C8, 3));+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X0, mk) << 0;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X0, mk) << 0;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X1, mk) << 4;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X1, mk) << 4;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X2, mk) << 8;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X2, mk) << 8;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X3, mk) << 12;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X3, mk) << 12;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X4, mk) << 16;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X4, mk) << 16;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X5, mk) << 20;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X5, mk) << 20;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X6, mk) << 24;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X6, mk) << 24;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X7, mk) << 28;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X7, mk) << 28;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X8, mk) << 32;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X8, mk) << 32;+ g |= (uint64_t) _mm256_cmpgt_epu64_mask(X9, mk) << 36;+ p |= (uint64_t) _mm256_cmpeq_epu64_mask(X9, mk) << 36;+ c = ((g << 1) + p) ^ p;+ X0 = _mm256_and_si256(_mm256_mask_add_epi64(X0, (__mmask8)(c >> 0 & 15), X0, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 0), X0);+ X1 = _mm256_and_si256(_mm256_mask_add_epi64(X1, (__mmask8)(c >> 4 & 15), X1, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 4), X1);+ X2 = _mm256_and_si256(_mm256_mask_add_epi64(X2, (__mmask8)(c >> 8 & 15), X2, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 8), X2);+ X3 = _mm256_and_si256(_mm256_mask_add_epi64(X3, (__mmask8)(c >> 12 & 15), X3, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 12), X3);+ X4 = _mm256_and_si256(_mm256_mask_add_epi64(X4, (__mmask8)(c >> 16 & 15), X4, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 16), X4);+ X5 = _mm256_and_si256(_mm256_mask_add_epi64(X5, (__mmask8)(c >> 20 & 15), X5, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 20), X5);+ X6 = _mm256_and_si256(_mm256_mask_add_epi64(X6, (__mmask8)(c >> 24 & 15), X6, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 24), X6);+ X7 = _mm256_and_si256(_mm256_mask_add_epi64(X7, (__mmask8)(c >> 28 & 15), X7, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 28), X7);+ X8 = _mm256_and_si256(_mm256_mask_add_epi64(X8, (__mmask8)(c >> 32 & 15), X8, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 32), X8);+ X9 = _mm256_and_si256(_mm256_mask_add_epi64(X9, (__mmask8)(c >> 36 & 15), X9, one), mk);+ _mm256_storeu_si256((__m256i *)(r + 36), X9);+}++/* both tables' entries k1 and k2 of 32, every entry read and a mask keeping+ * one; entries are 40 words apart */+IFMA_TARGET static void ifma_sel10(uint64_t *o1, const uint64_t *t1, uint64_t k1,+ uint64_t *o2, const uint64_t *t2, uint64_t k2)+{+ const __m256i one = _mm256_set1_epi64x(1);+ __m256i v1 = _mm256_set1_epi64x((long long) k1), v2 = _mm256_set1_epi64x((long long) k2);+ __m256i kv = _mm256_setzero_si256();+ __m256i P0 = kv, Q0 = kv, P1 = kv, Q1 = kv, P2 = kv, Q2 = kv, P3 = kv, Q3 = kv, P4 = kv, Q4 = kv, P5 = kv, Q5 = kv, P6 = kv, Q6 = kv, P7 = kv, Q7 = kv, P8 = kv, Q8 = kv, P9 = kv, Q9 = kv;+ int k;+ for (k = 0; k < 32; k++) {+ __mmask8 s1 = _mm256_cmpeq_epi64_mask(v1, kv), s2 = _mm256_cmpeq_epi64_mask(v2, kv);+ const uint64_t *e1 = t1 + 40 * k, *e2 = t2 + 40 * k;+ P0 = _mm256_mask_loadu_epi64(P0, s1, e1 + 0); Q0 = _mm256_mask_loadu_epi64(Q0, s2, e2 + 0);+ P1 = _mm256_mask_loadu_epi64(P1, s1, e1 + 4); Q1 = _mm256_mask_loadu_epi64(Q1, s2, e2 + 4);+ P2 = _mm256_mask_loadu_epi64(P2, s1, e1 + 8); Q2 = _mm256_mask_loadu_epi64(Q2, s2, e2 + 8);+ P3 = _mm256_mask_loadu_epi64(P3, s1, e1 + 12); Q3 = _mm256_mask_loadu_epi64(Q3, s2, e2 + 12);+ P4 = _mm256_mask_loadu_epi64(P4, s1, e1 + 16); Q4 = _mm256_mask_loadu_epi64(Q4, s2, e2 + 16);+ P5 = _mm256_mask_loadu_epi64(P5, s1, e1 + 20); Q5 = _mm256_mask_loadu_epi64(Q5, s2, e2 + 20);+ P6 = _mm256_mask_loadu_epi64(P6, s1, e1 + 24); Q6 = _mm256_mask_loadu_epi64(Q6, s2, e2 + 24);+ P7 = _mm256_mask_loadu_epi64(P7, s1, e1 + 28); Q7 = _mm256_mask_loadu_epi64(Q7, s2, e2 + 28);+ P8 = _mm256_mask_loadu_epi64(P8, s1, e1 + 32); Q8 = _mm256_mask_loadu_epi64(Q8, s2, e2 + 32);+ P9 = _mm256_mask_loadu_epi64(P9, s1, e1 + 36); Q9 = _mm256_mask_loadu_epi64(Q9, s2, e2 + 36);+ kv = _mm256_add_epi64(kv, one);+ }+ _mm256_storeu_si256((__m256i *)(o1 + 0), P0); _mm256_storeu_si256((__m256i *)(o2 + 0), Q0);+ _mm256_storeu_si256((__m256i *)(o1 + 4), P1); _mm256_storeu_si256((__m256i *)(o2 + 4), Q1);+ _mm256_storeu_si256((__m256i *)(o1 + 8), P2); _mm256_storeu_si256((__m256i *)(o2 + 8), Q2);+ _mm256_storeu_si256((__m256i *)(o1 + 12), P3); _mm256_storeu_si256((__m256i *)(o2 + 12), Q3);+ _mm256_storeu_si256((__m256i *)(o1 + 16), P4); _mm256_storeu_si256((__m256i *)(o2 + 16), Q4);+ _mm256_storeu_si256((__m256i *)(o1 + 20), P5); _mm256_storeu_si256((__m256i *)(o2 + 20), Q5);+ _mm256_storeu_si256((__m256i *)(o1 + 24), P6); _mm256_storeu_si256((__m256i *)(o2 + 24), Q6);+ _mm256_storeu_si256((__m256i *)(o1 + 28), P7); _mm256_storeu_si256((__m256i *)(o2 + 28), Q7);+ _mm256_storeu_si256((__m256i *)(o1 + 32), P8); _mm256_storeu_si256((__m256i *)(o2 + 32), Q8);+ _mm256_storeu_si256((__m256i *)(o1 + 36), P9); _mm256_storeu_si256((__m256i *)(o2 + 36), Q9);+}++/* 20 digits, 5 registers a number */+IFMA_TARGET static void ifma_amm20_x2(uint64_t *r1, const uint64_t *a1, const uint64_t *b1,+ const uint64_t *m1, uint64_t k1,+ uint64_t *r2, const uint64_t *a2, const uint64_t *b2,+ const uint64_t *m2, uint64_t k2)+{+ const __m256i zero = _mm256_setzero_si256();+#define L(p, k) _mm256_loadu_si256((const __m256i *)((p) + 4 * (k)))+ __m256i X0 = zero, X1 = zero, X2 = zero, X3 = zero, X4 = zero, Y0 = zero, Y1 = zero, Y2 = zero, Y3 = zero, Y4 = zero;+ __m256i A0 = L(a1, 0), A1 = L(a1, 1), A2 = L(a1, 2), A3 = L(a1, 3), A4 = L(a1, 4);+ __m256i B0 = L(a2, 0), B1 = L(a2, 1), B2 = L(a2, 2), B3 = L(a2, 3), B4 = L(a2, 4);+ uint64_t x1 = 0, x2 = 0;+ int i;++ for (i = 0; i < 20; i++) {+ uint64_t bi = b1[i], ci = b2[i], y, z;+ /* lane 0 in full: the products' high halves, which are lane 1's, too */+ unsigned __int128 s1 = (unsigned __int128) a1[0] * bi + x1;+ unsigned __int128 s2 = (unsigned __int128) a2[0] * ci + x2;+ __m256i bv = _mm256_set1_epi64x((long long) bi), cv = _mm256_set1_epi64x((long long) ci);+ __m256i yv, zv;++ y = ((uint64_t) s1 * k1) & IFMA_MASK52;+ z = ((uint64_t) s2 * k2) & IFMA_MASK52;+ s1 += (unsigned __int128) m1[0] * y;+ s2 += (unsigned __int128) m2[0] * z;+ yv = _mm256_set1_epi64x((long long) y);+ zv = _mm256_set1_epi64x((long long) z);+ X0 = _mm256_madd52lo_epu64(X0, A0, bv); Y0 = _mm256_madd52lo_epu64(Y0, B0, cv);+ X1 = _mm256_madd52lo_epu64(X1, A1, bv); Y1 = _mm256_madd52lo_epu64(Y1, B1, cv);+ X2 = _mm256_madd52lo_epu64(X2, A2, bv); Y2 = _mm256_madd52lo_epu64(Y2, B2, cv);+ X3 = _mm256_madd52lo_epu64(X3, A3, bv); Y3 = _mm256_madd52lo_epu64(Y3, B3, cv);+ X4 = _mm256_madd52lo_epu64(X4, A4, bv); Y4 = _mm256_madd52lo_epu64(Y4, B4, cv);+ X0 = _mm256_madd52lo_epu64(X0, L(m1, 0), yv); Y0 = _mm256_madd52lo_epu64(Y0, L(m2, 0), zv);+ X1 = _mm256_madd52lo_epu64(X1, L(m1, 1), yv); Y1 = _mm256_madd52lo_epu64(Y1, L(m2, 1), zv);+ X2 = _mm256_madd52lo_epu64(X2, L(m1, 2), yv); Y2 = _mm256_madd52lo_epu64(Y2, L(m2, 2), zv);+ X3 = _mm256_madd52lo_epu64(X3, L(m1, 3), yv); Y3 = _mm256_madd52lo_epu64(Y3, L(m2, 3), zv);+ X4 = _mm256_madd52lo_epu64(X4, L(m1, 4), yv); Y4 = _mm256_madd52lo_epu64(Y4, L(m2, 4), zv);+ /* down a lane: lane 0 is a multiple of 2^52, and s carries it */+ X0 = _mm256_alignr_epi64(X1, X0, 1); Y0 = _mm256_alignr_epi64(Y1, Y0, 1);+ X1 = _mm256_alignr_epi64(X2, X1, 1); Y1 = _mm256_alignr_epi64(Y2, Y1, 1);+ X2 = _mm256_alignr_epi64(X3, X2, 1); Y2 = _mm256_alignr_epi64(Y3, Y2, 1);+ X3 = _mm256_alignr_epi64(X4, X3, 1); Y3 = _mm256_alignr_epi64(Y4, Y3, 1);+ X4 = _mm256_alignr_epi64(zero, X4, 1); Y4 = _mm256_alignr_epi64(zero, Y4, 1);+ x1 = (uint64_t) _mm_cvtsi128_si64(_mm256_castsi256_si128(X0)) + (uint64_t)(s1 >> 52);+ x2 = (uint64_t) _mm_cvtsi128_si64(_mm256_castsi256_si128(Y0)) + (uint64_t)(s2 >> 52);+ X0 = _mm256_madd52hi_epu64(X0, A0, bv); Y0 = _mm256_madd52hi_epu64(Y0, B0, cv);+ X1 = _mm256_madd52hi_epu64(X1, A1, bv); Y1 = _mm256_madd52hi_epu64(Y1, B1, cv);+ X2 = _mm256_madd52hi_epu64(X2, A2, bv); Y2 = _mm256_madd52hi_epu64(Y2, B2, cv);+ X3 = _mm256_madd52hi_epu64(X3, A3, bv); Y3 = _mm256_madd52hi_epu64(Y3, B3, cv);+ X4 = _mm256_madd52hi_epu64(X4, A4, bv); Y4 = _mm256_madd52hi_epu64(Y4, B4, cv);+ X0 = _mm256_madd52hi_epu64(X0, L(m1, 0), yv); Y0 = _mm256_madd52hi_epu64(Y0, L(m2, 0), zv);+ X1 = _mm256_madd52hi_epu64(X1, L(m1, 1), yv); Y1 = _mm256_madd52hi_epu64(Y1, L(m2, 1), zv);+ X2 = _mm256_madd52hi_epu64(X2, L(m1, 2), yv); Y2 = _mm256_madd52hi_epu64(Y2, L(m2, 2), zv);+ X3 = _mm256_madd52hi_epu64(X3, L(m1, 3), yv); Y3 = _mm256_madd52hi_epu64(Y3, L(m2, 3), zv);+ X4 = _mm256_madd52hi_epu64(X4, L(m1, 4), yv); Y4 = _mm256_madd52hi_epu64(Y4, L(m2, 4), zv);+ }+#undef L+ /* lane 0, with the carry it was never given, is what the scalar holds */+ X0 = _mm256_mask_set1_epi64(X0, 1, (long long) x1);+ Y0 = _mm256_mask_set1_epi64(Y0, 1, (long long) x2);+ ifma_norm5(r1, X0, X1, X2, X3, X4);+ ifma_norm5(r2, Y0, Y1, Y2, Y3, Y4);+}++/* 30 digits, 8 registers a number */+IFMA_TARGET static void ifma_amm30_x2(uint64_t *r1, const uint64_t *a1, const uint64_t *b1,+ const uint64_t *m1, uint64_t k1,+ uint64_t *r2, const uint64_t *a2, const uint64_t *b2,+ const uint64_t *m2, uint64_t k2)+{+ const __m256i zero = _mm256_setzero_si256();+#define L(p, k) _mm256_loadu_si256((const __m256i *)((p) + 4 * (k)))+ __m256i X0 = zero, X1 = zero, X2 = zero, X3 = zero, X4 = zero, X5 = zero, X6 = zero, X7 = zero, Y0 = zero, Y1 = zero, Y2 = zero, Y3 = zero, Y4 = zero, Y5 = zero, Y6 = zero, Y7 = zero;+ uint64_t x1 = 0, x2 = 0;+ int i;++ for (i = 0; i < 30; i++) {+ uint64_t bi = b1[i], ci = b2[i], y, z;+ /* lane 0 in full: the products' high halves, which are lane 1's, too */+ unsigned __int128 s1 = (unsigned __int128) a1[0] * bi + x1;+ unsigned __int128 s2 = (unsigned __int128) a2[0] * ci + x2;+ __m256i bv = _mm256_set1_epi64x((long long) bi), cv = _mm256_set1_epi64x((long long) ci);+ __m256i yv, zv;++ y = ((uint64_t) s1 * k1) & IFMA_MASK52;+ z = ((uint64_t) s2 * k2) & IFMA_MASK52;+ s1 += (unsigned __int128) m1[0] * y;+ s2 += (unsigned __int128) m2[0] * z;+ yv = _mm256_set1_epi64x((long long) y);+ zv = _mm256_set1_epi64x((long long) z);+ X0 = _mm256_madd52lo_epu64(X0, L(a1, 0), bv); Y0 = _mm256_madd52lo_epu64(Y0, L(a2, 0), cv);+ X1 = _mm256_madd52lo_epu64(X1, L(a1, 1), bv); Y1 = _mm256_madd52lo_epu64(Y1, L(a2, 1), cv);+ X2 = _mm256_madd52lo_epu64(X2, L(a1, 2), bv); Y2 = _mm256_madd52lo_epu64(Y2, L(a2, 2), cv);+ X3 = _mm256_madd52lo_epu64(X3, L(a1, 3), bv); Y3 = _mm256_madd52lo_epu64(Y3, L(a2, 3), cv);+ X4 = _mm256_madd52lo_epu64(X4, L(a1, 4), bv); Y4 = _mm256_madd52lo_epu64(Y4, L(a2, 4), cv);+ X5 = _mm256_madd52lo_epu64(X5, L(a1, 5), bv); Y5 = _mm256_madd52lo_epu64(Y5, L(a2, 5), cv);+ X6 = _mm256_madd52lo_epu64(X6, L(a1, 6), bv); Y6 = _mm256_madd52lo_epu64(Y6, L(a2, 6), cv);+ X7 = _mm256_madd52lo_epu64(X7, L(a1, 7), bv); Y7 = _mm256_madd52lo_epu64(Y7, L(a2, 7), cv);+ X0 = _mm256_madd52lo_epu64(X0, L(m1, 0), yv); Y0 = _mm256_madd52lo_epu64(Y0, L(m2, 0), zv);+ X1 = _mm256_madd52lo_epu64(X1, L(m1, 1), yv); Y1 = _mm256_madd52lo_epu64(Y1, L(m2, 1), zv);+ X2 = _mm256_madd52lo_epu64(X2, L(m1, 2), yv); Y2 = _mm256_madd52lo_epu64(Y2, L(m2, 2), zv);+ X3 = _mm256_madd52lo_epu64(X3, L(m1, 3), yv); Y3 = _mm256_madd52lo_epu64(Y3, L(m2, 3), zv);+ X4 = _mm256_madd52lo_epu64(X4, L(m1, 4), yv); Y4 = _mm256_madd52lo_epu64(Y4, L(m2, 4), zv);+ X5 = _mm256_madd52lo_epu64(X5, L(m1, 5), yv); Y5 = _mm256_madd52lo_epu64(Y5, L(m2, 5), zv);+ X6 = _mm256_madd52lo_epu64(X6, L(m1, 6), yv); Y6 = _mm256_madd52lo_epu64(Y6, L(m2, 6), zv);+ X7 = _mm256_madd52lo_epu64(X7, L(m1, 7), yv); Y7 = _mm256_madd52lo_epu64(Y7, L(m2, 7), zv);+ /* down a lane: lane 0 is a multiple of 2^52, and s carries it */+ X0 = _mm256_alignr_epi64(X1, X0, 1); Y0 = _mm256_alignr_epi64(Y1, Y0, 1);+ X1 = _mm256_alignr_epi64(X2, X1, 1); Y1 = _mm256_alignr_epi64(Y2, Y1, 1);+ X2 = _mm256_alignr_epi64(X3, X2, 1); Y2 = _mm256_alignr_epi64(Y3, Y2, 1);+ X3 = _mm256_alignr_epi64(X4, X3, 1); Y3 = _mm256_alignr_epi64(Y4, Y3, 1);+ X4 = _mm256_alignr_epi64(X5, X4, 1); Y4 = _mm256_alignr_epi64(Y5, Y4, 1);+ X5 = _mm256_alignr_epi64(X6, X5, 1); Y5 = _mm256_alignr_epi64(Y6, Y5, 1);+ X6 = _mm256_alignr_epi64(X7, X6, 1); Y6 = _mm256_alignr_epi64(Y7, Y6, 1);+ X7 = _mm256_alignr_epi64(zero, X7, 1); Y7 = _mm256_alignr_epi64(zero, Y7, 1);+ x1 = (uint64_t) _mm_cvtsi128_si64(_mm256_castsi256_si128(X0)) + (uint64_t)(s1 >> 52);+ x2 = (uint64_t) _mm_cvtsi128_si64(_mm256_castsi256_si128(Y0)) + (uint64_t)(s2 >> 52);+ X0 = _mm256_madd52hi_epu64(X0, L(a1, 0), bv); Y0 = _mm256_madd52hi_epu64(Y0, L(a2, 0), cv);+ X1 = _mm256_madd52hi_epu64(X1, L(a1, 1), bv); Y1 = _mm256_madd52hi_epu64(Y1, L(a2, 1), cv);+ X2 = _mm256_madd52hi_epu64(X2, L(a1, 2), bv); Y2 = _mm256_madd52hi_epu64(Y2, L(a2, 2), cv);+ X3 = _mm256_madd52hi_epu64(X3, L(a1, 3), bv); Y3 = _mm256_madd52hi_epu64(Y3, L(a2, 3), cv);+ X4 = _mm256_madd52hi_epu64(X4, L(a1, 4), bv); Y4 = _mm256_madd52hi_epu64(Y4, L(a2, 4), cv);+ X5 = _mm256_madd52hi_epu64(X5, L(a1, 5), bv); Y5 = _mm256_madd52hi_epu64(Y5, L(a2, 5), cv);+ X6 = _mm256_madd52hi_epu64(X6, L(a1, 6), bv); Y6 = _mm256_madd52hi_epu64(Y6, L(a2, 6), cv);+ X7 = _mm256_madd52hi_epu64(X7, L(a1, 7), bv); Y7 = _mm256_madd52hi_epu64(Y7, L(a2, 7), cv);+ X0 = _mm256_madd52hi_epu64(X0, L(m1, 0), yv); Y0 = _mm256_madd52hi_epu64(Y0, L(m2, 0), zv);+ X1 = _mm256_madd52hi_epu64(X1, L(m1, 1), yv); Y1 = _mm256_madd52hi_epu64(Y1, L(m2, 1), zv);+ X2 = _mm256_madd52hi_epu64(X2, L(m1, 2), yv); Y2 = _mm256_madd52hi_epu64(Y2, L(m2, 2), zv);+ X3 = _mm256_madd52hi_epu64(X3, L(m1, 3), yv); Y3 = _mm256_madd52hi_epu64(Y3, L(m2, 3), zv);+ X4 = _mm256_madd52hi_epu64(X4, L(m1, 4), yv); Y4 = _mm256_madd52hi_epu64(Y4, L(m2, 4), zv);+ X5 = _mm256_madd52hi_epu64(X5, L(m1, 5), yv); Y5 = _mm256_madd52hi_epu64(Y5, L(m2, 5), zv);+ X6 = _mm256_madd52hi_epu64(X6, L(m1, 6), yv); Y6 = _mm256_madd52hi_epu64(Y6, L(m2, 6), zv);+ X7 = _mm256_madd52hi_epu64(X7, L(m1, 7), yv); Y7 = _mm256_madd52hi_epu64(Y7, L(m2, 7), zv);+ }+#undef L+ /* lane 0, with the carry it was never given, is what the scalar holds */+ X0 = _mm256_mask_set1_epi64(X0, 1, (long long) x1);+ Y0 = _mm256_mask_set1_epi64(Y0, 1, (long long) x2);+ ifma_norm8(r1, X0, X1, X2, X3, X4, X5, X6, X7);+ ifma_norm8(r2, Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7);+}++/* 40 digits, 10 registers a number */+IFMA_TARGET static void ifma_amm40_x2(uint64_t *r1, const uint64_t *a1, const uint64_t *b1,+ const uint64_t *m1, uint64_t k1,+ uint64_t *r2, const uint64_t *a2, const uint64_t *b2,+ const uint64_t *m2, uint64_t k2)+{+ const __m256i zero = _mm256_setzero_si256();+#define L(p, k) _mm256_loadu_si256((const __m256i *)((p) + 4 * (k)))+ __m256i X0 = zero, X1 = zero, X2 = zero, X3 = zero, X4 = zero, X5 = zero, X6 = zero, X7 = zero, X8 = zero, X9 = zero, Y0 = zero, Y1 = zero, Y2 = zero, Y3 = zero, Y4 = zero, Y5 = zero, Y6 = zero, Y7 = zero, Y8 = zero, Y9 = zero;+ uint64_t x1 = 0, x2 = 0;+ int i;++ for (i = 0; i < 40; i++) {+ uint64_t bi = b1[i], ci = b2[i], y, z;+ /* lane 0 in full: the products' high halves, which are lane 1's, too */+ unsigned __int128 s1 = (unsigned __int128) a1[0] * bi + x1;+ unsigned __int128 s2 = (unsigned __int128) a2[0] * ci + x2;+ __m256i bv = _mm256_set1_epi64x((long long) bi), cv = _mm256_set1_epi64x((long long) ci);+ __m256i yv, zv;++ y = ((uint64_t) s1 * k1) & IFMA_MASK52;+ z = ((uint64_t) s2 * k2) & IFMA_MASK52;+ s1 += (unsigned __int128) m1[0] * y;+ s2 += (unsigned __int128) m2[0] * z;+ yv = _mm256_set1_epi64x((long long) y);+ zv = _mm256_set1_epi64x((long long) z);+ X0 = _mm256_madd52lo_epu64(X0, L(a1, 0), bv); Y0 = _mm256_madd52lo_epu64(Y0, L(a2, 0), cv);+ X1 = _mm256_madd52lo_epu64(X1, L(a1, 1), bv); Y1 = _mm256_madd52lo_epu64(Y1, L(a2, 1), cv);+ X2 = _mm256_madd52lo_epu64(X2, L(a1, 2), bv); Y2 = _mm256_madd52lo_epu64(Y2, L(a2, 2), cv);+ X3 = _mm256_madd52lo_epu64(X3, L(a1, 3), bv); Y3 = _mm256_madd52lo_epu64(Y3, L(a2, 3), cv);+ X4 = _mm256_madd52lo_epu64(X4, L(a1, 4), bv); Y4 = _mm256_madd52lo_epu64(Y4, L(a2, 4), cv);+ X5 = _mm256_madd52lo_epu64(X5, L(a1, 5), bv); Y5 = _mm256_madd52lo_epu64(Y5, L(a2, 5), cv);+ X6 = _mm256_madd52lo_epu64(X6, L(a1, 6), bv); Y6 = _mm256_madd52lo_epu64(Y6, L(a2, 6), cv);+ X7 = _mm256_madd52lo_epu64(X7, L(a1, 7), bv); Y7 = _mm256_madd52lo_epu64(Y7, L(a2, 7), cv);+ X8 = _mm256_madd52lo_epu64(X8, L(a1, 8), bv); Y8 = _mm256_madd52lo_epu64(Y8, L(a2, 8), cv);+ X9 = _mm256_madd52lo_epu64(X9, L(a1, 9), bv); Y9 = _mm256_madd52lo_epu64(Y9, L(a2, 9), cv);+ X0 = _mm256_madd52lo_epu64(X0, L(m1, 0), yv); Y0 = _mm256_madd52lo_epu64(Y0, L(m2, 0), zv);+ X1 = _mm256_madd52lo_epu64(X1, L(m1, 1), yv); Y1 = _mm256_madd52lo_epu64(Y1, L(m2, 1), zv);+ X2 = _mm256_madd52lo_epu64(X2, L(m1, 2), yv); Y2 = _mm256_madd52lo_epu64(Y2, L(m2, 2), zv);+ X3 = _mm256_madd52lo_epu64(X3, L(m1, 3), yv); Y3 = _mm256_madd52lo_epu64(Y3, L(m2, 3), zv);+ X4 = _mm256_madd52lo_epu64(X4, L(m1, 4), yv); Y4 = _mm256_madd52lo_epu64(Y4, L(m2, 4), zv);+ X5 = _mm256_madd52lo_epu64(X5, L(m1, 5), yv); Y5 = _mm256_madd52lo_epu64(Y5, L(m2, 5), zv);+ X6 = _mm256_madd52lo_epu64(X6, L(m1, 6), yv); Y6 = _mm256_madd52lo_epu64(Y6, L(m2, 6), zv);+ X7 = _mm256_madd52lo_epu64(X7, L(m1, 7), yv); Y7 = _mm256_madd52lo_epu64(Y7, L(m2, 7), zv);+ X8 = _mm256_madd52lo_epu64(X8, L(m1, 8), yv); Y8 = _mm256_madd52lo_epu64(Y8, L(m2, 8), zv);+ X9 = _mm256_madd52lo_epu64(X9, L(m1, 9), yv); Y9 = _mm256_madd52lo_epu64(Y9, L(m2, 9), zv);+ /* down a lane: lane 0 is a multiple of 2^52, and s carries it */+ X0 = _mm256_alignr_epi64(X1, X0, 1); Y0 = _mm256_alignr_epi64(Y1, Y0, 1);+ X1 = _mm256_alignr_epi64(X2, X1, 1); Y1 = _mm256_alignr_epi64(Y2, Y1, 1);+ X2 = _mm256_alignr_epi64(X3, X2, 1); Y2 = _mm256_alignr_epi64(Y3, Y2, 1);+ X3 = _mm256_alignr_epi64(X4, X3, 1); Y3 = _mm256_alignr_epi64(Y4, Y3, 1);+ X4 = _mm256_alignr_epi64(X5, X4, 1); Y4 = _mm256_alignr_epi64(Y5, Y4, 1);+ X5 = _mm256_alignr_epi64(X6, X5, 1); Y5 = _mm256_alignr_epi64(Y6, Y5, 1);+ X6 = _mm256_alignr_epi64(X7, X6, 1); Y6 = _mm256_alignr_epi64(Y7, Y6, 1);+ X7 = _mm256_alignr_epi64(X8, X7, 1); Y7 = _mm256_alignr_epi64(Y8, Y7, 1);+ X8 = _mm256_alignr_epi64(X9, X8, 1); Y8 = _mm256_alignr_epi64(Y9, Y8, 1);+ X9 = _mm256_alignr_epi64(zero, X9, 1); Y9 = _mm256_alignr_epi64(zero, Y9, 1);+ x1 = (uint64_t) _mm_cvtsi128_si64(_mm256_castsi256_si128(X0)) + (uint64_t)(s1 >> 52);+ x2 = (uint64_t) _mm_cvtsi128_si64(_mm256_castsi256_si128(Y0)) + (uint64_t)(s2 >> 52);+ X0 = _mm256_madd52hi_epu64(X0, L(a1, 0), bv); Y0 = _mm256_madd52hi_epu64(Y0, L(a2, 0), cv);+ X1 = _mm256_madd52hi_epu64(X1, L(a1, 1), bv); Y1 = _mm256_madd52hi_epu64(Y1, L(a2, 1), cv);+ X2 = _mm256_madd52hi_epu64(X2, L(a1, 2), bv); Y2 = _mm256_madd52hi_epu64(Y2, L(a2, 2), cv);+ X3 = _mm256_madd52hi_epu64(X3, L(a1, 3), bv); Y3 = _mm256_madd52hi_epu64(Y3, L(a2, 3), cv);+ X4 = _mm256_madd52hi_epu64(X4, L(a1, 4), bv); Y4 = _mm256_madd52hi_epu64(Y4, L(a2, 4), cv);+ X5 = _mm256_madd52hi_epu64(X5, L(a1, 5), bv); Y5 = _mm256_madd52hi_epu64(Y5, L(a2, 5), cv);+ X6 = _mm256_madd52hi_epu64(X6, L(a1, 6), bv); Y6 = _mm256_madd52hi_epu64(Y6, L(a2, 6), cv);+ X7 = _mm256_madd52hi_epu64(X7, L(a1, 7), bv); Y7 = _mm256_madd52hi_epu64(Y7, L(a2, 7), cv);+ X8 = _mm256_madd52hi_epu64(X8, L(a1, 8), bv); Y8 = _mm256_madd52hi_epu64(Y8, L(a2, 8), cv);+ X9 = _mm256_madd52hi_epu64(X9, L(a1, 9), bv); Y9 = _mm256_madd52hi_epu64(Y9, L(a2, 9), cv);+ X0 = _mm256_madd52hi_epu64(X0, L(m1, 0), yv); Y0 = _mm256_madd52hi_epu64(Y0, L(m2, 0), zv);+ X1 = _mm256_madd52hi_epu64(X1, L(m1, 1), yv); Y1 = _mm256_madd52hi_epu64(Y1, L(m2, 1), zv);+ X2 = _mm256_madd52hi_epu64(X2, L(m1, 2), yv); Y2 = _mm256_madd52hi_epu64(Y2, L(m2, 2), zv);+ X3 = _mm256_madd52hi_epu64(X3, L(m1, 3), yv); Y3 = _mm256_madd52hi_epu64(Y3, L(m2, 3), zv);+ X4 = _mm256_madd52hi_epu64(X4, L(m1, 4), yv); Y4 = _mm256_madd52hi_epu64(Y4, L(m2, 4), zv);+ X5 = _mm256_madd52hi_epu64(X5, L(m1, 5), yv); Y5 = _mm256_madd52hi_epu64(Y5, L(m2, 5), zv);+ X6 = _mm256_madd52hi_epu64(X6, L(m1, 6), yv); Y6 = _mm256_madd52hi_epu64(Y6, L(m2, 6), zv);+ X7 = _mm256_madd52hi_epu64(X7, L(m1, 7), yv); Y7 = _mm256_madd52hi_epu64(Y7, L(m2, 7), zv);+ X8 = _mm256_madd52hi_epu64(X8, L(m1, 8), yv); Y8 = _mm256_madd52hi_epu64(Y8, L(m2, 8), zv);+ X9 = _mm256_madd52hi_epu64(X9, L(m1, 9), yv); Y9 = _mm256_madd52hi_epu64(Y9, L(m2, 9), zv);+ }+#undef L+ /* lane 0, with the carry it was never given, is what the scalar holds */+ X0 = _mm256_mask_set1_epi64(X0, 1, (long long) x1);+ Y0 = _mm256_mask_set1_epi64(Y0, 1, (long long) x2);+ ifma_norm10(r1, X0, X1, X2, X3, X4, X5, X6, X7, X8, X9);+ ifma_norm10(r2, Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8, Y9);+}++#endif
@@ -0,0 +1,178 @@+#!/usr/bin/env python3+"""Generate cbits/crypton_powm_ifma.h: two almost-Montgomery multiplications+at once in radix 2^52 with AVX-512 IFMA on 256-bit registers, at 20, 30 and+40 digits. Usage: python3 cbits/crypton_powm_ifma.py > cbits/crypton_powm_ifma.h++Gueron and Krasnov's method, a digit of b at a time. Lane 0 is followed in+full in a scalar, so it is read before the high halves go in and they stay+off the chain the next digit waits on.+"""++SIZES = (20, 30, 40)++HEADER = """\+/* Generated by cbits/crypton_powm_ifma.py; do not edit.+ *+ * Almost-Montgomery multiplication in radix 2^52, two at once: r = a b+ * 2^-52D mod m, under 2m for a and b under 2m. Digits are 52 bits in 64-bit+ * words, each number padded with zero words to a whole number of 256-bit+ * registers. m is read from memory; at 20 digits a is held in registers,+ * above that it is read from memory too. */+#ifndef CRYPTON_POWM_IFMA_H+#define CRYPTON_POWM_IFMA_H++#include <stdint.h>+#include <immintrin.h>++#define IFMA_MASK52 ((UINT64_C(1) << 52) - 1)+#define IFMA_TARGET __attribute__((target("avx2,avx512f,avx512vl,avx512ifma")))+"""++FOOTER = """\+#endif+"""+++def regs(d):+ return (d + 3) // 4+++def gen_norm(R):+ o = []+ w = o.append+ xs = [f"X{j}" for j in range(R)]+ w(f"/* {4 * R} lanes to 52-bit digits: what is above 52 bits moves up a lane,")+ w(f" * and the one-bit carries that can then remain are resolved together */")+ w(f"IFMA_TARGET static inline void ifma_norm{R}(uint64_t *r, " ++ ", ".join(f"__m256i {x}" for x in xs) + ")")+ w("{")+ w("\tconst __m256i mk = _mm256_set1_epi64x((long long) IFMA_MASK52), one = _mm256_set1_epi64x(1);")+ w("\tconst __m256i zero = _mm256_setzero_si256();")+ w("\tuint64_t g = 0, p = 0, c;")+ for j in range(R):+ w(f"\t__m256i C{j} = _mm256_srli_epi64(X{j}, 52);")+ for j in range(R):+ prev = f"C{j - 1}" if j else "zero"+ w(f"\tX{j} = _mm256_add_epi64(_mm256_and_si256(X{j}, mk), _mm256_alignr_epi64(C{j}, {prev}, 3));")+ for j in range(R):+ w(f"\tg |= (uint64_t) _mm256_cmpgt_epu64_mask(X{j}, mk) << {4 * j};")+ w(f"\tp |= (uint64_t) _mm256_cmpeq_epu64_mask(X{j}, mk) << {4 * j};")+ w("\tc = ((g << 1) + p) ^ p;")+ for j in range(R):+ w(f"\tX{j} = _mm256_and_si256(_mm256_mask_add_epi64(X{j}, (__mmask8)(c >> {4 * j} & 15), X{j}, one), mk);")+ w(f"\t_mm256_storeu_si256((__m256i *)(r + {4 * j}), X{j});")+ w("}")+ w("")+ return "\n".join(o)+++def gen_amm(d):+ R = regs(d)+ in_regs = R <= 5+ o = []+ w = o.append+ w(f"/* {d} digits, {R} registers a number */")+ w(f"IFMA_TARGET static void ifma_amm{d}_x2(uint64_t *r1, const uint64_t *a1, const uint64_t *b1,")+ w(f" const uint64_t *m1, uint64_t k1,")+ w(f" uint64_t *r2, const uint64_t *a2, const uint64_t *b2,")+ w(f" const uint64_t *m2, uint64_t k2)")+ w("{")+ w("\tconst __m256i zero = _mm256_setzero_si256();")+ w("#define L(p, k) _mm256_loadu_si256((const __m256i *)((p) + 4 * (k)))")+ X = [f"X{j}" for j in range(R)]+ Y = [f"Y{j}" for j in range(R)]+ w("\t__m256i " + ", ".join(f"{v} = zero" for v in X + Y) + ";")+ if in_regs:+ w("\t__m256i " + ", ".join(f"A{j} = L(a1, {j})" for j in range(R)) + ";")+ w("\t__m256i " + ", ".join(f"B{j} = L(a2, {j})" for j in range(R)) + ";")+ A = [f"A{j}" for j in range(R)]+ B = [f"B{j}" for j in range(R)]+ else:+ A = [f"L(a1, {j})" for j in range(R)]+ B = [f"L(a2, {j})" for j in range(R)]+ M = [f"L(m1, {j})" for j in range(R)]+ N = [f"L(m2, {j})" for j in range(R)]+ w("\tuint64_t x1 = 0, x2 = 0;")+ w("\tint i;")+ w("")+ w(f"\tfor (i = 0; i < {d}; i++) {{")+ w("\t\tuint64_t bi = b1[i], ci = b2[i], y, z;")+ w("\t\t/* lane 0 in full: the products' high halves, which are lane 1's, too */")+ w("\t\tunsigned __int128 s1 = (unsigned __int128) a1[0] * bi + x1;")+ w("\t\tunsigned __int128 s2 = (unsigned __int128) a2[0] * ci + x2;")+ w("\t\t__m256i bv = _mm256_set1_epi64x((long long) bi), cv = _mm256_set1_epi64x((long long) ci);")+ w("\t\t__m256i yv, zv;")+ w("")+ w("\t\ty = ((uint64_t) s1 * k1) & IFMA_MASK52;")+ w("\t\tz = ((uint64_t) s2 * k2) & IFMA_MASK52;")+ w("\t\ts1 += (unsigned __int128) m1[0] * y;")+ w("\t\ts2 += (unsigned __int128) m2[0] * z;")+ w("\t\tyv = _mm256_set1_epi64x((long long) y);")+ w("\t\tzv = _mm256_set1_epi64x((long long) z);")+ for j in range(R):+ w(f"\t\tX{j} = _mm256_madd52lo_epu64(X{j}, {A[j]}, bv); Y{j} = _mm256_madd52lo_epu64(Y{j}, {B[j]}, cv);")+ for j in range(R):+ w(f"\t\tX{j} = _mm256_madd52lo_epu64(X{j}, {M[j]}, yv); Y{j} = _mm256_madd52lo_epu64(Y{j}, {N[j]}, zv);")+ w("\t\t/* down a lane: lane 0 is a multiple of 2^52, and s carries it */")+ for j in range(R):+ nx = f"X{j + 1}" if j + 1 < R else "zero"+ ny = f"Y{j + 1}" if j + 1 < R else "zero"+ w(f"\t\tX{j} = _mm256_alignr_epi64({nx}, X{j}, 1); Y{j} = _mm256_alignr_epi64({ny}, Y{j}, 1);")+ w("\t\tx1 = (uint64_t) _mm_cvtsi128_si64(_mm256_castsi256_si128(X0)) + (uint64_t)(s1 >> 52);")+ w("\t\tx2 = (uint64_t) _mm_cvtsi128_si64(_mm256_castsi256_si128(Y0)) + (uint64_t)(s2 >> 52);")+ for j in range(R):+ w(f"\t\tX{j} = _mm256_madd52hi_epu64(X{j}, {A[j]}, bv); Y{j} = _mm256_madd52hi_epu64(Y{j}, {B[j]}, cv);")+ for j in range(R):+ w(f"\t\tX{j} = _mm256_madd52hi_epu64(X{j}, {M[j]}, yv); Y{j} = _mm256_madd52hi_epu64(Y{j}, {N[j]}, zv);")+ w("\t}")+ w("#undef L")+ w("\t/* lane 0, with the carry it was never given, is what the scalar holds */")+ w("\tX0 = _mm256_mask_set1_epi64(X0, 1, (long long) x1);")+ w("\tY0 = _mm256_mask_set1_epi64(Y0, 1, (long long) x2);")+ w(f"\tifma_norm{R}(r1, " + ", ".join(X) + ");")+ w(f"\tifma_norm{R}(r2, " + ", ".join(Y) + ");")+ w("}")+ w("")+ return "\n".join(o)+++def gen_sel(R):+ o = []+ w = o.append+ w(f"/* both tables' entries k1 and k2 of 32, every entry read and a mask keeping")+ w(f" * one; entries are {4 * R} words apart */")+ w(f"IFMA_TARGET static void ifma_sel{R}(uint64_t *o1, const uint64_t *t1, uint64_t k1,")+ w(f" uint64_t *o2, const uint64_t *t2, uint64_t k2)")+ w("{")+ w("\tconst __m256i one = _mm256_set1_epi64x(1);")+ w("\t__m256i v1 = _mm256_set1_epi64x((long long) k1), v2 = _mm256_set1_epi64x((long long) k2);")+ w("\t__m256i kv = _mm256_setzero_si256();")+ w("\t__m256i " + ", ".join(f"P{j} = kv, Q{j} = kv" for j in range(R)) + ";")+ w("\tint k;")+ w("\tfor (k = 0; k < 32; k++) {")+ w("\t\t__mmask8 s1 = _mm256_cmpeq_epi64_mask(v1, kv), s2 = _mm256_cmpeq_epi64_mask(v2, kv);")+ w(f"\t\tconst uint64_t *e1 = t1 + {4 * R} * k, *e2 = t2 + {4 * R} * k;")+ for j in range(R):+ w(f"\t\tP{j} = _mm256_mask_loadu_epi64(P{j}, s1, e1 + {4 * j}); Q{j} = _mm256_mask_loadu_epi64(Q{j}, s2, e2 + {4 * j});")+ w("\t\tkv = _mm256_add_epi64(kv, one);")+ w("\t}")+ for j in range(R):+ w(f"\t_mm256_storeu_si256((__m256i *)(o1 + {4 * j}), P{j}); _mm256_storeu_si256((__m256i *)(o2 + {4 * j}), Q{j});")+ w("}")+ w("")+ return "\n".join(o)+++def main():+ print(HEADER)+ rs = sorted({regs(d) for d in SIZES})+ for R in rs:+ print(gen_norm(R))+ print(gen_sel(R))+ for d in SIZES:+ print(gen_amm(d))+ print(FOOTER, end="")+++if __name__ == "__main__":+ main()
@@ -1,126 +0,0 @@-/*- * Copyright (C) Thomas DuBuisson- * Copyright (C) 2013 Vincent Hanquez <tab@snarc.org>- *- * All rights reserved.- * - * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- * 3. Neither the name of the author nor the names of his contributors- * may be used to endorse or promote products derived from this software- * without specific prior written permission.- * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF- * SUCH DAMAGE.- */--#include <stdint.h>-#include <stdlib.h>-#include <stdio.h>-#include <string.h>--int crypton_cpu_has_rdrand()-{- uint32_t ax,bx,cx,dx,func=1;-#if defined(__PIC__) && defined(__i386__)- __asm__ volatile ("mov %%ebx, %%edi;" "cpuid;" "xchgl %%ebx, %%edi;"- : "=a" (ax), "=D" (bx), "=c" (cx), "=d" (dx) : "a" (func));-#else- __asm__ volatile ("cpuid": "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));-#endif- return (cx & 0x40000000);-}--/* inline encoding of 'rdrand %rax' to cover old binutils- * - no inputs- * - 'cc' to the clobber list as we modify condition code.- * - output of rdrand in rax and have a 8 bit error condition- */-#define inline_rdrand_rax(val, err) \- asm(".byte 0x48,0x0f,0xc7,0xf0; setc %1" \- : "=a" (val), "=q" (err) \- : \- : "cc")--/* inline encoding of 'rdrand %eax' to cover old binutils- * - no inputs- * - 'cc' to the clobber list as we modify condition code.- * - output of rdrand in eax and have a 8 bit error condition- */-#define inline_rdrand_eax(val, err) \- asm(".byte 0x0f,0xc7,0xf0; setc %1" \- : "=a" (val), "=q" (err) \- : \- : "cc")--#ifdef __x86_64__-# define RDRAND_SZ 8-# define RDRAND_T uint64_t-#define inline_rdrand(val, err) err = crypton_rdrand_step(&val)-#else-# define RDRAND_SZ 4-# define RDRAND_T uint32_t-#define inline_rdrand(val, err) err = crypton_rdrand_step(&val)-#endif--/* sadly many people are still using an old binutils,- * leading to report that instruction is not recognized.- */-#if 1-/* Returns 1 on success */-static inline int crypton_rdrand_step(RDRAND_T *buffer)-{- unsigned char err;- asm volatile ("rdrand %0; setc %1" : "=r" (*buffer), "=qm" (err));- return (int) err;-}-#endif--/* Returns the number of bytes successfully generated */-int crypton_get_rand_bytes(uint8_t *buffer, size_t len)-{- RDRAND_T tmp;- int aligned = (intptr_t) buffer % RDRAND_SZ;- int orig_len = len;- int to_alignment = RDRAND_SZ - aligned;- uint8_t ok;-- if (aligned != 0) {- inline_rdrand(tmp, ok);- if (!ok)- return 0;- memcpy(buffer, (uint8_t *) &tmp, to_alignment);- buffer += to_alignment;- len -= to_alignment;- }-- for (; len >= RDRAND_SZ; buffer += RDRAND_SZ, len -= RDRAND_SZ) {- inline_rdrand(tmp, ok);- if (!ok)- return (orig_len - len);- *((RDRAND_T *) buffer) = tmp;- }-- if (len > 0) {- inline_rdrand(tmp, ok);- if (!ok)- return (orig_len - len);- memcpy(buffer, (uint8_t *) &tmp, len);- }- return orig_len;-}
@@ -57,16 +57,17 @@ #define R(a, b, c, d, e, f, k, i, s) \ a += f(b, c, d) + w[i] + k; a = rol32(a, s) + e; c = rol32(c, 10) -static void ripemd160_do_chunk(struct ripemd160_ctx *ctx, uint32_t *buf)+/* The words are read out of the block rather than the block being pointed at+ * as though it were an array of them; see crypton_md5.c. */+static void ripemd160_do_chunk(struct ripemd160_ctx *ctx, const uint8_t *buf) { uint32_t a1, b1, c1, d1, e1, a2, b2, c2, d2, e2;-#ifdef ARCH_IS_BIG_ENDIAN uint32_t w[16];- cpu_to_le32_array(w, buf, 16);-#else- uint32_t *w = buf;-#endif+ int wi; + for (wi = 0; wi < 16; wi++)+ w[wi] = load_le32(buf + 4 * wi);+ a1 = ctx->h[0]; b1 = ctx->h[1]; c1 = ctx->h[2]; d1 = ctx->h[3]; e1 = ctx->h[4]; a2 = ctx->h[0]; b2 = ctx->h[1]; c2 = ctx->h[2]; d2 = ctx->h[3]; e2 = ctx->h[4]; @@ -260,24 +261,15 @@ ctx->sz += len; if (index && len >= to_fill) { memcpy(ctx->buf + index, data, to_fill);- ripemd160_do_chunk(ctx, (uint32_t *) ctx->buf);+ ripemd160_do_chunk(ctx, ctx->buf); len -= to_fill; data += to_fill; index = 0; } - if (need_alignment(data, 4)) {- uint32_t tramp[16];- ASSERT_ALIGNMENT(tramp, 4);- for (; len >= 64; len -= 64, data += 64) {- memcpy(tramp, data, 64);- ripemd160_do_chunk(ctx, tramp);- }- } else {- /* process as much 64-block as possible */- for (; len >= 64; len -= 64, data += 64)- ripemd160_do_chunk(ctx, (uint32_t *) data);- }+ /* No trampoline: load_le32 does not ask for a boundary. */+ for (; len >= 64; len -= 64, data += 64)+ ripemd160_do_chunk(ctx, data); /* append data into buf */ if (len)
@@ -59,7 +59,7 @@ QR (x15,x12,x13,x14); \ } -static void salsa_core(int rounds, block *out, const crypton_salsa_state *in)+static void salsa_core(int rounds, crypton_salsa_block *out, const crypton_salsa_state *in) { uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; int i;@@ -94,7 +94,7 @@ out->d[15] = cpu_to_le32(x15); } -void crypton_salsa_core_xor(int rounds, block *out, block *in)+void crypton_salsa_core_xor(int rounds, crypton_salsa_block *out, crypton_salsa_block *in) { uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; int i;@@ -165,7 +165,7 @@ void crypton_salsa_combine(uint8_t *dst, crypton_salsa_context *ctx, const uint8_t *src, uint32_t bytes) {- block out;+ crypton_salsa_block out; crypton_salsa_state *st; int i; @@ -225,7 +225,7 @@ void crypton_salsa_generate(uint8_t *dst, crypton_salsa_context *ctx, uint32_t bytes) { crypton_salsa_state *st;- block out;+ crypton_salsa_block out; int i; if (!bytes)@@ -252,7 +252,7 @@ /* xor new 64-bytes chunks and store the left over if any */ for (; bytes >= 64; bytes -= 64, dst += 64) { /* generate new chunk and update state */- salsa_core(ctx->nb_rounds, (block *) dst, st);+ salsa_core(ctx->nb_rounds, (crypton_salsa_block *) dst, st); st->d[8] += 1; if (st->d[8] == 0) st->d[9] += 1;
@@ -34,9 +34,9 @@ uint64_t q[8]; uint32_t d[16]; uint8_t b[64];-} block;+} crypton_salsa_block; -typedef block crypton_salsa_state;+typedef crypton_salsa_block crypton_salsa_state; typedef struct { crypton_salsa_state st;@@ -47,7 +47,7 @@ } crypton_salsa_context; /* for scrypt */-void crypton_salsa_core_xor(int rounds, block *out, block *in);+void crypton_salsa_core_xor(int rounds, crypton_salsa_block *out, crypton_salsa_block *in); void crypton_salsa_init_core(crypton_salsa_state *st, uint32_t keylen, const uint8_t *key, uint32_t ivlen, const uint8_t *iv); void crypton_salsa_init(crypton_salsa_context *ctx, uint8_t nb_rounds, uint32_t keylen, const uint8_t *key, uint32_t ivlen, const uint8_t *iv);
@@ -37,10 +37,10 @@ array_copy32(X, &in[(2 * r - 1) * 16], 16); for (i = 0; i < 2 * r; i += 2) {- crypton_salsa_core_xor(8, (block *) X, (block *) &in[i*16]);+ crypton_salsa_core_xor(8, (crypton_salsa_block *) X, (crypton_salsa_block *) &in[i*16]); array_copy32(&out[i * 8], X, 16); - crypton_salsa_core_xor(8, (block *) X, (block *) &in[i*16+16]);+ crypton_salsa_core_xor(8, (crypton_salsa_block *) X, (crypton_salsa_block *) &in[i*16+16]); array_copy32(&out[i * 8 + r * 16], X, 16); } }
@@ -32,7 +32,7 @@ * Two threads racing to answer here both write the same value. */ #ifdef WITH_ARMV8_SHA1-extern void crypton_sha1_armv8_do_chunk(uint32_t state[5], const uint32_t buf[16]);+extern void crypton_sha1_armv8_do_chunk(uint32_t state[5], const uint8_t buf[64]); extern void crypton_sha1_armv8_do_chunks(uint32_t state[5], const uint8_t *data, uint32_t blocks); extern int crypton_sha1_armv8_available(void);@@ -55,8 +55,20 @@ const void *data, size_t blocks); #endif +/* Resolved before there is a second thread; see the constructor in+ * cbits/crypton_aes.c for why. The test below then only ever reads. */ static int sha1_use_armv8 = -1;++__attribute__((constructor))+static void sha1_armv8_ctor(void)+{+ sha1_use_armv8 = crypton_sha1_armv8_available();+#ifdef SHA1_ASM+ if (sha1_use_armv8)+ crypton_armcap_P |= CRYPTON_ARMCAP_SHA1; #endif+}+#endif #ifdef WITH_X86_SHA_NI #include "crypton_cpu.h"@@ -89,11 +101,13 @@ #define M(i) (w[i & 0x0f] = rol32(w[i & 0x0f] ^ w[(i - 14) & 0x0f] \ ^ w[(i - 8) & 0x0f] ^ w[(i - 3) & 0x0f], 1)) -static void sha1_do_chunk_generic(struct sha1_ctx *ctx, uint32_t *buf)+/* The words are read out of the block rather than the block being pointed at+ * as though it were an array of them; see crypton_md5.c. */+static void sha1_do_chunk_generic(struct sha1_ctx *ctx, const uint8_t *buf) { uint32_t a, b, c, d, e; uint32_t w[16];-#define CPY(i) w[i] = be32_to_cpu(buf[i])+#define CPY(i) w[i] = load_be32(buf + 4 * (i)) CPY(0); CPY(1); CPY(2); CPY(3); CPY(4); CPY(5); CPY(6); CPY(7); CPY(8); CPY(9); CPY(10); CPY(11); CPY(12); CPY(13); CPY(14); CPY(15); #undef CPY@@ -197,14 +211,14 @@ * They arrived long after the x86-64 baseline, so ask before using them. * Two threads racing to answer here both write the same value. */-extern void crypton_sha1_x86_do_chunk(uint32_t state[5], const uint32_t buf[16]);+extern void crypton_sha1_x86_do_chunk(uint32_t state[5], const uint8_t buf[64]); extern void crypton_sha1_x86_do_chunks(uint32_t state[5], const uint8_t *data, uint32_t blocks); static int sha1_use_x86 = -1; #endif -static inline void sha1_do_chunk(struct sha1_ctx *ctx, uint32_t *buf)+static inline void sha1_do_chunk(struct sha1_ctx *ctx, const uint8_t *buf) { #ifdef WITH_ARMV8_SHA1 if (sha1_use_armv8 < 0) {@@ -247,7 +261,7 @@ /* process partial buffer if there's enough data to make a block */ if (index && len >= to_fill) { memcpy(ctx->buf + index, data, to_fill);- sha1_do_chunk(ctx, (uint32_t *) ctx->buf);+ sha1_do_chunk(ctx, ctx->buf); len -= to_fill; data += to_fill; index = 0;@@ -292,18 +306,9 @@ } #endif - if (need_alignment(data, 4)) {- uint32_t tramp[16];- ASSERT_ALIGNMENT(tramp, 4);- for (; len >= 64; len -= 64, data += 64) {- memcpy(tramp, data, 64);- sha1_do_chunk(ctx, tramp);- }- } else {- /* process as much 64-block as possible */- for (; len >= 64; len -= 64, data += 64)- sha1_do_chunk(ctx, (uint32_t *) data);- }+ /* No trampoline: load_be32 does not ask for a boundary. */+ for (; len >= 64; len -= 64, data += 64)+ sha1_do_chunk(ctx, data); /* append data into buf */ if (len)
@@ -78,13 +78,16 @@ #define s0(x) (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3)) #define s1(x) (ror32(x,17) ^ ror32(x,19) ^ (x >> 10)) -static void sha256_do_chunk_generic(struct sha256_ctx *ctx, uint32_t buf[])+/* The sixteen words are read out of the block rather than the block being+ * pointed at as though it were an array of them; see crypton_md5.c. */+static void sha256_do_chunk_generic(struct sha256_ctx *ctx, const uint8_t *buf) { uint32_t a, b, c, d, e, f, g, h, t1, t2; int i; uint32_t w[64]; - cpu_to_be32_array(w, buf, 16);+ for (i = 0; i < 16; i++)+ w[i] = load_be32(buf + 4 * i); for (i = 16; i < 64; i++) w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16]; @@ -120,10 +123,18 @@ * sha256_armv8.c. They are optional in ARMv8.0, so ask before using them. * Two threads racing to answer here both write the same value. */-extern void crypton_sha256_armv8_do_chunk(uint32_t state[8], const uint32_t buf[16]);+extern void crypton_sha256_armv8_do_chunk(uint32_t state[8], const uint8_t buf[64]); extern int crypton_sha256_armv8_available(void); +/* Resolved before there is a second thread; see the constructor in+ * cbits/crypton_aes.c for why. The test below then only ever reads. */ static int sha256_use_armv8 = -1;++__attribute__((constructor))+static void sha256_armv8_ctor(void)+{+ sha256_use_armv8 = crypton_sha256_armv8_available();+} #endif #if (defined(WITH_ARMV8_SHA256_ASM) && defined(WITH_ARMV8_SHA2)) \@@ -141,22 +152,34 @@ extern void crypton_sha256_asm_block_data_order(uint32_t state[8], const void *data, size_t blocks); +#ifdef WITH_ARMV8_SHA256_ASM+/* The assembly picks its path from crypton_armcap_P, so the answer to the+ * runtime check has to reach that word rather than the flag above. It is+ * set here, before there is a second thread, for the reason the constructor+ * in cbits/crypton_aes.c gives.+ *+ * This ran from sha256_asm_ready below until 2.1.3, guarded by the flag+ * still being unresolved -- which stopped happening when the constructor+ * above was added, so the bit was never set and the assembly took its+ * generic path. SHA-256 was 5.7 times slower on an Apple M4 for it. */+__attribute__((constructor))+static void sha256_armcap_ctor(void)+{+ if (crypton_sha256_armv8_available())+ crypton_armcap_P |= CRYPTON_ARMCAP_SHA256;+}+#endif+ static void sha256_asm_ready(void) {-#ifdef WITH_ARMV8_SHA256_ASM- if (sha256_use_armv8 < 0) {- if (crypton_sha256_armv8_available())- crypton_armcap_P |= CRYPTON_ARMCAP_SHA256;- sha256_use_armv8 = 1;- }-#else+#ifndef WITH_ARMV8_SHA256_ASM crypton_x86_ia32cap_resolve(); #endif } #endif -static void sha256_do_chunk(struct sha256_ctx *ctx, uint32_t buf[])+static void sha256_do_chunk(struct sha256_ctx *ctx, const uint8_t *buf) { #ifdef SHA256_ASM sha256_asm_ready();@@ -192,7 +215,7 @@ /* process partial buffer if there's enough data to make a block */ if (index && len >= to_fill) { memcpy(ctx->buf + index, data, to_fill);- sha256_do_chunk(ctx, (uint32_t *) ctx->buf);+ sha256_do_chunk(ctx, ctx->buf); len -= to_fill; data += to_fill; index = 0;@@ -211,18 +234,9 @@ len -= (uint32_t) blocks * 64; } #else- if (need_alignment(data, 4)) {- uint32_t tramp[16];- ASSERT_ALIGNMENT(tramp, 4);- for (; len >= 64; len -= 64, data += 64) {- memcpy(tramp, data, 64);- sha256_do_chunk(ctx, tramp);- }- } else {- /* process as much 64-block as possible */- for (; len >= 64; len -= 64, data += 64)- sha256_do_chunk(ctx, (uint32_t *) data);- }+ /* No trampoline: load_be32 does not ask for a boundary. */+ for (; len >= 64; len -= 64, data += 64)+ sha256_do_chunk(ctx, data); #endif /* append data into buf */
@@ -51,6 +51,18 @@ void crypton_sha256_init(struct sha256_ctx *ctx); void crypton_sha256_update(struct sha256_ctx *ctx, const uint8_t *data, uint32_t len);+/* The pointers are all required to be non-null, which is said here so that+ * the compiler knows it too. Both of these write their digest through a+ * loop -- store_be32(out + 4 * i, ...) -- where sha1 and md5 write theirs at+ * constant offsets, and that is the difference that makes gcc's+ * -Wstringop-overflow reason about out being null: with+ * -fsanitize=undefined, UndefinedBehaviorSanitizer inserts a null check+ * before memcpy, because glibc declares memcpy nonnull, and the check puts a+ * null path in front of the warning pass, which then reports writing into+ * "a region of size 0" at "address zero". Saying the pointer is never null+ * removes the path rather than the warning. It costs nothing: compiled as+ * the package compiles it, the assembly is identical with and without. */+__attribute__((nonnull)) void crypton_sha256_finalize(struct sha256_ctx *ctx, uint8_t *out); void crypton_sha256_finalize_prefix(struct sha256_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out);
@@ -102,14 +102,16 @@ #define sha3_asm_absorb crypton_keccak_asm_absorb #endif -static inline void sha3_do_chunk(uint64_t state[25], uint64_t buf[], int bufsz)+/* The words are read out of the block rather than the block being pointed at+ * as though it were an array of them; see crypton_md5.c. */+static inline void sha3_do_chunk(uint64_t state[25], const uint8_t *buf, int bufsz) { int i, j, r; uint64_t tmp, bc[5]; /* merge buf with state */ for (i = 0; i < bufsz; i++)- state[i] ^= le64_to_cpu(buf[i]);+ state[i] ^= load_le64(buf + 8 * i); #ifdef WITH_ARMV8_SHA3 if (sha3_armv8_ok()) {@@ -180,14 +182,14 @@ to_fill = ctx->bufsz - ctx->bufindex; if (ctx->bufindex == ctx->bufsz) {- sha3_do_chunk(ctx->state, (uint64_t *) ctx->buf, ctx->bufsz / 8);+ sha3_do_chunk(ctx->state, ctx->buf, ctx->bufsz / 8); ctx->bufindex = 0; } /* process partial buffer if there's enough data to make a block */ if (ctx->bufindex && len >= to_fill) { memcpy(ctx->buf + ctx->bufindex, data, to_fill);- sha3_do_chunk(ctx->state, (uint64_t *) ctx->buf, ctx->bufsz / 8);+ sha3_do_chunk(ctx->state, ctx->buf, ctx->bufsz / 8); len -= to_fill; data += to_fill; ctx->bufindex = 0;@@ -207,18 +209,9 @@ } #endif - if (need_alignment(data, 8)) {- uint64_t tramp[SHA3_BUF_SIZE_MAX/8];- ASSERT_ALIGNMENT(tramp, 8);- for (; len >= ctx->bufsz; len -= ctx->bufsz, data += ctx->bufsz) {- memcpy(tramp, data, ctx->bufsz);- sha3_do_chunk(ctx->state, tramp, ctx->bufsz / 8);- }- } else {- /* process as much ctx->bufsz-block */- for (; len >= ctx->bufsz; len -= ctx->bufsz, data += ctx->bufsz)- sha3_do_chunk(ctx->state, (uint64_t *) data, ctx->bufsz / 8);- }+ /* No trampoline: load_le64 does not ask for a boundary. */+ for (; len >= ctx->bufsz; len -= ctx->bufsz, data += ctx->bufsz)+ sha3_do_chunk(ctx->state, data, ctx->bufsz / 8); /* append data into buf */@@ -232,7 +225,7 @@ { /* process full buffer if needed */ if (ctx->bufindex == ctx->bufsz) {- sha3_do_chunk(ctx->state, (uint64_t *) ctx->buf, ctx->bufsz / 8);+ sha3_do_chunk(ctx->state, ctx->buf, ctx->bufsz / 8); ctx->bufindex = 0; } @@ -242,7 +235,7 @@ ctx->buf[ctx->bufsz - 1] |= 0x80; /* process */- sha3_do_chunk(ctx->state, (uint64_t *) ctx->buf, ctx->bufsz / 8);+ sha3_do_chunk(ctx->state, ctx->buf, ctx->bufsz / 8); ctx->bufindex = 0; }
@@ -91,13 +91,16 @@ #define s0(x) (ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7)) #define s1(x) (ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6)) -static void sha512_do_chunk_generic(struct sha512_ctx *ctx, uint64_t *buf)+/* The words are read out of the block rather than the block being pointed at+ * as though it were an array of them; see crypton_md5.c. */+static void sha512_do_chunk_generic(struct sha512_ctx *ctx, const uint8_t *buf) { uint64_t a, b, c, d, e, f, g, h, t1, t2; int i; uint64_t w[80]; - cpu_to_be64_array(w, buf, 16);+ for (i = 0; i < 16; i++)+ w[i] = load_be64(buf + 8 * i); for (i = 16; i < 80; i++) w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16];@@ -135,10 +138,18 @@ * widespread than the SHA-256 ones, so ask before using them. Two threads * racing to answer here both write the same value. */-extern void crypton_sha512_armv8_do_chunk(uint64_t state[8], const uint64_t buf[16]);+extern void crypton_sha512_armv8_do_chunk(uint64_t state[8], const uint8_t buf[128]); extern int crypton_sha512_armv8_available(void); +/* Resolved before there is a second thread; see the constructor in+ * cbits/crypton_aes.c for why. The test below then only ever reads. */ static int sha512_use_armv8 = -1;++__attribute__((constructor))+static void sha512_armv8_ctor(void)+{+ sha512_use_armv8 = crypton_sha512_armv8_available();+} #endif @@ -154,7 +165,7 @@ const void *data, size_t blocks); #endif -static void sha512_do_chunk(struct sha512_ctx *ctx, uint64_t *buf)+static void sha512_do_chunk(struct sha512_ctx *ctx, const uint8_t *buf) { #ifdef SHA512_ASM crypton_x86_ia32cap_resolve();@@ -192,7 +203,7 @@ /* process partial buffer if there's enough data to make a block */ if (index && len >= to_fill) { memcpy(ctx->buf + index, data, to_fill);- sha512_do_chunk(ctx, (uint64_t *) ctx->buf);+ sha512_do_chunk(ctx, ctx->buf); len -= to_fill; data += to_fill; index = 0;@@ -210,18 +221,9 @@ len -= (uint32_t) blocks * 128; } #else- if (need_alignment(data, 8)) {- uint64_t tramp[16];- ASSERT_ALIGNMENT(tramp, 8);- for (; len >= 128; len -= 128, data += 128) {- memcpy(tramp, data, 128);- sha512_do_chunk(ctx, tramp);- }- } else {- /* process as much 128-block as possible */- for (; len >= 128; len -= 128, data += 128)- sha512_do_chunk(ctx, (uint64_t *) data);- }+ /* No trampoline: load_be64 does not ask for a boundary. */+ for (; len >= 128; len -= 128, data += 128)+ sha512_do_chunk(ctx, data); #endif /* append data into buf */@@ -344,7 +346,7 @@ /* re-init the context, otherwise len is changed */ memset(ctx, 0, sizeof(*ctx)); for (i = 0; i < 8; i++)- ctx->h[i] = cpu_to_be64(((uint64_t *) out)[i]);+ ctx->h[i] = load_be64(out + 8 * i); } } }
@@ -50,6 +50,18 @@ void crypton_sha512_init(struct sha512_ctx *ctx); void crypton_sha512_update(struct sha512_ctx *ctx, const uint8_t *data, uint32_t len);+/* The pointers are all required to be non-null, which is said here so that+ * the compiler knows it too. Both of these write their digest through a+ * loop -- store_be32(out + 4 * i, ...) -- where sha1 and md5 write theirs at+ * constant offsets, and that is the difference that makes gcc's+ * -Wstringop-overflow reason about out being null: with+ * -fsanitize=undefined, UndefinedBehaviorSanitizer inserts a null check+ * before memcpy, because glibc declares memcpy nonnull, and the check puts a+ * null path in front of the warning pass, which then reports writing into+ * "a region of size 0" at "address zero". Saying the pointer is never null+ * removes the path rather than the warning. It costs nothing: compiled as+ * the package compiles it, the assembly is identical with and without. */+__attribute__((nonnull)) void crypton_sha512_finalize(struct sha512_ctx *ctx, uint8_t *out); void crypton_sha512_finalize_prefix(struct sha512_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out);
@@ -37,7 +37,9 @@ static const uint8_t K256_6[2] = { 58, 22, }; static const uint8_t K256_7[2] = { 32, 32, }; -static inline void skein256_do_chunk(struct skein256_ctx *ctx, uint64_t *buf, uint32_t len)+/* The four words are read out of the block rather than the block being+ * pointed at as though it were an array of them; see crypton_md5.c. */+static inline void skein256_do_chunk(struct skein256_ctx *ctx, const uint8_t *bufp, uint32_t len) { uint64_t x[4]; uint64_t ts[3];@@ -78,11 +80,18 @@ ROUND(0,3,2,1,K256_7); \ INJECTKEY((i*2) + 2) - x[0] = le64_to_cpu(buf[0]) + ks[0];- x[1] = le64_to_cpu(buf[1]) + ks[1] + ts[0];- x[2] = le64_to_cpu(buf[2]) + ks[2] + ts[1];- x[3] = le64_to_cpu(buf[3]) + ks[3];+ uint64_t buf[4]; + buf[0] = load_le64(bufp);+ buf[1] = load_le64(bufp + 8);+ buf[2] = load_le64(bufp + 16);+ buf[3] = load_le64(bufp + 24);++ x[0] = buf[0] + ks[0];+ x[1] = buf[1] + ks[1] + ts[0];+ x[2] = buf[2] + ks[2] + ts[1];+ x[3] = buf[3] + ks[3];+ /* 9 pass of 8 rounds = 72 rounds */ PASS(0); PASS(1);@@ -98,10 +107,10 @@ ctx->t0 = ts[0]; ctx->t1 = ts[1]; - ctx->h[0] = x[0] ^ cpu_to_le64(buf[0]);- ctx->h[1] = x[1] ^ cpu_to_le64(buf[1]);- ctx->h[2] = x[2] ^ cpu_to_le64(buf[2]);- ctx->h[3] = x[3] ^ cpu_to_le64(buf[3]);+ ctx->h[0] = x[0] ^ buf[0];+ ctx->h[1] = x[1] ^ buf[1];+ ctx->h[2] = x[2] ^ buf[2];+ ctx->h[3] = x[3] ^ buf[3]; } void crypton_skein256_init(struct skein256_ctx *ctx, uint32_t hashlen)@@ -115,7 +124,7 @@ buf[0] = cpu_to_le64((SKEIN_VERSION << 32) | SKEIN_IDSTRING); buf[1] = cpu_to_le64(hashlen); buf[2] = 0; /* tree info, not implemented */- skein256_do_chunk(ctx, buf, 4*8);+ skein256_do_chunk(ctx, (const uint8_t *) buf, 4*8); SET_TYPE(ctx, FLAG_FIRST | FLAG_TYPE(TYPE_MSG)); }@@ -130,7 +139,7 @@ to_fill = 32 - ctx->bufindex; if (ctx->bufindex == 32) {- skein256_do_chunk(ctx, (uint64_t *) ctx->buf, 32);+ skein256_do_chunk(ctx, ctx->buf, 32); ctx->bufindex = 0; } @@ -138,24 +147,17 @@ * and there's without doubt further blocks */ if (ctx->bufindex && len > to_fill) { memcpy(ctx->buf + ctx->bufindex, data, to_fill);- skein256_do_chunk(ctx, (uint64_t *) ctx->buf, 32);+ skein256_do_chunk(ctx, ctx->buf, 32); len -= to_fill; data += to_fill; ctx->bufindex = 0; } - if (need_alignment(data, 8)) {- uint64_t tramp[4];- ASSERT_ALIGNMENT(tramp, 8);- for (; len > 32; len -= 32, data += 32) {- memcpy(tramp, data, 32);- skein256_do_chunk(ctx, tramp, 32);- }- } else {- /* process as much 32-block as possible except the last one in case we finalize */- for (; len > 32; len -= 32, data += 32)- skein256_do_chunk(ctx, (uint64_t *) data, 32);- }+ /* No trampoline for a block that is not on an eight-byte boundary: the+ * words are read with load_le64 now, which does not ask. The last+ * block is left for the finalisation. */+ for (; len > 32; len -= 32, data += 32)+ skein256_do_chunk(ctx, data, 32); /* append data into buf */ if (len) {@@ -174,7 +176,7 @@ /* if buf is not complete pad with 0 bytes */ if (ctx->bufindex < 32) memset(ctx->buf + ctx->bufindex, '\0', 32 - ctx->bufindex);- skein256_do_chunk(ctx, (uint64_t *) ctx->buf, ctx->bufindex);+ skein256_do_chunk(ctx, ctx->buf, ctx->bufindex); memset(ctx->buf, '\0', 32); @@ -187,9 +189,9 @@ /* threefish in counter mode, 0 for 1st 64 bytes, 1 for 2nd 64 bytes, .. */ for (i = 0; i*32 < outsize; i++) { uint64_t w[4];- *((uint64_t *) ctx->buf) = cpu_to_le64(i);+ store_le64(ctx->buf, i); SET_TYPE(ctx, FLAG_FIRST | FLAG_FINAL | FLAG_TYPE(TYPE_OUT));- skein256_do_chunk(ctx, (uint64_t *) ctx->buf, sizeof(uint64_t));+ skein256_do_chunk(ctx, ctx->buf, sizeof(uint64_t)); n = outsize - i * 32; if (n >= 32) n = 32;
@@ -37,8 +37,8 @@ #define SKEIN256_CTX_SIZE sizeof(struct skein256_ctx) -void cryponite_skein256_init(struct skein256_ctx *ctx, uint32_t hashlen);-void cryponite_skein256_update(struct skein256_ctx *ctx, const uint8_t *data, uint32_t len);-void cryponite_skein256_finalize(struct skein256_ctx *ctx, uint32_t hashlen, uint8_t *out);+void crypton_skein256_init(struct skein256_ctx *ctx, uint32_t hashlen);+void crypton_skein256_update(struct skein256_ctx *ctx, const uint8_t *data, uint32_t len);+void crypton_skein256_finalize(struct skein256_ctx *ctx, uint32_t hashlen, uint8_t *out); #endif
@@ -37,7 +37,9 @@ static const uint8_t K512_6[4] = { 25, 29, 39, 43, }; static const uint8_t K512_7[4] = { 8, 35, 56, 22, }; -static inline void skein512_do_chunk(struct skein512_ctx *ctx, uint64_t *buf, uint32_t len)+/* The words are read out of the block rather than the block being pointed at+ * as though it were an array of them; see crypton_md5.c. */+static inline void skein512_do_chunk(struct skein512_ctx *ctx, const uint8_t *bufp, uint32_t len) { uint64_t x[8]; uint64_t ts[3];@@ -88,15 +90,21 @@ ROUND(6,1,0,7,2,5,4,3,K512_7); \ INJECTKEY((i*2) + 2) - x[0] = le64_to_cpu(buf[0]) + ks[0];- x[1] = le64_to_cpu(buf[1]) + ks[1];- x[2] = le64_to_cpu(buf[2]) + ks[2];- x[3] = le64_to_cpu(buf[3]) + ks[3];- x[4] = le64_to_cpu(buf[4]) + ks[4];- x[5] = le64_to_cpu(buf[5]) + ks[5] + ts[0];- x[6] = le64_to_cpu(buf[6]) + ks[6] + ts[1];- x[7] = le64_to_cpu(buf[7]) + ks[7];+ uint64_t buf[8];+ int bi; + for (bi = 0; bi < 8; bi++)+ buf[bi] = load_le64(bufp + 8 * bi);++ x[0] = buf[0] + ks[0];+ x[1] = buf[1] + ks[1];+ x[2] = buf[2] + ks[2];+ x[3] = buf[3] + ks[3];+ x[4] = buf[4] + ks[4];+ x[5] = buf[5] + ks[5] + ts[0];+ x[6] = buf[6] + ks[6] + ts[1];+ x[7] = buf[7] + ks[7];+ /* 9 pass of 8 rounds = 72 rounds */ PASS(0); PASS(1);@@ -112,14 +120,14 @@ ctx->t0 = ts[0]; ctx->t1 = ts[1]; - ctx->h[0] = x[0] ^ cpu_to_le64(buf[0]);- ctx->h[1] = x[1] ^ cpu_to_le64(buf[1]);- ctx->h[2] = x[2] ^ cpu_to_le64(buf[2]);- ctx->h[3] = x[3] ^ cpu_to_le64(buf[3]);- ctx->h[4] = x[4] ^ cpu_to_le64(buf[4]);- ctx->h[5] = x[5] ^ cpu_to_le64(buf[5]);- ctx->h[6] = x[6] ^ cpu_to_le64(buf[6]);- ctx->h[7] = x[7] ^ cpu_to_le64(buf[7]);+ ctx->h[0] = x[0] ^ buf[0];+ ctx->h[1] = x[1] ^ buf[1];+ ctx->h[2] = x[2] ^ buf[2];+ ctx->h[3] = x[3] ^ buf[3];+ ctx->h[4] = x[4] ^ buf[4];+ ctx->h[5] = x[5] ^ buf[5];+ ctx->h[6] = x[6] ^ buf[6];+ ctx->h[7] = x[7] ^ buf[7]; } void crypton_skein512_init(struct skein512_ctx *ctx, uint32_t hashlen)@@ -133,7 +141,7 @@ buf[0] = cpu_to_le64((SKEIN_VERSION << 32) | SKEIN_IDSTRING); buf[1] = cpu_to_le64(hashlen); buf[2] = 0; /* tree info, not implemented */- skein512_do_chunk(ctx, buf, 4*8);+ skein512_do_chunk(ctx, (const uint8_t *) buf, 4*8); SET_TYPE(ctx, FLAG_FIRST | FLAG_TYPE(TYPE_MSG)); }@@ -148,7 +156,7 @@ to_fill = 64 - ctx->bufindex; if (ctx->bufindex == 64) {- skein512_do_chunk(ctx, (uint64_t *) ctx->buf, 64);+ skein512_do_chunk(ctx, ctx->buf, 64); ctx->bufindex = 0; } @@ -156,24 +164,15 @@ * and there's without doubt further blocks */ if (ctx->bufindex && len > to_fill) { memcpy(ctx->buf + ctx->bufindex, data, to_fill);- skein512_do_chunk(ctx, (uint64_t *) ctx->buf, 64);+ skein512_do_chunk(ctx, ctx->buf, 64); len -= to_fill; data += to_fill; ctx->bufindex = 0; } - if (need_alignment(data, 8)) {- uint64_t tramp[8];- ASSERT_ALIGNMENT(tramp, 8);- for (; len > 64; len -= 64, data += 64) {- memcpy(tramp, data, 64);- skein512_do_chunk(ctx, tramp, 64);- }- } else {- /* process as much 64-block as possible except the last one in case we finalize */- for (; len > 64; len -= 64, data += 64)- skein512_do_chunk(ctx, (uint64_t *) data, 64);- }+ /* No trampoline: load_le64 does not ask for a boundary. */+ for (; len > 64; len -= 64, data += 64)+ skein512_do_chunk(ctx, data, 64); /* append data into buf */ if (len) {@@ -192,7 +191,7 @@ /* if buf is not complete pad with 0 bytes */ if (ctx->bufindex < 64) memset(ctx->buf + ctx->bufindex, '\0', 64 - ctx->bufindex);- skein512_do_chunk(ctx, (uint64_t *) ctx->buf, ctx->bufindex);+ skein512_do_chunk(ctx, ctx->buf, ctx->bufindex); memset(ctx->buf, '\0', 64); @@ -205,9 +204,9 @@ /* threefish in counter mode, 0 for 1st 64 bytes, 1 for 2nd 64 bytes, .. */ for (i = 0; i*64 < outsize; i++) { uint64_t w[8];- *((uint64_t *) ctx->buf) = cpu_to_le64(i);+ store_le64(ctx->buf, i); SET_TYPE(ctx, FLAG_FIRST | FLAG_FINAL | FLAG_TYPE(TYPE_OUT));- skein512_do_chunk(ctx, (uint64_t *) ctx->buf, sizeof(uint64_t));+ skein512_do_chunk(ctx, ctx->buf, sizeof(uint64_t)); n = outsize - i * 64; if (n >= 64) n = 64;
@@ -37,8 +37,8 @@ #define SKEIN512_CTX_SIZE sizeof(struct skein512_ctx) -void cryponite_skein512_init(struct skein512_ctx *ctx, uint32_t hashlen);-void cryponite_skein512_update(struct skein512_ctx *ctx, const uint8_t *data, uint32_t len);-void cryponite_skein512_finalize(struct skein512_ctx *ctx, uint32_t hashlen, uint8_t *out);+void crypton_skein512_init(struct skein512_ctx *ctx, uint32_t hashlen);+void crypton_skein512_update(struct skein512_ctx *ctx, const uint8_t *data, uint32_t len);+void crypton_skein512_finalize(struct skein512_ctx *ctx, uint32_t hashlen, uint8_t *out); #endif
@@ -0,0 +1,388 @@+/*+ * The generator behind MonadRandom IO.+ *+ * A ChaCha20 DRBG per operating system thread, seeded from a process-wide+ * DRBG, which is itself seeded from the system entropy pool. This is the+ * shape RFC 9180's neighbours and the other libraries have settled on, and+ * it was asked for in #298.+ *+ * Per operating system thread and not per Haskell thread: a forkIO thread+ * moves between capabilities, so state kept against it would be shared by+ * threads running at the same time. That is why the state is here and+ * reached through pthread_getspecific rather than held in Haskell.+ *+ * Three things force a reseed:+ *+ * - a thread has produced CRYPTON_THREAD_RESEED bytes,+ * - the process DRBG has issued CRYPTON_GLOBAL_RESEED bytes of seed,+ * - the process has forked.+ *+ * The last one is the one that bites. A child inherits its parent's state+ * and would otherwise produce the same stream; the generation counter below+ * is bumped in the child by a pthread_atfork handler, and every generator+ * compares against it before it answers.+ */++#include <stdint.h>+#include <string.h>+#include <stdlib.h>++#include "crypton_chacha.h"+#include "crypton_sha512.h"++#ifdef _WIN32+#include <windows.h>+#else+#include <pthread.h>+#include <unistd.h>+#endif++/* from crypton_sysrandom.c */+int crypton_sysrandom_available(void);+int crypton_sysrandom_bytes(uint8_t *buf, int len);++#define CHACHA_ROUNDS 20+#define SEED_KEY 32+#define SEED_IV 8+#define SEED_LEN (SEED_KEY + SEED_IV)++#define CRYPTON_THREAD_RESEED (1u << 20)+#define CRYPTON_GLOBAL_RESEED (1u << 20)++typedef struct {+ crypton_chacha_context ctx;+ uint64_t used;+ uint32_t generation;+ int seeded;+} drg_t;++static drg_t global_drg;+static volatile uint32_t fork_generation = 0;++#ifdef _WIN32+static CRITICAL_SECTION global_lock;+/* Fls and not Tls: TlsAlloc has no destructor, so the state of every thread+ * that ever drew a byte would be left allocated and unscrubbed when the+ * thread ended. FlsAlloc takes the callback that pthread_key_create does. */+static DWORD thread_slot;+static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;+#else+static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;+static pthread_key_t thread_slot;+static pthread_once_t init_once = PTHREAD_ONCE_INIT;+#endif++static void scrub(void *p, size_t n)+{+ volatile uint8_t *q = (volatile uint8_t *) p;+ while (n--) *q++ = 0;+}++/*+ * Seed material for the process DRBG.+ *+ * What the system gives goes through SHA-512 rather than into the key+ * directly, so that the key is a fixed size whatever the call returns, and+ * so that a second source could be added without any of this changing shape.+ * There is one source today and the note below says why.+ */+static int seed_from_system(uint8_t out[SEED_LEN])+{+ struct sha512_ctx h;+ uint8_t buf[64];+ uint8_t digest[64];+ int got;++ crypton_sha512_init(&h);++ /*+ * The system call only. Where there is none -- an old kernel, a BSD+ * this does not know -- seeding fails and the caller keeps the path+ * it has, rather than this file growing a second copy of the device+ * reading that Crypto.Random.Entropy.Unix already does.+ *+ * And RDRAND is not mixed in beside it, which it was until+ * @vdukhovni pointed out that it cannot add anything: every system+ * this code runs on already feeds RDRAND into the pool the call below+ * draws from. Linux does that whatever random.trust_cpu says -- that+ * setting decides whether the contribution is *credited*, not whether+ * it is mixed -- so the instruction's output is in this buffer+ * already.+ *+ * The argument for keeping it was defence in depth against that pool+ * having gone wrong. It does not survive the above: a pool that has+ * gone wrong has gone wrong with RDRAND already in it, so asking the+ * instruction a second time covers only the case where the kernel's+ * mixing is broken and the instruction is not. That is not worth a+ * second code path, a flag, and the standing invitation to read this+ * as a second source when it is the same one twice.+ */+ got = crypton_sysrandom_available() ? crypton_sysrandom_bytes(buf, 64) : 0;+ if (got <= 0) {+ /* Nothing else here is a seed on its own, so there is nothing to+ * go on with: return before drawing anything that would only be+ * thrown away. */+ scrub(&h, sizeof h);+ scrub(buf, sizeof buf);+ return 0;+ }+ crypton_sha512_update(&h, buf, (uint32_t) got);+++ crypton_sha512_finalize(&h, digest);+ memcpy(out, digest, SEED_LEN);++ scrub(&h, sizeof h);+ scrub(buf, sizeof buf);+ scrub(digest, sizeof digest);+ return 1;+}++static void drg_seed(drg_t *d, const uint8_t seed[SEED_LEN])+{+ crypton_chacha_init(&d->ctx, CHACHA_ROUNDS, SEED_KEY, seed,+ SEED_IV, seed + SEED_KEY);+ d->used = 0;+ d->generation = fork_generation;+ d->seeded = 1;+}++/*+ * Forget the key that produced the bytes just handed out.+ *+ * Without this the key stands until the next reseed, and anyone who reads a+ * generator's state can wind the counter back and reproduce everything it+ * has issued since -- up to CRYPTON_THREAD_RESEED bytes that were meant to+ * be secret. Taking the next forty bytes of keystream as the new key and+ * nonce, and dropping the old ones, puts that out of reach one step after+ * it is issued: ChaCha20 does not run backwards, and the key that would+ * have been needed is gone. It is what arc4random does.+ *+ * crypton_chacha_init memsets the whole context, so the counter returns to+ * zero and the tail of a part-used block goes with the old key rather than+ * being handed out under the new one.+ *+ * d->used is not touched. It counts what callers were given, which is what+ * the reseed interval is written in terms of; these forty bytes are the+ * cost of the rekey and not an answer to anybody.+ */+static void drg_rekey(drg_t *d)+{+ uint8_t next[SEED_LEN];++ crypton_chacha_generate(next, &d->ctx, SEED_LEN);+ crypton_chacha_init(&d->ctx, CHACHA_ROUNDS, SEED_KEY, next,+ SEED_IV, next + SEED_KEY);+ scrub(next, sizeof next);+}++static int drg_stale(const drg_t *d, uint64_t limit)+{+ return !d->seeded || d->used >= limit || d->generation != fork_generation;+}++/* Bytes from the process DRBG, which is only ever asked for seed material. */+static int global_bytes(uint8_t *out, uint32_t len)+{+ int ok = 1;++#ifdef _WIN32+ EnterCriticalSection(&global_lock);+#else+ pthread_mutex_lock(&global_lock);+#endif+ if (drg_stale(&global_drg, CRYPTON_GLOBAL_RESEED)) {+ uint8_t seed[SEED_LEN];+ ok = seed_from_system(seed);+ if (ok)+ drg_seed(&global_drg, seed);+ scrub(seed, sizeof seed);+ }+ if (ok) {+ crypton_chacha_generate(out, &global_drg.ctx, len);+ global_drg.used += len;+ drg_rekey(&global_drg);+ }+#ifdef _WIN32+ LeaveCriticalSection(&global_lock);+#else+ pthread_mutex_unlock(&global_lock);+#endif+ return ok;+}++#ifdef _WIN32+static void WINAPI thread_free(void *p)+#else+static void thread_free(void *p)+#endif+{+ if (p) {+ scrub(p, sizeof(drg_t));+ free(p);+ }+}++#ifndef _WIN32+/* All three handlers, not just the child's. The child's first draw has to+ * reseed -- the generation has changed -- and reseeding takes global_lock.+ * A fork made while another thread held it would hand the child a mutex+ * locked by a thread that did not come across, and the child would wait on+ * it for ever. So the lock is taken before the fork and released on both+ * sides of it, which is the state the child needs it in. */+static void before_fork(void)+{+ pthread_mutex_lock(&global_lock);+}++static void after_fork_in_parent(void)+{+ pthread_mutex_unlock(&global_lock);+}++static void after_fork_in_child(void)+{+ pthread_mutex_unlock(&global_lock);+ fork_generation++;+}+#endif++#ifdef CRYPTON_SYSDRG_TESTING+/* For cbits/tests/sysdrg and nothing else: hold and release the process+ * generator's lock, so that a fork can be made to happen while another+ * thread holds it. Nothing outside that test declares these, and the+ * library is never built with this defined. */+void crypton_sysdrg_test_lock(void);+void crypton_sysdrg_test_unlock(void);++static drg_t *this_thread(void);++/* The calling thread's ChaCha key, which is d[4..11] of the state. A test+ * uses it to ask whether the key that produced a draw is still there+ * afterwards; see "a draw replaces the key that made it" in+ * cbits/tests/sysdrg. */+void crypton_sysdrg_test_key(uint8_t out[32]);++void crypton_sysdrg_test_key(uint8_t out[32])+{+ drg_t *d = this_thread();+ int i;++ if (!d)+ return;+ for (i = 0; i < 8; i++) {+ uint32_t w = d->ctx.st.d[4 + i];+ out[i * 4 + 0] = (uint8_t) (w);+ out[i * 4 + 1] = (uint8_t) (w >> 8);+ out[i * 4 + 2] = (uint8_t) (w >> 16);+ out[i * 4 + 3] = (uint8_t) (w >> 24);+ }+}++void crypton_sysdrg_test_lock(void)+{+#ifndef _WIN32+ pthread_mutex_lock(&global_lock);+#endif+}++void crypton_sysdrg_test_unlock(void)+{+#ifndef _WIN32+ pthread_mutex_unlock(&global_lock);+#endif+}+#endif++#ifdef _WIN32+static BOOL CALLBACK init_slot(PINIT_ONCE o, PVOID p, PVOID *c)+{+ (void) o; (void) p; (void) c;+ InitializeCriticalSection(&global_lock);+ thread_slot = FlsAlloc(thread_free);+ return TRUE;+}+#else+static void init_slot(void)+{+ pthread_key_create(&thread_slot, thread_free);+ pthread_atfork(before_fork, after_fork_in_parent, after_fork_in_child);+}+#endif++static drg_t *this_thread(void)+{+ drg_t *d;++#ifdef _WIN32+ InitOnceExecuteOnce(&init_once, init_slot, NULL, NULL);+ if (thread_slot == FLS_OUT_OF_INDEXES)+ return NULL;+ d = (drg_t *) FlsGetValue(thread_slot);+#else+ pthread_once(&init_once, init_slot);+ d = (drg_t *) pthread_getspecific(thread_slot);+#endif+ if (!d) {+ d = (drg_t *) calloc(1, sizeof(drg_t));+ if (!d)+ return NULL;+#ifdef _WIN32+ if (!FlsSetValue(thread_slot, d)) {+ free(d);+ return NULL;+ }+#else+ if (pthread_setspecific(thread_slot, d) != 0) {+ free(d);+ return NULL;+ }+#endif+ }+ return d;+}++/* Returns the number of bytes written, which is len unless there was no+ * seed to be had -- and then it is 0, so that the caller can say so rather+ * than hand back a buffer it cannot vouch for. */+int crypton_sysdrg_bytes(uint8_t *out, int len)+{+ drg_t *d;++ if (len < 0)+ return 0;+ d = this_thread();+ if (!d)+ return 0;++ if (drg_stale(d, CRYPTON_THREAD_RESEED)) {+ uint8_t seed[SEED_LEN];+ int ok = global_bytes(seed, SEED_LEN);+ if (ok)+ drg_seed(d, seed);+ scrub(seed, sizeof seed);+ if (!ok)+ return 0;+ }++ crypton_chacha_generate(out, &d->ctx, (uint32_t) len);+ d->used += (uint64_t) len;+ drg_rekey(d);+ return len;+}++/* For the tests: how many times the process has been seen to fork. */+uint32_t crypton_sysdrg_generation(void)+{+ return fork_generation;+}++/* For the tests: bytes this thread's generator has produced since it was+ * last seeded. A generator shared between threads would carry the first+ * thread's count into the second; a per-thread one starts again at zero,+ * and that is the only way from outside to tell the two apart. */+uint64_t crypton_sysdrg_thread_used(void)+{+ drg_t *d = this_thread();+ return d ? d->used : 0;+}
@@ -0,0 +1,119 @@+/*+ * The kernel's own random number generator, reached without a file+ * descriptor: getrandom(2) on Linux and FreeBSD, getentropy(3) on the+ * systems that have that instead.+ *+ * This is preferred over reading /dev/urandom because it needs no path and+ * no descriptor, so it still works where /dev is not mounted or not+ * populated -- a minimal container, a chroot, a sandbox -- and it cannot be+ * defeated by exhausting the descriptor table.+ *+ * Availability is decided at run time as well as at compile time: a binary+ * built against headers that declare getrandom can still run on a kernel+ * that does not implement it, and says so with ENOSYS.+ */++#include <stddef.h>+#include <stdint.h>+#include <errno.h>++#if defined(__linux__)+#include <unistd.h>+#include <sys/syscall.h>+#ifdef SYS_getrandom+#define CRYPTON_SYSRANDOM_GETRANDOM 1+#endif+#elif defined(__FreeBSD__)+#include <sys/param.h>+#if __FreeBSD_version >= 1200000+#include <sys/random.h>+#define CRYPTON_SYSRANDOM_GETRANDOM 1+#endif+#elif defined(__APPLE__)+/* getentropy(3) is declared in sys/random.h on Darwin, since 10.12 -- but+ * macOS only. Crypto.Random says iOS does not allow it, which is why that+ * platform builds with INSECURE_ENTROPY; until someone can try it there,+ * iOS keeps the path it has rather than gaining an untested one. */+#include <TargetConditionals.h>+#if defined(TARGET_OS_OSX) && TARGET_OS_OSX+#include <sys/random.h>+#define CRYPTON_SYSRANDOM_GETENTROPY 1+#endif+#elif defined(__OpenBSD__)+#include <unistd.h>+#define CRYPTON_SYSRANDOM_GETENTROPY 1+#elif defined(__NetBSD__)+#include <sys/param.h>+#if __NetBSD_Version__ >= 1000000000+#include <sys/random.h>+#define CRYPTON_SYSRANDOM_GETENTROPY 1+#endif+#endif++/* getentropy(3) refuses more than 256 bytes in one call. */+#define CRYPTON_GETENTROPY_MAX 256++#if defined(CRYPTON_SYSRANDOM_GETRANDOM)++static int sysrandom_once(uint8_t *buf, size_t n)+{+#if defined(__linux__)+ return (int) syscall(SYS_getrandom, buf, n, 0);+#else+ return (int) getrandom(buf, n, 0);+#endif+}++#elif defined(CRYPTON_SYSRANDOM_GETENTROPY)++static int sysrandom_once(uint8_t *buf, size_t n)+{+ if (n > CRYPTON_GETENTROPY_MAX)+ n = CRYPTON_GETENTROPY_MAX;+ if (getentropy(buf, n) != 0)+ return -1;+ return (int) n;+}++#else++static int sysrandom_once(uint8_t *buf, size_t n)+{+ (void) buf; (void) n;+ errno = ENOSYS;+ return -1;+}++#endif++/* Is the call there, on this kernel, right now? A zero-length request+ * answers that without consuming anything. */+int crypton_sysrandom_available(void)+{+ uint8_t b;+ int r = sysrandom_once(&b, 0);+ return r < 0 ? 0 : 1;+}++/* Fill the buffer. Returns the number of bytes written, which is n unless+ * the call failed for a reason other than being interrupted. */+int crypton_sysrandom_bytes(uint8_t *buf, int len)+{+ size_t n = (size_t) len;+ size_t done = 0;++ if (len < 0)+ return 0;+ while (done < n) {+ int r = sysrandom_once(buf + done, n - done);+ if (r < 0) {+ if (errno == EINTR)+ continue;+ break;+ }+ if (r == 0)+ break;+ done += (size_t) r;+ }+ return (int) done;+}
@@ -306,7 +306,9 @@ ctx->h[2] = 0xf096a5b4c3b2e187ULL; } -static inline void tiger_do_chunk(struct tiger_ctx *ctx, uint64_t *buf)+/* The words are read out of the block rather than the block being pointed at+ * as though it were an array of them; see crypton_md5.c. */+static inline void tiger_do_chunk(struct tiger_ctx *ctx, const uint8_t *buf) { uint64_t x0, x1, x2, x3, x4, x5, x6, x7; uint64_t a,b,c;@@ -314,8 +316,8 @@ b = ctx->h[1]; c = ctx->h[2]; - x0 = cpu_to_le64(buf[0]); x1 = cpu_to_le64(buf[1]); x2 = cpu_to_le64(buf[2]); x3 = cpu_to_le64(buf[3]);- x4 = cpu_to_le64(buf[4]); x5 = cpu_to_le64(buf[5]); x6 = cpu_to_le64(buf[6]); x7 = cpu_to_le64(buf[7]);+ x0 = load_le64(buf ); x1 = load_le64(buf + 8); x2 = load_le64(buf + 16); x3 = load_le64(buf + 24);+ x4 = load_le64(buf + 32); x5 = load_le64(buf + 40); x6 = load_le64(buf + 48); x7 = load_le64(buf + 56); #define BYTEOF(c, n) ((uint8_t) (c >> ((n * 8)))) @@ -376,24 +378,15 @@ /* process partial buffer if there's enough data to make a block */ if (index && len >= to_fill) { memcpy(ctx->buf + index, data, to_fill);- tiger_do_chunk(ctx, (uint64_t *) ctx->buf);+ tiger_do_chunk(ctx, ctx->buf); len -= to_fill; data += to_fill; index = 0; } - if (need_alignment(data, 8)) {- uint64_t tramp[8];- ASSERT_ALIGNMENT(tramp, 8);- for (; len >= 64; len -= 64, data += 64) {- memcpy(tramp, data, 64);- tiger_do_chunk(ctx, tramp);- }- } else {- /* process as much 64-block as possible */- for (; len >= 64; len -= 64, data += 64)- tiger_do_chunk(ctx, (uint64_t *) data);- }+ /* No trampoline: load_le64 does not ask for a boundary. */+ for (; len >= 64; len -= 64, data += 64)+ tiger_do_chunk(ctx, data); /* append data into buf */ if (len)
@@ -41,7 +41,7 @@ memset(ctx, 0, sizeof(*ctx)); ctx->nb_rounds = nb_rounds; - /* Create initial 512-bit input block:+ /* Create initial 512-bit input crypton_salsa_block: (x0, x5, x10, x15) is the Salsa20 constant (x1, x2, x3, x4, x11, x12, x13, x14) is a 256-bit key (x6, x7, x8, x9) is the first 128 bits of a 192-bit nonce@@ -56,7 +56,7 @@ void crypton_xsalsa_derive(crypton_salsa_context *ctx, uint32_t ivlen, const uint8_t *iv) {- /* Finish creating initial 512-bit input block:+ /* Finish creating initial 512-bit input crypton_salsa_block: (x6, x7, x8, x9) is the first 128 bits of a 192-bit nonce Except iv has been shifted by 64 bits so there are now only 128 bits ahead.@@ -65,15 +65,15 @@ ctx->st.d[ 9] += load_le32(iv + 4); /* Compute (z0, z1, . . . , z15) = doubleround ^(r/2) (x0, x1, . . . , x15) */- block hSalsa;- memset(&hSalsa, 0, sizeof(block));+ crypton_salsa_block hSalsa;+ memset(&hSalsa, 0, sizeof(crypton_salsa_block)); crypton_salsa_core_xor(ctx->nb_rounds, &hSalsa, &ctx->st); - /* Build a new 512-bit input block (x′0, x′1, . . . , x′15):+ /* Build a new 512-bit input crypton_salsa_block (x′0, x′1, . . . , x′15): (x′0, x′5, x′10, x′15) is the Salsa20 constant (x′1,x′2,x′3,x′4,x′11,x′12,x′13,x′14) = (z0,z5,z10,z15,z6,z7,z8,z9) (x′6,x′7) is the last 64 bits of the 192-bit nonce- (x′8, x′9) is a 64-bit block counter.+ (x′8, x′9) is a 64-bit crypton_salsa_block counter. */ ctx->st.d[ 1] = hSalsa.d[ 0] - ctx->st.d[ 0]; ctx->st.d[ 2] = hSalsa.d[ 5] - ctx->st.d[ 5];
@@ -0,0 +1,88 @@+/*+ * X25519 through the vendored s2n-bignum where it is built, and through+ * curve25519-donna where it is not.+ *+ * The fixed-base routine is the interesting half: crypton had none, and asked+ * for the public key by multiplying the base point 9 the general way. With a+ * table it is four to five times less work, and a TLS handshake generates a+ * key every time. Measured on an Apple M4:+ *+ * donna s2n+ * shared secret 18.15 us 12.35+ * key generation 18.15 3.65+ *+ * and on an x86-64, 41.19 to 26.96 and 41.18 to 8.54.+ */+#include <string.h>++#include "curve25519/x25519.h"++void crypton_curve25519_donna(uint8_t *mypublic, const uint8_t *secret,+ const uint8_t *basepoint);++/* The assembly takes four little-endian 64-bit words, which is the same bits+ * as the 32 little-endian bytes RFC 7748 sends, so the two cross by copying+ * -- on a little-endian machine, which is the only kind s2n-bignum is for. */+#if defined(CRYPTON_S2N_BIGNUM) && defined(__BYTE_ORDER__) \+ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__+#define CRYPTON_X25519_S2N 1+#include "crypton_cpu.h"++extern void curve25519_x25519(uint64_t res[4], const uint64_t scalar[4],+ const uint64_t point[4]);+extern void curve25519_x25519_alt(uint64_t res[4], const uint64_t scalar[4],+ const uint64_t point[4]);+extern void curve25519_x25519base(uint64_t res[4], const uint64_t scalar[4]);+extern void curve25519_x25519base_alt(uint64_t res[4], const uint64_t scalar[4]);++/* The same question as everywhere else in cbits/s2n: a microarchitecture one+ * on ARM that no feature bit answers, and exactly a feature bit on x86-64. */+static int use_alt(void)+{+#if defined(__aarch64__) || defined(__arm64__)+#ifdef __APPLE__+ return 1;+#else+ return 0;+#endif+#else+ return (crypton_x86_simd_features() & CRYPTON_X86_ADX) == 0;+#endif+}+#endif++void crypton_x25519(uint8_t out[32], const uint8_t secret[32],+ const uint8_t point[32])+{+#ifdef CRYPTON_X25519_S2N+ uint64_t r[4], s[4], p[4];++ memcpy(s, secret, 32);+ memcpy(p, point, 32);+ if (use_alt())+ curve25519_x25519_alt(r, s, p);+ else+ curve25519_x25519(r, s, p);+ memcpy(out, r, 32);+#else+ crypton_curve25519_donna(out, secret, point);+#endif+}++void crypton_x25519_base(uint8_t out[32], const uint8_t secret[32])+{+#ifdef CRYPTON_X25519_S2N+ uint64_t r[4], s[4];++ memcpy(s, secret, 32);+ if (use_alt())+ curve25519_x25519base_alt(r, s);+ else+ curve25519_x25519base(r, s);+ memcpy(out, r, 32);+#else+ static const uint8_t nine[32] = {9};++ crypton_curve25519_donna(out, secret, nine);+#endif+}
@@ -0,0 +1,16 @@+#ifndef CRYPTON_X25519_H+#define CRYPTON_X25519_H++#include <stdint.h>++/* out = secret * point, the X25519 of RFC 7748: three 32-byte little-endian+ * strings as they go over the wire. */+void crypton_x25519(uint8_t out[32], const uint8_t secret[32],+ const uint8_t point[32]);++/* out = secret * G, which is the same thing with the base point 9 -- but+ * where the assembly is built this reads a table instead and is four to five+ * times faster, which is what a key generation costs. */+void crypton_x25519_base(uint8_t out[32], const uint8_t secret[32]);++#endif
@@ -1462,7 +1462,10 @@ uint32_t pos = __builtin_ctz((uint32_t)current), odd = (uint32_t)current >> pos; int32_t delta = odd & mask; if (odd & 1<<(table_bits+1)) delta -= (1<<(table_bits+1));- current -= delta << pos;+ /* delta is negative half the time and shifting a negative+ * value left is undefined; current is unsigned, so the shift is+ * done there and means the same thing. */+ current -= (uint64_t)delta << pos; control[position].power = pos + 16*(w-1); control[position].addend = delta; position--;
@@ -68,7 +68,7 @@ * Expand bit 0 of the given uint8_t to a mask_t all 1 or all 0 * The input must be either 0 or 1 */-CRYPTON_DECAF_INLINE mask_t bit_to_mask(uint8_t bit) {+static CRYPTON_DECAF_INLINE mask_t bit_to_mask(uint8_t bit) { #ifdef _MSC_VER #pragma warning ( push) #pragma warning ( disable : 4146)
@@ -12,8 +12,33 @@ #include "ed25519-randombytes.h" #include "ed25519-hash.h" #include "ed25519-crypton-exts.h"+#include "ed25519/ed25519_s2n.h" /*+ The base point multiplied by a scalar, packed. s2n-bignum's assembly+ where it is built -- twice the speed of the table below, and signing+ does this twice -- and ed25519-donna's own table where it is not.+*/+static void+ed25519_base_pack(ed25519_public_key out, const bignum256modm s) {+ ge25519 ALIGN(16) p;++#if defined(CRYPTON_S2N_BIGNUM) && defined(__BYTE_ORDER__) \+ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__+ unsigned char e[32];++ contract256_modm(e, s);+ if (crypton_ed25519_base_mult(out, e)) {+ memset(e, 0, sizeof e);+ return;+ }+ memset(e, 0, sizeof e);+#endif+ ge25519_scalarmult_base_niels(&p, ge25519_niels_base_multiples, s);+ ge25519_pack(out, &p);+}++/* Generates a (extsk[0..31]) and aExt (extsk[32..63]) */ @@ -38,14 +63,12 @@ void ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key pk) { bignum256modm a;- ge25519 ALIGN(16) A; hash_512bits extsk; /* A = aB */ ed25519_extsk(extsk, sk); expand256_modm(a, extsk, 32);- ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a);- ge25519_pack(pk, &A);+ ed25519_base_pack(pk, a); } @@ -53,7 +76,6 @@ ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) { ed25519_hash_context ctx; bignum256modm r, S, a;- ge25519 ALIGN(16) R; hash_512bits extsk, hashr, hram; ed25519_extsk(extsk, sk);@@ -66,8 +88,7 @@ expand256_modm(r, hashr, 64); /* R = rB */- ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r);- ge25519_pack(RS, &R);+ ed25519_base_pack(RS, r); /* S = H(R,A,m).. */ ed25519_hram(hram, RS, pk, m, mlen);
@@ -0,0 +1,65 @@+/*+ * Ed25519's base point multiplication through the vendored s2n-bignum.+ *+ * Signing does this twice: once for the nonce's point R, and once for the+ * public key, which crypton derives from the secret key at every signature+ * rather than trusting the one it is handed. Both go through here, so both+ * halves of a signature move at once.+ *+ * Measured on an Apple M4, one multiplication with the encoding:+ * ed25519-donna 7.5 us against s2n-bignum 3.5.+ */+#include <string.h>++#include "ed25519/ed25519_s2n.h"++#if defined(CRYPTON_S2N_BIGNUM) && defined(__BYTE_ORDER__) \+ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__+#define CRYPTON_ED25519_S2N 1+#include "crypton_cpu.h"++extern void edwards25519_scalarmulbase(uint64_t res[8],+ const uint64_t scalar[4]);+extern void edwards25519_scalarmulbase_alt(uint64_t res[8],+ const uint64_t scalar[4]);+extern void edwards25519_encode(uint8_t z[32], const uint64_t p[8]);++/* The same question as everywhere else in cbits/s2n: a microarchitecture one+ * on ARM that no feature bit answers, and exactly a feature bit on x86-64. */+static int use_alt(void)+{+#if defined(__aarch64__) || defined(__arm64__)+#ifdef __APPLE__+ return 1;+#else+ return 0;+#endif+#else+ return (crypton_x86_simd_features() & CRYPTON_X86_ADX) == 0;+#endif+}+#endif++int crypton_ed25519_base_mult(uint8_t out[32], const uint8_t scalar[32])+{+#ifdef CRYPTON_ED25519_S2N+ /* the assembly takes four little-endian 64-bit words, which is the+ * same bits as the 32 little-endian bytes the scalar is kept in */+ uint64_t s[4], p[8];++ memcpy(s, scalar, 32);+ if (use_alt())+ edwards25519_scalarmulbase_alt(p, s);+ else+ edwards25519_scalarmulbase(p, s);+ edwards25519_encode(out, p);++ memset(s, 0, sizeof s);+ memset(p, 0, sizeof p);+ return 1;+#else+ (void) out;+ (void) scalar;+ return 0;+#endif+}
@@ -0,0 +1,14 @@+#ifndef CRYPTON_ED25519_S2N_H+#define CRYPTON_ED25519_S2N_H++#include <stdint.h>++/* The base point multiplied by a scalar, packed into Ed25519's 32-byte+ * encoding. The scalar is 32 little-endian bytes, already reduced.+ *+ * Returns 1 when the vendored s2n-bignum did the work and 0 when it is not+ * built, in which case the caller multiplies the base point itself.+ */+int crypton_ed25519_base_mult(uint8_t out[32], const uint8_t scalar[32]);++#endif
@@ -83,16 +83,9 @@ const crypton_p256_int* b, crypton_p256_int* c); -// b := 1 / a % MOD-// MOD best be SECP256r1_n-void crypton_p256_modinv(- const crypton_p256_int* MOD,- const crypton_p256_int* a,- crypton_p256_int* b);--// b := 1 / a % MOD+// b := 1 / a % MOD, in time that depends on a // MOD best be SECP256r1_n-// Faster than crypton_p256_modinv()+// Answers zero for an a that has no inverse, which is zero and MOD void crypton_p256_modinv_vartime( const crypton_p256_int* MOD, const crypton_p256_int* a,@@ -130,13 +123,6 @@ void crypton_p256_base_point_mul(const crypton_p256_int *n, crypton_p256_int *out_x, crypton_p256_int *out_y);--// {out_x,out_y} := n{in_x,in_y}-void crypton_p256_point_mul(const crypton_p256_int *n,- const crypton_p256_int *in_x,- const crypton_p256_int *in_y,- crypton_p256_int *out_x,- crypton_p256_int *out_y); // {out_x,out_y} := n1G + n2{in_x,in_y} void crypton_p256_points_mul_vartime(
@@ -76,6 +76,13 @@ 0 }; static const felem kZero = {0};++/* the curve's b, in Montgomery form, for the complete addition formula */+static const felem kB = {+ 0x13897bbf, 0x9cdf622, 0x43090d8, 0x2e67c4,+ 0x176b5678, 0x2afdc84, 0xd196888, 0xb090e90,+ 0xb8600c3+}; static const felem kP = { 0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff, 0, 0, 0x200000, 0xf000000,@@ -86,96 +93,99 @@ 0, 0, 0x400000, 0xe000000, 0x1fffffff };-/* kPrecomputed contains precomputed values to aid the calculation of scalar- * multiples of the base point, G. It's actually two, equal length, tables- * concatenated.+/* kPrecomputed holds the multiples of the base point G that the comb in+ * scalar_base_mult reads. Two tables of sixteen affine points, one after the+ * other. *- * The first table contains (x,y) felem pairs for 16 multiples of the base- * point, G.+ * The comb takes five bits of the signed all-bits-set representation at a+ * time, from positions 52 apart, and the two tables are offset from each+ * other by 26: *- * Index | Index (binary) | Value- * 0 | 0000 | 0G (all zeros, omitted)- * 1 | 0001 | G- * 2 | 0010 | 2**64G- * 3 | 0011 | 2**64G + G- * 4 | 0100 | 2**128G- * 5 | 0101 | 2**128G + G- * 6 | 0110 | 2**128G + 2**64G- * 7 | 0111 | 2**128G + 2**64G + G- * 8 | 1000 | 2**192G- * 9 | 1001 | 2**192G + G- * 10 | 1010 | 2**192G + 2**64G- * 11 | 1011 | 2**192G + 2**64G + G- * 12 | 1100 | 2**192G + 2**128G- * 13 | 1101 | 2**192G + 2**128G + G- * 14 | 1110 | 2**192G + 2**128G + 2**64G- * 15 | 1111 | 2**192G + 2**128G + 2**64G + G+ * first table i, 52+i, 104+i, 156+i, 208+i+ * second table 26+i, 78+i, 130+i, 182+i, 234+i *- * The second table follows the same style, but the terms are 2**32G,- * 2**96G, 2**160G, 2**224G.+ * for i from 25 down to 0, which covers all 260 bits between them. *+ * Every digit of that representation is +-1, so a block of five teeth takes+ * one of thirty-two values -- and they come in pairs that differ only by+ * sign. So sixteen entries are enough: the top tooth is taken positive, bit+ * j of the index says that tooth j agrees with it, and where the top tooth is+ * negative the caller negates y, which costs a subtraction. Entry zero is a+ * point like any other here, unlike the unsigned table this replaces, where+ * it stood for the infinity.+ *+ * Index | Index (binary) | Value+ * 0 | 0000 | 2**208G - 2**156G - 2**104G - 2**52G - G+ * 1 | 0001 | 2**208G - 2**156G - 2**104G - 2**52G + G+ * ... | ... | ...+ * 15 | 1111 | 2**208G + 2**156G + 2**104G + 2**52G + G+ * * This is ~2KB of data. */-static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = {- 0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee,- 0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3,- 0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c,- 0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22,- 0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050,- 0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b,- 0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa,- 0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2,- 0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609,- 0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581,- 0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca,- 0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33,- 0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6,- 0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd,- 0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0,- 0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881,- 0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a,- 0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26,- 0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b,- 0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023,- 0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133,- 0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa,- 0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29,- 0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc,- 0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8,- 0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59,- 0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39,- 0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689,- 0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa,- 0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3,- 0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1,- 0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f,- 0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72,- 0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d,- 0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b,- 0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a,- 0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a,- 0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f,- 0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb,- 0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc,- 0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9,- 0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce,- 0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2,- 0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca,- 0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229,- 0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57,- 0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c,- 0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa,- 0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651,- 0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec,- 0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7,- 0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c,- 0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927,- 0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298,- 0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8,- 0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2,- 0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d,- 0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4,- 0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8,- 0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78,+static const limb kPrecomputed[NLIMBS * 2 * 16 * 2] = {+ 0xe01bd76, 0xa0be8b3, 0x8494c1d, 0x609ab3d, 0x1188042f, 0x499c03d, 0x1df7cd26, 0x51b33c5, 0x1fb3bce,+ 0x39cdd45, 0xdc0dd9b, 0xe3053d7, 0x1ffaf46, 0x9ac284a, 0xac051d4, 0x1c09fe1b, 0x8227cbf, 0x5bf049b,+ 0xb9487d, 0x2ecb75f, 0x194825bf, 0xd70cf28, 0x14e528f3, 0x4d8670c, 0x35bbabb, 0x6b692ca, 0xd96d08,+ 0x1db081dc, 0xa87ea7b, 0x190e5549, 0xa4cf420, 0x1e151385, 0xaf3d4bd, 0x4057e9f, 0x5078feb, 0x154519a,+ 0xbf15dea, 0x453fa25, 0x1171c85a, 0x576c824, 0x154e7060, 0x71ede6e, 0x160467a2, 0xdea8a44, 0x81ffcb1,+ 0x61a56fa, 0x76119b9, 0x110bfb9b, 0x3d527ea, 0x1997bdb4, 0xe1d1253, 0x180ce91c, 0x11950ee, 0x53d5938,+ 0x694e7c9, 0xe0cf337, 0x16d8ae50, 0x202517f, 0x4d02e16, 0xd13b5fd, 0xfae97eb, 0xa1c7f60, 0x1206fe8,+ 0x11b1c908, 0xf8a82f, 0x6ab17a0, 0x48058e8, 0x2d0feb, 0xfada550, 0x658edb9, 0xa17567a, 0x8daa44d,+ 0x6361dc9, 0xec00c0e, 0x151a7b1c, 0xb35a683, 0x1643fe02, 0x70155c0, 0x1f131d45, 0x3998068, 0x25beef8,+ 0x88138de, 0x8995ce4, 0x18565c50, 0x60f12b6, 0xc47a656, 0x4a82bd9, 0xb547a17, 0xb333474, 0xe86513a,+ 0x7f8d2bc, 0x7f0f16c, 0x8cde475, 0x1ac3d5c, 0x1a832c9a, 0x6a93e7a, 0x19833281, 0xcec82db, 0x4f08cc,+ 0x72c4394, 0x4686520, 0x1e845ce, 0xfb181a1, 0xf5135a5, 0xa1265d6, 0x6c63ce8, 0xe81797e, 0x5dbcd5a,+ 0x2a5d603, 0x1ad4e91, 0xc86e1b3, 0x793abea, 0x1b8610a4, 0x8d5b975, 0x74dd850, 0xbbca81, 0xd7c35d8,+ 0x1bab7afc, 0x4df749, 0x4acb4ea, 0xfae8c89, 0x14552ae5, 0x6dc1c20, 0x14f629f, 0x2368fe5, 0xe5a9cba,+ 0x67576f7, 0x9c77c50, 0x1d63c92a, 0xbbb9ef8, 0xa7530d4, 0x963335, 0xfa09c54, 0xb6d03e3, 0xed1a022,+ 0x19c59f49, 0x45c823d, 0x17a28df1, 0x80ae516, 0xe2ada82, 0x19b97fb, 0x13a9ebf, 0xf1e7606, 0xde03632,+ 0x14e318b9, 0x7b57b83, 0x51a9a92, 0x3378a17, 0x1cde9289, 0x45956c2, 0x2bbab5e, 0x780b1f5, 0x8356034,+ 0x75eca28, 0x6f39648, 0xf2fdbda, 0x4c65cd9, 0xb3759e7, 0x710c0b1, 0xda24432, 0x8d236aa, 0xf4c449f,+ 0xaf9ba24, 0xb83ea7f, 0x1e46ecc3, 0x3f277b0, 0x6acdecd, 0x1f597d1, 0x8483d72, 0x57d29dd, 0x66d4060,+ 0x167c14af, 0xc142ded, 0xc1689ca, 0x651aa52, 0x8d05768, 0x9709cfa, 0x165fd283, 0x9f6f583, 0x9833b54,+ 0xd17e2d6, 0x2915c32, 0x1970ef24, 0xe8ca45b, 0x11c29e09, 0x8121f26, 0xb5afbe1, 0x10c80ec, 0x834a25c,+ 0xa37f0b0, 0xd6bac16, 0xed484fc, 0x8799206, 0x13db8bb1, 0xdce615c, 0x13320329, 0x79dc25, 0x914e7af,+ 0x860a414, 0xb8a9434, 0x50396ce, 0x902d3e6, 0x15c152f3, 0x3753c64, 0x970c055, 0xba296fb, 0x64bd63b,+ 0x118cbb94, 0x9d4274f, 0x121cdbfe, 0xb9137cf, 0xc8bddf1, 0xa1598d0, 0x446ab41, 0x11f1df2, 0x68115f1,+ 0x2f1f708, 0xee35192, 0x1dfeb3fc, 0x4e1e1a6, 0x1d9adcbb, 0x6688662, 0x63ad21b, 0x9d9a9e1, 0xb0f8b4b,+ 0xcd8bc3a, 0x3577d8, 0x1ffcb97d, 0xd31e8d6, 0x1c776310, 0x95b4ef7, 0x185a82ed, 0xe40bbb0, 0xbca1ea,+ 0x19462e0b, 0x2252179, 0x14f14f09, 0x565e68d, 0x7ba5f37, 0x4cd1858, 0x167941b3, 0x4d1c7a7, 0x7aef1ab,+ 0x1599efe9, 0x658e78d, 0x1ad33917, 0x7e74797, 0x19152edc, 0xdf7dc18, 0xdf677c, 0x9315d96, 0x4ba8eec,+ 0xc45cd82, 0x1acfa03, 0xe265b49, 0xcfa6eb, 0x89d7619, 0x7b05, 0x1ba11068, 0xe1672d3, 0x655622a,+ 0x1607ca6, 0x339049, 0x5454f70, 0x10edd75, 0x1133ceb7, 0xe3eec39, 0xc263156, 0xeb6ddbe, 0x10360a7,+ 0xfd5f981, 0x47dd502, 0x1e66dbbe, 0x8820b63, 0xeee91ef, 0xffde293, 0xb66325d, 0x3a5a2a, 0x6a2acbb,+ 0x11e949bc, 0xf6a6d57, 0x6b2ca24, 0xad903ec, 0x1e55de0, 0xe7074ed, 0xe681934, 0xea44010, 0xaa490cc,+ 0x512324a, 0x6a5eb00, 0xee5e100, 0xd60a02b, 0x1b89c993, 0x5cffb70, 0xa49030c, 0x405aee, 0xe1b27cc,+ 0x2e73a15, 0x9ca8dc0, 0x781dbff, 0x9fd85e0, 0x1884e4c8, 0x40873f6, 0x32d4b69, 0xf42f753, 0xeaf4c38,+ 0x2802a4c, 0x1283dac, 0x759100a, 0xcb3ba75, 0xf3203d3, 0xf89b8aa, 0x7caa59e, 0x384a60a, 0x37f69e7,+ 0x1e56d569, 0x120c552, 0x181734aa, 0x4fcd9b4, 0x7918e4e, 0xcd7938a, 0x2bbd8b2, 0x19f4f97, 0xa7af533,+ 0xbb69948, 0x3eff33e, 0x1f3ac118, 0x3739770, 0x58898fd, 0x623fafb, 0xa7e6d93, 0xd31a676, 0x615192d,+ 0xf543d28, 0xe61ce5a, 0x10ae4b39, 0xcd5a8d7, 0x1b34c6de, 0x81997ad, 0x198e2093, 0xd9b6ff7, 0x9a5954f,+ 0x16782589, 0xed3c1ab, 0x62dc4a5, 0xac12d0c, 0x8bc8b7c, 0x168ec4e, 0x177e11dc, 0x407df09, 0x4056e85,+ 0x9858305, 0xfe445e9, 0x18b1230a, 0x815ee9f, 0xa852eb4, 0x89444e0, 0x1a83481, 0x479359b, 0x2192576,+ 0x16d5e61b, 0xfe480c4, 0x1d60b8b7, 0x1c6e798, 0x1a01310, 0x9998572, 0x7c59f75, 0x49dda87, 0xe75e0b6,+ 0x1b2b7536, 0xb267d8, 0x15443085, 0x45e5924, 0x7fb947f, 0x296915d, 0x38fc56b, 0x4bae39f, 0xb218e7c,+ 0x115c3b16, 0x9d95f0c, 0xa50ac4c, 0xcce8037, 0xc3c7ba3, 0xf02773a, 0xbc2ad54, 0x26914c1, 0x19a4b8d,+ 0x3f8a1a6, 0xa0b8459, 0x1f77a521, 0x7d93297, 0x1dddb4b2, 0x9e4cd1c, 0x6e28403, 0xd7ce413, 0x5575b62,+ 0x12bb7dc1, 0xbdfb15e, 0xa542867, 0xe943d3e, 0x1367fbdd, 0x37b387, 0x14e4d75f, 0xb90b09d, 0xbf6ec28,+ 0xa5182c8, 0x1e5b34e, 0xabe4602, 0x1c13efa, 0x8d1182, 0x1c2947a, 0x1e04e0e3, 0x6caecdb, 0x40f14e8,+ 0x1b845e4a, 0xa9fb149, 0xb34f513, 0x3a0fdbb, 0xfad2335, 0x5bb9342, 0x18c5ad62, 0xc97fdc3, 0x31225c7,+ 0xb28a9ee, 0x585915, 0x1e355da1, 0x26ed08e, 0xc7d06a, 0xa65f219, 0x1fdf45cd, 0xc8323ea, 0x297b9ee,+ 0x1c031098, 0x9c39cf0, 0x1287d79f, 0x69a9e32, 0x10015650, 0x1c3dfc3, 0x12dcd848, 0x3155a59, 0xeff3212,+ 0x1a6ecdd0, 0xd26bd07, 0x18e077ab, 0x442b477, 0x46b735f, 0x495d60c, 0x1b57a6e5, 0x76a368a, 0xf53bd50,+ 0xf12c5e0, 0x80a9b4, 0x15562060, 0x4102113, 0xa144ab5, 0x5fa4e9, 0x1009f5e9, 0xe34343a, 0x26fda5a,+ 0x159e06a4, 0x5fa3aad, 0x10259b5f, 0xa69947d, 0x1190417e, 0x987da3f, 0x14e1e868, 0xdcb7e1e, 0x8890f9f,+ 0x14dece80, 0x94bbf5c, 0x18513a17, 0x4ca31ca, 0xc0a2713, 0xbc46074, 0x1536f6a5, 0x43991aa, 0xb9f8f1c,+ 0x987ba48, 0xb0829ae, 0xd29d324, 0x6339c35, 0x18ace0a4, 0x5d53b55, 0xff829f4, 0xe882ecf, 0xc05164c,+ 0x6bd6bba, 0x9dfc14f, 0x1981cab3, 0xcfebf18, 0x1ddac868, 0x94ec6d4, 0x5abd4b, 0x737fdb3, 0x18f531f,+ 0xd3c2a71, 0x337178f, 0x9f7c32e, 0xd9d7fda, 0x137d191f, 0xdd0757b, 0x14b6d65, 0x179f37a, 0x67b10e1,+ 0x1bfb2cfd, 0xfe4ca43, 0x1fee2930, 0x98c2aa0, 0x9826788, 0xeaf4ceb, 0x17a6be82, 0xc899ed1, 0x500fb01,+ 0x10918e6f, 0x36179ed, 0xbca6643, 0x2d80942, 0xf1ef61, 0xadca21c, 0xbe5b3a7, 0xadae157, 0x12daac,+ 0x1337dda8, 0x6326e5d, 0x2738e1b, 0x5cb5c54, 0x98ec8a0, 0x252647d, 0x1d5c173c, 0xbdf848d, 0x9e5217b,+ 0x1d64f447, 0xb71d1a, 0xb2c2360, 0xccb6bee, 0x1245995e, 0x94a9130, 0x5b93d91, 0x76c57ff, 0xeaa91d1,+ 0x3941881, 0xc2aafbd, 0x1c0540d0, 0x1a938f0, 0x1304b724, 0x8524e10, 0x1bef780f, 0xbc0ea48, 0xbe90dae,+ 0x1d10d5d8, 0xca979e2, 0x10db5cc4, 0x54e2493, 0x44d38f3, 0xbcb73b, 0x12dcff4, 0xd0ab219, 0xde69db2,+ 0x13594366, 0xc30e05f, 0xfc245d4, 0x8c5b52f, 0x81901c7, 0xa9d1e03, 0x11ead62e, 0xb7be89b, 0xc9c8486,+ 0x132a6fa0, 0x56af9b8, 0x41cb561, 0xf74418c, 0x141c461a, 0xbc18514, 0x1d6bbb68, 0x96d43c2, 0x7108696 };
@@ -83,16 +83,9 @@ const crypton_p256_int* b, crypton_p256_int* c); -// b := 1 / a % MOD-// MOD best be SECP256r1_n-void crypton_p256_modinv(- const crypton_p256_int* MOD,- const crypton_p256_int* a,- crypton_p256_int* b);--// b := 1 / a % MOD+// b := 1 / a % MOD, in time that depends on a // MOD best be SECP256r1_n-// Faster than crypton_p256_modinv()+// Answers zero for an a that has no inverse, which is zero and MOD void crypton_p256_modinv_vartime( const crypton_p256_int* MOD, const crypton_p256_int* a,@@ -130,13 +123,6 @@ void crypton_p256_base_point_mul(const crypton_p256_int *n, crypton_p256_int *out_x, crypton_p256_int *out_y);--// {out_x,out_y} := n{in_x,in_y}-void crypton_p256_point_mul(const crypton_p256_int *n,- const crypton_p256_int *in_x,- const crypton_p256_int *in_y,- crypton_p256_int *out_x,- crypton_p256_int *out_y); // {out_x,out_y} := n1G + n2{in_x,in_y} void crypton_p256_points_mul_vartime(
@@ -104,102 +104,111 @@ 2, 0xfc00000000000, 0x7ffffffffffff, 0xfff7fffffffff, 0x7ffff }; static const felem kZero = {0};++/* the curve's b, in Montgomery form, for the complete addition formula */+static const felem kB = {+ 0x1bec453897bbf, 0x33e210c243627, 0x484bb5ab3c017, 0x41a32d11055fb,+ 0x2e18030ec243a+}; static const felem kP = { 0x7ffffffffffff, 0x1fffffffffff, 0, 0x4000000000, 0x3fffffffc0000 }; static const felem k2P = { 0x7fffffffffffe, 0x3fffffffffff, 0, 0x8000000000, 0x7fffffff80000 };-/* kPrecomputed contains precomputed values to aid the calculation of scalar- * multiples of the base point, G. It's actually two, equal length, tables- * concatenated.+/* kPrecomputed holds the multiples of the base point G that the comb in+ * scalar_base_mult reads. Two tables of sixteen affine points, one after the+ * other. *- * The first table contains (x,y) felem pairs for 16 multiples of the base- * point, G.+ * The comb takes five bits of the signed all-bits-set representation at a+ * time, from positions 52 apart, and the two tables are offset from each+ * other by 26: *- * Index | Index (binary) | Value- * 0 | 0000 | 0G (all zeros, omitted)- * 1 | 0001 | G- * 2 | 0010 | 2**64G- * 3 | 0011 | 2**64G + G- * 4 | 0100 | 2**128G- * 5 | 0101 | 2**128G + G- * 6 | 0110 | 2**128G + 2**64G- * 7 | 0111 | 2**128G + 2**64G + G- * 8 | 1000 | 2**192G- * 9 | 1001 | 2**192G + G- * 10 | 1010 | 2**192G + 2**64G- * 11 | 1011 | 2**192G + 2**64G + G- * 12 | 1100 | 2**192G + 2**128G- * 13 | 1101 | 2**192G + 2**128G + G- * 14 | 1110 | 2**192G + 2**128G + 2**64G- * 15 | 1111 | 2**192G + 2**128G + 2**64G + G+ * first table i, 52+i, 104+i, 156+i, 208+i+ * second table 26+i, 78+i, 130+i, 182+i, 234+i *- * The second table follows the same style, but the terms are 2**32G,- * 2**96G, 2**160G, 2**224G.+ * for i from 25 down to 0, which covers all 260 bits between them. *+ * Every digit of that representation is +-1, so a block of five teeth takes+ * one of thirty-two values -- and they come in pairs that differ only by+ * sign. So sixteen entries are enough: the top tooth is taken positive, bit+ * j of the index says that tooth j agrees with it, and where the top tooth is+ * negative the caller negates y, which costs a subtraction. Entry zero is a+ * point like any other here, unlike the unsigned table this replaces, where+ * it stood for the infinity.+ *+ * Index | Index (binary) | Value+ * 0 | 0000 | 2**208G - 2**156G - 2**104G - 2**52G - G+ * 1 | 0001 | 2**208G - 2**156G - 2**104G - 2**52G + G+ * ... | ... | ...+ * 15 | 1111 | 2**208G + 2**156G + 2**104G + 2**52G + G+ * * This is ~2KB of data. */-static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = {- 0x661a831522878, 0xf17fb6d805e79, 0x5889441d6ea57, 0xae33cfdb995bb, 0xc482fbb529ba,- 0x4a6af9d2aac15, 0x90e867917377c, 0x487cc962d2ae3, 0xec2a97443446e, 0x2b8ff8c52c42,- 0x45f8a2d41a576, 0xb06988d2653e4, 0x718b22c357305, 0x33fc920e79d2b, 0x17af34b0fe8db,- 0x38e17eb402f2f, 0x3382558649705, 0x47f6d48f482d1, 0x7bd42488d9b83, 0x3b247c8b86b78,- 0x4d08fc26f7778, 0x7a29a82fb2795, 0x75cd18f90d11a, 0xad8e213b0bc, 0x2d5f0142899e8,- 0x506f98098fb57, 0x2f0c98301e4aa, 0x39b30dd5cf67d, 0x9c146498ab13c, 0xa5db92df5b7b,- 0x184897fc4124a, 0xe3f73a19d8aa, 0x4e1c18e47066b, 0x27b2d4b52eaee, 0x30eac3ea10e99,- 0x4e74546e2e7d5, 0x1f4dde2d97a1d, 0x6ead0f88e1200, 0x7dec87c220f02, 0x3d08ff096310f,- 0x23e5659633ffa, 0x6ec648f08c722, 0x3172a3806ea35, 0xf6e5b681eb3c5, 0x2c3758260f89d,- 0x38dca4fd1da12, 0xf06067b78830d, 0x3194be87a068c, 0x78893c7eb602b, 0xcead60438432,- 0x6ee69a56a67ab, 0xd886f77701895, 0x67b0a4d9cee2b, 0x3586bbf3e4d53, 0x1db6f32921d93,- 0x260756ca4b366, 0x4f40e9d2039fa, 0x4f3f09f5a82bf, 0xccde2d641e8cd, 0x305a30cd2e8c5,- 0x471c235cb5439, 0xab279cd962f5a, 0x17e1fb6e2dd94, 0xfe64589800a77, 0xe8793d99775f,- 0x48c62f4e614aa, 0xbf76ef20eb2a4, 0x669c672556c, 0x24683e0eff056, 0x12252b369ab76,- 0x821de9f162d5, 0xf911ec99a95be, 0x6721f065c906b, 0x58d452035c736, 0x1f9f01a6a15,- 0x6135009b7d8d3, 0xdaeeeb417dfc0, 0x63865fea0ee17, 0x6e0a304b939d6, 0x204ba2076833d,- 0x4ade586f35669, 0x2c1077e34611a, 0x5b1a3bea3b81a, 0xf97d018a22c8b, 0x38d7996b08af8,- 0x6ea62baeb7aa0, 0xebdcbd9ef2670, 0x35dc8fe0df3fe, 0xe458309d20c24, 0x11e87898716a0,- 0x7c44bab7cb456, 0xd64d3cf1bb64, 0x189bff1bf9e66, 0xb5218a049311, 0x285dda6cbcc81,- 0x3238dcafd8c7c, 0x607736c8de0, 0xdb83d99508b1, 0x4e1a0d404cd81, 0x1588008c00ff2,- 0x16b8b36722b27, 0x876609c3f3f1a, 0x66b72ef0e17d6, 0x705f8a279d568, 0x2eaac4cd01fdd,- 0x1171ce9705fe9, 0xffc79cd3264ee, 0x700c8ab4b80f0, 0x208d3d4f57a1, 0x337262a8ca4eb,- 0x297fd01d843fd, 0xa90956fa097f8, 0x529759fdb3845, 0x1d78c5e2d0397, 0x3d6938a4adbf3,- 0x16d5853560b66, 0xf138946b9a430, 0x2ab79f4dea6a0, 0xd42053ee43ae1, 0x3b9c3ef1cf870,- 0x598934ad81baf, 0x5f1821b1d07a7, 0x416bb3a973ff3, 0x23f07bd0a047a, 0x19bdc2e09f786,- 0x56dc9981cd51f, 0xfbace23c8cd65, 0x673bd3bf5b52e, 0x46a95d229fd61, 0xe09ad64bcfb1,- 0xe5292b91f17d, 0xfeefcd8afc287, 0x58f52b0a58711, 0x4800f20c201ef, 0x2084fce608f67,- 0x12ba0b128ae0b, 0x5977ae17030b4, 0x101126ee420f6, 0xf70823495c6bd, 0xde19a27d7770,- 0x5c6ac852260e8, 0x9d22950ac4356, 0x441cca955246c, 0x660a34e5332d9, 0x14ac8ea92f8d2,- 0x6b6d7709f307e, 0x67d7e13879db, 0x2ea8626f9fbbd, 0x99609006a4b40, 0x31bb2a8f8c779,- 0x10c04828ea335, 0xae9acdcbc080a, 0x617af2342607a, 0xc7494ea53e553, 0x2ca9e2872defa,- 0x6c399fab21f1f, 0xab139b245e758, 0x3ad933dcba589, 0x4797fecb08811, 0x31f5dbf8f594,- 0x7dc6361cc7a69, 0xc8a7953ead3f9, 0x79ed693d18015, 0x418a024999a6a, 0x2c4fdc9436aa,- 0x1eb98cb06aa75, 0x2989592796a9c, 0x11194821e425, 0xe27a648228388, 0x35d834b6c12a0,- 0x541807713b532, 0x7ae0a1008aaee, 0x7017a29bcb5e, 0x6b193c23c315c, 0x19bd25ac82f2a,- 0x6a01a43eef294, 0xddf5b5fd84f19, 0x33f5ba081c016, 0xdeb052d1bc082, 0x6b2f06afa617,- 0x7ca1eda6a939f, 0xbdeb35997b50c, 0x47f2d1bccda5, 0xc2ff4adfed667, 0x87712997be4,- 0x21fc2e2b37659, 0xf7d62cd5ed951, 0x27fa9cbdf7efa, 0xba25582bf3a6b, 0x2a42b8bd89398,- 0x6d377d07eecd2, 0x9ca1df5af387, 0x1109e3427e2ba, 0xce4aa4572a19, 0x103baaef71e16,- 0x2c3b2dfde328a, 0xbec4b4a30e1ef, 0x37d92a86204f3, 0x806cfde68eb39, 0x246e2f72b8aa5,- 0x68d3de93462a9, 0x53b8acba6bbc3, 0x2492a70fa1696, 0x38c62d5760f55, 0x15096fe4904f2,- 0x4e44e9bed3e3a, 0xb28bfd79cc9bc, 0x6a77513839320, 0x480dcec6739db, 0x3601b739f2465,- 0x43c348e2a7e1, 0xe448106327879, 0x175d9cae1b0ed, 0xd3b89dee743b8, 0x392d73ca255bc,- 0x32946db0d3a18, 0x9261b09907cc, 0x5ba517a755722, 0x51f24fdaf5184, 0x1cdc732989ed8,- 0x2f7806ba16694, 0xae0c9f029f8d0, 0xd8b45102ce1, 0xca1c7db9316d6, 0x162088a67066f,- 0x39de35b2b4162, 0xa19f550d88ae9, 0x7921b27026cde, 0x94b936b66e900, 0x1023bd5fa17fc,- 0x436837814cfa4, 0x29113492283c4, 0x66d1cdd8b51d8, 0xa540702278eb2, 0x47ef1b29285d,- 0x587b50917e50e, 0xb4cda75bab3b, 0x112520b0a9886, 0x66b9ac16fee49, 0x17bf17e92b2eb,- 0x2456a2f150ed7, 0xfa214412d0280, 0x3ca7dd947fe5b, 0xa72c28598d58a, 0x255d945efc3e,- 0x2873f04e0f215, 0x74178fd1af57b, 0x788848b5b2d6, 0xb1ffafaae0db6, 0x32a1b7b3cbb2a,- 0x4bd9935d6b2da, 0x9c08f24ad30a5, 0x4e58407a80f, 0x1b3a3825a5b17, 0x6547e9fc82f5,- 0x47484aa3656c3, 0x6ee43f341a494, 0x64a98f87adea2, 0x619b3f8e95f01, 0xb6e513266ed8,- 0x421c2a673090, 0xa1c1de32348c7, 0x55b85c3a1e8a3, 0xe05ce8ef330b4, 0x2561e49c15d84,- 0x40aa2d33130fa, 0x12b827d35866f, 0xfe4cf62c8ddb, 0x2fa0ef05bb28d, 0x1c06ca63f1cb8,- 0x32a971863863b, 0xff6fc86830da1, 0x71e7b25a14cf3, 0xea9c5ebb1373a, 0x250bbaa3e1634,- 0x5b5ffeda5b765, 0xf25d2a746331b, 0x115e3a3f43632, 0x67303af43c9d5, 0x14bb538a0e559,- 0x75623687d43b7, 0xa349674a4b38d, 0x613c61829ffc6, 0x689828d8110c7, 0x139115f5af7d5,- 0xf1d856152289, 0x45cbe967168ab, 0x51f38e1680901, 0x34808e8f652b0, 0x1f4a6a921e156,- 0x35dfaf3d8341f, 0xf53ace725cb63, 0x3d86a54eef35b, 0xa103aabaffe2c, 0x2decc36296fbd,- 0x510282be73d6f, 0xd4e6365db206a, 0x4bdc5f5bb8bf3, 0xde7ea32a3aee7, 0x71269e274305,+static const limb kPrecomputed[NLIMBS * 2 * 16 * 2] = {+ 0x17d166e01bd76, 0xd59ea12530768, 0x3d8c40217b04, 0x17bef9a4c9338, 0x7ecef3946ccf,+ 0x1bb3639cdd45, 0xd7a338c14f5f7, 0x1d44d614250ff, 0xff813fc37580a, 0x16fc126e089f2,+ 0x596ebe0b9487d, 0x6794652096fcb, 0x70ca729479eb8, 0x286b775769b0c, 0x365b421ada4b,+ 0xfd4f7db081dc, 0x7a1064395526a, 0x4bdf0a89c2d26, 0xac80afd3f5e7a, 0x551466941e3f,+ 0x27f44abf15dea, 0x641245c721691, 0x66eaa738302bb, 0x12c08cf44e3db, 0x207ff2c77aa29,+ 0x42337261a56fa, 0x93f5442fee6dd, 0x253ccbdeda1ea, 0xbb019d239c3a2, 0x14f564e046543,+ 0x19e66e694e7c9, 0x28bfdb62b9438, 0x5fd268170b101, 0x81f5d2fd7a276, 0x481bfa2871fd,+ 0x71505f1b1c908, 0x2c741aac5e803, 0x55001687f5a40, 0xe8cb1db73f5b4, 0x236a913685d59,+ 0x181c6361dc9, 0xd341d469ec73b, 0x5c0b21ff0159a, 0xa3e263a8ae02a, 0x96fbbe0e6601,+ 0x32b9c888138de, 0x895b615971422, 0x3d9623d32b307, 0xd16a8f42e9505, 0x3a1944eacccd1,+ 0x61e2d87f8d2bc, 0x1eae233791d5f, 0x67ad41964d0d6, 0x6f3066502d527, 0x13c23333b20b,+ 0x50ca4072c4394, 0xc0d087a117391, 0x5d67a89ad2fd8, 0xf8d8c79d1424c, 0x176f356ba05e5,+ 0x5a9d222a5d603, 0xd5f5321b86cc6, 0x175dc308523c9, 0x4e9bb0a11ab7, 0x35f0d7602ef2a,+ 0x1bee93bab7afc, 0x464492b2d3a81, 0x420a2a9572fd7, 0x9429ec53edb83, 0x396a72e88da3f,+ 0xef8a067576f7, 0xcf7c758f24aa7, 0x33553a986a5dd, 0x8df4138a812c6, 0x3b46808adb40f,+ 0x39047b9c59f49, 0x728b5e8a37c51, 0x7fb7156d41405, 0x182753d7e3372, 0x3780d8cbc79d8,+ 0x6af7074e318b9, 0xc50b946a6a49e, 0x6c2e6f494499b, 0xd457756bc8b2a, 0x20d580d1e02c7,+ 0x672c9075eca28, 0x2e6cbcbf6f69b, 0xb159bacf3a63, 0xa9b448864e218, 0x3d31127e348da,+ 0x7d4feaf9ba24, 0x3bd8791bb30ee, 0x7d13566f669f9, 0x750907ae43eb2, 0x19b501815f4a7,+ 0x285bdb67c14af, 0xd529305a272b0, 0x4fa4682bb4328, 0xecbfa5072e13, 0x260ced527dbd6,+ 0x22b864d17e2d6, 0x522de5c3bc90a, 0x7268e14f04f46, 0xb16b5f7c30243, 0x20d2897043203,+ 0x57582ca37f0b0, 0xc9033b5213f35, 0x15c9edc5d8c3c, 0x966640653b9cc, 0x24539ebc1e770,+ 0x152868860a414, 0x69f3140e5b3ae, 0x464ae0a979c81, 0xed2e180aa6ea7, 0x192f58eee8a5b,+ 0x284e9f18cbb94, 0x9be7c8736ffa7, 0xd0645eef8dc8, 0xc888d568342b3, 0x1a0457c447c77,+ 0x46a3242f1f708, 0xf0d377facff3b, 0x662ecd6e5da70, 0x84c75a436cd10, 0x2c3e2d2e766a7,+ 0x6aefb0cd8bc3a, 0xf46b7ff2e5f40, 0x6f7e3bb188698, 0xc30b505db2b69, 0x2f287ab902ee,+ 0x4a42f39462e0b, 0xf346d3c53c248, 0x583dd2f9bab2, 0x9ecf2836699a3, 0x1ebbc6ad3471e,+ 0x31cf1b599efe9, 0xa3cbeb4ce45d9, 0x418c8a976e3f3, 0x581becef9befb, 0x12ea3bb24c576,+ 0x59f406c45cd82, 0xd375b8996d246, 0x30544ebb0c867, 0x4f74220d0000f, 0x195588ab859cb,+ 0x6720921607ca6, 0x6eba95153dc00, 0x439899e75b887, 0xf984c62adc7dd, 0x40d829fadb76,+ 0x7baa04fd5f981, 0x5b1f99b6ef91, 0x29377748f7c41, 0xa96cc64bbffbc, 0x1a8ab2ec0e968,+ 0x54daaf1e949bc, 0x81f61acb2893d, 0x4ed0f2aef056c, 0x41cd03269ce0e, 0x2a924333a9100,+ 0x4bd600512324a, 0x5015bb978401a, 0x370dc4e4c9eb0, 0xb94920618b9ff, 0x386c9f301016b,+ 0x151b802e73a15, 0xc2f01e076ffe7, 0x3f6c4272644fe, 0x4c65a96d2810e, 0x3abd30e3d0bdd,+ 0x507b582802a4c, 0xdd3a9d6440284, 0xaa79901e9e59, 0x28f954b3df137, 0xdfda79ce1298,+ 0x418aa5e56d569, 0x6cda605cd2a84, 0x38a3c8c72727e, 0x5c577b1659af2, 0x29ebd4cc67d3e,+ 0x5fe67cbb69948, 0xcbb87ceb0460f, 0x2fb2c44c7e9b9, 0xd94fcdb26c47f, 0x185464b74c699,+ 0x439cb4f543d28, 0xd46bc2b92ce79, 0x7add9a636f66a, 0xdf31c41270332, 0x2696553f66dbf,+ 0x2783576782589, 0x968618b71297b, 0x44e45e45be560, 0x26efc23b82d1d, 0x1015ba1501f7c,+ 0x488bd29858305, 0xf74fe2c48c2bf, 0x4e0542975a40a, 0x6c35069031288, 0x86495d91e4d6,+ 0x4901896d5e61b, 0x73cc7582e2dff, 0x5720d009880e3, 0x1cf8b3eeb3330, 0x39d782d92776a,+ 0x64cfb1b2b7536, 0x2c925510c2142, 0x15d3fdca3fa2f, 0x7c71f8ad652d2, 0x2c8639f12eb8e,+ 0x32be1915c3b16, 0x401ba942b1327, 0x73a61e3dd1e67, 0x57855aa9e04e, 0x6692e349a453,+ 0x1708b23f8a1a6, 0x994bfdde94868, 0x51ceeeda593ec, 0x4cdc508073c99, 0x155d6d8b5f390,+ 0x3f62bd2bb7dc1, 0x1e9f2950a19ef, 0x3879b3fdeef4a, 0x769c9aebe06f6, 0x2fdbb0a2e42c2,+ 0x4b669ca5182c8, 0x9f7d2af918087, 0x47a04688c10e0, 0x6fc09c1c63852, 0x103c53a1b2bb3,+ 0x3f6293b845e4a, 0x7eddacd3d44ea, 0x3427d6919a9d0, 0xf18b5ac4b772, 0xc48971f25ff7,+ 0x30b22ab28a9ee, 0x684778d576841, 0x219063e835137, 0xabfbe8b9b4cbe, 0xa5ee7bb20c8f,+ 0x739e1c031098, 0x4f194a1f5e7e7, 0x7c3800ab2834d, 0x665b9b090387b, 0x3bfcc848c5569,+ 0x4d7a0fa6ecdd0, 0x5a3be381deaf4, 0x60c235b9afa21, 0x2b6af4dca92ba, 0x3d4ef541da8da,+ 0x15368f12c5e0, 0x1089d55881802, 0x4e950a255aa08, 0xea013ebd20bf4, 0x9bf696b8d0d0,+ 0x74755b59e06a4, 0xca3ec0966d7d7, 0x23f8c820bf534, 0x7a9c3d0d130fb, 0x22243e7f72df8,+ 0x177eb94dece80, 0x18e56144e85e5, 0x746051389a65, 0xaaa6ded4b788c, 0x2e7e3c710e646,+ 0x10535c987ba48, 0xce1ab4a74c92c, 0x355c567052319, 0x3dff053e8baa7, 0x30145933a20bb,+ 0x3f829e6bd6bba, 0x5f8c66072ace7, 0x6d4eed643467f, 0xcc0b57a9729d8, 0x63d4c7dcdff6,+ 0x6e2f1ed3c2a71, 0xbfed27df0cb8c, 0x57b9be8c8fece, 0xe8296dacbba0e, 0x19ec43845e7cd,+ 0x499487bfb2cfd, 0x15507fb8a4c3f, 0x4eb4c133c44c6, 0x46f4d7d05d5e9, 0x1403ec072267b,+ 0x42f3db0918e6f, 0x4a12f29990cd, 0x21c078f7b096c, 0x5d7cb674f5b94, 0x4b6ab2b6b85,+ 0x64dcbb337dda8, 0xae2a09ce386d8, 0x47d4c764502e5, 0x37ab82e784a4c, 0x279485eef7e12,+ 0x6e3a35d64f447, 0xb5f72cb08d802, 0x130922ccaf665, 0xfcb727b232952, 0x3aaa4745db15f,+ 0x555f7a3941881, 0x9c78701503430, 0x6109825b920d4, 0x237def01f0a49, 0x2fa436baf03a9,+ 0x52f3c5d10d5d8, 0x1249c36d73132, 0x73b2269c79aa7, 0x6425b9fe81796, 0x379a76cb42ac8,+ 0x61c0bf3594366, 0xda97bf0917530, 0x60340c80e3c62, 0x6e3d5ac5d53a3, 0x3272121adefa2,+ 0x55f37132a6fa0, 0x20c61072d5855, 0x514a0e230d7ba, 0xbad776d17830, 0x1c421a5a5b50f };
@@ -0,0 +1,25 @@+/*+ * The vendored s2n-bignum assembly, behind one call that picks the variant+ * the machine wants. See cbits/s2n/README.md for which and why.+ *+ * Only declared in the 64-bit field build: s2n-bignum is x86-64 and AArch64+ * only, and this interface is the four little-endian 64-bit words those+ * architectures give crypton_p256_int anyway.+ */+#ifndef CRYPTON_P256_S2N_H+#define CRYPTON_P256_S2N_H++#include <stdint.h>++/* res = scalar * point, all of them affine and not in Montgomery form:+ * point is x then y, four words each, and res the same. The point at+ * infinity goes in and comes out as (0, 0). */+void crypton_s2n_p256_scalarmul(uint64_t res[8], const uint64_t scalar[4],+ const uint64_t point[8]);++/* res = scalar * G, the same shape out. The table it reads and the window+ * width it was built for are in cbits/p256/p256_base_table.c, which+ * cbits/p256/gen_base_table.py writes. */+void crypton_s2n_p256_scalarmulbase(uint64_t res[8], const uint64_t scalar[4]);++#endif
@@ -0,0 +1,2 @@+834a90d5e846ffa1e1611bd24e160bb2e9b86d35+v2.0.0
@@ -0,0 +1,305 @@+mldsa-native is a fork of the public domain Dilithium reference implementation,+available on https://github.com/pq-crystals/dilithium.++All new files and all files derived from the Dilithium reference+implementation are made available under the Apache-2.0 license OR+the ISC license OR the MIT license. These licenses are+reproduced at the bottom of this file.++Files outside the library itself may carry different terms. Every file+states its own SPDX-License-Identifier, which determines the terms that+apply to it. In particular:++The code in test/notrandombytes/*, and its copies in+examples/*/test_only_rng/* and scripts/notrandombytes, is derived from+https://cr.yp.to/papers.html#surf and licensed under+LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT.+It is only used for testing purposes.++The benchmarking code in test/hal/* carries the+MIT license. It is only used for testing purposes.++The tiny_sha3 code in+examples/bring_your_own_fips202/custom_fips202/tiny_sha3/* and+examples/custom_backend/mldsa_native/src/fips202/native/custom/src/*+carries the MIT license. It is only used to demonstrate custom+FIPS-202 implementations.++The proofs in proofs/* are in part derived from Amazon Web Services+verification infrastructure and licensed under+Apache-2.0 OR ISC OR MIT-0, MIT-0, or MIT-0 AND Apache-2.0. The IACR+document class proofs/isabelle/neon_ntt/document/iacrtrans.cls is+licensed under CC0-1.0. None of this is part of the library.++Documentation is licensed under CC-BY-4.0.++```+Copyright (c) The mldsa-native project authors+Copyright (c) The mlkem-native project authors+Copyright (c) 2020 Dougall Johnson+Copyright (c) 2022 Arm Limited+SPDX-License-Identifier: MIT++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.+```++ISC license for mldsa-native content+------------------------------------++Copyright (c) The mldsa-native project authors++Permission to use, copy, modify, and/or distribute this software for any purpose+with or without fee is hereby granted, provided that the above copyright notice+and this permission notice appear in all copies.++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF+THIS SOFTWARE.+++MIT license for mldsa-native content+------------------------------------++Copyright (c) The mldsa-native project authors++Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the “Software”), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of+the Software, and to permit persons to whom the Software is furnished to do so,+subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.++Apache-2.0 license for mldsa-native content+-------------------------------------------++ Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++ 1. Definitions.++ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document.++ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License.++ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity.++ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License.++ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files.++ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types.++ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below).++ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof.++ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution."++ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work.++ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form.++ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed.++ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions:++ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and++ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and++ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and++ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License.++ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License.++ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions.++ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file.++ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License.++ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages.++ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability.++ END OF TERMS AND CONDITIONS++ APPENDIX: How to apply the Apache License to your work.++ To apply the Apache License to your work, attach the following+ boilerplate notice, with the fields enclosed by brackets "[]"+ replaced with your own identifying information. (Don't include+ the brackets!) The text should be enclosed in the appropriate+ comment syntax for the file format. We also recommend that a+ file or class name and description of purpose be included on the+ same "printed page" as the copyright notice for easier+ identification within third-party archives.++ Copyright (c) The mldsa-native project authors++ Licensed under the Apache License, Version 2.0 (the "License");+ you may not use this file except in compliance with the License.+ You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++ Unless required by applicable law or agreed to in writing, software+ distributed under the License is distributed on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ See the License for the specific language governing permissions and+ limitations under the License.
@@ -0,0 +1,60 @@+# mldsa-native++ML-DSA (FIPS 204) from the PQ Code Package, vendored here and built for all+three parameter sets.++## Where it comes from++<https://github.com/pq-code-package/mldsa-native>. `COMMIT` holds the+revision this tree is at; `import.sh` puts it there and is how the tree is+refreshed. Nothing here is edited by hand -- every choice crypton makes is+made in `crypton_mldsa.h`, `crypton_mldsa.c` and `crypton.cabal`, so that a+re-import is a straight overwrite.++## Licence++`Apache-2.0 OR ISC OR MIT`, the same three-way form as `cbits/s2n` and by+some of the same authors. crypton takes it under ISC, which is already in+the package's `license:` field. `LICENSE` is the upstream file and is+listed in `license-files:`.++## What is taken and what is not++The whole of `mldsa/`, less the backends for architectures crypton does not+build for: the 32-bit+`src/fips202/native/armv81m`. (Unlike mlkem-native, this one ships only the+AArch64 and x86-64 arithmetic backends, so there is nothing else to drop.) Every reference to those is behind an+`MLD_SYS_` guard that cannot be true on the architectures crypton does+build for, so dropping them changes no build and keeps a few dozen files of+unreachable assembly out of the release tarball. To take one back, delete+its line from `import.sh` and add its directory to `extra-source-files:`.++## How it is built++Upstream builds for one parameter set at a time. `crypton_mldsa.c`+includes the amalgamation once per set -- the level-independent half kept by+exactly one of them -- which is how a single crypton offers ML-DSA-44, 65+and 87. `crypton_mldsa_asm.S` does the same for the assembly, which is+level-independent and so is included once.++This is the shape `cbits/aes/armv8.c` already uses for the three AES key+sizes, and it has the same hazard: **cabal does not know that the wrapper+depends on the tree it includes.** After changing anything under+`cbits/mldsa`, touch `crypton_mldsa.c`, or the build keeps the object it+already has and the change is not tested.++The hand-written backends are selected by `CRYPTON_MLDSA_NATIVE_BACKEND`,+which `crypton.cabal` defines on x86-64 and AArch64 other than Windows --+the same exclusion, and for the same reasons, as `cbits/s2n`. Everywhere+else the portable C is built, which is the same code and passes the same+tests.++There is no randomised API: `MLD_CONFIG_NO_RANDOMIZED_API` is set, no+`randombytes()` is needed, and randomness is drawn in Haskell through+`MonadRandom` as it is for every other key crypton generates.++The symbols are `crypton_mldsa44_*`, `crypton_mldsa65_*` and+`crypton_mldsa87_*` rather than upstream's defaults, so that an+application linking another copy of mldsa-native -- through some other+library, or its own -- does not present the linker with two sets of+functions answering to one set of names.
@@ -0,0 +1,31 @@+/*+ * All three ML-DSA parameter sets in one translation unit.+ *+ * mldsa-native is built for one parameter set at a time; a build wanting+ * several includes the amalgamation once per set, with the level-independent+ * half kept by exactly one of them. This is the same shape as+ * cbits/aes/armv8.c, which includes cbits/aes/armv8_impl.c three times for+ * the three AES key sizes.+ *+ * NOTE, as there: cabal does not know that this file depends on the tree it+ * includes. After changing anything under cbits/mldsa, touch this file, or+ * the build will quietly keep the object it already has.+ */+#include "crypton_mldsa.h"++#define MLD_CONFIG_MULTILEVEL_WITH_SHARED 1+#define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+#define MLD_CONFIG_PARAMETER_SET 44+#include "mldsa_native.c"+#undef MLD_CONFIG_MULTILEVEL_WITH_SHARED+#undef MLD_CONFIG_PARAMETER_SET++#define MLD_CONFIG_MULTILEVEL_NO_SHARED+#define MLD_CONFIG_PARAMETER_SET 65+#include "mldsa_native.c"+#undef MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+#undef MLD_CONFIG_PARAMETER_SET++#define MLD_CONFIG_PARAMETER_SET 87+#include "mldsa_native.c"+#undef MLD_CONFIG_PARAMETER_SET
@@ -0,0 +1,79 @@+/*+ * What crypton asks of the vendored mldsa-native, in one place. The tree+ * under cbits/mldsa is upstream's and is overwritten by import.sh, so every+ * choice crypton makes is made here instead of by editing it.+ *+ * Included first by both crypton_mldsa.c and crypton_mldsa_asm.S, so it must+ * hold nothing the assembler cannot read: directives, and C behind+ * __ASSEMBLER__.+ */+#ifndef CRYPTON_MLDSA_H+#define CRYPTON_MLDSA_H++/*+ * The symbols are crypton's own, not the default PQCP_MLDSA_NATIVE_*. An+ * application is free to link another copy of mldsa-native -- through some+ * other library, or its own -- and two copies answering to one set of names+ * is a problem the linker resolves silently and in nobody's favour. With+ * MLD_CONFIG_MULTILEVEL_BUILD the level is appended, so the entry points+ * are crypton_mldsa44_*, crypton_mldsa65_* and crypton_mldsa87_*.+ */+#define MLD_CONFIG_NAMESPACE_PREFIX crypton_mldsa+#define MLD_CONFIG_MULTILEVEL_BUILD++/*+ * No randomised API, so no randombytes() to provide. Randomness is drawn+ * in Haskell through MonadRandom, the way every other key in crypton is+ * generated, and the deterministic entry points are what the FFI calls.+ * That also keeps the C free of any opinion about where entropy comes from.+ */+#define MLD_CONFIG_NO_RANDOMIZED_API++/*+ * The hand-written backends, where crypton.cabal says the architecture has+ * them. Without this the portable C is built, which is correct everywhere+ * and is what every other architecture gets.+ */+#ifdef CRYPTON_MLDSA_NATIVE_BACKEND+#define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH+#define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202++/*+ * Which of the backend's instructions this processor actually has.+ *+ * Without this both packages decide at compile time: the backend is built+ * because the architecture has the instructions in principle, and is then+ * called with no check. Upstream says so plainly -- if the machine that+ * runs the binary may differ from the one that built it, this function+ * MUST be provided -- and crypton is a library whose builds are copied+ * between machines and shipped by distributions. Without it a binary+ * built on a host with AVX2 dies with SIGILL on one without (#316).+ *+ * The dispatch sites are upstream's; each falls back to the portable C+ * when this answers no. The answers come from crypton's own detection,+ * the same that AES-NI, PCLMUL and the s2n-bignum variants use.+ */+#define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC+#ifndef __ASSEMBLER__+#include "src/sys.h"+#include "crypton_cpu.h"++static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap)+{+#if defined(__x86_64__)+ if (cap == MLD_SYS_CAP_X86_64_AVX2)+ return (crypton_x86_simd_features() & CRYPTON_X86_AVX2) != 0;+#elif defined(__aarch64__)+ /* NEON is not optional on AArch64; the Keccak instructions are. */+ if (cap == MLD_SYS_CAP_AARCH64_NEON)+ return 1;+ if (cap == MLD_SYS_CAP_AARCH64_SHA3)+ return (crypton_arm_features() & CRYPTON_ARM_SHA3) != 0;+#endif+ (void)cap;+ return 0;+}+#endif /* !__ASSEMBLER__ */+#endif++#endif /* CRYPTON_MLDSA_H */
@@ -0,0 +1,14 @@+/*+ * The assembly half, which is level-independent: it is included once, with+ * the shared directives kept, and covers all three parameter sets. See the+ * comment at the top of mldsa_native_asm.S.+ *+ * Built only where crypton.cabal defines CRYPTON_MLDSA_NATIVE_BACKEND; on+ * every other architecture this file is not in asm-sources at all.+ */+#include "crypton_mldsa.h"++#define MLD_CONFIG_MULTILEVEL_WITH_SHARED 1+#define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+#define MLD_CONFIG_PARAMETER_SET 65+#include "mldsa_native_asm.S"
@@ -0,0 +1,40 @@+#!/bin/sh+# Re-import the vendored parts of the PQ Code Package's mldsa-native.+#+# The files are kept unmodified. Everything crypton decides -- which+# parameter sets exist, what the symbols are called, that there is no+# randomised API -- is decided in cbits/mldsa/crypton_mldsa.c and in+# crypton.cabal, not by editing anything here. Run this from cbits/mldsa:+#+# ./import.sh [tag-or-commit]+#+# and commit the result together with the COMMIT line it writes, so that the+# tree always says which upstream revision it holds.+set -eu++REPO=https://github.com/pq-code-package/mldsa-native+REV=${1:-v2.0.0}+HERE=$(cd "$(dirname "$0")" && pwd)+TMP=$(mktemp -d)+trap 'rm -rf "$TMP"' EXIT++git clone -q "$REPO" "$TMP/u"+git -C "$TMP/u" checkout -q "$REV"++rm -rf "$HERE/src"+cp "$TMP/u/mldsa/mldsa_native.c" "$HERE/"+cp "$TMP/u/mldsa/mldsa_native.h" "$HERE/"+cp "$TMP/u/mldsa/mldsa_native_asm.S" "$HERE/"+cp "$TMP/u/mldsa/mldsa_native_config.h" "$HERE/"+cp -R "$TMP/u/mldsa/src" "$HERE/src"+cp "$TMP/u/LICENSE" "$HERE/LICENSE"++# The 32-bit Armv8.1-M Keccak, for an architecture crypton does not build+# for. Every reference to it is behind an MLD_SYS_ guard that cannot be true+# on the ones it does, so dropping it changes no build and keeps unreachable+# assembly out of the release tarball.+rm -rf "$HERE/src/fips202/native/armv81m"++git -C "$TMP/u" rev-parse HEAD > "$HERE/COMMIT"+git -C "$TMP/u" describe --tags --exact-match 2>/dev/null >> "$HERE/COMMIT" || true+echo "imported $(head -1 "$HERE/COMMIT")"
@@ -0,0 +1,803 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++/******************************************************************************+ *+ * Single compilation unit (SCU) for fixed-level build of mldsa-native+ *+ * This compilation unit bundles together all source files for a build+ * of mldsa-native for a fixed security level (MLDSA-44/65/87).+ *+ * # API+ *+ * The API exposed by this file is described in mldsa_native.h.+ *+ * # Multi-level build+ *+ * If you want an SCU build of mldsa-native with support for multiple security+ * levels, you need to include this file multiple times, and set+ * MLD_CONFIG_MULTILEVEL_WITH_SHARED and MLD_CONFIG_MULTILEVEL_NO_SHARED+ * appropriately. This is exemplified in examples/monolithic_build_multilevel+ * and examples/monolithic_build_multilevel_native.+ *+ * # Configuration+ *+ * The following options from the mldsa-native configuration are relevant:+ *+ * - MLD_CONFIG_FIPS202_CUSTOM_HEADER+ * Set this option if you use a custom FIPS202 implementation.+ *+ * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH+ * Set this option if you want to include the native arithmetic backends+ * in your build.+ *+ * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202+ * Set this option if you want to include the native FIPS202 backends+ * in your build.+ *+ * - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+ * Set this option if you want to keep the directives defined in+ * level-independent headers. This is needed for a multi-level build.+ */++/* If parts of the mldsa-native source tree are not used,+ * consider reducing this header via `unifdef`.+ *+ * Example:+ * ```bash+ * unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native.c+ * ```+ */++#include "src/common.h"++#include "src/ct.c"+#include "src/debug.c"+#include "src/packing.c"+#include "src/poly.c"+#include "src/poly_kl.c"+#include "src/polyvec.c"+#include "src/polyvec_lazy.c"+#include "src/sign.c"++#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER)+#include "src/fips202/fips202.c"+#include "src/fips202/fips202x4.c"+#include "src/fips202/keccakf1600.c"+#endif++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)+#if defined(MLD_SYS_AARCH64)+#include "src/native/aarch64/src/aarch64_zetas.c"+#include "src/native/aarch64/src/polyz_unpack_table.c"+#include "src/native/aarch64/src/rej_uniform_eta_table.c"+#include "src/native/aarch64/src/rej_uniform_table.c"+#endif /* MLD_SYS_AARCH64 */+#if defined(MLD_SYS_X86_64)+#include "src/native/x86_64/src/consts.c"+#include "src/native/x86_64/src/rej_uniform_table.c"+#endif+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)+#if defined(MLD_SYS_AARCH64)+#include "src/fips202/native/aarch64/src/keccakf1600_round_constants.c"+#endif+#if defined(MLD_SYS_X86_64)+#include "src/fips202/native/x86_64/src/keccakf1600_constants.c"+#endif+#if defined(MLD_SYS_ARMV81M_MVE)+#include "src/fips202/native/armv81m/src/keccak_f1600_x4_mve.c"+#include "src/fips202/native/armv81m/src/keccakf1600_round_constants.c"+#endif+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */++/* Macro #undef's+ *+ * The following undefines macros from headers+ * included by the source files imported above.+ *+ * This is to allow building and linking multiple builds+ * of mldsa-native for varying parameter sets through concatenation+ * of this file, as if the files had been compiled separately.+ * If this is not relevant to you, you may remove the following.+ */++/*+ * Undefine macros from MLD_CONFIG_PARAMETER_SET-specific files+ */+/* mldsa/mldsa_native.h */+#undef MLDSA44_BYTES+#undef MLDSA44_CRHBYTES+#undef MLDSA44_PUBLICKEYBYTES+#undef MLDSA44_RNDBYTES+#undef MLDSA44_SECRETKEYBYTES+#undef MLDSA44_SEEDBYTES+#undef MLDSA44_TRBYTES+#undef MLDSA65_BYTES+#undef MLDSA65_CRHBYTES+#undef MLDSA65_PUBLICKEYBYTES+#undef MLDSA65_RNDBYTES+#undef MLDSA65_SECRETKEYBYTES+#undef MLDSA65_SEEDBYTES+#undef MLDSA65_TRBYTES+#undef MLDSA87_BYTES+#undef MLDSA87_CRHBYTES+#undef MLDSA87_PUBLICKEYBYTES+#undef MLDSA87_RNDBYTES+#undef MLDSA87_SECRETKEYBYTES+#undef MLDSA87_SEEDBYTES+#undef MLDSA87_TRBYTES+#undef MLDSA_BYTES+#undef MLDSA_BYTES_+#undef MLDSA_CRHBYTES+#undef MLDSA_PUBLICKEYBYTES+#undef MLDSA_PUBLICKEYBYTES_+#undef MLDSA_RNDBYTES+#undef MLDSA_SECRETKEYBYTES+#undef MLDSA_SECRETKEYBYTES_+#undef MLDSA_SEEDBYTES+#undef MLDSA_TRBYTES+#undef MLD_API_CONCAT+#undef MLD_API_CONCAT_+#undef MLD_API_CONCAT_UNDERSCORE+#undef MLD_API_MUST_CHECK_RETURN_VALUE+#undef MLD_API_NAMESPACE+#undef MLD_API_NAMESPACE_PREFIX+#undef MLD_API_QUALIFIER+#undef MLD_DOMAIN_SEPARATION_MAX_BYTES+#undef MLD_ERR_FAIL+#undef MLD_ERR_INVALID_ARG+#undef MLD_ERR_INVALID_KEY+#undef MLD_ERR_INVALID_SIGNATURE+#undef MLD_ERR_OUT_OF_MEMORY+#undef MLD_ERR_PCT_FAIL+#undef MLD_ERR_RNG_FAIL+#undef MLD_ERR_SIGNING_PAUSED+#undef MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED+#undef MLD_H+#undef MLD_MAX3_+#undef MLD_MAX4_+#undef MLD_PREHASH_NONE+#undef MLD_PREHASH_SHA2_224+#undef MLD_PREHASH_SHA2_256+#undef MLD_PREHASH_SHA2_384+#undef MLD_PREHASH_SHA2_512+#undef MLD_PREHASH_SHA2_512_224+#undef MLD_PREHASH_SHA2_512_256+#undef MLD_PREHASH_SHA3_224+#undef MLD_PREHASH_SHA3_256+#undef MLD_PREHASH_SHA3_384+#undef MLD_PREHASH_SHA3_512+#undef MLD_PREHASH_SHAKE_128+#undef MLD_PREHASH_SHAKE_256+#undef MLD_TOTAL_ALLOC_44+#undef MLD_TOTAL_ALLOC_44_KEYPAIR+#undef MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT+#undef MLD_TOTAL_ALLOC_44_KEYPAIR_PCT+#undef MLD_TOTAL_ALLOC_44_PK_FROM_SK+#undef MLD_TOTAL_ALLOC_44_SIGN+#undef MLD_TOTAL_ALLOC_44_VERIFY+#undef MLD_TOTAL_ALLOC_65+#undef MLD_TOTAL_ALLOC_65_KEYPAIR+#undef MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT+#undef MLD_TOTAL_ALLOC_65_KEYPAIR_PCT+#undef MLD_TOTAL_ALLOC_65_PK_FROM_SK+#undef MLD_TOTAL_ALLOC_65_SIGN+#undef MLD_TOTAL_ALLOC_65_VERIFY+#undef MLD_TOTAL_ALLOC_87+#undef MLD_TOTAL_ALLOC_87_KEYPAIR+#undef MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT+#undef MLD_TOTAL_ALLOC_87_KEYPAIR_PCT+#undef MLD_TOTAL_ALLOC_87_PK_FROM_SK+#undef MLD_TOTAL_ALLOC_87_SIGN+#undef MLD_TOTAL_ALLOC_87_VERIFY+/* mldsa/src/common.h */+#undef MLD_ADD_PARAM_SET+#undef MLD_ALLOC+#undef MLD_APPLY+#undef MLD_ASM_FN_SIZE+#undef MLD_ASM_FN_SYMBOL+#undef MLD_ASM_NAMESPACE+#undef MLD_BUILD_INTERNAL+#undef MLD_COMMON_H+#undef MLD_CONCAT+#undef MLD_CONCAT_+#undef MLD_EMPTY_CU+#undef MLD_ERR_FAIL+#undef MLD_ERR_INVALID_ARG+#undef MLD_ERR_INVALID_KEY+#undef MLD_ERR_INVALID_SIGNATURE+#undef MLD_ERR_OUT_OF_MEMORY+#undef MLD_ERR_PCT_FAIL+#undef MLD_ERR_RNG_FAIL+#undef MLD_ERR_SIGNING_PAUSED+#undef MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED+#undef MLD_EXTERNAL_API+#undef MLD_FIPS202X4_HEADER_FILE+#undef MLD_FIPS202_HEADER_FILE+#undef MLD_FREE+#undef MLD_INTERNAL_API+#undef MLD_INTERNAL_DATA_DECLARATION+#undef MLD_INTERNAL_DATA_DEFINITION+#undef MLD_MULTILEVEL_BUILD+#undef MLD_NAMESPACE+#undef MLD_NAMESPACE_KL+#undef MLD_NAMESPACE_PREFIX+#undef MLD_NAMESPACE_PREFIX_KL+#undef mld_memcpy+#undef mld_memset+/* mldsa/src/packing.h */+#undef MLD_PACKING_H+#undef mld_pack_sig_c+#undef mld_pack_sig_h+#undef mld_pack_sig_z+#undef mld_pack_sk_rho_key_tr_s2+#undef mld_pack_sk_s1+#undef mld_sig_unpack_hints+#undef mld_unpack_pk_t1+#undef mld_unpack_sk+/* mldsa/src/params.h */+#undef MLDSA_BETA+#undef MLDSA_CRHBYTES+#undef MLDSA_CRYPTO_BYTES+#undef MLDSA_CRYPTO_PUBLICKEYBYTES+#undef MLDSA_CRYPTO_SECRETKEYBYTES+#undef MLDSA_CTILDEBYTES+#undef MLDSA_D+#undef MLDSA_ETA+#undef MLDSA_GAMMA1+#undef MLDSA_GAMMA2+#undef MLDSA_GAMMA2_32+#undef MLDSA_GAMMA2_88+#undef MLDSA_K+#undef MLDSA_L+#undef MLDSA_N+#undef MLDSA_OMEGA+#undef MLDSA_PK_END+#undef MLDSA_PK_RHO_BYTES+#undef MLDSA_PK_RHO_OFFSET+#undef MLDSA_PK_T1_BYTES+#undef MLDSA_PK_T1_OFFSET+#undef MLDSA_POLYETA_PACKEDBYTES+#undef MLDSA_POLYT0_PACKEDBYTES+#undef MLDSA_POLYT1_PACKEDBYTES+#undef MLDSA_POLYVECH_PACKEDBYTES+#undef MLDSA_POLYW1_PACKEDBYTES+#undef MLDSA_POLYW1_PACKEDBYTES_32+#undef MLDSA_POLYW1_PACKEDBYTES_88+#undef MLDSA_POLYZ_PACKEDBYTES+#undef MLDSA_Q+#undef MLDSA_Q_HALF+#undef MLDSA_RNDBYTES+#undef MLDSA_SEEDBYTES+#undef MLDSA_SIG_C_BYTES+#undef MLDSA_SIG_C_OFFSET+#undef MLDSA_SIG_END+#undef MLDSA_SIG_H_BYTES+#undef MLDSA_SIG_H_OFFSET+#undef MLDSA_SIG_Z_BYTES+#undef MLDSA_SIG_Z_OFFSET+#undef MLDSA_SK_END+#undef MLDSA_SK_KEY_BYTES+#undef MLDSA_SK_KEY_OFFSET+#undef MLDSA_SK_RHO_BYTES+#undef MLDSA_SK_RHO_OFFSET+#undef MLDSA_SK_S1_BYTES+#undef MLDSA_SK_S1_OFFSET+#undef MLDSA_SK_S2_BYTES+#undef MLDSA_SK_S2_OFFSET+#undef MLDSA_SK_T0_BYTES+#undef MLDSA_SK_T0_OFFSET+#undef MLDSA_SK_TR_BYTES+#undef MLDSA_SK_TR_OFFSET+#undef MLDSA_TAU+#undef MLDSA_TRBYTES+#undef MLD_MAX_KAPPA+#undef MLD_PARAMS_H+/* mldsa/src/poly_kl.h */+#undef MLD_POLYETA_UNPACK_LOWER_BOUND+#undef MLD_POLY_KL_H+#undef mld_poly_challenge+#undef mld_poly_decompose+#undef mld_poly_uniform_eta+#undef mld_poly_uniform_eta_4x+#undef mld_poly_uniform_gamma1+#undef mld_poly_uniform_gamma1_4x+#undef mld_poly_use_hint+#undef mld_polyeta_pack+#undef mld_polyeta_unpack+#undef mld_polyw1_pack+#undef mld_polyz_pack+#undef mld_polyz_unpack+/* mldsa/src/polyvec.h */+#undef MLD_POLYVEC_H+#undef mld_polyveck+#undef mld_polyveck_caddq+#undef mld_polyveck_chknorm+#undef mld_polyveck_decompose+#undef mld_polyveck_invntt_tomont+#undef mld_polyveck_ntt+#undef mld_polyveck_pack_eta+#undef mld_polyveck_pack_w1+#undef mld_polyveck_reduce+#undef mld_polyveck_unpack_eta+#undef mld_polyvecl+#undef mld_polyvecl_chknorm+#undef mld_polyvecl_ntt+#undef mld_polyvecl_pack_eta+#undef mld_polyvecl_pointwise_acc_montgomery+#undef mld_polyvecl_uniform_gamma1+#undef mld_polyvecl_unpack_eta+#undef mld_polyvecl_unpack_z+/* mldsa/src/polyvec_lazy.h */+#undef MLD_POLYVEC_LAZY_H+#undef mld_poly_permute_bitrev_to_custom_optional+#undef mld_polymat+#undef mld_polymat_eager+#undef mld_polymat_lazy+#undef mld_polyvec_matrix_expand+#undef mld_polyvec_matrix_expand_eager+#undef mld_polyvec_matrix_expand_lazy+#undef mld_polyvec_matrix_pointwise_montgomery+#undef mld_polyvec_matrix_pointwise_montgomery_row+#undef mld_polyvec_matrix_pointwise_montgomery_row_eager+#undef mld_polyvec_matrix_pointwise_montgomery_row_lazy+#undef mld_polyvec_matrix_pointwise_montgomery_yvec+#undef mld_polyvec_matrix_pointwise_montgomery_yvec_eager+#undef mld_polyvec_matrix_pointwise_montgomery_yvec_lazy+#undef mld_sk_s1hat+#undef mld_sk_s1hat_eager+#undef mld_sk_s1hat_get_poly+#undef mld_sk_s1hat_get_poly_eager+#undef mld_sk_s1hat_get_poly_lazy+#undef mld_sk_s1hat_lazy+#undef mld_sk_s2hat+#undef mld_sk_s2hat_eager+#undef mld_sk_s2hat_get_poly+#undef mld_sk_s2hat_get_poly_eager+#undef mld_sk_s2hat_get_poly_lazy+#undef mld_sk_s2hat_lazy+#undef mld_sk_t0hat+#undef mld_sk_t0hat_eager+#undef mld_sk_t0hat_get_poly+#undef mld_sk_t0hat_get_poly_eager+#undef mld_sk_t0hat_get_poly_lazy+#undef mld_sk_t0hat_lazy+#undef mld_unpack_sk_s1hat+#undef mld_unpack_sk_s1hat_eager+#undef mld_unpack_sk_s1hat_lazy+#undef mld_unpack_sk_s2hat+#undef mld_unpack_sk_s2hat_eager+#undef mld_unpack_sk_s2hat_lazy+#undef mld_unpack_sk_t0hat+#undef mld_unpack_sk_t0hat_eager+#undef mld_unpack_sk_t0hat_lazy+#undef mld_yvec+#undef mld_yvec_eager+#undef mld_yvec_get_poly+#undef mld_yvec_get_poly_eager+#undef mld_yvec_get_poly_lazy+#undef mld_yvec_init+#undef mld_yvec_init_eager+#undef mld_yvec_init_lazy+#undef mld_yvec_lazy+/* mldsa/src/rounding.h */+#undef MLD_2_POW_D+#undef MLD_ROUNDING_H+#undef mld_decompose+#undef mld_make_hint+#undef mld_power2round+#undef mld_use_hint+/* mldsa/src/sign.h */+#undef MLD_DOMAIN_SEPARATION_MAX_BYTES+#undef MLD_PREHASH_NONE+#undef MLD_PREHASH_SHA2_224+#undef MLD_PREHASH_SHA2_256+#undef MLD_PREHASH_SHA2_384+#undef MLD_PREHASH_SHA2_512+#undef MLD_PREHASH_SHA2_512_224+#undef MLD_PREHASH_SHA2_512_256+#undef MLD_PREHASH_SHA3_224+#undef MLD_PREHASH_SHA3_256+#undef MLD_PREHASH_SHA3_384+#undef MLD_PREHASH_SHA3_512+#undef MLD_PREHASH_SHAKE_128+#undef MLD_PREHASH_SHAKE_256+#undef MLD_SIGN_H+#undef mld_prepare_domain_separation_prefix+#undef mld_sign_keypair+#undef mld_sign_keypair_internal+#undef mld_sign_pk_from_sk+#undef mld_sign_signature+#undef mld_sign_signature_extmu+#undef mld_sign_signature_internal+#undef mld_sign_signature_pre_hash_internal+#undef mld_sign_signature_pre_hash_shake256+#undef mld_sign_verify+#undef mld_sign_verify_extmu+#undef mld_sign_verify_internal+#undef mld_sign_verify_pre_hash_internal+#undef mld_sign_verify_pre_hash_shake256++#if !defined(MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS)+/*+ * Undefine macros from MLD_CONFIG_PARAMETER_SET-generic files+ */+/* mldsa/src/context.h */+#undef MLD_CONTEXT_H+#undef MLD_CONTEXT_PARAMETERS_0+#undef MLD_CONTEXT_PARAMETERS_1+#undef MLD_CONTEXT_PARAMETERS_2+#undef MLD_CONTEXT_PARAMETERS_3+#undef MLD_CONTEXT_PARAMETERS_4+#undef MLD_CONTEXT_PARAMETERS_5+#undef MLD_CONTEXT_PARAMETERS_6+#undef MLD_CONTEXT_PARAMETERS_7+#undef MLD_CONTEXT_PARAMETERS_8+#undef MLD_CONTEXT_PARAMETERS_9+#undef MLD_CONTEXT_UNUSED+#undef mld_sign_attempt+#undef mld_sign_finish+#undef mld_sign_resume+/* mldsa/src/ct.h */+#undef MLD_CT_H+#undef MLD_USE_ASM_VALUE_BARRIER+#undef mld_ct_opt_blocker_u64+/* mldsa/src/debug.h */+#undef MLD_DEBUG_H+#undef mld_assert+#undef mld_assert_abs_bound+#undef mld_assert_abs_bound_2d+#undef mld_assert_bound+#undef mld_assert_bound_2d+#undef mld_debug_check_assert+#undef mld_debug_check_bounds+/* mldsa/src/poly.h */+#undef MLD_FQMUL_BOUND+#undef MLD_INTT_BOUND+#undef MLD_NTT_BOUND+#undef MLD_POLY_H+#undef mld_poly_add+#undef mld_poly_caddq+#undef mld_poly_chknorm+#undef mld_poly_invntt_tomont+#undef mld_poly_ntt+#undef mld_poly_pointwise_montgomery+#undef mld_poly_power2round+#undef mld_poly_reduce+#undef mld_poly_shiftl+#undef mld_poly_sub+#undef mld_poly_uniform+#undef mld_poly_uniform_4x+#undef mld_polyt0_pack+#undef mld_polyt0_unpack+#undef mld_polyt1_pack+#undef mld_polyt1_unpack+#undef mld_polyw1_pack_32+#undef mld_polyw1_pack_88+/* mldsa/src/randombytes.h */+#undef MLD_RANDOMBYTES_H+/* mldsa/src/reduce.h */+#undef MLD_MONT+#undef MLD_REDUCE32_DOMAIN_MAX+#undef MLD_REDUCE32_RANGE_MAX+#undef MLD_REDUCE_H+/* mldsa/src/symmetric.h */+#undef MLD_STREAM128_BLOCKBYTES+#undef MLD_STREAM256_BLOCKBYTES+#undef MLD_SYMMETRIC_H+#undef mld_xof128_absorb_once+#undef mld_xof128_ctx+#undef mld_xof128_init+#undef mld_xof128_release+#undef mld_xof128_squeezeblocks+#undef mld_xof128_x4_absorb+#undef mld_xof128_x4_ctx+#undef mld_xof128_x4_init+#undef mld_xof128_x4_release+#undef mld_xof128_x4_squeezeblocks+#undef mld_xof256_absorb_once+#undef mld_xof256_ctx+#undef mld_xof256_init+#undef mld_xof256_release+#undef mld_xof256_squeezeblocks+#undef mld_xof256_x4_absorb+#undef mld_xof256_x4_ctx+#undef mld_xof256_x4_init+#undef mld_xof256_x4_release+#undef mld_xof256_x4_squeezeblocks+/* mldsa/src/sys.h */+#undef MLD_ALIGN+#undef MLD_ALIGN_UP+#undef MLD_ALWAYS_INLINE+#undef MLD_CET_ENDBR+#undef MLD_CT_TESTING_DECLASSIFY+#undef MLD_CT_TESTING_SECRET+#undef MLD_DEFAULT_ALIGN+#undef MLD_HAVE_INLINE_ASM+#undef MLD_INLINE+#undef MLD_MUST_CHECK_RETURN_VALUE+#undef MLD_NOINLINE+#undef MLD_RESTRICT+#undef MLD_STATIC_TESTABLE+#undef MLD_SYSV_ABI+#undef MLD_SYSV_ABI_SUPPORTED+#undef MLD_SYS_AARCH64+#undef MLD_SYS_AARCH64_EB+#undef MLD_SYS_AARCH64_NEON+#undef MLD_SYS_APPLE+#undef MLD_SYS_ARMV81M_MVE+#undef MLD_SYS_BIG_ENDIAN+#undef MLD_SYS_H+#undef MLD_SYS_LINUX+#undef MLD_SYS_LITTLE_ENDIAN+#undef MLD_SYS_PPC64LE+#undef MLD_SYS_RISCV32+#undef MLD_SYS_RISCV64+#undef MLD_SYS_RISCV64_RVV+#undef MLD_SYS_WINDOWS+#undef MLD_SYS_X86_64+#undef MLD_SYS_X86_64_AVX2+/* mldsa/src/cbmc.h */+#undef MLD_CBMC_H+#undef __contract__+#undef __loop__++#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER)+/*+ * Undefine macros from FIPS-202 files+ */+/* mldsa/src/fips202/fips202.h */+#undef MLD_FIPS202_FIPS202_H+#undef MLD_KECCAK_LANES+#undef SHA3_256_HASHBYTES+#undef SHA3_256_RATE+#undef SHA3_512_HASHBYTES+#undef SHA3_512_RATE+#undef SHAKE128_RATE+#undef SHAKE256_RATE+#undef mld_shake128_absorb+#undef mld_shake128_finalize+#undef mld_shake128_init+#undef mld_shake128_release+#undef mld_shake128_squeeze+#undef mld_shake256+#undef mld_shake256_absorb+#undef mld_shake256_finalize+#undef mld_shake256_init+#undef mld_shake256_release+#undef mld_shake256_squeeze+/* mldsa/src/fips202/fips202x4.h */+#undef MLD_FIPS202_FIPS202X4_H+#undef mld_shake128x4_absorb_once+#undef mld_shake128x4_init+#undef mld_shake128x4_release+#undef mld_shake128x4_squeezeblocks+#undef mld_shake256x4_absorb_once+#undef mld_shake256x4_init+#undef mld_shake256x4_release+#undef mld_shake256x4_squeezeblocks+/* mldsa/src/fips202/keccakf1600.h */+#undef MLD_FIPS202_KECCAKF1600_H+#undef MLD_KECCAK_LANES+#undef MLD_KECCAK_WAY+#undef mld_keccakf1600_extract_bytes+#undef mld_keccakf1600_permute+#undef mld_keccakf1600_xor_bytes+#undef mld_keccakf1600x4_extract_bytes+#undef mld_keccakf1600x4_permute+#undef mld_keccakf1600x4_xor_bytes+#endif /* !MLD_CONFIG_FIPS202_CUSTOM_HEADER */++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)+/* mldsa/src/fips202/native/api.h */+#undef MLD_FIPS202_NATIVE_API_H+#undef MLD_NATIVE_FUNC_FALLBACK+#undef MLD_NATIVE_FUNC_SUCCESS+/* mldsa/src/fips202/native/auto.h */+#undef MLD_FIPS202_NATIVE_AUTO_H+#if defined(MLD_SYS_AARCH64)+/*+ * Undefine macros from native code (FIPS202, AArch64)+ */+/* mldsa/src/fips202/native/aarch64/auto.h */+#undef MLD_FIPS202_NATIVE_AARCH64_AUTO_H+/* mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h */+#undef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H+#undef mld_keccak_f1600_x1_scalar_aarch64_asm+#undef mld_keccak_f1600_x1_v84a_aarch64_asm+#undef mld_keccak_f1600_x2_v84a_aarch64_asm+#undef mld_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm+#undef mld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm+#undef mld_keccakf1600_round_constants+/* mldsa/src/fips202/native/aarch64/x1_scalar.h */+#undef MLD_FIPS202_AARCH64_NEED_X1_SCALAR+#undef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H+#undef MLD_USE_NATIVE_FIPS202_X1+/* mldsa/src/fips202/native/aarch64/x1_v84a.h */+#undef MLD_FIPS202_AARCH64_NEED_X1_V84A+#undef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H+#undef MLD_USE_NATIVE_FIPS202_X1+/* mldsa/src/fips202/native/aarch64/x2_v84a.h */+#undef MLD_FIPS202_AARCH64_NEED_X2_V84A+#undef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H+#undef MLD_USE_NATIVE_FIPS202_X4+/* mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h */+#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID+#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H+#undef MLD_USE_NATIVE_FIPS202_X4+/* mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h */+#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID+#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H+#undef MLD_USE_NATIVE_FIPS202_X4+#endif /* MLD_SYS_AARCH64 */+#if defined(MLD_SYS_X86_64)+/*+ * Undefine macros from native code (FIPS202, x86_64)+ */+/* mldsa/src/fips202/native/x86_64/keccak_f1600_x4_avx2.h */+#undef MLD_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H+#undef MLD_FIPS202_X86_64_NEED_X4_AVX2+#undef MLD_USE_NATIVE_FIPS202_X4+/* mldsa/src/fips202/native/x86_64/src/fips202_native_x86_64.h */+#undef MLD_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H+#undef mld_keccak_f1600_x4_avx2_asm+#undef mld_keccak_rho56+#undef mld_keccak_rho8+#undef mld_keccakf1600_round_constants+#endif /* MLD_SYS_X86_64 */+#if defined(MLD_SYS_ARMV81M_MVE)+/*+ * Undefine macros from native code (FIPS202, Armv8.1-M)+ */+/* mldsa/src/fips202/native/armv81m/mve.h */+#undef MLD_FIPS202_ARMV81M_NEED_X4+#undef MLD_FIPS202_NATIVE_ARMV81M+#undef MLD_FIPS202_NATIVE_ARMV81M_MVE_H+#undef MLD_USE_NATIVE_FIPS202_X4+#undef MLD_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES+#undef MLD_USE_NATIVE_FIPS202_X4_XOR_BYTES+#undef mld_keccak_f1600_x4_native_impl+/* mldsa/src/fips202/native/armv81m/src/fips202_native_armv81m.h */+#undef MLD_FIPS202_NATIVE_ARMV81M_SRC_FIPS202_NATIVE_ARMV81M_H+#undef mld_keccak_f1600_x4_mve_asm+#undef mld_keccak_f1600_x4_state_extract_bytes_asm+#undef mld_keccak_f1600_x4_state_xor_bytes_asm+#undef mld_keccakf1600_round_constants+#endif /* MLD_SYS_ARMV81M_MVE */+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */+#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)+/* mldsa/src/native/api.h */+#undef MLD_FQMUL_BOUND+#undef MLD_INTT_BOUND+#undef MLD_NATIVE_API_H+#undef MLD_NATIVE_FUNC_FALLBACK+#undef MLD_NATIVE_FUNC_SUCCESS+#undef MLD_NTT_BOUND+#undef MLD_REDUCE32_RANGE_MAX+/* mldsa/src/native/meta.h */+#undef MLD_NATIVE_META_H+#if defined(MLD_SYS_AARCH64)+/*+ * Undefine macros from native code (Arith, AArch64)+ */+/* mldsa/src/native/aarch64/meta.h */+#undef MLD_ARITH_BACKEND_AARCH64+#undef MLD_NATIVE_AARCH64_META_H+#undef MLD_USE_NATIVE_INTT+#undef MLD_USE_NATIVE_NTT+#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7+#undef MLD_USE_NATIVE_POLYZ_UNPACK_17+#undef MLD_USE_NATIVE_POLYZ_UNPACK_19+#undef MLD_USE_NATIVE_POLY_CADDQ+#undef MLD_USE_NATIVE_POLY_CHKNORM+#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32+#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88+#undef MLD_USE_NATIVE_POLY_USE_HINT_32+#undef MLD_USE_NATIVE_POLY_USE_HINT_88+#undef MLD_USE_NATIVE_REJ_UNIFORM+#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2+#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4+/* mldsa/src/native/aarch64/src/arith_native_aarch64.h */+#undef MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN+#undef MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN+#undef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H+#undef mld_aarch64_intt_zetas_layer123456+#undef mld_aarch64_intt_zetas_layer78+#undef mld_aarch64_ntt_zetas_layer123456+#undef mld_aarch64_ntt_zetas_layer78+#undef mld_intt_aarch64_asm+#undef mld_ntt_aarch64_asm+#undef mld_poly_caddq_aarch64_asm+#undef mld_poly_chknorm_aarch64_asm+#undef mld_poly_decompose_32_aarch64_asm+#undef mld_poly_decompose_88_aarch64_asm+#undef mld_poly_pointwise_montgomery_aarch64_asm+#undef mld_poly_use_hint_32_aarch64_asm+#undef mld_poly_use_hint_88_aarch64_asm+#undef mld_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm+#undef mld_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm+#undef mld_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm+#undef mld_polyz_unpack_17_aarch64_asm+#undef mld_polyz_unpack_17_indices+#undef mld_polyz_unpack_19_aarch64_asm+#undef mld_polyz_unpack_19_indices+#undef mld_rej_uniform_aarch64_asm+#undef mld_rej_uniform_eta2_aarch64_asm+#undef mld_rej_uniform_eta4_aarch64_asm+#undef mld_rej_uniform_eta_table+#undef mld_rej_uniform_table+#endif /* MLD_SYS_AARCH64 */+#if defined(MLD_SYS_X86_64)+/*+ * Undefine macros from native code (Arith, X86_64)+ */+/* mldsa/src/native/x86_64/meta.h */+#undef MLD_ARITH_BACKEND_X86_64_DEFAULT+#undef MLD_NATIVE_X86_64_META_H+#undef MLD_USE_NATIVE_INTT+#undef MLD_USE_NATIVE_NTT+#undef MLD_USE_NATIVE_NTT_CUSTOM_ORDER+#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7+#undef MLD_USE_NATIVE_POLYZ_UNPACK_17+#undef MLD_USE_NATIVE_POLYZ_UNPACK_19+#undef MLD_USE_NATIVE_POLY_CADDQ+#undef MLD_USE_NATIVE_POLY_CHKNORM+#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32+#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88+#undef MLD_USE_NATIVE_POLY_USE_HINT_32+#undef MLD_USE_NATIVE_POLY_USE_HINT_88+#undef MLD_USE_NATIVE_REJ_UNIFORM+#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2+#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4+/* mldsa/src/native/x86_64/src/arith_native_x86_64.h */+#undef MLD_AVX2_REJ_UNIFORM_BUFLEN+#undef MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN+#undef MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN+#undef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H+#undef mld_invntt_avx2_asm+#undef mld_ntt_avx2_asm+#undef mld_nttunpack_avx2_asm+#undef mld_pointwise_acc_l4_avx2_asm+#undef mld_pointwise_acc_l5_avx2_asm+#undef mld_pointwise_acc_l7_avx2_asm+#undef mld_pointwise_avx2_asm+#undef mld_poly_caddq_avx2_asm+#undef mld_poly_chknorm_avx2_asm+#undef mld_poly_decompose_32_avx2_asm+#undef mld_poly_decompose_88_avx2_asm+#undef mld_poly_use_hint_32_avx2_asm+#undef mld_poly_use_hint_88_avx2_asm+#undef mld_polyz_unpack_17_avx2_asm+#undef mld_polyz_unpack_19_avx2_asm+#undef mld_rej_uniform_avx2_asm+#undef mld_rej_uniform_eta2_avx2_asm+#undef mld_rej_uniform_eta4_avx2_asm+#undef mld_rej_uniform_table+/* mldsa/src/native/x86_64/src/consts.h */+#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV+#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV+#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQ+#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV+#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS+#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV+#undef MLD_NATIVE_X86_64_SRC_CONSTS_H+#undef mld_qdata+#endif /* MLD_SYS_X86_64 */+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */+#endif /* !MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */
@@ -0,0 +1,956 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#ifndef MLD_H+#define MLD_H++/*+ * Public API for mldsa-native+ *+ * This header defines the public API of a single build of mldsa-native.+ *+ * Make sure the configuration file is in the include path+ * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined).+ *+ * # API conventions+ *+ * Conventions shared by all functions below (return values, pointer validity,+ * output buffers on error) are documented in API-CONVENTIONS.md.+ *+ * # Multi-level builds+ *+ * This header specifies a build of mldsa-native for a fixed security level.+ * If you need multiple security levels, leave the security level unspecified+ * in the configuration file and include this header multiple times, setting+ * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H+ * guard to allow multiple inclusions.+ */++/******************************* Key sizes ************************************/++/* Sizes of cryptographic material, per parameter set */+/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */+/* check-magic: off */+#define MLDSA44_SECRETKEYBYTES 2560+#define MLDSA44_PUBLICKEYBYTES 1312+#define MLDSA44_BYTES 2420++#define MLDSA65_SECRETKEYBYTES 4032+#define MLDSA65_PUBLICKEYBYTES 1952+#define MLDSA65_BYTES 3309++#define MLDSA87_SECRETKEYBYTES 4896+#define MLDSA87_PUBLICKEYBYTES 2592+#define MLDSA87_BYTES 4627+/* check-magic: on */++/* Size of seed and randomness in bytes (level-independent) */+#define MLDSA_SEEDBYTES 32+#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES+#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES+#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES++/* Size of CRH output in bytes (level-independent) */+#define MLDSA_CRHBYTES 64+#define MLDSA44_CRHBYTES MLDSA_CRHBYTES+#define MLDSA65_CRHBYTES MLDSA_CRHBYTES+#define MLDSA87_CRHBYTES MLDSA_CRHBYTES++/* Size of TR in bytes (level-independent)+ *+ * TR = SHAKE256(pk, 64) is the hash of the public key. Callers of the+ * external-mu API (signature_extmu / verify_extmu) that compute the message+ * representative mu = SHAKE256(TR || M', MLDSA_CRHBYTES) themselves -- e.g. to+ * sign or verify a message that is too large or streamed to hold in memory --+ * need this constant to size the TR buffer. */+#define MLDSA_TRBYTES 64+#define MLDSA44_TRBYTES MLDSA_TRBYTES+#define MLDSA65_TRBYTES MLDSA_TRBYTES+#define MLDSA87_TRBYTES MLDSA_TRBYTES++/* Size of randomness for signing in bytes (level-independent) */+#define MLDSA_RNDBYTES 32+#define MLDSA44_RNDBYTES MLDSA_RNDBYTES+#define MLDSA65_RNDBYTES MLDSA_RNDBYTES+#define MLDSA87_RNDBYTES MLDSA_RNDBYTES++/* Sizes of cryptographic material, as a function of LVL=44,65,87 */+#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES+#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES+#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES+#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL)+#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL)+#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL)++/****************************** Error codes ***********************************/++/* Generic failure condition, reserved for failures not covered by a more+ * specific error code. */+#define MLD_ERR_FAIL (-1)+/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE+ * is defined and the provided MLD_CUSTOM_ALLOC can fail. */+#define MLD_ERR_OUT_OF_MEMORY (-2)+/* An RNG failure occurred. Might be due to insufficient entropy or+ * system misconfiguration. */+#define MLD_ERR_RNG_FAIL (-3)+/* The signing rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS iterations without producing a valid+ * signature. With a FIPS 204 Appendix C compliant bound (>= 821) this+ * has probability < 2^-256. */+#define MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED (-4)+/* Signing was paused before completing, at the request of a caller-provided+ * MLD_CONFIG_SIGN_HOOK_ATTEMPT hook (see mldsa_native_config.h). The caller+ * resumes by re-invoking signing with the same inputs; the attempt hook,+ * together with MLD_CONFIG_SIGN_HOOK_RESUME, decides where to continue. */+#define MLD_ERR_SIGNING_PAUSED (-5)+/* Signature verification failed: the signature is not valid for the given+ * message and public key. Returned by the verification API. */+#define MLD_ERR_INVALID_SIGNATURE (-6)+/* Secret key validation failed: the secret key is malformed or internally+ * inconsistent. Returned by pk_from_sk. */+#define MLD_ERR_INVALID_KEY (-7)+/* The Pairwise Consistency Test failed. Only possible when+ * MLD_CONFIG_KEYGEN_PCT is enabled; signals that the freshly generated key+ * pair failed its sign/verify self-test. */+#define MLD_ERR_PCT_FAIL (-8)+/* An argument was invalid, e.g. an unsupported pre-hash algorithm or a context+ * string longer than 255 bytes. */+#define MLD_ERR_INVALID_ARG (-9)++/********************* Namespacing and Qualifiers *****************************/++#define MLD_API_CONCAT_(x, y) x##y+#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y)+#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y)++/* You need to make sure the config file is in the include path. */+#if defined(MLD_CONFIG_FILE)+#include MLD_CONFIG_FILE+#else+#include "mldsa_native_config.h"+#endif++/* Namespace prefix for the public API symbols. For multi-level builds, the+ * parameter set is appended to disambiguate the security levels. */+#if defined(MLD_CONFIG_MULTILEVEL_BUILD)+#define MLD_API_NAMESPACE_PREFIX \+ MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET)+#else+#define MLD_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX+#endif++#define MLD_API_NAMESPACE(sym) \+ MLD_API_CONCAT_UNDERSCORE(MLD_API_NAMESPACE_PREFIX, sym)++#if defined(__GNUC__) || defined(__clang__)+#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result))+#else+#define MLD_API_MUST_CHECK_RETURN_VALUE+#endif++#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER)+#define MLD_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER+#else+#define MLD_API_QUALIFIER+#endif++/* Hash algorithm constants for domain separation */+#define MLD_PREHASH_NONE 0+#define MLD_PREHASH_SHA2_224 1+#define MLD_PREHASH_SHA2_256 2+#define MLD_PREHASH_SHA2_384 3+#define MLD_PREHASH_SHA2_512 4+#define MLD_PREHASH_SHA2_512_224 5+#define MLD_PREHASH_SHA2_512_256 6+#define MLD_PREHASH_SHA3_224 7+#define MLD_PREHASH_SHA3_256 8+#define MLD_PREHASH_SHA3_384 9+#define MLD_PREHASH_SHA3_512 10+#define MLD_PREHASH_SHAKE_128 11+#define MLD_PREHASH_SHAKE_256 12++/* Maximum formatted domain separation message length */+#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64)++/****************************** Function API **********************************/++#if !defined(MLD_CONFIG_CONSTANTS_ONLY)++#include <stddef.h>+#include <stdint.h>++#ifdef __cplusplus+extern "C"+{+#endif++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+/**+ * Generate a public-private key pair from a seed.+ *+ * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise Consistency Test+ * (PCT) as required by FIPS 140-3 IG.+ *+ * @warning The seed must be generated by a cryptographically secure random+ * number generator.+ *+ * @spec{Implements @[FIPS204, Algorithm 6, ML-DSA.KeyGen_internal].}+ *+ * @param[out] pk Output public key.+ * @param[out] sk Output private key.+ * @param[in] seed Input random seed.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_RNG_FAIL Random number generation failed+ * during the PCT. Only possible when+ * MLD_CONFIG_KEYGEN_PCT is enabled.+ * @retval MLD_ERR_SIGNING_PAUSED The PCT's signing step was paused by+ * a MLD_CONFIG_SIGN_HOOK_ATTEMPT hook.+ * This should currently never happen:+ * signing hooks require+ * MLD_CONFIG_NO_RANDOMIZED_API, which+ * is incompatible with+ * MLD_CONFIG_KEYGEN_PCT, so the two+ * cannot be enabled simultaneously.+ * @retval MLD_ERR_PCT_FAIL MLD_CONFIG_KEYGEN_PCT is enabled and+ * the PCT check failed.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(keypair_internal)(+ uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)],+ uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)],+ const uint8_t seed[MLDSA_SEEDBYTES]+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);++#if !defined(MLD_CONFIG_CORE_API_ONLY)+#if !defined(MLD_CONFIG_NO_RANDOMIZED_API)+/**+ * Generate a public-private key pair.+ *+ * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise Consistency Test+ * (PCT) as required by FIPS 140-3 IG.+ *+ * @spec{Implements @[FIPS204, Algorithm 1, ML-DSA.KeyGen].}+ *+ * @param[out] pk Output public key.+ * @param[out] sk Output private key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_RNG_FAIL Random number generation failed.+ * @retval MLD_ERR_SIGNING_PAUSED The PCT's signing step was paused by+ * a MLD_CONFIG_SIGN_HOOK_ATTEMPT hook.+ * This should currently never happen:+ * signing hooks require+ * MLD_CONFIG_NO_RANDOMIZED_API, which+ * is incompatible with+ * MLD_CONFIG_KEYGEN_PCT, so the two+ * cannot be enabled simultaneously.+ * @retval MLD_ERR_PCT_FAIL MLD_CONFIG_KEYGEN_PCT is enabled and+ * the PCT check failed.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(keypair)(+ uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)],+ uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)]+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+/**+ * Compute signature using a caller-supplied random seed and prefix.+ *+ * On error (non-zero return value), the signature buffer sig is zeroized.+ *+ * @spec{Implements @[FIPS204, Algorithm 7, ML-DSA.Sign_internal].}+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Pointer to buffer to hold the generated signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] m Pointer to message to be signed (when+ * externalmu == 0), or to a precomputed+ * message representative mu (when externalmu != 0).+ * @param mlen Length of m. Must equal MLDSA_CRHBYTES when+ * externalmu != 0.+ * @param[in] pre Pointer to prefix string. Ignored when+ * externalmu != 0.+ * @param prelen Length of prefix string. Ignored when+ * externalmu != 0.+ * @param[in] rnd Random seed.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param externalmu 0: m/mlen is the raw message; mu = H(tr, pre, m) is+ * computed internally.+ * non-zero: m points to a precomputed mu of+ * MLDSA_CRHBYTES bytes; pre/prelen unused.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(signature_internal)(+ uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)], const uint8_t *m,+ size_t mlen, const uint8_t *pre, size_t prelen,+ const uint8_t rnd[MLDSA_RNDBYTES],+ const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)],+ int externalmu+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);++#if !defined(MLD_CONFIG_CORE_API_ONLY)+#if !defined(MLD_CONFIG_NO_RANDOMIZED_API)+/**+ * Compute signature. This function implements the randomized variant of+ * ML-DSA. If you require the deterministic variant, use+ * signature_internal directly.+ *+ * @spec{Implements @[FIPS204, Algorithm 2, ML-DSA.Sign].}+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Pointer to buffer to hold the generated signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] m Pointer to message to be signed. May be NULL if+ * mlen == 0.+ * @param mlen Length of message.+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string. Should be <= 255.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_RNG_FAIL Random number generation failed.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ * @retval MLD_ERR_INVALID_ARG The context string exceeded 255+ * bytes.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(signature)(+ uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)], const uint8_t *m,+ size_t mlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)]+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);++/**+ * Compute signature in "external mu" mode: the caller has already computed+ * the message representative mu = SHAKE256(tr || M', 64), where+ * tr = SHAKE256(pk, 64) and M' is the FIPS 204 formatted message (e.g.+ * 0x00 || ctxlen || ctx || msg for pure ML-DSA). This is useful when the+ * message is large or streamed and cannot be held in memory.+ *+ * @spec{Implements @[FIPS204, Algorithm 2, ML-DSA.Sign external mu variant].}+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Pointer to buffer to hold the generated signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] mu Precomputed message representative.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_RNG_FAIL Random number generation failed.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(signature_extmu)(+ uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)],+ const uint8_t mu[MLDSA_CRHBYTES],+ const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)]+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);++#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+/**+ * Verify signature. Internal API.+ *+ * @spec{Implements @[FIPS204, Algorithm 8, ML-DSA.Verify_internal].}+ *+ * @param[in] sig Pointer to input signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] m Pointer to message (when externalmu == 0), or to a+ * precomputed message representative mu (when+ * externalmu != 0).+ * @param mlen Length of m. Must equal MLDSA_CRHBYTES when+ * externalmu != 0.+ * @param[in] pre Pointer to prefix string. Ignored when externalmu != 0.+ * @param prelen Length of prefix string. Ignored when externalmu != 0.+ * @param[in] pk Bit-packed public key.+ * @param externalmu 0: m/mlen is the raw message; mu = H(H(pk), pre, m) is+ * computed internally.+ * non-zero: m points to a precomputed mu of+ * MLDSA_CRHBYTES bytes; pre/prelen unused.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(verify_internal)(+ const uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)], const uint8_t *m,+ size_t mlen, const uint8_t *pre, size_t prelen,+ const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)],+ int externalmu+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);++#if !defined(MLD_CONFIG_CORE_API_ONLY)+/**+ * Verify signature.+ *+ * @spec{Implements @[FIPS204, Algorithm 3, ML-DSA.Verify].}+ *+ * @param[in] sig Pointer to input signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] m Pointer to message. May be NULL if mlen == 0.+ * @param mlen Length of message.+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] pk Bit-packed public key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ * @retval MLD_ERR_INVALID_ARG The context string exceeded 255 bytes.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(verify)(+ const uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)], const uint8_t *m,+ size_t mlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)]+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);++/**+ * Verify signature in "external mu" mode: the caller has already computed+ * the message representative mu = SHAKE256(tr || M', 64), where+ * tr = SHAKE256(pk, 64) and M' is the FIPS 204 formatted message (e.g.+ * 0x00 || ctxlen || ctx || msg for pure ML-DSA). The same mu must have+ * been used at signing time.+ *+ * @spec{Implements @[FIPS204, Algorithm 3, ML-DSA.Verify external mu variant].}+ *+ * @param[in] sig Pointer to input signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] mu Precomputed message representative.+ * @param[in] pk Bit-packed public key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(verify_extmu)(+ const uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)],+ const uint8_t mu[MLDSA_CRHBYTES],+ const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)]+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);++#endif /* !MLD_CONFIG_CORE_API_ONLY */+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_CORE_API_ONLY)+#if !defined(MLD_CONFIG_NO_SIGN_API)+/**+ * Compute signature with pre-hashed message.+ *+ * @spec{Implements @[FIPS204, Algorithm 4, HashML-DSA.Sign].}+ *+ * Supported hash algorithm constants:+ * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384,+ * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256,+ * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384,+ * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256.+ *+ * MLD_PREHASH_NONE is rejected by this API.+ *+ * @warning This is an unstable API that may change in the future. If you need+ * a stable API use signature_pre_hash_shake256.+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Pointer to buffer to hold the generated signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] ph Pointer to pre-hashed message.+ * @param phlen Length of pre-hashed message. Must match the output+ * length of hashalg (the digest size for SHA-2/SHA-3,+ * 32 bytes for MLD_PREHASH_SHAKE_128, 64 bytes for+ * MLD_PREHASH_SHAKE_256).+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] rnd Random seed.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param hashalg Hash algorithm constant (one of MLD_PREHASH_*).+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ * @retval MLD_ERR_INVALID_ARG The pre-hash algorithm was+ * MLD_PREHASH_NONE or unsupported,+ * phlen did not match the output+ * length of hashalg, or the context+ * string exceeded 255 bytes.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(signature_pre_hash_internal)(+ uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)], const uint8_t *ph,+ size_t phlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t rnd[MLDSA_RNDBYTES],+ const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)],+ int hashalg+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+/**+ * Verifies signature with pre-hashed message.+ *+ * @spec{Implements @[FIPS204, Algorithm 5, HashML-DSA.Verify].}+ *+ * Supported hash algorithm constants:+ * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384,+ * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256,+ * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384,+ * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256.+ *+ * MLD_PREHASH_NONE is rejected by this API.+ *+ * @warning This is an unstable API that may change in the future. If you need+ * a stable API use verify_pre_hash_shake256.+ *+ * @param[in] sig Pointer to input signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] ph Pointer to pre-hashed message.+ * @param phlen Length of pre-hashed message. Must match the output+ * length of hashalg (the digest size for SHA-2/SHA-3,+ * 32 bytes for MLD_PREHASH_SHAKE_128, 64 bytes for+ * MLD_PREHASH_SHAKE_256).+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] pk Bit-packed public key.+ * @param hashalg Hash algorithm constant (one of MLD_PREHASH_*).+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ * @retval MLD_ERR_INVALID_ARG The pre-hash algorithm was+ * MLD_PREHASH_NONE or unsupported, phlen+ * did not match the output length of+ * hashalg, or the context string exceeded+ * 255 bytes.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(verify_pre_hash_internal)(+ const uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)], const uint8_t *ph,+ size_t phlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)],+ int hashalg+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+/**+ * Compute signature with pre-hashed message using SHAKE256. This function+ * computes the SHAKE256 hash of the message internally.+ *+ * @spec{Implements @[FIPS204, Algorithm 4, HashML-DSA.Sign] with SHAKE256 as+ * the pre-hash.}+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Pointer to buffer to hold the generated signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] m Pointer to message to be hashed and signed. May be+ * NULL if mlen == 0.+ * @param mlen Length of message.+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] rnd Random seed.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ * @retval MLD_ERR_INVALID_ARG The context string exceeded 255+ * bytes.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(signature_pre_hash_shake256)(+ uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)], const uint8_t *m,+ size_t mlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t rnd[MLDSA_RNDBYTES],+ const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)]+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+/**+ * Verify signature with pre-hashed message using SHAKE256. This function+ * computes the SHAKE256 hash of the message internally.+ *+ * @spec{Implements @[FIPS204, Algorithm 5, HashML-DSA.Verify] with SHAKE256 as+ * the pre-hash.}+ *+ * @param[in] sig Pointer to input signature of+ * MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) bytes.+ * @param[in] m Pointer to message to be hashed and verified. May be+ * NULL if mlen == 0.+ * @param mlen Length of message.+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] pk Bit-packed public key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ * @retval MLD_ERR_INVALID_ARG The context string exceeded 255 bytes.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(verify_pre_hash_shake256)(+ const uint8_t sig[MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)], const uint8_t *m,+ size_t mlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)]+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */++#if !defined(MLD_CONFIG_CORE_API_ONLY)+/**+ * Prepare domain separation prefix for ML-DSA signing.+ *+ * For pure ML-DSA (hashalg == MLD_PREHASH_NONE):+ * Format: 0x00 || ctxlen (1 byte) || ctx.+ *+ * For HashML-DSA (hashalg != MLD_PREHASH_NONE):+ * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph.+ *+ * This function is useful for building incremental signing APIs.+ *+ * @spec{For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements+ * @[FIPS204, Algorithm 4, line 23]. For Pure ML-DSA+ * (hashalg == MLD_PREHASH_NONE), implements+ * ```+ * M' <- BytesToBits(IntegerToBytes(0, 1)+ * || IntegerToBytes(|ctx|, 1)+ * || ctx+ * ```+ * which is part of @[FIPS204, Algorithm 2, ML-DSA.Sign, line 10] and+ * @[FIPS204, Algorithm 3, ML-DSA.Verify, line 5].}+ *+ * @param[out] prefix Output domain separation prefix buffer.+ * @param[in] ph Pointer to pre-hashed message (ignored for pure+ * ML-DSA).+ * @param phlen Length of pre-hashed message; must match the output+ * length of hashalg (ignored for pure ML-DSA).+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param hashalg Hash algorithm constant (MLD_PREHASH_NONE for pure+ * ML-DSA, or MLD_PREHASH_* for HashML-DSA).+ *+ * @return The total length of the formatted prefix, or 0 on error.+ * Errors are:+ * - The context string exceeded 255 bytes.+ * - For HashML-DSA: hashalg was unsupported, ph was NULL, or phlen+ * did not match the output length of hashalg.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)(+ uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph,+ size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg);++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+/**+ * Perform basic validity checks on secret key, and derive public key.+ *+ * Referring to the decoding of the secret key `sk=(rho, K, tr, s1, s2, t0)`+ * (cf. @[FIPS204, Algorithm 25, skDecode]), the following checks are+ * performed:+ * - Check that s1 and s2 have coefficients in [-MLDSA_ETA, MLDSA_ETA].+ * - Check that t0 and tr stored in sk match recomputed values.+ *+ * @note This function leaks whether the secret key is valid or invalid+ * through its return value and timing.+ *+ * @param[out] pk Output public key.+ * @param[in] sk Input secret key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was used and an+ * allocation via MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_KEY Secret key validation failed.+ */+MLD_API_QUALIFIER+MLD_API_MUST_CHECK_RETURN_VALUE+int MLD_API_NAMESPACE(pk_from_sk)(+ uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)],+ const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)]+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+ ,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */++#ifdef __cplusplus+}+#endif++#undef MLD_API_NAMESPACE_PREFIX++#endif /* !MLD_CONFIG_CONSTANTS_ONLY */++/***************************** Memory Usage **********************************/++/*+ * By default mldsa-native performs all memory allocations on the stack.+ * Alternatively, mldsa-native supports custom allocation of large structures+ * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option.+ * See mldsa_native_config.h for details.+ *+ * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum+ * (accumulative) allocation via MLD_ALLOC for each parameter set and operation.+ * Note that some stack allocation remains even+ * when using custom allocators, so these values are lower than total stack+ * usage with the default stack-only allocation.+ *+ * These constants may be used to implement custom allocations using a+ * fixed-sized buffer and a simple allocator (e.g., bump allocator).+ */+/* check-magic: off */+#if !defined(MLD_CONFIG_REDUCE_RAM)+#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 26912+#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 48480+#define MLD_TOTAL_ALLOC_44_PK_FROM_SK 28480+#define MLD_TOTAL_ALLOC_44_SIGN 44704+#define MLD_TOTAL_ALLOC_44_VERIFY 24448+#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 44320+#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 74624+#define MLD_TOTAL_ALLOC_65_PK_FROM_SK 46720+#define MLD_TOTAL_ALLOC_65_SIGN 69312+#define MLD_TOTAL_ALLOC_65_VERIFY 39872+#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 75040+#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 115488+#define MLD_TOTAL_ALLOC_87_PK_FROM_SK 78272+#define MLD_TOTAL_ALLOC_87_SIGN 108224+#define MLD_TOTAL_ALLOC_87_VERIFY 68800+#else /* !MLD_CONFIG_REDUCE_RAM */+#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 11584+#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 16896+#define MLD_TOTAL_ALLOC_44_PK_FROM_SK 13152+#define MLD_TOTAL_ALLOC_44_SIGN 13120+#define MLD_TOTAL_ALLOC_44_VERIFY 9120+#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 14656+#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 22560+#define MLD_TOTAL_ALLOC_65_PK_FROM_SK 17056+#define MLD_TOTAL_ALLOC_65_SIGN 17248+#define MLD_TOTAL_ALLOC_65_VERIFY 10208+#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 18752+#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 28608+#define MLD_TOTAL_ALLOC_87_PK_FROM_SK 21984+#define MLD_TOTAL_ALLOC_87_SIGN 21344+#define MLD_TOTAL_ALLOC_87_VERIFY 12512+#endif /* MLD_CONFIG_REDUCE_RAM */+/* check-magic: on */++/*+ * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT.+ */+#if defined(MLD_CONFIG_KEYGEN_PCT)+#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT+#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT+#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT+#else+#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT+#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT+#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT+#endif++#define MLD_MAX3_(a, b, c) \+ ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c)))+#define MLD_MAX4_(a, b, c, d) MLD_MAX3_((a), (b), MLD_MAX3_((c), (d), (d)))++/*+ * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across standard API operations+ * (keygen, sign, verify) for each parameter set.+ */+#define MLD_TOTAL_ALLOC_44 \+ MLD_MAX4_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_PK_FROM_SK, \+ MLD_TOTAL_ALLOC_44_SIGN, MLD_TOTAL_ALLOC_44_VERIFY)+#define MLD_TOTAL_ALLOC_65 \+ MLD_MAX4_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_PK_FROM_SK, \+ MLD_TOTAL_ALLOC_65_SIGN, MLD_TOTAL_ALLOC_65_VERIFY)+#define MLD_TOTAL_ALLOC_87 \+ MLD_MAX4_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_PK_FROM_SK, \+ MLD_TOTAL_ALLOC_87_SIGN, MLD_TOTAL_ALLOC_87_VERIFY)++#endif /* !MLD_H */
@@ -0,0 +1,830 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++/******************************************************************************+ *+ * Single assembly unit for fixed-level build of mldsa-native+ *+ * This assembly unit bundles together all assembly files for a build+ * of mldsa-native for a fixed security level (MLDSA-44/65/87).+ *+ * # Multi-level build+ *+ * If you want an SCU build of mldsa-native with support for multiple security+ * levels, you should include this file once with+ * MLD_CONFIG_MULTILEVEL_WITH_SHARED set.+ *+ * (You could also follow the same pattern as for mldsa_native.c+ * and include it for every level, setting MLD_CONFIG_MULTILEVEL_NO_SHARED+ * for all but one. For builds with MLD_CONFIG_MULTILEVEL_NO_SHARED, this+ * file will then be ignored.)+ *+ * # Configuration+ *+ * The following options from the mldsa-native configuration are relevant:+ *+ * - MLD_CONFIG_FIPS202_CUSTOM_HEADER+ * Set this option if you use a custom FIPS202 implementation.+ *+ * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH+ * Set this option if you want to include the native arithmetic backends+ * in your build.+ *+ * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202+ * Set this option if you want to include the native FIPS202 backends+ * in your build.+ *+ * - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+ * Set this option if you want to keep the directives defined in+ * level-independent headers. This is needed for a multi-level build.+ */++/* If parts of the mldsa-native source tree are not used,+ * consider reducing this header via `unifdef`.+ *+ * Example:+ * ```bash+ * unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native_asm.S+ * ```+ */++#include "src/common.h"++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)+#if defined(MLD_SYS_AARCH64)+#include "src/native/aarch64/src/mldsa_intt_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_ntt_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_pointwise_montgomery_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_poly_caddq_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_poly_chknorm_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_poly_decompose_32_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_poly_decompose_88_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_poly_use_hint_32_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_poly_use_hint_88_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_polyz_unpack_17_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_polyz_unpack_19_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_rej_uniform_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_rej_uniform_eta2_aarch64_asm.S"+#include "src/native/aarch64/src/mldsa_rej_uniform_eta4_aarch64_asm.S"+#endif /* MLD_SYS_AARCH64 */+#if defined(MLD_SYS_X86_64)+#include "src/native/x86_64/src/mldsa_intt_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_ntt_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_nttunpack_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_pointwise_acc_l4_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_pointwise_acc_l5_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_pointwise_acc_l7_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_pointwise_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_poly_caddq_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_poly_chknorm_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_poly_decompose_32_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_poly_decompose_88_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_poly_use_hint_32_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_poly_use_hint_88_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_polyz_unpack_17_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_polyz_unpack_19_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_rej_uniform_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_rej_uniform_eta2_avx2_asm.S"+#include "src/native/x86_64/src/mldsa_rej_uniform_eta4_avx2_asm.S"+#endif /* MLD_SYS_X86_64 */+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)+#if defined(MLD_SYS_AARCH64)+#include "src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_aarch64_asm.S"+#include "src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_aarch64_asm.S"+#include "src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_aarch64_asm.S"+#include "src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.S"+#include "src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.S"+#endif /* MLD_SYS_AARCH64 */+#if defined(MLD_SYS_X86_64)+#include "src/fips202/native/x86_64/src/keccak_f1600_x4_avx2_asm.S"+#endif+#if defined(MLD_SYS_ARMV81M_MVE)+#include "src/fips202/native/armv81m/src/keccak_f1600_x4_mve.S"+#include "src/fips202/native/armv81m/src/keccak_f1600_x4_state_extract_bytes_mve.S"+#include "src/fips202/native/armv81m/src/keccak_f1600_x4_state_xor_bytes_mve.S"+#endif+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */+++/* Macro #undef's+ *+ * The following undefines macros from headers+ * included by the source files imported above.+ *+ * This is to allow building and linking multiple builds+ * of mldsa-native for varying parameter sets through concatenation+ * of this file, as if the files had been compiled separately.+ * If this is not relevant to you, you may remove the following.+ *+ * NOTE: This is not needed for the assembly SCU since, at present,+ * there is no need to include it multiple times.+ * We keep it for uniformity with mldsa_native.c only.+ *+ * NOTE: To avoid having to distinguish between which headers are included+ * from the assembly files, we #undef the same set of directives+ * as in mldsa_native.c+ */++/*+ * Undefine macros from MLD_CONFIG_PARAMETER_SET-specific files+ */+/* mldsa/mldsa_native.h */+#undef MLDSA44_BYTES+#undef MLDSA44_CRHBYTES+#undef MLDSA44_PUBLICKEYBYTES+#undef MLDSA44_RNDBYTES+#undef MLDSA44_SECRETKEYBYTES+#undef MLDSA44_SEEDBYTES+#undef MLDSA44_TRBYTES+#undef MLDSA65_BYTES+#undef MLDSA65_CRHBYTES+#undef MLDSA65_PUBLICKEYBYTES+#undef MLDSA65_RNDBYTES+#undef MLDSA65_SECRETKEYBYTES+#undef MLDSA65_SEEDBYTES+#undef MLDSA65_TRBYTES+#undef MLDSA87_BYTES+#undef MLDSA87_CRHBYTES+#undef MLDSA87_PUBLICKEYBYTES+#undef MLDSA87_RNDBYTES+#undef MLDSA87_SECRETKEYBYTES+#undef MLDSA87_SEEDBYTES+#undef MLDSA87_TRBYTES+#undef MLDSA_BYTES+#undef MLDSA_BYTES_+#undef MLDSA_CRHBYTES+#undef MLDSA_PUBLICKEYBYTES+#undef MLDSA_PUBLICKEYBYTES_+#undef MLDSA_RNDBYTES+#undef MLDSA_SECRETKEYBYTES+#undef MLDSA_SECRETKEYBYTES_+#undef MLDSA_SEEDBYTES+#undef MLDSA_TRBYTES+#undef MLD_API_CONCAT+#undef MLD_API_CONCAT_+#undef MLD_API_CONCAT_UNDERSCORE+#undef MLD_API_MUST_CHECK_RETURN_VALUE+#undef MLD_API_NAMESPACE+#undef MLD_API_NAMESPACE_PREFIX+#undef MLD_API_QUALIFIER+#undef MLD_DOMAIN_SEPARATION_MAX_BYTES+#undef MLD_ERR_FAIL+#undef MLD_ERR_INVALID_ARG+#undef MLD_ERR_INVALID_KEY+#undef MLD_ERR_INVALID_SIGNATURE+#undef MLD_ERR_OUT_OF_MEMORY+#undef MLD_ERR_PCT_FAIL+#undef MLD_ERR_RNG_FAIL+#undef MLD_ERR_SIGNING_PAUSED+#undef MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED+#undef MLD_H+#undef MLD_MAX3_+#undef MLD_MAX4_+#undef MLD_PREHASH_NONE+#undef MLD_PREHASH_SHA2_224+#undef MLD_PREHASH_SHA2_256+#undef MLD_PREHASH_SHA2_384+#undef MLD_PREHASH_SHA2_512+#undef MLD_PREHASH_SHA2_512_224+#undef MLD_PREHASH_SHA2_512_256+#undef MLD_PREHASH_SHA3_224+#undef MLD_PREHASH_SHA3_256+#undef MLD_PREHASH_SHA3_384+#undef MLD_PREHASH_SHA3_512+#undef MLD_PREHASH_SHAKE_128+#undef MLD_PREHASH_SHAKE_256+#undef MLD_TOTAL_ALLOC_44+#undef MLD_TOTAL_ALLOC_44_KEYPAIR+#undef MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT+#undef MLD_TOTAL_ALLOC_44_KEYPAIR_PCT+#undef MLD_TOTAL_ALLOC_44_PK_FROM_SK+#undef MLD_TOTAL_ALLOC_44_SIGN+#undef MLD_TOTAL_ALLOC_44_VERIFY+#undef MLD_TOTAL_ALLOC_65+#undef MLD_TOTAL_ALLOC_65_KEYPAIR+#undef MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT+#undef MLD_TOTAL_ALLOC_65_KEYPAIR_PCT+#undef MLD_TOTAL_ALLOC_65_PK_FROM_SK+#undef MLD_TOTAL_ALLOC_65_SIGN+#undef MLD_TOTAL_ALLOC_65_VERIFY+#undef MLD_TOTAL_ALLOC_87+#undef MLD_TOTAL_ALLOC_87_KEYPAIR+#undef MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT+#undef MLD_TOTAL_ALLOC_87_KEYPAIR_PCT+#undef MLD_TOTAL_ALLOC_87_PK_FROM_SK+#undef MLD_TOTAL_ALLOC_87_SIGN+#undef MLD_TOTAL_ALLOC_87_VERIFY+/* mldsa/src/common.h */+#undef MLD_ADD_PARAM_SET+#undef MLD_ALLOC+#undef MLD_APPLY+#undef MLD_ASM_FN_SIZE+#undef MLD_ASM_FN_SYMBOL+#undef MLD_ASM_NAMESPACE+#undef MLD_BUILD_INTERNAL+#undef MLD_COMMON_H+#undef MLD_CONCAT+#undef MLD_CONCAT_+#undef MLD_EMPTY_CU+#undef MLD_ERR_FAIL+#undef MLD_ERR_INVALID_ARG+#undef MLD_ERR_INVALID_KEY+#undef MLD_ERR_INVALID_SIGNATURE+#undef MLD_ERR_OUT_OF_MEMORY+#undef MLD_ERR_PCT_FAIL+#undef MLD_ERR_RNG_FAIL+#undef MLD_ERR_SIGNING_PAUSED+#undef MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED+#undef MLD_EXTERNAL_API+#undef MLD_FIPS202X4_HEADER_FILE+#undef MLD_FIPS202_HEADER_FILE+#undef MLD_FREE+#undef MLD_INTERNAL_API+#undef MLD_INTERNAL_DATA_DECLARATION+#undef MLD_INTERNAL_DATA_DEFINITION+#undef MLD_MULTILEVEL_BUILD+#undef MLD_NAMESPACE+#undef MLD_NAMESPACE_KL+#undef MLD_NAMESPACE_PREFIX+#undef MLD_NAMESPACE_PREFIX_KL+#undef mld_memcpy+#undef mld_memset+/* mldsa/src/packing.h */+#undef MLD_PACKING_H+#undef mld_pack_sig_c+#undef mld_pack_sig_h+#undef mld_pack_sig_z+#undef mld_pack_sk_rho_key_tr_s2+#undef mld_pack_sk_s1+#undef mld_sig_unpack_hints+#undef mld_unpack_pk_t1+#undef mld_unpack_sk+/* mldsa/src/params.h */+#undef MLDSA_BETA+#undef MLDSA_CRHBYTES+#undef MLDSA_CRYPTO_BYTES+#undef MLDSA_CRYPTO_PUBLICKEYBYTES+#undef MLDSA_CRYPTO_SECRETKEYBYTES+#undef MLDSA_CTILDEBYTES+#undef MLDSA_D+#undef MLDSA_ETA+#undef MLDSA_GAMMA1+#undef MLDSA_GAMMA2+#undef MLDSA_GAMMA2_32+#undef MLDSA_GAMMA2_88+#undef MLDSA_K+#undef MLDSA_L+#undef MLDSA_N+#undef MLDSA_OMEGA+#undef MLDSA_PK_END+#undef MLDSA_PK_RHO_BYTES+#undef MLDSA_PK_RHO_OFFSET+#undef MLDSA_PK_T1_BYTES+#undef MLDSA_PK_T1_OFFSET+#undef MLDSA_POLYETA_PACKEDBYTES+#undef MLDSA_POLYT0_PACKEDBYTES+#undef MLDSA_POLYT1_PACKEDBYTES+#undef MLDSA_POLYVECH_PACKEDBYTES+#undef MLDSA_POLYW1_PACKEDBYTES+#undef MLDSA_POLYW1_PACKEDBYTES_32+#undef MLDSA_POLYW1_PACKEDBYTES_88+#undef MLDSA_POLYZ_PACKEDBYTES+#undef MLDSA_Q+#undef MLDSA_Q_HALF+#undef MLDSA_RNDBYTES+#undef MLDSA_SEEDBYTES+#undef MLDSA_SIG_C_BYTES+#undef MLDSA_SIG_C_OFFSET+#undef MLDSA_SIG_END+#undef MLDSA_SIG_H_BYTES+#undef MLDSA_SIG_H_OFFSET+#undef MLDSA_SIG_Z_BYTES+#undef MLDSA_SIG_Z_OFFSET+#undef MLDSA_SK_END+#undef MLDSA_SK_KEY_BYTES+#undef MLDSA_SK_KEY_OFFSET+#undef MLDSA_SK_RHO_BYTES+#undef MLDSA_SK_RHO_OFFSET+#undef MLDSA_SK_S1_BYTES+#undef MLDSA_SK_S1_OFFSET+#undef MLDSA_SK_S2_BYTES+#undef MLDSA_SK_S2_OFFSET+#undef MLDSA_SK_T0_BYTES+#undef MLDSA_SK_T0_OFFSET+#undef MLDSA_SK_TR_BYTES+#undef MLDSA_SK_TR_OFFSET+#undef MLDSA_TAU+#undef MLDSA_TRBYTES+#undef MLD_MAX_KAPPA+#undef MLD_PARAMS_H+/* mldsa/src/poly_kl.h */+#undef MLD_POLYETA_UNPACK_LOWER_BOUND+#undef MLD_POLY_KL_H+#undef mld_poly_challenge+#undef mld_poly_decompose+#undef mld_poly_uniform_eta+#undef mld_poly_uniform_eta_4x+#undef mld_poly_uniform_gamma1+#undef mld_poly_uniform_gamma1_4x+#undef mld_poly_use_hint+#undef mld_polyeta_pack+#undef mld_polyeta_unpack+#undef mld_polyw1_pack+#undef mld_polyz_pack+#undef mld_polyz_unpack+/* mldsa/src/polyvec.h */+#undef MLD_POLYVEC_H+#undef mld_polyveck+#undef mld_polyveck_caddq+#undef mld_polyveck_chknorm+#undef mld_polyveck_decompose+#undef mld_polyveck_invntt_tomont+#undef mld_polyveck_ntt+#undef mld_polyveck_pack_eta+#undef mld_polyveck_pack_w1+#undef mld_polyveck_reduce+#undef mld_polyveck_unpack_eta+#undef mld_polyvecl+#undef mld_polyvecl_chknorm+#undef mld_polyvecl_ntt+#undef mld_polyvecl_pack_eta+#undef mld_polyvecl_pointwise_acc_montgomery+#undef mld_polyvecl_uniform_gamma1+#undef mld_polyvecl_unpack_eta+#undef mld_polyvecl_unpack_z+/* mldsa/src/polyvec_lazy.h */+#undef MLD_POLYVEC_LAZY_H+#undef mld_poly_permute_bitrev_to_custom_optional+#undef mld_polymat+#undef mld_polymat_eager+#undef mld_polymat_lazy+#undef mld_polyvec_matrix_expand+#undef mld_polyvec_matrix_expand_eager+#undef mld_polyvec_matrix_expand_lazy+#undef mld_polyvec_matrix_pointwise_montgomery+#undef mld_polyvec_matrix_pointwise_montgomery_row+#undef mld_polyvec_matrix_pointwise_montgomery_row_eager+#undef mld_polyvec_matrix_pointwise_montgomery_row_lazy+#undef mld_polyvec_matrix_pointwise_montgomery_yvec+#undef mld_polyvec_matrix_pointwise_montgomery_yvec_eager+#undef mld_polyvec_matrix_pointwise_montgomery_yvec_lazy+#undef mld_sk_s1hat+#undef mld_sk_s1hat_eager+#undef mld_sk_s1hat_get_poly+#undef mld_sk_s1hat_get_poly_eager+#undef mld_sk_s1hat_get_poly_lazy+#undef mld_sk_s1hat_lazy+#undef mld_sk_s2hat+#undef mld_sk_s2hat_eager+#undef mld_sk_s2hat_get_poly+#undef mld_sk_s2hat_get_poly_eager+#undef mld_sk_s2hat_get_poly_lazy+#undef mld_sk_s2hat_lazy+#undef mld_sk_t0hat+#undef mld_sk_t0hat_eager+#undef mld_sk_t0hat_get_poly+#undef mld_sk_t0hat_get_poly_eager+#undef mld_sk_t0hat_get_poly_lazy+#undef mld_sk_t0hat_lazy+#undef mld_unpack_sk_s1hat+#undef mld_unpack_sk_s1hat_eager+#undef mld_unpack_sk_s1hat_lazy+#undef mld_unpack_sk_s2hat+#undef mld_unpack_sk_s2hat_eager+#undef mld_unpack_sk_s2hat_lazy+#undef mld_unpack_sk_t0hat+#undef mld_unpack_sk_t0hat_eager+#undef mld_unpack_sk_t0hat_lazy+#undef mld_yvec+#undef mld_yvec_eager+#undef mld_yvec_get_poly+#undef mld_yvec_get_poly_eager+#undef mld_yvec_get_poly_lazy+#undef mld_yvec_init+#undef mld_yvec_init_eager+#undef mld_yvec_init_lazy+#undef mld_yvec_lazy+/* mldsa/src/rounding.h */+#undef MLD_2_POW_D+#undef MLD_ROUNDING_H+#undef mld_decompose+#undef mld_make_hint+#undef mld_power2round+#undef mld_use_hint+/* mldsa/src/sign.h */+#undef MLD_DOMAIN_SEPARATION_MAX_BYTES+#undef MLD_PREHASH_NONE+#undef MLD_PREHASH_SHA2_224+#undef MLD_PREHASH_SHA2_256+#undef MLD_PREHASH_SHA2_384+#undef MLD_PREHASH_SHA2_512+#undef MLD_PREHASH_SHA2_512_224+#undef MLD_PREHASH_SHA2_512_256+#undef MLD_PREHASH_SHA3_224+#undef MLD_PREHASH_SHA3_256+#undef MLD_PREHASH_SHA3_384+#undef MLD_PREHASH_SHA3_512+#undef MLD_PREHASH_SHAKE_128+#undef MLD_PREHASH_SHAKE_256+#undef MLD_SIGN_H+#undef mld_prepare_domain_separation_prefix+#undef mld_sign_keypair+#undef mld_sign_keypair_internal+#undef mld_sign_pk_from_sk+#undef mld_sign_signature+#undef mld_sign_signature_extmu+#undef mld_sign_signature_internal+#undef mld_sign_signature_pre_hash_internal+#undef mld_sign_signature_pre_hash_shake256+#undef mld_sign_verify+#undef mld_sign_verify_extmu+#undef mld_sign_verify_internal+#undef mld_sign_verify_pre_hash_internal+#undef mld_sign_verify_pre_hash_shake256++#if !defined(MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS)+/*+ * Undefine macros from MLD_CONFIG_PARAMETER_SET-generic files+ */+/* mldsa/src/context.h */+#undef MLD_CONTEXT_H+#undef MLD_CONTEXT_PARAMETERS_0+#undef MLD_CONTEXT_PARAMETERS_1+#undef MLD_CONTEXT_PARAMETERS_2+#undef MLD_CONTEXT_PARAMETERS_3+#undef MLD_CONTEXT_PARAMETERS_4+#undef MLD_CONTEXT_PARAMETERS_5+#undef MLD_CONTEXT_PARAMETERS_6+#undef MLD_CONTEXT_PARAMETERS_7+#undef MLD_CONTEXT_PARAMETERS_8+#undef MLD_CONTEXT_PARAMETERS_9+#undef MLD_CONTEXT_UNUSED+#undef mld_sign_attempt+#undef mld_sign_finish+#undef mld_sign_resume+/* mldsa/src/ct.h */+#undef MLD_CT_H+#undef MLD_USE_ASM_VALUE_BARRIER+#undef mld_ct_opt_blocker_u64+/* mldsa/src/debug.h */+#undef MLD_DEBUG_H+#undef mld_assert+#undef mld_assert_abs_bound+#undef mld_assert_abs_bound_2d+#undef mld_assert_bound+#undef mld_assert_bound_2d+#undef mld_debug_check_assert+#undef mld_debug_check_bounds+/* mldsa/src/poly.h */+#undef MLD_FQMUL_BOUND+#undef MLD_INTT_BOUND+#undef MLD_NTT_BOUND+#undef MLD_POLY_H+#undef mld_poly_add+#undef mld_poly_caddq+#undef mld_poly_chknorm+#undef mld_poly_invntt_tomont+#undef mld_poly_ntt+#undef mld_poly_pointwise_montgomery+#undef mld_poly_power2round+#undef mld_poly_reduce+#undef mld_poly_shiftl+#undef mld_poly_sub+#undef mld_poly_uniform+#undef mld_poly_uniform_4x+#undef mld_polyt0_pack+#undef mld_polyt0_unpack+#undef mld_polyt1_pack+#undef mld_polyt1_unpack+#undef mld_polyw1_pack_32+#undef mld_polyw1_pack_88+/* mldsa/src/randombytes.h */+#undef MLD_RANDOMBYTES_H+/* mldsa/src/reduce.h */+#undef MLD_MONT+#undef MLD_REDUCE32_DOMAIN_MAX+#undef MLD_REDUCE32_RANGE_MAX+#undef MLD_REDUCE_H+/* mldsa/src/symmetric.h */+#undef MLD_STREAM128_BLOCKBYTES+#undef MLD_STREAM256_BLOCKBYTES+#undef MLD_SYMMETRIC_H+#undef mld_xof128_absorb_once+#undef mld_xof128_ctx+#undef mld_xof128_init+#undef mld_xof128_release+#undef mld_xof128_squeezeblocks+#undef mld_xof128_x4_absorb+#undef mld_xof128_x4_ctx+#undef mld_xof128_x4_init+#undef mld_xof128_x4_release+#undef mld_xof128_x4_squeezeblocks+#undef mld_xof256_absorb_once+#undef mld_xof256_ctx+#undef mld_xof256_init+#undef mld_xof256_release+#undef mld_xof256_squeezeblocks+#undef mld_xof256_x4_absorb+#undef mld_xof256_x4_ctx+#undef mld_xof256_x4_init+#undef mld_xof256_x4_release+#undef mld_xof256_x4_squeezeblocks+/* mldsa/src/sys.h */+#undef MLD_ALIGN+#undef MLD_ALIGN_UP+#undef MLD_ALWAYS_INLINE+#undef MLD_CET_ENDBR+#undef MLD_CT_TESTING_DECLASSIFY+#undef MLD_CT_TESTING_SECRET+#undef MLD_DEFAULT_ALIGN+#undef MLD_HAVE_INLINE_ASM+#undef MLD_INLINE+#undef MLD_MUST_CHECK_RETURN_VALUE+#undef MLD_NOINLINE+#undef MLD_RESTRICT+#undef MLD_STATIC_TESTABLE+#undef MLD_SYSV_ABI+#undef MLD_SYSV_ABI_SUPPORTED+#undef MLD_SYS_AARCH64+#undef MLD_SYS_AARCH64_EB+#undef MLD_SYS_AARCH64_NEON+#undef MLD_SYS_APPLE+#undef MLD_SYS_ARMV81M_MVE+#undef MLD_SYS_BIG_ENDIAN+#undef MLD_SYS_H+#undef MLD_SYS_LINUX+#undef MLD_SYS_LITTLE_ENDIAN+#undef MLD_SYS_PPC64LE+#undef MLD_SYS_RISCV32+#undef MLD_SYS_RISCV64+#undef MLD_SYS_RISCV64_RVV+#undef MLD_SYS_WINDOWS+#undef MLD_SYS_X86_64+#undef MLD_SYS_X86_64_AVX2+/* mldsa/src/cbmc.h */+#undef MLD_CBMC_H+#undef __contract__+#undef __loop__++#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER)+/*+ * Undefine macros from FIPS-202 files+ */+/* mldsa/src/fips202/fips202.h */+#undef MLD_FIPS202_FIPS202_H+#undef MLD_KECCAK_LANES+#undef SHA3_256_HASHBYTES+#undef SHA3_256_RATE+#undef SHA3_512_HASHBYTES+#undef SHA3_512_RATE+#undef SHAKE128_RATE+#undef SHAKE256_RATE+#undef mld_shake128_absorb+#undef mld_shake128_finalize+#undef mld_shake128_init+#undef mld_shake128_release+#undef mld_shake128_squeeze+#undef mld_shake256+#undef mld_shake256_absorb+#undef mld_shake256_finalize+#undef mld_shake256_init+#undef mld_shake256_release+#undef mld_shake256_squeeze+/* mldsa/src/fips202/fips202x4.h */+#undef MLD_FIPS202_FIPS202X4_H+#undef mld_shake128x4_absorb_once+#undef mld_shake128x4_init+#undef mld_shake128x4_release+#undef mld_shake128x4_squeezeblocks+#undef mld_shake256x4_absorb_once+#undef mld_shake256x4_init+#undef mld_shake256x4_release+#undef mld_shake256x4_squeezeblocks+/* mldsa/src/fips202/keccakf1600.h */+#undef MLD_FIPS202_KECCAKF1600_H+#undef MLD_KECCAK_LANES+#undef MLD_KECCAK_WAY+#undef mld_keccakf1600_extract_bytes+#undef mld_keccakf1600_permute+#undef mld_keccakf1600_xor_bytes+#undef mld_keccakf1600x4_extract_bytes+#undef mld_keccakf1600x4_permute+#undef mld_keccakf1600x4_xor_bytes+#endif /* !MLD_CONFIG_FIPS202_CUSTOM_HEADER */++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)+/* mldsa/src/fips202/native/api.h */+#undef MLD_FIPS202_NATIVE_API_H+#undef MLD_NATIVE_FUNC_FALLBACK+#undef MLD_NATIVE_FUNC_SUCCESS+/* mldsa/src/fips202/native/auto.h */+#undef MLD_FIPS202_NATIVE_AUTO_H+#if defined(MLD_SYS_AARCH64)+/*+ * Undefine macros from native code (FIPS202, AArch64)+ */+/* mldsa/src/fips202/native/aarch64/auto.h */+#undef MLD_FIPS202_NATIVE_AARCH64_AUTO_H+/* mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h */+#undef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H+#undef mld_keccak_f1600_x1_scalar_aarch64_asm+#undef mld_keccak_f1600_x1_v84a_aarch64_asm+#undef mld_keccak_f1600_x2_v84a_aarch64_asm+#undef mld_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm+#undef mld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm+#undef mld_keccakf1600_round_constants+/* mldsa/src/fips202/native/aarch64/x1_scalar.h */+#undef MLD_FIPS202_AARCH64_NEED_X1_SCALAR+#undef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H+#undef MLD_USE_NATIVE_FIPS202_X1+/* mldsa/src/fips202/native/aarch64/x1_v84a.h */+#undef MLD_FIPS202_AARCH64_NEED_X1_V84A+#undef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H+#undef MLD_USE_NATIVE_FIPS202_X1+/* mldsa/src/fips202/native/aarch64/x2_v84a.h */+#undef MLD_FIPS202_AARCH64_NEED_X2_V84A+#undef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H+#undef MLD_USE_NATIVE_FIPS202_X4+/* mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h */+#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID+#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H+#undef MLD_USE_NATIVE_FIPS202_X4+/* mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h */+#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID+#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H+#undef MLD_USE_NATIVE_FIPS202_X4+#endif /* MLD_SYS_AARCH64 */+#if defined(MLD_SYS_X86_64)+/*+ * Undefine macros from native code (FIPS202, x86_64)+ */+/* mldsa/src/fips202/native/x86_64/keccak_f1600_x4_avx2.h */+#undef MLD_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H+#undef MLD_FIPS202_X86_64_NEED_X4_AVX2+#undef MLD_USE_NATIVE_FIPS202_X4+/* mldsa/src/fips202/native/x86_64/src/fips202_native_x86_64.h */+#undef MLD_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H+#undef mld_keccak_f1600_x4_avx2_asm+#undef mld_keccak_rho56+#undef mld_keccak_rho8+#undef mld_keccakf1600_round_constants+#endif /* MLD_SYS_X86_64 */+#if defined(MLD_SYS_ARMV81M_MVE)+/*+ * Undefine macros from native code (FIPS202, Armv8.1-M)+ */+/* mldsa/src/fips202/native/armv81m/mve.h */+#undef MLD_FIPS202_ARMV81M_NEED_X4+#undef MLD_FIPS202_NATIVE_ARMV81M+#undef MLD_FIPS202_NATIVE_ARMV81M_MVE_H+#undef MLD_USE_NATIVE_FIPS202_X4+#undef MLD_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES+#undef MLD_USE_NATIVE_FIPS202_X4_XOR_BYTES+#undef mld_keccak_f1600_x4_native_impl+/* mldsa/src/fips202/native/armv81m/src/fips202_native_armv81m.h */+#undef MLD_FIPS202_NATIVE_ARMV81M_SRC_FIPS202_NATIVE_ARMV81M_H+#undef mld_keccak_f1600_x4_mve_asm+#undef mld_keccak_f1600_x4_state_extract_bytes_asm+#undef mld_keccak_f1600_x4_state_xor_bytes_asm+#undef mld_keccakf1600_round_constants+#endif /* MLD_SYS_ARMV81M_MVE */+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */+#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)+/* mldsa/src/native/api.h */+#undef MLD_FQMUL_BOUND+#undef MLD_INTT_BOUND+#undef MLD_NATIVE_API_H+#undef MLD_NATIVE_FUNC_FALLBACK+#undef MLD_NATIVE_FUNC_SUCCESS+#undef MLD_NTT_BOUND+#undef MLD_REDUCE32_RANGE_MAX+/* mldsa/src/native/meta.h */+#undef MLD_NATIVE_META_H+#if defined(MLD_SYS_AARCH64)+/*+ * Undefine macros from native code (Arith, AArch64)+ */+/* mldsa/src/native/aarch64/meta.h */+#undef MLD_ARITH_BACKEND_AARCH64+#undef MLD_NATIVE_AARCH64_META_H+#undef MLD_USE_NATIVE_INTT+#undef MLD_USE_NATIVE_NTT+#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7+#undef MLD_USE_NATIVE_POLYZ_UNPACK_17+#undef MLD_USE_NATIVE_POLYZ_UNPACK_19+#undef MLD_USE_NATIVE_POLY_CADDQ+#undef MLD_USE_NATIVE_POLY_CHKNORM+#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32+#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88+#undef MLD_USE_NATIVE_POLY_USE_HINT_32+#undef MLD_USE_NATIVE_POLY_USE_HINT_88+#undef MLD_USE_NATIVE_REJ_UNIFORM+#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2+#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4+/* mldsa/src/native/aarch64/src/arith_native_aarch64.h */+#undef MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN+#undef MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN+#undef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H+#undef mld_aarch64_intt_zetas_layer123456+#undef mld_aarch64_intt_zetas_layer78+#undef mld_aarch64_ntt_zetas_layer123456+#undef mld_aarch64_ntt_zetas_layer78+#undef mld_intt_aarch64_asm+#undef mld_ntt_aarch64_asm+#undef mld_poly_caddq_aarch64_asm+#undef mld_poly_chknorm_aarch64_asm+#undef mld_poly_decompose_32_aarch64_asm+#undef mld_poly_decompose_88_aarch64_asm+#undef mld_poly_pointwise_montgomery_aarch64_asm+#undef mld_poly_use_hint_32_aarch64_asm+#undef mld_poly_use_hint_88_aarch64_asm+#undef mld_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm+#undef mld_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm+#undef mld_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm+#undef mld_polyz_unpack_17_aarch64_asm+#undef mld_polyz_unpack_17_indices+#undef mld_polyz_unpack_19_aarch64_asm+#undef mld_polyz_unpack_19_indices+#undef mld_rej_uniform_aarch64_asm+#undef mld_rej_uniform_eta2_aarch64_asm+#undef mld_rej_uniform_eta4_aarch64_asm+#undef mld_rej_uniform_eta_table+#undef mld_rej_uniform_table+#endif /* MLD_SYS_AARCH64 */+#if defined(MLD_SYS_X86_64)+/*+ * Undefine macros from native code (Arith, X86_64)+ */+/* mldsa/src/native/x86_64/meta.h */+#undef MLD_ARITH_BACKEND_X86_64_DEFAULT+#undef MLD_NATIVE_X86_64_META_H+#undef MLD_USE_NATIVE_INTT+#undef MLD_USE_NATIVE_NTT+#undef MLD_USE_NATIVE_NTT_CUSTOM_ORDER+#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5+#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7+#undef MLD_USE_NATIVE_POLYZ_UNPACK_17+#undef MLD_USE_NATIVE_POLYZ_UNPACK_19+#undef MLD_USE_NATIVE_POLY_CADDQ+#undef MLD_USE_NATIVE_POLY_CHKNORM+#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32+#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88+#undef MLD_USE_NATIVE_POLY_USE_HINT_32+#undef MLD_USE_NATIVE_POLY_USE_HINT_88+#undef MLD_USE_NATIVE_REJ_UNIFORM+#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2+#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4+/* mldsa/src/native/x86_64/src/arith_native_x86_64.h */+#undef MLD_AVX2_REJ_UNIFORM_BUFLEN+#undef MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN+#undef MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN+#undef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H+#undef mld_invntt_avx2_asm+#undef mld_ntt_avx2_asm+#undef mld_nttunpack_avx2_asm+#undef mld_pointwise_acc_l4_avx2_asm+#undef mld_pointwise_acc_l5_avx2_asm+#undef mld_pointwise_acc_l7_avx2_asm+#undef mld_pointwise_avx2_asm+#undef mld_poly_caddq_avx2_asm+#undef mld_poly_chknorm_avx2_asm+#undef mld_poly_decompose_32_avx2_asm+#undef mld_poly_decompose_88_avx2_asm+#undef mld_poly_use_hint_32_avx2_asm+#undef mld_poly_use_hint_88_avx2_asm+#undef mld_polyz_unpack_17_avx2_asm+#undef mld_polyz_unpack_19_avx2_asm+#undef mld_rej_uniform_avx2_asm+#undef mld_rej_uniform_eta2_avx2_asm+#undef mld_rej_uniform_eta4_avx2_asm+#undef mld_rej_uniform_table+/* mldsa/src/native/x86_64/src/consts.h */+#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV+#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV+#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQ+#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV+#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS+#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV+#undef MLD_NATIVE_X86_64_SRC_CONSTS_H+#undef mld_qdata+#endif /* MLD_SYS_X86_64 */+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */+#endif /* !MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */
@@ -0,0 +1,855 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS140_3_IG]+ * Implementation Guidance for FIPS 140-3 and the Cryptographic Module+ * Validation Program+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ *+ * - [FIPS204_UPDATES]+ * FIPS 204 Potential Updates (Errata)+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/files/pubs/fips/204/final/docs/fips-204-potential-updates.xlsx+ */++#ifndef MLD_CONFIG_H+#define MLD_CONFIG_H++/**+ * MLD_CONFIG_PARAMETER_SET+ *+ * Specifies the parameter set for ML-DSA+ * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44+ * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65+ * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87+ *+ * If you want to support multiple parameter sets, build the+ * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD.+ * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while+ * minimizing code duplication.+ *+ * This can also be set using CFLAGS.+ */+#ifndef MLD_CONFIG_PARAMETER_SET+#define MLD_CONFIG_PARAMETER_SET \+ 44 /* Change this for different security strengths */+#endif++/**+ * MLD_CONFIG_FILE+ *+ * If defined, this is a header that will be included instead+ * of the default configuration file mldsa/mldsa_native_config.h.+ *+ * When you need to build mldsa-native in multiple configurations,+ * using varying MLD_CONFIG_FILE can be more convenient+ * than configuring everything through CFLAGS.+ *+ * To use, MLD_CONFIG_FILE _must_ be defined prior+ * to the inclusion of any mldsa-native headers. For example,+ * it can be set by passing `-DMLD_CONFIG_FILE="..."`+ * on the command line.+ */+/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */++/**+ * MLD_CONFIG_NAMESPACE_PREFIX+ *+ * The prefix to use to namespace global symbols from mldsa/.+ *+ * In a multi-level build, level-dependent symbols will+ * additionally be prefixed with the parameter set (44/65/87).+ *+ * This can also be set using CFLAGS.+ */+#if !defined(MLD_CONFIG_NAMESPACE_PREFIX)+#define MLD_CONFIG_NAMESPACE_PREFIX MLD_DEFAULT_NAMESPACE_PREFIX+#endif++/**+ * MLD_CONFIG_MULTILEVEL_BUILD+ *+ * Set this if the build is part of a multi-level build supporting+ * multiple parameter sets.+ *+ * If you need only a single parameter set, keep this unset.+ *+ * To build mldsa-native with support for all parameter sets,+ * build it three times -- once per parameter set -- and set the+ * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of+ * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others.+ * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them.+ *+ * See examples/multilevel_build for an example.+ *+ * This can also be set using CFLAGS.+ */+/* #define MLD_CONFIG_MULTILEVEL_BUILD */++/**+ * MLD_CONFIG_EXTERNAL_API_QUALIFIER+ *+ * If set, this option provides an additional function+ * qualifier to be added to declarations of mldsa-native's+ * public API.+ *+ * The primary use case for this option are single-CU builds+ * where the public API exposed by mldsa-native is wrapped by+ * another API in the consuming application. In this case,+ * even mldsa-native's public API can be marked `static`.+ */+/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */++/**+ * MLD_CONFIG_NO_KEYPAIR_API+ *+ * By default, mldsa-native includes support for generating key+ * pairs. If you don't need this, set MLD_CONFIG_NO_KEYPAIR_API+ * to exclude keypair, keypair_internal,+ * pk_from_sk, and all internal APIs only needed by+ * those functions.+ */+/* #define MLD_CONFIG_NO_KEYPAIR_API */++/**+ * MLD_CONFIG_NO_SIGN_API+ *+ * By default, mldsa-native includes support for creating+ * signatures. If you don't need this, set MLD_CONFIG_NO_SIGN_API+ * to exclude signature,+ * signature_extmu, signature_internal,+ * signature_pre_hash_internal,+ * signature_pre_hash_shake256, and all internal APIs+ * only needed by those functions.+ */+/* #define MLD_CONFIG_NO_SIGN_API */++/**+ * MLD_CONFIG_NO_VERIFY_API+ *+ * By default, mldsa-native includes support for verifying+ * signatures. If you don't need this, set+ * MLD_CONFIG_NO_VERIFY_API to exclude verify,+ * verify_extmu, verify_internal,+ * verify_pre_hash_internal,+ * verify_pre_hash_shake256, and all internal APIs+ * only needed by those functions.+ */+/* #define MLD_CONFIG_NO_VERIFY_API */++/**+ * MLD_CONFIG_CORE_API_ONLY+ *+ * Set this to remove all public APIs except+ * keypair_internal, signature_internal,+ * and verify_internal.+ */+/* #define MLD_CONFIG_CORE_API_ONLY */++/**+ * MLD_CONFIG_NO_RANDOMIZED_API+ *+ * If this option is set, mldsa-native will be built without the+ * randomized API functions (keypair,+ * signature, and signature_extmu).+ * This allows users to build mldsa-native without providing a+ * randombytes() implementation if they only need the+ * internal deterministic API+ * (keypair_internal, signature_internal).+ *+ * @note This option is incompatible with MLD_CONFIG_KEYGEN_PCT+ * as the current PCT implementation requires+ * signature().+ */+/* #define MLD_CONFIG_NO_RANDOMIZED_API */++/**+ * MLD_CONFIG_CONSTANTS_ONLY+ *+ * If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.)+ * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY.+ *+ * This only affects the public header mldsa_native.h, not+ * the implementation.+ */+/* #define MLD_CONFIG_CONSTANTS_ONLY */+/******************************************************************************+ *+ * Build-only configuration options+ *+ * The remaining configurations are build-options only.+ * They do not affect the API described in mldsa_native.h.+ *+ *****************************************************************************/+#if defined(MLD_BUILD_INTERNAL)++/**+ * MLD_CONFIG_MULTILEVEL_WITH_SHARED+ *+ * This is for multi-level builds of mldsa-native only. If you+ * need only a single parameter set, keep this unset.+ *+ * If this is set, all MLD_CONFIG_PARAMETER_SET-independent+ * code will be included in the build, including code needed only+ * for other parameter sets.+ *+ * Example: mld_polyw1_pack_88 is only needed for+ * MLD_CONFIG_PARAMETER_SET == 44. Yet, if this option is set for a+ * build with MLD_CONFIG_PARAMETER_SET == 65/87, it would be included.+ *+ * To build mldsa-native with support for all parameter sets,+ * build it three times -- once per parameter set -- and set the+ * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of+ * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others.+ * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them.+ *+ * See examples/multilevel_build for an example.+ *+ * This can also be set using CFLAGS.+ */+/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */++/**+ * MLD_CONFIG_MULTILEVEL_NO_SHARED+ *+ * This is for multi-level builds of mldsa-native only. If you+ * need only a single parameter set, keep this unset.+ *+ * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code+ * will be included in the build.+ *+ * To build mldsa-native with support for all parameter sets,+ * build it three times -- once per parameter set -- and set the+ * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of+ * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others.+ * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them.+ *+ * See examples/multilevel_build for an example.+ *+ * This can also be set using CFLAGS.+ */+/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */++/**+ * MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+ *+ * This is only relevant for single compilation unit (SCU)+ * builds of mldsa-native. In this case, it determines whether+ * directives defined in parameter-set-independent headers should+ * be #undef'ined or not at the end of the SCU file. This is+ * needed in multilevel builds.+ *+ * See examples/multilevel_build_native for an example.+ *+ * This can also be set using CFLAGS.+ */+/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */++/**+ * MLD_CONFIG_USE_NATIVE_BACKEND_ARITH+ *+ * Determines whether a native arithmetic backend should be used.+ *+ * The arithmetic backend covers performance-critical functions+ * such as the number-theoretic transform (NTT).+ *+ * If this option is unset, the C backend will be used.+ *+ * If this option is set, the arithmetic backend to be used is+ * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is+ * unset, the default backend for your target architecture+ * will be used. If set, it must be the name of a backend metadata+ * file.+ *+ * This can also be set using CFLAGS.+ */+#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)+/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */+#endif++/**+ * MLD_CONFIG_ARITH_BACKEND_FILE+ *+ * The arithmetic backend to use.+ *+ * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option+ * is ignored.+ *+ * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must+ * either be undefined or the filename of an arithmetic backend.+ * If unset, the default backend will be used.+ *+ * This can be set using CFLAGS.+ */+#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \+ !defined(MLD_CONFIG_ARITH_BACKEND_FILE)+#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h"+#endif++/**+ * MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202+ *+ * Determines whether a native FIPS202 backend should be used.+ *+ * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is+ * the performance bottleneck of SHA3 and SHAKE.+ *+ * If this option is unset, the C backend will be used.+ *+ * If this option is set, the FIPS202 backend to be used is+ * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is+ * unset, the default backend for your target architecture+ * will be used. If set, it must be the name of a backend metadata+ * file.+ *+ * This can also be set using CFLAGS.+ */+#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)+/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */+#endif++/**+ * MLD_CONFIG_FIPS202_BACKEND_FILE+ *+ * The FIPS-202 backend to use.+ *+ * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option+ * must either be undefined or the filename of a FIPS202 backend.+ * If unset, the default backend will be used.+ *+ * This can be set using CFLAGS.+ */+#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \+ !defined(MLD_CONFIG_FIPS202_BACKEND_FILE)+#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h"+#endif++/**+ * MLD_CONFIG_FIPS202_CUSTOM_HEADER+ *+ * Custom header to use for FIPS-202+ *+ * This should only be set if you intend to use a custom+ * FIPS-202 implementation, different from the one shipped+ * with mldsa-native.+ *+ * If set, it must be the name of a file serving as the+ * replacement for mldsa/src/fips202/fips202.h, and exposing+ * the same API (see FIPS202.md).+ */+/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */++/**+ * MLD_CONFIG_FIPS202X4_CUSTOM_HEADER+ *+ * Custom header to use for FIPS-202-X4+ *+ * This should only be set if you intend to use a custom+ * FIPS-202 implementation, different from the one shipped+ * with mldsa-native.+ *+ * If set, it must be the name of a file serving as the+ * replacement for mldsa/src/fips202/fips202x4.h, and exposing+ * the same API (see FIPS202.md).+ */+/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */++/**+ * MLD_CONFIG_CUSTOM_ZEROIZE+ *+ * In compliance with @[FIPS204, Section 3.6.3], mldsa-native zeroizes+ * intermediate buffers before returning from function calls. By default,+ * those buffers are allocated from the stack; if MLD_CONFIG_CUSTOM_ALLOC_FREE+ * is set, they are (mostly -- few exceptions remain at present) allocated from+ * the configured custom allocator.+ *+ * mldsa-native also zeroizes caller-owned output buffers as needed to uphold+ * the API convention that outputs be either unmodified or zeroized upon+ * failure.+ *+ * Set this option and define `mld_zeroize` if you want to use a custom+ * method to zeroize intermediate and output buffers.+ *+ * The default implementation uses SecureZeroMemory on Windows and a+ * memset + compiler barrier otherwise. If neither of those is available on+ * the target platform, compilation will fail, and you will need to use+ * MLD_CONFIG_CUSTOM_ZEROIZE to provide a custom implementation of+ * `mld_zeroize()`.+ *+ * @warning+ * The zeroization conducted by mldsa-native reduces the likelihood of data+ * leaking on the stack or custom allocators, but it does not eliminate it.+ * For example, the C standard makes no guarantee about where a compiler+ * allocates local structures and whether/where it makes copies of them.+ * Also, in addition to entire structures, there may also be potentially+ * exploitable leakage of individual values on the stack. If you need+ * bullet-proof zeroization of the stack, you need to consider additional+ * measures instead of what this feature provides. In this case, you can+ * set mld_zeroize to a no-op. Note that in this case you are also responsible+ * for zeroizing output buffers upon failure.+ */+/* #define MLD_CONFIG_CUSTOM_ZEROIZE+ #if !defined(__ASSEMBLER__)+ #include <stdint.h>+ #include "src/src.h"+ static MLD_INLINE void mld_zeroize(void *ptr, size_t len)+ {+ ... your implementation ...+ }+ #endif+*/++/**+ * MLD_CONFIG_CUSTOM_RANDOMBYTES+ *+ * mldsa-native does not provide a secure randombytes+ * implementation. Such an implementation has to be provided by+ * the consumer.+ *+ * If this option is not set, mldsa-native expects a function+ * int randombytes(uint8_t *out, size_t outlen).+ *+ * Set this option and define `mld_randombytes` if you want to+ * use a custom method to sample randombytes with a different name+ * or signature.+ */+/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES+ #if !defined(__ASSEMBLER__)+ #include <stdint.h>+ #include "src/src.h"+ static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len)+ {+ ... your implementation ...+ return 0;+ }+ #endif+*/++/**+ * MLD_CONFIG_CUSTOM_CAPABILITY_FUNC+ *+ * mldsa-native backends may rely on specific hardware features.+ * Those backends will only be included in an mldsa-native build+ * if support for the respective features is enabled at+ * compile-time. However, when building for a heterogeneous set+ * of CPUs to run the resulting binary/library on, feature+ * detection at _runtime_ is needed to decide whether a backend+ * can be used or not.+ *+ * Set this option and define `mld_sys_check_capability` if you+ * want to use a custom method to dispatch between implementations.+ *+ * Return value 1 indicates that a capability is supported.+ * Return value 0 indicates that a capability is not supported.+ *+ * If this option is not set, mldsa-native uses compile-time+ * feature detection only to decide which backend to use.+ *+ * If you compile mldsa-native on a system with different+ * capabilities than the system that the resulting binary/library+ * will be run on, you must use this option.+ */+/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC+ static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap)+ {+ ... your implementation ...+ }+*/++/**+ * MLD_CONFIG_CUSTOM_ALLOC_FREE+ *+ * Set this option and define `MLD_CUSTOM_ALLOC` and+ * `MLD_CUSTOM_FREE` if you want to use custom allocation for+ * large local structures or buffers.+ *+ * By default, all buffers/structures are allocated on the stack.+ * If this option is set, most of them will be allocated via+ * MLD_CUSTOM_ALLOC.+ *+ * Parameters to MLD_CUSTOM_ALLOC:+ * - T* v: Target pointer to declare.+ * - T: Type of structure to be allocated+ * - N: Number of elements to be allocated.+ *+ * Parameters to MLD_CUSTOM_FREE:+ * - T* v: Target pointer to free. May be NULL.+ * - T: Type of structure to be freed.+ * - N: Number of elements to be freed.+ *+ * @warning This option is experimental. Its scope, configuration and+ * function/macro signatures may change at any time. We expect a+ * stable API in a future version.+ *+ * @note Even if this option is set, some allocations further down+ * the call stack will still be made from the stack. Those will+ * likely be added to the scope of this option in the future.+ *+ * @note MLD_CUSTOM_ALLOC need not guarantee a successful+ * allocation nor include error handling. Upon failure, the+ * target pointer should simply be set to NULL. The calling+ * code will handle this case and invoke MLD_CUSTOM_FREE.+ */+/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE+ #if !defined(__ASSEMBLER__)+ #include <stdlib.h>+ #define MLD_CUSTOM_ALLOC(v, T, N) \+ T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \+ MLD_ALIGN_UP(sizeof(T) * (N)))+ #define MLD_CUSTOM_FREE(v, T, N) free(v)+ #endif+*/++/**+ * MLD_CONFIG_CUSTOM_MEMCPY+ *+ * Set this option and define `mld_memcpy` if you want to+ * use a custom method to copy memory instead of the standard+ * library memcpy function.+ *+ * The custom implementation must have the same signature and+ * behavior as the standard memcpy function:+ * void *mld_memcpy(void *dest, const void *src, size_t n)+ */+/* #define MLD_CONFIG_CUSTOM_MEMCPY+ #if !defined(__ASSEMBLER__)+ #include <stdint.h>+ #include "src/src.h"+ static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n)+ {+ ... your implementation ...+ }+ #endif+*/++/**+ * MLD_CONFIG_CUSTOM_MEMSET+ *+ * Set this option and define `mld_memset` if you want to+ * use a custom method to set memory instead of the standard+ * library memset function.+ *+ * The custom implementation must have the same signature and+ * behavior as the standard memset function:+ * void *mld_memset(void *s, int c, size_t n)+ */+/* #define MLD_CONFIG_CUSTOM_MEMSET+ #if !defined(__ASSEMBLER__)+ #include <stdint.h>+ #include "src/src.h"+ static MLD_INLINE void *mld_memset(void *s, int c, size_t n)+ {+ ... your implementation ...+ }+ #endif+*/++/**+ * MLD_CONFIG_INTERNAL_API_QUALIFIER+ *+ * If set, this option provides an additional qualifier+ * to be added to declarations of internal API functions and data.+ *+ * The primary use case for this option are single-CU builds,+ * in which case this option can be set to `static`.+ */+/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */++/**+ * MLD_CONFIG_CT_TESTING_ENABLED+ *+ * If set, mldsa-native annotates data as secret / public using+ * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and+ * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret-+ * dependent control flow of variable time execution (depending+ * on the exact version of valgrind installed).+ */+/* #define MLD_CONFIG_CT_TESTING_ENABLED */++/**+ * MLD_CONFIG_NO_ASM+ *+ * If this option is set, mldsa-native will be built without+ * use of native code or inline assembly.+ *+ * By default, inline assembly is used to implement value barriers.+ * Without inline assembly, mldsa-native will use a global volatile+ * 'opt blocker' instead; see ct.h.+ *+ * Inline assembly is also used to implement a secure zeroization+ * function on non-Windows platforms. If this option is set and+ * the target platform is not Windows, you MUST set+ * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization+ * function.+ *+ * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and+ * MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no+ * native backends will be used.+ */+/* #define MLD_CONFIG_NO_ASM */++/**+ * MLD_CONFIG_NO_ASM_VALUE_BARRIER+ *+ * If this option is set, mldsa-native will be built without+ * use of native code or inline assembly for value barriers.+ *+ * By default, inline assembly (if available) is used to implement+ * value barriers.+ * Without inline assembly, mldsa-native will use a global volatile+ * 'opt blocker' instead; see ct.h.+ */+/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */++/**+ * MLD_CONFIG_KEYGEN_PCT+ *+ * Compliance with @[FIPS140_3_IG, p.87] requires a+ * Pairwise Consistency Test (PCT) to be carried out on a freshly+ * generated keypair before it can be exported.+ *+ * Set this option if such a check should be implemented.+ * In this case, keypair_internal and+ * keypair will return MLD_ERR_PCT_FAIL if the+ * PCT failed.+ *+ * @note This feature will drastically lower the performance of+ * key generation.+ *+ * @note This option is incompatible with MLD_CONFIG_NO_SIGN_API+ * and MLD_CONFIG_NO_VERIFY_API as the current PCT implementation+ * requires signature() and verify().+ */+/* #define MLD_CONFIG_KEYGEN_PCT */++/**+ * MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST+ *+ * If this option is set, the user must provide a runtime+ * function `static inline int mld_break_pct() { ... }` to+ * indicate whether the PCT should be made fail.+ *+ * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set.+ */+/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST+ #if !defined(__ASSEMBLER__)+ #include "src/src.h"+ static MLD_INLINE int mld_break_pct(void)+ {+ ... return 0/1 depending on whether PCT should be broken ...+ }+ #endif+*/++/**+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ *+ * Upper bound on the number of rejection-sampling iterations+ * performed by ML-DSA signing (@[FIPS204, Algorithm 7]).+ *+ * If a valid signature is not produced within this many+ * attempts, signing returns MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED.+ * This is useful in timing-sensitive environments that+ * require a deterministic worst-case bound on signing time.+ *+ * For FIPS 204 compliance, this value MUST be at least 821,+ * cf. @[FIPS204, Appendix C] and @[FIPS204_UPDATES], which is+ * chosen so that the signing failure rate is < 2^{-256}.+ *+ * Default: Largest possible value before internal counters+ * would overflow. This is larger than the FIPS204 bound.+ *+ * In particular, in the default configuration, the signing+ * failure rate is < 2^{-256}.+ */+/* #define MLD_CONFIG_MAX_SIGNING_ATTEMPTS 821 */++/**+ * MLD_CONFIG_SERIAL_FIPS202_ONLY+ *+ * Set this to use a FIPS202 implementation with global state+ * that supports only one active Keccak computation at a time+ * (e.g. some hardware accelerators).+ *+ * If this option is set, ML-DSA will use FIPS202 operations+ * serially, ensuring that only one SHAKE context is active+ * at any given time.+ *+ * This allows offloading Keccak computations to a hardware+ * accelerator that holds only a single Keccak state locally,+ * rather than requiring support for multiple concurrent+ * Keccak states.+ *+ * @note Depending on the target CPU, this may reduce+ * performance when using software FIPS202 implementations.+ * Only enable this when you have to.+ */+/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */++/**+ * MLD_CONFIG_CONTEXT_PARAMETER+ *+ * Set this to add a caller-supplied context parameter to the public API+ * functions, which is then forwarded unchanged to the custom callbacks+ * (allocation, and signing hooks below).+ *+ * When this option is set, every public API function gains a trailing+ * parameter+ *+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+ *+ * as its last argument; its type is configured via+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE (see below). mldsa-native treats this+ * value as opaque: it never dereferences it and only passes it on to the+ * configurable hook macros. It is meant to carry per-caller state -- e.g. a+ * pointer to a memory pool for the allocation hooks, or the resume state for+ * the signing hooks -- into those hooks.+ *+ * When this option is unset (the default), no extra parameter is added and+ * the hook macros never receive a context argument.+ *+ * The hooks that receive the context are the allocation hooks (see+ * MLD_CONFIG_CUSTOM_ALLOC_FREE) and the signing hooks (see+ * MLD_CONFIG_SIGN_HOOK_RESUME / _ATTEMPT / _FINISH); each is documented with+ * its own option below.+ */+/* #define MLD_CONFIG_CONTEXT_PARAMETER */++/**+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE+ *+ * Set this to define the type of the context parameter added by+ * MLD_CONFIG_CONTEXT_PARAMETER. It can be any C type usable as a function+ * parameter, e.g. `void *` or a pointer to a caller-defined struct such as+ * `struct my_ctx *`.+ *+ * This option must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is+ * defined; defining one without the other is a compile-time error.+ */+/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */++/**+ * Signing hooks: MLD_CONFIG_SIGN_HOOK_RESUME / _ATTEMPT / _FINISH+ *+ * Three optional, independent hooks into the ML-DSA signing rejection-sampling+ * loop. Each is enabled by defining the matching option, in which case the+ * integration must provide the corresponding function. If a hook needs+ * per-operation state, enable MLD_CONFIG_CONTEXT_PARAMETER; the context is then+ * appended as the last argument.+ *+ * @warning This feature is experimental. Its scope, configuration and+ * function signatures may change at any time, including after v2.+ *+ * Enabling any of the hooks requires MLD_CONFIG_NO_RANDOMIZED_API (restricting+ * the public API to deterministic operations). This is because the restartable+ * signing as enabled by the signing hooks only produces the uninterrupted+ * signature when the randomness is fixed across calls. A logging-only use+ * (attempt always returns 0; resume/finish merely observe) would be safe with+ * the randomized API too, but for now the requirement is imposed uniformly on+ * all three hooks.+ *+ * Note: Randomized signing is a shim wrapper around deterministic signing, and+ * all helper functions you need to build it are exposed publicly. Thus, if you+ * need a restartable, randomized signing operation, you can build your own by+ * replicating the logic and adding the RNG seed to the restart context. In this+ * case, please also consider letting the mldsa-native maintainers know of your+ * need for randomized, restartable signing, so the feature can be appropriately+ * prioritized.+ *+ * - MLD_CONFIG_SIGN_HOOK_ATTEMPT: int mld_sign_hook_attempt(attempt[, ctxt])+ * Called before each attempt. Returns 0 to proceed, or non-zero to pause:+ * signing then returns MLD_ERR_SIGNING_PAUSED with `attempt` as the resume+ * point (needs MLD_CONFIG_SIGN_HOOK_RESUME to resume; otherwise just aborts).+ * Always returning 0 makes it a logging/benchmarking hook.+ *+ * - MLD_CONFIG_SIGN_HOOK_RESUME: uint16_t mld_sign_hook_resume([ctxt])+ * Returns the attempt to resume from (0 for a fresh operation), i.e. the one+ * recorded when a previous call paused.+ *+ * - MLD_CONFIG_SIGN_HOOK_FINISH: void mld_sign_hook_finish(attempt[, ctxt])+ * Called on success with the succeeding attempt. Observe-only.+ *+ * When an option is unset, the hook is a no-op (resume to 0, attempt proceeds),+ * i.e. ordinary one-shot signing.+ *+ * Independent of MLD_CONFIG_MAX_SIGNING_ATTEMPTS, which is a static upper bound+ * on the number of signing attempts.+ *+ * See test/src/test_sign_hook.c for a worked example using all three.+ */+/* #define MLD_CONFIG_SIGN_HOOK_RESUME+ #define MLD_CONFIG_SIGN_HOOK_ATTEMPT+ #define MLD_CONFIG_SIGN_HOOK_FINISH+ #if !defined(__ASSEMBLER__)+ #include <stdint.h>+ #include "src/sys.h"+ static MLD_INLINE uint16_t mld_sign_hook_resume(void)+ {+ ... return the attempt to resume from ...+ }+ static MLD_INLINE int mld_sign_hook_attempt(uint16_t attempt)+ {+ ... return non-zero to pause here; for resume, store attempt ...+ return 0;+ }+ static MLD_INLINE void mld_sign_hook_finish(uint16_t attempt)+ {+ ... mark the operation complete (attempt = successful attempt) ...+ }+ #endif+*/++/**+ * MLD_CONFIG_REDUCE_RAM+ *+ * Set this to reduce RAM usage. This trades memory for performance.+ *+ * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants defined in+ * mldsa_native.h.+ *+ * This option is useful for embedded systems with tight RAM constraints but+ * relaxed performance requirements.+ *+ */+/* #define MLD_CONFIG_REDUCE_RAM */++/************************* Config internals ********************************/++#endif /* MLD_BUILD_INTERNAL */++/* Default namespace+ *+ * Don't change this. If you need a different namespace, re-define+ * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following.+ *+ * The default MLDSA namespace is+ *+ * PQCP_MLDSA_NATIVE_MLDSA<LEVEL>_+ *+ * e.g., PQCP_MLDSA_NATIVE_MLDSA44_+ */++#if defined(MLD_CONFIG_MULTILEVEL_BUILD)+/* In a multi-level build the parameter set is appended by the namespacing+ * machinery, so the default prefix must not embed it. */+#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA+#elif MLD_CONFIG_PARAMETER_SET == 44+#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44+#elif MLD_CONFIG_PARAMETER_SET == 65+#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65+#elif MLD_CONFIG_PARAMETER_SET == 87+#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87+#endif++#endif /* !MLD_CONFIG_H */
@@ -0,0 +1,233 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_CBMC_H+#define MLD_CBMC_H++/***************************************************+ * Basic replacements for __CPROVER_XXX contracts+ ***************************************************/+/*+ * The `__contract__` / `__loop__` annotation macros use a+ * leading-double-underscore spelling in line with other CBMC macros.+ * clang-tidy flags these as reserved identifiers; we suppress the diagnostic+ * at each definition site (NOLINT) rather than disabling the check globally,+ * so it stays active for the rest of the tree.+ */+#ifndef CBMC++/* clang-format off */+#define __contract__(x) /* NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */+#define __loop__(x) /* NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */+/* clang-format on */+#define cassert(x)++#else /* !CBMC */+++/* clang-format off */+#define __contract__(x) x /* NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */+#define __loop__(x) x /* NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */+/* clang-format on */++/* Conditionally expand to __VA_ARGS__ depending on MLD_CONFIG_REDUCE_RAM. */+#if defined(MLD_CONFIG_REDUCE_RAM)+#define MLD_IF_REDUCE_RAM(...) __VA_ARGS__+#define MLD_IF_NOT_REDUCE_RAM(...)+#else+#define MLD_IF_REDUCE_RAM(...)+#define MLD_IF_NOT_REDUCE_RAM(...) __VA_ARGS__+#endif++/* https://diffblue.github.io/cbmc/contracts-assigns.html */+#define assigns(...) __CPROVER_assigns(__VA_ARGS__)++/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */+#define requires(...) __CPROVER_requires(__VA_ARGS__)+#define ensures(...) __CPROVER_ensures(__VA_ARGS__)+/* https://diffblue.github.io/cbmc/contracts-loops.html */+#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__)+#define decreases(...) __CPROVER_decreases(__VA_ARGS__)+/* cassert to avoid confusion with in-built assert */+#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed")+#define assume(...) __CPROVER_assume(__VA_ARGS__)++/***************************************************+ * Macros for "expression" forms that may appear+ * _inside_ top-level contracts.+ ***************************************************/++/*+ * function return value - useful inside ensures+ * https://diffblue.github.io/cbmc/contracts-functions.html+ */+#define return_value (__CPROVER_return_value)++/*+ * assigns l-value targets+ * https://diffblue.github.io/cbmc/contracts-assigns.html+ */+#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__)+#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__)+#define same_object(...) __CPROVER_same_object(__VA_ARGS__)++/*+ * Pointer-related predicates+ * https://diffblue.github.io/cbmc/contracts-memory-predicates.html+ */+#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__)+#define readable(...) __CPROVER_r_ok(__VA_ARGS__)+#define writeable(...) __CPROVER_w_ok(__VA_ARGS__)++/* Maximum supported buffer size+ *+ * Larger buffers may be supported, but due to internal modeling constraints+ * in CBMC, the proofs of memory- and type-safety won't be able to run.+ *+ * If you find yourself in need for a buffer size larger than this,+ * please contact the maintainers, so we can prioritize work to relax+ * this somewhat artificial bound.+ */+#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12)+++/*+ * History variables+ * https://diffblue.github.io/cbmc/contracts-history-variables.html+ */+#define old(...) __CPROVER_old(__VA_ARGS__)+#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__)++/*+ * Quantifiers+ * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub+ * https://diffblue.github.io/cbmc/contracts-quantifiers.html+ *+ * The quantified variable is declared as uint32_t, so these macros+ * quantify only over indices in [0, UINT32_MAX). Bounds larger than+ * UINT32_MAX (4 GiB) are NOT supported: the explicit (uint32_t) casts+ * on the bounds will trigger CBMC's conversion check if a wider bound+ * (e.g. a size_t > UINT32_MAX) is passed.+ *+ * Quantifying over size_t (64-bit) was found to blow up SMT proof+ * times, so we deliberately keep the index width at 32 bits. Callers+ * dealing with size_t-typed buffers must add an explicit+ * requires(len <= UINT32_MAX)+ * precondition.+ */++/*+ * Prevent clang-format from corrupting CBMC's special ==> operator+ */+/* clang-format off */+#define forall(qvar, qvar_lb, qvar_ub, predicate) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> (predicate) \+ }++#define exists(qvar, qvar_lb, qvar_ub, predicate) \+ __CPROVER_exists \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) && (predicate) \+ }+/* clang-format on */++/***************************************************+ * Convenience macros for common contract patterns+ ***************************************************/+/*+ * Prevent clang-format from corrupting CBMC's special ==> operator+ */+/* clang-format off */+#define CBMC_CONCAT_(left, right) left##right+#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right)++#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \+ value_lb, value_ub) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> \+ (((int)(value_lb) <= ((array_var)[(qvar)])) && \+ (((array_var)[(qvar)]) < (int)(value_ub))) \+ }++#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \+ array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \+ (qvar_ub), (array_var), (value_lb), (value_ub))++#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> \+ ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \+ }++#define array_unchanged(array_var, N) \+ array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var))++#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> \+ ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \+ }++#define array_unchanged_u64(array_var, N) \+ array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var))++#define array_unchanged_u8_core(qvar, qvar_lb, qvar_ub, array_var) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> \+ ((array_var)[(qvar)]) == (old(* (uint8_t (*)[(qvar_ub)])(array_var)))[(qvar)] \+ }++#define array_unchanged_u8(array_var, N) \+ array_unchanged_u8_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var))++#define array_zeroized_u8_core(qvar, qvar_lb, qvar_ub, array_var) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> \+ ((array_var)[(qvar)]) == 0 \+ }++#define array_zeroized_u8(array_var, N) \+ array_zeroized_u8_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var))+/* clang-format on */++/*+ * Output-buffer discipline on failure, as documented in API-CONVENTIONS.md:+ * when a function fails, each caller-owned output buffer is left either+ * fully unchanged or fully zeroized -- never holding partially computed or+ * stale data that could be mistaken for a valid result.+ *+ * Note the disjunction is over the buffer as a whole: it is not enough for+ * each byte to be individually either unchanged or zero.+ */+#define array_unchanged_or_zeroized_u8(array_var, N) \+ (array_unchanged_u8((array_var), (N)) || array_zeroized_u8((array_var), (N)))++/* Wrapper around array_bound operating on absolute values.+ *+ * The absolute value bound `k` is exclusive.+ *+ * Note that since the lower bound in array_bound is inclusive, we have to+ * raise it by 1 here.+ */+#define array_abs_bound(arr, lb, ub, k) \+ array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k))++#endif /* CBMC */++#endif /* !MLD_CBMC_H */
@@ -0,0 +1,301 @@+/*+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_COMMON_H+#define MLD_COMMON_H++#ifndef __ASSEMBLER__+#include <stdint.h>+#endif+++#define MLD_BUILD_INTERNAL++#if defined(MLD_CONFIG_FILE)+#include MLD_CONFIG_FILE+#else+#include "mldsa_native_config.h"+#endif++#include "params.h"+#include "sys.h"++/* Internal and public API have external linkage by default, but+ * this can be overwritten by the user, e.g. for single-CU builds. */+#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER)+#define MLD_INTERNAL_API+#define MLD_INTERNAL_DATA_DECLARATION extern+#define MLD_INTERNAL_DATA_DEFINITION+#else+#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER+#define MLD_INTERNAL_DATA_DECLARATION MLD_CONFIG_INTERNAL_API_QUALIFIER+#define MLD_INTERNAL_DATA_DEFINITION MLD_CONFIG_INTERNAL_API_QUALIFIER+#endif++#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER)+#define MLD_EXTERNAL_API+#else+#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER+#endif++#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \+ defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED)+#define MLD_MULTILEVEL_BUILD+#endif++#define MLD_CONCAT_(x1, x2) x1##x2+#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2)++#if defined(MLD_MULTILEVEL_BUILD)+#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET)+#else+#define MLD_ADD_PARAM_SET(s) s+#endif++#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _)+#define MLD_NAMESPACE_PREFIX_KL \+ MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _)++/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX.+ *+ * If multiple parameter sets are used, functions depending on the parameter+ * set are additionally prefixed with 44/65/87. See mldsa_native_config.h.+ *+ * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then+ * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/+ * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair.+ */+#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s)+#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s)++/* On Apple platforms, we need to emit leading underscore+ * in front of assembly symbols. We thus introduce a separate+ * namespace wrapper for ASM symbols. */+#if !defined(__APPLE__)+#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym)+#else+#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym))+#endif++/*+ * On X86_64 if control-flow protections (CET) are enabled (through+ * -fcf-protection=), we add an endbr64 instruction at every global function+ * label. See sys.h for more details+ */+#if defined(MLD_SYS_X86_64)+#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR+#elif defined(MLD_SYS_ARMV81M_MVE)+/* clang-format off */+#define MLD_ASM_FN_SYMBOL(sym) \+ .type MLD_ASM_NAMESPACE(sym), %function; \+ MLD_ASM_NAMESPACE(sym) :+/* clang-format on */+#else /* !MLD_SYS_X86_64 && MLD_SYS_ARMV81M_MVE */+#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) :+#endif /* !MLD_SYS_X86_64 && !MLD_SYS_ARMV81M_MVE */++/*+ * Output the size of an assembly function.+ */+#if defined(__ELF__)+#define MLD_ASM_FN_SIZE(sym) \+ .size MLD_ASM_NAMESPACE(sym), .- MLD_ASM_NAMESPACE(sym)+#else+#define MLD_ASM_FN_SIZE(sym)+#endif++/* We aim to simplify the user's life by supporting builds where+ * all source files are included, even those that are not needed.+ * Those files are appropriately guarded and will be empty when unneeded.+ * The following is to avoid compilers complaining about this. */+#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s);++/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */+#if defined(MLD_CONFIG_NO_ASM)+#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH+#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202+#endif++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \+ !defined(MLD_CONFIG_ARITH_BACKEND_FILE)+#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not.+#endif++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \+ !defined(MLD_CONFIG_FIPS202_BACKEND_FILE)+#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not.+#endif++#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT)+#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires signature()+#endif++#if defined(MLD_CONFIG_NO_SIGN_API) && defined(MLD_CONFIG_KEYGEN_PCT)+#error Bad configuration: MLD_CONFIG_NO_SIGN_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires signature()+#endif++#if defined(MLD_CONFIG_NO_VERIFY_API) && defined(MLD_CONFIG_KEYGEN_PCT)+#error Bad configuration: MLD_CONFIG_NO_VERIFY_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires verify()+#endif++#if defined(MLD_CONFIG_CORE_API_ONLY) && defined(MLD_CONFIG_KEYGEN_PCT)+#error Bad configuration: MLD_CONFIG_CORE_API_ONLY is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires signature() and verify()+#endif++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)+#include MLD_CONFIG_ARITH_BACKEND_FILE+/* Include to enforce consistency of API and implementation,+ * and conduct sanity checks on the backend.+ *+ * Keep this _after_ the inclusion of the backend; otherwise,+ * the sanity checks won't have an effect. */+#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__)+#include "native/api.h"+#endif+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */++#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)+#include MLD_CONFIG_FIPS202_BACKEND_FILE+/* Include to enforce consistency of API and implementation,+ * and conduct sanity checks on the backend.+ *+ * Keep this _after_ the inclusion of the backend; otherwise,+ * the sanity checks won't have an effect. */+#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__)+#include "fips202/native/api.h"+#endif+#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */++#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER)+#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h"+#else+#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER+#endif++#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER)+#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h"+#else+#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER+#endif++/* Standard library function replacements */+#if !defined(__ASSEMBLER__)+#if !defined(MLD_CONFIG_CUSTOM_MEMCPY)+#include <string.h>+#define mld_memcpy memcpy+#endif++#if !defined(MLD_CONFIG_CUSTOM_MEMSET)+#include <string.h>+#define mld_memset memset+#endif++/* Allocation macros for large local structures+ *+ * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N]+ * MLD_FREE(v, T, N) zeroizes and frees the allocation+ *+ * Default implementation uses stack allocation.+ * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE+ * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE.+ */+#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \+ (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE))+#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE+#endif++/* Context-parameter machinery (MLD_CONTEXT_PARAMETERS_n and related config+ * checks). Kept in a separate, level-generic header for readability; included+ * here so it is available to the allocation macros below and to all consumers+ * of common.h. */+#include "context.h"++#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE)+/* Default: stack allocation */++/* This is a declaration macro, not an expression macro: T is a type and v is+ * a declarator, neither of which can be wrapped in parentheses. The+ * bugprone-macro-parentheses diagnostic is therefore a false positive here. */+#define MLD_ALLOC(v, T, N, context) \+ MLD_ALIGN T mld_alloc_##v[N]; \+ T *v = mld_alloc_##v /* NOLINT(bugprone-macro-parentheses) */++/* The MLD_FREE macro body references mld_zeroize(), which is declared in+ * ct.h. We deliberately do NOT include ct.h here: doing so would create a+ * circular dependency (ct.h includes common.h), and common.h itself never+ * calls mld_zeroize() -- only the macro expansion does. Each translation+ * unit that uses MLD_FREE therefore includes ct.h directly. */+#define MLD_FREE(v, T, N, context) \+ do \+ { \+ MLD_CONTEXT_UNUSED(context); \+ mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \+ (v) = NULL; \+ } while (0)++#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */++/* Custom allocation */++/*+ * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here.+ */+#define MLD_APPLY(f, args) f args++#define MLD_ALLOC(v, T, N, context) \+ MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context))++#define MLD_FREE(v, T, N, context) \+ do \+ { \+ if (v != NULL) \+ { \+ mld_zeroize(v, sizeof(T) * (N)); \+ MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \+ v = NULL; \+ } \+ } while (0)++#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */++/****************************** Error codes ***********************************/++/* Generic failure condition, reserved for failures not covered by a more+ * specific error code. */+#define MLD_ERR_FAIL (-1)+/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE+ * is defined and the provided MLD_CUSTOM_ALLOC can fail. */+#define MLD_ERR_OUT_OF_MEMORY (-2)+/* An RNG failure occurred. Might be due to insufficient entropy or+ * system misconfiguration. */+#define MLD_ERR_RNG_FAIL (-3)+/* The signing rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS iterations without producing a valid+ * signature. With a FIPS 204 Appendix C compliant bound (>= 821) this+ * has probability < 2^-256. */+#define MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED (-4)+/* Signing was paused before completing, at the request of a caller-provided+ * MLD_CONFIG_SIGN_HOOK_ATTEMPT hook (see mldsa_native_config.h). The caller+ * resumes by re-invoking signing with the same inputs; the attempt hook,+ * together with MLD_CONFIG_SIGN_HOOK_RESUME, decides where to continue. */+#define MLD_ERR_SIGNING_PAUSED (-5)+/* Signature verification failed: the signature is not valid for the given+ * message and public key. Returned by the verification API. */+#define MLD_ERR_INVALID_SIGNATURE (-6)+/* Secret key validation failed: the secret key is malformed or internally+ * inconsistent. Returned by pk_from_sk. */+#define MLD_ERR_INVALID_KEY (-7)+/* The Pairwise Consistency Test failed. Only possible when+ * MLD_CONFIG_KEYGEN_PCT is enabled; signals that the freshly generated key+ * pair failed its sign/verify self-test. */+#define MLD_ERR_PCT_FAIL (-8)+/* An argument was invalid, e.g. an unsupported pre-hash algorithm or a context+ * string longer than 255 bytes. */+#define MLD_ERR_INVALID_ARG (-9)+++#endif /* !__ASSEMBLER__ */++#endif /* !MLD_COMMON_H */
@@ -0,0 +1,152 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_CONTEXT_H+#define MLD_CONTEXT_H++/* This header is included by common.h once the configuration has been pulled+ * in; it is not meant to be included directly. */+#if !defined(__ASSEMBLER__)++#include <stdint.h>+#include "cbmc.h"+#include "sys.h"++/*+ * If the integration wants to provide a context parameter for use in+ * platform-specific hooks, then it should define this parameter.+ *+ * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros+ * defining the function names and expand to either pass or discard the context+ * argument as required by the current build. If there is no context parameter+ * requested then these are removed from the prototypes and from all calls.+ */+#ifdef MLD_CONFIG_CONTEXT_PARAMETER+#define MLD_CONTEXT_PARAMETERS_0(context) (context)+#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context)+#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context)+#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \+ (arg0, arg1, arg2, context)+#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \+ (arg0, arg1, arg2, arg3, context)+#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \+ (arg0, arg1, arg2, arg3, arg4, context)+#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \+ (arg0, arg1, arg2, arg3, arg4, arg5, context)+#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \+ context) \+ (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context)+#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \+ arg7, context) \+ (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context)+#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \+ arg7, arg8, context) \+ (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context)+#else /* MLD_CONFIG_CONTEXT_PARAMETER */+#define MLD_CONTEXT_PARAMETERS_0(context) ()+#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0)+#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1)+#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2)+#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \+ (arg0, arg1, arg2, arg3)+#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \+ (arg0, arg1, arg2, arg3, arg4)+#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \+ (arg0, arg1, arg2, arg3, arg4, arg5)+#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \+ context) \+ (arg0, arg1, arg2, arg3, arg4, arg5, arg6)+#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \+ arg7, context) \+ (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)+#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \+ arg7, arg8, context) \+ (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)+#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */++/* Consume a context parameter carried only for the integration's benefit,+ * avoiding -Wunused-parameter; expands to nothing when no context is+ * configured. */+#if defined(MLD_CONFIG_CONTEXT_PARAMETER)+#define MLD_CONTEXT_UNUSED(context) ((void)(context))+#else+#define MLD_CONTEXT_UNUSED(context) ((void)0)+#endif++#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \+ defined(MLD_CONFIG_CONTEXT_PARAMETER)+#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined+#endif++/* The signing hooks tie into the rejection-sampling loop. A pausing attempt+ * hook only reproduces the uninterrupted signature if the randomness is fixed+ * across calls, and thus requires the deterministic API.+ * For now we impose that requirement on all three hooks uniformly: enabling any+ * of them requires MLD_CONFIG_NO_RANDOMIZED_API. This also rules out+ * MLD_CONFIG_KEYGEN_PCT (whose PCT needs the randomized signature(), see+ * common.h).+ *+ * A logging-only use (attempt always returns 0; resume/finish merely observe)+ * would be safe with the randomized API too, but the restriction is applied+ * uniformly for now. */+#if (defined(MLD_CONFIG_SIGN_HOOK_RESUME) || \+ defined(MLD_CONFIG_SIGN_HOOK_ATTEMPT) || \+ defined(MLD_CONFIG_SIGN_HOOK_FINISH)) && \+ !defined(MLD_CONFIG_NO_RANDOMIZED_API)+#error Signing hooks (MLD_CONFIG_SIGN_HOOK_RESUME / _ATTEMPT / _FINISH) require MLD_CONFIG_NO_RANDOMIZED_API+#endif /* (MLD_CONFIG_SIGN_HOOK_RESUME || MLD_CONFIG_SIGN_HOOK_ATTEMPT || \+ MLD_CONFIG_SIGN_HOOK_FINISH) && !MLD_CONFIG_NO_RANDOMIZED_API */++/* Signing hooks (MLD_CONFIG_SIGN_HOOK_RESUME / _ATTEMPT / _FINISH; documented+ * in mldsa_native_config.h). The following macros route the call sites to+ * mld_sign_hook_*, appending or dropping the context argument; each unset hook+ * uses the dummy below. */+#define mld_sign_resume mld_sign_hook_resume MLD_CONTEXT_PARAMETERS_0+#define mld_sign_attempt mld_sign_hook_attempt MLD_CONTEXT_PARAMETERS_1+#define mld_sign_finish mld_sign_hook_finish MLD_CONTEXT_PARAMETERS_1++/* We don't use mld_sign_resume here because MLD_CONTEXT_PARAMETERS_0 is+ * unsuitable for function declarations: it misses `void` as the placeholder+ * argument. */+#if !defined(MLD_CONFIG_SIGN_HOOK_RESUME)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint16_t mld_sign_hook_resume(+#if defined(MLD_CONFIG_CONTEXT_PARAMETER)+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context+#else+ void+#endif+)+__contract__(assigns() ensures(1))+{+ MLD_CONTEXT_UNUSED(context);+ return 0;+}+#endif /* !MLD_CONFIG_SIGN_HOOK_RESUME */++#if !defined(MLD_CONFIG_SIGN_HOOK_ATTEMPT)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_sign_attempt(+ uint16_t attempt, MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(assigns() ensures(1))+{+ ((void)attempt);+ MLD_CONTEXT_UNUSED(context);+ return 0;+}+#endif /* !MLD_CONFIG_SIGN_HOOK_ATTEMPT */++#if !defined(MLD_CONFIG_SIGN_HOOK_FINISH)+static MLD_INLINE void mld_sign_finish(+ uint16_t attempt, MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(assigns() ensures(1))+{+ ((void)attempt);+ MLD_CONTEXT_UNUSED(context);+}+#endif /* !MLD_CONFIG_SIGN_HOOK_FINISH */++#endif /* !__ASSEMBLER__ */++#endif /* !MLD_CONTEXT_H */
@@ -0,0 +1,21 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#include "ct.h"++#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)+/*+ * Masking value used in constant-time functions from+ * ct.h to block the compiler's range analysis and+ * thereby reduce the risk of compiler-introduced branches.+ */+volatile uint64_t mld_ct_opt_blocker_u64 = 0;++#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++MLD_EMPTY_CU(ct)++#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,373 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ *+ * - [libmceliece]+ * libmceliece implementation of Classic McEliece+ * Bernstein, Chou+ * https://lib.mceliece.org/+ *+ * - [optblocker]+ * PQC forum post on opt-blockers using volatile globals+ * Daniel J. Bernstein+ * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ+ */++#ifndef MLD_CT_H+#define MLD_CT_H++#include "cbmc.h"+#include "common.h"++/* Constant-time comparisons and conditional operations++ We reduce the risk for compilation into variable-time code+ through the use of 'value barriers'.++ Functionally, a value barrier is a no-op. To the compiler, however,+ it constitutes an arbitrary modification of its input, and therefore+ harden's value propagation and range analysis.++ We consider two approaches to implement a value barrier:+ - An empty inline asm block which marks the target value as clobbered.+ - XOR'ing with the value of a volatile global that's set to 0;+ see @[optblocker] for a discussion of this idea, and+ @[libmceliece, inttypes/crypto_intN.h] for an implementation.++ The first approach is cheap because it only prevents the compiler+ from reasoning about the value of the variable past the barrier,+ but does not directly generate additional instructions.++ The second approach generates redundant loads and XOR operations+ and therefore comes at a higher runtime cost. However, it appears+ more robust towards optimization, as compilers should never drop+ a volatile load.++ We use the empty-ASM value barrier for GCC and clang, and fall+ back to the global volatile barrier otherwise.++ The global value barrier can be forced by setting+ MLD_CONFIG_NO_ASM_VALUE_BARRIER.++*/++#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER)+#define MLD_USE_ASM_VALUE_BARRIER+#endif+++#if !defined(MLD_USE_ASM_VALUE_BARRIER)+/*+ * Declaration of global volatile that the global value barrier+ * is loading from and masking with.+ */+#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64)+extern volatile uint64_t mld_ct_opt_blocker_u64;+++/* Helper functions for obtaining global masks of various sizes */++/* This contract is not proved but treated as an axiom.+ *+ * Its validity relies on the assumption that the global opt-blocker+ * constant mld_ct_opt_blocker_u64 is not modified.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void)+__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; }++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void)+__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); }++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void)+__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); }++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void)+__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); }++/* Opt-blocker based implementation of value barriers */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b)+__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); }++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b)+__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); }++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b)+__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); }+++#else /* !MLD_USE_ASM_VALUE_BARRIER */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b)+__contract__(ensures(return_value == b))+{+ __asm__ volatile("" : "+r"(b));+ return b;+}++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b)+__contract__(ensures(return_value == b))+{+ __asm__ volatile("" : "+r"(b));+ return b;+}++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b)+__contract__(ensures(return_value == b))+{+ __asm__ volatile("" : "+r"(b));+ return b;+}+#endif /* MLD_USE_ASM_VALUE_BARRIER */++#ifdef CBMC+#pragma CPROVER check push+#pragma CPROVER check disable "conversion"+#endif++/**+ * Cast uint32 value to int32.+ *+ * @param x Input value.+ *+ * @return For uint32_t x, the unique y in int32_t so that x == y mod 2^32.+ * Concretely:+ * - x < 2^31: returns x+ * - x >= 2^31: returns x - 2^32+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x)+{+ /*+ * PORTABILITY: This relies on uint32_t -> int32_t+ * being implemented as the inverse of int32_t -> uint32_t,+ * which is implementation-defined (C99 6.3.1.3 (3))+ * CBMC (correctly) fails to prove this conversion is OK,+ * so we have to suppress that check here+ */+ return (int32_t)x;+}++#ifdef CBMC+#pragma CPROVER check pop+#endif+++/**+ * Cast int64 value to uint32 as per C standard.+ *+ * @param x Input value.+ *+ * @return For int64_t x, the unique y in uint32_t so that x == y mod 2^32.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x)+{+ return (uint32_t)(x & (int64_t)UINT32_MAX);+}++/**+ * Cast int32 value to uint32 as per C standard.+ *+ * @param x Input value.+ *+ * @return For int32_t x, the unique y in uint32_t so that x == y mod 2^32.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x)+{+ return mld_cast_int64_to_uint32((int64_t)x);+}++/**+ * Functionally equivalent to cond ? a : b, but implemented with guards against+ * compiler-introduced branches.+ *+ * @param a First alternative.+ * @param b Second alternative.+ * @param cond Condition variable.+ *+ * @return a if cond is 0xFFFFFFFF, b if cond is 0.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond)+__contract__(+ requires(cond == 0x0 || cond == 0xFFFFFFFF)+ ensures(return_value == (cond ? a : b))+)+{+ uint32_t au = mld_cast_int32_to_uint32(a);+ uint32_t bu = mld_cast_int32_to_uint32(b);+ uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu));+ return mld_cast_uint32_to_int32(res);+}++/**+ * Return 0 if input is zero, and -1 otherwise.+ *+ * @param x Value to be converted into a mask.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x)+__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF)))+{+ int64_t tmp = mld_value_barrier_i64(-((int64_t)x));+ /*+ * PORTABILITY: Right-shift on a signed integer is+ * implementation-defined for negative left argument.+ * Here, we assume it's sign-preserving "arithmetic" shift right.+ * See (C99 6.5.7 (5))+ */+ tmp >>= 32;+ return mld_cast_int64_to_uint32(tmp);+}++/**+ * Return 0 if input is zero, and -1 otherwise.+ *+ * @param x Value to be converted into a mask.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x)+__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF)))+{+ uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x);+ return (uint8_t)(mask & 0xFF);+}++/**+ * Return 0 if input is non-negative, and -1 otherwise.+ *+ * @param x Value to be converted into a mask.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x)+__contract__(+ ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0))+)+{+ int64_t tmp = mld_value_barrier_i64((int64_t)x);+ /*+ * PORTABILITY: Right-shift on a signed integer is+ * implementation-defined for negative left argument.+ * Here, we assume it's sign-preserving "arithmetic" shift right.+ * See (C99 6.5.7 (5))+ */+ tmp >>= 31;+ return mld_cast_int64_to_uint32(tmp);+}++/**+ * Return -x if x<0, x otherwise.+ *+ * @param x Input value.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x)+__contract__(+ requires(x >= -INT32_MAX)+ ensures(return_value == ((x < 0) ? -x : x))+)+{+ return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x));+}++/**+ * Compare two arrays for equality in constant time.+ *+ * @param[in] a Pointer to first byte array.+ * @param[in] b Pointer to second byte array.+ * @param len Length of the byte arrays, upper-bounded to UINT16_MAX to+ * control proof complexity only.+ *+ * @return 0 if the byte arrays are equal, 0xFF otherwise.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b,+ const size_t len)+__contract__(+ requires(len <= UINT16_MAX)+ requires(memory_no_alias(a, len))+ requires(memory_no_alias(b, len))+ ensures((return_value == 0) || (return_value == 0xFF))+ ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i]))))+{+ uint8_t r = 0, s = 0;+ unsigned i;++ for (i = 0; i < len; i++)+ __loop__(+ invariant(i <= len)+ invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))+ decreases(len - i))+ {+ r |= a[i] ^ b[i];+ /* s is useless, but prevents the loop from being aborted once r=0xff. */+ s ^= a[i] ^ b[i];+ }++ /*+ * - Convert r into a mask; this may not be necessary, but is an additional+ * safeguard+ * towards leaking information about a and b.+ * - XOR twice with s, separated by a value barrier, to prevent the compile+ * from dropping the s computation in the loop.+ */+ return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s);+}++/**+ * Force-zeroize a buffer.+ *+ * @[FIPS204, Section 3.6.3] Destruction of intermediate values.+ *+ * @param[out] ptr Pointer to buffer to be zeroed.+ * @param len Amount of bytes to be zeroed.+ */+#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE)+#if defined(MLD_SYS_WINDOWS)+#include <windows.h>+#elif !defined(MLD_HAVE_INLINE_ASM)+#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE.+#endif++static MLD_INLINE void mld_zeroize(void *ptr, size_t len)+__contract__(+ requires(len <= UINT32_MAX)+ requires(memory_no_alias(ptr, len))+ assigns(memory_slice(ptr, len))+ ensures(array_zeroized_u8((uint8_t *)ptr, len)))+{+#if defined(MLD_SYS_WINDOWS)+ SecureZeroMemory(ptr, len);+#else+ mld_memset(ptr, 0, len);+ /* This follows OpenSSL and seems sufficient to prevent the compiler+ * from optimizing away the memset.+ *+ * If there was a reliable way to detect availability of memset_s(),+ * that would be preferred. */+ __asm__ __volatile__("" : : "r"(ptr) : "memory");+#endif /* !MLD_SYS_WINDOWS */+}+#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */++#endif /* !MLD_CT_H */
@@ -0,0 +1,75 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */++#include "common.h"++#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#if defined(MLDSA_DEBUG)++#include <inttypes.h>+#include <stdio.h>+#include <stdlib.h>+#include "debug.h"++#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] "++MLD_INTERNAL_API+void mld_debug_check_assert(const char *file, int line, const int val)+{+ if (val == 0)+ {+ fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n",+ file, line, val);+ exit(1);+ }+}++MLD_INTERNAL_API+void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr,+ unsigned len, int64_t lower_bound_exclusive,+ int64_t upper_bound_exclusive)+{+ int err = 0;+ unsigned i;+ for (i = 0; i < len; i++)+ {+ int32_t val = ptr[i];+ if (!(val > lower_bound_exclusive && val < upper_bound_exclusive))+ {+ fprintf(stderr,+ MLD_DEBUG_ERROR_HEADER+ "Bounds assertion failed: Index %u, value %d out of bounds "+ "(%" PRId64 ",%" PRId64 ")\n",+ file, line, i, (int)val, lower_bound_exclusive,+ upper_bound_exclusive);+ err = 1;+ }+ }++ if (err == 1)+ {+ exit(1);+ }+}++#else /* MLDSA_DEBUG */++MLD_EMPTY_CU(debug)++#endif /* !MLDSA_DEBUG */++#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */++MLD_EMPTY_CU(debug)++#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef MLD_DEBUG_ERROR_HEADER
@@ -0,0 +1,125 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_DEBUG_H+#define MLD_DEBUG_H+#include "common.h"++#if defined(MLDSA_DEBUG)++/**+ * Check debug assertion.+ *+ * Prints an error message to stderr and calls exit(1) if not.+ *+ * @param file Filename.+ * @param line Line number.+ * @param val Value asserted to be non-zero.+ */+#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert)+MLD_INTERNAL_API+void mld_debug_check_assert(const char *file, int line, const int val);++/**+ * Check whether values in an array of int32_t are within specified bounds.+ *+ * Prints an error message to stderr and calls exit(1) if not.+ *+ * @param file Filename.+ * @param line Line number.+ * @param[in] ptr Base of array to be checked.+ * @param len Number of int32_t in ptr.+ * @param lower_bound_exclusive Exclusive lower bound.+ * @param upper_bound_exclusive Exclusive upper bound.+ */+#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds)+MLD_INTERNAL_API+void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr,+ unsigned len, int64_t lower_bound_exclusive,+ int64_t upper_bound_exclusive);++/* Check assertion, calling exit() upon failure+ *+ * val: Value that's asserted to be non-zero+ */+#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val))++/* Check bounds in array of int32_t's+ * ptr: Base of int32_t array; will be explicitly cast to int32_t*,+ * so you may pass a byte-compatible type such as mld_poly or mld_polyvec.+ * len: Number of int32_t in array+ * value_lb: Inclusive lower value bound+ * value_ub: Exclusive upper value bound */+#define mld_assert_bound(ptr, len, value_lb, value_ub) \+ mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \+ ((int64_t)(value_lb)) - 1, (value_ub))++/* Check absolute bounds in array of int32_t's+ * ptr: Base of array, expression of type int32_t*+ * len: Number of int32_t in array+ * value_abs_bd: Exclusive absolute upper bound */+#define mld_assert_abs_bound(ptr, len, value_abs_bd) \+ mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \+ (value_abs_bd))++/* Version of bounds assertions for 2-dimensional arrays */+#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \+ mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub))++#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \+ mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd))++/* When running CBMC, convert debug assertions into proof obligations */+#elif defined(CBMC)+#include "cbmc.h"++#define mld_assert(val) cassert(val)++#define mld_assert_bound(ptr, len, value_lb, value_ub) \+ cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub)))++#define mld_assert_abs_bound(ptr, len, value_abs_bd) \+ cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd)))++/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't+ * just use a single flattened array_bound(...) here. */+#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \+ cassert(forall(kN, 0, (M), \+ array_bound(&((int32_t (*)[(N)])(ptr))[kN][0], 0, (N), \+ (value_lb), (value_ub))))++#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \+ cassert(forall(kN, 0, (M), \+ array_abs_bound(&((int32_t (*)[(N)])(ptr))[kN][0], 0, (N), \+ (value_abs_bd))))++#else /* !MLDSA_DEBUG && CBMC */++#define mld_assert(val) \+ do \+ { \+ } while (0)+#define mld_assert_bound(ptr, len, value_lb, value_ub) \+ do \+ { \+ } while (0)+#define mld_assert_abs_bound(ptr, len, value_abs_bd) \+ do \+ { \+ } while (0)++#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \+ do \+ { \+ } while (0)++#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \+ do \+ { \+ } while (0)+++#endif /* !MLDSA_DEBUG && !CBMC */+#endif /* !MLD_DEBUG_H */
@@ -0,0 +1,270 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ *+ * - [mupq]+ * Common files for pqm4, pqm3, pqriscv+ * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen+ * https://github.com/mupq/mupq+ *+ * - [supercop]+ * SUPERCOP benchmarking framework+ * Daniel J. Bernstein+ * http://bench.cr.yp.to/supercop.html+ *+ * - [tweetfips]+ * 'tweetfips202' FIPS202 implementation+ * Van Assche, Bernstein, Schwabe+ * https://keccak.team/2015/tweetfips202.html+ */++/* Based on the CC0 implementation from @[mupq] and the public domain+ * implementation @[supercop, crypto_hash/keccakc512/simple/]+ * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */++#include <stddef.h>++#include "../common.h"+#include "../ct.h"+#include "fips202.h"+#include "keccakf1600.h"+#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/**+ * Initializes the Keccak state.+ *+ * @param[out] s Pointer to Keccak state.+ */+static void keccak_init(uint64_t s[MLD_KECCAK_LANES])+__contract__(+ requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES))+ assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES))+)+{+ mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES);+}++/**+ * Absorb step of Keccak; incremental.+ *+ * @param[in,out] s Pointer to Keccak state.+ * @param pos Position in current block to be absorbed.+ * @param r Rate in bytes (e.g., 168 for SHAKE128).+ * @param[in] in Pointer to input to be absorbed into s.+ * @param inlen Length of input in bytes.+ *+ * @return New position pos in current block.+ */+static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES],+ unsigned int pos, unsigned int r,+ const uint8_t *in, size_t inlen)+__contract__(+ requires(inlen <= MLD_MAX_BUFFER_SIZE)+ requires(r > 0)+ requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES)+ requires(pos <= r)+ requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES))+ requires(memory_no_alias(in, inlen))+ assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES))+ ensures(return_value < r))+{+ while (inlen >= r - pos)+ __loop__(+ assigns(pos, in, inlen,+ memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES))+ invariant(inlen <= loop_entry(inlen))+ invariant(pos <= r)+ invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))+ decreases(inlen + pos))+ {+ mld_keccakf1600_xor_bytes(s, in, pos, r - pos);+ inlen -= r - pos;+ in += r - pos;+ mld_keccakf1600_permute(s);+ pos = 0;+ }+ /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */+ mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen);++ /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned+ * is safe. */+ return (unsigned)(pos + inlen);+}++/**+ * Finalize absorb step.+ *+ * @param[in,out] s Pointer to Keccak state.+ * @param pos Position in current block to be absorbed.+ * @param r Rate in bytes (e.g., 168 for SHAKE128).+ * @param p Domain separation byte.+ */+static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos,+ unsigned int r, uint8_t p)+__contract__(+ requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES)+ requires((r / 8) >= 1)+ requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES))+ assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES))+)+{+ uint8_t b = 0x80;+ mld_keccakf1600_xor_bytes(s, &p, pos, 1);+ mld_keccakf1600_xor_bytes(s, &b, r - 1, 1);+}++/**+ * Squeeze step of Keccak. Squeezes arbitrarily many bytes. Modifies the+ * state. Can be called multiple times to keep squeezing, i.e., is+ * incremental.+ *+ * @param[out] out Pointer to output data.+ * @param outlen Number of bytes to be squeezed (written to out).+ * @param[in,out] s Pointer to input/output Keccak state.+ * @param pos Number of bytes in current block already squeezed.+ * @param r Rate in bytes (e.g., 168 for SHAKE128).+ *+ * @return New position pos in current block.+ */+static unsigned int keccak_squeeze(uint8_t *out, size_t outlen,+ uint64_t s[MLD_KECCAK_LANES],+ unsigned int pos, unsigned int r)+__contract__(+ requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) ||+ (r == SHAKE256_RATE && pos <= SHAKE256_RATE) ||+ (r == SHA3_512_RATE && pos <= SHA3_512_RATE))+ requires(outlen <= 8 * r /* somewhat arbitrary bound */)+ requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES))+ requires(memory_no_alias(out, outlen))+ assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES))+ assigns(memory_slice(out, outlen))+ ensures(return_value <= r))+{+ unsigned int i;+ size_t out_offset = 0;++ /* Reference: This code is re-factored from the reference implementation+ * to facilitate proof with CBMC and to improve readability.+ *+ * Take a mutable copy of outlen to count down the number of bytes+ * still to squeeze. The initial value of outlen is needed for the CBMC+ * assigns() clauses. */+ size_t bytes_to_go = outlen;++ while (bytes_to_go > 0)+ __loop__(+ assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen))+ invariant(bytes_to_go <= outlen)+ invariant(out_offset == outlen - bytes_to_go)+ invariant(pos <= r)+ decreases(bytes_to_go)+ )+ {+ if (pos == r)+ {+ mld_keccakf1600_permute(s);+ pos = 0;+ }+ /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */+ i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos;+ mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i);+ bytes_to_go -= i;+ pos += i;+ out_offset += i;+ }++ return pos;+}++MLD_INTERNAL_API+void mld_shake128_init(mld_shake128ctx *state)+{+ keccak_init(state->s);+ state->pos = 0;+}++MLD_INTERNAL_API+void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in,+ size_t inlen)+{+ state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen);+}++MLD_INTERNAL_API+void mld_shake128_finalize(mld_shake128ctx *state)+{+ keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F);+ state->pos = SHAKE128_RATE;+}++MLD_INTERNAL_API+void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state)+{+ state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE);+}++MLD_INTERNAL_API+void mld_shake128_release(mld_shake128ctx *state)+{+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(state, sizeof(mld_shake128ctx));+}++MLD_INTERNAL_API+void mld_shake256_init(mld_shake256ctx *state)+{+ keccak_init(state->s);+ state->pos = 0;+}++MLD_INTERNAL_API+void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in,+ size_t inlen)+{+ state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen);+}++MLD_INTERNAL_API+void mld_shake256_finalize(mld_shake256ctx *state)+{+ keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F);+ state->pos = SHAKE256_RATE;+}++MLD_INTERNAL_API+void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state)+{+ state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE);+}++MLD_INTERNAL_API+void mld_shake256_release(mld_shake256ctx *state)+{+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(state, sizeof(mld_shake256ctx));+}++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_CORE_API_ONLY)+MLD_INTERNAL_API+void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)+{+ mld_shake256ctx state;++ mld_shake256_init(&state);+ mld_shake256_absorb(&state, in, inlen);+ mld_shake256_finalize(&state);+ mld_shake256_squeeze(out, outlen, &state);+ mld_shake256_release(&state);+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_CORE_API_ONLY */++#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */
@@ -0,0 +1,224 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_FIPS202_FIPS202_H+#define MLD_FIPS202_FIPS202_H++#include <stddef.h>+#include "../cbmc.h"+#include "../common.h"++#define SHAKE128_RATE 168+#define SHAKE256_RATE 136+#define SHA3_256_RATE 136+#define SHA3_512_RATE 72+#define MLD_KECCAK_LANES 25+#define SHA3_256_HASHBYTES 32+#define SHA3_512_HASHBYTES 64+++/** Context for the incremental SHAKE128 XOF. */+typedef struct+{+ uint64_t s[MLD_KECCAK_LANES]; /**< Keccak state. */+ unsigned int pos; /**< Byte position within the current Keccak block. */+} mld_shake128ctx;++/** Context for the incremental SHAKE256 XOF. */+typedef struct+{+ uint64_t s[MLD_KECCAK_LANES]; /**< Keccak state. */+ unsigned int pos; /**< Byte position within the current Keccak block. */+} mld_shake256ctx;++#define mld_shake128_init MLD_NAMESPACE(shake128_init)+/**+ * Initializes state for use as SHAKE128 XOF.+ *+ * @param[out] state Pointer to (uninitialized) state.+ */+MLD_INTERNAL_API+void mld_shake128_init(mld_shake128ctx *state)+__contract__(+ requires(memory_no_alias(state, sizeof(mld_shake128ctx)))+ assigns(memory_slice(state, sizeof(mld_shake128ctx)))+ ensures(state->pos == 0)+);++#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb)+/**+ * Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. Can be+ * called multiple times to absorb multiple chunks of data.+ *+ * @param[in,out] state Pointer to (initialized) output state.+ * @param[in] in Pointer to input to be absorbed into s.+ * @param inlen Length of input in bytes.+ */+MLD_INTERNAL_API+void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in,+ size_t inlen)+__contract__(+ requires(inlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(state, sizeof(mld_shake128ctx)))+ requires(memory_no_alias(in, inlen))+ requires(state->pos <= SHAKE128_RATE)+ assigns(memory_slice(state, sizeof(mld_shake128ctx)))+ ensures(state->pos <= SHAKE128_RATE)+);++#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize)+/**+ * Concludes the absorb phase of the SHAKE128 XOF.+ *+ * @param[in,out] state Pointer to state.+ */+MLD_INTERNAL_API+void mld_shake128_finalize(mld_shake128ctx *state)+__contract__(+ requires(memory_no_alias(state, sizeof(mld_shake128ctx)))+ requires(state->pos <= SHAKE128_RATE)+ assigns(memory_slice(state, sizeof(mld_shake128ctx)))+ ensures(state->pos <= SHAKE128_RATE)+);++#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze)+/**+ * Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many bytes. Can be+ * called multiple times to keep squeezing.+ *+ * @param[out] out Pointer to output blocks.+ * @param outlen Number of bytes to be squeezed (written to output).+ * @param[in,out] state Pointer to input/output state.+ */+MLD_INTERNAL_API+void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state)+__contract__(+ requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */)+ requires(memory_no_alias(state, sizeof(mld_shake128ctx)))+ requires(memory_no_alias(out, outlen))+ requires(state->pos <= SHAKE128_RATE)+ assigns(memory_slice(state, sizeof(mld_shake128ctx)))+ assigns(memory_slice(out, outlen))+ ensures(state->pos <= SHAKE128_RATE)+);++#define mld_shake128_release MLD_NAMESPACE(shake128_release)+/**+ * Release and securely zero the SHAKE128 state.+ *+ * @param[in,out] state Pointer to state.+ */+MLD_INTERNAL_API+void mld_shake128_release(mld_shake128ctx *state)+__contract__(+ requires(memory_no_alias(state, sizeof(mld_shake128ctx)))+ assigns(memory_slice(state, sizeof(mld_shake128ctx)))+);++#define mld_shake256_init MLD_NAMESPACE(shake256_init)+/**+ * Initializes state for use as SHAKE256 XOF.+ *+ * @param[out] state Pointer to (uninitialized) state.+ */+MLD_INTERNAL_API+void mld_shake256_init(mld_shake256ctx *state)+__contract__(+ requires(memory_no_alias(state, sizeof(mld_shake256ctx)))+ assigns(memory_slice(state, sizeof(mld_shake256ctx)))+ ensures(state->pos == 0)+);++#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb)+/**+ * Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. Can be+ * called multiple times to absorb multiple chunks of data.+ *+ * @param[in,out] state Pointer to (initialized) output state.+ * @param[in] in Pointer to input to be absorbed into s.+ * @param inlen Length of input in bytes.+ */+MLD_INTERNAL_API+void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in,+ size_t inlen)+__contract__(+ requires(inlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(state, sizeof(mld_shake256ctx)))+ requires(memory_no_alias(in, inlen))+ requires(state->pos <= SHAKE256_RATE)+ assigns(memory_slice(state, sizeof(mld_shake256ctx)))+ ensures(state->pos <= SHAKE256_RATE)+);++#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize)+/**+ * Concludes the absorb phase of the SHAKE256 XOF.+ *+ * @param[in,out] state Pointer to state.+ */+MLD_INTERNAL_API+void mld_shake256_finalize(mld_shake256ctx *state)+__contract__(+ requires(memory_no_alias(state, sizeof(mld_shake256ctx)))+ requires(state->pos <= SHAKE256_RATE)+ assigns(memory_slice(state, sizeof(mld_shake256ctx)))+ ensures(state->pos <= SHAKE256_RATE)+);++#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze)+/**+ * Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many bytes. Can be+ * called multiple times to keep squeezing.+ *+ * @param[out] out Pointer to output blocks.+ * @param outlen Number of bytes to be squeezed (written to output).+ * @param[in,out] state Pointer to input/output state.+ */+MLD_INTERNAL_API+void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state)+__contract__(+ requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */)+ requires(memory_no_alias(state, sizeof(mld_shake256ctx)))+ requires(memory_no_alias(out, outlen))+ requires(state->pos <= SHAKE256_RATE)+ assigns(memory_slice(state, sizeof(mld_shake256ctx)))+ assigns(memory_slice(out, outlen))+ ensures(state->pos <= SHAKE256_RATE)+);++#define mld_shake256_release MLD_NAMESPACE(shake256_release)+/**+ * Release and securely zero the SHAKE256 state.+ *+ * @param[in,out] state Pointer to state.+ */+MLD_INTERNAL_API+void mld_shake256_release(mld_shake256ctx *state)+__contract__(+ requires(memory_no_alias(state, sizeof(mld_shake256ctx)))+ assigns(memory_slice(state, sizeof(mld_shake256ctx)))+);++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_CORE_API_ONLY)+#define mld_shake256 MLD_NAMESPACE(shake256)+/**+ * SHAKE256 XOF with non-incremental API.+ *+ * @param[out] out Pointer to output.+ * @param outlen Requested output length in bytes.+ * @param[in] in Pointer to input.+ * @param inlen Length of input in bytes.+ */+MLD_INTERNAL_API+void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)+__contract__(+ requires(inlen <= MLD_MAX_BUFFER_SIZE)+ requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */)+ requires(memory_no_alias(in, inlen))+ requires(memory_no_alias(out, outlen))+ assigns(memory_slice(out, outlen))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_CORE_API_ONLY */++#endif /* !MLD_FIPS202_FIPS202_H */
@@ -0,0 +1,187 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#include "../common.h"+#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)++#include "../ct.h"+#include "fips202.h"+#include "fips202x4.h"+#include "keccakf1600.h"++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_REDUCE_RAM) || \+ defined(MLD_UNIT_TEST)+static void mld_keccak_absorb_once_x4(uint64_t *s, unsigned r,+ const uint8_t *in0, const uint8_t *in1,+ const uint8_t *in2, const uint8_t *in3,+ size_t inlen, uint8_t p)+__contract__(+ requires(inlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+ requires(r > 0)+ requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES)+ requires(memory_no_alias(in0, inlen))+ requires(memory_no_alias(in1, inlen))+ requires(memory_no_alias(in2, inlen))+ requires(memory_no_alias(in3, inlen))+ assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)))+{+ while (inlen >= r)+ __loop__(+ assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+ invariant(inlen <= loop_entry(inlen))+ invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen))+ invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen))+ invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen))+ invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))+ decreases(inlen))+ {+ mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r);+ mld_keccakf1600x4_permute(s);++ in0 += r;+ in1 += r;+ in2 += r;+ in3 += r;+ inlen -= r;+ }++ /* Safety: At this point, inlen < r, so the truncations to unsigned are safe+ * below. */+ if (inlen > 0)+ {+ mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen);+ }++ if (inlen == r - 1)+ {+ p |= 128;+ mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1);+ }+ else+ {+ mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1);+ p = 128;+ mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1);+ }+}++static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1,+ uint8_t *out2, uint8_t *out3,+ size_t nblocks, uint64_t *s, unsigned r)+__contract__(+ requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES)+ requires(nblocks <= 8 /* somewhat arbitrary bound */)+ requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+ requires(memory_no_alias(out0, nblocks * r))+ requires(memory_no_alias(out1, nblocks * r))+ requires(memory_no_alias(out2, nblocks * r))+ requires(memory_no_alias(out3, nblocks * r))+ assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+ assigns(memory_slice(out0, nblocks * r))+ assigns(memory_slice(out1, nblocks * r))+ assigns(memory_slice(out2, nblocks * r))+ assigns(memory_slice(out3, nblocks * r)))+{+ size_t current_offset = 0;+ while (nblocks > 0)+ __loop__(+ assigns(nblocks, current_offset,+ memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY),+ memory_slice(out0, nblocks * r),+ memory_slice(out1, nblocks * r),+ memory_slice(out2, nblocks * r),+ memory_slice(out3, nblocks * r))+ invariant(nblocks <= loop_entry(nblocks))+ invariant(current_offset == (loop_entry(nblocks) - nblocks) * r)+ decreases(nblocks))+ {+ mld_keccakf1600x4_permute(s);+ mld_keccakf1600x4_extract_bytes(+ s, &out0[current_offset], &out1[current_offset], &out2[current_offset],+ &out3[current_offset], 0, r);+ current_offset += r;+ nblocks--;+ }+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_REDUCE_RAM || \+ MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+MLD_INTERNAL_API+void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0,+ const uint8_t *in1, const uint8_t *in2,+ const uint8_t *in3, size_t inlen)+{+ mld_memset(state, 0, sizeof(mld_shake128x4ctx));+ mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3,+ inlen, 0x1F);+}++MLD_INTERNAL_API+void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2,+ uint8_t *out3, size_t nblocks,+ mld_shake128x4ctx *state)+{+ mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx,+ SHAKE128_RATE);+}++MLD_INTERNAL_API+void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; }+MLD_INTERNAL_API+void mld_shake128x4_release(mld_shake128x4ctx *state)+{+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(state, sizeof(mld_shake128x4ctx));+}+#endif /* !MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ (!defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)))+MLD_INTERNAL_API+void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0,+ const uint8_t *in1, const uint8_t *in2,+ const uint8_t *in3, size_t inlen)+{+ mld_memset(state, 0, sizeof(mld_shake256x4ctx));+ mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3,+ inlen, 0x1F);+}++MLD_INTERNAL_API+void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2,+ uint8_t *out3, size_t nblocks,+ mld_shake256x4ctx *state)+{+ mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx,+ SHAKE256_RATE);+}++MLD_INTERNAL_API+void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; }+MLD_INTERNAL_API+void mld_shake256x4_release(mld_shake256x4ctx *state)+{+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(state, sizeof(mld_shake256x4ctx));+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || (!MLD_CONFIG_NO_SIGN_API && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST)) */++#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED && !MLD_CONFIG_SERIAL_FIPS202_ONLY \+ */
@@ -0,0 +1,125 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_FIPS202_FIPS202X4_H+#define MLD_FIPS202_FIPS202X4_H++#include "../common.h"++#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)++#include <stddef.h>++#include "../cbmc.h"+#include "fips202.h"+#include "keccakf1600.h"++/** Context for the non-incremental 4-way SHAKE128 API. */+typedef struct+{+ uint64_t ctx[MLD_KECCAK_LANES *+ MLD_KECCAK_WAY]; /**< 4-way Keccak state, stored sequentially. */+} mld_shake128x4ctx;++/** Context for the 4-way batched SHAKE256 XOF. */+typedef struct+{+ uint64_t ctx[MLD_KECCAK_LANES *+ MLD_KECCAK_WAY]; /**< Interleaved 4-way Keccak state. */+} mld_shake256x4ctx;++#if !defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once)+MLD_INTERNAL_API+void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0,+ const uint8_t *in1, const uint8_t *in2,+ const uint8_t *in3, size_t inlen)+__contract__(+ requires(inlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(state, sizeof(mld_shake128x4ctx)))+ requires(memory_no_alias(in0, inlen))+ requires(memory_no_alias(in1, inlen))+ requires(memory_no_alias(in2, inlen))+ requires(memory_no_alias(in3, inlen))+ assigns(memory_slice(state, sizeof(mld_shake128x4ctx)))+);++#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks)+MLD_INTERNAL_API+void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2,+ uint8_t *out3, size_t nblocks,+ mld_shake128x4ctx *state)+__contract__(+ requires(nblocks <= 8 /* somewhat arbitrary bound */)+ requires(memory_no_alias(state, sizeof(mld_shake128x4ctx)))+ requires(memory_no_alias(out0, nblocks * SHAKE128_RATE))+ requires(memory_no_alias(out1, nblocks * SHAKE128_RATE))+ requires(memory_no_alias(out2, nblocks * SHAKE128_RATE))+ requires(memory_no_alias(out3, nblocks * SHAKE128_RATE))+ assigns(memory_slice(out0, nblocks * SHAKE128_RATE),+ memory_slice(out1, nblocks * SHAKE128_RATE),+ memory_slice(out2, nblocks * SHAKE128_RATE),+ memory_slice(out3, nblocks * SHAKE128_RATE),+ memory_slice(state, sizeof(mld_shake128x4ctx)))+);++#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init)+MLD_INTERNAL_API+void mld_shake128x4_init(mld_shake128x4ctx *state);++#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release)+MLD_INTERNAL_API+void mld_shake128x4_release(mld_shake128x4ctx *state);+#endif /* !MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ (!defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)))+#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once)+MLD_INTERNAL_API+void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0,+ const uint8_t *in1, const uint8_t *in2,+ const uint8_t *in3, size_t inlen)+__contract__(+ requires(inlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(state, sizeof(mld_shake256x4ctx)))+ requires(memory_no_alias(in0, inlen))+ requires(memory_no_alias(in1, inlen))+ requires(memory_no_alias(in2, inlen))+ requires(memory_no_alias(in3, inlen))+ assigns(memory_slice(state, sizeof(mld_shake256x4ctx)))+);++#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks)+MLD_INTERNAL_API+void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2,+ uint8_t *out3, size_t nblocks,+ mld_shake256x4ctx *state)+__contract__(+ requires(nblocks <= 8 /* somewhat arbitrary bound */)+ requires(memory_no_alias(state, sizeof(mld_shake256x4ctx)))+ requires(memory_no_alias(out0, nblocks * SHAKE256_RATE))+ requires(memory_no_alias(out1, nblocks * SHAKE256_RATE))+ requires(memory_no_alias(out2, nblocks * SHAKE256_RATE))+ requires(memory_no_alias(out3, nblocks * SHAKE256_RATE))+ assigns(memory_slice(out0, nblocks * SHAKE256_RATE),+ memory_slice(out1, nblocks * SHAKE256_RATE),+ memory_slice(out2, nblocks * SHAKE256_RATE),+ memory_slice(out3, nblocks * SHAKE256_RATE),+ memory_slice(state, sizeof(mld_shake256x4ctx)))+);++#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init)+MLD_INTERNAL_API+void mld_shake256x4_init(mld_shake256x4ctx *state);++#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release)+MLD_INTERNAL_API+void mld_shake256x4_release(mld_shake256x4ctx *state);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || (!MLD_CONFIG_NO_SIGN_API && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST)) */++#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */+#endif /* !MLD_FIPS202_FIPS202X4_H */
@@ -0,0 +1,510 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [mupq]+ * Common files for pqm4, pqm3, pqriscv+ * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen+ * https://github.com/mupq/mupq+ *+ * - [supercop]+ * SUPERCOP benchmarking framework+ * Daniel J. Bernstein+ * http://bench.cr.yp.to/supercop.html+ *+ * - [tweetfips]+ * 'tweetfips202' FIPS202 implementation+ * Van Assche, Bernstein, Schwabe+ * https://keccak.team/2015/tweetfips202.html+ */++/* Based on the CC0 implementation from @[mupq] and the public domain+ * implementation @[supercop, crypto_hash/keccakc512/simple/]+ * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */++#include "keccakf1600.h"+#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#define MLD_KECCAK_NROUNDS 24+#define MLD_KECCAK_ROL(a, offset) (((a) << (offset)) ^ ((a) >> (64 - (offset))))++MLD_INTERNAL_API+void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data,+ unsigned offset, unsigned length)+{+ unsigned i;+#if defined(MLD_SYS_LITTLE_ENDIAN)+ uint8_t *state_ptr = (uint8_t *)state + offset;+ for (i = 0; i < length; i++)+ __loop__(invariant(i <= length)+ decreases(length - i))+ {+ data[i] = state_ptr[i];+ }+#else /* MLD_SYS_LITTLE_ENDIAN */+ /* Portable version */+ for (i = 0; i < length; i++)+ __loop__(invariant(i <= length)+ decreases(length - i))+ {+ data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF;+ }+#endif /* !MLD_SYS_LITTLE_ENDIAN */+}++MLD_INTERNAL_API+void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data,+ unsigned offset, unsigned length)+{+ unsigned i;+#if defined(MLD_SYS_LITTLE_ENDIAN)+ uint8_t *state_ptr = (uint8_t *)state + offset;+ for (i = 0; i < length; i++)+ __loop__(invariant(i <= length)+ decreases(length - i))+ {+ state_ptr[i] ^= data[i];+ }+#else /* MLD_SYS_LITTLE_ENDIAN */+ /* Portable version */+ for (i = 0; i < length; i++)+ __loop__(invariant(i <= length)+ decreases(length - i))+ {+ state[(offset + i) >> 3] ^= (uint64_t)data[i]+ << (8 * ((offset + i) & 0x07));+ }+#endif /* !MLD_SYS_LITTLE_ENDIAN */+}++#if (!defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_REDUCE_RAM) || \+ defined(MLD_UNIT_TEST)) && \+ !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+static void mld_keccakf1600x4_extract_bytes_c(uint64_t *state,+ unsigned char *data0,+ unsigned char *data1,+ unsigned char *data2,+ unsigned char *data3,+ unsigned offset, unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+ requires(memory_no_alias(data0, length))+ requires(memory_no_alias(data1, length))+ requires(memory_no_alias(data2, length))+ requires(memory_no_alias(data3, length))+ assigns(memory_slice(data0, length))+ assigns(memory_slice(data1, length))+ assigns(memory_slice(data2, length))+ assigns(memory_slice(data3, length))+)+{+ mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset,+ length);+ mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset,+ length);+ mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset,+ length);+ mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset,+ length);+}++MLD_INTERNAL_API+void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0,+ unsigned char *data1, unsigned char *data2,+ unsigned char *data3, unsigned offset,+ unsigned length)+{+#if defined(MLD_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES)+ if (mld_keccakf1600_extract_bytes_x4_native(state, data0, data1, data2, data3,+ offset, length) ==+ MLD_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLD_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES */+ mld_keccakf1600x4_extract_bytes_c(state, data0, data1, data2, data3, offset,+ length);+}++static void mld_keccakf1600x4_xor_bytes_c(uint64_t *state,+ const unsigned char *data0,+ const unsigned char *data1,+ const unsigned char *data2,+ const unsigned char *data3,+ unsigned offset, unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+ requires(memory_no_alias(data0, length))+ /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */+ requires((data0 == data1 &&+ data0 == data2 &&+ data0 == data3) ||+ (memory_no_alias(data1, length) &&+ memory_no_alias(data2, length) &&+ memory_no_alias(data3, length)))+ assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+)+{+ mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset,+ length);+ mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset,+ length);+ mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset,+ length);+ mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset,+ length);+}++MLD_INTERNAL_API+void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0,+ const unsigned char *data1,+ const unsigned char *data2,+ const unsigned char *data3, unsigned offset,+ unsigned length)+{+#if defined(MLD_USE_NATIVE_FIPS202_X4_XOR_BYTES)+ if (mld_keccakf1600_xor_bytes_x4_native(state, data0, data1, data2, data3,+ offset,+ length) == MLD_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLD_USE_NATIVE_FIPS202_X4_XOR_BYTES */+ mld_keccakf1600x4_xor_bytes_c(state, data0, data1, data2, data3, offset,+ length);+}++MLD_INTERNAL_API+void mld_keccakf1600x4_permute(uint64_t *state)+{+#if defined(MLD_USE_NATIVE_FIPS202_X4)+ if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLD_USE_NATIVE_FIPS202_X4 */+ mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0);+ mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1);+ mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2);+ mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3);+}+#endif /* (!MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_REDUCE_RAM || \+ MLD_UNIT_TEST) && !MLD_CONFIG_SERIAL_FIPS202_ONLY */++static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = {+ (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL,+ (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL,+ (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL,+ (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL,+ (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL,+ (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL,+ (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL,+ (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL,+ (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL,+ (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL,+ (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL,+ (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL};++MLD_STATIC_TESTABLE+void mld_keccakf1600_permute_c(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES))+ assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES))+)+{+ unsigned round;++ uint64_t Aba, Abe, Abi, Abo, Abu;+ uint64_t Aga, Age, Agi, Ago, Agu;+ uint64_t Aka, Ake, Aki, Ako, Aku;+ uint64_t Ama, Ame, Ami, Amo, Amu;+ uint64_t Asa, Ase, Asi, Aso, Asu;+ uint64_t BCa, BCe, BCi, BCo, BCu;+ uint64_t Da, De, Di, Do, Du;+ uint64_t Eba, Ebe, Ebi, Ebo, Ebu;+ uint64_t Ega, Ege, Egi, Ego, Egu;+ uint64_t Eka, Eke, Eki, Eko, Eku;+ uint64_t Ema, Eme, Emi, Emo, Emu;+ uint64_t Esa, Ese, Esi, Eso, Esu;++ /* copyFromState(A, state) */+ Aba = state[0];+ Abe = state[1];+ Abi = state[2];+ Abo = state[3];+ Abu = state[4];+ Aga = state[5];+ Age = state[6];+ Agi = state[7];+ Ago = state[8];+ Agu = state[9];+ Aka = state[10];+ Ake = state[11];+ Aki = state[12];+ Ako = state[13];+ Aku = state[14];+ Ama = state[15];+ Ame = state[16];+ Ami = state[17];+ Amo = state[18];+ Amu = state[19];+ Asa = state[20];+ Ase = state[21];+ Asi = state[22];+ Aso = state[23];+ Asu = state[24];++ for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2)+ __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)+ decreases(MLD_KECCAK_NROUNDS - round))+ {+ /* prepareTheta */+ BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa;+ BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase;+ BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi;+ BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso;+ BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu;++ /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */+ Da = BCu ^ MLD_KECCAK_ROL(BCe, 1);+ De = BCa ^ MLD_KECCAK_ROL(BCi, 1);+ Di = BCe ^ MLD_KECCAK_ROL(BCo, 1);+ Do = BCi ^ MLD_KECCAK_ROL(BCu, 1);+ Du = BCo ^ MLD_KECCAK_ROL(BCa, 1);++ Aba ^= Da;+ BCa = Aba;+ Age ^= De;+ BCe = MLD_KECCAK_ROL(Age, 44);+ Aki ^= Di;+ BCi = MLD_KECCAK_ROL(Aki, 43);+ Amo ^= Do;+ BCo = MLD_KECCAK_ROL(Amo, 21);+ Asu ^= Du;+ BCu = MLD_KECCAK_ROL(Asu, 14);+ Eba = BCa ^ ((~BCe) & BCi);+ Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round];+ Ebe = BCe ^ ((~BCi) & BCo);+ Ebi = BCi ^ ((~BCo) & BCu);+ Ebo = BCo ^ ((~BCu) & BCa);+ Ebu = BCu ^ ((~BCa) & BCe);++ Abo ^= Do;+ BCa = MLD_KECCAK_ROL(Abo, 28);+ Agu ^= Du;+ BCe = MLD_KECCAK_ROL(Agu, 20);+ Aka ^= Da;+ BCi = MLD_KECCAK_ROL(Aka, 3);+ Ame ^= De;+ BCo = MLD_KECCAK_ROL(Ame, 45);+ Asi ^= Di;+ BCu = MLD_KECCAK_ROL(Asi, 61);+ Ega = BCa ^ ((~BCe) & BCi);+ Ege = BCe ^ ((~BCi) & BCo);+ Egi = BCi ^ ((~BCo) & BCu);+ Ego = BCo ^ ((~BCu) & BCa);+ Egu = BCu ^ ((~BCa) & BCe);++ Abe ^= De;+ BCa = MLD_KECCAK_ROL(Abe, 1);+ Agi ^= Di;+ BCe = MLD_KECCAK_ROL(Agi, 6);+ Ako ^= Do;+ BCi = MLD_KECCAK_ROL(Ako, 25);+ Amu ^= Du;+ BCo = MLD_KECCAK_ROL(Amu, 8);+ Asa ^= Da;+ BCu = MLD_KECCAK_ROL(Asa, 18);+ Eka = BCa ^ ((~BCe) & BCi);+ Eke = BCe ^ ((~BCi) & BCo);+ Eki = BCi ^ ((~BCo) & BCu);+ Eko = BCo ^ ((~BCu) & BCa);+ Eku = BCu ^ ((~BCa) & BCe);++ Abu ^= Du;+ BCa = MLD_KECCAK_ROL(Abu, 27);+ Aga ^= Da;+ BCe = MLD_KECCAK_ROL(Aga, 36);+ Ake ^= De;+ BCi = MLD_KECCAK_ROL(Ake, 10);+ Ami ^= Di;+ BCo = MLD_KECCAK_ROL(Ami, 15);+ Aso ^= Do;+ BCu = MLD_KECCAK_ROL(Aso, 56);+ Ema = BCa ^ ((~BCe) & BCi);+ Eme = BCe ^ ((~BCi) & BCo);+ Emi = BCi ^ ((~BCo) & BCu);+ Emo = BCo ^ ((~BCu) & BCa);+ Emu = BCu ^ ((~BCa) & BCe);++ Abi ^= Di;+ BCa = MLD_KECCAK_ROL(Abi, 62);+ Ago ^= Do;+ BCe = MLD_KECCAK_ROL(Ago, 55);+ Aku ^= Du;+ BCi = MLD_KECCAK_ROL(Aku, 39);+ Ama ^= Da;+ BCo = MLD_KECCAK_ROL(Ama, 41);+ Ase ^= De;+ BCu = MLD_KECCAK_ROL(Ase, 2);+ Esa = BCa ^ ((~BCe) & BCi);+ Ese = BCe ^ ((~BCi) & BCo);+ Esi = BCi ^ ((~BCo) & BCu);+ Eso = BCo ^ ((~BCu) & BCa);+ Esu = BCu ^ ((~BCa) & BCe);++ /* prepareTheta */+ BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa;+ BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese;+ BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi;+ BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso;+ BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu;++ /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */+ Da = BCu ^ MLD_KECCAK_ROL(BCe, 1);+ De = BCa ^ MLD_KECCAK_ROL(BCi, 1);+ Di = BCe ^ MLD_KECCAK_ROL(BCo, 1);+ Do = BCi ^ MLD_KECCAK_ROL(BCu, 1);+ Du = BCo ^ MLD_KECCAK_ROL(BCa, 1);++ Eba ^= Da;+ BCa = Eba;+ Ege ^= De;+ BCe = MLD_KECCAK_ROL(Ege, 44);+ Eki ^= Di;+ BCi = MLD_KECCAK_ROL(Eki, 43);+ Emo ^= Do;+ BCo = MLD_KECCAK_ROL(Emo, 21);+ Esu ^= Du;+ BCu = MLD_KECCAK_ROL(Esu, 14);+ Aba = BCa ^ ((~BCe) & BCi);+ Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1];+ Abe = BCe ^ ((~BCi) & BCo);+ Abi = BCi ^ ((~BCo) & BCu);+ Abo = BCo ^ ((~BCu) & BCa);+ Abu = BCu ^ ((~BCa) & BCe);++ Ebo ^= Do;+ BCa = MLD_KECCAK_ROL(Ebo, 28);+ Egu ^= Du;+ BCe = MLD_KECCAK_ROL(Egu, 20);+ Eka ^= Da;+ BCi = MLD_KECCAK_ROL(Eka, 3);+ Eme ^= De;+ BCo = MLD_KECCAK_ROL(Eme, 45);+ Esi ^= Di;+ BCu = MLD_KECCAK_ROL(Esi, 61);+ Aga = BCa ^ ((~BCe) & BCi);+ Age = BCe ^ ((~BCi) & BCo);+ Agi = BCi ^ ((~BCo) & BCu);+ Ago = BCo ^ ((~BCu) & BCa);+ Agu = BCu ^ ((~BCa) & BCe);++ Ebe ^= De;+ BCa = MLD_KECCAK_ROL(Ebe, 1);+ Egi ^= Di;+ BCe = MLD_KECCAK_ROL(Egi, 6);+ Eko ^= Do;+ BCi = MLD_KECCAK_ROL(Eko, 25);+ Emu ^= Du;+ BCo = MLD_KECCAK_ROL(Emu, 8);+ Esa ^= Da;+ BCu = MLD_KECCAK_ROL(Esa, 18);+ Aka = BCa ^ ((~BCe) & BCi);+ Ake = BCe ^ ((~BCi) & BCo);+ Aki = BCi ^ ((~BCo) & BCu);+ Ako = BCo ^ ((~BCu) & BCa);+ Aku = BCu ^ ((~BCa) & BCe);++ Ebu ^= Du;+ BCa = MLD_KECCAK_ROL(Ebu, 27);+ Ega ^= Da;+ BCe = MLD_KECCAK_ROL(Ega, 36);+ Eke ^= De;+ BCi = MLD_KECCAK_ROL(Eke, 10);+ Emi ^= Di;+ BCo = MLD_KECCAK_ROL(Emi, 15);+ Eso ^= Do;+ BCu = MLD_KECCAK_ROL(Eso, 56);+ Ama = BCa ^ ((~BCe) & BCi);+ Ame = BCe ^ ((~BCi) & BCo);+ Ami = BCi ^ ((~BCo) & BCu);+ Amo = BCo ^ ((~BCu) & BCa);+ Amu = BCu ^ ((~BCa) & BCe);++ Ebi ^= Di;+ BCa = MLD_KECCAK_ROL(Ebi, 62);+ Ego ^= Do;+ BCe = MLD_KECCAK_ROL(Ego, 55);+ Eku ^= Du;+ BCi = MLD_KECCAK_ROL(Eku, 39);+ Ema ^= Da;+ BCo = MLD_KECCAK_ROL(Ema, 41);+ Ese ^= De;+ BCu = MLD_KECCAK_ROL(Ese, 2);+ Asa = BCa ^ ((~BCe) & BCi);+ Ase = BCe ^ ((~BCi) & BCo);+ Asi = BCi ^ ((~BCo) & BCu);+ Aso = BCo ^ ((~BCu) & BCa);+ Asu = BCu ^ ((~BCa) & BCe);+ }++ /* copyToState(state, A) */+ state[0] = Aba;+ state[1] = Abe;+ state[2] = Abi;+ state[3] = Abo;+ state[4] = Abu;+ state[5] = Aga;+ state[6] = Age;+ state[7] = Agi;+ state[8] = Ago;+ state[9] = Agu;+ state[10] = Aka;+ state[11] = Ake;+ state[12] = Aki;+ state[13] = Ako;+ state[14] = Aku;+ state[15] = Ama;+ state[16] = Ame;+ state[17] = Ami;+ state[18] = Amo;+ state[19] = Amu;+ state[20] = Asa;+ state[21] = Ase;+ state[22] = Asi;+ state[23] = Aso;+ state[24] = Asu;+}++MLD_INTERNAL_API+void mld_keccakf1600_permute(uint64_t *state)+{+#if defined(MLD_USE_NATIVE_FIPS202_X1)+ if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLD_USE_NATIVE_FIPS202_X1 */+ mld_keccakf1600_permute_c(state);+}++#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */++MLD_EMPTY_CU(keccakf1600)++#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef MLD_KECCAK_NROUNDS+#undef MLD_KECCAK_ROL
@@ -0,0 +1,110 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_FIPS202_KECCAKF1600_H+#define MLD_FIPS202_KECCAKF1600_H+#include "../cbmc.h"+#include "../common.h"+#include "fips202.h"++#define MLD_KECCAK_LANES 25+#define MLD_KECCAK_WAY 4++/*+ * WARNING:+ * The contents of this structure, including the placement+ * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED.+ * The struct is only exposed here to allow its construction on the stack.+ */++#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes)+MLD_INTERNAL_API+void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data,+ unsigned offset, unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES))+ requires(memory_no_alias(data, length))+ assigns(memory_slice(data, length))+);++#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes)+MLD_INTERNAL_API+void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data,+ unsigned offset, unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES))+ requires(memory_no_alias(data, length))+ assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES))+);++#if (!defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_REDUCE_RAM) || \+ defined(MLD_UNIT_TEST)) && \+ !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+#define mld_keccakf1600x4_extract_bytes \+ MLD_NAMESPACE(keccakf1600x4_extract_bytes)+MLD_INTERNAL_API+void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0,+ unsigned char *data1, unsigned char *data2,+ unsigned char *data3, unsigned offset,+ unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+ requires(memory_no_alias(data0, length))+ requires(memory_no_alias(data1, length))+ requires(memory_no_alias(data2, length))+ requires(memory_no_alias(data3, length))+ assigns(memory_slice(data0, length))+ assigns(memory_slice(data1, length))+ assigns(memory_slice(data2, length))+ assigns(memory_slice(data3, length))+);++#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes)+MLD_INTERNAL_API+void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0,+ const unsigned char *data1,+ const unsigned char *data2,+ const unsigned char *data3, unsigned offset,+ unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+ requires(memory_no_alias(data0, length))+ /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */+ requires((data0 == data1 &&+ data0 == data2 &&+ data0 == data3) ||+ (memory_no_alias(data1, length) &&+ memory_no_alias(data2, length) &&+ memory_no_alias(data3, length)))+ assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+);++#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute)+MLD_INTERNAL_API+void mld_keccakf1600x4_permute(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+ assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))+);+#endif /* (!MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_REDUCE_RAM || \+ MLD_UNIT_TEST) && !MLD_CONFIG_SERIAL_FIPS202_ONLY */++#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute)+MLD_INTERNAL_API+void mld_keccakf1600_permute(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES))+ assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES))+);++#endif /* !MLD_FIPS202_KECCAKF1600_H */
@@ -0,0 +1,85 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [HYBRID]+ * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64+ * Becker, Kannwischer+ * https://eprint.iacr.org/2022/1243+ */++#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H+#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H+/* Default FIPS202 assembly profile for AArch64 systems */++/*+ * Default logic to decide which implementation to use.+ *+ */++/*+ * Keccak-f1600+ *+ * - On Arm-based Apple CPUs, or CPUs with MLD_SYS_AARCH64_FAST_SHA3 set,+ * we pick a pure Neon implementation.+ * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set,+ * we use lazy-rotation scalar assembly from @[HYBRID].+ * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we+ * fall back to the standard C implementation.+ */+#if defined(__ARM_FEATURE_SHA3) && \+ (defined(__APPLE__) || defined(MLD_SYS_AARCH64_FAST_SHA3))+#include "x1_v84a.h"+#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER)+#include "x1_scalar.h"+#endif++#if (!defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_REDUCE_RAM)) && \+ !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+/* Batched, SIMD-based Keccak-f1600 implementations. */+#if defined(MLD_SYS_AARCH64_NEON)++/*+ * Keccak-f1600x2/x4+ *+ * The optimal implementation is highly CPU-specific; see @[HYBRID].+ *+ * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600.+ * If v8.4-A is implemented and we are on an Apple CPU (or a CPU with+ * MLD_SYS_AARCH64_FAST_SHA3 set), we use a plain Neon-based implementation.+ * If v8.4-A is implemented and we are on neither, we use a+ * scalar/Neon/Neon hybrid.+ * The reason for this distinction is that Apple CPUs (and other CPUs flagged+ * via MLD_SYS_AARCH64_FAST_SHA3) appear to implement the SHA3 instructions on+ * all SIMD units, while Arm CPUs prior to Cortex-X4 don't, and ordinary Neon+ * instructions are still needed.+ */+#if defined(__ARM_FEATURE_SHA3)+/*+ * For Apple-M cores (and other cores flagged via MLD_SYS_AARCH64_FAST_SHA3),+ * we use a plain implementation leveraging SHA3 instructions only.+ */+#if defined(__APPLE__) || defined(MLD_SYS_AARCH64_FAST_SHA3)+#include "x2_v84a.h"+#else+#include "x4_v8a_v84a_scalar.h"+#endif++#else /* __ARM_FEATURE_SHA3 */++#include "x4_v8a_scalar.h"++#endif /* !__ARM_FEATURE_SHA3 */++#endif /* MLD_SYS_AARCH64_NEON */++#endif /* (!MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_SIGN_API || \+ !MLD_CONFIG_REDUCE_RAM) && !MLD_CONFIG_SERIAL_FIPS202_ONLY */++#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */
@@ -0,0 +1,69 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H+#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H+++#include "../../../../cbmc.h"+#include "../../../../common.h"+++#define mld_keccakf1600_round_constants \+ MLD_NAMESPACE(keccakf1600_round_constants)+MLD_INTERNAL_DATA_DECLARATION const uint64_t+ mld_keccakf1600_round_constants[24];++#define mld_keccak_f1600_x1_scalar_aarch64_asm \+ MLD_NAMESPACE(keccak_f1600_x1_scalar_aarch64_asm)+void mld_keccak_f1600_x1_scalar_aarch64_asm(uint64_t state[25],+ const uint64_t rc[24])+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1))+ requires(rc == mld_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1))+);++#define mld_keccak_f1600_x1_v84a_aarch64_asm \+ MLD_NAMESPACE(keccak_f1600_x1_v84a_aarch64_asm)+void mld_keccak_f1600_x1_v84a_aarch64_asm(uint64_t state[25],+ const uint64_t rc[24])+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1))+ requires(rc == mld_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1))+);++#define mld_keccak_f1600_x2_v84a_aarch64_asm \+ MLD_NAMESPACE(keccak_f1600_x2_v84a_aarch64_asm)+void mld_keccak_f1600_x2_v84a_aarch64_asm(uint64_t state[50],+ const uint64_t rc[24])+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2))+ requires(rc == mld_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2))+);++#define mld_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm \+ MLD_NAMESPACE(keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm)+void mld_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm(uint64_t state[100],+ const uint64_t rc[24])+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ requires(rc == mld_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4))+);++#define mld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm \+ MLD_NAMESPACE(keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm)+void mld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm(+ uint64_t state[100], const uint64_t rc[24])+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ requires(rc == mld_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4))+);++#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */
@@ -0,0 +1,378 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++// Author: Hanno Becker <hanno.becker@arm.com>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>++/*yaml+ Name: keccak_f1600_x1_scalar_aarch64_asm+ Description: AArch64 scalar implementation of Keccak-f[1600] permutation for single state+ Signature: void mld_keccak_f1600_x1_scalar_aarch64_asm(uint64_t state[25], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ x0:+ type: buffer+ size_bytes: 200+ permissions: read/write+ c_parameter: uint64_t state[25]+ description: Keccak state (25 x uint64_t)+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: uint64_t const *rc+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 128+ description: register preservation and temporary storage+*/++#include "../../../../common.h"+#if defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x1_scalar_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(keccak_f1600_x1_scalar_aarch64_asm)+MLD_ASM_FN_SYMBOL(keccak_f1600_x1_scalar_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x80+ .cfi_adjust_cfa_offset 0x80+ stp x19, x20, [sp, #0x20]+ .cfi_rel_offset x19, 0x20+ .cfi_rel_offset x20, 0x28+ stp x21, x22, [sp, #0x30]+ .cfi_rel_offset x21, 0x30+ .cfi_rel_offset x22, 0x38+ stp x23, x24, [sp, #0x40]+ .cfi_rel_offset x23, 0x40+ .cfi_rel_offset x24, 0x48+ stp x25, x26, [sp, #0x50]+ .cfi_rel_offset x25, 0x50+ .cfi_rel_offset x26, 0x58+ stp x27, x28, [sp, #0x60]+ .cfi_rel_offset x27, 0x60+ .cfi_rel_offset x28, 0x68+ stp x29, x30, [sp, #0x70]+ .cfi_rel_offset x29, 0x70+ .cfi_rel_offset x30, 0x78++Lmld_keccak_f1600_x1_scalar_initial:+ mov x26, x1+ str x1, [sp, #0x8]+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ str x0, [sp]+ eor x30, x24, x25+ eor x27, x9, x10+ eor x0, x30, x21+ eor x26, x27, x6+ eor x27, x26, x7+ eor x29, x0, x22+ eor x26, x29, x23+ eor x29, x4, x5+ eor x30, x29, x1+ eor x0, x27, x8+ eor x29, x30, x2+ eor x30, x19, x20+ eor x30, x30, x16+ eor x27, x26, x0, ror #63+ eor x4, x4, x27+ eor x30, x30, x17+ eor x30, x30, x28+ eor x29, x29, x3+ eor x0, x0, x30, ror #63+ eor x30, x30, x29, ror #63+ eor x22, x22, x30+ eor x23, x23, x30+ str x23, [sp, #0x18]+ eor x23, x14, x15+ eor x14, x14, x0+ eor x23, x23, x11+ eor x15, x15, x0+ eor x1, x1, x27+ eor x23, x23, x12+ eor x23, x23, x13+ eor x11, x11, x0+ eor x29, x29, x23, ror #63+ eor x23, x23, x26, ror #63+ eor x26, x13, x0+ eor x13, x28, x23+ eor x28, x24, x30+ eor x24, x16, x23+ eor x16, x21, x30+ eor x21, x25, x30+ eor x30, x19, x23+ eor x19, x20, x23+ eor x20, x17, x23+ eor x17, x12, x0+ eor x0, x2, x27+ eor x2, x6, x29+ eor x6, x8, x29+ bic x8, x28, x13, ror #47+ eor x12, x3, x27+ bic x3, x13, x17, ror #19+ eor x5, x5, x27+ ldr x27, [sp, #0x18]+ bic x25, x17, x2, ror #5+ eor x9, x9, x29+ eor x23, x25, x5, ror #52+ eor x3, x3, x2, ror #24+ eor x8, x8, x17, ror #2+ eor x17, x10, x29+ bic x25, x12, x22, ror #47+ eor x29, x7, x29+ bic x10, x4, x27, ror #2+ bic x7, x5, x28, ror #10+ eor x10, x10, x20, ror #50+ eor x13, x7, x13, ror #57+ bic x7, x2, x5, ror #47+ eor x2, x25, x24, ror #39+ bic x25, x20, x11, ror #57+ bic x5, x17, x4, ror #25+ eor x25, x25, x17, ror #53+ bic x17, x11, x17, ror #60+ eor x28, x7, x28, ror #57+ bic x7, x9, x12, ror #42+ eor x7, x7, x22, ror #25+ bic x22, x22, x24, ror #56+ bic x24, x24, x15, ror #31+ eor x22, x22, x15, ror #23+ bic x20, x27, x20, ror #48+ bic x15, x15, x9, ror #16+ eor x12, x15, x12, ror #58+ eor x15, x5, x27, ror #27+ eor x5, x20, x11, ror #41+ ldr x11, [sp, #0x8]+ eor x20, x17, x4, ror #21+ eor x17, x24, x9, ror #47+ mov x24, #0x1 // =1+ bic x9, x0, x16, ror #9+ str x24, [sp, #0x10]+ bic x24, x29, x1, ror #44+ bic x27, x1, x21, ror #50+ bic x4, x26, x29, ror #63+ eor x1, x1, x4, ror #21+ ldr x11, [x11]+ bic x4, x21, x30, ror #57+ eor x21, x24, x21, ror #30+ eor x24, x9, x19, ror #44+ bic x9, x14, x6, ror #5+ eor x9, x9, x0, ror #43+ bic x0, x6, x0, ror #38+ eor x1, x1, x11+ eor x11, x4, x26, ror #35+ eor x4, x0, x16, ror #47+ bic x0, x16, x19, ror #35+ eor x16, x27, x30, ror #43+ bic x27, x30, x26, ror #42+ bic x26, x19, x14, ror #41+ eor x19, x0, x14, ror #12+ eor x14, x26, x6, ror #46+ eor x6, x27, x29, ror #41++Lmld_keccak_f1600_x1_scalar_loop:+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ eor x26, x8, x9, ror #57+ eor x27, x0, x14, ror #10+ eor x29, x16, x28, ror #63+ eor x26, x26, x6, ror #51+ eor x30, x23, x22, ror #50+ eor x0, x26, x10, ror #31+ eor x29, x29, x19, ror #37+ eor x27, x27, x12, ror #5+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ eor x26, x30, x21, ror #26+ eor x26, x26, x25, ror #15+ ror x30, x27, #0x3e+ eor x30, x30, x26, ror #57+ ror x26, x26, #0x3a+ eor x16, x30, x16+ eor x28, x30, x28, ror #63+ str x28, [sp, #0x18]+ eor x29, x29, x17, ror #36+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ eor x29, x29, x20, ror #2+ eor x28, x28, x4, ror #54+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ eor x28, x28, x5, ror #25+ ror x0, x0, #0x38+ eor x0, x0, x29, ror #63+ eor x27, x28, x27, ror #61+ eor x13, x0, x13, ror #46+ eor x28, x29, x28, ror #63+ eor x29, x30, x20, ror #2+ eor x20, x26, x3, ror #39+ eor x11, x0, x11, ror #50+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ eor x21, x26, x1+ eor x9, x27, x9, ror #49+ eor x24, x28, x24, ror #28+ eor x1, x30, x17, ror #36+ eor x14, x0, x14, ror #8+ eor x22, x28, x22, ror #44+ eor x8, x27, x8, ror #56+ eor x17, x27, x7, ror #19+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ eor x4, x26, x4, ror #54+ eor x0, x0, x12, ror #3+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ eor x26, x26, x5, ror #25+ eor x2, x7, x16, ror #39+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ eor x7, x7, x22, ror #25+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ eor x30, x27, x6, ror #43+ eor x22, x20, x15, ror #23+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ bic x5, x13, x17, ror #63+ eor x5, x21, x5, ror #21+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ bic x21, x21, x25, ror #50+ bic x20, x27, x4, ror #25+ bic x10, x16, x15, ror #31+ eor x16, x21, x19, ror #43+ eor x21, x17, x25, ror #30+ bic x19, x25, x19, ror #57+ ldr x25, [sp, #0x10]+ eor x17, x10, x9, ror #47+ ldr x9, [sp, #0x8]+ eor x15, x20, x28, ror #27+ bic x20, x4, x28, ror #2+ eor x10, x20, x1, ror #50+ bic x20, x11, x27, ror #60+ eor x20, x20, x4, ror #21+ bic x4, x28, x1, ror #48+ bic x1, x1, x11, ror #57+ ldr x28, [x9, x25, lsl #3]+ ldr x9, [sp, #0x18]+ add x25, x25, #0x1+ str x25, [sp, #0x10]+ cmp x25, #0x17+ eor x25, x1, x27, ror #53+ bic x27, x30, x26, ror #47+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ eor x11, x19, x13, ror #35+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ bic x27, x24, x9, ror #47+ bic x19, x23, x3, ror #9+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ bic x29, x3, x29, ror #35+ eor x13, x13, x9, ror #57+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ bic x14, x14, x8, ror #5+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ b.le Lmld_keccak_f1600_x1_scalar_loop+ ror x6, x6, #0x2b+ ror x11, x11, #0x32+ ror x21, x21, #0x14+ ror x2, x2, #0x3d+ ror x7, x7, #0x13+ ror x12, x12, #0x3+ ror x17, x17, #0x24+ ror x22, x22, #0x2c+ ror x3, x3, #0x27+ ror x8, x8, #0x38+ ror x13, x13, #0x2e+ ror x28, x28, #0x3f+ ror x23, x23, #0x3a+ ror x4, x4, #0x36+ ror x9, x9, #0x31+ ror x14, x14, #0x8+ ror x19, x19, #0x25+ ror x24, x24, #0x1c+ ror x5, x5, #0x19+ ror x10, x10, #0x17+ ror x15, x15, #0x3e+ ror x20, x20, #0x2+ ror x25, x25, #0x9+ ldr x0, [sp]+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ ldp x19, x20, [sp, #0x20]+ .cfi_restore x19+ .cfi_restore x20+ ldp x21, x22, [sp, #0x30]+ .cfi_restore x21+ .cfi_restore x22+ ldp x23, x24, [sp, #0x40]+ .cfi_restore x23+ .cfi_restore x24+ ldp x25, x26, [sp, #0x50]+ .cfi_restore x25+ .cfi_restore x26+ ldp x27, x28, [sp, #0x60]+ .cfi_restore x27+ .cfi_restore x28+ ldp x29, x30, [sp, #0x70]+ .cfi_restore x29+ .cfi_restore x30+ add sp, sp, #0x80+ .cfi_adjust_cfa_offset -0x80+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(keccak_f1600_x1_scalar_aarch64_asm)++#endif /* MLD_FIPS202_AARCH64_NEED_X1_SCALAR && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,207 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [HYBRID]+ * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64+ * Becker, Kannwischer+ * https://eprint.iacr.org/2022/1243+ */++/*yaml+ Name: keccak_f1600_x1_v84a_aarch64_asm+ Description: AArch64 ARMv8.4-A implementation of Keccak-f[1600] permutation for single state+ Signature: void mld_keccak_f1600_x1_v84a_aarch64_asm(uint64_t state[25], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON, SHA3]+ x0:+ type: buffer+ size_bytes: 200+ permissions: read/write+ c_parameter: uint64_t state[25]+ description: Keccak state (25 x uint64_t)+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: uint64_t const *rc+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 64+ description: register preservation+*/++//+// Author: Hanno Becker <hanno.becker@arm.com>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>+//+// This implementation is essentially from the paper @[HYBRID].+// The only difference is interleaving/deinterleaving of Keccak state+// during load and store, so that the caller need not do this.+//++#include "../../../../common.h"+#if defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#if defined(__ARM_FEATURE_SHA3)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x1_v84a_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(keccak_f1600_x1_v84a_aarch64_asm)+MLD_ASM_FN_SYMBOL(keccak_f1600_x1_v84a_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ ldp d0, d1, [x0]+ ldp d2, d3, [x0, #0x10]+ ldp d4, d5, [x0, #0x20]+ ldp d6, d7, [x0, #0x30]+ ldp d8, d9, [x0, #0x40]+ ldp d10, d11, [x0, #0x50]+ ldp d12, d13, [x0, #0x60]+ ldp d14, d15, [x0, #0x70]+ ldp d16, d17, [x0, #0x80]+ ldp d18, d19, [x0, #0x90]+ ldp d20, d21, [x0, #0xa0]+ ldp d22, d23, [x0, #0xb0]+ ldr d24, [x0, #0xc0]+ mov x2, #0x18 // =24++Lmld_keccak_f1600_x1_v84a_loop:+ eor3 v30.16b, v0.16b, v5.16b, v10.16b+ eor3 v29.16b, v1.16b, v6.16b, v11.16b+ eor3 v28.16b, v2.16b, v7.16b, v12.16b+ eor3 v27.16b, v3.16b, v8.16b, v13.16b+ eor3 v26.16b, v4.16b, v9.16b, v14.16b+ eor3 v30.16b, v30.16b, v15.16b, v20.16b+ eor3 v29.16b, v29.16b, v16.16b, v21.16b+ eor3 v28.16b, v28.16b, v17.16b, v22.16b+ eor3 v27.16b, v27.16b, v18.16b, v23.16b+ eor3 v26.16b, v26.16b, v19.16b, v24.16b+ rax1 v25.2d, v30.2d, v28.2d+ rax1 v28.2d, v28.2d, v26.2d+ rax1 v26.2d, v26.2d, v29.2d+ rax1 v29.2d, v29.2d, v27.2d+ rax1 v27.2d, v27.2d, v30.2d+ eor v30.16b, v0.16b, v26.16b+ xar v0.2d, v2.2d, v29.2d, #0x2+ xar v2.2d, v12.2d, v29.2d, #0x15+ xar v12.2d, v13.2d, v28.2d, #0x27+ xar v13.2d, v19.2d, v27.2d, #0x38+ xar v19.2d, v23.2d, v28.2d, #0x8+ xar v23.2d, v15.2d, v26.2d, #0x17+ xar v15.2d, v1.2d, v25.2d, #0x3f+ xar v1.2d, v8.2d, v28.2d, #0x9+ xar v8.2d, v16.2d, v25.2d, #0x13+ xar v16.2d, v7.2d, v29.2d, #0x3a+ xar v7.2d, v10.2d, v26.2d, #0x3d+ xar v10.2d, v3.2d, v28.2d, #0x24+ xar v3.2d, v18.2d, v28.2d, #0x2b+ xar v18.2d, v17.2d, v29.2d, #0x31+ xar v17.2d, v11.2d, v25.2d, #0x36+ xar v11.2d, v9.2d, v27.2d, #0x2c+ xar v9.2d, v22.2d, v29.2d, #0x3+ xar v22.2d, v14.2d, v27.2d, #0x19+ xar v14.2d, v20.2d, v26.2d, #0x2e+ xar v20.2d, v4.2d, v27.2d, #0x25+ xar v4.2d, v24.2d, v27.2d, #0x32+ xar v24.2d, v21.2d, v25.2d, #0x3e+ xar v21.2d, v5.2d, v26.2d, #0x1c+ xar v27.2d, v6.2d, v25.2d, #0x14+ ld1r { v31.2d }, [x1], #8+ bcax v5.16b, v10.16b, v7.16b, v11.16b+ bcax v6.16b, v11.16b, v8.16b, v7.16b+ bcax v7.16b, v7.16b, v9.16b, v8.16b+ bcax v8.16b, v8.16b, v10.16b, v9.16b+ bcax v9.16b, v9.16b, v11.16b, v10.16b+ bcax v10.16b, v15.16b, v12.16b, v16.16b+ bcax v11.16b, v16.16b, v13.16b, v12.16b+ bcax v12.16b, v12.16b, v14.16b, v13.16b+ bcax v13.16b, v13.16b, v15.16b, v14.16b+ bcax v14.16b, v14.16b, v16.16b, v15.16b+ bcax v15.16b, v20.16b, v17.16b, v21.16b+ bcax v16.16b, v21.16b, v18.16b, v17.16b+ bcax v17.16b, v17.16b, v19.16b, v18.16b+ bcax v18.16b, v18.16b, v20.16b, v19.16b+ bcax v19.16b, v19.16b, v21.16b, v20.16b+ bcax v20.16b, v0.16b, v22.16b, v1.16b+ bcax v21.16b, v1.16b, v23.16b, v22.16b+ bcax v22.16b, v22.16b, v24.16b, v23.16b+ bcax v23.16b, v23.16b, v0.16b, v24.16b+ bcax v24.16b, v24.16b, v1.16b, v0.16b+ bcax v0.16b, v30.16b, v2.16b, v27.16b+ bcax v1.16b, v27.16b, v3.16b, v2.16b+ bcax v2.16b, v2.16b, v4.16b, v3.16b+ bcax v3.16b, v3.16b, v30.16b, v4.16b+ bcax v4.16b, v4.16b, v27.16b, v30.16b+ eor v0.16b, v0.16b, v31.16b+ sub x2, x2, #0x1+ cbnz x2, Lmld_keccak_f1600_x1_v84a_loop+ stp d0, d1, [x0]+ stp d2, d3, [x0, #0x10]+ stp d4, d5, [x0, #0x20]+ stp d6, d7, [x0, #0x30]+ stp d8, d9, [x0, #0x40]+ stp d10, d11, [x0, #0x50]+ stp d12, d13, [x0, #0x60]+ stp d14, d15, [x0, #0x70]+ stp d16, d17, [x0, #0x80]+ stp d18, d19, [x0, #0x90]+ stp d20, d21, [x0, #0xa0]+ stp d22, d23, [x0, #0xb0]+ str d24, [x0, #0xc0]+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(keccak_f1600_x1_v84a_aarch64_asm)++#endif /* __ARM_FEATURE_SHA3 */++#endif /* MLD_FIPS202_AARCH64_NEED_X1_V84A && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,262 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [HYBRID]+ * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64+ * Becker, Kannwischer+ * https://eprint.iacr.org/2022/1243+ */++/*yaml+ Name: keccak_f1600_x2_v84a_aarch64_asm+ Description: AArch64 ARMv8.4-A implementation of Keccak-f[1600] permutation for two sequential states+ Signature: void mld_keccak_f1600_x2_v84a_aarch64_asm(uint64_t state[50], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON, SHA3]+ x0:+ type: buffer+ size_bytes: 400+ permissions: read/write+ c_parameter: uint64_t state[50]+ description: Two sequential Keccak states (state0[25], state1[25])+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: uint64_t const *rc+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 64+ description: register preservation+*/++//+// Author: Hanno Becker <hanno.becker@arm.com>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>+//+// This implementation is essentially from the paper @[HYBRID].+// The only difference is interleaving/deinterleaving of Keccak state+// during load and store, so that the caller need not do this.+//++#include "../../../../common.h"+#if defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#if defined(__ARM_FEATURE_SHA3)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x2_v84a_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(keccak_f1600_x2_v84a_aarch64_asm)+MLD_ASM_FN_SYMBOL(keccak_f1600_x2_v84a_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ add x2, x0, #0xc8+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v0.2d, v25.2d, v27.2d+ trn2 v1.2d, v25.2d, v27.2d+ trn1 v2.2d, v26.2d, v28.2d+ trn2 v3.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v4.2d, v25.2d, v27.2d+ trn2 v5.2d, v25.2d, v27.2d+ trn1 v6.2d, v26.2d, v28.2d+ trn2 v7.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v8.2d, v25.2d, v27.2d+ trn2 v9.2d, v25.2d, v27.2d+ trn1 v10.2d, v26.2d, v28.2d+ trn2 v11.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v12.2d, v25.2d, v27.2d+ trn2 v13.2d, v25.2d, v27.2d+ trn1 v14.2d, v26.2d, v28.2d+ trn2 v15.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v16.2d, v25.2d, v27.2d+ trn2 v17.2d, v25.2d, v27.2d+ trn1 v18.2d, v26.2d, v28.2d+ trn2 v19.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v20.2d, v25.2d, v27.2d+ trn2 v21.2d, v25.2d, v27.2d+ trn1 v22.2d, v26.2d, v28.2d+ trn2 v23.2d, v26.2d, v28.2d+ ldr d25, [x0]+ ldr d27, [x2]+ trn1 v24.2d, v25.2d, v27.2d+ mov x2, #0x18 // =24++Lmld_keccak_f1600_x2_v84a_loop:+ eor3 v30.16b, v0.16b, v5.16b, v10.16b+ eor3 v29.16b, v1.16b, v6.16b, v11.16b+ eor3 v28.16b, v2.16b, v7.16b, v12.16b+ eor3 v27.16b, v3.16b, v8.16b, v13.16b+ eor3 v26.16b, v4.16b, v9.16b, v14.16b+ eor3 v30.16b, v30.16b, v15.16b, v20.16b+ eor3 v29.16b, v29.16b, v16.16b, v21.16b+ eor3 v28.16b, v28.16b, v17.16b, v22.16b+ eor3 v27.16b, v27.16b, v18.16b, v23.16b+ eor3 v26.16b, v26.16b, v19.16b, v24.16b+ rax1 v25.2d, v30.2d, v28.2d+ rax1 v28.2d, v28.2d, v26.2d+ rax1 v26.2d, v26.2d, v29.2d+ rax1 v29.2d, v29.2d, v27.2d+ rax1 v27.2d, v27.2d, v30.2d+ eor v30.16b, v0.16b, v26.16b+ xar v0.2d, v2.2d, v29.2d, #0x2+ xar v2.2d, v12.2d, v29.2d, #0x15+ xar v12.2d, v13.2d, v28.2d, #0x27+ xar v13.2d, v19.2d, v27.2d, #0x38+ xar v19.2d, v23.2d, v28.2d, #0x8+ xar v23.2d, v15.2d, v26.2d, #0x17+ xar v15.2d, v1.2d, v25.2d, #0x3f+ xar v1.2d, v8.2d, v28.2d, #0x9+ xar v8.2d, v16.2d, v25.2d, #0x13+ xar v16.2d, v7.2d, v29.2d, #0x3a+ xar v7.2d, v10.2d, v26.2d, #0x3d+ xar v10.2d, v3.2d, v28.2d, #0x24+ xar v3.2d, v18.2d, v28.2d, #0x2b+ xar v18.2d, v17.2d, v29.2d, #0x31+ xar v17.2d, v11.2d, v25.2d, #0x36+ xar v11.2d, v9.2d, v27.2d, #0x2c+ xar v9.2d, v22.2d, v29.2d, #0x3+ xar v22.2d, v14.2d, v27.2d, #0x19+ xar v14.2d, v20.2d, v26.2d, #0x2e+ xar v20.2d, v4.2d, v27.2d, #0x25+ xar v4.2d, v24.2d, v27.2d, #0x32+ xar v24.2d, v21.2d, v25.2d, #0x3e+ xar v21.2d, v5.2d, v26.2d, #0x1c+ xar v27.2d, v6.2d, v25.2d, #0x14+ ld1r { v31.2d }, [x1], #8+ bcax v5.16b, v10.16b, v7.16b, v11.16b+ bcax v6.16b, v11.16b, v8.16b, v7.16b+ bcax v7.16b, v7.16b, v9.16b, v8.16b+ bcax v8.16b, v8.16b, v10.16b, v9.16b+ bcax v9.16b, v9.16b, v11.16b, v10.16b+ bcax v10.16b, v15.16b, v12.16b, v16.16b+ bcax v11.16b, v16.16b, v13.16b, v12.16b+ bcax v12.16b, v12.16b, v14.16b, v13.16b+ bcax v13.16b, v13.16b, v15.16b, v14.16b+ bcax v14.16b, v14.16b, v16.16b, v15.16b+ bcax v15.16b, v20.16b, v17.16b, v21.16b+ bcax v16.16b, v21.16b, v18.16b, v17.16b+ bcax v17.16b, v17.16b, v19.16b, v18.16b+ bcax v18.16b, v18.16b, v20.16b, v19.16b+ bcax v19.16b, v19.16b, v21.16b, v20.16b+ bcax v20.16b, v0.16b, v22.16b, v1.16b+ bcax v21.16b, v1.16b, v23.16b, v22.16b+ bcax v22.16b, v22.16b, v24.16b, v23.16b+ bcax v23.16b, v23.16b, v0.16b, v24.16b+ bcax v24.16b, v24.16b, v1.16b, v0.16b+ bcax v0.16b, v30.16b, v2.16b, v27.16b+ bcax v1.16b, v27.16b, v3.16b, v2.16b+ bcax v2.16b, v2.16b, v4.16b, v3.16b+ bcax v3.16b, v3.16b, v30.16b, v4.16b+ bcax v4.16b, v4.16b, v27.16b, v30.16b+ eor v0.16b, v0.16b, v31.16b+ sub x2, x2, #0x1+ cbnz x2, Lmld_keccak_f1600_x2_v84a_loop+ sub x0, x0, #0xc0+ add x2, x0, #0xc8+ trn1 v25.2d, v0.2d, v1.2d+ trn1 v26.2d, v2.2d, v3.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v0.2d, v1.2d+ trn2 v28.2d, v2.2d, v3.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v4.2d, v5.2d+ trn1 v26.2d, v6.2d, v7.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v4.2d, v5.2d+ trn2 v28.2d, v6.2d, v7.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v8.2d, v9.2d+ trn1 v26.2d, v10.2d, v11.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v8.2d, v9.2d+ trn2 v28.2d, v10.2d, v11.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v12.2d, v13.2d+ trn1 v26.2d, v14.2d, v15.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v12.2d, v13.2d+ trn2 v28.2d, v14.2d, v15.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v16.2d, v17.2d+ trn1 v26.2d, v18.2d, v19.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v16.2d, v17.2d+ trn2 v28.2d, v18.2d, v19.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v20.2d, v21.2d+ trn1 v26.2d, v22.2d, v23.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v20.2d, v21.2d+ trn2 v28.2d, v22.2d, v23.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ str d24, [x0]+ trn2 v25.2d, v24.2d, v24.2d+ str d25, [x2]+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(keccak_f1600_x2_v84a_aarch64_asm)++#endif /* __ARM_FEATURE_SHA3 */++#endif /* MLD_FIPS202_AARCH64_NEED_X2_V84A && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,1080 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++// Author: Hanno Becker <hannobecker@posteo.de>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>++/*yaml+ Name: keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm+ Description: AArch64 hybrid scalar/vector implementation of Keccak-f[1600] permutation for four sequential states+ Signature: void mld_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm(uint64_t state[100], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 800+ permissions: read/write+ c_parameter: uint64_t state[100]+ description: Four sequential Keccak states (state0[25], state1[25], state2[25], state3[25])+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: uint64_t const *rc+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 224+ description: register preservation and temporary storage+*/++#include "../../../../common.h"+#if defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm)+MLD_ASM_FN_SYMBOL(keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0xe0+ .cfi_adjust_cfa_offset 0xe0+ stp x19, x20, [sp, #0x30]+ .cfi_rel_offset x19, 0x30+ .cfi_rel_offset x20, 0x38+ stp x21, x22, [sp, #0x40]+ .cfi_rel_offset x21, 0x40+ .cfi_rel_offset x22, 0x48+ stp x23, x24, [sp, #0x50]+ .cfi_rel_offset x23, 0x50+ .cfi_rel_offset x24, 0x58+ stp x25, x26, [sp, #0x60]+ .cfi_rel_offset x25, 0x60+ .cfi_rel_offset x26, 0x68+ stp x27, x28, [sp, #0x70]+ .cfi_rel_offset x27, 0x70+ .cfi_rel_offset x28, 0x78+ stp x29, x30, [sp, #0x80]+ .cfi_rel_offset x29, 0x80+ .cfi_rel_offset x30, 0x88+ stp d8, d9, [sp, #0x90]+ .cfi_rel_offset d8, 0x90+ .cfi_rel_offset d9, 0x98+ stp d10, d11, [sp, #0xa0]+ .cfi_rel_offset d10, 0xa0+ .cfi_rel_offset d11, 0xa8+ stp d12, d13, [sp, #0xb0]+ .cfi_rel_offset d12, 0xb0+ .cfi_rel_offset d13, 0xb8+ stp d14, d15, [sp, #0xc0]+ .cfi_rel_offset d14, 0xc0+ .cfi_rel_offset d15, 0xc8+ mov x29, x1+ mov x30, #0x0 // =0+ str x30, [sp, #0x20]+ str x29, [sp, #0x8]+ str x29, [sp, #0x10]+ str x0, [sp]+ add x4, x0, #0xc8+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v0.2d, v25.2d, v27.2d+ trn2 v1.2d, v25.2d, v27.2d+ trn1 v2.2d, v26.2d, v28.2d+ trn2 v3.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v4.2d, v25.2d, v27.2d+ trn2 v5.2d, v25.2d, v27.2d+ trn1 v6.2d, v26.2d, v28.2d+ trn2 v7.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v8.2d, v25.2d, v27.2d+ trn2 v9.2d, v25.2d, v27.2d+ trn1 v10.2d, v26.2d, v28.2d+ trn2 v11.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v12.2d, v25.2d, v27.2d+ trn2 v13.2d, v25.2d, v27.2d+ trn1 v14.2d, v26.2d, v28.2d+ trn2 v15.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v16.2d, v25.2d, v27.2d+ trn2 v17.2d, v25.2d, v27.2d+ trn1 v18.2d, v26.2d, v28.2d+ trn2 v19.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v20.2d, v25.2d, v27.2d+ trn2 v21.2d, v25.2d, v27.2d+ trn1 v22.2d, v26.2d, v28.2d+ trn2 v23.2d, v26.2d, v28.2d+ ldr d25, [x0]+ ldr d27, [x4]+ trn1 v24.2d, v25.2d, v27.2d+ sub x0, x0, #0xc0+ add x0, x0, #0x190+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ sub x0, x0, #0x190++Lmld_keccak_f1600_x4_v8a_scalar_hybrid_initial:+ eor x30, x24, x25+ eor x27, x9, x10+ eor v30.16b, v0.16b, v5.16b+ eor v30.16b, v30.16b, v10.16b+ eor x0, x30, x21+ eor v30.16b, v30.16b, v15.16b+ eor x26, x27, x6+ eor x27, x26, x7+ eor v30.16b, v30.16b, v20.16b+ eor x29, x0, x22+ eor v29.16b, v1.16b, v6.16b+ eor x26, x29, x23+ eor v29.16b, v29.16b, v11.16b+ eor x29, x4, x5+ eor x30, x29, x1+ eor v29.16b, v29.16b, v16.16b+ eor x0, x27, x8+ eor v29.16b, v29.16b, v21.16b+ eor x29, x30, x2+ eor v28.16b, v2.16b, v7.16b+ eor x30, x19, x20+ eor x30, x30, x16+ eor v28.16b, v28.16b, v12.16b+ eor x27, x26, x0, ror #63+ eor v28.16b, v28.16b, v17.16b+ eor x4, x4, x27+ eor v28.16b, v28.16b, v22.16b+ eor x30, x30, x17+ eor x30, x30, x28+ eor v27.16b, v3.16b, v8.16b+ eor x29, x29, x3+ eor v27.16b, v27.16b, v13.16b+ eor x0, x0, x30, ror #63+ eor v27.16b, v27.16b, v18.16b+ eor x30, x30, x29, ror #63+ eor x22, x22, x30+ eor v27.16b, v27.16b, v23.16b+ eor x23, x23, x30+ eor v26.16b, v4.16b, v9.16b+ str x23, [sp, #0xd0]+ eor v26.16b, v26.16b, v14.16b+ eor x23, x14, x15+ eor x14, x14, x0+ eor v26.16b, v26.16b, v19.16b+ eor x23, x23, x11+ eor v26.16b, v26.16b, v24.16b+ eor x15, x15, x0+ eor x1, x1, x27+ add v31.2d, v28.2d, v28.2d+ eor x23, x23, x12+ sri v31.2d, v28.2d, #0x3f+ eor x23, x23, x13+ eor v25.16b, v31.16b, v30.16b+ eor x11, x11, x0+ eor x29, x29, x23, ror #63+ add v31.2d, v26.2d, v26.2d+ eor x23, x23, x26, ror #63+ sri v31.2d, v26.2d, #0x3f+ eor x26, x13, x0+ eor v28.16b, v31.16b, v28.16b+ eor x13, x28, x23+ eor x28, x24, x30+ add v31.2d, v29.2d, v29.2d+ eor x24, x16, x23+ sri v31.2d, v29.2d, #0x3f+ eor x16, x21, x30+ eor v26.16b, v31.16b, v26.16b+ eor x21, x25, x30+ eor x30, x19, x23+ add v31.2d, v27.2d, v27.2d+ eor x19, x20, x23+ sri v31.2d, v27.2d, #0x3f+ eor x20, x17, x23+ eor v29.16b, v31.16b, v29.16b+ eor x17, x12, x0+ eor x0, x2, x27+ add v31.2d, v30.2d, v30.2d+ eor x2, x6, x29+ sri v31.2d, v30.2d, #0x3f+ eor x6, x8, x29+ eor v27.16b, v31.16b, v27.16b+ bic x8, x28, x13, ror #47+ eor x12, x3, x27+ eor v30.16b, v0.16b, v26.16b+ bic x3, x13, x17, ror #19+ eor v31.16b, v2.16b, v29.16b+ eor x5, x5, x27+ ldr x27, [sp, #0xd0]+ shl v0.2d, v31.2d, #0x3e+ bic x25, x17, x2, ror #5+ sri v0.2d, v31.2d, #0x2+ eor x9, x9, x29+ eor v31.16b, v12.16b, v29.16b+ eor x23, x25, x5, ror #52+ eor x3, x3, x2, ror #24+ shl v2.2d, v31.2d, #0x2b+ eor x8, x8, x17, ror #2+ sri v2.2d, v31.2d, #0x15+ eor x17, x10, x29+ eor v31.16b, v13.16b, v28.16b+ bic x25, x12, x22, ror #47+ eor x29, x7, x29+ shl v12.2d, v31.2d, #0x19+ bic x10, x4, x27, ror #2+ sri v12.2d, v31.2d, #0x27+ bic x7, x5, x28, ror #10+ eor v31.16b, v19.16b, v27.16b+ eor x10, x10, x20, ror #50+ eor x13, x7, x13, ror #57+ shl v13.2d, v31.2d, #0x8+ bic x7, x2, x5, ror #47+ sri v13.2d, v31.2d, #0x38+ eor x2, x25, x24, ror #39+ eor v31.16b, v23.16b, v28.16b+ bic x25, x20, x11, ror #57+ bic x5, x17, x4, ror #25+ shl v19.2d, v31.2d, #0x38+ eor x25, x25, x17, ror #53+ sri v19.2d, v31.2d, #0x8+ bic x17, x11, x17, ror #60+ eor v31.16b, v15.16b, v26.16b+ eor x28, x7, x28, ror #57+ bic x7, x9, x12, ror #42+ shl v23.2d, v31.2d, #0x29+ eor x7, x7, x22, ror #25+ sri v23.2d, v31.2d, #0x17+ bic x22, x22, x24, ror #56+ bic x24, x24, x15, ror #31+ eor v31.16b, v1.16b, v25.16b+ eor x22, x22, x15, ror #23+ shl v15.2d, v31.2d, #0x1+ bic x20, x27, x20, ror #48+ sri v15.2d, v31.2d, #0x3f+ bic x15, x15, x9, ror #16+ eor x12, x15, x12, ror #58+ eor v31.16b, v8.16b, v28.16b+ eor x15, x5, x27, ror #27+ shl v1.2d, v31.2d, #0x37+ eor x5, x20, x11, ror #41+ sri v1.2d, v31.2d, #0x9+ ldr x11, [sp, #0x8]+ eor x20, x17, x4, ror #21+ eor v31.16b, v16.16b, v25.16b+ eor x17, x24, x9, ror #47+ shl v8.2d, v31.2d, #0x2d+ mov x24, #0x1 // =1+ sri v8.2d, v31.2d, #0x13+ bic x9, x0, x16, ror #9+ str x24, [sp, #0x18]+ eor v31.16b, v7.16b, v29.16b+ bic x24, x29, x1, ror #44+ shl v16.2d, v31.2d, #0x6+ bic x27, x1, x21, ror #50+ sri v16.2d, v31.2d, #0x3a+ bic x4, x26, x29, ror #63+ eor x1, x1, x4, ror #21+ eor v31.16b, v10.16b, v26.16b+ ldr x11, [x11]+ shl v7.2d, v31.2d, #0x3+ bic x4, x21, x30, ror #57+ sri v7.2d, v31.2d, #0x3d+ eor x21, x24, x21, ror #30+ eor x24, x9, x19, ror #44+ eor v31.16b, v3.16b, v28.16b+ bic x9, x14, x6, ror #5+ shl v10.2d, v31.2d, #0x1c+ eor x9, x9, x0, ror #43+ sri v10.2d, v31.2d, #0x24+ bic x0, x6, x0, ror #38+ eor x1, x1, x11+ eor v31.16b, v18.16b, v28.16b+ eor x11, x4, x26, ror #35+ shl v3.2d, v31.2d, #0x15+ eor x4, x0, x16, ror #47+ bic x0, x16, x19, ror #35+ sri v3.2d, v31.2d, #0x2b+ eor x16, x27, x30, ror #43+ eor v31.16b, v17.16b, v29.16b+ bic x27, x30, x26, ror #42+ shl v18.2d, v31.2d, #0xf+ bic x26, x19, x14, ror #41+ eor x19, x0, x14, ror #12+ sri v18.2d, v31.2d, #0x31+ eor x14, x26, x6, ror #46+ eor v31.16b, v11.16b, v25.16b+ eor x6, x27, x29, ror #41+ shl v17.2d, v31.2d, #0xa+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ sri v17.2d, v31.2d, #0x36+ eor x26, x8, x9, ror #57+ eor v31.16b, v9.16b, v27.16b+ eor x27, x0, x14, ror #10+ shl v11.2d, v31.2d, #0x14+ eor x29, x16, x28, ror #63+ eor x26, x26, x6, ror #51+ sri v11.2d, v31.2d, #0x2c+ eor x30, x23, x22, ror #50+ eor v31.16b, v22.16b, v29.16b+ eor x0, x26, x10, ror #31+ shl v9.2d, v31.2d, #0x3d+ eor x29, x29, x19, ror #37+ eor x27, x27, x12, ror #5+ sri v9.2d, v31.2d, #0x3+ eor x30, x30, x24, ror #34+ eor v31.16b, v14.16b, v27.16b+ eor x0, x0, x7, ror #27+ shl v22.2d, v31.2d, #0x27+ eor x26, x30, x21, ror #26+ eor x26, x26, x25, ror #15+ sri v22.2d, v31.2d, #0x19+ ror x30, x27, #0x3e+ eor v31.16b, v20.16b, v26.16b+ eor x30, x30, x26, ror #57+ ror x26, x26, #0x3a+ shl v14.2d, v31.2d, #0x12+ eor x16, x30, x16+ sri v14.2d, v31.2d, #0x2e+ eor x28, x30, x28, ror #63+ eor v31.16b, v4.16b, v27.16b+ str x28, [sp, #0xd0]+ eor x29, x29, x17, ror #36+ shl v20.2d, v31.2d, #0x1b+ eor x28, x1, x2, ror #61+ sri v20.2d, v31.2d, #0x25+ eor x19, x30, x19, ror #37+ eor v31.16b, v24.16b, v27.16b+ eor x29, x29, x20, ror #2+ eor x28, x28, x4, ror #54+ shl v4.2d, v31.2d, #0xe+ eor x26, x26, x0, ror #55+ sri v4.2d, v31.2d, #0x32+ eor x28, x28, x3, ror #39+ eor v31.16b, v21.16b, v25.16b+ eor x28, x28, x5, ror #25+ ror x0, x0, #0x38+ shl v24.2d, v31.2d, #0x2+ eor x0, x0, x29, ror #63+ sri v24.2d, v31.2d, #0x3e+ eor x27, x28, x27, ror #61+ eor v31.16b, v5.16b, v26.16b+ eor x13, x0, x13, ror #46+ eor x28, x29, x28, ror #63+ shl v21.2d, v31.2d, #0x24+ eor x29, x30, x20, ror #2+ sri v21.2d, v31.2d, #0x1c+ eor x20, x26, x3, ror #39+ eor v31.16b, v6.16b, v25.16b+ eor x11, x0, x11, ror #50+ eor x25, x28, x25, ror #9+ shl v27.2d, v31.2d, #0x2c+ eor x3, x28, x21, ror #20+ sri v27.2d, v31.2d, #0x14+ eor x21, x26, x1+ eor x9, x27, x9, ror #49+ bic v31.16b, v7.16b, v11.16b+ eor x24, x28, x24, ror #28+ eor v5.16b, v31.16b, v10.16b+ eor x1, x30, x17, ror #36+ bic v31.16b, v8.16b, v7.16b+ eor x14, x0, x14, ror #8+ eor x22, x28, x22, ror #44+ eor v6.16b, v31.16b, v11.16b+ eor x8, x27, x8, ror #56+ bic v31.16b, v9.16b, v8.16b+ eor x17, x27, x7, ror #19+ eor v7.16b, v31.16b, v7.16b+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ bic v31.16b, v10.16b, v9.16b+ eor x4, x26, x4, ror #54+ eor v8.16b, v31.16b, v8.16b+ eor x0, x0, x12, ror #3+ bic v31.16b, v11.16b, v10.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ eor v9.16b, v31.16b, v9.16b+ eor x26, x26, x5, ror #25+ bic v31.16b, v12.16b, v16.16b+ eor x2, x7, x16, ror #39+ eor v10.16b, v31.16b, v15.16b+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ bic v31.16b, v13.16b, v12.16b+ eor x7, x7, x22, ror #25+ eor v11.16b, v31.16b, v16.16b+ eor x12, x30, x20, ror #58+ bic v31.16b, v14.16b, v13.16b+ bic x20, x22, x16, ror #56+ eor x30, x27, x6, ror #43+ eor v12.16b, v31.16b, v12.16b+ eor x22, x20, x15, ror #23+ bic v31.16b, v15.16b, v14.16b+ bic x6, x19, x13, ror #42+ eor v13.16b, v31.16b, v13.16b+ eor x6, x6, x17, ror #41+ bic x5, x13, x17, ror #63+ bic v31.16b, v16.16b, v15.16b+ eor x5, x21, x5, ror #21+ eor v14.16b, v31.16b, v14.16b+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ bic v31.16b, v17.16b, v21.16b+ bic x21, x21, x25, ror #50+ eor v15.16b, v31.16b, v20.16b+ bic x20, x27, x4, ror #25+ bic v31.16b, v18.16b, v17.16b+ bic x10, x16, x15, ror #31+ eor x16, x21, x19, ror #43+ eor v16.16b, v31.16b, v21.16b+ eor x21, x17, x25, ror #30+ bic v31.16b, v19.16b, v18.16b+ bic x19, x25, x19, ror #57+ eor v17.16b, v31.16b, v17.16b+ ldr x25, [sp, #0x18]+ eor x17, x10, x9, ror #47+ bic v31.16b, v20.16b, v19.16b+ ldr x9, [sp, #0x8]+ eor v18.16b, v31.16b, v18.16b+ eor x15, x20, x28, ror #27+ bic v31.16b, v21.16b, v20.16b+ bic x20, x4, x28, ror #2+ eor x10, x20, x1, ror #50+ eor v19.16b, v31.16b, v19.16b+ bic x20, x11, x27, ror #60+ bic v31.16b, v22.16b, v1.16b+ eor x20, x20, x4, ror #21+ eor v20.16b, v31.16b, v0.16b+ bic x4, x28, x1, ror #48+ bic x1, x1, x11, ror #57+ bic v31.16b, v23.16b, v22.16b+ ldr x28, [x9, x25, lsl #3]+ eor v21.16b, v31.16b, v1.16b+ ldr x9, [sp, #0xd0]+ bic v31.16b, v24.16b, v23.16b+ add x25, x25, #0x1+ str x25, [sp, #0x18]+ eor v22.16b, v31.16b, v22.16b+ cmp x25, #0x17+ bic v31.16b, v0.16b, v24.16b+ eor x25, x1, x27, ror #53+ bic x27, x30, x26, ror #47+ eor v23.16b, v31.16b, v23.16b+ eor x1, x5, x28+ bic v31.16b, v1.16b, v0.16b+ eor x5, x4, x11, ror #41+ eor v24.16b, v31.16b, v24.16b+ eor x11, x19, x13, ror #35+ bic x13, x26, x24, ror #10+ bic v31.16b, v2.16b, v27.16b+ eor x28, x27, x24, ror #57+ eor v0.16b, v31.16b, v30.16b+ bic x27, x24, x9, ror #47+ bic v31.16b, v3.16b, v2.16b+ bic x19, x23, x3, ror #9+ bic x4, x29, x14, ror #41+ eor v1.16b, v31.16b, v27.16b+ eor x24, x19, x29, ror #44+ bic v31.16b, v4.16b, v3.16b+ bic x29, x3, x29, ror #35+ eor v2.16b, v31.16b, v2.16b+ eor x13, x13, x9, ror #57+ eor x19, x29, x14, ror #12+ bic v31.16b, v30.16b, v4.16b+ bic x29, x9, x0, ror #19+ eor v3.16b, v31.16b, v3.16b+ bic x14, x14, x8, ror #5+ bic v31.16b, v27.16b, v30.16b+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ eor v4.16b, v31.16b, v4.16b+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ ldr x30, [sp, #0x10]+ ld1r { v28.2d }, [x30], #8+ str x30, [sp, #0x10]+ eor v0.16b, v0.16b, v28.16b++Lmld_keccak_f1600_x4_v8a_scalar_hybrid_loop:+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ eor v30.16b, v0.16b, v5.16b+ eor v30.16b, v30.16b, v10.16b+ eor x26, x8, x9, ror #57+ eor v30.16b, v30.16b, v15.16b+ eor x27, x0, x14, ror #10+ eor x29, x16, x28, ror #63+ eor v30.16b, v30.16b, v20.16b+ eor x26, x26, x6, ror #51+ eor v29.16b, v1.16b, v6.16b+ eor x30, x23, x22, ror #50+ eor v29.16b, v29.16b, v11.16b+ eor x0, x26, x10, ror #31+ eor x29, x29, x19, ror #37+ eor v29.16b, v29.16b, v16.16b+ eor x27, x27, x12, ror #5+ eor v29.16b, v29.16b, v21.16b+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ eor v28.16b, v2.16b, v7.16b+ eor x26, x30, x21, ror #26+ eor v28.16b, v28.16b, v12.16b+ eor x26, x26, x25, ror #15+ eor v28.16b, v28.16b, v17.16b+ ror x30, x27, #0x3e+ eor x30, x30, x26, ror #57+ eor v28.16b, v28.16b, v22.16b+ ror x26, x26, #0x3a+ eor v27.16b, v3.16b, v8.16b+ eor x16, x30, x16+ eor v27.16b, v27.16b, v13.16b+ eor x28, x30, x28, ror #63+ str x28, [sp, #0xd0]+ eor v27.16b, v27.16b, v18.16b+ eor x29, x29, x17, ror #36+ eor v27.16b, v27.16b, v23.16b+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ eor v26.16b, v4.16b, v9.16b+ eor x29, x29, x20, ror #2+ eor v26.16b, v26.16b, v14.16b+ eor x28, x28, x4, ror #54+ eor v26.16b, v26.16b, v19.16b+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ eor v26.16b, v26.16b, v24.16b+ eor x28, x28, x5, ror #25+ add v31.2d, v28.2d, v28.2d+ ror x0, x0, #0x38+ eor x0, x0, x29, ror #63+ sri v31.2d, v28.2d, #0x3f+ eor x27, x28, x27, ror #61+ eor v25.16b, v31.16b, v30.16b+ eor x13, x0, x13, ror #46+ add v31.2d, v26.2d, v26.2d+ eor x28, x29, x28, ror #63+ eor x29, x30, x20, ror #2+ sri v31.2d, v26.2d, #0x3f+ eor x20, x26, x3, ror #39+ eor v28.16b, v31.16b, v28.16b+ eor x11, x0, x11, ror #50+ add v31.2d, v29.2d, v29.2d+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ sri v31.2d, v29.2d, #0x3f+ eor x21, x26, x1+ eor v26.16b, v31.16b, v26.16b+ eor x9, x27, x9, ror #49+ eor x24, x28, x24, ror #28+ add v31.2d, v27.2d, v27.2d+ eor x1, x30, x17, ror #36+ sri v31.2d, v27.2d, #0x3f+ eor x14, x0, x14, ror #8+ eor v29.16b, v31.16b, v29.16b+ eor x22, x28, x22, ror #44+ eor x8, x27, x8, ror #56+ add v31.2d, v30.2d, v30.2d+ eor x17, x27, x7, ror #19+ sri v31.2d, v30.2d, #0x3f+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ eor v27.16b, v31.16b, v27.16b+ eor x4, x26, x4, ror #54+ eor v30.16b, v0.16b, v26.16b+ eor x0, x0, x12, ror #3+ eor v31.16b, v2.16b, v29.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ shl v0.2d, v31.2d, #0x3e+ eor x26, x26, x5, ror #25+ sri v0.2d, v31.2d, #0x2+ eor x2, x7, x16, ror #39+ eor v31.16b, v12.16b, v29.16b+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ shl v2.2d, v31.2d, #0x2b+ eor x7, x7, x22, ror #25+ sri v2.2d, v31.2d, #0x15+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ eor v31.16b, v13.16b, v28.16b+ eor x30, x27, x6, ror #43+ shl v12.2d, v31.2d, #0x19+ eor x22, x20, x15, ror #23+ sri v12.2d, v31.2d, #0x27+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ eor v31.16b, v19.16b, v27.16b+ bic x5, x13, x17, ror #63+ shl v13.2d, v31.2d, #0x8+ eor x5, x21, x5, ror #21+ sri v13.2d, v31.2d, #0x38+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ eor v31.16b, v23.16b, v28.16b+ bic x21, x21, x25, ror #50+ shl v19.2d, v31.2d, #0x38+ bic x20, x27, x4, ror #25+ bic x10, x16, x15, ror #31+ sri v19.2d, v31.2d, #0x8+ eor x16, x21, x19, ror #43+ eor v31.16b, v15.16b, v26.16b+ eor x21, x17, x25, ror #30+ shl v23.2d, v31.2d, #0x29+ bic x19, x25, x19, ror #57+ ldr x25, [sp, #0x18]+ sri v23.2d, v31.2d, #0x17+ eor x17, x10, x9, ror #47+ eor v31.16b, v1.16b, v25.16b+ ldr x9, [sp, #0x8]+ eor x15, x20, x28, ror #27+ shl v15.2d, v31.2d, #0x1+ bic x20, x4, x28, ror #2+ sri v15.2d, v31.2d, #0x3f+ eor x10, x20, x1, ror #50+ eor v31.16b, v8.16b, v28.16b+ bic x20, x11, x27, ror #60+ eor x20, x20, x4, ror #21+ shl v1.2d, v31.2d, #0x37+ bic x4, x28, x1, ror #48+ sri v1.2d, v31.2d, #0x9+ bic x1, x1, x11, ror #57+ eor v31.16b, v16.16b, v25.16b+ ldr x28, [x9, x25, lsl #3]+ ldr x9, [sp, #0xd0]+ shl v8.2d, v31.2d, #0x2d+ add x25, x25, #0x1+ sri v8.2d, v31.2d, #0x13+ str x25, [sp, #0x18]+ cmp x25, #0x17+ eor v31.16b, v7.16b, v29.16b+ eor x25, x1, x27, ror #53+ shl v16.2d, v31.2d, #0x6+ bic x27, x30, x26, ror #47+ sri v16.2d, v31.2d, #0x3a+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ eor v31.16b, v10.16b, v26.16b+ eor x11, x19, x13, ror #35+ shl v7.2d, v31.2d, #0x3+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ sri v7.2d, v31.2d, #0x3d+ bic x27, x24, x9, ror #47+ eor v31.16b, v3.16b, v28.16b+ bic x19, x23, x3, ror #9+ shl v10.2d, v31.2d, #0x1c+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ sri v10.2d, v31.2d, #0x24+ bic x29, x3, x29, ror #35+ eor v31.16b, v18.16b, v28.16b+ eor x13, x13, x9, ror #57+ shl v3.2d, v31.2d, #0x15+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ sri v3.2d, v31.2d, #0x2b+ bic x14, x14, x8, ror #5+ eor v31.16b, v17.16b, v29.16b+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ shl v18.2d, v31.2d, #0xf+ bic x23, x8, x23, ror #38+ sri v18.2d, v31.2d, #0x31+ eor x8, x27, x0, ror #2+ eor v31.16b, v11.16b, v25.16b+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ shl v17.2d, v31.2d, #0xa+ eor x23, x3, x26, ror #52+ sri v17.2d, v31.2d, #0x36+ eor x3, x29, x30, ror #24+ eor x0, x15, x11, ror #52+ eor v31.16b, v9.16b, v27.16b+ eor x0, x0, x13, ror #48+ shl v11.2d, v31.2d, #0x14+ eor x26, x8, x9, ror #57+ sri v11.2d, v31.2d, #0x2c+ eor x27, x0, x14, ror #10+ eor x29, x16, x28, ror #63+ eor v31.16b, v22.16b, v29.16b+ eor x26, x26, x6, ror #51+ shl v9.2d, v31.2d, #0x3d+ eor x30, x23, x22, ror #50+ sri v9.2d, v31.2d, #0x3+ eor x0, x26, x10, ror #31+ eor x29, x29, x19, ror #37+ eor v31.16b, v14.16b, v27.16b+ eor x27, x27, x12, ror #5+ shl v22.2d, v31.2d, #0x27+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ sri v22.2d, v31.2d, #0x19+ eor x26, x30, x21, ror #26+ eor v31.16b, v20.16b, v26.16b+ eor x26, x26, x25, ror #15+ shl v14.2d, v31.2d, #0x12+ ror x30, x27, #0x3e+ eor x30, x30, x26, ror #57+ sri v14.2d, v31.2d, #0x2e+ ror x26, x26, #0x3a+ eor v31.16b, v4.16b, v27.16b+ eor x16, x30, x16+ shl v20.2d, v31.2d, #0x1b+ eor x28, x30, x28, ror #63+ str x28, [sp, #0xd0]+ sri v20.2d, v31.2d, #0x25+ eor x29, x29, x17, ror #36+ eor v31.16b, v24.16b, v27.16b+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ shl v4.2d, v31.2d, #0xe+ eor x29, x29, x20, ror #2+ sri v4.2d, v31.2d, #0x32+ eor x28, x28, x4, ror #54+ eor v31.16b, v21.16b, v25.16b+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ shl v24.2d, v31.2d, #0x2+ eor x28, x28, x5, ror #25+ sri v24.2d, v31.2d, #0x3e+ ror x0, x0, #0x38+ eor x0, x0, x29, ror #63+ eor v31.16b, v5.16b, v26.16b+ eor x27, x28, x27, ror #61+ shl v21.2d, v31.2d, #0x24+ eor x13, x0, x13, ror #46+ sri v21.2d, v31.2d, #0x1c+ eor x28, x29, x28, ror #63+ eor x29, x30, x20, ror #2+ eor v31.16b, v6.16b, v25.16b+ eor x20, x26, x3, ror #39+ shl v27.2d, v31.2d, #0x2c+ eor x11, x0, x11, ror #50+ sri v27.2d, v31.2d, #0x14+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ bic v31.16b, v7.16b, v11.16b+ eor x21, x26, x1+ eor v5.16b, v31.16b, v10.16b+ eor x9, x27, x9, ror #49+ eor x24, x28, x24, ror #28+ bic v31.16b, v8.16b, v7.16b+ eor x1, x30, x17, ror #36+ eor v6.16b, v31.16b, v11.16b+ eor x14, x0, x14, ror #8+ bic v31.16b, v9.16b, v8.16b+ eor x22, x28, x22, ror #44+ eor x8, x27, x8, ror #56+ eor v7.16b, v31.16b, v7.16b+ eor x17, x27, x7, ror #19+ bic v31.16b, v10.16b, v9.16b+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ eor v8.16b, v31.16b, v8.16b+ eor x4, x26, x4, ror #54+ bic v31.16b, v11.16b, v10.16b+ eor x0, x0, x12, ror #3+ eor v9.16b, v31.16b, v9.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ bic v31.16b, v12.16b, v16.16b+ eor x26, x26, x5, ror #25+ eor v10.16b, v31.16b, v15.16b+ eor x2, x7, x16, ror #39+ bic v31.16b, v13.16b, v12.16b+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ eor v11.16b, v31.16b, v16.16b+ eor x7, x7, x22, ror #25+ bic v31.16b, v14.16b, v13.16b+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ eor v12.16b, v31.16b, v12.16b+ eor x30, x27, x6, ror #43+ bic v31.16b, v15.16b, v14.16b+ eor x22, x20, x15, ror #23+ eor v13.16b, v31.16b, v13.16b+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ bic v31.16b, v16.16b, v15.16b+ bic x5, x13, x17, ror #63+ eor v14.16b, v31.16b, v14.16b+ eor x5, x21, x5, ror #21+ bic v31.16b, v17.16b, v21.16b+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ eor v15.16b, v31.16b, v20.16b+ bic x21, x21, x25, ror #50+ bic v31.16b, v18.16b, v17.16b+ bic x20, x27, x4, ror #25+ bic x10, x16, x15, ror #31+ eor v16.16b, v31.16b, v21.16b+ eor x16, x21, x19, ror #43+ bic v31.16b, v19.16b, v18.16b+ eor x21, x17, x25, ror #30+ eor v17.16b, v31.16b, v17.16b+ bic x19, x25, x19, ror #57+ ldr x25, [sp, #0x18]+ bic v31.16b, v20.16b, v19.16b+ eor x17, x10, x9, ror #47+ eor v18.16b, v31.16b, v18.16b+ ldr x9, [sp, #0x8]+ eor x15, x20, x28, ror #27+ bic v31.16b, v21.16b, v20.16b+ bic x20, x4, x28, ror #2+ eor v19.16b, v31.16b, v19.16b+ eor x10, x20, x1, ror #50+ bic v31.16b, v22.16b, v1.16b+ bic x20, x11, x27, ror #60+ eor x20, x20, x4, ror #21+ eor v20.16b, v31.16b, v0.16b+ bic x4, x28, x1, ror #48+ bic v31.16b, v23.16b, v22.16b+ bic x1, x1, x11, ror #57+ eor v21.16b, v31.16b, v1.16b+ ldr x28, [x9, x25, lsl #3]+ ldr x9, [sp, #0xd0]+ bic v31.16b, v24.16b, v23.16b+ add x25, x25, #0x1+ eor v22.16b, v31.16b, v22.16b+ str x25, [sp, #0x18]+ cmp x25, #0x17+ bic v31.16b, v0.16b, v24.16b+ eor x25, x1, x27, ror #53+ eor v23.16b, v31.16b, v23.16b+ bic x27, x30, x26, ror #47+ bic v31.16b, v1.16b, v0.16b+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ eor v24.16b, v31.16b, v24.16b+ eor x11, x19, x13, ror #35+ bic v31.16b, v2.16b, v27.16b+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ eor v0.16b, v31.16b, v30.16b+ bic x27, x24, x9, ror #47+ bic v31.16b, v3.16b, v2.16b+ bic x19, x23, x3, ror #9+ eor v1.16b, v31.16b, v27.16b+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ bic v31.16b, v4.16b, v3.16b+ bic x29, x3, x29, ror #35+ eor v2.16b, v31.16b, v2.16b+ eor x13, x13, x9, ror #57+ bic v31.16b, v30.16b, v4.16b+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ eor v3.16b, v31.16b, v3.16b+ bic x14, x14, x8, ror #5+ bic v31.16b, v27.16b, v30.16b+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ eor v4.16b, v31.16b, v4.16b+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ ldr x30, [sp, #0x10]+ ld1r { v28.2d }, [x30], #8+ str x30, [sp, #0x10]+ eor v0.16b, v0.16b, v28.16b++Lmld_keccak_f1600_x4_v8a_scalar_hybrid_loop_end:+ b.le Lmld_keccak_f1600_x4_v8a_scalar_hybrid_loop+ ror x2, x2, #0x3d+ ror x3, x3, #0x27+ ror x4, x4, #0x36+ ror x5, x5, #0x19+ ror x6, x6, #0x2b+ ror x7, x7, #0x13+ ror x8, x8, #0x38+ ror x9, x9, #0x31+ ror x10, x10, #0x17+ ror x11, x11, #0x32+ ror x12, x12, #0x3+ ror x13, x13, #0x2e+ ror x14, x14, #0x8+ ror x15, x15, #0x3e+ ror x17, x17, #0x24+ ror x28, x28, #0x3f+ ror x19, x19, #0x25+ ror x20, x20, #0x2+ ror x21, x21, #0x14+ ror x22, x22, #0x2c+ ror x23, x23, #0x3a+ ror x24, x24, #0x1c+ ror x25, x25, #0x9+ ldr x30, [sp, #0x20]+ cmp x30, #0x1+ b.eq Lmld_keccak_f1600_x4_v8a_scalar_hybrid_done+ mov x30, #0x1 // =1+ str x30, [sp, #0x20]+ ldr x0, [sp]+ add x0, x0, #0x190+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ sub x0, x0, #0x190+ add x0, x0, #0x258+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ sub x0, x0, #0x258+ b Lmld_keccak_f1600_x4_v8a_scalar_hybrid_initial++Lmld_keccak_f1600_x4_v8a_scalar_hybrid_done:+ ldr x0, [sp]+ add x0, x0, #0x258+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ sub x0, x0, #0x258+ add x4, x0, #0xc8+ trn1 v25.2d, v0.2d, v1.2d+ trn1 v26.2d, v2.2d, v3.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v0.2d, v1.2d+ trn2 v28.2d, v2.2d, v3.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v4.2d, v5.2d+ trn1 v26.2d, v6.2d, v7.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v4.2d, v5.2d+ trn2 v28.2d, v6.2d, v7.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v8.2d, v9.2d+ trn1 v26.2d, v10.2d, v11.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v8.2d, v9.2d+ trn2 v28.2d, v10.2d, v11.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v12.2d, v13.2d+ trn1 v26.2d, v14.2d, v15.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v12.2d, v13.2d+ trn2 v28.2d, v14.2d, v15.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v16.2d, v17.2d+ trn1 v26.2d, v18.2d, v19.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v16.2d, v17.2d+ trn2 v28.2d, v18.2d, v19.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v20.2d, v21.2d+ trn1 v26.2d, v22.2d, v23.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v20.2d, v21.2d+ trn2 v28.2d, v22.2d, v23.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ str d24, [x0]+ trn2 v25.2d, v24.2d, v24.2d+ str d25, [x4]+ ldp d8, d9, [sp, #0x90]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0xa0]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0xb0]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0xc0]+ .cfi_restore d14+ .cfi_restore d15+ ldp x19, x20, [sp, #0x30]+ .cfi_restore x19+ .cfi_restore x20+ ldp x21, x22, [sp, #0x40]+ .cfi_restore x21+ .cfi_restore x22+ ldp x23, x24, [sp, #0x50]+ .cfi_restore x23+ .cfi_restore x24+ ldp x25, x26, [sp, #0x60]+ .cfi_restore x25+ .cfi_restore x26+ ldp x27, x28, [sp, #0x70]+ .cfi_restore x27+ .cfi_restore x28+ ldp x29, x30, [sp, #0x80]+ .cfi_restore x29+ .cfi_restore x30+ add sp, sp, #0xe0+ .cfi_adjust_cfa_offset -0xe0+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm)++#endif /* MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,990 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++// Author: Hanno Becker <hannobecker@posteo.de>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>++/*yaml+ Name: keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm+ Description: AArch64 hybrid scalar/vector implementation of Keccak-f[1600] permutation for four sequential states with ARMv8.4-A optimizations+ Signature: void mld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm(uint64_t state[100], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON, SHA3]+ x0:+ type: buffer+ size_bytes: 800+ permissions: read/write+ c_parameter: uint64_t state[100]+ description: Four sequential Keccak states (state0[25], state1[25], state2[25], state3[25])+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: uint64_t const *rc+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 224+ description: register preservation and temporary storage+*/++#include "../../../../common.h"+#if defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#if defined(__ARM_FEATURE_SHA3)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm)+MLD_ASM_FN_SYMBOL(keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0xe0+ .cfi_adjust_cfa_offset 0xe0+ stp x19, x20, [sp, #0x30]+ .cfi_rel_offset x19, 0x30+ .cfi_rel_offset x20, 0x38+ stp x21, x22, [sp, #0x40]+ .cfi_rel_offset x21, 0x40+ .cfi_rel_offset x22, 0x48+ stp x23, x24, [sp, #0x50]+ .cfi_rel_offset x23, 0x50+ .cfi_rel_offset x24, 0x58+ stp x25, x26, [sp, #0x60]+ .cfi_rel_offset x25, 0x60+ .cfi_rel_offset x26, 0x68+ stp x27, x28, [sp, #0x70]+ .cfi_rel_offset x27, 0x70+ .cfi_rel_offset x28, 0x78+ stp x29, x30, [sp, #0x80]+ .cfi_rel_offset x29, 0x80+ .cfi_rel_offset x30, 0x88+ stp d8, d9, [sp, #0x90]+ .cfi_rel_offset d8, 0x90+ .cfi_rel_offset d9, 0x98+ stp d10, d11, [sp, #0xa0]+ .cfi_rel_offset d10, 0xa0+ .cfi_rel_offset d11, 0xa8+ stp d12, d13, [sp, #0xb0]+ .cfi_rel_offset d12, 0xb0+ .cfi_rel_offset d13, 0xb8+ stp d14, d15, [sp, #0xc0]+ .cfi_rel_offset d14, 0xc0+ .cfi_rel_offset d15, 0xc8+ mov x29, x1+ mov x30, #0x0 // =0+ str x30, [sp, #0x20]+ str x29, [sp, #0x8]+ str x29, [sp, #0x10]+ str x0, [sp]+ add x4, x0, #0xc8+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v0.2d, v25.2d, v27.2d+ trn2 v1.2d, v25.2d, v27.2d+ trn1 v2.2d, v26.2d, v28.2d+ trn2 v3.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v4.2d, v25.2d, v27.2d+ trn2 v5.2d, v25.2d, v27.2d+ trn1 v6.2d, v26.2d, v28.2d+ trn2 v7.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v8.2d, v25.2d, v27.2d+ trn2 v9.2d, v25.2d, v27.2d+ trn1 v10.2d, v26.2d, v28.2d+ trn2 v11.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v12.2d, v25.2d, v27.2d+ trn2 v13.2d, v25.2d, v27.2d+ trn1 v14.2d, v26.2d, v28.2d+ trn2 v15.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v16.2d, v25.2d, v27.2d+ trn2 v17.2d, v25.2d, v27.2d+ trn1 v18.2d, v26.2d, v28.2d+ trn2 v19.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v20.2d, v25.2d, v27.2d+ trn2 v21.2d, v25.2d, v27.2d+ trn1 v22.2d, v26.2d, v28.2d+ trn2 v23.2d, v26.2d, v28.2d+ ldr d25, [x0]+ ldr d27, [x4]+ trn1 v24.2d, v25.2d, v27.2d+ sub x0, x0, #0xc0+ add x0, x0, #0x190+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ sub x0, x0, #0x190++Lmld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_initial:+ eor x30, x24, x25+ eor x27, x9, x10+ eor3 v30.16b, v0.16b, v5.16b, v10.16b+ eor v30.16b, v30.16b, v15.16b+ eor x0, x30, x21+ eor x26, x27, x6+ eor v30.16b, v30.16b, v20.16b+ eor x27, x26, x7+ eor x29, x0, x22+ eor3 v29.16b, v1.16b, v6.16b, v11.16b+ eor x26, x29, x23+ eor x29, x4, x5+ eor v29.16b, v29.16b, v16.16b+ eor x30, x29, x1+ eor x0, x27, x8+ eor v29.16b, v29.16b, v21.16b+ eor x29, x30, x2+ eor x30, x19, x20+ eor3 v28.16b, v2.16b, v7.16b, v12.16b+ eor x30, x30, x16+ eor x27, x26, x0, ror #63+ eor v28.16b, v28.16b, v17.16b+ eor x4, x4, x27+ eor x30, x30, x17+ eor v28.16b, v28.16b, v22.16b+ eor x30, x30, x28+ eor x29, x29, x3+ eor3 v27.16b, v3.16b, v8.16b, v13.16b+ eor x0, x0, x30, ror #63+ eor x30, x30, x29, ror #63+ eor v27.16b, v27.16b, v18.16b+ eor x22, x22, x30+ eor v27.16b, v27.16b, v23.16b+ eor x23, x23, x30+ str x23, [sp, #0xd0]+ eor3 v26.16b, v4.16b, v9.16b, v14.16b+ eor x23, x14, x15+ eor x14, x14, x0+ eor v26.16b, v26.16b, v19.16b+ eor x23, x23, x11+ eor x15, x15, x0+ eor v26.16b, v26.16b, v24.16b+ eor x1, x1, x27+ eor x23, x23, x12+ rax1 v25.2d, v30.2d, v28.2d+ eor x23, x23, x13+ eor x11, x11, x0+ add v31.2d, v26.2d, v26.2d+ eor x29, x29, x23, ror #63+ eor x23, x23, x26, ror #63+ sri v31.2d, v26.2d, #0x3f+ eor x26, x13, x0+ eor x13, x28, x23+ eor v28.16b, v31.16b, v28.16b+ eor x28, x24, x30+ eor x24, x16, x23+ rax1 v26.2d, v26.2d, v29.2d+ eor x16, x21, x30+ eor x21, x25, x30+ add v31.2d, v27.2d, v27.2d+ eor x30, x19, x23+ sri v31.2d, v27.2d, #0x3f+ eor x19, x20, x23+ eor x20, x17, x23+ eor v29.16b, v31.16b, v29.16b+ eor x17, x12, x0+ eor x0, x2, x27+ rax1 v27.2d, v27.2d, v30.2d+ eor x2, x6, x29+ eor x6, x8, x29+ eor v30.16b, v0.16b, v26.16b+ bic x8, x28, x13, ror #47+ eor x12, x3, x27+ eor v31.16b, v2.16b, v29.16b+ bic x3, x13, x17, ror #19+ eor x5, x5, x27+ shl v0.2d, v31.2d, #0x3e+ ldr x27, [sp, #0xd0]+ bic x25, x17, x2, ror #5+ sri v0.2d, v31.2d, #0x2+ eor x9, x9, x29+ eor x23, x25, x5, ror #52+ xar v2.2d, v12.2d, v29.2d, #0x15+ eor x3, x3, x2, ror #24+ eor x8, x8, x17, ror #2+ eor v31.16b, v13.16b, v28.16b+ eor x17, x10, x29+ bic x25, x12, x22, ror #47+ shl v12.2d, v31.2d, #0x19+ eor x29, x7, x29+ bic x10, x4, x27, ror #2+ sri v12.2d, v31.2d, #0x27+ bic x7, x5, x28, ror #10+ xar v13.2d, v19.2d, v27.2d, #0x38+ eor x10, x10, x20, ror #50+ eor x13, x7, x13, ror #57+ eor v31.16b, v23.16b, v28.16b+ bic x7, x2, x5, ror #47+ eor x2, x25, x24, ror #39+ shl v19.2d, v31.2d, #0x38+ bic x25, x20, x11, ror #57+ bic x5, x17, x4, ror #25+ sri v19.2d, v31.2d, #0x8+ eor x25, x25, x17, ror #53+ bic x17, x11, x17, ror #60+ xar v23.2d, v15.2d, v26.2d, #0x17+ eor x28, x7, x28, ror #57+ bic x7, x9, x12, ror #42+ eor v31.16b, v1.16b, v25.16b+ eor x7, x7, x22, ror #25+ bic x22, x22, x24, ror #56+ shl v15.2d, v31.2d, #0x1+ bic x24, x24, x15, ror #31+ eor x22, x22, x15, ror #23+ sri v15.2d, v31.2d, #0x3f+ bic x20, x27, x20, ror #48+ bic x15, x15, x9, ror #16+ xar v1.2d, v8.2d, v28.2d, #0x9+ eor x12, x15, x12, ror #58+ eor x15, x5, x27, ror #27+ eor v31.16b, v16.16b, v25.16b+ eor x5, x20, x11, ror #41+ shl v8.2d, v31.2d, #0x2d+ ldr x11, [sp, #0x8]+ eor x20, x17, x4, ror #21+ sri v8.2d, v31.2d, #0x13+ eor x17, x24, x9, ror #47+ mov x24, #0x1 // =1+ xar v16.2d, v7.2d, v29.2d, #0x3a+ bic x9, x0, x16, ror #9+ str x24, [sp, #0x18]+ eor v31.16b, v10.16b, v26.16b+ bic x24, x29, x1, ror #44+ bic x27, x1, x21, ror #50+ shl v7.2d, v31.2d, #0x3+ bic x4, x26, x29, ror #63+ eor x1, x1, x4, ror #21+ sri v7.2d, v31.2d, #0x3d+ ldr x11, [x11]+ bic x4, x21, x30, ror #57+ xar v10.2d, v3.2d, v28.2d, #0x24+ eor x21, x24, x21, ror #30+ eor x24, x9, x19, ror #44+ eor v31.16b, v18.16b, v28.16b+ bic x9, x14, x6, ror #5+ eor x9, x9, x0, ror #43+ shl v3.2d, v31.2d, #0x15+ bic x0, x6, x0, ror #38+ eor x1, x1, x11+ sri v3.2d, v31.2d, #0x2b+ eor x11, x4, x26, ror #35+ eor x4, x0, x16, ror #47+ xar v18.2d, v17.2d, v29.2d, #0x31+ bic x0, x16, x19, ror #35+ eor v31.16b, v11.16b, v25.16b+ eor x16, x27, x30, ror #43+ bic x27, x30, x26, ror #42+ shl v17.2d, v31.2d, #0xa+ bic x26, x19, x14, ror #41+ eor x19, x0, x14, ror #12+ sri v17.2d, v31.2d, #0x36+ eor x14, x26, x6, ror #46+ eor x6, x27, x29, ror #41+ xar v11.2d, v9.2d, v27.2d, #0x2c+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ eor v31.16b, v22.16b, v29.16b+ eor x26, x8, x9, ror #57+ eor x27, x0, x14, ror #10+ shl v9.2d, v31.2d, #0x3d+ eor x29, x16, x28, ror #63+ eor x26, x26, x6, ror #51+ sri v9.2d, v31.2d, #0x3+ eor x30, x23, x22, ror #50+ eor x0, x26, x10, ror #31+ xar v22.2d, v14.2d, v27.2d, #0x19+ eor x29, x29, x19, ror #37+ eor x27, x27, x12, ror #5+ eor v31.16b, v20.16b, v26.16b+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ shl v14.2d, v31.2d, #0x12+ eor x26, x30, x21, ror #26+ sri v14.2d, v31.2d, #0x2e+ eor x26, x26, x25, ror #15+ ror x30, x27, #0x3e+ xar v20.2d, v4.2d, v27.2d, #0x25+ eor x30, x30, x26, ror #57+ ror x26, x26, #0x3a+ eor v31.16b, v24.16b, v27.16b+ eor x16, x30, x16+ eor x28, x30, x28, ror #63+ shl v4.2d, v31.2d, #0xe+ str x28, [sp, #0xd0]+ eor x29, x29, x17, ror #36+ sri v4.2d, v31.2d, #0x32+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ xar v24.2d, v21.2d, v25.2d, #0x3e+ eor x29, x29, x20, ror #2+ eor x28, x28, x4, ror #54+ eor v31.16b, v5.16b, v26.16b+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ shl v21.2d, v31.2d, #0x24+ eor x28, x28, x5, ror #25+ ror x0, x0, #0x38+ sri v21.2d, v31.2d, #0x1c+ eor x0, x0, x29, ror #63+ eor x27, x28, x27, ror #61+ xar v27.2d, v6.2d, v25.2d, #0x14+ eor x13, x0, x13, ror #46+ eor x28, x29, x28, ror #63+ bic v31.16b, v7.16b, v11.16b+ eor x29, x30, x20, ror #2+ eor v5.16b, v31.16b, v10.16b+ eor x20, x26, x3, ror #39+ eor x11, x0, x11, ror #50+ bcax v6.16b, v11.16b, v8.16b, v7.16b+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ bic v31.16b, v9.16b, v8.16b+ eor x21, x26, x1+ eor x9, x27, x9, ror #49+ eor v7.16b, v31.16b, v7.16b+ eor x24, x28, x24, ror #28+ eor x1, x30, x17, ror #36+ bcax v8.16b, v8.16b, v10.16b, v9.16b+ eor x14, x0, x14, ror #8+ eor x22, x28, x22, ror #44+ bic v31.16b, v11.16b, v10.16b+ eor x8, x27, x8, ror #56+ eor x17, x27, x7, ror #19+ eor v9.16b, v31.16b, v9.16b+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ bcax v10.16b, v15.16b, v12.16b, v16.16b+ eor x4, x26, x4, ror #54+ eor x0, x0, x12, ror #3+ bic v31.16b, v13.16b, v12.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ eor v11.16b, v31.16b, v16.16b+ eor x26, x26, x5, ror #25+ bcax v12.16b, v12.16b, v14.16b, v13.16b+ eor x2, x7, x16, ror #39+ bic x7, x9, x20, ror #42+ bic v31.16b, v15.16b, v14.16b+ bic x30, x15, x9, ror #16+ eor x7, x7, x22, ror #25+ eor v13.16b, v31.16b, v13.16b+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ bic v31.16b, v16.16b, v15.16b+ eor x30, x27, x6, ror #43+ eor x22, x20, x15, ror #23+ eor v14.16b, v31.16b, v14.16b+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ bcax v15.16b, v20.16b, v17.16b, v21.16b+ bic x5, x13, x17, ror #63+ eor x5, x21, x5, ror #21+ bic v31.16b, v18.16b, v17.16b+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ eor v16.16b, v31.16b, v21.16b+ bic x21, x21, x25, ror #50+ bic x20, x27, x4, ror #25+ bcax v17.16b, v17.16b, v19.16b, v18.16b+ bic x10, x16, x15, ror #31+ eor x16, x21, x19, ror #43+ bic v31.16b, v20.16b, v19.16b+ eor x21, x17, x25, ror #30+ bic x19, x25, x19, ror #57+ eor v18.16b, v31.16b, v18.16b+ ldr x25, [sp, #0x18]+ bcax v19.16b, v19.16b, v21.16b, v20.16b+ eor x17, x10, x9, ror #47+ ldr x9, [sp, #0x8]+ bic v31.16b, v22.16b, v1.16b+ eor x15, x20, x28, ror #27+ bic x20, x4, x28, ror #2+ eor v20.16b, v31.16b, v0.16b+ eor x10, x20, x1, ror #50+ bic x20, x11, x27, ror #60+ bcax v21.16b, v1.16b, v23.16b, v22.16b+ eor x20, x20, x4, ror #21+ bic x4, x28, x1, ror #48+ bic v31.16b, v24.16b, v23.16b+ bic x1, x1, x11, ror #57+ ldr x28, [x9, x25, lsl #3]+ eor v22.16b, v31.16b, v22.16b+ ldr x9, [sp, #0xd0]+ add x25, x25, #0x1+ bcax v23.16b, v23.16b, v0.16b, v24.16b+ str x25, [sp, #0x18]+ cmp x25, #0x17+ bic v31.16b, v1.16b, v0.16b+ eor x25, x1, x27, ror #53+ bic x27, x30, x26, ror #47+ eor v24.16b, v31.16b, v24.16b+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ bcax v0.16b, v30.16b, v2.16b, v27.16b+ eor x11, x19, x13, ror #35+ bic v31.16b, v3.16b, v2.16b+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ eor v1.16b, v31.16b, v27.16b+ bic x27, x24, x9, ror #47+ bic x19, x23, x3, ror #9+ bcax v2.16b, v2.16b, v4.16b, v3.16b+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ bic v31.16b, v30.16b, v4.16b+ bic x29, x3, x29, ror #35+ eor x13, x13, x9, ror #57+ eor v3.16b, v31.16b, v3.16b+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ bcax v4.16b, v4.16b, v27.16b, v30.16b+ bic x14, x14, x8, ror #5+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ ldr x30, [sp, #0x10]+ ld1r { v28.2d }, [x30], #8+ str x30, [sp, #0x10]+ eor v0.16b, v0.16b, v28.16b++Lmld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_loop:+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ eor3 v30.16b, v0.16b, v5.16b, v10.16b+ eor v30.16b, v30.16b, v15.16b+ eor x26, x8, x9, ror #57+ eor x27, x0, x14, ror #10+ eor v30.16b, v30.16b, v20.16b+ eor x29, x16, x28, ror #63+ eor x26, x26, x6, ror #51+ eor3 v29.16b, v1.16b, v6.16b, v11.16b+ eor x30, x23, x22, ror #50+ eor x0, x26, x10, ror #31+ eor v29.16b, v29.16b, v16.16b+ eor x29, x29, x19, ror #37+ eor x27, x27, x12, ror #5+ eor v29.16b, v29.16b, v21.16b+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ eor3 v28.16b, v2.16b, v7.16b, v12.16b+ eor x26, x30, x21, ror #26+ eor x26, x26, x25, ror #15+ eor v28.16b, v28.16b, v17.16b+ ror x30, x27, #0x3e+ eor x30, x30, x26, ror #57+ eor v28.16b, v28.16b, v22.16b+ ror x26, x26, #0x3a+ eor x16, x30, x16+ eor3 v27.16b, v3.16b, v8.16b, v13.16b+ eor x28, x30, x28, ror #63+ str x28, [sp, #0xd0]+ eor v27.16b, v27.16b, v18.16b+ eor x29, x29, x17, ror #36+ eor x28, x1, x2, ror #61+ eor v27.16b, v27.16b, v23.16b+ eor x19, x30, x19, ror #37+ eor x29, x29, x20, ror #2+ eor3 v26.16b, v4.16b, v9.16b, v14.16b+ eor x28, x28, x4, ror #54+ eor x26, x26, x0, ror #55+ eor v26.16b, v26.16b, v19.16b+ eor x28, x28, x3, ror #39+ eor x28, x28, x5, ror #25+ eor v26.16b, v26.16b, v24.16b+ ror x0, x0, #0x38+ eor x0, x0, x29, ror #63+ rax1 v25.2d, v30.2d, v28.2d+ eor x27, x28, x27, ror #61+ eor x13, x0, x13, ror #46+ add v31.2d, v26.2d, v26.2d+ eor x28, x29, x28, ror #63+ eor x29, x30, x20, ror #2+ sri v31.2d, v26.2d, #0x3f+ eor x20, x26, x3, ror #39+ eor x11, x0, x11, ror #50+ eor v28.16b, v31.16b, v28.16b+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ rax1 v26.2d, v26.2d, v29.2d+ eor x21, x26, x1+ add v31.2d, v27.2d, v27.2d+ eor x9, x27, x9, ror #49+ eor x24, x28, x24, ror #28+ sri v31.2d, v27.2d, #0x3f+ eor x1, x30, x17, ror #36+ eor x14, x0, x14, ror #8+ eor v29.16b, v31.16b, v29.16b+ eor x22, x28, x22, ror #44+ eor x8, x27, x8, ror #56+ rax1 v27.2d, v27.2d, v30.2d+ eor x17, x27, x7, ror #19+ eor x15, x0, x15, ror #62+ eor v30.16b, v0.16b, v26.16b+ bic x7, x20, x22, ror #47+ eor x4, x26, x4, ror #54+ eor v31.16b, v2.16b, v29.16b+ eor x0, x0, x12, ror #3+ eor x28, x28, x23, ror #58+ shl v0.2d, v31.2d, #0x3e+ eor x23, x26, x2, ror #61+ eor x26, x26, x5, ror #25+ sri v0.2d, v31.2d, #0x2+ eor x2, x7, x16, ror #39+ bic x7, x9, x20, ror #42+ xar v2.2d, v12.2d, v29.2d, #0x15+ bic x30, x15, x9, ror #16+ eor x7, x7, x22, ror #25+ eor v31.16b, v13.16b, v28.16b+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ shl v12.2d, v31.2d, #0x19+ eor x30, x27, x6, ror #43+ eor x22, x20, x15, ror #23+ sri v12.2d, v31.2d, #0x27+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ xar v13.2d, v19.2d, v27.2d, #0x38+ bic x5, x13, x17, ror #63+ eor x5, x21, x5, ror #21+ eor v31.16b, v23.16b, v28.16b+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ shl v19.2d, v31.2d, #0x38+ bic x21, x21, x25, ror #50+ bic x20, x27, x4, ror #25+ sri v19.2d, v31.2d, #0x8+ bic x10, x16, x15, ror #31+ eor x16, x21, x19, ror #43+ xar v23.2d, v15.2d, v26.2d, #0x17+ eor x21, x17, x25, ror #30+ bic x19, x25, x19, ror #57+ eor v31.16b, v1.16b, v25.16b+ ldr x25, [sp, #0x18]+ eor x17, x10, x9, ror #47+ shl v15.2d, v31.2d, #0x1+ ldr x9, [sp, #0x8]+ sri v15.2d, v31.2d, #0x3f+ eor x15, x20, x28, ror #27+ bic x20, x4, x28, ror #2+ xar v1.2d, v8.2d, v28.2d, #0x9+ eor x10, x20, x1, ror #50+ bic x20, x11, x27, ror #60+ eor v31.16b, v16.16b, v25.16b+ eor x20, x20, x4, ror #21+ bic x4, x28, x1, ror #48+ shl v8.2d, v31.2d, #0x2d+ bic x1, x1, x11, ror #57+ ldr x28, [x9, x25, lsl #3]+ sri v8.2d, v31.2d, #0x13+ ldr x9, [sp, #0xd0]+ add x25, x25, #0x1+ xar v16.2d, v7.2d, v29.2d, #0x3a+ str x25, [sp, #0x18]+ cmp x25, #0x17+ eor v31.16b, v10.16b, v26.16b+ eor x25, x1, x27, ror #53+ bic x27, x30, x26, ror #47+ shl v7.2d, v31.2d, #0x3+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ sri v7.2d, v31.2d, #0x3d+ eor x11, x19, x13, ror #35+ bic x13, x26, x24, ror #10+ xar v10.2d, v3.2d, v28.2d, #0x24+ eor x28, x27, x24, ror #57+ bic x27, x24, x9, ror #47+ eor v31.16b, v18.16b, v28.16b+ bic x19, x23, x3, ror #9+ bic x4, x29, x14, ror #41+ shl v3.2d, v31.2d, #0x15+ eor x24, x19, x29, ror #44+ bic x29, x3, x29, ror #35+ sri v3.2d, v31.2d, #0x2b+ eor x13, x13, x9, ror #57+ eor x19, x29, x14, ror #12+ xar v18.2d, v17.2d, v29.2d, #0x31+ bic x29, x9, x0, ror #19+ bic x14, x14, x8, ror #5+ eor v31.16b, v11.16b, v25.16b+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ shl v17.2d, v31.2d, #0xa+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ sri v17.2d, v31.2d, #0x36+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ xar v11.2d, v9.2d, v27.2d, #0x2c+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ eor v31.16b, v22.16b, v29.16b+ eor x0, x15, x11, ror #52+ shl v9.2d, v31.2d, #0x3d+ eor x0, x0, x13, ror #48+ eor x26, x8, x9, ror #57+ sri v9.2d, v31.2d, #0x3+ eor x27, x0, x14, ror #10+ eor x29, x16, x28, ror #63+ xar v22.2d, v14.2d, v27.2d, #0x19+ eor x26, x26, x6, ror #51+ eor x30, x23, x22, ror #50+ eor v31.16b, v20.16b, v26.16b+ eor x0, x26, x10, ror #31+ eor x29, x29, x19, ror #37+ shl v14.2d, v31.2d, #0x12+ eor x27, x27, x12, ror #5+ eor x30, x30, x24, ror #34+ sri v14.2d, v31.2d, #0x2e+ eor x0, x0, x7, ror #27+ eor x26, x30, x21, ror #26+ xar v20.2d, v4.2d, v27.2d, #0x25+ eor x26, x26, x25, ror #15+ ror x30, x27, #0x3e+ eor v31.16b, v24.16b, v27.16b+ eor x30, x30, x26, ror #57+ ror x26, x26, #0x3a+ shl v4.2d, v31.2d, #0xe+ eor x16, x30, x16+ eor x28, x30, x28, ror #63+ sri v4.2d, v31.2d, #0x32+ str x28, [sp, #0xd0]+ eor x29, x29, x17, ror #36+ xar v24.2d, v21.2d, v25.2d, #0x3e+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ eor v31.16b, v5.16b, v26.16b+ eor x29, x29, x20, ror #2+ eor x28, x28, x4, ror #54+ shl v21.2d, v31.2d, #0x24+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ sri v21.2d, v31.2d, #0x1c+ eor x28, x28, x5, ror #25+ ror x0, x0, #0x38+ xar v27.2d, v6.2d, v25.2d, #0x14+ eor x0, x0, x29, ror #63+ eor x27, x28, x27, ror #61+ bic v31.16b, v7.16b, v11.16b+ eor x13, x0, x13, ror #46+ eor x28, x29, x28, ror #63+ eor v5.16b, v31.16b, v10.16b+ eor x29, x30, x20, ror #2+ eor x20, x26, x3, ror #39+ bcax v6.16b, v11.16b, v8.16b, v7.16b+ eor x11, x0, x11, ror #50+ eor x25, x28, x25, ror #9+ bic v31.16b, v9.16b, v8.16b+ eor x3, x28, x21, ror #20+ eor v7.16b, v31.16b, v7.16b+ eor x21, x26, x1+ eor x9, x27, x9, ror #49+ bcax v8.16b, v8.16b, v10.16b, v9.16b+ eor x24, x28, x24, ror #28+ eor x1, x30, x17, ror #36+ bic v31.16b, v11.16b, v10.16b+ eor x14, x0, x14, ror #8+ eor x22, x28, x22, ror #44+ eor v9.16b, v31.16b, v9.16b+ eor x8, x27, x8, ror #56+ eor x17, x27, x7, ror #19+ bcax v10.16b, v15.16b, v12.16b, v16.16b+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ bic v31.16b, v13.16b, v12.16b+ eor x4, x26, x4, ror #54+ eor x0, x0, x12, ror #3+ eor v11.16b, v31.16b, v16.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ bcax v12.16b, v12.16b, v14.16b, v13.16b+ eor x26, x26, x5, ror #25+ eor x2, x7, x16, ror #39+ bic v31.16b, v15.16b, v14.16b+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ eor v13.16b, v31.16b, v13.16b+ eor x7, x7, x22, ror #25+ eor x12, x30, x20, ror #58+ bic v31.16b, v16.16b, v15.16b+ bic x20, x22, x16, ror #56+ eor x30, x27, x6, ror #43+ eor v14.16b, v31.16b, v14.16b+ eor x22, x20, x15, ror #23+ bic x6, x19, x13, ror #42+ bcax v15.16b, v20.16b, v17.16b, v21.16b+ eor x6, x6, x17, ror #41+ bic x5, x13, x17, ror #63+ bic v31.16b, v18.16b, v17.16b+ eor x5, x21, x5, ror #21+ bic x17, x17, x21, ror #44+ eor v16.16b, v31.16b, v21.16b+ eor x27, x27, x10, ror #23+ bic x21, x21, x25, ror #50+ bcax v17.16b, v17.16b, v19.16b, v18.16b+ bic x20, x27, x4, ror #25+ bic x10, x16, x15, ror #31+ bic v31.16b, v20.16b, v19.16b+ eor x16, x21, x19, ror #43+ eor x21, x17, x25, ror #30+ eor v18.16b, v31.16b, v18.16b+ bic x19, x25, x19, ror #57+ ldr x25, [sp, #0x18]+ bcax v19.16b, v19.16b, v21.16b, v20.16b+ eor x17, x10, x9, ror #47+ bic v31.16b, v22.16b, v1.16b+ ldr x9, [sp, #0x8]+ eor x15, x20, x28, ror #27+ eor v20.16b, v31.16b, v0.16b+ bic x20, x4, x28, ror #2+ eor x10, x20, x1, ror #50+ bcax v21.16b, v1.16b, v23.16b, v22.16b+ bic x20, x11, x27, ror #60+ eor x20, x20, x4, ror #21+ bic v31.16b, v24.16b, v23.16b+ bic x4, x28, x1, ror #48+ bic x1, x1, x11, ror #57+ eor v22.16b, v31.16b, v22.16b+ ldr x28, [x9, x25, lsl #3]+ ldr x9, [sp, #0xd0]+ bcax v23.16b, v23.16b, v0.16b, v24.16b+ add x25, x25, #0x1+ str x25, [sp, #0x18]+ bic v31.16b, v1.16b, v0.16b+ cmp x25, #0x17+ eor x25, x1, x27, ror #53+ eor v24.16b, v31.16b, v24.16b+ bic x27, x30, x26, ror #47+ eor x1, x5, x28+ bcax v0.16b, v30.16b, v2.16b, v27.16b+ eor x5, x4, x11, ror #41+ eor x11, x19, x13, ror #35+ bic v31.16b, v3.16b, v2.16b+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ eor v1.16b, v31.16b, v27.16b+ bic x27, x24, x9, ror #47+ bic x19, x23, x3, ror #9+ bcax v2.16b, v2.16b, v4.16b, v3.16b+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ bic v31.16b, v30.16b, v4.16b+ bic x29, x3, x29, ror #35+ eor x13, x13, x9, ror #57+ eor v3.16b, v31.16b, v3.16b+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ bcax v4.16b, v4.16b, v27.16b, v30.16b+ bic x14, x14, x8, ror #5+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ ldr x30, [sp, #0x10]+ ld1r { v28.2d }, [x30], #8+ str x30, [sp, #0x10]+ eor v0.16b, v0.16b, v28.16b++Lmld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_loop_end:+ b.le Lmld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_loop+ ror x2, x2, #0x3d+ ror x3, x3, #0x27+ ror x4, x4, #0x36+ ror x5, x5, #0x19+ ror x6, x6, #0x2b+ ror x7, x7, #0x13+ ror x8, x8, #0x38+ ror x9, x9, #0x31+ ror x10, x10, #0x17+ ror x11, x11, #0x32+ ror x12, x12, #0x3+ ror x13, x13, #0x2e+ ror x14, x14, #0x8+ ror x15, x15, #0x3e+ ror x17, x17, #0x24+ ror x28, x28, #0x3f+ ror x19, x19, #0x25+ ror x20, x20, #0x2+ ror x21, x21, #0x14+ ror x22, x22, #0x2c+ ror x23, x23, #0x3a+ ror x24, x24, #0x1c+ ror x25, x25, #0x9+ ldr x30, [sp, #0x20]+ cmp x30, #0x1+ b.eq Lmld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_done+ mov x30, #0x1 // =1+ str x30, [sp, #0x20]+ ldr x0, [sp]+ add x0, x0, #0x190+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ sub x0, x0, #0x190+ add x0, x0, #0x258+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ sub x0, x0, #0x258+ b Lmld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_initial++Lmld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_done:+ ldr x0, [sp]+ add x0, x0, #0x258+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ sub x0, x0, #0x258+ add x4, x0, #0xc8+ trn1 v25.2d, v0.2d, v1.2d+ trn1 v26.2d, v2.2d, v3.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v0.2d, v1.2d+ trn2 v28.2d, v2.2d, v3.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v4.2d, v5.2d+ trn1 v26.2d, v6.2d, v7.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v4.2d, v5.2d+ trn2 v28.2d, v6.2d, v7.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v8.2d, v9.2d+ trn1 v26.2d, v10.2d, v11.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v8.2d, v9.2d+ trn2 v28.2d, v10.2d, v11.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v12.2d, v13.2d+ trn1 v26.2d, v14.2d, v15.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v12.2d, v13.2d+ trn2 v28.2d, v14.2d, v15.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v16.2d, v17.2d+ trn1 v26.2d, v18.2d, v19.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v16.2d, v17.2d+ trn2 v28.2d, v18.2d, v19.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v20.2d, v21.2d+ trn1 v26.2d, v22.2d, v23.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v20.2d, v21.2d+ trn2 v28.2d, v22.2d, v23.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ str d24, [x0]+ trn2 v25.2d, v24.2d, v24.2d+ str d25, [x4]+ ldp d8, d9, [sp, #0x90]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0xa0]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0xb0]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0xc0]+ .cfi_restore d14+ .cfi_restore d15+ ldp x19, x20, [sp, #0x30]+ .cfi_restore x19+ .cfi_restore x20+ ldp x21, x22, [sp, #0x40]+ .cfi_restore x21+ .cfi_restore x22+ ldp x23, x24, [sp, #0x50]+ .cfi_restore x23+ .cfi_restore x24+ ldp x25, x26, [sp, #0x60]+ .cfi_restore x25+ .cfi_restore x26+ ldp x27, x28, [sp, #0x70]+ .cfi_restore x27+ .cfi_restore x28+ ldp x29, x30, [sp, #0x80]+ .cfi_restore x29+ .cfi_restore x30+ add sp, sp, #0xe0+ .cfi_adjust_cfa_offset -0xe0+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm)++#endif /* __ARM_FEATURE_SHA3 */++#endif /* MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,47 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++#include "../../../../common.h"++#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \+ defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \+ defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \+ defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \+ defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#include "fips202_native_aarch64.h"++MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const uint64_t+ mld_keccakf1600_round_constants[24] = {+ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a,+ 0x8000000080008000, 0x000000000000808b, 0x0000000080000001,+ 0x8000000080008081, 0x8000000000008009, 0x000000000000008a,+ 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,+ 0x000000008000808b, 0x800000000000008b, 0x8000000000008089,+ 0x8000000000008003, 0x8000000000008002, 0x8000000000000080,+ 0x000000000000800a, 0x800000008000000a, 0x8000000080008081,+ 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,+};++#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \+ MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \+ || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \+ MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED */++MLD_EMPTY_CU(fips202_aarch64_round_constants)++#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \+ MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \+ || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \+ MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,27 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H+#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H++/* Part of backend API */+#define MLD_USE_NATIVE_FIPS202_X1+/* Guard for assembly file */+#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state)+{+ mld_keccak_f1600_x1_scalar_aarch64_asm(state,+ mld_keccakf1600_round_constants);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */
@@ -0,0 +1,36 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H+#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H++#if !defined(__ARM_FEATURE_SHA3)+#error This backend can only be used if SHA3 extensions are available.+#endif++/* Part of backend API */+#define MLD_USE_NATIVE_FIPS202_X1+/* Guard for assembly file */+#define MLD_FIPS202_AARCH64_NEED_X1_V84A++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON) ||+ !mld_sys_check_capability(MLD_SYS_CAP_AARCH64_SHA3))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ mld_keccak_f1600_x1_v84a_aarch64_asm(state, mld_keccakf1600_round_constants);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */
@@ -0,0 +1,40 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H+#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H++#if !defined(__ARM_FEATURE_SHA3)+#error This backend can only be used if SHA3 extensions are available.+#endif++/* Part of backend API */+#define MLD_USE_NATIVE_FIPS202_X4+/* Guard for assembly file */+#define MLD_FIPS202_AARCH64_NEED_X2_V84A++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON) ||+ !mld_sys_check_capability(MLD_SYS_CAP_AARCH64_SHA3))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ mld_keccak_f1600_x2_v84a_aarch64_asm(state + 0 * 25,+ mld_keccakf1600_round_constants);+ mld_keccak_f1600_x2_v84a_aarch64_asm(state + 2 * 25,+ mld_keccakf1600_round_constants);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */
@@ -0,0 +1,32 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H+#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H++/* Part of backend API */+#define MLD_USE_NATIVE_FIPS202_X4+/* Guard for assembly file */+#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ mld_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm(+ state, mld_keccakf1600_round_constants);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */
@@ -0,0 +1,37 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H+#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H++#if !defined(__ARM_FEATURE_SHA3)+#error This backend can only be used if SHA3 extensions are available.+#endif++/* Part of backend API */+#define MLD_USE_NATIVE_FIPS202_X4+/* Guard for assembly file */+#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON) ||+ !mld_sys_check_capability(MLD_SYS_CAP_AARCH64_SHA3))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ mld_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm(+ state, mld_keccakf1600_round_constants);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */
@@ -0,0 +1,129 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_FIPS202_NATIVE_API_H+#define MLD_FIPS202_NATIVE_API_H+/*+ * FIPS-202 native interface+ *+ * This header is primarily for documentation purposes.+ * It should not be included by backend implementations.+ */++#include "../../cbmc.h"+#include "../../common.h"++/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */+#define MLD_NATIVE_FUNC_SUCCESS (0)+/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that+ * the target/parameters are unsupported; typically, this would be because of+ * dependencies on CPU features not detected on the host CPU. In this case,+ * the frontend falls back to the default C implementation.+ *+ * IMPORTANT: Backend implementations must ensure that the decision of whether+ * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on+ * the input data itself. Fallback decisions may only depend on system+ * capabilities (e.g., CPU features) and, where present, length information.+ * This requirement applies to all backend functions to maintain constant-time+ * properties.+ */+#define MLD_NATIVE_FUNC_FALLBACK (-1)++/*+ * This is the C<->native interface allowing for the drop-in+ * of custom Keccak-F1600 implementations.+ *+ * A _backend_ is a specific implementation of parts of this interface.+ *+ * You can replace 1-fold or 4-fold batched Keccak-F1600.+ * To enable, set MLD_USE_NATIVE_FIPS202_X1 or MLD_USE_NATIVE_FIPS202_X4+ * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native()+ * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your+ * implementation.+ */++#if defined(MLD_USE_NATIVE_FIPS202_X1)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1))+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1))+);+#endif /* MLD_USE_NATIVE_FIPS202_X1 */+#if defined(MLD_USE_NATIVE_FIPS202_X4)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4))+);+#endif /* MLD_USE_NATIVE_FIPS202_X4 */++/*+ * Native x4 XOR bytes and extract bytes interface.+ *+ * These functions allow backends to provide optimized implementations for+ * XORing input data into the state and extracting output data from the state.+ * This is particularly useful for backends that use a different internal state+ * representation (e.g., bit-interleaved), as conversion can happen during+ * XOR/extract rather than before/after each permutation.+ *+ * NOTE: We assume that the custom representation of the zero state is the+ * all-zero state.+ *+ * MLD_USE_NATIVE_FIPS202_X4_XOR_BYTES: Backend provides native XOR bytes+ * MLD_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES: Backend provides native extract+ * bytes+ */++#if defined(MLD_USE_NATIVE_FIPS202_X4_XOR_BYTES)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccakf1600_xor_bytes_x4_native(+ uint64_t *state, const unsigned char *data0, const unsigned char *data1,+ const unsigned char *data2, const unsigned char *data3, unsigned offset,+ unsigned length)+__contract__(+ requires(0 <= offset && offset <= 25 * sizeof(uint64_t) &&+ 0 <= length && length <= 25 * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ requires(memory_no_alias(data0, length))+ requires((data0 == data1 &&+ data0 == data2 &&+ data0 == data3) ||+ (memory_no_alias(data1, length) &&+ memory_no_alias(data2, length) &&+ memory_no_alias(data3, length)))+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)));+#endif /* MLD_USE_NATIVE_FIPS202_X4_XOR_BYTES */++#if defined(MLD_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccakf1600_extract_bytes_x4_native(+ uint64_t *state, unsigned char *data0, unsigned char *data1,+ unsigned char *data2, unsigned char *data3, unsigned offset,+ unsigned length)+__contract__(+ requires(0 <= offset && offset <= 25 * sizeof(uint64_t) &&+ 0 <= length && length <= 25 * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ requires(memory_no_alias(data0, length))+ requires(memory_no_alias(data1, length))+ requires(memory_no_alias(data2, length))+ requires(memory_no_alias(data3, length))+ assigns(memory_slice(data0, length))+ assigns(memory_slice(data1, length))+ assigns(memory_slice(data2, length))+ assigns(memory_slice(data3, length))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS));+#endif /* MLD_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES */++#endif /* !MLD_FIPS202_NATIVE_API_H */
@@ -0,0 +1,35 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_FIPS202_NATIVE_AUTO_H+#define MLD_FIPS202_NATIVE_AUTO_H++/*+ * Default FIPS202 backend+ */+#include "../../sys.h"++#if defined(MLD_SYS_AARCH64)+#include "aarch64/auto.h"+#endif++/* The x86_64 backend requires toolchain support for the SysV ABI */+#if defined(MLD_SYS_X86_64_AVX2) && defined(MLD_SYSV_ABI_SUPPORTED) && \+ (!defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_REDUCE_RAM)) && \+ !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+#include "x86_64/keccak_f1600_x4_avx2.h"+#endif /* MLD_SYS_X86_64_AVX2 && MLD_SYSV_ABI_SUPPORTED && \+ (!MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_SIGN_API || \+ !MLD_CONFIG_REDUCE_RAM) && !MLD_CONFIG_SERIAL_FIPS202_ONLY */++/* We do not yet include the FIPS202 backend for Armv8.1-M+MVE by default+ * as it is still experimental and undergoing review. */+/* #if defined(MLD_SYS_ARMV81M_MVE) */+/* #include "armv81m/mve.h" */+/* #endif */++#endif /* !MLD_FIPS202_NATIVE_AUTO_H */
@@ -0,0 +1,34 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H+#define MLD_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H++#include "../../../common.h"++#define MLD_FIPS202_X86_64_NEED_X4_AVX2++/* Part of backend API */+#define MLD_USE_NATIVE_FIPS202_X4++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_x86_64.h"+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ mld_keccak_f1600_x4_avx2_asm(state, mld_keccakf1600_round_constants,+ mld_keccak_rho8, mld_keccak_rho56);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLD_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H */
@@ -0,0 +1,45 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H+#define MLD_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H++#include "../../../../cbmc.h"+#include "../../../../common.h"++/* TODO: Reconsider whether this check is needed -- x86_64 is always+ * little-endian, so the backend selection already implies this. */+#ifndef MLD_SYS_LITTLE_ENDIAN+#error Expecting a little-endian platform+#endif++#define mld_keccakf1600_round_constants \+ MLD_NAMESPACE(keccakf1600_round_constants)+MLD_INTERNAL_DATA_DECLARATION const uint64_t+ mld_keccakf1600_round_constants[24];++#define mld_keccak_rho8 MLD_NAMESPACE(keccak_rho8)+MLD_INTERNAL_DATA_DECLARATION const uint64_t mld_keccak_rho8[4];++#define mld_keccak_rho56 MLD_NAMESPACE(keccak_rho56)+MLD_INTERNAL_DATA_DECLARATION const uint64_t mld_keccak_rho56[4];++#define mld_keccak_f1600_x4_avx2_asm MLD_NAMESPACE(keccak_f1600_x4_avx2_asm)+MLD_SYSV_ABI+void mld_keccak_f1600_x4_avx2_asm(uint64_t states[100], const uint64_t rc[24],+ const uint64_t rho8[4],+ const uint64_t rho56[4])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/keccak_f1600_x4_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(states, sizeof(uint64_t) * 25 * 4))+ requires(rc == mld_keccakf1600_round_constants)+ requires(rho8 == mld_keccak_rho8)+ requires(rho56 == mld_keccak_rho56)+ assigns(memory_slice(states, sizeof(uint64_t) * 25 * 4))+);++#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H */
@@ -0,0 +1,488 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+/*yaml+ Name: keccak_f1600_x4_avx2_asm+ Description: x86_64 AVX2 Keccak-f[1600] permutation for four sequential states+ Signature: void mld_keccak_f1600_x4_avx2_asm(uint64_t states[100], const uint64_t rc[24], const uint64_t rho8[4], const uint64_t rho56[4])+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 800+ permissions: read/write+ c_parameter: uint64_t states[100]+ description: Four sequential Keccak states (4 x 25 x uint64_t)+ rsi:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: const uint64_t rc[24]+ description: Round constants (24 x uint64_t)+ rdx:+ type: buffer+ size_bytes: 32+ permissions: read-only+ c_parameter: const uint64_t rho8[4]+ description: Rotation constant rho8 (4 x uint64_t)+ rcx:+ type: buffer+ size_bytes: 32+ permissions: read-only+ c_parameter: const uint64_t rho56[4]+ description: Rotation constant rho56 (4 x uint64_t)+*/++#include "../../../../common.h"++#if defined(MLD_FIPS202_X86_64_NEED_X4_AVX2) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/fips202/x86_64/src/keccak_f1600_x4_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(keccak_f1600_x4_avx2_asm)+MLD_ASM_FN_SYMBOL(keccak_f1600_x4_avx2_asm)++ .cfi_startproc+ movq %rsp, %r11+ .cfi_def_cfa_register %r11+ andq $-0x20, %rsp+ subq $0x300, %rsp # imm = 0x300+ vmovdqu (%rdi), %ymm0+ vmovdqu 0xc8(%rdi), %ymm3+ vmovdqu 0x190(%rdi), %ymm1+ vmovdqu 0x258(%rdi), %ymm4+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm7 # ymm7 = ymm2[0,1],ymm3[0,1]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm3 # ymm3 = ymm2[2,3],ymm3[2,3]+ vmovdqu 0x278(%rdi), %ymm4+ vmovdqu %ymm3, 0x40(%rsp)+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm3 # ymm3 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm7, (%rsp)+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vmovdqu 0x20(%rdi), %ymm0+ vmovdqu 0x1b0(%rdi), %ymm1+ vmovdqu %ymm3, 0x60(%rsp)+ vmovdqu 0xe8(%rdi), %ymm3+ vmovdqu %ymm7, 0x20(%rsp)+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm7 # ymm7 = ymm2[0,1],ymm3[0,1]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm3 # ymm3 = ymm2[2,3],ymm3[2,3]+ vmovdqu 0x298(%rdi), %ymm4+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm14 # ymm14 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm7, 0x80(%rsp)+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vmovdqu 0x40(%rdi), %ymm0+ vmovdqu 0x1d0(%rdi), %ymm1+ vmovdqu %ymm3, 0xc0(%rsp)+ vmovdqu 0x108(%rdi), %ymm3+ vmovdqu %ymm14, %ymm10+ vmovdqu %ymm7, 0xa0(%rsp)+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm11 # ymm11 = ymm2[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm3 # ymm3 = ymm2[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vmovdqu %ymm3, 0x100(%rsp)+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm8 # ymm8 = ymm0[2,3],ymm1[2,3]+ vmovdqu 0x128(%rdi), %ymm3+ vmovdqu 0x60(%rdi), %ymm0+ vmovdqu 0x1f0(%rdi), %ymm1+ vmovdqu %ymm7, 0xe0(%rsp)+ vmovdqu %ymm11, %ymm14+ vmovdqu 0x2b8(%rdi), %ymm4+ vmovdqu 0x2f8(%rdi), %ymm5+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vmovdqu 0x2d8(%rdi), %ymm4+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm15 # ymm15 = ymm2[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm3 # ymm3 = ymm2[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm9 # ymm9 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm3, 0x140(%rsp)+ vmovdqu 0x80(%rdi), %ymm0+ vmovdqu 0x148(%rdi), %ymm3+ vmovdqu 0x210(%rdi), %ymm1+ vmovdqu %ymm7, 0x120(%rsp)+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm7 # ymm7 = ymm2[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm13 # ymm13 = ymm2[2,3],ymm3[2,3]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm3 # ymm3 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm7, 0x160(%rsp)+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vmovdqu 0xa0(%rdi), %ymm0+ vmovdqu 0x230(%rdi), %ymm1+ vmovdqu %ymm3, 0x1a0(%rsp)+ vmovdqu 0x168(%rdi), %ymm3+ vpunpcklqdq %ymm5, %ymm1, %ymm4 # ymm4 = ymm1[0],ymm5[0],ymm1[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm5[1],ymm1[3],ymm5[3]+ vmovdqu %ymm7, 0x180(%rsp)+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm12 # ymm12 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm3 # ymm3 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm7 # ymm7 = ymm2[2,3],ymm4[2,3]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm4 # ymm4 = ymm0[2,3],ymm1[2,3]+ vmovq 0x250(%rdi), %xmm0+ vmovq 0xc0(%rdi), %xmm1+ vmovdqu %ymm12, 0x1c0(%rsp)+ vmovdqu %ymm4, 0x1e0(%rsp)+ vpinsrq $0x1, 0x318(%rdi), %xmm0, %xmm0+ vpinsrq $0x1, 0x188(%rdi), %xmm1, %xmm1+ vinserti128 $0x1, %xmm0, %ymm1, %ymm2+ movq $0x0, %r10++LLmld_keccak_f1600_x4_avx2_asm:+ vmovdqu 0xa0(%rsp), %ymm4+ vpxor 0x1c0(%rsp), %ymm9, %ymm0+ vmovdqu %ymm9, 0x200(%rsp)+ vmovdqu %ymm10, %ymm9+ vmovdqu 0xc0(%rsp), %ymm11+ vmovdqu 0x160(%rsp), %ymm12+ vmovdqu %ymm3, 0x240(%rsp)+ vpxor 0x100(%rsp), %ymm4, %ymm1+ vmovdqu 0x40(%rsp), %ymm10+ vmovdqu %ymm4, 0x220(%rsp)+ vpxor %ymm3, %ymm12, %ymm12+ vmovdqu 0x20(%rsp), %ymm6+ vmovdqu 0x140(%rsp), %ymm4+ vmovdqu %ymm14, 0x2a0(%rsp)+ vpxor %ymm1, %ymm0, %ymm0+ vpxor %ymm8, %ymm11, %ymm1+ vpxor 0x180(%rsp), %ymm7, %ymm11+ vmovdqu %ymm10, 0x280(%rsp)+ vpxor %ymm1, %ymm12, %ymm12+ vpxor %ymm15, %ymm9, %ymm1+ vmovdqu 0xe0(%rsp), %ymm3+ vmovdqu %ymm8, 0x260(%rsp)+ vpxor %ymm1, %ymm11, %ymm11+ vpxor 0x120(%rsp), %ymm14, %ymm1+ vpxor %ymm6, %ymm12, %ymm12+ vmovdqu 0x60(%rsp), %ymm8+ vpxor %ymm10, %ymm11, %ymm11+ vpxor 0x1e0(%rsp), %ymm13, %ymm10+ vpxor %ymm4, %ymm3, %ymm3+ vmovdqu %ymm4, 0x2c0(%rsp)+ vpsrlq $0x3f, %ymm12, %ymm4+ vpsrlq $0x3f, %ymm11, %ymm5+ vpxor (%rsp), %ymm0, %ymm0+ vpxor %ymm1, %ymm10, %ymm10+ vmovdqu 0x80(%rsp), %ymm1+ vpxor %ymm8, %ymm10, %ymm10+ vmovdqu %ymm1, %ymm14+ vpxor 0x1a0(%rsp), %ymm2, %ymm1+ vmovdqu %ymm14, 0x2e0(%rsp)+ vpxor %ymm3, %ymm1, %ymm1+ vpsllq $0x1, %ymm12, %ymm3+ vpor %ymm4, %ymm3, %ymm3+ vpsllq $0x1, %ymm11, %ymm4+ vpxor %ymm14, %ymm1, %ymm1+ vpor %ymm5, %ymm4, %ymm4+ vpsrlq $0x3f, %ymm10, %ymm14+ vpxor %ymm1, %ymm3, %ymm3+ vpsllq $0x1, %ymm10, %ymm5+ vpxor %ymm0, %ymm4, %ymm4+ vpor %ymm14, %ymm5, %ymm5+ vpxor %ymm6, %ymm4, %ymm6+ vpxor %ymm12, %ymm5, %ymm5+ vpsrlq $0x3f, %ymm1, %ymm12+ vpsllq $0x1, %ymm1, %ymm1+ vpxor %ymm7, %ymm5, %ymm7+ vpxor %ymm9, %ymm5, %ymm9+ vpor %ymm12, %ymm1, %ymm1+ vpxor (%rsp), %ymm3, %ymm12+ vpxor %ymm11, %ymm1, %ymm1+ vpsrlq $0x3f, %ymm0, %ymm11+ vpsllq $0x1, %ymm0, %ymm0+ vpxor %ymm13, %ymm1, %ymm13+ vpxor %ymm8, %ymm1, %ymm8+ vpor %ymm11, %ymm0, %ymm0+ vpxor %ymm10, %ymm0, %ymm0+ vpxor 0xc0(%rsp), %ymm4, %ymm10+ vpxor %ymm2, %ymm0, %ymm2+ vpsrlq $0x14, %ymm10, %ymm11+ vpsllq $0x2c, %ymm10, %ymm10+ vpor %ymm11, %ymm10, %ymm10+ vpxor %ymm15, %ymm5, %ymm11+ vpbroadcastq (%rsi), %ymm15+ vpsrlq $0x15, %ymm11, %ymm14+ vpsllq $0x2b, %ymm11, %ymm11+ vpor %ymm14, %ymm11, %ymm11+ vpandn %ymm11, %ymm10, %ymm14+ vpxor %ymm15, %ymm14, %ymm14+ vpxor %ymm12, %ymm14, %ymm15+ vpsrlq $0x2b, %ymm13, %ymm14+ vpsllq $0x15, %ymm13, %ymm13+ vmovdqu %ymm15, (%rsp)+ vpor %ymm14, %ymm13, %ymm13+ vpandn %ymm13, %ymm11, %ymm14+ vpxor %ymm10, %ymm14, %ymm15+ vpsrlq $0x32, %ymm2, %ymm14+ vpsllq $0xe, %ymm2, %ymm2+ vmovdqu %ymm15, 0x20(%rsp)+ vpor %ymm14, %ymm2, %ymm2+ vpandn %ymm2, %ymm13, %ymm14+ vpxor %ymm11, %ymm14, %ymm11+ vmovdqu %ymm11, 0x40(%rsp)+ vpandn %ymm12, %ymm2, %ymm11+ vpandn %ymm10, %ymm12, %ymm12+ vpxor %ymm13, %ymm11, %ymm11+ vmovdqu %ymm11, 0x60(%rsp)+ vpxor %ymm2, %ymm12, %ymm11+ vpsrlq $0x24, %ymm8, %ymm2+ vpsllq $0x1c, %ymm8, %ymm8+ vmovdqu %ymm11, 0x80(%rsp)+ vpor %ymm2, %ymm8, %ymm8+ vpxor 0xe0(%rsp), %ymm0, %ymm2+ vpsrlq $0x2c, %ymm2, %ymm10+ vpsllq $0x14, %ymm2, %ymm2+ vpor %ymm10, %ymm2, %ymm2+ vpxor 0x100(%rsp), %ymm3, %ymm10+ vpsrlq $0x3d, %ymm10, %ymm11+ vpsllq $0x3, %ymm10, %ymm10+ vpor %ymm11, %ymm10, %ymm10+ vpandn %ymm10, %ymm2, %ymm11+ vpxor %ymm8, %ymm11, %ymm11+ vmovdqu %ymm11, 0xa0(%rsp)+ vpxor 0x160(%rsp), %ymm4, %ymm11+ vpsrlq $0x13, %ymm11, %ymm12+ vpsllq $0x2d, %ymm11, %ymm11+ vpor %ymm12, %ymm11, %ymm11+ vpandn %ymm11, %ymm10, %ymm12+ vpxor %ymm2, %ymm12, %ymm12+ vmovdqu %ymm12, 0xc0(%rsp)+ vpsrlq $0x3, %ymm7, %ymm12+ vpsllq $0x3d, %ymm7, %ymm7+ vpor %ymm12, %ymm7, %ymm7+ vpandn %ymm7, %ymm11, %ymm12+ vpxor %ymm10, %ymm12, %ymm10+ vpandn %ymm8, %ymm7, %ymm12+ vpandn %ymm2, %ymm8, %ymm8+ vpsrlq $0x3f, %ymm6, %ymm2+ vpsllq $0x1, %ymm6, %ymm6+ vpxor %ymm11, %ymm12, %ymm14+ vpor %ymm2, %ymm6, %ymm6+ vpsrlq $0x3a, %ymm9, %ymm2+ vpxor %ymm7, %ymm8, %ymm12+ vpsllq $0x6, %ymm9, %ymm9+ vmovdqu %ymm12, 0xe0(%rsp)+ vpxor 0x1a0(%rsp), %ymm0, %ymm7+ vpor %ymm2, %ymm9, %ymm9+ vpxor 0x120(%rsp), %ymm1, %ymm2+ vpshufb (%rdx), %ymm7, %ymm7+ vpsrlq $0x27, %ymm2, %ymm11+ vpsllq $0x19, %ymm2, %ymm2+ vpor %ymm2, %ymm11, %ymm11+ vpandn %ymm11, %ymm9, %ymm2+ vpandn %ymm7, %ymm11, %ymm8+ vpxor %ymm6, %ymm2, %ymm12+ vpxor 0x1c0(%rsp), %ymm3, %ymm2+ vpxor %ymm9, %ymm8, %ymm8+ vmovdqu %ymm12, 0x100(%rsp)+ vpsrlq $0x2e, %ymm2, %ymm12+ vpsllq $0x12, %ymm2, %ymm2+ vpor %ymm2, %ymm12, %ymm2+ vpandn %ymm2, %ymm7, %ymm12+ vpxor %ymm11, %ymm12, %ymm15+ vpandn %ymm6, %ymm2, %ymm11+ vpandn %ymm9, %ymm6, %ymm6+ vpxor %ymm7, %ymm11, %ymm12+ vmovdqu %ymm12, 0x120(%rsp)+ vpxor %ymm2, %ymm6, %ymm12+ vpxor 0x2e0(%rsp), %ymm0, %ymm6+ vpxor 0x2c0(%rsp), %ymm0, %ymm0+ vmovdqu %ymm12, 0x140(%rsp)+ vpsrlq $0x25, %ymm6, %ymm2+ vpsllq $0x1b, %ymm6, %ymm6+ vpor %ymm6, %ymm2, %ymm2+ vpxor 0x220(%rsp), %ymm3, %ymm6+ vpxor 0x200(%rsp), %ymm3, %ymm3+ vpsrlq $0x1c, %ymm6, %ymm7+ vpsllq $0x24, %ymm6, %ymm6+ vpor %ymm6, %ymm7, %ymm7+ vpxor 0x260(%rsp), %ymm4, %ymm6+ vpxor 0x240(%rsp), %ymm4, %ymm4+ vpsrlq $0x36, %ymm6, %ymm12+ vpsllq $0xa, %ymm6, %ymm6+ vpor %ymm6, %ymm12, %ymm12+ vpxor 0x180(%rsp), %ymm5, %ymm6+ vpxor 0x280(%rsp), %ymm5, %ymm5+ vpandn %ymm12, %ymm7, %ymm9+ vpsrlq $0x31, %ymm6, %ymm11+ vpsllq $0xf, %ymm6, %ymm6+ vpxor %ymm2, %ymm9, %ymm9+ vpor %ymm6, %ymm11, %ymm11+ vpandn %ymm11, %ymm12, %ymm6+ vpxor %ymm7, %ymm6, %ymm6+ vmovdqu %ymm6, 0x160(%rsp)+ vpxor 0x1e0(%rsp), %ymm1, %ymm6+ vpxor 0x2a0(%rsp), %ymm1, %ymm1+ vpshufb (%rcx), %ymm6, %ymm6+ vpandn %ymm6, %ymm11, %ymm13+ vpxor %ymm12, %ymm13, %ymm13+ vmovdqu %ymm13, 0x180(%rsp)+ vpandn %ymm2, %ymm6, %ymm13+ vpandn %ymm7, %ymm2, %ymm2+ vpxor %ymm6, %ymm2, %ymm2+ vpsrlq $0x3e, %ymm4, %ymm6+ vpxor %ymm11, %ymm13, %ymm13+ vmovdqu %ymm2, 0x1a0(%rsp)+ vpsrlq $0x2, %ymm5, %ymm2+ vpsllq $0x3e, %ymm5, %ymm5+ vpor %ymm5, %ymm2, %ymm2+ vpsrlq $0x9, %ymm1, %ymm5+ vpsllq $0x37, %ymm1, %ymm1+ vpsllq $0x2, %ymm4, %ymm4+ vpor %ymm1, %ymm5, %ymm1+ vpsrlq $0x19, %ymm0, %ymm5+ vpor %ymm4, %ymm6, %ymm4+ vpsllq $0x27, %ymm0, %ymm0+ vpor %ymm0, %ymm5, %ymm5+ vpandn %ymm5, %ymm1, %ymm0+ vpxor %ymm2, %ymm0, %ymm0+ vmovdqu %ymm0, 0x1c0(%rsp)+ vpsrlq $0x17, %ymm3, %ymm0+ vpsllq $0x29, %ymm3, %ymm3+ vpor %ymm3, %ymm0, %ymm0+ vpandn %ymm4, %ymm0, %ymm7+ vpandn %ymm0, %ymm5, %ymm3+ vpxor %ymm5, %ymm7, %ymm7+ vpandn %ymm2, %ymm4, %ymm5+ vpandn %ymm1, %ymm2, %ymm2+ vpxor %ymm0, %ymm5, %ymm5+ vpxor %ymm1, %ymm3, %ymm3+ vpxor %ymm4, %ymm2, %ymm2+ vmovdqu %ymm5, 0x1e0(%rsp)+ addq $0x8, %rsi+ addq $0x1, %r10+ cmpq $0x18, %r10+ jne LLmld_keccak_f1600_x4_avx2_asm+ vmovdqu (%rsp), %ymm4+ vmovdqu 0x40(%rsp), %ymm5+ vmovdqu 0x20(%rsp), %ymm0+ vmovdqu 0x60(%rsp), %ymm1+ vmovdqu 0x1c0(%rsp), %ymm12+ vmovdqu %ymm2, 0x1c0(%rsp)+ vpunpcklqdq %ymm0, %ymm4, %ymm2 # ymm2 = ymm4[0],ymm0[0],ymm4[2],ymm0[2]+ vpunpckhqdq %ymm0, %ymm4, %ymm0 # ymm0 = ymm4[1],ymm0[1],ymm4[3],ymm0[3]+ vpunpcklqdq %ymm1, %ymm5, %ymm4 # ymm4 = ymm5[0],ymm1[0],ymm5[2],ymm1[2]+ vpunpckhqdq %ymm1, %ymm5, %ymm1 # ymm1 = ymm5[1],ymm1[1],ymm5[3],ymm1[3]+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vmovdqu 0x80(%rsp), %ymm4+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm5 # ymm5 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm0 # ymm0 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm6, (%rdi)+ vmovdqu %ymm5, 0xc8(%rdi)+ vmovdqu %ymm2, 0x190(%rdi)+ vmovdqu %ymm0, 0x258(%rdi)+ vmovdqu 0xa0(%rsp), %ymm0+ vpunpcklqdq %ymm0, %ymm4, %ymm2 # ymm2 = ymm4[0],ymm0[0],ymm4[2],ymm0[2]+ vpunpckhqdq %ymm0, %ymm4, %ymm1 # ymm1 = ymm4[1],ymm0[1],ymm4[3],ymm0[3]+ vmovdqu 0xc0(%rsp), %ymm0+ vpunpcklqdq %ymm10, %ymm0, %ymm4 # ymm4 = ymm0[0],ymm10[0],ymm0[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm10[1],ymm0[3],ymm10[3]+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x20, %ymm0, %ymm1, %ymm5 # ymm5 = ymm1[0,1],ymm0[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vmovdqu 0xe0(%rsp), %ymm4+ vperm2i128 $0x31, %ymm0, %ymm1, %ymm1 # ymm1 = ymm1[2,3],ymm0[2,3]+ vmovdqu 0x100(%rsp), %ymm0+ vmovdqu %ymm2, 0x1b0(%rdi)+ vmovdqu %ymm1, 0x278(%rdi)+ vpunpcklqdq %ymm4, %ymm14, %ymm2 # ymm2 = ymm14[0],ymm4[0],ymm14[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm14, %ymm1 # ymm1 = ymm14[1],ymm4[1],ymm14[3],ymm4[3]+ vpunpcklqdq %ymm8, %ymm0, %ymm4 # ymm4 = ymm0[0],ymm8[0],ymm0[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm8[1],ymm0[3],ymm8[3]+ vmovdqu %ymm6, 0x20(%rdi)+ vmovdqu %ymm5, 0xe8(%rdi)+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x20, %ymm0, %ymm1, %ymm5 # ymm5 = ymm1[0,1],ymm0[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vperm2i128 $0x31, %ymm0, %ymm1, %ymm1 # ymm1 = ymm1[2,3],ymm0[2,3]+ vmovdqu 0x120(%rsp), %ymm4+ vmovdqu 0x140(%rsp), %ymm0+ vmovdqu %ymm2, 0x1d0(%rdi)+ vmovdqu %ymm1, 0x298(%rdi)+ vpunpcklqdq %ymm4, %ymm15, %ymm2 # ymm2 = ymm15[0],ymm4[0],ymm15[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm15, %ymm1 # ymm1 = ymm15[1],ymm4[1],ymm15[3],ymm4[3]+ vpunpcklqdq %ymm9, %ymm0, %ymm4 # ymm4 = ymm0[0],ymm9[0],ymm0[2],ymm9[2]+ vmovdqu %ymm5, 0x108(%rdi)+ vpunpckhqdq %ymm9, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm9[1],ymm0[3],ymm9[3]+ vmovdqu %ymm6, 0x40(%rdi)+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vperm2i128 $0x20, %ymm0, %ymm1, %ymm5 # ymm5 = ymm1[0,1],ymm0[0,1]+ vmovdqu 0x160(%rsp), %ymm4+ vperm2i128 $0x31, %ymm0, %ymm1, %ymm1 # ymm1 = ymm1[2,3],ymm0[2,3]+ vmovdqu 0x180(%rsp), %ymm0+ vmovdqu %ymm5, 0x128(%rdi)+ vmovdqu 0x1a0(%rsp), %ymm5+ vmovdqu %ymm2, 0x1f0(%rdi)+ vpunpcklqdq %ymm0, %ymm4, %ymm2 # ymm2 = ymm4[0],ymm0[0],ymm4[2],ymm0[2]+ vpunpckhqdq %ymm0, %ymm4, %ymm0 # ymm0 = ymm4[1],ymm0[1],ymm4[3],ymm0[3]+ vpunpcklqdq %ymm5, %ymm13, %ymm4 # ymm4 = ymm13[0],ymm5[0],ymm13[2],ymm5[2]+ vmovdqu %ymm6, 0x60(%rdi)+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vmovdqu %ymm1, 0x2b8(%rdi)+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vpunpckhqdq %ymm5, %ymm13, %ymm1 # ymm1 = ymm13[1],ymm5[1],ymm13[3],ymm5[3]+ vmovdqu %ymm6, 0x80(%rdi)+ vmovdqu 0x1e0(%rsp), %ymm4+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm5 # ymm5 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm0 # ymm0 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm2, 0x210(%rdi)+ vpunpcklqdq %ymm3, %ymm12, %ymm2 # ymm2 = ymm12[0],ymm3[0],ymm12[2],ymm3[2]+ vmovdqu %ymm0, 0x2d8(%rdi)+ vpunpckhqdq %ymm3, %ymm12, %ymm0 # ymm0 = ymm12[1],ymm3[1],ymm12[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm7, %ymm3 # ymm3 = ymm7[0],ymm4[0],ymm7[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm7, %ymm1 # ymm1 = ymm7[1],ymm4[1],ymm7[3],ymm4[3]+ vmovdqu %ymm5, 0x148(%rdi)+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm5 # ymm5 = ymm2[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm3[2,3]+ vmovdqu 0x1c0(%rsp), %ymm3+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm4 # ymm4 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm0 # ymm0 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm5, 0xa0(%rdi)+ vextracti128 $0x1, %ymm3, %xmm15+ vmovdqu %ymm4, 0x168(%rdi)+ vmovdqu %ymm2, 0x230(%rdi)+ vmovdqu %ymm0, 0x2f8(%rdi)+ vmovq %xmm3, 0xc0(%rdi)+ vmovhpd %xmm3, 0x188(%rdi)+ vmovq %xmm15, 0x250(%rdi)+ vmovhpd %xmm15, 0x318(%rdi)+ movq %r11, %rsp+ .cfi_def_cfa_register %rsp+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(keccak_f1600_x4_avx2_asm)++#endif /* MLD_FIPS202_X86_64_NEED_X4_AVX2 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,52 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++#include "../../../../common.h"+#if defined(MLD_FIPS202_X86_64_NEED_X4_AVX2) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#include <stdint.h>++#include "fips202_native_x86_64.h"++MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const uint64_t+ mld_keccakf1600_round_constants[24] = {+ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a,+ 0x8000000080008000, 0x000000000000808b, 0x0000000080000001,+ 0x8000000080008081, 0x8000000000008009, 0x000000000000008a,+ 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,+ 0x000000008000808b, 0x800000000000008b, 0x8000000000008089,+ 0x8000000000008003, 0x8000000000008002, 0x8000000000000080,+ 0x000000000000800a, 0x800000008000000a, 0x8000000080008081,+ 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,+};++MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const uint64_t mld_keccak_rho8[4] = {+ 0x0605040302010007,+ 0x0e0d0c0b0a09080f,+ 0x1615141312111017,+ 0x1e1d1c1b1a19181f,+};++MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const uint64_t mld_keccak_rho56[4] = {+ 0x0007060504030201,+ 0x080f0e0d0c0b0a09,+ 0x1017161514131211,+ 0x181f1e1d1c1b1a19,+};++#else /* MLD_FIPS202_X86_64_NEED_X4_AVX2 && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++MLD_EMPTY_CU(fips202_x86_64_constants)++#endif /* !(MLD_FIPS202_X86_64_NEED_X4_AVX2 && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,314 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_NATIVE_AARCH64_META_H+#define MLD_NATIVE_AARCH64_META_H++/* Set of primitives that this backend replaces */+#define MLD_USE_NATIVE_NTT+#define MLD_USE_NATIVE_INTT+#define MLD_USE_NATIVE_REJ_UNIFORM+#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2+#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4+#define MLD_USE_NATIVE_POLY_DECOMPOSE_32+#define MLD_USE_NATIVE_POLY_DECOMPOSE_88+#define MLD_USE_NATIVE_POLY_CADDQ+#define MLD_USE_NATIVE_POLY_USE_HINT_32+#define MLD_USE_NATIVE_POLY_USE_HINT_88+#define MLD_USE_NATIVE_POLY_CHKNORM+#define MLD_USE_NATIVE_POLYZ_UNPACK_17+#define MLD_USE_NATIVE_POLYZ_UNPACK_19+#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY+#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4+#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5+#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7++/* Identifier for this backend so that source and assembly files+ * in the build can be appropriately guarded. */+#define MLD_ARITH_BACKEND_AARCH64+++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/arith_native_aarch64.h"++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_ntt_aarch64_asm(data, mld_aarch64_ntt_zetas_layer123456,+ mld_aarch64_ntt_zetas_layer78);+ return MLD_NATIVE_FUNC_SUCCESS;+}++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_intt_aarch64_asm(data, mld_aarch64_intt_zetas_layer78,+ mld_aarch64_intt_zetas_layer123456);+ return MLD_NATIVE_FUNC_SUCCESS;+}++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON) || len != MLDSA_N ||+ buflen % 24 != 0)+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */+ return (int)mld_rej_uniform_aarch64_asm(r, buf, buflen,+ mld_rej_uniform_table);+}++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 2+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+{+ uint64_t outlen;+ /* AArch64 implementation assumes specific buffer lengths */+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON) || len != MLDSA_N ||+ buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN)+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ /* Constant time: Inputs and outputs to this function are secret.+ * It is safe to leak which coefficients are accepted/rejected.+ * The assembly implementation must not leak any other information about the+ * accepted coefficients. Constant-time testing cannot cover this, and we+ * hence have to manually verify the assembly.+ * We declassify prior the input data and mark the outputs as secret.+ */+ MLD_CT_TESTING_DECLASSIFY(buf, buflen);+ outlen = mld_rej_uniform_eta2_aarch64_asm(r, buf, buflen,+ mld_rej_uniform_eta_table);+ MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen);+ /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */+ return (int)outlen;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_ETA == 2 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 4+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+{+ uint64_t outlen;+ /* AArch64 implementation assumes specific buffer lengths */+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON) || len != MLDSA_N ||+ buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN)+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ /* Constant time: Inputs and outputs to this function are secret.+ * It is safe to leak which coefficients are accepted/rejected.+ * The assembly implementation must not leak any other information about the+ * accepted coefficients. Constant-time testing cannot cover this, and we+ * hence have to manually verify the assembly.+ * We declassify prior the input data and mark the outputs as secret.+ */+ MLD_CT_TESTING_DECLASSIFY(buf, buflen);+ outlen = mld_rej_uniform_eta4_aarch64_asm(r, buf, buflen,+ mld_rej_uniform_eta_table);+ MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen);+ /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */+ return (int)outlen;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_ETA == 4 */+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_decompose_32_aarch64_asm(a1, a0);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_decompose_88_aarch64_asm(a1, a0);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */+#endif /* !MLD_CONFIG_NO_SIGN_API */++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_caddq_aarch64_asm(a);+ return MLD_NATIVE_FUNC_SUCCESS;+}++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *a, const int32_t *h)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_use_hint_32_aarch64_asm(a, h);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *a, const int32_t *h)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_use_hint_88_aarch64_asm(a, h);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */+#endif /* !MLD_CONFIG_NO_VERIFY_API */++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ return mld_poly_chknorm_aarch64_asm(a, B);+}++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_polyz_unpack_17_aarch64_asm(r, buf, mld_polyz_unpack_17_indices);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_polyz_unpack_19_aarch64_asm(r, buf, mld_polyz_unpack_19_indices);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_pointwise_montgomery_native(+ int32_t a[MLDSA_N], const int32_t b[MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_pointwise_montgomery_aarch64_asm(a, b);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 4+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native(+ int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N],+ const int32_t v[4][MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm(w, u, v);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 4 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 5+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native(+ int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N],+ const int32_t v[5][MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm(w, u, v);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 5 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 7+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native(+ int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N],+ const int32_t v[7][MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_AARCH64_NEON))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm(w, u, v);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 7 */++#endif /* !__ASSEMBLER__ */+#endif /* !MLD_NATIVE_AARCH64_META_H */
@@ -0,0 +1,248 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#include "arith_native_aarch64.h"++/*+ * Table of zeta values used in the AArch64 forward NTT+ * See autogen for details.+ */+MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const int32_t+ mld_aarch64_ntt_zetas_layer123456[144] = {+ -3572223, -915382907, 3765607, 964937599, 3761513, 963888510,+ -3201494, -820383522, -2883726, -738955404, -3145678, -806080660,+ -3201430, -820367122, 0, 0, -601683, -154181397,+ -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133,+ 3182878, 815613168, 2740543, 702264730, -3586446, -919027554,+ 0, 0, 3542485, 907762539, 2663378, 682491182,+ -1674615, -429120452, -3110818, -797147778, 2101410, 538486762,+ 3704823, 949361686, 1159875, 297218217, 0, 0,+ 2682288, 687336873, -3524442, -903139016, -434125, -111244624,+ 394148, 101000509, 928749, 237992130, 1095468, 280713909,+ -3506380, -898510625, 0, 0, 2129892, 545785280,+ 676590, 173376332, -1335936, -342333886, 2071829, 530906624,+ -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273,+ 0, 0, 3764867, 964747974, -3227876, -827143915,+ 1714295, 439288460, 3415069, 875112161, 1759347, 450833045,+ -817536, -209493775, -3574466, -915957677, 0, 0,+ -1005239, -257592709, 2453983, 628833668, 1460718, 374309300,+ 3756790, 962678241, -1935799, -496048908, -1716988, -439978542,+ -3950053, -1012201926, 0, 0, 557458, 142848732,+ -642628, -164673562, -3585098, -918682129, -2897314, -742437332,+ 3192354, 818041395, 556856, 142694469, 3870317, 991769559,+ 0, 0, -1221177, -312926867, 2815639, 721508096,+ 2283733, 585207070, 2917338, 747568486, 1853806, 475038184,+ 3345963, 857403734, 1858416, 476219497, 0, 0,+};++MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const int32_t+ mld_aarch64_ntt_zetas_layer78[384] = {+ 3073009, 1277625, -2635473, 3852015, 787459213,+ 327391679, -675340520, 987079667, 1753, -2659525,+ 2660408, -59148, 449207, -681503850, 681730119,+ -15156688, -1935420, -1455890, -1780227, 2772600,+ -495951789, -373072124, -456183549, 710479343, 4183372,+ -3222807, -3121440, -274060, 1071989969, -825844983,+ -799869667, -70227934, 1182243, 636927, -3956745,+ -3284915, 302950022, 163212680, -1013916752, -841760171,+ 87208, -3965306, -2296397, -3716946, 22347069,+ -1016110510, -588452222, -952468207, 2508980, 2028118,+ 1937570, -3815725, 642926661, 519705671, 496502727,+ -977780347, -27812, 1009365, -1979497, -3956944,+ -7126831, 258649997, -507246529, -1013967746, 822541,+ -2454145, 1596822, -3759465, 210776307, -628875181,+ 409185979, -963363710, 2811291, -2983781, -1109516,+ 4158088, 720393920, -764594519, -284313712, 1065510939,+ -1685153, 2678278, -3551006, -250446, -431820817,+ 686309310, -909946047, -64176841, -3410568, -3768948,+ 635956, -2455377, -873958779, -965793731, 162963861,+ -629190881, 1528066, 482649, 1148858, -2962264,+ 391567239, 123678909, 294395108, -759080783, -4146264,+ 2192938, 2387513, -268456, -1062481036, 561940831,+ 611800717, -68791907, -1772588, -1727088, -3611750,+ -3180456, -454226054, -442566669, -925511710, -814992530,+ -565603, 169688, 2462444, -3334383, -144935890,+ 43482586, 631001801, -854436357, 3747250, 1239911,+ 3195676, 1254190, 960233614, 317727459, 818892658,+ 321386456, 2296099, -3838479, 2642980, -12417,+ 588375860, -983611064, 677264190, -3181859, -4166425,+ -3488383, 1987814, -3197248, -1067647297, -893898890,+ 509377762, -819295484, 2998219, -89301, -1354892,+ -1310261, 768294260, -22883400, -347191365, -335754661,+ 141835, 2513018, 613238, -2218467, 36345249,+ 643961400, 157142369, -568482643, 1736313, 235407,+ -3250154, 3258457, 444930577, 60323094, -832852657,+ 834980303, -458740, 4040196, 2039144, -818761,+ -117552223, 1035301089, 522531086, -209807681, -1921994,+ -3472069, -1879878, -2178965, -492511373, -889718424,+ -481719139, -558360247, -2579253, 1787943, -2391089,+ -2254727, -660934133, 458160776, -612717067, -577774276,+ -1623354, -2374402, 586241, 527981, -415984810,+ -608441020, 150224382, 135295244, 2105286, -2033807,+ -1179613, -2743411, 539479988, -521163479, -302276083,+ -702999655, 3482206, -4182915, -1300016, -2362063,+ 892316032, -1071872863, -333129378, -605279149, -1476985,+ 2491325, 507927, -724804, -378477722, 638402564,+ 130156402, -185731180, 1994046, -1393159, -1187885,+ -1834526, 510974714, -356997292, -304395785, -470097680,+ -1317678, 2461387, 3035980, 621164, -337655269,+ 630730945, 777970524, 159173408, -3033742, 2647994,+ -2612853, 749577, -777397036, 678549029, -669544140,+ 192079267, -338420, 3009748, 4148469, -4022750,+ -86720197, 771248568, 1063046068, -1030830548, 3901472,+ -1226661, 2925816, 3374250, 999753034, -314332144,+ 749740976, 864652284, 3980599, -1615530, 1665318,+ 1163598, 1020029345, -413979908, 426738094, 298172236,+ 2569011, 1723229, 2028038, -3369273, 658309618,+ 441577800, 519685171, -863376927, 1356448, -2775755,+ 2683270, -2778788, 347590090, -711287812, 687588511,+ -712065019, 3994671, -1370517, 3363542, 545376,+ 1023635298, -351195274, 861908357, 139752717, -11879,+ 3020393, 214880, -770441, -3043996, 773976352,+ 55063046, -197425671, -3467665, 2312838, -653275,+ -459163, -888589898, 592665232, -167401858, -117660617,+ 3105558, 508145, 860144, 140244, 795799901,+ 130212265, 220412084, 35937555, -1103344, -553718,+ 3430436, -1514152, -282732136, -141890356, 879049958,+ -388001774, 348812, -327848, 1011223, -2354215,+ 89383150, -84011120, 259126110, -603268097, -2185084,+ 2358373, -3014420, 2926054, -559928242, 604333585,+ -772445769, 749801963, 3123762, -2193087, -1716814,+ -392707, 800464680, -561979013, -439933955, -100631253,+ -3818627, -1922253, -2236726, 1744507, -978523985,+ -492577742, -573161516, 447030292, -303005, -3974485,+ 1900052, 1054478, -77645096, -1018462631, 486888731,+ 270210213, 3531229, -3773731, -781875, -731434,+ 904878186, -967019376, -200355636, -187430119,+};++MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const int32_t+ mld_aarch64_intt_zetas_layer78[384] = {+ -1744507, 2236726, 1922253, 3818627, -447030292,+ 573161516, 492577742, 978523985, 731434, 781875,+ 3773731, -3531229, 187430119, 200355636, 967019376,+ -904878186, -1054478, -1900052, 3974485, 303005,+ -270210213, -486888731, 1018462631, 77645096, 2354215,+ -1011223, 327848, -348812, 603268097, -259126110,+ 84011120, -89383150, 392707, 1716814, 2193087,+ -3123762, 100631253, 439933955, 561979013, -800464680,+ -2926054, 3014420, -2358373, 2185084, -749801963,+ 772445769, -604333585, 559928242, 459163, 653275,+ -2312838, 3467665, 117660617, 167401858, -592665232,+ 888589898, 1514152, -3430436, 553718, 1103344,+ 388001774, -879049958, 141890356, 282732136, -140244,+ -860144, -508145, -3105558, -35937555, -220412084,+ -130212265, -795799901, 2778788, -2683270, 2775755,+ -1356448, 712065019, -687588511, 711287812, -347590090,+ 770441, -214880, -3020393, 11879, 197425671,+ -55063046, -773976352, 3043996, -545376, -3363542,+ 1370517, -3994671, -139752717, -861908357, 351195274,+ -1023635298, -3374250, -2925816, 1226661, -3901472,+ -864652284, -749740976, 314332144, -999753034, 3369273,+ -2028038, -1723229, -2569011, 863376927, -519685171,+ -441577800, -658309618, -1163598, -1665318, 1615530,+ -3980599, -298172236, -426738094, 413979908, -1020029345,+ -621164, -3035980, -2461387, 1317678, -159173408,+ -777970524, -630730945, 337655269, 4022750, -4148469,+ -3009748, 338420, 1030830548, -1063046068, -771248568,+ 86720197, -749577, 2612853, -2647994, 3033742,+ -192079267, 669544140, -678549029, 777397036, 2362063,+ 1300016, 4182915, -3482206, 605279149, 333129378,+ 1071872863, -892316032, 1834526, 1187885, 1393159,+ -1994046, 470097680, 304395785, 356997292, -510974714,+ 724804, -507927, -2491325, 1476985, 185731180,+ -130156402, -638402564, 378477722, 2254727, 2391089,+ -1787943, 2579253, 577774276, 612717067, -458160776,+ 660934133, 2743411, 1179613, 2033807, -2105286,+ 702999655, 302276083, 521163479, -539479988, -527981,+ -586241, 2374402, 1623354, -135295244, -150224382,+ 608441020, 415984810, -3258457, 3250154, -235407,+ -1736313, -834980303, 832852657, -60323094, -444930577,+ 2178965, 1879878, 3472069, 1921994, 558360247,+ 481719139, 889718424, 492511373, 818761, -2039144,+ -4040196, 458740, 209807681, -522531086, -1035301089,+ 117552223, 3197248, -1987814, 3488383, 4166425,+ 819295484, -509377762, 893898890, 1067647297, 2218467,+ -613238, -2513018, -141835, 568482643, -157142369,+ -643961400, -36345249, 1310261, 1354892, 89301,+ -2998219, 335754661, 347191365, 22883400, -768294260,+ 3334383, -2462444, -169688, 565603, 854436357,+ -631001801, -43482586, 144935890, 12417, -2642980,+ 3838479, -2296099, 3181859, -677264190, 983611064,+ -588375860, -1254190, -3195676, -1239911, -3747250,+ -321386456, -818892658, -317727459, -960233614, 2962264,+ -1148858, -482649, -1528066, 759080783, -294395108,+ -123678909, -391567239, 3180456, 3611750, 1727088,+ 1772588, 814992530, 925511710, 442566669, 454226054,+ 268456, -2387513, -2192938, 4146264, 68791907,+ -611800717, -561940831, 1062481036, -4158088, 1109516,+ 2983781, -2811291, -1065510939, 284313712, 764594519,+ -720393920, 2455377, -635956, 3768948, 3410568,+ 629190881, -162963861, 965793731, 873958779, 250446,+ 3551006, -2678278, 1685153, 64176841, 909946047,+ -686309310, 431820817, 3815725, -1937570, -2028118,+ -2508980, 977780347, -496502727, -519705671, -642926661,+ 3759465, -1596822, 2454145, -822541, 963363710,+ -409185979, 628875181, -210776307, 3956944, 1979497,+ -1009365, 27812, 1013967746, 507246529, -258649997,+ 7126831, 274060, 3121440, 3222807, -4183372,+ 70227934, 799869667, 825844983, -1071989969, 3716946,+ 2296397, 3965306, -87208, 952468207, 588452222,+ 1016110510, -22347069, 3284915, 3956745, -636927,+ -1182243, 841760171, 1013916752, -163212680, -302950022,+ -3852015, 2635473, -1277625, -3073009, -987079667,+ 675340520, -327391679, -787459213, -2772600, 1780227,+ 1455890, 1935420, -710479343, 456183549, 373072124,+ 495951789, 59148, -2660408, 2659525, -1753,+ 15156688, -681730119, 681503850, -449207,+};++MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const int32_t+ mld_aarch64_intt_zetas_layer123456[160] = {+ -2283733, -585207070, 0, 0, -1858416, -476219497,+ -3345963, -857403734, -2815639, -721508096, 0, 0,+ -1853806, -475038184, -2917338, -747568486, 3585098, 918682129,+ 0, 0, -3870317, -991769559, -556856, -142694469,+ 642628, 164673562, 0, 0, -3192354, -818041395,+ 2897314, 742437332, -1460718, -374309300, 0, 0,+ 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668,+ 0, 0, 1935799, 496048908, -3756790, -962678241,+ -1714295, -439288460, 0, 0, 3574466, 915957677,+ 817536, 209493775, 3227876, 827143915, 0, 0,+ -1759347, -450833045, -3415069, -875112161, 1335936, 342333886,+ 0, 0, -2156050, -552488273, -3241972, -830756018,+ -676590, -173376332, 0, 0, 4018989, 1029866791,+ -2071829, -530906624, 434125, 111244624, 0, 0,+ 3506380, 898510625, -1095468, -280713909, 3524442, 903139016,+ 0, 0, -928749, -237992130, -394148, -101000509,+ 1674615, 429120452, 0, 0, -1159875, -297218217,+ -3704823, -949361686, -2663378, -682491182, 0, 0,+ -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200,+ 0, 0, 3586446, 919027554, -2740543, -702264730,+ 3370349, 863652652, 0, 0, -3182878, -815613168,+ -3602218, -923069133, -294725, -75523344, -3761513, -963888510,+ -3765607, -964937599, 3201430, 820367122, 3145678, 806080660,+ 2883726, 738955404, 3201494, 820383522, 1221177, 312926867,+ -557458, -142848732, 1005239, 257592709, -3764867, -964747974,+ -2129892, -545785280, -2682288, -687336873, -3542485, -907762539,+ 601683, 154181397, 0, 0,+};++#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++MLD_EMPTY_CU(aarch64_zetas)++#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,367 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H+#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H++#include "../../../cbmc.h"+#include "../../../common.h"++#define mld_aarch64_ntt_zetas_layer123456 \+ MLD_NAMESPACE(aarch64_ntt_zetas_layer123456)+#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78)++#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78)+#define mld_aarch64_intt_zetas_layer123456 \+ MLD_NAMESPACE(aarch64_intt_zetas_layer123456)++MLD_INTERNAL_DATA_DECLARATION const int32_t+ mld_aarch64_ntt_zetas_layer123456[144];+MLD_INTERNAL_DATA_DECLARATION const int32_t mld_aarch64_ntt_zetas_layer78[384];++MLD_INTERNAL_DATA_DECLARATION const int32_t mld_aarch64_intt_zetas_layer78[384];+MLD_INTERNAL_DATA_DECLARATION const int32_t+ mld_aarch64_intt_zetas_layer123456[160];++#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table)+MLD_INTERNAL_DATA_DECLARATION const uint8_t mld_rej_uniform_table[256];+#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table)+MLD_INTERNAL_DATA_DECLARATION const uint8_t mld_rej_uniform_eta_table[4096];+#endif++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices)+MLD_INTERNAL_DATA_DECLARATION const uint8_t mld_polyz_unpack_17_indices[64];+#endif+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices)+MLD_INTERNAL_DATA_DECLARATION const uint8_t mld_polyz_unpack_19_indices[64];+#endif+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */+++/*+ * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits.+ * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes.+ * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially.+ * Sampling 2 blocks initially results in slightly worse performance.+ */+#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136)+/*+ * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits.+ * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes.+ * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially.+ */+#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136)++#define mld_ntt_aarch64_asm MLD_NAMESPACE(ntt_aarch64_asm)+void mld_ntt_aarch64_asm(int32_t r[MLDSA_N], const int32_t zetas_l123456[144],+ const int32_t zetas_l78[384])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_ntt_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ /* check-magic: 8380417 == MLDSA_Q */+ requires(array_abs_bound(r, 0, MLDSA_N, 8380417))+ requires(zetas_l123456 == mld_aarch64_ntt_zetas_layer123456)+ requires(zetas_l78 == mld_aarch64_ntt_zetas_layer78)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ /* check-magic: off */+ ensures(array_abs_bound(r, 0, MLDSA_N, 75423753))+ /* check-magic: on */+);++#define mld_intt_aarch64_asm MLD_NAMESPACE(intt_aarch64_asm)+void mld_intt_aarch64_asm(int32_t r[MLDSA_N], const int32_t zetas_l78[384],+ const int32_t zetas_l123456[160])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_intt_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(r, 0, MLDSA_N, 8380417))+ requires(zetas_l78 == mld_aarch64_intt_zetas_layer78)+ requires(zetas_l123456 == mld_aarch64_intt_zetas_layer123456)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ /* check-magic: off */+ ensures(array_abs_bound(r, 0, MLDSA_N, 8380417))+ /* check-magic: on */+);++#define mld_rej_uniform_aarch64_asm MLD_NAMESPACE(rej_uniform_aarch64_asm)+MLD_MUST_CHECK_RETURN_VALUE+uint64_t mld_rej_uniform_aarch64_asm(int32_t r[MLDSA_N], const uint8_t *buf,+ unsigned buflen, const uint8_t table[256])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_aarch64_asm.ml. */+__contract__(+ requires(buflen % 24 == 0)+ requires(memory_no_alias(buf, buflen))+ requires(table == mld_rej_uniform_table)+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(return_value <= MLDSA_N)+ ensures(array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q))+);++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_rej_uniform_eta2_aarch64_asm \+ MLD_NAMESPACE(rej_uniform_eta2_aarch64_asm)+MLD_MUST_CHECK_RETURN_VALUE+uint64_t mld_rej_uniform_eta2_aarch64_asm(int32_t r[MLDSA_N],+ const uint8_t *buf, unsigned buflen,+ const uint8_t table[4096])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta2_aarch64_asm.ml */+__contract__(+ requires(buflen % 8 == 0)+ requires(buflen >= 8)+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(buf, buflen))+ requires(table == mld_rej_uniform_eta_table)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(return_value <= MLDSA_N)+ /* check-magic: 3 == 2 + 1 (asm is eta=2-specific) */+ ensures(array_abs_bound(r, 0, return_value, 3))+);++#define mld_rej_uniform_eta4_aarch64_asm \+ MLD_NAMESPACE(rej_uniform_eta4_aarch64_asm)+MLD_MUST_CHECK_RETURN_VALUE+uint64_t mld_rej_uniform_eta4_aarch64_asm(int32_t r[MLDSA_N],+ const uint8_t *buf, unsigned buflen,+ const uint8_t table[4096])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta4_aarch64_asm.ml */+__contract__(+ requires(buflen % 8 == 0)+ requires(buflen >= 8)+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(buf, buflen))+ requires(table == mld_rej_uniform_eta_table)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(return_value <= MLDSA_N)+ /* check-magic: 5 == 4 + 1 (asm is eta=4-specific) */+ ensures(array_abs_bound(r, 0, return_value, 5))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_poly_decompose_32_aarch64_asm \+ MLD_NAMESPACE(poly_decompose_32_aarch64_asm)+void mld_poly_decompose_32_aarch64_asm(int32_t a1[MLDSA_N], int32_t a0[MLDSA_N])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_poly_decompose_32_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N))+ assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N))+ /* check-magic: 16 == (MLDSA_Q - 1) / (2 * ((MLDSA_Q - 1) / 32)) */+ ensures(array_bound(a1, 0, MLDSA_N, 0, 16))+ /* check-magic: 261889 == (MLDSA_Q - 1) / 32 + 1 */+ ensures(array_abs_bound(a0, 0, MLDSA_N, 261889))+);++#define mld_poly_decompose_88_aarch64_asm \+ MLD_NAMESPACE(poly_decompose_88_aarch64_asm)+void mld_poly_decompose_88_aarch64_asm(int32_t a1[MLDSA_N], int32_t a0[MLDSA_N])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_poly_decompose_88_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N))+ assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N))+ /* check-magic: 44 == (MLDSA_Q - 1) / (2 * ((MLDSA_Q - 1) / 88)) */+ ensures(array_bound(a1, 0, MLDSA_N, 0, 44))+ /* check-magic: 95233 == (MLDSA_Q - 1) / 88 + 1 */+ ensures(array_abs_bound(a0, 0, MLDSA_N, 95233))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#define mld_poly_caddq_aarch64_asm MLD_NAMESPACE(poly_caddq_aarch64_asm)+void mld_poly_caddq_aarch64_asm(int32_t a[MLDSA_N])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_poly_caddq_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ ensures(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))+);++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_poly_use_hint_32_aarch64_asm \+ MLD_NAMESPACE(poly_use_hint_32_aarch64_asm)+void mld_poly_use_hint_32_aarch64_asm(int32_t a[MLDSA_N],+ const int32_t h[MLDSA_N])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_poly_use_hint_32_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))+ requires(array_bound(h, 0, MLDSA_N, 0, 2))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ ensures(array_bound(a, 0, MLDSA_N, 0, 16))+);++#define mld_poly_use_hint_88_aarch64_asm \+ MLD_NAMESPACE(poly_use_hint_88_aarch64_asm)+void mld_poly_use_hint_88_aarch64_asm(int32_t a[MLDSA_N],+ const int32_t h[MLDSA_N])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_poly_use_hint_88_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))+ requires(array_bound(h, 0, MLDSA_N, 0, 2))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ ensures(array_bound(a, 0, MLDSA_N, 0, 44))+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#define mld_poly_chknorm_aarch64_asm MLD_NAMESPACE(poly_chknorm_aarch64_asm)+MLD_MUST_CHECK_RETURN_VALUE+int mld_poly_chknorm_aarch64_asm(const int32_t a[MLDSA_N], int32_t B)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_poly_chknorm_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ /* HOL Light precondition: abs(ival(x i)) < 2^31, i.e., a[i] != INT32_MIN */+ requires(forall(k0, 0, MLDSA_N, a[k0] > INT32_MIN))+ ensures(return_value == 0 || return_value == 1)+ ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B))+);++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+#define mld_polyz_unpack_17_aarch64_asm \+ MLD_NAMESPACE(polyz_unpack_17_aarch64_asm)+void mld_polyz_unpack_17_aarch64_asm(int32_t r[MLDSA_N], const uint8_t buf[576],+ const uint8_t indices[64])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_polyz_unpack_17_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(buf, 576))+ requires(indices == mld_polyz_unpack_17_indices)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_bound(r, 0, MLDSA_N, -((1 << 17) - 1), (1 << 17) + 1))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+#define mld_polyz_unpack_19_aarch64_asm \+ MLD_NAMESPACE(polyz_unpack_19_aarch64_asm)+void mld_polyz_unpack_19_aarch64_asm(int32_t r[MLDSA_N], const uint8_t buf[640],+ const uint8_t indices[64])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_polyz_unpack_19_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(buf, 640))+ requires(indices == mld_polyz_unpack_19_indices)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_bound(r, 0, MLDSA_N, -((1 << 19) - 1), (1 << 19) + 1))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+#define mld_poly_pointwise_montgomery_aarch64_asm \+ MLD_NAMESPACE(poly_pointwise_montgomery_aarch64_asm)+void mld_poly_pointwise_montgomery_aarch64_asm(int32_t a[MLDSA_N],+ const int32_t b[MLDSA_N])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mldsa_pointwise_montgomery_aarch64_asm.ml+ */+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N))+ /* Input bound MLD_NTT_BOUND = 9 * MLD_FQMUL_BOUND, the guaranteed bound of+ * any forward NTT implementation. Hardcoded here to keep this header free+ * of poly.h. */+ /* check-magic: 94279698 == 9 * ((5 * MLDSA_Q + 3) / 4) */+ requires(array_abs_bound(a, 0, MLDSA_N, 94279698))+ requires(array_abs_bound(b, 0, MLDSA_N, 94279698))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(a, 0, MLDSA_N, 8380417))+);+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#define mld_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm \+ MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_aarch64_asm)+void mld_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm(+ int32_t r[MLDSA_N], const int32_t a[4][MLDSA_N],+ const int32_t b[4][MLDSA_N])+/* This must be kept in sync with the HOL-Light specification+ * in+ * proofs/hol_light/aarch64/proofs/mldsa_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm.ml+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, sizeof(int32_t) * 4 * MLDSA_N))+ requires(memory_no_alias(b, sizeof(int32_t) * 4 * MLDSA_N))+ requires(forall(l0, 0, 4, array_abs_bound(a[l0], 0, MLDSA_N, 8380417)))+ /* check-magic: 94279698 == 9 * ((5 * MLDSA_Q + 3) / 4) */+ requires(forall(l1, 0, 4, array_abs_bound(b[l1], 0, MLDSA_N, 94279698)))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(r, 0, MLDSA_N, 8380417))+);++#define mld_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm \+ MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_aarch64_asm)+void mld_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm(+ int32_t r[MLDSA_N], const int32_t a[5][MLDSA_N],+ const int32_t b[5][MLDSA_N])+/* This must be kept in sync with the HOL-Light specification+ * in+ * proofs/hol_light/aarch64/proofs/mldsa_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm.ml+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, sizeof(int32_t) * 5 * MLDSA_N))+ requires(memory_no_alias(b, sizeof(int32_t) * 5 * MLDSA_N))+ requires(forall(l0, 0, 5, array_abs_bound(a[l0], 0, MLDSA_N, 8380417)))+ /* check-magic: 94279698 == 9 * ((5 * MLDSA_Q + 3) / 4) */+ requires(forall(l1, 0, 5, array_abs_bound(b[l1], 0, MLDSA_N, 94279698)))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(r, 0, MLDSA_N, 8380417))+);++#define mld_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm \+ MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_aarch64_asm)+void mld_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm(+ int32_t r[MLDSA_N], const int32_t a[7][MLDSA_N],+ const int32_t b[7][MLDSA_N])+/* This must be kept in sync with the HOL-Light specification+ * in+ * proofs/hol_light/aarch64/proofs/mldsa_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm.ml+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, sizeof(int32_t) * 7 * MLDSA_N))+ requires(memory_no_alias(b, sizeof(int32_t) * 7 * MLDSA_N))+ requires(forall(l0, 0, 7, array_abs_bound(a[l0], 0, MLDSA_N, 8380417)))+ /* check-magic: 94279698 == 9 * ((5 * MLDSA_Q + 3) / 4) */+ requires(forall(l1, 0, 7, array_abs_bound(b[l1], 0, MLDSA_N, 94279698)))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(r, 0, MLDSA_N, 8380417))+);++#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */
@@ -0,0 +1,786 @@+/* Copyright (c) 2022 Arm Limited+ * Copyright (c) 2022 Hanno Becker+ * Copyright (c) 2023 Amin Abdulrahman, Matthias Kannwischer+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [NeonNTT]+ * Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1+ * Becker, Hwang, Kannwischer, Yang, Yang+ * https://eprint.iacr.org/2021/986+ *+ * - [NeonNTT_Autoformalised]+ * Neon NTT - (Auto)formalised+ * Hanno Becker+ * https://eprint.iacr.org/2026/1223+ *+ * - [SLOTHY_Paper]+ * Fast and Clean: Auditable high-performance assembly via constraint solving+ * Abdulrahman, Becker, Kannwischer, Klein+ * https://eprint.iacr.org/2022/1303+ */++/* AArch64 ML-DSA inverse NTT following @[NeonNTT], @[SLOTHY_Paper], and @[NeonNTT_Autoformalised] */++/*yaml+ Name: intt_aarch64_asm+ Description: AArch64 ML-DSA inverse NTT+ Signature: void mld_intt_aarch64_asm(int32_t r[256], const int32_t zetas_l78[384], const int32_t zetas_l123456[160])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t r[256]+ description: Input/output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 1536+ permissions: read-only+ c_parameter: const int32_t zetas_l78[384]+ description: Twiddle factors for layers 7-8 (384 x int32_t)+ x2:+ type: buffer+ size_bytes: 640+ permissions: read-only+ c_parameter: const int32_t zetas_l123456[160]+ description: Twiddle factors for layers 1-6 (160 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_intt_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(intt_aarch64_asm)+MLD_ASM_FN_SYMBOL(intt_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ mov w5, #0xe001 // =57345+ movk w5, #0x7f, lsl #16+ dup v31.4s, w5+ mov x3, x0+ mov x4, #0x10 // =16+ ldr q27, [x3, #0x10]+ ldr q18, [x3]+ ldr q3, [x3, #0x20]+ ldr q13, [x3, #0x30]+ ldr q2, [x1, #0x30]+ ldr q8, [x3, #0x70]+ ldr q21, [x3, #0x60]+ trn1 v10.4s, v18.4s, v27.4s+ trn2 v23.4s, v18.4s, v27.4s+ trn1 v6.4s, v3.4s, v13.4s+ trn2 v18.4s, v3.4s, v13.4s+ ldr q12, [x1, #0x50]+ ldr q17, [x1, #0x40]+ trn2 v29.2d, v10.2d, v6.2d+ trn2 v14.2d, v23.2d, v18.2d+ trn1 v10.2d, v10.2d, v6.2d+ trn1 v26.2d, v23.2d, v18.2d+ sub v3.4s, v29.4s, v14.4s+ trn1 v13.4s, v21.4s, v8.4s+ ldr q6, [x1, #0x10]+ add v24.4s, v10.4s, v26.4s+ sub v30.4s, v10.4s, v26.4s+ sqrdmulh v12.4s, v3.4s, v12.4s+ ldr q9, [x1, #0x20]+ sqrdmulh v5.4s, v30.4s, v2.4s+ mul v4.4s, v3.4s, v17.4s+ ldr q3, [x3, #0x50]+ add v10.4s, v29.4s, v14.4s+ ldr q26, [x3, #0x40]+ mul v15.4s, v30.4s, v9.4s+ trn2 v30.4s, v21.4s, v8.4s+ sub v21.4s, v24.4s, v10.4s+ add v29.4s, v24.4s, v10.4s+ mls v15.4s, v5.4s, v31.s[0]+ ldr q16, [x1], #0x60+ trn2 v10.4s, v26.4s, v3.4s+ mls v4.4s, v12.4s, v31.s[0]+ trn1 v3.4s, v26.4s, v3.4s+ ldr q0, [x1, #0x50]+ trn2 v25.2d, v10.2d, v30.2d+ sqrdmulh v12.4s, v21.4s, v6.4s+ trn2 v1.2d, v3.2d, v13.2d+ mul v21.4s, v21.4s, v16.4s+ sub v23.4s, v1.4s, v25.4s+ sub v2.4s, v15.4s, v4.4s+ add v20.4s, v15.4s, v4.4s+ sqrdmulh v4.4s, v23.4s, v0.4s+ trn1 v7.2d, v3.2d, v13.2d+ sqrdmulh v3.4s, v2.4s, v6.4s+ trn1 v15.2d, v10.2d, v30.2d+ mls v21.4s, v12.4s, v31.s[0]+ ldr q12, [x1, #0x30]+ sub v13.4s, v7.4s, v15.4s+ mul v10.4s, v2.4s, v16.4s+ ldr q16, [x1, #0x40]+ ldr q5, [x1, #0x20]+ mls v10.4s, v3.4s, v31.s[0]+ trn2 v11.4s, v29.4s, v20.4s+ sqrdmulh v2.4s, v13.4s, v12.4s+ ldr d9, [x2], #0x20+ mul v17.4s, v13.4s, v5.4s+ trn1 v24.4s, v29.4s, v20.4s+ trn1 v12.4s, v21.4s, v10.4s+ trn2 v10.4s, v21.4s, v10.4s+ mul v22.4s, v23.4s, v16.4s+ ldur q26, [x2, #-0x10]+ trn1 v13.2d, v24.2d, v12.2d+ trn1 v3.2d, v11.2d, v10.2d+ mls v17.4s, v2.4s, v31.s[0]+ mls v22.4s, v4.4s, v31.s[0]+ sub v23.4s, v13.4s, v3.4s+ trn2 v10.2d, v11.2d, v10.2d+ sqrdmulh v0.4s, v23.4s, v26.s[1]+ trn2 v21.2d, v24.2d, v12.2d+ mul v29.4s, v23.4s, v26.s[0]+ sub v23.4s, v21.4s, v10.4s+ sqrdmulh v8.4s, v23.4s, v26.s[3]+ add v6.4s, v1.4s, v25.4s+ add v11.4s, v21.4s, v10.4s+ mls v29.4s, v0.4s, v31.s[0]+ add v30.4s, v13.4s, v3.4s+ ldr q2, [x1, #0x10]+ mul v3.4s, v23.4s, v26.s[2]+ add v12.4s, v7.4s, v15.4s+ mls v3.4s, v8.4s, v31.s[0]+ sub v13.4s, v30.4s, v11.4s+ sub v21.4s, v12.4s, v6.4s+ add v26.4s, v17.4s, v22.4s+ sqrdmulh v28.4s, v13.4s, v9.s[1]+ mul v18.4s, v13.4s, v9.s[0]+ sub v8.4s, v29.4s, v3.4s+ sqrdmulh v24.4s, v21.4s, v2.4s+ add v15.4s, v30.4s, v11.4s+ add v10.4s, v29.4s, v3.4s+ add v14.4s, v12.4s, v6.4s+ sqrdmulh v16.4s, v8.4s, v9.s[1]+ sub v3.4s, v17.4s, v22.4s+ mul v8.4s, v8.4s, v9.s[0]+ ldr q17, [x1], #0x60+ sub x4, x4, #0x2++Lmld_intt_layer5678_start:+ ldr d4, [x2], #0x20+ mul v0.4s, v21.4s, v17.4s+ ldr q7, [x3, #0xa0]+ ldr q27, [x3, #0xb0]+ mls v8.4s, v16.4s, v31.s[0]+ ldr q29, [x3, #0x80]+ trn1 v9.4s, v14.4s, v26.4s+ ldr q25, [x3, #0x90]+ mls v0.4s, v24.4s, v31.s[0]+ str q15, [x3], #0x40+ trn1 v1.4s, v7.4s, v27.4s+ ldr q15, [x1, #0x50]+ trn2 v12.4s, v7.4s, v27.4s+ sqrdmulh v16.4s, v3.4s, v2.4s+ trn1 v21.4s, v29.4s, v25.4s+ stur q8, [x3, #-0x10]+ trn2 v19.4s, v29.4s, v25.4s+ mls v18.4s, v28.4s, v31.s[0]+ ldr q22, [x1, #0x30]+ trn2 v13.2d, v21.2d, v1.2d+ trn2 v5.2d, v19.2d, v12.2d+ mul v23.4s, v3.4s, v17.4s+ trn1 v17.2d, v21.2d, v1.2d+ ldr q29, [x1, #0x40]+ mls v23.4s, v16.4s, v31.s[0]+ sub v30.4s, v13.4s, v5.4s+ trn1 v24.2d, v19.2d, v12.2d+ stur q10, [x3, #-0x30]+ sqrdmulh v16.4s, v30.4s, v15.4s+ ldr q10, [x1, #0x20]+ trn2 v12.4s, v14.4s, v26.4s+ stur q18, [x3, #-0x20]+ mul v11.4s, v30.4s, v29.4s+ sub v8.4s, v17.4s, v24.4s+ trn1 v20.4s, v0.4s, v23.4s+ ldr q2, [x1, #0x10]+ trn2 v26.4s, v0.4s, v23.4s+ sqrdmulh v19.4s, v8.4s, v22.4s+ ldur q14, [x2, #-0x10]+ trn1 v21.2d, v9.2d, v20.2d+ mul v8.4s, v8.4s, v10.4s+ trn1 v6.2d, v12.2d, v26.2d+ trn2 v0.2d, v9.2d, v20.2d+ mls v11.4s, v16.4s, v31.s[0]+ sub v7.4s, v21.4s, v6.4s+ trn2 v28.2d, v12.2d, v26.2d+ add v10.4s, v21.4s, v6.4s+ mul v18.4s, v7.4s, v14.s[0]+ add v20.4s, v13.4s, v5.4s+ sqrdmulh v30.4s, v7.4s, v14.s[1]+ sub v21.4s, v0.4s, v28.4s+ add v13.4s, v0.4s, v28.4s+ add v9.4s, v17.4s, v24.4s+ sqrdmulh v1.4s, v21.4s, v14.s[3]+ ldr q17, [x1], #0x60+ mul v14.4s, v21.4s, v14.s[2]+ sub v21.4s, v9.4s, v20.4s+ mls v18.4s, v30.4s, v31.s[0]+ mls v14.4s, v1.4s, v31.s[0]+ mls v8.4s, v19.4s, v31.s[0]+ sub v3.4s, v10.4s, v13.4s+ add v15.4s, v10.4s, v13.4s+ sqrdmulh v28.4s, v3.4s, v4.s[1]+ add v10.4s, v18.4s, v14.4s+ sub v19.4s, v18.4s, v14.4s+ mul v18.4s, v3.4s, v4.s[0]+ sub v3.4s, v8.4s, v11.4s+ add v26.4s, v8.4s, v11.4s+ sqrdmulh v16.4s, v19.4s, v4.s[1]+ add v14.4s, v9.4s, v20.4s+ mul v8.4s, v19.4s, v4.s[0]+ sqrdmulh v24.4s, v21.4s, v2.4s+ subs x4, x4, #0x1+ cbnz x4, Lmld_intt_layer5678_start+ sqrdmulh v19.4s, v3.4s, v2.4s+ trn2 v0.4s, v14.4s, v26.4s+ str q15, [x3], #0x40+ trn1 v30.4s, v14.4s, v26.4s+ mul v26.4s, v21.4s, v17.4s+ stur q10, [x3, #-0x30]+ ldr d29, [x2], #0x20+ mls v26.4s, v24.4s, v31.s[0]+ mul v10.4s, v3.4s, v17.4s+ ldur q14, [x2, #-0x10]+ mls v10.4s, v19.4s, v31.s[0]+ mls v8.4s, v16.4s, v31.s[0]+ trn2 v22.4s, v26.4s, v10.4s+ trn1 v25.4s, v26.4s, v10.4s+ trn1 v1.2d, v30.2d, v25.2d+ trn1 v2.2d, v0.2d, v22.2d+ trn2 v13.2d, v30.2d, v25.2d+ trn2 v7.2d, v0.2d, v22.2d+ mls v18.4s, v28.4s, v31.s[0]+ sub v22.4s, v1.4s, v2.4s+ add v3.4s, v13.4s, v7.4s+ sqrdmulh v27.4s, v22.4s, v14.s[1]+ sub v4.4s, v13.4s, v7.4s+ stur q8, [x3, #-0x10]+ sqrdmulh v0.4s, v4.4s, v14.s[3]+ add v16.4s, v1.4s, v2.4s+ stur q18, [x3, #-0x20]+ mul v23.4s, v4.4s, v14.s[2]+ add v4.4s, v16.4s, v3.4s+ sub v17.4s, v16.4s, v3.4s+ mul v14.4s, v22.4s, v14.s[0]+ str q4, [x3], #0x40+ mls v23.4s, v0.4s, v31.s[0]+ mls v14.4s, v27.4s, v31.s[0]+ mul v11.4s, v17.4s, v29.s[0]+ sqrdmulh v10.4s, v17.4s, v29.s[1]+ sub v0.4s, v14.4s, v23.4s+ add v6.4s, v14.4s, v23.4s+ sqrdmulh v12.4s, v0.4s, v29.s[1]+ mul v0.4s, v0.4s, v29.s[0]+ stur q6, [x3, #-0x30]+ mls v11.4s, v10.4s, v31.s[0]+ mls v0.4s, v12.4s, v31.s[0]+ stur q11, [x3, #-0x20]+ stur q0, [x3, #-0x10]+ mov w5, #0x3ffe // =16382+ dup v29.4s, w5+ mov w5, #0xe03 // =3587+ movk w5, #0x40, lsl #16+ dup v30.4s, w5+ mov x4, #0x4 // =4+ ldr q0, [x2], #0x80+ ldur q1, [x2, #-0x70]+ ldur q2, [x2, #-0x60]+ ldur q3, [x2, #-0x50]+ ldur q4, [x2, #-0x40]+ ldur q5, [x2, #-0x30]+ ldur q6, [x2, #-0x20]+ ldur q7, [x2, #-0x10]+ ldr q8, [x0, #0xc0]+ ldr q27, [x0, #0x80]+ ldr q20, [x0, #0x1c0]+ ldr q23, [x0, #0x180]+ ldr q24, [x0, #0x3c0]+ ldr q28, [x0, #0x40]+ ldr q25, [x0, #0x340]+ ldr q10, [x0, #0x380]+ sub v15.4s, v27.4s, v8.4s+ ldr q26, [x0]+ ldr q18, [x0, #0x300]+ add v9.4s, v23.4s, v20.4s+ mul v11.4s, v15.4s, v4.s[0]+ sub v19.4s, v23.4s, v20.4s+ sub v22.4s, v10.4s, v24.4s+ ldr q13, [x0, #0x240]+ sqrdmulh v12.4s, v15.4s, v4.s[1]+ sub v14.4s, v26.4s, v28.4s+ ldr q17, [x0, #0x200]+ add v23.4s, v18.4s, v25.4s+ sqrdmulh v15.4s, v14.4s, v3.s[3]+ sub v18.4s, v18.4s, v25.4s+ mul v25.4s, v14.4s, v3.s[2]+ sub v16.4s, v17.4s, v13.4s+ mls v11.4s, v12.4s, v31.s[0]+ add v21.4s, v10.4s, v24.4s+ mls v25.4s, v15.4s, v31.s[0]+ mul v12.4s, v16.4s, v5.s[2]+ sub v10.4s, v23.4s, v21.4s+ sqrdmulh v14.4s, v10.4s, v3.s[1]+ add v23.4s, v23.4s, v21.4s+ add v27.4s, v27.4s, v8.4s+ mul v15.4s, v10.4s, v3.s[0]+ add v24.4s, v25.4s, v11.4s+ sub v10.4s, v25.4s, v11.4s+ ldr q25, [x0, #0x100]+ sqrdmulh v8.4s, v18.4s, v6.s[3]+ add v21.4s, v26.4s, v28.4s+ ldr q26, [x0, #0x140]+ sqrdmulh v20.4s, v16.4s, v5.s[3]+ sqrdmulh v28.4s, v22.4s, v7.s[1]+ add v11.4s, v25.4s, v26.4s+ mls v15.4s, v14.4s, v31.s[0]+ add v17.4s, v17.4s, v13.4s+ mul v13.4s, v22.4s, v7.s[0]+ ldr q14, [x0, #0x280]+ ldr q22, [x0, #0x2c0]+ mls v13.4s, v28.4s, v31.s[0]+ sub v16.4s, v25.4s, v26.4s+ sub v28.4s, v21.4s, v27.4s+ mls v12.4s, v20.4s, v31.s[0]+ add v20.4s, v11.4s, v9.4s+ add v26.4s, v14.4s, v22.4s+ sub v14.4s, v14.4s, v22.4s+ sqrdmulh v22.4s, v28.4s, v1.s[3]+ sub v9.4s, v11.4s, v9.4s+ mul v25.4s, v14.4s, v6.s[0]+ sub v11.4s, v17.4s, v26.4s+ add v17.4s, v17.4s, v26.4s+ add v26.4s, v21.4s, v27.4s+ sqrdmulh v27.4s, v11.4s, v2.s[3]+ mul v21.4s, v11.4s, v2.s[2]+ mul v11.4s, v18.4s, v6.s[2]+ mls v11.4s, v8.4s, v31.s[0]+ sqrdmulh v8.4s, v14.4s, v6.s[1]+ add v18.4s, v26.4s, v20.4s+ mls v21.4s, v27.4s, v31.s[0]+ sub v27.4s, v17.4s, v23.4s+ mul v14.4s, v28.4s, v1.s[2]+ sub v28.4s, v26.4s, v20.4s+ add v23.4s, v17.4s, v23.4s+ mls v25.4s, v8.4s, v31.s[0]+ add v26.4s, v21.4s, v15.4s+ sub v15.4s, v21.4s, v15.4s+ mul v8.4s, v19.4s, v5.s[0]+ mls v14.4s, v22.4s, v31.s[0]+ sub v22.4s, v11.4s, v13.4s+ sub v20.4s, v12.4s, v25.4s+ add v21.4s, v12.4s, v25.4s+ sqrdmulh v12.4s, v22.4s, v3.s[1]+ mul v17.4s, v16.4s, v4.s[2]+ sqrdmulh v25.4s, v16.4s, v4.s[3]+ add v16.4s, v11.4s, v13.4s+ mul v11.4s, v22.4s, v3.s[0]+ sqrdmulh v19.4s, v19.4s, v5.s[1]+ sqrdmulh v22.4s, v15.4s, v1.s[1]+ sqrdmulh v13.4s, v20.4s, v2.s[3]+ mul v20.4s, v20.4s, v2.s[2]+ mls v11.4s, v12.4s, v31.s[0]+ mls v20.4s, v13.4s, v31.s[0]+ sub v13.4s, v18.4s, v23.4s+ add v23.4s, v18.4s, v23.4s+ mls v17.4s, v25.4s, v31.s[0]+ mls v8.4s, v19.4s, v31.s[0]+ sub v18.4s, v20.4s, v11.4s+ add v20.4s, v20.4s, v11.4s+ sqrdmulh v12.4s, v9.4s, v2.s[1]+ mul v15.4s, v15.4s, v1.s[0]+ sub v11.4s, v17.4s, v8.4s+ mls v15.4s, v22.4s, v31.s[0]+ add v19.4s, v17.4s, v8.4s+ sqrdmulh v25.4s, v11.4s, v2.s[1]+ add v17.4s, v24.4s, v19.4s+ sub v24.4s, v24.4s, v19.4s+ mul v19.4s, v11.4s, v2.s[0]+ sqrdmulh v8.4s, v24.4s, v0.s[3]+ mls v19.4s, v25.4s, v31.s[0]+ mul v25.4s, v9.4s, v2.s[0]+ sub x4, x4, #0x1++Lmld_intt_layer1234_start:+ sub v22.4s, v21.4s, v16.4s+ mls v25.4s, v12.4s, v31.s[0]+ add v12.4s, v21.4s, v16.4s+ mul v9.4s, v24.4s, v0.s[2]+ mls v9.4s, v8.4s, v31.s[0]+ sub v16.4s, v14.4s, v25.4s+ add v14.4s, v14.4s, v25.4s+ sqrdmulh v24.4s, v22.4s, v1.s[1]+ sub v11.4s, v14.4s, v26.4s+ sqrdmulh v21.4s, v16.4s, v0.s[3]+ add v25.4s, v14.4s, v26.4s+ mul v14.4s, v22.4s, v1.s[0]+ mls v14.4s, v24.4s, v31.s[0]+ mul v16.4s, v16.4s, v0.s[2]+ mls v16.4s, v21.4s, v31.s[0]+ add v24.4s, v9.4s, v14.4s+ sqrdmulh v21.4s, v25.4s, v30.4s+ sqrdmulh v26.4s, v11.4s, v0.s[1]+ mul v8.4s, v25.4s, v29.4s+ mls v8.4s, v21.4s, v31.s[0]+ mul v25.4s, v24.4s, v29.4s+ mul v22.4s, v11.4s, v0.s[0]+ sub v11.4s, v17.4s, v12.4s+ str q8, [x0, #0x80]+ sub v8.4s, v9.4s, v14.4s+ add v14.4s, v16.4s, v15.4s+ sqrdmulh v9.4s, v11.4s, v0.s[1]+ sub v21.4s, v16.4s, v15.4s+ mls v22.4s, v26.4s, v31.s[0]+ mul v15.4s, v11.4s, v0.s[0]+ mls v15.4s, v9.4s, v31.s[0]+ add v11.4s, v17.4s, v12.4s+ mul v16.4s, v10.4s, v1.s[2]+ str q22, [x0, #0x280]+ sqrdmulh v26.4s, v10.4s, v1.s[3]+ str q15, [x0, #0x240]+ sqrdmulh v9.4s, v8.4s, v0.s[1]+ mul v12.4s, v8.4s, v0.s[0]+ mls v16.4s, v26.4s, v31.s[0]+ sqrdmulh v10.4s, v27.4s, v1.s[1]+ sqrdmulh v15.4s, v14.4s, v30.4s+ add v22.4s, v16.4s, v19.4s+ sub v19.4s, v16.4s, v19.4s+ mls v12.4s, v9.4s, v31.s[0]+ add v8.4s, v22.4s, v20.4s+ sub v26.4s, v22.4s, v20.4s+ mul v27.4s, v27.4s, v1.s[0]+ sqrdmulh v17.4s, v11.4s, v30.4s+ mls v27.4s, v10.4s, v31.s[0]+ mul v20.4s, v11.4s, v29.4s+ sqrdmulh v22.4s, v24.4s, v30.4s+ mls v20.4s, v17.4s, v31.s[0]+ mul v14.4s, v14.4s, v29.4s+ sqrdmulh v16.4s, v23.4s, v30.4s+ str q20, [x0, #0x40]+ sqrdmulh v11.4s, v21.4s, v0.s[1]+ sqrdmulh v20.4s, v28.4s, v0.s[3]+ mul v17.4s, v23.4s, v29.4s+ mul v23.4s, v28.4s, v0.s[2]+ mls v17.4s, v16.4s, v31.s[0]+ mul v10.4s, v21.4s, v0.s[0]+ str q12, [x0, #0x340]+ mls v25.4s, v22.4s, v31.s[0]+ str q17, [x0], #0x10+ ldr q17, [x0, #0x2c0]+ mls v14.4s, v15.4s, v31.s[0]+ ldr q12, [x0, #0x200]+ sqrdmulh v16.4s, v13.4s, v0.s[1]+ str q25, [x0, #0x130]+ mul v28.4s, v13.4s, v0.s[0]+ ldr q13, [x0, #0x240]+ str q14, [x0, #0x170]+ mul v14.4s, v18.4s, v1.s[0]+ mls v28.4s, v16.4s, v31.s[0]+ ldr q21, [x0, #0xc0]+ mls v10.4s, v11.4s, v31.s[0]+ mls v23.4s, v20.4s, v31.s[0]+ str q28, [x0, #0x1f0]+ ldr q11, [x0, #0x300]+ sqrdmulh v28.4s, v18.4s, v1.s[1]+ str q10, [x0, #0x370]+ mul v16.4s, v19.4s, v0.s[2]+ sqrdmulh v19.4s, v19.4s, v0.s[3]+ sqrdmulh v10.4s, v26.4s, v0.s[1]+ add v18.4s, v12.4s, v13.4s+ sub v12.4s, v12.4s, v13.4s+ mls v16.4s, v19.4s, v31.s[0]+ ldr q9, [x0, #0x280]+ ldr q20, [x0, #0x380]+ add v24.4s, v23.4s, v27.4s+ sub v25.4s, v23.4s, v27.4s+ mul v19.4s, v26.4s, v0.s[0]+ mls v14.4s, v28.4s, v31.s[0]+ add v13.4s, v9.4s, v17.4s+ sub v28.4s, v18.4s, v13.4s+ mls v19.4s, v10.4s, v31.s[0]+ sqrdmulh v23.4s, v25.4s, v0.s[1]+ mul v15.4s, v25.4s, v0.s[0]+ str q19, [x0, #0x2b0]+ ldr q19, [x0, #0x80]+ sqrdmulh v22.4s, v8.4s, v30.4s+ mls v15.4s, v23.4s, v31.s[0]+ add v26.4s, v16.4s, v14.4s+ mul v10.4s, v8.4s, v29.4s+ add v8.4s, v18.4s, v13.4s+ sqrdmulh v13.4s, v26.4s, v30.4s+ str q15, [x0, #0x2f0]+ sub v18.4s, v9.4s, v17.4s+ mul v27.4s, v26.4s, v29.4s+ sqrdmulh v23.4s, v12.4s, v5.s[3]+ mls v27.4s, v13.4s, v31.s[0]+ mul v25.4s, v18.4s, v6.s[0]+ sqrdmulh v13.4s, v18.4s, v6.s[1]+ str q27, [x0, #0x1b0]+ sub v27.4s, v19.4s, v21.4s+ add v21.4s, v19.4s, v21.4s+ mul v18.4s, v12.4s, v5.s[2]+ sub v9.4s, v16.4s, v14.4s+ mul v26.4s, v24.4s, v29.4s+ ldr q12, [x0, #0x3c0]+ mls v25.4s, v13.4s, v31.s[0]+ sub v16.4s, v20.4s, v12.4s+ sqrdmulh v17.4s, v24.4s, v30.4s+ mul v13.4s, v16.4s, v7.s[0]+ mls v18.4s, v23.4s, v31.s[0]+ mls v26.4s, v17.4s, v31.s[0]+ sqrdmulh v17.4s, v9.4s, v0.s[1]+ sqrdmulh v24.4s, v16.4s, v7.s[1]+ ldr q16, [x0, #0x340]+ str q26, [x0, #0xf0]+ sub v15.4s, v18.4s, v25.4s+ mul v23.4s, v9.4s, v0.s[0]+ ldr q19, [x0, #0x180]+ ldr q14, [x0, #0x1c0]+ sqrdmulh v9.4s, v15.4s, v2.s[3]+ add v20.4s, v20.4s, v12.4s+ add v12.4s, v11.4s, v16.4s+ mul v26.4s, v15.4s, v2.s[2]+ sub v16.4s, v11.4s, v16.4s+ sub v11.4s, v12.4s, v20.4s+ mls v23.4s, v17.4s, v31.s[0]+ add v20.4s, v12.4s, v20.4s+ sub v12.4s, v19.4s, v14.4s+ mul v17.4s, v27.4s, v4.s[0]+ mls v10.4s, v22.4s, v31.s[0]+ add v22.4s, v19.4s, v14.4s+ ldr q14, [x0, #0x40]+ str q23, [x0, #0x3b0]+ sqrdmulh v23.4s, v27.4s, v4.s[1]+ ldr q19, [x0, #0x100]+ ldr q15, [x0, #0x140]+ mls v26.4s, v9.4s, v31.s[0]+ str q10, [x0, #0xb0]+ sqrdmulh v10.4s, v11.4s, v3.s[1]+ sub v27.4s, v8.4s, v20.4s+ mls v13.4s, v24.4s, v31.s[0]+ add v8.4s, v8.4s, v20.4s+ sub v20.4s, v19.4s, v15.4s+ sqrdmulh v9.4s, v16.4s, v6.s[3]+ add v19.4s, v19.4s, v15.4s+ ldr q15, [x0]+ mul v24.4s, v20.4s, v4.s[2]+ mls v17.4s, v23.4s, v31.s[0]+ add v23.4s, v15.4s, v14.4s+ sub v14.4s, v15.4s, v14.4s+ mul v15.4s, v11.4s, v3.s[0]+ sub v11.4s, v23.4s, v21.4s+ mul v16.4s, v16.4s, v6.s[2]+ add v23.4s, v23.4s, v21.4s+ add v21.4s, v18.4s, v25.4s+ sqrdmulh v25.4s, v20.4s, v4.s[3]+ sqrdmulh v18.4s, v12.4s, v5.s[1]+ sqrdmulh v20.4s, v14.4s, v3.s[3]+ mul v12.4s, v12.4s, v5.s[0]+ mls v16.4s, v9.4s, v31.s[0]+ mls v12.4s, v18.4s, v31.s[0]+ mls v24.4s, v25.4s, v31.s[0]+ sub v25.4s, v16.4s, v13.4s+ add v16.4s, v16.4s, v13.4s+ mul v13.4s, v28.4s, v2.s[2]+ sqrdmulh v9.4s, v25.4s, v3.s[1]+ mul v18.4s, v25.4s, v3.s[0]+ sqrdmulh v25.4s, v28.4s, v2.s[3]+ mls v18.4s, v9.4s, v31.s[0]+ mls v15.4s, v10.4s, v31.s[0]+ sub v9.4s, v24.4s, v12.4s+ mul v28.4s, v14.4s, v3.s[2]+ add v12.4s, v24.4s, v12.4s+ mls v28.4s, v20.4s, v31.s[0]+ add v20.4s, v26.4s, v18.4s+ add v24.4s, v19.4s, v22.4s+ mls v13.4s, v25.4s, v31.s[0]+ sub v18.4s, v26.4s, v18.4s+ sqrdmulh v26.4s, v11.4s, v1.s[3]+ add v25.4s, v23.4s, v24.4s+ mul v14.4s, v11.4s, v1.s[2]+ sub v10.4s, v28.4s, v17.4s+ add v17.4s, v28.4s, v17.4s+ sub v28.4s, v23.4s, v24.4s+ sqrdmulh v11.4s, v9.4s, v2.s[1]+ sub v22.4s, v19.4s, v22.4s+ sub v24.4s, v17.4s, v12.4s+ mls v14.4s, v26.4s, v31.s[0]+ add v17.4s, v17.4s, v12.4s+ sqrdmulh v12.4s, v22.4s, v2.s[1]+ sub v23.4s, v13.4s, v15.4s+ add v26.4s, v13.4s, v15.4s+ mul v19.4s, v9.4s, v2.s[0]+ sqrdmulh v9.4s, v23.4s, v1.s[1]+ mul v15.4s, v23.4s, v1.s[0]+ mls v19.4s, v11.4s, v31.s[0]+ sub v13.4s, v25.4s, v8.4s+ mls v15.4s, v9.4s, v31.s[0]+ add v23.4s, v25.4s, v8.4s+ sqrdmulh v8.4s, v24.4s, v0.s[3]+ mul v25.4s, v22.4s, v2.s[0]+ subs x4, x4, #0x1+ cbnz x4, Lmld_intt_layer1234_start+ mul v22.4s, v24.4s, v0.s[2]+ sqrdmulh v9.4s, v23.4s, v30.4s+ mls v25.4s, v12.4s, v31.s[0]+ mul v23.4s, v23.4s, v29.4s+ mls v23.4s, v9.4s, v31.s[0]+ mls v22.4s, v8.4s, v31.s[0]+ sqrdmulh v11.4s, v10.4s, v1.s[3]+ sub v9.4s, v14.4s, v25.4s+ str q23, [x0], #0x10+ mul v23.4s, v10.4s, v1.s[2]+ sqrdmulh v24.4s, v9.4s, v0.s[3]+ mls v23.4s, v11.4s, v31.s[0]+ mul v9.4s, v9.4s, v0.s[2]+ mls v9.4s, v24.4s, v31.s[0]+ sub v24.4s, v23.4s, v19.4s+ add v19.4s, v23.4s, v19.4s+ mul v8.4s, v28.4s, v0.s[2]+ add v23.4s, v14.4s, v25.4s+ mul v11.4s, v13.4s, v0.s[0]+ sub v25.4s, v21.4s, v16.4s+ sub v10.4s, v9.4s, v15.4s+ add v15.4s, v9.4s, v15.4s+ add v16.4s, v21.4s, v16.4s+ sqrdmulh v28.4s, v28.4s, v0.s[3]+ add v9.4s, v23.4s, v26.4s+ add v14.4s, v17.4s, v16.4s+ sqrdmulh v21.4s, v13.4s, v0.s[1]+ sub v13.4s, v17.4s, v16.4s+ mul v16.4s, v14.4s, v29.4s+ sub v12.4s, v23.4s, v26.4s+ mul v17.4s, v13.4s, v0.s[0]+ mls v8.4s, v28.4s, v31.s[0]+ sqrdmulh v28.4s, v14.4s, v30.4s+ sub v14.4s, v19.4s, v20.4s+ add v20.4s, v19.4s, v20.4s+ sqrdmulh v19.4s, v13.4s, v0.s[1]+ sqrdmulh v26.4s, v27.4s, v1.s[1]+ mls v16.4s, v28.4s, v31.s[0]+ sqrdmulh v28.4s, v12.4s, v0.s[1]+ mul v27.4s, v27.4s, v1.s[0]+ str q16, [x0, #0x30]+ mul v12.4s, v12.4s, v0.s[0]+ mls v12.4s, v28.4s, v31.s[0]+ mls v27.4s, v26.4s, v31.s[0]+ sqrdmulh v26.4s, v25.4s, v1.s[1]+ str q12, [x0, #0x270]+ sqrdmulh v12.4s, v14.4s, v0.s[1]+ sub v13.4s, v8.4s, v27.4s+ add v27.4s, v8.4s, v27.4s+ mul v16.4s, v14.4s, v0.s[0]+ mul v8.4s, v20.4s, v29.4s+ mls v16.4s, v12.4s, v31.s[0]+ mul v12.4s, v18.4s, v1.s[0]+ sqrdmulh v14.4s, v20.4s, v30.4s+ str q16, [x0, #0x2b0]+ sqrdmulh v20.4s, v18.4s, v1.s[1]+ mul v25.4s, v25.4s, v1.s[0]+ mls v25.4s, v26.4s, v31.s[0]+ mls v17.4s, v19.4s, v31.s[0]+ mul v18.4s, v9.4s, v29.4s+ add v28.4s, v22.4s, v25.4s+ sqrdmulh v9.4s, v9.4s, v30.4s+ sub v23.4s, v22.4s, v25.4s+ str q17, [x0, #0x230]+ mls v11.4s, v21.4s, v31.s[0]+ mls v8.4s, v14.4s, v31.s[0]+ sqrdmulh v21.4s, v28.4s, v30.4s+ str q11, [x0, #0x1f0]+ mul v17.4s, v28.4s, v29.4s+ str q8, [x0, #0xb0]+ mul v28.4s, v10.4s, v0.s[0]+ mls v17.4s, v21.4s, v31.s[0]+ sqrdmulh v21.4s, v10.4s, v0.s[1]+ mul v8.4s, v15.4s, v29.4s+ str q17, [x0, #0x130]+ sqrdmulh v15.4s, v15.4s, v30.4s+ mul v10.4s, v24.4s, v0.s[2]+ sqrdmulh v24.4s, v24.4s, v0.s[3]+ mls v12.4s, v20.4s, v31.s[0]+ mls v8.4s, v15.4s, v31.s[0]+ mls v10.4s, v24.4s, v31.s[0]+ sqrdmulh v24.4s, v27.4s, v30.4s+ str q8, [x0, #0x170]+ mul v14.4s, v13.4s, v0.s[0]+ sub v16.4s, v10.4s, v12.4s+ sqrdmulh v17.4s, v13.4s, v0.s[1]+ add v10.4s, v10.4s, v12.4s+ mul v13.4s, v27.4s, v29.4s+ sqrdmulh v20.4s, v10.4s, v30.4s+ mls v14.4s, v17.4s, v31.s[0]+ mls v13.4s, v24.4s, v31.s[0]+ sqrdmulh v24.4s, v23.4s, v0.s[1]+ str q14, [x0, #0x2f0]+ sqrdmulh v8.4s, v16.4s, v0.s[1]+ str q13, [x0, #0xf0]+ mls v18.4s, v9.4s, v31.s[0]+ mul v9.4s, v23.4s, v0.s[0]+ mul v14.4s, v16.4s, v0.s[0]+ str q18, [x0, #0x70]+ mul v27.4s, v10.4s, v29.4s+ mls v28.4s, v21.4s, v31.s[0]+ mls v14.4s, v8.4s, v31.s[0]+ mls v27.4s, v20.4s, v31.s[0]+ str q28, [x0, #0x370]+ mls v9.4s, v24.4s, v31.s[0]+ str q14, [x0, #0x3b0]+ str q27, [x0, #0x1b0]+ str q9, [x0, #0x330]+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(intt_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,686 @@+/* Copyright (c) 2022 Arm Limited+ * Copyright (c) 2022 Hanno Becker+ * Copyright (c) 2023 Amin Abdulrahman, Matthias Kannwischer+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [NeonNTT]+ * Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1+ * Becker, Hwang, Kannwischer, Yang, Yang+ * https://eprint.iacr.org/2021/986+ *+ * - [NeonNTT_Autoformalised]+ * Neon NTT - (Auto)formalised+ * Hanno Becker+ * https://eprint.iacr.org/2026/1223+ *+ * - [SLOTHY_Paper]+ * Fast and Clean: Auditable high-performance assembly via constraint solving+ * Abdulrahman, Becker, Kannwischer, Klein+ * https://eprint.iacr.org/2022/1303+ */++/* AArch64 ML-DSA forward NTT following @[NeonNTT], @[SLOTHY_Paper], and @[NeonNTT_Autoformalised] */++/*yaml+ Name: ntt_aarch64_asm+ Description: AArch64 ML-DSA forward NTT+ Signature: void mld_ntt_aarch64_asm(int32_t r[256], const int32_t zetas_l123456[144], const int32_t zetas_l78[384])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t r[256]+ description: Input/output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 576+ permissions: read-only+ c_parameter: const int32_t zetas_l123456[144]+ description: Twiddle factors for layers 1-6 (144 x int32_t)+ x2:+ type: buffer+ size_bytes: 1536+ permissions: read-only+ c_parameter: const int32_t zetas_l78[384]+ description: Twiddle factors for layers 7-8 (384 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_ntt_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(ntt_aarch64_asm)+MLD_ASM_FN_SYMBOL(ntt_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ mov w5, #0xe001 // =57345+ movk w5, #0x7f, lsl #16+ dup v7.4s, w5+ mov x3, x0+ mov x4, #0x8 // =8+ ldr q0, [x1], #0x40+ ldur q1, [x1, #-0x30]+ ldur q2, [x1, #-0x20]+ ldur q3, [x1, #-0x10]+ ldr q23, [x0, #0x390]+ ldr q13, [x0, #0x380]+ ldr q22, [x0, #0x80]+ ldr q26, [x0, #0x190]+ ldr q8, [x0, #0x280]+ ldr q6, [x0, #0x210]+ mul v10.4s, v13.4s, v0.s[0]+ sqrdmulh v13.4s, v13.4s, v0.s[1]+ mul v12.4s, v8.4s, v0.s[0]+ sqrdmulh v27.4s, v8.4s, v0.s[1]+ mul v4.4s, v6.4s, v0.s[0]+ mls v10.4s, v13.4s, v7.s[0]+ ldr q13, [x0, #0x180]+ sqrdmulh v14.4s, v23.4s, v0.s[1]+ mls v12.4s, v27.4s, v7.s[0]+ add v31.4s, v13.4s, v10.4s+ sub v13.4s, v13.4s, v10.4s+ mul v10.4s, v23.4s, v0.s[0]+ sqrdmulh v8.4s, v13.4s, v1.s[1]+ sub v18.4s, v22.4s, v12.4s+ mls v10.4s, v14.4s, v7.s[0]+ mul v13.4s, v13.4s, v1.s[0]+ mls v13.4s, v8.4s, v7.s[0]+ sub v29.4s, v26.4s, v10.4s+ add v25.4s, v26.4s, v10.4s+ mul v10.4s, v31.4s, v0.s[2]+ mul v14.4s, v25.4s, v0.s[2]+ add v17.4s, v18.4s, v13.4s+ sub v15.4s, v18.4s, v13.4s+ sqrdmulh v13.4s, v31.4s, v0.s[3]+ sqrdmulh v20.4s, v15.4s, v3.s[1]+ sqrdmulh v5.4s, v17.4s, v2.s[3]+ mls v10.4s, v13.4s, v7.s[0]+ ldr q13, [x0, #0x300]+ mul v18.4s, v17.4s, v2.s[2]+ add v31.4s, v22.4s, v12.4s+ mul v23.4s, v15.4s, v3.s[0]+ ldr q17, [x0, #0x90]+ add v19.4s, v31.4s, v10.4s+ sub v16.4s, v31.4s, v10.4s+ mul v10.4s, v13.4s, v0.s[0]+ sqrdmulh v13.4s, v13.4s, v0.s[1]+ sqrdmulh v27.4s, v16.4s, v2.s[1]+ mul v11.4s, v16.4s, v2.s[0]+ mls v10.4s, v13.4s, v7.s[0]+ ldr q13, [x0, #0x290]+ ldr q22, [x0, #0x100]+ mls v11.4s, v27.4s, v7.s[0]+ sqrdmulh v15.4s, v13.4s, v0.s[1]+ sub v12.4s, v22.4s, v10.4s+ add v30.4s, v22.4s, v10.4s+ mul v10.4s, v13.4s, v0.s[0]+ ldr q28, [x0]+ sqrdmulh v13.4s, v25.4s, v0.s[3]+ sqrdmulh v27.4s, v30.4s, v0.s[3]+ mls v10.4s, v15.4s, v7.s[0]+ mls v14.4s, v13.4s, v7.s[0]+ ldr q13, [x0, #0x200]+ sqrdmulh v25.4s, v12.4s, v1.s[1]+ add v24.4s, v17.4s, v10.4s+ sub v21.4s, v17.4s, v10.4s+ sqrdmulh v8.4s, v13.4s, v0.s[1]+ sub v9.4s, v24.4s, v14.4s+ mul v26.4s, v12.4s, v1.s[0]+ mul v13.4s, v13.4s, v0.s[0]+ mls v13.4s, v8.4s, v7.s[0]+ mul v8.4s, v30.4s, v0.s[2]+ mls v8.4s, v27.4s, v7.s[0]+ add v16.4s, v28.4s, v13.4s+ sub v10.4s, v28.4s, v13.4s+ mls v26.4s, v25.4s, v7.s[0]+ sqrdmulh v12.4s, v19.4s, v1.s[3]+ sub v25.4s, v16.4s, v8.4s+ mls v23.4s, v20.4s, v7.s[0]+ sub v22.4s, v25.4s, v11.4s+ sqrdmulh v20.4s, v9.4s, v2.s[1]+ sub v15.4s, v10.4s, v26.4s+ sub x4, x4, #0x2++Lmld_ntt_layer123_start:+ add v31.4s, v10.4s, v26.4s+ mul v17.4s, v19.4s, v1.s[2]+ add v26.4s, v15.4s, v23.4s+ ldr q30, [x0, #0x2a0]+ sub v13.4s, v15.4s, v23.4s+ mul v23.4s, v29.4s, v1.s[0]+ add v25.4s, v25.4s, v11.4s+ str q22, [x0, #0x180]+ mul v11.4s, v9.4s, v2.s[0]+ str q13, [x0, #0x380]+ ldr q28, [x0, #0x10]+ add v10.4s, v16.4s, v8.4s+ mls v17.4s, v12.4s, v7.s[0]+ ldr q13, [x0, #0x3a0]+ str q26, [x0, #0x300]+ sqrdmulh v27.4s, v30.4s, v0.s[1]+ mls v18.4s, v5.4s, v7.s[0]+ ldr q9, [x0, #0x1a0]+ sub v16.4s, v10.4s, v17.4s+ add v15.4s, v10.4s, v17.4s+ sqrdmulh v10.4s, v6.4s, v0.s[1]+ str q16, [x0, #0x80]+ str q15, [x0], #0x10+ sqrdmulh v19.4s, v13.4s, v0.s[1]+ sub v15.4s, v31.4s, v18.4s+ mul v8.4s, v13.4s, v0.s[0]+ add v26.4s, v31.4s, v18.4s+ str q15, [x0, #0x270]+ sqrdmulh v13.4s, v29.4s, v1.s[1]+ str q26, [x0, #0x1f0]+ mls v8.4s, v19.4s, v7.s[0]+ mls v11.4s, v20.4s, v7.s[0]+ mls v23.4s, v13.4s, v7.s[0]+ add v22.4s, v9.4s, v8.4s+ ldr q6, [x0, #0x210]+ sub v29.4s, v9.4s, v8.4s+ mul v17.4s, v30.4s, v0.s[0]+ ldr q9, [x0, #0x300]+ sqrdmulh v13.4s, v22.4s, v0.s[3]+ add v18.4s, v21.4s, v23.4s+ mls v4.4s, v10.4s, v7.s[0]+ sub v31.4s, v21.4s, v23.4s+ sqrdmulh v16.4s, v31.4s, v3.s[1]+ add v19.4s, v24.4s, v14.4s+ mul v14.4s, v22.4s, v0.s[2]+ sub v10.4s, v28.4s, v4.4s+ mls v14.4s, v13.4s, v7.s[0]+ ldr q13, [x0, #0x100]+ sqrdmulh v22.4s, v9.4s, v0.s[1]+ mul v8.4s, v9.4s, v0.s[0]+ mul v23.4s, v31.4s, v3.s[0]+ mls v8.4s, v22.4s, v7.s[0]+ mls v23.4s, v16.4s, v7.s[0]+ add v16.4s, v28.4s, v4.4s+ ldr q22, [x0, #0x90]+ mul v4.4s, v6.4s, v0.s[0]+ mls v17.4s, v27.4s, v7.s[0]+ add v21.4s, v13.4s, v8.4s+ sub v27.4s, v13.4s, v8.4s+ sqrdmulh v31.4s, v21.4s, v0.s[3]+ str q25, [x0, #0xf0]+ mul v8.4s, v21.4s, v0.s[2]+ add v24.4s, v22.4s, v17.4s+ sub v21.4s, v22.4s, v17.4s+ sqrdmulh v5.4s, v18.4s, v2.s[3]+ mls v8.4s, v31.4s, v7.s[0]+ sub v9.4s, v24.4s, v14.4s+ sqrdmulh v20.4s, v27.4s, v1.s[1]+ mul v26.4s, v27.4s, v1.s[0]+ sub v25.4s, v16.4s, v8.4s+ mul v18.4s, v18.4s, v2.s[2]+ sub v22.4s, v25.4s, v11.4s+ mls v26.4s, v20.4s, v7.s[0]+ sqrdmulh v20.4s, v9.4s, v2.s[1]+ sqrdmulh v12.4s, v19.4s, v1.s[3]+ sub v15.4s, v10.4s, v26.4s+ subs x4, x4, #0x1+ cbnz x4, Lmld_ntt_layer123_start+ add v13.4s, v10.4s, v26.4s+ mls v18.4s, v5.4s, v7.s[0]+ str q22, [x0, #0x180]+ add v27.4s, v16.4s, v8.4s+ mul v22.4s, v19.4s, v1.s[2]+ add v26.4s, v24.4s, v14.4s+ ldr q31, [x0, #0x110]+ sub v14.4s, v15.4s, v23.4s+ add v17.4s, v15.4s, v23.4s+ mls v22.4s, v12.4s, v7.s[0]+ add v28.4s, v13.4s, v18.4s+ str q14, [x0, #0x380]+ sqrdmulh v24.4s, v6.4s, v0.s[1]+ add v5.4s, v25.4s, v11.4s+ sub v19.4s, v13.4s, v18.4s+ str q17, [x0, #0x300]+ str q5, [x0, #0x100]+ mul v16.4s, v9.4s, v2.s[0]+ ldr q18, [x0, #0x310]+ str q19, [x0, #0x280]+ mls v16.4s, v20.4s, v7.s[0]+ str q28, [x0, #0x200]+ add v13.4s, v27.4s, v22.4s+ ldr q15, [x0, #0x10]+ sub v10.4s, v27.4s, v22.4s+ mls v4.4s, v24.4s, v7.s[0]+ str q13, [x0], #0x10+ str q10, [x0, #0x70]+ sqrdmulh v12.4s, v29.4s, v1.s[1]+ mul v23.4s, v29.4s, v1.s[0]+ mul v8.4s, v26.4s, v1.s[2]+ add v20.4s, v15.4s, v4.4s+ sub v6.4s, v15.4s, v4.4s+ mls v23.4s, v12.4s, v7.s[0]+ sqrdmulh v22.4s, v18.4s, v0.s[1]+ mul v5.4s, v18.4s, v0.s[0]+ sub v28.4s, v21.4s, v23.4s+ sqrdmulh v10.4s, v26.4s, v1.s[3]+ mls v5.4s, v22.4s, v7.s[0]+ sqrdmulh v30.4s, v28.4s, v3.s[1]+ add v4.4s, v21.4s, v23.4s+ mls v8.4s, v10.4s, v7.s[0]+ add v12.4s, v31.4s, v5.4s+ sub v9.4s, v31.4s, v5.4s+ sqrdmulh v25.4s, v4.4s, v2.s[3]+ sqrdmulh v15.4s, v9.4s, v1.s[1]+ sqrdmulh v31.4s, v12.4s, v0.s[3]+ mul v18.4s, v12.4s, v0.s[2]+ mul v11.4s, v9.4s, v1.s[0]+ mls v18.4s, v31.4s, v7.s[0]+ mul v29.4s, v4.4s, v2.s[2]+ mls v29.4s, v25.4s, v7.s[0]+ add v23.4s, v20.4s, v18.4s+ mls v11.4s, v15.4s, v7.s[0]+ sub v31.4s, v20.4s, v18.4s+ add v17.4s, v23.4s, v8.4s+ add v5.4s, v31.4s, v16.4s+ mul v24.4s, v28.4s, v3.s[0]+ str q17, [x0], #0x10+ sub v19.4s, v31.4s, v16.4s+ mls v24.4s, v30.4s, v7.s[0]+ str q5, [x0, #0xf0]+ add v31.4s, v6.4s, v11.4s+ sub v26.4s, v23.4s, v8.4s+ str q19, [x0, #0x170]+ add v4.4s, v31.4s, v29.4s+ sub v13.4s, v6.4s, v11.4s+ str q26, [x0, #0x70]+ sub v11.4s, v31.4s, v29.4s+ sub v22.4s, v13.4s, v24.4s+ add v23.4s, v13.4s, v24.4s+ str q4, [x0, #0x1f0]+ str q11, [x0, #0x270]+ str q23, [x0, #0x2f0]+ str q22, [x0, #0x370]+ mov x0, x3+ mov x4, #0x8 // =8+ ldr q9, [x0, #0x40]+ ldr q23, [x1], #0x40+ ldr q21, [x2, #0x60]+ ldr q1, [x0, #0x20]+ ldur q14, [x1, #-0x30]+ ldr q13, [x0]+ ldr q11, [x2, #0x50]+ sqrdmulh v16.4s, v9.4s, v23.s[1]+ ldr q17, [x0, #0x50]+ mul v15.4s, v9.4s, v23.s[0]+ ldr q30, [x0, #0x70]+ ldr q27, [x0, #0x60]+ ldr q8, [x2, #0x30]+ sqrdmulh v12.4s, v17.4s, v23.s[1]+ ldr q6, [x0, #0x30]+ mls v15.4s, v16.4s, v7.s[0]+ sqrdmulh v18.4s, v27.4s, v23.s[1]+ sqrdmulh v19.4s, v30.4s, v23.s[1]+ add v5.4s, v13.4s, v15.4s+ mul v25.4s, v27.4s, v23.s[0]+ sub v26.4s, v13.4s, v15.4s+ mls v25.4s, v18.4s, v7.s[0]+ mul v10.4s, v17.4s, v23.s[0]+ mls v10.4s, v12.4s, v7.s[0]+ mul v4.4s, v30.4s, v23.s[0]+ sub v22.4s, v1.4s, v25.4s+ mls v4.4s, v19.4s, v7.s[0]+ add v28.4s, v1.4s, v25.4s+ sqrdmulh v19.4s, v28.4s, v23.s[3]+ sqrdmulh v9.4s, v22.4s, v14.s[1]+ add v2.4s, v6.4s, v4.4s+ mul v0.4s, v28.4s, v23.s[2]+ sqrdmulh v27.4s, v2.4s, v23.s[3]+ sub v17.4s, v6.4s, v4.4s+ mul v3.4s, v2.4s, v23.s[2]+ sqrdmulh v20.4s, v17.4s, v14.s[1]+ ldr q1, [x0, #0x10]+ mls v3.4s, v27.4s, v7.s[0]+ mls v0.4s, v19.4s, v7.s[0]+ ldur q16, [x1, #-0x20]+ add v31.4s, v1.4s, v10.4s+ mul v30.4s, v17.4s, v14.s[0]+ mls v30.4s, v20.4s, v7.s[0]+ add v27.4s, v31.4s, v3.4s+ sub v23.4s, v1.4s, v10.4s+ sub v24.4s, v31.4s, v3.4s+ sqrdmulh v4.4s, v27.4s, v14.s[3]+ sqrdmulh v10.4s, v24.4s, v16.s[1]+ mul v18.4s, v24.4s, v16.s[0]+ add v15.4s, v23.4s, v30.4s+ sub v23.4s, v23.4s, v30.4s+ mul v29.4s, v27.4s, v14.s[2]+ sub v2.4s, v5.4s, v0.4s+ add v12.4s, v5.4s, v0.4s+ mls v18.4s, v10.4s, v7.s[0]+ ldur q3, [x1, #-0x10]+ mls v29.4s, v4.4s, v7.s[0]+ mul v4.4s, v22.4s, v14.s[0]+ add v1.4s, v2.4s, v18.4s+ sub v24.4s, v2.4s, v18.4s+ mls v4.4s, v9.4s, v7.s[0]+ ldr q20, [x2, #0x10]+ add v25.4s, v12.4s, v29.4s+ mul v9.4s, v23.4s, v3.s[0]+ sub v5.4s, v12.4s, v29.4s+ sqrdmulh v31.4s, v23.4s, v3.s[1]+ trn2 v6.4s, v1.4s, v24.4s+ trn2 v10.4s, v25.4s, v5.4s+ sqrdmulh v13.4s, v15.4s, v16.s[3]+ trn2 v30.2d, v10.2d, v6.2d+ ldr q3, [x2], #0xc0+ mul v12.4s, v15.4s, v16.s[2]+ trn1 v27.2d, v10.2d, v6.2d+ mls v9.4s, v31.4s, v7.s[0]+ trn1 v22.4s, v25.4s, v5.4s+ sub v6.4s, v26.4s, v4.4s+ mls v12.4s, v13.4s, v7.s[0]+ trn1 v1.4s, v1.4s, v24.4s+ add v13.4s, v26.4s, v4.4s+ trn2 v10.2d, v22.2d, v1.2d+ mul v28.4s, v30.4s, v3.4s+ sub v31.4s, v6.4s, v9.4s+ sub x4, x4, #0x1++Lmld_ntt_layer45678_start:+ add v2.4s, v13.4s, v12.4s+ sqrdmulh v5.4s, v30.4s, v20.4s+ sub v25.4s, v13.4s, v12.4s+ add v17.4s, v6.4s, v9.4s+ mul v19.4s, v10.4s, v3.4s+ trn2 v4.4s, v2.4s, v25.4s+ ldur q24, [x2, #-0x50]+ trn2 v29.4s, v17.4s, v31.4s+ sqrdmulh v15.4s, v10.4s, v20.4s+ mls v28.4s, v5.4s, v7.s[0]+ trn2 v3.2d, v4.2d, v29.2d+ sqrdmulh v12.4s, v3.4s, v24.4s+ mul v16.4s, v3.4s, v21.4s+ mls v19.4s, v15.4s, v7.s[0]+ ldur q10, [x2, #-0xa0]+ add v13.4s, v27.4s, v28.4s+ mls v16.4s, v12.4s, v7.s[0]+ sqrdmulh v9.4s, v13.4s, v8.4s+ sub v30.4s, v27.4s, v28.4s+ ldr q18, [x1], #0x40+ mul v8.4s, v13.4s, v10.4s+ ldr q10, [x0, #0xd0]+ sqrdmulh v14.4s, v30.4s, v11.4s+ ldr q23, [x0, #0xe0]+ sqrdmulh v13.4s, v10.4s, v18.s[1]+ sqrdmulh v12.4s, v23.4s, v18.s[1]+ ldur q6, [x2, #-0x80]+ mul v3.4s, v10.4s, v18.s[0]+ mls v3.4s, v13.4s, v7.s[0]+ ldr q13, [x0, #0xf0]+ trn1 v27.4s, v2.4s, v25.4s+ mul v2.4s, v30.4s, v6.4s+ trn1 v20.4s, v17.4s, v31.4s+ trn1 v25.2d, v4.2d, v29.2d+ sqrdmulh v10.4s, v13.4s, v18.s[1]+ trn2 v5.2d, v27.2d, v20.2d+ ldur q6, [x2, #-0x10]+ mls v8.4s, v9.4s, v7.s[0]+ sub v15.4s, v25.4s, v16.4s+ sqrdmulh v31.4s, v5.4s, v24.4s+ sqrdmulh v30.4s, v15.4s, v6.4s+ ldur q9, [x2, #-0x30]+ mul v4.4s, v5.4s, v21.4s+ ldur q21, [x2, #-0x40]+ ldur q6, [x2, #-0x20]+ add v5.4s, v25.4s, v16.4s+ mls v4.4s, v31.4s, v7.s[0]+ mul v0.4s, v5.4s, v21.4s+ mul v17.4s, v13.4s, v18.s[0]+ mls v17.4s, v10.4s, v7.s[0]+ ldr q28, [x0, #0xb0]+ sqrdmulh v26.4s, v5.4s, v9.4s+ mul v9.4s, v15.4s, v6.4s+ trn1 v6.2d, v22.2d, v1.2d+ mls v9.4s, v30.4s, v7.s[0]+ add v25.4s, v28.4s, v17.4s+ mls v2.4s, v14.4s, v7.s[0]+ trn1 v5.2d, v27.2d, v20.2d+ ldr q20, [x2, #0x10]+ mul v29.4s, v25.4s, v18.s[2]+ add v15.4s, v6.4s, v19.4s+ ldr q30, [x0, #0xc0]+ sub v19.4s, v6.4s, v19.4s+ add v31.4s, v15.4s, v8.4s+ mls v0.4s, v26.4s, v7.s[0]+ ldur q14, [x1, #-0x30]+ add v21.4s, v19.4s, v2.4s+ sub v24.4s, v19.4s, v2.4s+ sqrdmulh v27.4s, v25.4s, v18.s[3]+ sub v26.4s, v15.4s, v8.4s+ ldr q2, [x0, #0x90]+ mul v16.4s, v30.4s, v18.s[0]+ sub v25.4s, v28.4s, v17.4s+ trn1 v11.4s, v31.4s, v26.4s+ ldr q1, [x0, #0xa0]+ trn1 v6.4s, v21.4s, v24.4s+ sqrdmulh v13.4s, v25.4s, v14.s[1]+ add v8.4s, v2.4s, v3.4s+ trn2 v28.2d, v11.2d, v6.2d+ sqrdmulh v19.4s, v30.4s, v18.s[1]+ sub v10.4s, v5.4s, v4.4s+ ldur q22, [x1, #-0x20]+ str q28, [x0, #0x20]+ mls v29.4s, v27.4s, v7.s[0]+ add v15.4s, v10.4s, v9.4s+ mul v25.4s, v25.4s, v14.s[0]+ ldur q27, [x1, #-0x10]+ trn2 v17.4s, v31.4s, v26.4s+ trn2 v21.4s, v21.4s, v24.4s+ mls v16.4s, v19.4s, v7.s[0]+ sub v24.4s, v8.4s, v29.4s+ sub v10.4s, v10.4s, v9.4s+ mls v25.4s, v13.4s, v7.s[0]+ trn1 v13.2d, v11.2d, v6.2d+ ldr q28, [x0, #0x80]+ sqrdmulh v30.4s, v24.4s, v22.s[1]+ trn2 v19.2d, v17.2d, v21.2d+ trn1 v6.2d, v17.2d, v21.2d+ mul v31.4s, v23.4s, v18.s[0]+ str q13, [x0], #0x80+ stur q6, [x0, #-0x70]+ stur q19, [x0, #-0x50]+ ldr q11, [x2, #0x50]+ mls v31.4s, v12.4s, v7.s[0]+ ldr q21, [x2, #0x60]+ trn1 v9.4s, v15.4s, v10.4s+ trn2 v6.4s, v15.4s, v10.4s+ mul v24.4s, v24.4s, v22.s[0]+ sub v10.4s, v2.4s, v3.4s+ ldr q3, [x2], #0xc0+ mls v24.4s, v30.4s, v7.s[0]+ add v26.4s, v8.4s, v29.4s+ ldur q8, [x2, #-0x90]+ add v17.4s, v5.4s, v4.4s+ sqrdmulh v2.4s, v26.4s, v14.s[3]+ sub v13.4s, v1.4s, v31.4s+ add v30.4s, v1.4s, v31.4s+ add v15.4s, v10.4s, v25.4s+ sqrdmulh v19.4s, v13.4s, v14.s[1]+ sub v25.4s, v10.4s, v25.4s+ mul v29.4s, v13.4s, v14.s[0]+ sub v5.4s, v28.4s, v16.4s+ sqrdmulh v4.4s, v30.4s, v18.s[3]+ sub v23.4s, v17.4s, v0.4s+ add v31.4s, v17.4s, v0.4s+ mul v18.4s, v30.4s, v18.s[2]+ add v1.4s, v28.4s, v16.4s+ trn2 v12.4s, v31.4s, v23.4s+ mls v29.4s, v19.4s, v7.s[0]+ trn1 v13.4s, v31.4s, v23.4s+ trn2 v30.2d, v12.2d, v6.2d+ mls v18.4s, v4.4s, v7.s[0]+ trn2 v10.2d, v13.2d, v9.2d+ trn1 v31.2d, v13.2d, v9.2d+ mul v19.4s, v26.4s, v14.s[2]+ trn1 v12.2d, v12.2d, v6.2d+ sub v6.4s, v5.4s, v29.4s+ mls v19.4s, v2.4s, v7.s[0]+ add v13.4s, v5.4s, v29.4s+ stur q10, [x0, #-0x20]+ sub v10.4s, v1.4s, v18.4s+ add v28.4s, v1.4s, v18.4s+ sqrdmulh v5.4s, v25.4s, v27.s[1]+ stur q31, [x0, #-0x40]+ add v26.4s, v10.4s, v24.4s+ sub v31.4s, v10.4s, v24.4s+ mul v9.4s, v25.4s, v27.s[0]+ stur q12, [x0, #-0x30]+ sub v24.4s, v28.4s, v19.4s+ sqrdmulh v10.4s, v15.4s, v22.s[3]+ trn1 v1.4s, v26.4s, v31.4s+ stur q30, [x0, #-0x10]+ add v30.4s, v28.4s, v19.4s+ mls v9.4s, v5.4s, v7.s[0]+ trn2 v25.4s, v26.4s, v31.4s+ trn2 v14.4s, v30.4s, v24.4s+ mul v12.4s, v15.4s, v22.s[2]+ trn1 v22.4s, v30.4s, v24.4s+ trn1 v27.2d, v14.2d, v25.2d+ mls v12.4s, v10.4s, v7.s[0]+ trn2 v30.2d, v14.2d, v25.2d+ sub v31.4s, v6.4s, v9.4s+ trn2 v10.2d, v22.2d, v1.2d+ mul v28.4s, v30.4s, v3.4s+ subs x4, x4, #0x1+ cbnz x4, Lmld_ntt_layer45678_start+ add v9.4s, v6.4s, v9.4s+ sqrdmulh v6.4s, v30.4s, v20.4s+ ldur q24, [x2, #-0xa0]+ add v25.4s, v13.4s, v12.4s+ sub v15.4s, v13.4s, v12.4s+ mul v19.4s, v10.4s, v3.4s+ trn2 v5.4s, v9.4s, v31.4s+ sqrdmulh v3.4s, v10.4s, v20.4s+ trn2 v10.4s, v25.4s, v15.4s+ mls v28.4s, v6.4s, v7.s[0]+ trn2 v13.2d, v10.2d, v5.2d+ ldur q30, [x2, #-0x50]+ mul v12.4s, v13.4s, v21.4s+ mls v19.4s, v3.4s, v7.s[0]+ add v20.4s, v27.4s, v28.4s+ sqrdmulh v13.4s, v13.4s, v30.4s+ sub v3.4s, v27.4s, v28.4s+ mul v24.4s, v20.4s, v24.4s+ sqrdmulh v6.4s, v3.4s, v11.4s+ ldur q27, [x2, #-0x80]+ mls v12.4s, v13.4s, v7.s[0]+ trn1 v25.4s, v25.4s, v15.4s+ mul v27.4s, v3.4s, v27.4s+ trn1 v31.4s, v9.4s, v31.4s+ trn1 v3.2d, v10.2d, v5.2d+ ldur q13, [x2, #-0x30]+ ldur q15, [x2, #-0x40]+ sqrdmulh v9.4s, v20.4s, v8.4s+ trn2 v20.2d, v25.2d, v31.2d+ ldur q10, [x2, #-0x10]+ mls v27.4s, v6.4s, v7.s[0]+ add v5.4s, v3.4s, v12.4s+ sub v6.4s, v3.4s, v12.4s+ sqrdmulh v3.4s, v20.4s, v30.4s+ trn1 v12.2d, v22.2d, v1.2d+ sqrdmulh v10.4s, v6.4s, v10.4s+ mls v24.4s, v9.4s, v7.s[0]+ sub v9.4s, v12.4s, v19.4s+ trn1 v25.2d, v25.2d, v31.2d+ sqrdmulh v31.4s, v5.4s, v13.4s+ add v30.4s, v9.4s, v27.4s+ add v13.4s, v12.4s, v19.4s+ mul v1.4s, v20.4s, v21.4s+ ldur q12, [x2, #-0x20]+ add v21.4s, v13.4s, v24.4s+ sub v13.4s, v13.4s, v24.4s+ mls v1.4s, v3.4s, v7.s[0]+ sub v3.4s, v9.4s, v27.4s+ mul v9.4s, v6.4s, v12.4s+ trn2 v12.4s, v21.4s, v13.4s+ trn1 v6.4s, v30.4s, v3.4s+ trn2 v30.4s, v30.4s, v3.4s+ mls v9.4s, v10.4s, v7.s[0]+ trn1 v13.4s, v21.4s, v13.4s+ mul v15.4s, v5.4s, v15.4s+ sub v3.4s, v25.4s, v1.4s+ add v5.4s, v25.4s, v1.4s+ mls v15.4s, v31.4s, v7.s[0]+ trn1 v21.2d, v13.2d, v6.2d+ trn2 v6.2d, v13.2d, v6.2d+ add v10.4s, v3.4s, v9.4s+ sub v13.4s, v3.4s, v9.4s+ str q21, [x0], #0x80+ trn1 v3.2d, v12.2d, v30.2d+ trn2 v31.2d, v12.2d, v30.2d+ trn1 v21.4s, v10.4s, v13.4s+ sub v30.4s, v5.4s, v15.4s+ add v12.4s, v5.4s, v15.4s+ stur q3, [x0, #-0x70]+ trn2 v13.4s, v10.4s, v13.4s+ trn1 v19.4s, v12.4s, v30.4s+ trn2 v12.4s, v12.4s, v30.4s+ stur q6, [x0, #-0x60]+ stur q31, [x0, #-0x50]+ trn1 v10.2d, v19.2d, v21.2d+ trn2 v3.2d, v19.2d, v21.2d+ trn1 v21.2d, v12.2d, v13.2d+ trn2 v13.2d, v12.2d, v13.2d+ stur q10, [x0, #-0x40]+ stur q3, [x0, #-0x20]+ stur q13, [x0, #-0x10]+ stur q21, [x0, #-0x30]+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(ntt_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,106 @@+/* Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: poly_pointwise_montgomery_aarch64_asm+ Description: AArch64 pointwise Montgomery multiplication of two polynomials+ Signature: void mld_poly_pointwise_montgomery_aarch64_asm(int32_t a[256], const int32_t b[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t a[256]+ description: Input/output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int32_t b[256]+ description: Input polynomial (256 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ (!defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_pointwise_montgomery_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_pointwise_montgomery_aarch64_asm)+MLD_ASM_FN_SYMBOL(poly_pointwise_montgomery_aarch64_asm)++ .cfi_startproc+ mov w3, #0xe001 // =57345+ movk w3, #0x7f, lsl #16+ dup v0.4s, w3+ mov w3, #0x2001 // =8193+ movk w3, #0x380, lsl #16+ dup v1.4s, w3+ mov x3, #0x40 // =64++Lmld_poly_pointwise_montgomery_loop_start:+ ldr q16, [x0]+ ldr q17, [x0, #0x10]+ ldr q18, [x0, #0x20]+ ldr q19, [x0, #0x30]+ ldr q21, [x1, #0x10]+ ldr q22, [x1, #0x20]+ ldr q23, [x1, #0x30]+ ldr q20, [x1], #0x40+ smull v24.2d, v16.2s, v20.2s+ smull2 v25.2d, v16.4s, v20.4s+ smull v26.2d, v17.2s, v21.2s+ smull2 v27.2d, v17.4s, v21.4s+ smull v28.2d, v18.2s, v22.2s+ smull2 v29.2d, v18.4s, v22.4s+ smull v30.2d, v19.2s, v23.2s+ smull2 v31.2d, v19.4s, v23.4s+ uzp1 v16.4s, v24.4s, v25.4s+ mul v16.4s, v16.4s, v1.4s+ smlsl v24.2d, v16.2s, v0.2s+ smlsl2 v25.2d, v16.4s, v0.4s+ uzp2 v16.4s, v24.4s, v25.4s+ uzp1 v17.4s, v26.4s, v27.4s+ mul v17.4s, v17.4s, v1.4s+ smlsl v26.2d, v17.2s, v0.2s+ smlsl2 v27.2d, v17.4s, v0.4s+ uzp2 v17.4s, v26.4s, v27.4s+ uzp1 v18.4s, v28.4s, v29.4s+ mul v18.4s, v18.4s, v1.4s+ smlsl v28.2d, v18.2s, v0.2s+ smlsl2 v29.2d, v18.4s, v0.4s+ uzp2 v18.4s, v28.4s, v29.4s+ uzp1 v19.4s, v30.4s, v31.4s+ mul v19.4s, v19.4s, v1.4s+ smlsl v30.2d, v19.2s, v0.2s+ smlsl2 v31.2d, v19.4s, v0.4s+ uzp2 v19.4s, v30.4s, v31.4s+ str q17, [x0, #0x10]+ str q18, [x0, #0x20]+ str q19, [x0, #0x30]+ str q16, [x0], #0x40+ subs x3, x3, #0x4+ cbnz x3, Lmld_poly_pointwise_montgomery_loop_start+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_pointwise_montgomery_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && (!MLD_CONFIG_NO_SIGN_API || \+ !MLD_CONFIG_NO_VERIFY_API || MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST) \+ && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,69 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+/*yaml+ Name: poly_caddq_aarch64_asm+ Description: AArch64 conditional addition of q to each coefficient+ Signature: void mld_poly_caddq_aarch64_asm(int32_t a[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t a[256]+ description: Input/output polynomial (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_poly_caddq_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_caddq_aarch64_asm)+MLD_ASM_FN_SYMBOL(poly_caddq_aarch64_asm)++ .cfi_startproc+ mov w9, #0xe001 // =57345+ movk w9, #0x7f, lsl #16+ dup v4.4s, w9+ mov x1, #0x10 // =16++Lmld_poly_caddq_loop:+ ldr q0, [x0]+ ldr q1, [x0, #0x10]+ ldr q2, [x0, #0x20]+ ldr q3, [x0, #0x30]+ ushr v5.4s, v0.4s, #0x1f+ mla v0.4s, v5.4s, v4.4s+ ushr v5.4s, v1.4s, #0x1f+ mla v1.4s, v5.4s, v4.4s+ ushr v5.4s, v2.4s, #0x1f+ mla v2.4s, v5.4s, v4.4s+ ushr v5.4s, v3.4s, #0x1f+ mla v3.4s, v5.4s, v4.4s+ str q1, [x0, #0x10]+ str q2, [x0, #0x20]+ str q3, [x0, #0x30]+ str q0, [x0], #0x40+ subs x1, x1, #0x1+ b.ne Lmld_poly_caddq_loop+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_caddq_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,76 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+/*yaml+ Name: poly_chknorm_aarch64_asm+ Description: AArch64 infinity-norm bound check on polynomial coefficients+ Signature: int mld_poly_chknorm_aarch64_asm(const int32_t a[256], int32_t B)+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int32_t a[256]+ description: Input polynomial (256 x int32_t)+ x1:+ type: scalar+ c_parameter: int32_t B+ description: Norm bound+ test_with: 131072 # representative non-negative bound (1 << 17)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_poly_chknorm_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_chknorm_aarch64_asm)+MLD_ASM_FN_SYMBOL(poly_chknorm_aarch64_asm)++ .cfi_startproc+ dup v20.4s, w1+ eor v21.16b, v21.16b, v21.16b+ mov x2, #0x10 // =16++Lmld_poly_chknorm_loop:+ ldr q1, [x0, #0x10]+ ldr q2, [x0, #0x20]+ ldr q3, [x0, #0x30]+ ldr q0, [x0], #0x40+ abs v1.4s, v1.4s+ cmge v1.4s, v1.4s, v20.4s+ orr v21.16b, v21.16b, v1.16b+ abs v2.4s, v2.4s+ cmge v2.4s, v2.4s, v20.4s+ orr v21.16b, v21.16b, v2.16b+ abs v3.4s, v3.4s+ cmge v3.4s, v3.4s, v20.4s+ orr v21.16b, v21.16b, v3.16b+ abs v0.4s, v0.4s+ cmge v0.4s, v0.4s, v20.4s+ orr v21.16b, v21.16b, v0.16b+ subs x2, x2, #0x1+ b.ne Lmld_poly_chknorm_loop+ umaxv s21, v21.4s+ fmov w0, s21+ and w0, w0, #0x1+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_chknorm_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,108 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+/*yaml+ Name: poly_decompose_32_aarch64_asm+ Description: AArch64 coefficient decomposition (alpha = (Q-1)/32)+ Signature: void mld_poly_decompose_32_aarch64_asm(int32_t a1[256], int32_t a0[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t a1[256]+ description: Output high-part polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t a0[256]+ description: Input polynomial / output low-part (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_NO_SIGN_API) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87))++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_poly_decompose_32_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_decompose_32_aarch64_asm)+MLD_ASM_FN_SYMBOL(poly_decompose_32_aarch64_asm)++ .cfi_startproc+ mov w4, #0xe001 // =57345+ movk w4, #0x7f, lsl #16+ dup v20.4s, w4+ mov w5, #0xe100 // =57600+ movk w5, #0x7b, lsl #16+ dup v21.4s, w5+ mov w7, #0xfe00 // =65024+ movk w7, #0x7, lsl #16+ dup v22.4s, w7+ mov w11, #0x401 // =1025+ movk w11, #0x4010, lsl #16+ dup v23.4s, w11+ mov x3, #0x10 // =16++Lmld_poly_decompose_32_loop:+ ldr q0, [x1]+ ldr q1, [x1, #0x10]+ ldr q2, [x1, #0x20]+ ldr q3, [x1, #0x30]+ sqdmulh v5.4s, v1.4s, v23.4s+ srshr v5.4s, v5.4s, #0x12+ cmgt v24.4s, v1.4s, v21.4s+ mls v1.4s, v5.4s, v22.4s+ bic v5.16b, v5.16b, v24.16b+ add v1.4s, v1.4s, v24.4s+ sqdmulh v6.4s, v2.4s, v23.4s+ srshr v6.4s, v6.4s, #0x12+ cmgt v24.4s, v2.4s, v21.4s+ mls v2.4s, v6.4s, v22.4s+ bic v6.16b, v6.16b, v24.16b+ add v2.4s, v2.4s, v24.4s+ sqdmulh v7.4s, v3.4s, v23.4s+ srshr v7.4s, v7.4s, #0x12+ cmgt v24.4s, v3.4s, v21.4s+ mls v3.4s, v7.4s, v22.4s+ bic v7.16b, v7.16b, v24.16b+ add v3.4s, v3.4s, v24.4s+ sqdmulh v4.4s, v0.4s, v23.4s+ srshr v4.4s, v4.4s, #0x12+ cmgt v24.4s, v0.4s, v21.4s+ mls v0.4s, v4.4s, v22.4s+ bic v4.16b, v4.16b, v24.16b+ add v0.4s, v0.4s, v24.4s+ str q5, [x0, #0x10]+ str q6, [x0, #0x20]+ str q7, [x0, #0x30]+ str q4, [x0], #0x40+ str q1, [x1, #0x10]+ str q2, [x1, #0x20]+ str q3, [x1, #0x30]+ str q0, [x1], #0x40+ subs x3, x3, #0x1+ b.ne Lmld_poly_decompose_32_loop+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_decompose_32_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_NO_SIGN_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,108 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+/*yaml+ Name: poly_decompose_88_aarch64_asm+ Description: AArch64 coefficient decomposition (alpha = (Q-1)/88)+ Signature: void mld_poly_decompose_88_aarch64_asm(int32_t a1[256], int32_t a0[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t a1[256]+ description: Output high-part polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t a0[256]+ description: Input polynomial / output low-part (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_NO_SIGN_API) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_poly_decompose_88_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_decompose_88_aarch64_asm)+MLD_ASM_FN_SYMBOL(poly_decompose_88_aarch64_asm)++ .cfi_startproc+ mov w4, #0xe001 // =57345+ movk w4, #0x7f, lsl #16+ dup v20.4s, w4+ mov w5, #0x6c00 // =27648+ movk w5, #0x7e, lsl #16+ dup v21.4s, w5+ mov w7, #0xe800 // =59392+ movk w7, #0x2, lsl #16+ dup v22.4s, w7+ mov w11, #0x581 // =1409+ movk w11, #0x5816, lsl #16+ dup v23.4s, w11+ mov x3, #0x10 // =16++Lmld_poly_decompose_88_loop:+ ldr q0, [x1]+ ldr q1, [x1, #0x10]+ ldr q2, [x1, #0x20]+ ldr q3, [x1, #0x30]+ sqdmulh v5.4s, v1.4s, v23.4s+ srshr v5.4s, v5.4s, #0x11+ cmgt v24.4s, v1.4s, v21.4s+ mls v1.4s, v5.4s, v22.4s+ bic v5.16b, v5.16b, v24.16b+ add v1.4s, v1.4s, v24.4s+ sqdmulh v6.4s, v2.4s, v23.4s+ srshr v6.4s, v6.4s, #0x11+ cmgt v24.4s, v2.4s, v21.4s+ mls v2.4s, v6.4s, v22.4s+ bic v6.16b, v6.16b, v24.16b+ add v2.4s, v2.4s, v24.4s+ sqdmulh v7.4s, v3.4s, v23.4s+ srshr v7.4s, v7.4s, #0x11+ cmgt v24.4s, v3.4s, v21.4s+ mls v3.4s, v7.4s, v22.4s+ bic v7.16b, v7.16b, v24.16b+ add v3.4s, v3.4s, v24.4s+ sqdmulh v4.4s, v0.4s, v23.4s+ srshr v4.4s, v4.4s, #0x11+ cmgt v24.4s, v0.4s, v21.4s+ mls v0.4s, v4.4s, v22.4s+ bic v4.16b, v4.16b, v24.16b+ add v0.4s, v0.4s, v24.4s+ str q5, [x0, #0x10]+ str q6, [x0, #0x20]+ str q7, [x0, #0x30]+ str q4, [x0], #0x40+ str q1, [x1, #0x10]+ str q2, [x1, #0x20]+ str q3, [x1, #0x30]+ str q0, [x1], #0x40+ subs x3, x3, #0x1+ b.ne Lmld_poly_decompose_88_loop+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_decompose_88_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_NO_SIGN_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44) \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,125 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+/*yaml+ Name: poly_use_hint_32_aarch64_asm+ Description: AArch64 hint application (alpha = (Q-1)/32)+ Signature: void mld_poly_use_hint_32_aarch64_asm(int32_t a[256], const int32_t h[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t a[256]+ description: Input/output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int32_t h[256]+ description: Hint polynomial (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_NO_VERIFY_API) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87))++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_poly_use_hint_32_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_use_hint_32_aarch64_asm)+MLD_ASM_FN_SYMBOL(poly_use_hint_32_aarch64_asm)++ .cfi_startproc+ mov w4, #0xe001 // =57345+ movk w4, #0x7f, lsl #16+ dup v20.4s, w4+ mov w5, #0xe100 // =57600+ movk w5, #0x7b, lsl #16+ dup v21.4s, w5+ mov w7, #0xfe00 // =65024+ movk w7, #0x7, lsl #16+ dup v22.4s, w7+ mov w11, #0x401 // =1025+ movk w11, #0x4010, lsl #16+ dup v23.4s, w11+ movi v24.4s, #0xf+ mov x3, #0x10 // =16++Lmld_poly_use_hint_32_loop:+ ldr q1, [x0, #0x10]+ ldr q2, [x0, #0x20]+ ldr q3, [x0, #0x30]+ ldr q0, [x0]+ ldr q5, [x1, #0x10]+ ldr q6, [x1, #0x20]+ ldr q7, [x1, #0x30]+ ldr q4, [x1], #0x40+ sqdmulh v17.4s, v1.4s, v23.4s+ srshr v17.4s, v17.4s, #0x12+ cmgt v25.4s, v1.4s, v21.4s+ mls v1.4s, v17.4s, v22.4s+ bic v17.16b, v17.16b, v25.16b+ add v1.4s, v1.4s, v25.4s+ cmle v1.4s, v1.4s, #0+ orr v1.4s, #0x1+ mla v17.4s, v1.4s, v5.4s+ and v17.16b, v17.16b, v24.16b+ sqdmulh v18.4s, v2.4s, v23.4s+ srshr v18.4s, v18.4s, #0x12+ cmgt v25.4s, v2.4s, v21.4s+ mls v2.4s, v18.4s, v22.4s+ bic v18.16b, v18.16b, v25.16b+ add v2.4s, v2.4s, v25.4s+ cmle v2.4s, v2.4s, #0+ orr v2.4s, #0x1+ mla v18.4s, v2.4s, v6.4s+ and v18.16b, v18.16b, v24.16b+ sqdmulh v19.4s, v3.4s, v23.4s+ srshr v19.4s, v19.4s, #0x12+ cmgt v25.4s, v3.4s, v21.4s+ mls v3.4s, v19.4s, v22.4s+ bic v19.16b, v19.16b, v25.16b+ add v3.4s, v3.4s, v25.4s+ cmle v3.4s, v3.4s, #0+ orr v3.4s, #0x1+ mla v19.4s, v3.4s, v7.4s+ and v19.16b, v19.16b, v24.16b+ sqdmulh v16.4s, v0.4s, v23.4s+ srshr v16.4s, v16.4s, #0x12+ cmgt v25.4s, v0.4s, v21.4s+ mls v0.4s, v16.4s, v22.4s+ bic v16.16b, v16.16b, v25.16b+ add v0.4s, v0.4s, v25.4s+ cmle v0.4s, v0.4s, #0+ orr v0.4s, #0x1+ mla v16.4s, v0.4s, v4.4s+ and v16.16b, v16.16b, v24.16b+ str q17, [x0, #0x10]+ str q18, [x0, #0x20]+ str q19, [x0, #0x30]+ str q16, [x0], #0x40+ subs x3, x3, #0x1+ b.ne Lmld_poly_use_hint_32_loop+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_use_hint_32_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_NO_VERIFY_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,133 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+/*yaml+ Name: poly_use_hint_88_aarch64_asm+ Description: AArch64 hint application (alpha = (Q-1)/88)+ Signature: void mld_poly_use_hint_88_aarch64_asm(int32_t a[256], const int32_t h[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t a[256]+ description: Input/output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int32_t h[256]+ description: Hint polynomial (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_NO_VERIFY_API) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_poly_use_hint_88_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_use_hint_88_aarch64_asm)+MLD_ASM_FN_SYMBOL(poly_use_hint_88_aarch64_asm)++ .cfi_startproc+ mov w4, #0xe001 // =57345+ movk w4, #0x7f, lsl #16+ dup v20.4s, w4+ mov w5, #0x6c00 // =27648+ movk w5, #0x7e, lsl #16+ dup v21.4s, w5+ mov w7, #0xe800 // =59392+ movk w7, #0x2, lsl #16+ dup v22.4s, w7+ mov w11, #0x581 // =1409+ movk w11, #0x5816, lsl #16+ dup v23.4s, w11+ movi v24.4s, #0x2b+ mov x3, #0x10 // =16++Lmld_poly_use_hint_88_loop:+ ldr q1, [x0, #0x10]+ ldr q2, [x0, #0x20]+ ldr q3, [x0, #0x30]+ ldr q0, [x0]+ ldr q5, [x1, #0x10]+ ldr q6, [x1, #0x20]+ ldr q7, [x1, #0x30]+ ldr q4, [x1], #0x40+ sqdmulh v17.4s, v1.4s, v23.4s+ srshr v17.4s, v17.4s, #0x11+ cmgt v25.4s, v1.4s, v21.4s+ mls v1.4s, v17.4s, v22.4s+ bic v17.16b, v17.16b, v25.16b+ add v1.4s, v1.4s, v25.4s+ cmle v1.4s, v1.4s, #0+ orr v1.4s, #0x1+ mla v17.4s, v1.4s, v5.4s+ cmgt v25.4s, v17.4s, v24.4s+ bic v17.16b, v17.16b, v25.16b+ umin v17.4s, v17.4s, v24.4s+ sqdmulh v18.4s, v2.4s, v23.4s+ srshr v18.4s, v18.4s, #0x11+ cmgt v25.4s, v2.4s, v21.4s+ mls v2.4s, v18.4s, v22.4s+ bic v18.16b, v18.16b, v25.16b+ add v2.4s, v2.4s, v25.4s+ cmle v2.4s, v2.4s, #0+ orr v2.4s, #0x1+ mla v18.4s, v2.4s, v6.4s+ cmgt v25.4s, v18.4s, v24.4s+ bic v18.16b, v18.16b, v25.16b+ umin v18.4s, v18.4s, v24.4s+ sqdmulh v19.4s, v3.4s, v23.4s+ srshr v19.4s, v19.4s, #0x11+ cmgt v25.4s, v3.4s, v21.4s+ mls v3.4s, v19.4s, v22.4s+ bic v19.16b, v19.16b, v25.16b+ add v3.4s, v3.4s, v25.4s+ cmle v3.4s, v3.4s, #0+ orr v3.4s, #0x1+ mla v19.4s, v3.4s, v7.4s+ cmgt v25.4s, v19.4s, v24.4s+ bic v19.16b, v19.16b, v25.16b+ umin v19.4s, v19.4s, v24.4s+ sqdmulh v16.4s, v0.4s, v23.4s+ srshr v16.4s, v16.4s, #0x11+ cmgt v25.4s, v0.4s, v21.4s+ mls v0.4s, v16.4s, v22.4s+ bic v16.16b, v16.16b, v25.16b+ add v0.4s, v0.4s, v25.4s+ cmle v0.4s, v0.4s, #0+ orr v0.4s, #0x1+ mla v16.4s, v0.4s, v4.4s+ cmgt v25.4s, v16.4s, v24.4s+ bic v16.16b, v16.16b, v25.16b+ umin v16.4s, v16.4s, v24.4s+ str q17, [x0, #0x10]+ str q18, [x0, #0x20]+ str q19, [x0, #0x30]+ str q16, [x0], #0x40+ subs x3, x3, #0x1+ b.ne Lmld_poly_use_hint_88_loop+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_use_hint_88_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_NO_VERIFY_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44) \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,157 @@+/* Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: polyvecl_pointwise_acc_montgomery_l4_aarch64_asm+ Description: AArch64 pointwise multiply-accumulate of length-4 polynomial vectors+ Signature: void mld_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm(int32_t r[256], const int32_t a[4][256], const int32_t b[4][256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t r[256]+ description: Output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 4096+ permissions: read-only+ c_parameter: const int32_t a[4][256]+ description: Input polynomial vector a (4 x 256 x int32_t)+ x2:+ type: buffer+ size_bytes: 4096+ permissions: read-only+ c_parameter: const int32_t b[4][256]+ description: Input polynomial vector b (4 x 256 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 4)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_aarch64_asm)+MLD_ASM_FN_SYMBOL(polyvecl_pointwise_acc_montgomery_l4_aarch64_asm)++ .cfi_startproc+ mov w3, #0xe001 // =57345+ movk w3, #0x7f, lsl #16+ dup v0.4s, w3+ mov w3, #0x2001 // =8193+ movk w3, #0x380, lsl #16+ dup v1.4s, w3+ mov x3, #0x40 // =64++Lmld_polyvecl_pointwise_acc_montgomery_l4_loop_start:+ ldr q17, [x1, #0x10]+ ldr q18, [x1, #0x20]+ ldr q19, [x1, #0x30]+ ldr q16, [x1], #0x40+ ldr q21, [x2, #0x10]+ ldr q22, [x2, #0x20]+ ldr q23, [x2, #0x30]+ ldr q20, [x2], #0x40+ smull v24.2d, v16.2s, v20.2s+ smull2 v25.2d, v16.4s, v20.4s+ smull v26.2d, v17.2s, v21.2s+ smull2 v27.2d, v17.4s, v21.4s+ smull v28.2d, v18.2s, v22.2s+ smull2 v29.2d, v18.4s, v22.4s+ smull v30.2d, v19.2s, v23.2s+ smull2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0x3c0]+ ldr q17, [x1, #0x3d0]+ ldr q18, [x1, #0x3e0]+ ldr q19, [x1, #0x3f0]+ ldr q20, [x2, #0x3c0]+ ldr q21, [x2, #0x3d0]+ ldr q22, [x2, #0x3e0]+ ldr q23, [x2, #0x3f0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0x7c0]+ ldr q17, [x1, #0x7d0]+ ldr q18, [x1, #0x7e0]+ ldr q19, [x1, #0x7f0]+ ldr q20, [x2, #0x7c0]+ ldr q21, [x2, #0x7d0]+ ldr q22, [x2, #0x7e0]+ ldr q23, [x2, #0x7f0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0xbc0]+ ldr q17, [x1, #0xbd0]+ ldr q18, [x1, #0xbe0]+ ldr q19, [x1, #0xbf0]+ ldr q20, [x2, #0xbc0]+ ldr q21, [x2, #0xbd0]+ ldr q22, [x2, #0xbe0]+ ldr q23, [x2, #0xbf0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ uzp1 v16.4s, v24.4s, v25.4s+ mul v16.4s, v16.4s, v1.4s+ smlsl v24.2d, v16.2s, v0.2s+ smlsl2 v25.2d, v16.4s, v0.4s+ uzp2 v16.4s, v24.4s, v25.4s+ uzp1 v17.4s, v26.4s, v27.4s+ mul v17.4s, v17.4s, v1.4s+ smlsl v26.2d, v17.2s, v0.2s+ smlsl2 v27.2d, v17.4s, v0.4s+ uzp2 v17.4s, v26.4s, v27.4s+ uzp1 v18.4s, v28.4s, v29.4s+ mul v18.4s, v18.4s, v1.4s+ smlsl v28.2d, v18.2s, v0.2s+ smlsl2 v29.2d, v18.4s, v0.4s+ uzp2 v18.4s, v28.4s, v29.4s+ uzp1 v19.4s, v30.4s, v31.4s+ mul v19.4s, v19.4s, v1.4s+ smlsl v30.2d, v19.2s, v0.2s+ smlsl2 v31.2d, v19.4s, v0.4s+ uzp2 v19.4s, v30.4s, v31.4s+ str q17, [x0, #0x10]+ str q18, [x0, #0x20]+ str q19, [x0, #0x30]+ str q16, [x0], #0x40+ subs x3, x3, #0x4+ cbnz x3, Lmld_polyvecl_pointwise_acc_montgomery_l4_loop_start+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(polyvecl_pointwise_acc_montgomery_l4_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 4) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,173 @@+/* Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: polyvecl_pointwise_acc_montgomery_l5_aarch64_asm+ Description: AArch64 pointwise multiply-accumulate of length-5 polynomial vectors+ Signature: void mld_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm(int32_t r[256], const int32_t a[5][256], const int32_t b[5][256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t r[256]+ description: Output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 5120+ permissions: read-only+ c_parameter: const int32_t a[5][256]+ description: Input polynomial vector a (5 x 256 x int32_t)+ x2:+ type: buffer+ size_bytes: 5120+ permissions: read-only+ c_parameter: const int32_t b[5][256]+ description: Input polynomial vector b (5 x 256 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 5)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_aarch64_asm)+MLD_ASM_FN_SYMBOL(polyvecl_pointwise_acc_montgomery_l5_aarch64_asm)++ .cfi_startproc+ mov w3, #0xe001 // =57345+ movk w3, #0x7f, lsl #16+ dup v0.4s, w3+ mov w3, #0x2001 // =8193+ movk w3, #0x380, lsl #16+ dup v1.4s, w3+ mov x3, #0x40 // =64++Lmld_polyvecl_pointwise_acc_montgomery_l5_loop_start:+ ldr q17, [x1, #0x10]+ ldr q18, [x1, #0x20]+ ldr q19, [x1, #0x30]+ ldr q16, [x1], #0x40+ ldr q21, [x2, #0x10]+ ldr q22, [x2, #0x20]+ ldr q23, [x2, #0x30]+ ldr q20, [x2], #0x40+ smull v24.2d, v16.2s, v20.2s+ smull2 v25.2d, v16.4s, v20.4s+ smull v26.2d, v17.2s, v21.2s+ smull2 v27.2d, v17.4s, v21.4s+ smull v28.2d, v18.2s, v22.2s+ smull2 v29.2d, v18.4s, v22.4s+ smull v30.2d, v19.2s, v23.2s+ smull2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0x3c0]+ ldr q17, [x1, #0x3d0]+ ldr q18, [x1, #0x3e0]+ ldr q19, [x1, #0x3f0]+ ldr q20, [x2, #0x3c0]+ ldr q21, [x2, #0x3d0]+ ldr q22, [x2, #0x3e0]+ ldr q23, [x2, #0x3f0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0x7c0]+ ldr q17, [x1, #0x7d0]+ ldr q18, [x1, #0x7e0]+ ldr q19, [x1, #0x7f0]+ ldr q20, [x2, #0x7c0]+ ldr q21, [x2, #0x7d0]+ ldr q22, [x2, #0x7e0]+ ldr q23, [x2, #0x7f0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0xbc0]+ ldr q17, [x1, #0xbd0]+ ldr q18, [x1, #0xbe0]+ ldr q19, [x1, #0xbf0]+ ldr q20, [x2, #0xbc0]+ ldr q21, [x2, #0xbd0]+ ldr q22, [x2, #0xbe0]+ ldr q23, [x2, #0xbf0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0xfc0]+ ldr q17, [x1, #0xfd0]+ ldr q18, [x1, #0xfe0]+ ldr q19, [x1, #0xff0]+ ldr q20, [x2, #0xfc0]+ ldr q21, [x2, #0xfd0]+ ldr q22, [x2, #0xfe0]+ ldr q23, [x2, #0xff0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ uzp1 v16.4s, v24.4s, v25.4s+ mul v16.4s, v16.4s, v1.4s+ smlsl v24.2d, v16.2s, v0.2s+ smlsl2 v25.2d, v16.4s, v0.4s+ uzp2 v16.4s, v24.4s, v25.4s+ uzp1 v17.4s, v26.4s, v27.4s+ mul v17.4s, v17.4s, v1.4s+ smlsl v26.2d, v17.2s, v0.2s+ smlsl2 v27.2d, v17.4s, v0.4s+ uzp2 v17.4s, v26.4s, v27.4s+ uzp1 v18.4s, v28.4s, v29.4s+ mul v18.4s, v18.4s, v1.4s+ smlsl v28.2d, v18.2s, v0.2s+ smlsl2 v29.2d, v18.4s, v0.4s+ uzp2 v18.4s, v28.4s, v29.4s+ uzp1 v19.4s, v30.4s, v31.4s+ mul v19.4s, v19.4s, v1.4s+ smlsl v30.2d, v19.2s, v0.2s+ smlsl2 v31.2d, v19.4s, v0.4s+ uzp2 v19.4s, v30.4s, v31.4s+ str q17, [x0, #0x10]+ str q18, [x0, #0x20]+ str q19, [x0, #0x30]+ str q16, [x0], #0x40+ subs x3, x3, #0x4+ cbnz x3, Lmld_polyvecl_pointwise_acc_montgomery_l5_loop_start+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(polyvecl_pointwise_acc_montgomery_l5_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 5) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,205 @@+/* Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: polyvecl_pointwise_acc_montgomery_l7_aarch64_asm+ Description: AArch64 pointwise multiply-accumulate of length-7 polynomial vectors+ Signature: void mld_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm(int32_t r[256], const int32_t a[7][256], const int32_t b[7][256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t r[256]+ description: Output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 7168+ permissions: read-only+ c_parameter: const int32_t a[7][256]+ description: Input polynomial vector a (7 x 256 x int32_t)+ x2:+ type: buffer+ size_bytes: 7168+ permissions: read-only+ c_parameter: const int32_t b[7][256]+ description: Input polynomial vector b (7 x 256 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 7)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_aarch64_asm)+MLD_ASM_FN_SYMBOL(polyvecl_pointwise_acc_montgomery_l7_aarch64_asm)++ .cfi_startproc+ mov w3, #0xe001 // =57345+ movk w3, #0x7f, lsl #16+ dup v0.4s, w3+ mov w3, #0x2001 // =8193+ movk w3, #0x380, lsl #16+ dup v1.4s, w3+ mov x3, #0x40 // =64++Lmld_polyvecl_pointwise_acc_montgomery_l7_loop_start:+ ldr q17, [x1, #0x10]+ ldr q18, [x1, #0x20]+ ldr q19, [x1, #0x30]+ ldr q16, [x1], #0x40+ ldr q21, [x2, #0x10]+ ldr q22, [x2, #0x20]+ ldr q23, [x2, #0x30]+ ldr q20, [x2], #0x40+ smull v24.2d, v16.2s, v20.2s+ smull2 v25.2d, v16.4s, v20.4s+ smull v26.2d, v17.2s, v21.2s+ smull2 v27.2d, v17.4s, v21.4s+ smull v28.2d, v18.2s, v22.2s+ smull2 v29.2d, v18.4s, v22.4s+ smull v30.2d, v19.2s, v23.2s+ smull2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0x3c0]+ ldr q17, [x1, #0x3d0]+ ldr q18, [x1, #0x3e0]+ ldr q19, [x1, #0x3f0]+ ldr q20, [x2, #0x3c0]+ ldr q21, [x2, #0x3d0]+ ldr q22, [x2, #0x3e0]+ ldr q23, [x2, #0x3f0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0x7c0]+ ldr q17, [x1, #0x7d0]+ ldr q18, [x1, #0x7e0]+ ldr q19, [x1, #0x7f0]+ ldr q20, [x2, #0x7c0]+ ldr q21, [x2, #0x7d0]+ ldr q22, [x2, #0x7e0]+ ldr q23, [x2, #0x7f0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0xbc0]+ ldr q17, [x1, #0xbd0]+ ldr q18, [x1, #0xbe0]+ ldr q19, [x1, #0xbf0]+ ldr q20, [x2, #0xbc0]+ ldr q21, [x2, #0xbd0]+ ldr q22, [x2, #0xbe0]+ ldr q23, [x2, #0xbf0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0xfc0]+ ldr q17, [x1, #0xfd0]+ ldr q18, [x1, #0xfe0]+ ldr q19, [x1, #0xff0]+ ldr q20, [x2, #0xfc0]+ ldr q21, [x2, #0xfd0]+ ldr q22, [x2, #0xfe0]+ ldr q23, [x2, #0xff0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0x13c0]+ ldr q17, [x1, #0x13d0]+ ldr q18, [x1, #0x13e0]+ ldr q19, [x1, #0x13f0]+ ldr q20, [x2, #0x13c0]+ ldr q21, [x2, #0x13d0]+ ldr q22, [x2, #0x13e0]+ ldr q23, [x2, #0x13f0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ ldr q16, [x1, #0x17c0]+ ldr q17, [x1, #0x17d0]+ ldr q18, [x1, #0x17e0]+ ldr q19, [x1, #0x17f0]+ ldr q20, [x2, #0x17c0]+ ldr q21, [x2, #0x17d0]+ ldr q22, [x2, #0x17e0]+ ldr q23, [x2, #0x17f0]+ smlal v24.2d, v16.2s, v20.2s+ smlal2 v25.2d, v16.4s, v20.4s+ smlal v26.2d, v17.2s, v21.2s+ smlal2 v27.2d, v17.4s, v21.4s+ smlal v28.2d, v18.2s, v22.2s+ smlal2 v29.2d, v18.4s, v22.4s+ smlal v30.2d, v19.2s, v23.2s+ smlal2 v31.2d, v19.4s, v23.4s+ uzp1 v16.4s, v24.4s, v25.4s+ mul v16.4s, v16.4s, v1.4s+ smlsl v24.2d, v16.2s, v0.2s+ smlsl2 v25.2d, v16.4s, v0.4s+ uzp2 v16.4s, v24.4s, v25.4s+ uzp1 v17.4s, v26.4s, v27.4s+ mul v17.4s, v17.4s, v1.4s+ smlsl v26.2d, v17.2s, v0.2s+ smlsl2 v27.2d, v17.4s, v0.4s+ uzp2 v17.4s, v26.4s, v27.4s+ uzp1 v18.4s, v28.4s, v29.4s+ mul v18.4s, v18.4s, v1.4s+ smlsl v28.2d, v18.2s, v0.2s+ smlsl2 v29.2d, v18.4s, v0.4s+ uzp2 v18.4s, v28.4s, v29.4s+ uzp1 v19.4s, v30.4s, v31.4s+ mul v19.4s, v19.4s, v1.4s+ smlsl v30.2d, v19.2s, v0.2s+ smlsl2 v31.2d, v19.4s, v0.4s+ uzp2 v19.4s, v30.4s, v31.4s+ str q17, [x0, #0x10]+ str q18, [x0, #0x20]+ str q19, [x0, #0x30]+ str q16, [x0], #0x40+ subs x3, x3, #0x4+ cbnz x3, Lmld_polyvecl_pointwise_acc_montgomery_l7_loop_start+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(polyvecl_pointwise_acc_montgomery_l7_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 7) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,103 @@+/*+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: polyz_unpack_17_aarch64_asm+ Description: AArch64 unpacking of 17-bit packed coefficients+ Signature: void mld_polyz_unpack_17_aarch64_asm(int32_t r[256], const uint8_t buf[576], const uint8_t indices[64])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t r[256]+ description: Output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 576+ permissions: read-only+ c_parameter: const uint8_t buf[576]+ description: Packed input bytes+ x2:+ type: buffer+ size_bytes: 64+ permissions: read-only+ c_parameter: const uint8_t indices[64]+ description: Permutation index table (64 x uint8_t)+*/++ #include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ (!defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_polyz_unpack_17_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(polyz_unpack_17_aarch64_asm)+MLD_ASM_FN_SYMBOL(polyz_unpack_17_aarch64_asm)++ .cfi_startproc+ ldr q24, [x2]+ ldr q25, [x2, #0x10]+ ldr q26, [x2, #0x20]+ ldr q27, [x2, #0x30]+ mov x3, #0xfe00000000 // =1090921693184+ mov v28.d[0], x3+ mov x3, #0xfc // =252+ movk x3, #0xfa, lsl #32+ mov v28.d[1], x3+ movi v29.4s, #0x3, msl #16+ movi v30.4s, #0x2, lsl #16+ mov x9, #0x10 // =16++Lmld_polyz_unpack_17_loop:+ ld1 { v0.16b, v1.16b }, [x1]+ add x1, x1, #0x14+ ld1 { v2.16b }, [x1], #16+ tbl v4.16b, { v0.16b }, v24.16b+ tbl v5.16b, { v0.16b, v1.16b }, v25.16b+ tbl v6.16b, { v1.16b }, v26.16b+ tbl v7.16b, { v1.16b, v2.16b }, v27.16b+ ushl v4.4s, v4.4s, v28.4s+ and v4.16b, v4.16b, v29.16b+ sub v4.4s, v30.4s, v4.4s+ ushl v5.4s, v5.4s, v28.4s+ and v5.16b, v5.16b, v29.16b+ sub v5.4s, v30.4s, v5.4s+ ushl v6.4s, v6.4s, v28.4s+ and v6.16b, v6.16b, v29.16b+ sub v6.4s, v30.4s, v6.4s+ ushl v7.4s, v7.4s, v28.4s+ and v7.16b, v7.16b, v29.16b+ sub v7.4s, v30.4s, v7.4s+ str q5, [x0, #0x10]+ str q6, [x0, #0x20]+ str q7, [x0, #0x30]+ str q4, [x0], #0x40+ subs x9, x9, #0x1+ b.ne Lmld_polyz_unpack_17_loop+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(polyz_unpack_17_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && (!MLD_CONFIG_NO_SIGN_API || \+ !MLD_CONFIG_NO_VERIFY_API) && !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44) \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,100 @@+/*+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: polyz_unpack_19_aarch64_asm+ Description: AArch64 unpacking of 19-bit packed coefficients+ Signature: void mld_polyz_unpack_19_aarch64_asm(int32_t r[256], const uint8_t buf[640], const uint8_t indices[64])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t r[256]+ description: Output polynomial (256 x int32_t)+ x1:+ type: buffer+ size_bytes: 640+ permissions: read-only+ c_parameter: const uint8_t buf[640]+ description: Packed input bytes+ x2:+ type: buffer+ size_bytes: 64+ permissions: read-only+ c_parameter: const uint8_t indices[64]+ description: Permutation index table (64 x uint8_t)+*/++ #include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ (!defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87))++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_polyz_unpack_19_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(polyz_unpack_19_aarch64_asm)+MLD_ASM_FN_SYMBOL(polyz_unpack_19_aarch64_asm)++ .cfi_startproc+ ldr q24, [x2]+ ldr q25, [x2, #0x10]+ ldr q26, [x2, #0x20]+ ldr q27, [x2, #0x30]+ mov x3, #0xfc00000000 // =1082331758592+ dup v28.2d, x3+ movi v29.4s, #0xf, msl #16+ movi v30.4s, #0x8, lsl #16+ mov x9, #0x10 // =16++Lmld_polyz_unpack_19_loop:+ ld1 { v0.16b, v1.16b }, [x1]+ add x1, x1, #0x18+ ld1 { v2.16b }, [x1], #16+ tbl v4.16b, { v0.16b }, v24.16b+ tbl v5.16b, { v0.16b, v1.16b }, v25.16b+ tbl v6.16b, { v1.16b }, v26.16b+ tbl v7.16b, { v1.16b, v2.16b }, v27.16b+ ushl v4.4s, v4.4s, v28.4s+ and v4.16b, v4.16b, v29.16b+ sub v4.4s, v30.4s, v4.4s+ ushl v5.4s, v5.4s, v28.4s+ and v5.16b, v5.16b, v29.16b+ sub v5.4s, v30.4s, v5.4s+ ushl v6.4s, v6.4s, v28.4s+ and v6.16b, v6.16b, v29.16b+ sub v6.4s, v30.4s, v6.4s+ ushl v7.4s, v7.4s, v28.4s+ and v7.16b, v7.16b, v29.16b+ sub v7.4s, v30.4s, v7.4s+ str q5, [x0, #0x10]+ str q6, [x0, #0x20]+ str q7, [x0, #0x30]+ str q4, [x0], #0x40+ subs x9, x9, #0x1+ b.ne Lmld_polyz_unpack_19_loop+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(polyz_unpack_19_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && (!MLD_CONFIG_NO_SIGN_API || \+ !MLD_CONFIG_NO_VERIFY_API) && !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,222 @@+/*+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: rej_uniform_aarch64_asm+ Description: AArch64 rejection sampling of uniform coefficients mod q+ Signature: uint64_t mld_rej_uniform_aarch64_asm(int32_t r[256], const uint8_t *buf, unsigned buflen, const uint8_t table[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t r[256]+ description: Output buffer (256 x int32_t)+ x1:+ type: buffer+ size_bytes: x2+ permissions: read-only+ c_parameter: const uint8_t *buf+ description: Input buffer+ x2:+ type: scalar+ c_parameter: unsigned buflen+ description: Length of input buffer (must be a multiple of 24)+ test_with: 840 # MLD_POLY_UNIFORM_NBLOCKS * SHAKE128_RATE = 5 * 168+ x3:+ type: buffer+ size_bytes: 256+ permissions: read-only+ c_parameter: const uint8_t table[256]+ description: Lookup table (256 x uint8_t)+*/++ #include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_rej_uniform_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(rej_uniform_aarch64_asm)+MLD_ASM_FN_SYMBOL(rej_uniform_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x440+ .cfi_adjust_cfa_offset 0x440+ mov x7, #0x1 // =1+ movk x7, #0x2, lsl #32+ mov v31.d[0], x7+ mov x7, #0x4 // =4+ movk x7, #0x8, lsl #32+ mov v31.d[1], x7+ mov w7, #0xe001 // =57345+ movk w7, #0x7f, lsl #16+ dup v30.4s, w7+ mov x8, sp+ mov x7, x8+ mov x11, #0x0 // =0+ eor v16.16b, v16.16b, v16.16b++Lmld_rej_uniform_initial_zero:+ str q16, [x7], #0x40+ stur q16, [x7, #-0x30]+ stur q16, [x7, #-0x20]+ stur q16, [x7, #-0x10]+ add x11, x11, #0x10+ cmp x11, #0x100+ b.lt Lmld_rej_uniform_initial_zero+ mov x7, x8+ mov x9, #0x0 // =0+ mov x4, #0x100 // =256+ cmp x2, #0x30+ b.lo Lmld_rej_uniform_loop48_end++Lmld_rej_uniform_loop48:+ cmp x9, x4+ b.hs Lmld_rej_uniform_memory_copy+ sub x2, x2, #0x30+ ld3 { v0.16b, v1.16b, v2.16b }, [x1], #48+ movi v4.16b, #0x80+ bic v2.16b, v2.16b, v4.16b+ zip1 v4.16b, v0.16b, v1.16b+ zip2 v5.16b, v0.16b, v1.16b+ ushll v6.8h, v2.8b, #0x0+ ushll2 v7.8h, v2.16b, #0x0+ zip1 v16.8h, v4.8h, v6.8h+ zip2 v17.8h, v4.8h, v6.8h+ zip1 v18.8h, v5.8h, v7.8h+ zip2 v19.8h, v5.8h, v7.8h+ cmhi v4.4s, v30.4s, v16.4s+ cmhi v5.4s, v30.4s, v17.4s+ cmhi v6.4s, v30.4s, v18.4s+ cmhi v7.4s, v30.4s, v19.4s+ and v4.16b, v4.16b, v31.16b+ and v5.16b, v5.16b, v31.16b+ and v6.16b, v6.16b, v31.16b+ and v7.16b, v7.16b, v31.16b+ uaddlv d20, v4.4s+ uaddlv d21, v5.4s+ uaddlv d22, v6.4s+ uaddlv d23, v7.4s+ fmov x12, d20+ fmov x13, d21+ fmov x14, d22+ fmov x15, d23+ ldr q24, [x3, x12, lsl #4]+ ldr q25, [x3, x13, lsl #4]+ ldr q26, [x3, x14, lsl #4]+ ldr q27, [x3, x15, lsl #4]+ cnt v4.16b, v4.16b+ cnt v5.16b, v5.16b+ cnt v6.16b, v6.16b+ cnt v7.16b, v7.16b+ uaddlv d20, v4.4s+ uaddlv d21, v5.4s+ uaddlv d22, v6.4s+ uaddlv d23, v7.4s+ fmov x12, d20+ fmov x13, d21+ fmov x14, d22+ fmov x15, d23+ tbl v16.16b, { v16.16b }, v24.16b+ tbl v17.16b, { v17.16b }, v25.16b+ tbl v18.16b, { v18.16b }, v26.16b+ tbl v19.16b, { v19.16b }, v27.16b+ st1 { v16.4s }, [x7]+ add x7, x7, x12, lsl #2+ st1 { v17.4s }, [x7]+ add x7, x7, x13, lsl #2+ st1 { v18.4s }, [x7]+ add x7, x7, x14, lsl #2+ st1 { v19.4s }, [x7]+ add x7, x7, x15, lsl #2+ add x12, x12, x13+ add x14, x14, x15+ add x9, x9, x12+ add x9, x9, x14+ cmp x2, #0x30+ b.hs Lmld_rej_uniform_loop48++Lmld_rej_uniform_loop48_end:+ cmp x9, x4+ b.hs Lmld_rej_uniform_memory_copy+ cmp x2, #0x18+ b.lo Lmld_rej_uniform_memory_copy+ sub x2, x2, #0x18+ ld3 { v0.8b, v1.8b, v2.8b }, [x1], #24+ movi v4.16b, #0x80+ bic v2.16b, v2.16b, v4.16b+ zip1 v4.16b, v0.16b, v1.16b+ ushll v6.8h, v2.8b, #0x0+ zip1 v16.8h, v4.8h, v6.8h+ zip2 v17.8h, v4.8h, v6.8h+ cmhi v4.4s, v30.4s, v16.4s+ cmhi v5.4s, v30.4s, v17.4s+ and v4.16b, v4.16b, v31.16b+ and v5.16b, v5.16b, v31.16b+ uaddlv d20, v4.4s+ uaddlv d21, v5.4s+ fmov x12, d20+ fmov x13, d21+ ldr q24, [x3, x12, lsl #4]+ ldr q25, [x3, x13, lsl #4]+ cnt v4.16b, v4.16b+ cnt v5.16b, v5.16b+ uaddlv d20, v4.4s+ uaddlv d21, v5.4s+ fmov x12, d20+ fmov x13, d21+ tbl v16.16b, { v16.16b }, v24.16b+ tbl v17.16b, { v17.16b }, v25.16b+ st1 { v16.4s }, [x7]+ add x7, x7, x12, lsl #2+ st1 { v17.4s }, [x7]+ add x7, x7, x13, lsl #2+ add x9, x9, x12+ add x9, x9, x13++Lmld_rej_uniform_memory_copy:+ cmp x9, x4+ csel x9, x9, x4, lo+ mov x11, #0x0 // =0+ mov x7, x8++Lmld_rej_uniform_final_copy:+ ldr q16, [x7], #0x40+ ldur q17, [x7, #-0x30]+ ldur q18, [x7, #-0x20]+ ldur q19, [x7, #-0x10]+ str q16, [x0], #0x40+ stur q17, [x0, #-0x30]+ stur q18, [x0, #-0x20]+ stur q19, [x0, #-0x10]+ add x11, x11, #0x10+ cmp x11, #0x100+ b.lt Lmld_rej_uniform_final_copy+ mov x0, x9+ b Lmld_rej_uniform_return++Lmld_rej_uniform_return:+ add sp, sp, #0x440+ .cfi_adjust_cfa_offset -0x440+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(rej_uniform_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,170 @@+/*+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: rej_uniform_eta2_aarch64_asm+ Description: AArch64 rejection sampling of eta=2 secret coefficients+ Signature: uint64_t mld_rej_uniform_eta2_aarch64_asm(int32_t r[256], const uint8_t *buf, unsigned buflen, const uint8_t table[4096])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t r[256]+ description: Output buffer (256 x int32_t)+ x1:+ type: buffer+ size_bytes: x2+ permissions: read-only+ c_parameter: const uint8_t *buf+ description: Input buffer+ x2:+ type: scalar+ c_parameter: unsigned buflen+ description: Length of input buffer (must be a multiple of 8)+ test_with: 136 # MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN+ x3:+ type: buffer+ size_bytes: 4096+ permissions: read-only+ c_parameter: const uint8_t table[4096]+ description: Lookup table (4096 x uint8_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ !defined(MLD_CONFIG_NO_KEYPAIR_API) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 2)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_rej_uniform_eta2_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(rej_uniform_eta2_aarch64_asm)+MLD_ASM_FN_SYMBOL(rej_uniform_eta2_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x240+ .cfi_adjust_cfa_offset 0x240+ mov x7, #0x1 // =1+ movk x7, #0x2, lsl #16+ movk x7, #0x4, lsl #32+ movk x7, #0x8, lsl #48+ mov v31.d[0], x7+ mov x7, #0x10 // =16+ movk x7, #0x20, lsl #16+ movk x7, #0x40, lsl #32+ movk x7, #0x80, lsl #48+ mov v31.d[1], x7+ movi v30.8h, #0xf+ mov x8, sp+ mov x7, x8+ mov x11, #0x0 // =0+ eor v16.16b, v16.16b, v16.16b++Lmld_rej_uniform_eta2_initial_zero:+ str q16, [x7], #0x40+ stur q16, [x7, #-0x30]+ stur q16, [x7, #-0x20]+ stur q16, [x7, #-0x10]+ add x11, x11, #0x20+ cmp x11, #0x100+ b.lt Lmld_rej_uniform_eta2_initial_zero+ mov x7, x8+ mov x9, #0x0 // =0+ mov x4, #0x100 // =256++Lmld_rej_uniform_eta2_loop8:+ cmp x9, x4+ b.hs Lmld_rej_uniform_eta2_memory_copy+ sub x2, x2, #0x8+ ld1 { v0.8b }, [x1], #8+ movi v26.8b, #0xf+ and v27.8b, v0.8b, v26.8b+ ushr v28.8b, v0.8b, #0x4+ zip1 v26.8b, v27.8b, v28.8b+ zip2 v29.8b, v27.8b, v28.8b+ ushll v16.8h, v26.8b, #0x0+ ushll v17.8h, v29.8b, #0x0+ cmhi v4.8h, v30.8h, v16.8h+ cmhi v5.8h, v30.8h, v17.8h+ and v4.16b, v4.16b, v31.16b+ and v5.16b, v5.16b, v31.16b+ uaddlv s20, v4.8h+ uaddlv s21, v5.8h+ fmov w12, s20+ fmov w13, s21+ ldr q24, [x3, x12, lsl #4]+ ldr q25, [x3, x13, lsl #4]+ cnt v4.16b, v4.16b+ cnt v5.16b, v5.16b+ uaddlv s20, v4.8h+ uaddlv s21, v5.8h+ fmov w12, s20+ fmov w13, s21+ tbl v16.16b, { v16.16b }, v24.16b+ tbl v17.16b, { v17.16b }, v25.16b+ st1 { v16.8h }, [x7]+ add x7, x7, x12, lsl #1+ st1 { v17.8h }, [x7]+ add x7, x7, x13, lsl #1+ add x12, x12, x13+ add x9, x9, x12+ cmp x2, #0x8+ b.hs Lmld_rej_uniform_eta2_loop8++Lmld_rej_uniform_eta2_memory_copy:+ cmp x9, x4+ csel x9, x9, x4, lo+ mov w7, #0x199a // =6554+ dup v26.8h, w7+ movi v27.8h, #0x5+ movi v7.8h, #0x2+ mov x11, #0x0 // =0+ mov x7, x8++Lmld_rej_uniform_eta2_final_copy:+ ldr q16, [x7], #0x20+ ldur q18, [x7, #-0x10]+ sqdmulh v28.8h, v16.8h, v26.8h+ mls v16.8h, v28.8h, v27.8h+ sqdmulh v28.8h, v18.8h, v26.8h+ mls v18.8h, v28.8h, v27.8h+ sub v16.8h, v7.8h, v16.8h+ sub v18.8h, v7.8h, v18.8h+ sshll2 v17.4s, v16.8h, #0x0+ sshll v16.4s, v16.4h, #0x0+ sshll2 v19.4s, v18.8h, #0x0+ sshll v18.4s, v18.4h, #0x0+ str q16, [x0], #0x40+ stur q17, [x0, #-0x30]+ stur q18, [x0, #-0x20]+ stur q19, [x0, #-0x10]+ add x11, x11, #0x10+ cmp x11, #0x100+ b.lt Lmld_rej_uniform_eta2_final_copy+ mov x0, x9+ add sp, sp, #0x240+ .cfi_adjust_cfa_offset -0x240+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(rej_uniform_eta2_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_NO_KEYPAIR_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_ETA == 2) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,163 @@+/*+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: rej_uniform_eta4_aarch64_asm+ Description: AArch64 rejection sampling of eta=4 secret coefficients+ Signature: uint64_t mld_rej_uniform_eta4_aarch64_asm(int32_t r[256], const uint8_t *buf, unsigned buflen, const uint8_t table[4096])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t r[256]+ description: Output buffer (256 x int32_t)+ x1:+ type: buffer+ size_bytes: x2+ permissions: read-only+ c_parameter: const uint8_t *buf+ description: Input buffer+ x2:+ type: scalar+ c_parameter: unsigned buflen+ description: Length of input buffer (must be a multiple of 8)+ test_with: 272 # MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN+ x3:+ type: buffer+ size_bytes: 4096+ permissions: read-only+ c_parameter: const uint8_t table[4096]+ description: Lookup table (4096 x uint8_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ !defined(MLD_CONFIG_NO_KEYPAIR_API) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 4)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/aarch64_opt/src/mldsa_rej_uniform_eta4_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(rej_uniform_eta4_aarch64_asm)+MLD_ASM_FN_SYMBOL(rej_uniform_eta4_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x240+ .cfi_adjust_cfa_offset 0x240+ mov x7, #0x1 // =1+ movk x7, #0x2, lsl #16+ movk x7, #0x4, lsl #32+ movk x7, #0x8, lsl #48+ mov v31.d[0], x7+ mov x7, #0x10 // =16+ movk x7, #0x20, lsl #16+ movk x7, #0x40, lsl #32+ movk x7, #0x80, lsl #48+ mov v31.d[1], x7+ movi v30.8h, #0x9+ movi v7.8h, #0x4+ mov x8, sp+ mov x7, x8+ mov x11, #0x0 // =0+ eor v16.16b, v16.16b, v16.16b++Lmld_rej_uniform_eta4_initial_zero:+ str q16, [x7], #0x40+ stur q16, [x7, #-0x30]+ stur q16, [x7, #-0x20]+ stur q16, [x7, #-0x10]+ add x11, x11, #0x20+ cmp x11, #0x100+ b.lt Lmld_rej_uniform_eta4_initial_zero+ mov x7, x8+ mov x9, #0x0 // =0+ mov x4, #0x100 // =256++Lmld_rej_uniform_eta4_loop8:+ cmp x9, x4+ b.hs Lmld_rej_uniform_eta4_memory_copy+ sub x2, x2, #0x8+ ld1 { v0.8b }, [x1], #8+ movi v26.8b, #0xf+ and v27.8b, v0.8b, v26.8b+ ushr v28.8b, v0.8b, #0x4+ zip1 v26.8b, v27.8b, v28.8b+ zip2 v29.8b, v27.8b, v28.8b+ ushll v16.8h, v26.8b, #0x0+ ushll v17.8h, v29.8b, #0x0+ cmhi v4.8h, v30.8h, v16.8h+ cmhi v5.8h, v30.8h, v17.8h+ and v4.16b, v4.16b, v31.16b+ and v5.16b, v5.16b, v31.16b+ uaddlv s20, v4.8h+ uaddlv s21, v5.8h+ fmov w12, s20+ fmov w13, s21+ ldr q24, [x3, x12, lsl #4]+ ldr q25, [x3, x13, lsl #4]+ cnt v4.16b, v4.16b+ cnt v5.16b, v5.16b+ uaddlv s20, v4.8h+ uaddlv s21, v5.8h+ fmov w12, s20+ fmov w13, s21+ tbl v16.16b, { v16.16b }, v24.16b+ tbl v17.16b, { v17.16b }, v25.16b+ st1 { v16.8h }, [x7]+ add x7, x7, x12, lsl #1+ st1 { v17.8h }, [x7]+ add x7, x7, x13, lsl #1+ add x12, x12, x13+ add x9, x9, x12+ cmp x2, #0x8+ b.hs Lmld_rej_uniform_eta4_loop8++Lmld_rej_uniform_eta4_memory_copy:+ cmp x9, x4+ csel x9, x9, x4, lo+ mov x11, #0x0 // =0+ mov x7, x8++Lmld_rej_uniform_eta4_final_copy:+ ldr q16, [x7], #0x20+ ldur q18, [x7, #-0x10]+ sub v16.8h, v7.8h, v16.8h+ sub v18.8h, v7.8h, v18.8h+ sshll2 v17.4s, v16.8h, #0x0+ sshll v16.4s, v16.4h, #0x0+ sshll2 v19.4s, v18.8h, #0x0+ sshll v18.4s, v18.4h, #0x0+ str q16, [x0], #0x40+ stur q17, [x0, #-0x30]+ stur q18, [x0, #-0x20]+ stur q19, [x0, #-0x10]+ add x11, x11, #0x10+ cmp x11, #0x100+ b.lt Lmld_rej_uniform_eta4_final_copy+ mov x0, x9+ add sp, sp, #0x240+ .cfi_adjust_cfa_offset -0x240+ ret+ .cfi_endproc++MLD_ASM_FN_SIZE(rej_uniform_eta4_aarch64_asm)++#endif /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_NO_KEYPAIR_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_ETA == 4) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,52 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#include "arith_native_aarch64.h"++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+/* Table of indices used for tbl instructions in polyz_unpack_{17,19}.+ * See autogen for details. */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const uint8_t+ mld_polyz_unpack_17_indices[64] = {+ 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255,+ 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255,+ 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255,+ 11, 12, 13, 255, 13, 14, 15, 255, 15, 28, 29, 255, 29, 30, 31, 255,+};+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const uint8_t+ mld_polyz_unpack_19_indices[64] = {+ 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255,+ 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255,+ 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255,+ 14, 15, 24, 255, 24, 25, 26, 255, 27, 28, 29, 255, 29, 30, 31, 255,+};+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */++#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++MLD_EMPTY_CU(aarch64_polyz_unpack_table)++#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,547 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ !defined(MLD_CONFIG_NO_KEYPAIR_API) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#include "arith_native_aarch64.h"++/*+ * Lookup table used by 16-bit rejection sampling (rej_eta).+ * Adapted from ML-KEM for ML-DSA eta rejection sampling.+ * See autogen for details.+ */+MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const uint8_t+ mld_rej_uniform_eta_table[4096] = {+ 255, 255, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */,+ 0, 1, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */,+ 2, 3, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */,+ 0, 1, 2, 3, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */,+ 4, 5, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */,+ 0, 1, 4, 5, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */,+ 2, 3, 4, 5, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */,+ 0, 1, 2, 3, 4, 5, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */,+ 6, 7, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */,+ 0, 1, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */,+ 2, 3, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */,+ 0, 1, 2, 3, 6, 7, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */,+ 4, 5, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */,+ 0, 1, 4, 5, 6, 7, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */,+ 2, 3, 4, 5, 6, 7, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */,+ 8, 9, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */,+ 0, 1, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */,+ 2, 3, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */,+ 0, 1, 2, 3, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */,+ 4, 5, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */,+ 0, 1, 4, 5, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */,+ 2, 3, 4, 5, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */,+ 6, 7, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */,+ 0, 1, 6, 7, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */,+ 2, 3, 6, 7, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */,+ 4, 5, 6, 7, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */,+ 10, 11, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */,+ 0, 1, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */,+ 2, 3, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */,+ 0, 1, 2, 3, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */,+ 4, 5, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */,+ 0, 1, 4, 5, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */,+ 2, 3, 4, 5, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */,+ 6, 7, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */,+ 0, 1, 6, 7, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */,+ 2, 3, 6, 7, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */,+ 4, 5, 6, 7, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */,+ 8, 9, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */,+ 0, 1, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */,+ 2, 3, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */,+ 4, 5, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */,+ 6, 7, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */,+ 12, 13, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */,+ 0, 1, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */,+ 2, 3, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */,+ 0, 1, 2, 3, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */,+ 4, 5, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */,+ 0, 1, 4, 5, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */,+ 2, 3, 4, 5, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */,+ 0, 1, 2, 3, 4, 5, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */,+ 6, 7, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */,+ 0, 1, 6, 7, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */,+ 2, 3, 6, 7, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */,+ 0, 1, 2, 3, 6, 7, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */,+ 4, 5, 6, 7, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */,+ 0, 1, 4, 5, 6, 7, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */,+ 2, 3, 4, 5, 6, 7, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */,+ 8, 9, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */,+ 0, 1, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */,+ 2, 3, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */,+ 0, 1, 2, 3, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */,+ 4, 5, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */,+ 0, 1, 4, 5, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */,+ 2, 3, 4, 5, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */,+ 6, 7, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */,+ 0, 1, 6, 7, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */,+ 2, 3, 6, 7, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */,+ 4, 5, 6, 7, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */,+ 10, 11, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */,+ 0, 1, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */,+ 2, 3, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */,+ 0, 1, 2, 3, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */,+ 4, 5, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */,+ 0, 1, 4, 5, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */,+ 2, 3, 4, 5, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */,+ 6, 7, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */,+ 0, 1, 6, 7, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */,+ 2, 3, 6, 7, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */,+ 4, 5, 6, 7, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */,+ 8, 9, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */,+ 0, 1, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */,+ 2, 3, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */,+ 4, 5, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */,+ 6, 7, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */,+ 14, 15, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */,+ 0, 1, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */,+ 2, 3, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */,+ 0, 1, 2, 3, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */,+ 4, 5, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */,+ 0, 1, 4, 5, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */,+ 2, 3, 4, 5, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */,+ 0, 1, 2, 3, 4, 5, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */,+ 6, 7, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */,+ 0, 1, 6, 7, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */,+ 2, 3, 6, 7, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */,+ 0, 1, 2, 3, 6, 7, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */,+ 4, 5, 6, 7, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */,+ 0, 1, 4, 5, 6, 7, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */,+ 2, 3, 4, 5, 6, 7, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */,+ 8, 9, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */,+ 0, 1, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */,+ 2, 3, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */,+ 0, 1, 2, 3, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */,+ 4, 5, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */,+ 0, 1, 4, 5, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */,+ 2, 3, 4, 5, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */,+ 6, 7, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */,+ 0, 1, 6, 7, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */,+ 2, 3, 6, 7, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */,+ 4, 5, 6, 7, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */,+ 10, 11, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */,+ 0, 1, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */,+ 2, 3, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */,+ 0, 1, 2, 3, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */,+ 4, 5, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */,+ 0, 1, 4, 5, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */,+ 2, 3, 4, 5, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */,+ 6, 7, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */,+ 0, 1, 6, 7, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */,+ 2, 3, 6, 7, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */,+ 4, 5, 6, 7, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */,+ 8, 9, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */,+ 0, 1, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */,+ 2, 3, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */,+ 4, 5, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */,+ 6, 7, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */,+ 12, 13, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */,+ 0, 1, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */,+ 2, 3, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */,+ 0, 1, 2, 3, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */,+ 4, 5, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */,+ 0, 1, 4, 5, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */,+ 2, 3, 4, 5, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */,+ 0, 1, 2, 3, 4, 5, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */,+ 6, 7, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */,+ 0, 1, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */,+ 2, 3, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */,+ 0, 1, 2, 3, 6, 7, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */,+ 4, 5, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */,+ 0, 1, 4, 5, 6, 7, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */,+ 2, 3, 4, 5, 6, 7, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */,+ 8, 9, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */,+ 0, 1, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */,+ 2, 3, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */,+ 0, 1, 2, 3, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */,+ 4, 5, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */,+ 0, 1, 4, 5, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */,+ 2, 3, 4, 5, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */,+ 6, 7, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */,+ 0, 1, 6, 7, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */,+ 2, 3, 6, 7, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */,+ 4, 5, 6, 7, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */,+ 10, 11, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */,+ 0, 1, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */,+ 2, 3, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */,+ 0, 1, 2, 3, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */,+ 4, 5, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */,+ 0, 1, 4, 5, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */,+ 2, 3, 4, 5, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */,+ 6, 7, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */,+ 0, 1, 6, 7, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */,+ 2, 3, 6, 7, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */,+ 4, 5, 6, 7, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */,+ 8, 9, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */,+ 0, 1, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */,+ 2, 3, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */,+ 4, 5, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */,+ 6, 7, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */,+};++#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_NO_KEYPAIR_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED */++MLD_EMPTY_CU(aarch64_rej_uniform_eta_table)++#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_NO_KEYPAIR_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,63 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_AARCH64) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#include "arith_native_aarch64.h"++/*+ * Lookup table used by rejection sampling of the public matrix.+ * See autogen for details.+ */+MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const uint8_t+ mld_rej_uniform_table[256] = {+ 255, 255, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */,+ 0, 1, 2, 3, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */,+ 4, 5, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */,+ 8, 9, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */,+ 12, 13, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */,+ 0, 1, 2, 3, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */,+ 4, 5, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */,+ 8, 9, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */,+};++#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */++MLD_EMPTY_CU(aarch64_rej_uniform_table)++#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,617 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_NATIVE_API_H+#define MLD_NATIVE_API_H+/*+ * Native arithmetic interface+ *+ * This header is primarily for documentation purposes.+ * It should not be included by backend implementations.+ *+ * To ensure consistency with backends, the header will be+ * included automatically after inclusion of the active+ * backend, to ensure consistency of function signatures,+ * and run sanity checks.+ */++#include "../cbmc.h"+#include "../common.h"++/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */+#define MLD_NATIVE_FUNC_SUCCESS (0)+/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that+ * the target/parameters are unsupported; typically, this would be because of+ * dependencies on CPU features not detected on the host CPU. In this case,+ * the frontend falls back to the default C implementation.+ *+ * IMPORTANT: Backend implementations must ensure that the decision of whether+ * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on+ * the input data itself. Fallback decisions may only depend on system+ * capabilities (e.g., CPU features) and, where present, length information.+ * This requirement applies to all backend functions to maintain constant-time+ * properties.+ */+#define MLD_NATIVE_FUNC_FALLBACK (-1)++/* Absolute exclusive upper bound for the output of fqmul.+ *+ * NOTE: This is the same bound as in poly.h and has to be kept+ * in sync. */+#define MLD_FQMUL_BOUND ((5 * MLDSA_Q + 3) / 4)++/* Bound on absolute value of coefficients after NTT.+ *+ * NOTE: This is the same bound as in poly.h and has to be kept+ * in sync. */+#define MLD_NTT_BOUND (9 * MLD_FQMUL_BOUND)++/* Absolute exclusive upper bound for the output of the inverse NTT+ *+ * NOTE: This is the same bound as in poly.h and has to be kept+ * in sync. */+#define MLD_INTT_BOUND MLDSA_Q++/* Absolute bound for range of mld_reduce32()+ *+ * NOTE: This is the same bound as in reduce.h and has to be kept+ * in sync. */+/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */+#define MLD_REDUCE32_RANGE_MAX 6283009+/*+ * This is the C<->native interface allowing for the drop-in of+ * native code for performance-critical arithmetic components of ML-DSA.+ *+ * A _backend_ is a specific implementation of (part of) this interface.+ *+ * To add a function to a backend, define MLD_USE_NATIVE_XXX and+ * implement `static inline xxx(...)` in the profile header.+ */++/*+ * Those functions are meant to be trivial wrappers around the chosen native+ * implementation. The are static inline to avoid unnecessary calls.+ * The macro before each declaration controls whether a native+ * implementation is present.+ */++#if defined(MLD_USE_NATIVE_NTT)+/**+ * Computes negacyclic number-theoretic transform (NTT) of a polynomial+ * in place.+ *+ * The input polynomial is assumed to be in normal order. The output+ * polynomial is in bitreversed order.+ *+ * @param[in,out] p Pointer to in/output polynomial.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N])+__contract__(+ requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N))+);+#endif /* MLD_USE_NATIVE_NTT */+++#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER)+/*+ * This must only be set if NTT and INTT have native implementations+ * that are adapted to the custom order.+ */+#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT)+#error \+ "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \+set if there are native implementations for NTT and INTT."+#endif++/**+ * When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, convert a polynomial in+ * NTT domain from bitreversed order to the custom order output by the native+ * NTT.+ *+ * This must only be defined if there is native code for both the NTT and+ * INTT.+ *+ * @param[in,out] p Pointer to in/output polynomial.+ */+static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N])+__contract__(+ /* We don't specify that this should be a permutation, but only+ * that it does not change the bound established at the end of+ * mld_polyvec_matrix_expand.+ */+ requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N))+ ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)));+#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */+++#if defined(MLD_USE_NATIVE_INTT)+/**+ * Computes inverse of negacyclic number-theoretic transform (NTT) of a+ * polynomial in place.+ *+ * The input polynomial is in bitreversed order. The output polynomial is+ * assumed to be in normal order.+ *+ * @param[in,out] p Pointer to in/output polynomial.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N])+__contract__(+ requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N))+);+#endif /* MLD_USE_NATIVE_INTT */++#if defined(MLD_USE_NATIVE_REJ_UNIFORM)+/**+ * Run rejection sampling on uniform random bytes to generate uniform random+ * integers in [0, MLDSA_Q-1].+ *+ * @param[out] r Pointer to output buffer.+ * @param len Requested number of 32-bit integers (uniform mod+ * MLDSA_Q).+ * @param[in] buf Pointer to input buffer (assumed to be uniform random+ * bytes).+ * @param buflen Length of input buffer in bytes.+ *+ * @return - MLD_NATIVE_FUNC_FALLBACK if the native implementation does not+ * support the input lengths.+ * - Otherwise, the non-negative number of sampled 32-bit integers+ * (at most len).+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+__contract__(+ requires(len <= MLDSA_N)+ requires(buflen <= ( 5 * 168) && buflen % 3 == 0)+ requires(memory_no_alias(r, sizeof(int32_t) * len))+ requires(memory_no_alias(buf, buflen))+ assigns(memory_slice(r, sizeof(int32_t) * len))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len))+ ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q))+);+#endif /* MLD_USE_NATIVE_REJ_UNIFORM */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 2+/**+ * Run rejection sampling on uniform random bytes to generate uniform random+ * integers in [-2, +2].+ *+ * @param[out] r Pointer to output buffer.+ * @param len Requested number of 32-bit integers (uniform in+ * [-2, +2]).+ * @param[in] buf Pointer to input buffer (assumed to be uniform random+ * bytes).+ * @param buflen Length of input buffer in bytes.+ *+ * @return - MLD_NATIVE_FUNC_FALLBACK if the native implementation does not+ * support the input lengths.+ * - Otherwise, the non-negative number of sampled 32-bit integers+ * (at most len).+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+__contract__(+ requires(len <= MLDSA_N)+ requires(buflen <= (2 * 136))+ requires(memory_no_alias(r, sizeof(int32_t) * len))+ requires(memory_no_alias(buf, buflen))+ assigns(memory_slice(r, sizeof(int32_t) * len))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len))+ /* check-magic: 3 == 2 + 1 (decl gated on MLDSA_ETA == 2) */+ ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, 3)))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_ETA == 2 */+#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */++#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 4+/**+ * Run rejection sampling on uniform random bytes to generate uniform random+ * integers in [-4, +4].+ *+ * @param[out] r Pointer to output buffer.+ * @param len Requested number of 32-bit integers (uniform in+ * [-4, +4]).+ * @param[in] buf Pointer to input buffer (assumed to be uniform random+ * bytes).+ * @param buflen Length of input buffer in bytes.+ *+ * @return - MLD_NATIVE_FUNC_FALLBACK if the native implementation does not+ * support the input lengths.+ * - Otherwise, the non-negative number of sampled 32-bit integers+ * (at most len).+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+__contract__(+ requires(len <= MLDSA_N)+ requires(buflen <= (2 * 136))+ requires(memory_no_alias(r, sizeof(int32_t) * len))+ requires(memory_no_alias(buf, buflen))+ assigns(memory_slice(r, sizeof(int32_t) * len))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len))+ /* check-magic: 5 == 4 + 1 (decl gated on MLDSA_ETA == 4) */+ ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, 5)))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_ETA == 4 */+#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+/**+ * Native implementation of poly_decompose for GAMMA2 = (MLDSA_Q-1)/32.+ *+ * For all coefficients c of the input polynomial, compute high and low bits+ * c0, c1 such c mod MLDSA_Q = c1*(2*GAMMA2) + c0 with+ * -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except c1 = (MLDSA_Q-1)/(2*GAMMA2) where+ * we set c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0.+ * Assumes coefficients to be standard representatives.+ *+ * @param[out] a1 Output polynomial with coefficients c1.+ * @param[in,out] a0 Input/output polynomial. Output has coefficients c0.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0)+__contract__(+ requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N))+ assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */+#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */++#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+/**+ * Native implementation of poly_decompose for GAMMA2 = (MLDSA_Q-1)/88.+ *+ * For all coefficients c of the input polynomial, compute high and low bits+ * c0, c1 such c mod MLDSA_Q = c1*(2*GAMMA2) + c0 with+ * -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except c1 = (MLDSA_Q-1)/(2*GAMMA2) where+ * we set c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0.+ * Assumes coefficients to be standard representatives.+ *+ * @param[out] a1 Output polynomial with coefficients c1.+ * @param[in,out] a0 Input/output polynomial. Output has coefficients c0.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0)+__contract__(+ requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N))+ assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */+#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if defined(MLD_USE_NATIVE_POLY_CADDQ)+/**+ * For all coefficients of in/out polynomial add Q if coefficient is negative.+ *+ * @param[in,out] a Pointer to input/output polynomial.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N])+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N))+);+#endif /* MLD_USE_NATIVE_POLY_CADDQ */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+/**+ * Native implementation of poly_use_hint for GAMMA2 = (MLDSA_Q-1)/32.+ *+ * Use hint h to correct the high bits of a in-place.+ *+ * @param[in,out] a Input/output polynomial.+ * @param[in] h Hint polynomial.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *a, const int32_t *h)+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))+ requires(array_bound(h, 0, MLDSA_N, 0, 2))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */+#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */++#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+/**+ * Native implementation of poly_use_hint for GAMMA2 = (MLDSA_Q-1)/88.+ *+ * Use hint h to correct the high bits of a in-place.+ *+ * @param[in,out] a Input/output polynomial.+ * @param[in] h Hint polynomial.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *a, const int32_t *h)+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))+ requires(array_bound(h, 0, MLDSA_N, 0, 2))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */+#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if defined(MLD_USE_NATIVE_POLY_CHKNORM)+/**+ * Check infinity norm of polynomial against given bound. Assumes input+ * coefficients were reduced by mld_reduce32().+ *+ * @param[in] a Pointer to polynomial.+ * @param B Norm bound, which must be in the range+ * 0 .. MLDSA_Q - MLD_REDUCE32_RANGE_MAX inclusive.+ *+ * @return - MLD_NATIVE_FUNC_FALLBACK if the target CPU cannot support a+ * native implementation of this function.+ * - MLD_NATIVE_FUNC_SUCCESS if the infinity norm is strictly smaller+ * than B.+ * - 1 otherwise.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B)+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX)+ requires(array_bound(a, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == 0 ||+ return_value == 1)+ ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==>+ ((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)))+);+#endif /* MLD_USE_NATIVE_POLY_CHKNORM */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+/**+ * Native implementation of polyz_unpack for GAMMA1 = 2^17.+ *+ * Unpack polynomial z with coefficients in+ * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1].+ *+ * @param[out] r Pointer to output polynomial.+ * @param[in] a Byte array with bit-packed polynomial.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a)+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */+#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */++#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+/**+ * Native implementation of polyz_unpack for GAMMA1 = 2^19.+ *+ * Unpack polynomial z with coefficients in+ * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1].+ *+ * @param[out] r Pointer to output polynomial.+ * @param[in] a Byte array with bit-packed polynomial.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a)+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */+#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY)+/**+ * Pointwise multiplication of polynomials in NTT domain with Montgomery+ * reduction. Destructive in the first argument.+ *+ * Computes a[i] = a[i] * b[i] * R^(-1) mod MLDSA_Q for all i, where R = 2^32.+ *+ * @param[in,out] a First input/output polynomial.+ * @param[in] b Second input polynomial.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_pointwise_montgomery_native(+ int32_t a[MLDSA_N], const int32_t b[MLDSA_N])+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND))+ requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND))+);+#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 4+/**+ * Native implementation of polyvecl_pointwise_acc_montgomery for MLDSA_L = 4.+ *+ * Pointwise multiply vectors of polynomials of length MLDSA_L, multiply+ * resulting vector by 2^{-32} and add (accumulate) polynomials in it.+ * Input/output vectors are in NTT domain representation.+ *+ * @param[out] w Output polynomial.+ * @param[in] u First input vector.+ * @param[in] v Second input vector.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native(+ int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N],+ const int32_t v[4][MLDSA_N])+__contract__(+ requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N))+ requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N))+ requires(forall(l0, 0, 4,+ array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q)))+ requires(forall(l1, 0, 4,+ array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND)))+ assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 4 */+#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */++#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 5+/**+ * Native implementation of polyvecl_pointwise_acc_montgomery for MLDSA_L = 5.+ *+ * Pointwise multiply vectors of polynomials of length MLDSA_L, multiply+ * resulting vector by 2^{-32} and add (accumulate) polynomials in it.+ * Input/output vectors are in NTT domain representation.+ *+ * @param[out] w Output polynomial.+ * @param[in] u First input vector.+ * @param[in] v Second input vector.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native(+ int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N],+ const int32_t v[5][MLDSA_N])+__contract__(+ requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N))+ requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N))+ requires(forall(l0, 0, 5,+ array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q)))+ requires(forall(l1, 0, 5,+ array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND)))+ assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 5 */+#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */++#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 7+/**+ * Native implementation of polyvecl_pointwise_acc_montgomery for MLDSA_L = 7.+ *+ * Pointwise multiply vectors of polynomials of length MLDSA_L, multiply+ * resulting vector by 2^{-32} and add (accumulate) polynomials in it.+ * Input/output vectors are in NTT domain representation.+ *+ * @param[out] w Output polynomial.+ * @param[in] u First input vector.+ * @param[in] v Second input vector.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native(+ int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N],+ const int32_t v[7][MLDSA_N])+__contract__(+ requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N))+ requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N))+ requires(forall(l0, 0, 7,+ array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q)))+ requires(forall(l1, 0, 7,+ array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND)))+ assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N))+ ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q))+ ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 7 */+#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */++#endif /* !MLD_NATIVE_API_H */
@@ -0,0 +1,24 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_NATIVE_META_H+#define MLD_NATIVE_META_H++/*+ * Default arithmetic backend+ */+#include "../sys.h"++#ifdef MLD_SYS_AARCH64_NEON+#include "aarch64/meta.h"+#endif++/* The x86_64 backend requires toolchain support for the SysV ABI */+#if defined(MLD_SYS_X86_64_AVX2) && defined(MLD_SYSV_ABI_SUPPORTED)+#include "x86_64/meta.h"+#endif++#endif /* !MLD_NATIVE_META_H */
@@ -0,0 +1,323 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_NATIVE_X86_64_META_H+#define MLD_NATIVE_X86_64_META_H++/* Identifier for this backend so that source and assembly files+ * in the build can be appropriately guarded. */+#define MLD_ARITH_BACKEND_X86_64_DEFAULT++#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER+#define MLD_USE_NATIVE_NTT+#define MLD_USE_NATIVE_INTT+#define MLD_USE_NATIVE_REJ_UNIFORM+#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2+#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4+#define MLD_USE_NATIVE_POLY_DECOMPOSE_32+#define MLD_USE_NATIVE_POLY_DECOMPOSE_88+#define MLD_USE_NATIVE_POLY_CADDQ+#define MLD_USE_NATIVE_POLY_USE_HINT_32+#define MLD_USE_NATIVE_POLY_USE_HINT_88+#define MLD_USE_NATIVE_POLY_CHKNORM+#define MLD_USE_NATIVE_POLYZ_UNPACK_17+#define MLD_USE_NATIVE_POLYZ_UNPACK_19+#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY+#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4+#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5+#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7++#if !defined(__ASSEMBLER__)+#include <string.h>+#include "../../common.h"+#include "../api.h"+#include "src/arith_native_x86_64.h"++static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N])+{+ if (mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ mld_nttunpack_avx2_asm(data);+ }+}++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ mld_ntt_avx2_asm(data, mld_qdata);+ return MLD_NATIVE_FUNC_SUCCESS;+}++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_invntt_avx2_asm(data, mld_qdata);+ return MLD_NATIVE_FUNC_SUCCESS;+}++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+{+ /* AVX2 implementation assumes specific buffer lengths */+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2) || len != MLDSA_N ||+ buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN)+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */+ return (int)mld_rej_uniform_avx2_asm(r, buf, mld_rej_uniform_table);+}++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 2+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+{+ unsigned int outlen;+ /* AVX2 implementation assumes specific buffer lengths */+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2) || len != MLDSA_N ||+ buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN)+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ /* Constant time: Inputs and outputs to this function are secret.+ * It is safe to leak which coefficients are accepted/rejected.+ * The assembly implementation must not leak any other information about the+ * accepted coefficients. Constant-time testing cannot cover this, and we+ * hence have to manually verify the assembly.+ * We declassify prior the input data and mark the outputs as secret.+ */+ MLD_CT_TESTING_DECLASSIFY(buf, buflen);+ outlen = mld_rej_uniform_eta2_avx2_asm(r, buf, mld_rej_uniform_table);+ MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen);+ /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */+ return (int)outlen;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_ETA == 2 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 4+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+{+ unsigned int outlen;+ /* AVX2 implementation assumes specific buffer lengths */+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2) || len != MLDSA_N ||+ buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN)+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }++ /* Constant time: Inputs and outputs to this function are secret.+ * It is safe to leak which coefficients are accepted/rejected.+ * The assembly implementation must not leak any other information about the+ * accepted coefficients. Constant-time testing cannot cover this, and we+ * hence have to manually verify the assembly.+ * We declassify prior the input data and mark the outputs as secret.+ */+ MLD_CT_TESTING_DECLASSIFY(buf, buflen);+ outlen = mld_rej_uniform_eta4_avx2_asm(r, buf, mld_rej_uniform_table);+ MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen);+ /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */+ return (int)outlen;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_ETA == 4 */+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_decompose_32_avx2_asm(a1, a0);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_decompose_88_avx2_asm(a1, a0);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */+#endif /* !MLD_CONFIG_NO_SIGN_API */++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_caddq_avx2_asm(a);+ return MLD_NATIVE_FUNC_SUCCESS;+}++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *a, const int32_t *h)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_use_hint_32_avx2_asm(a, h);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *a, const int32_t *h)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_poly_use_hint_88_avx2_asm(a, h);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */+#endif /* !MLD_CONFIG_NO_VERIFY_API */++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ return mld_poly_chknorm_avx2_asm(a, B);+}++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_polyz_unpack_17_avx2_asm(r, a);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a)+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_polyz_unpack_19_avx2_asm(r, a);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_poly_pointwise_montgomery_native(+ int32_t a[MLDSA_N], const int32_t b[MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_pointwise_avx2_asm(a, b, mld_qdata);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 4+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native(+ int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N],+ const int32_t v[4][MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_pointwise_acc_l4_avx2_asm(w, u, v, mld_qdata);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 4 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 5+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native(+ int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N],+ const int32_t v[5][MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_pointwise_acc_l5_avx2_asm(w, u, v, mld_qdata);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 5 */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 7+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native(+ int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N],+ const int32_t v[7][MLDSA_N])+{+ if (!mld_sys_check_capability(MLD_SYS_CAP_X86_64_AVX2))+ {+ return MLD_NATIVE_FUNC_FALLBACK;+ }+ mld_pointwise_acc_l7_avx2_asm(w, u, v, mld_qdata);+ return MLD_NATIVE_FUNC_SUCCESS;+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 7 */++#endif /* !__ASSEMBLER__ */++#endif /* !MLD_NATIVE_X86_64_META_H */
@@ -0,0 +1,330 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H+#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H+#include "../../../common.h"++#include "consts.h"++#define MLD_AVX2_REJ_UNIFORM_BUFLEN \+ (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */+++/*+ * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits.+ * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes.+ * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially.+ * Sampling 2 blocks initially results in slightly worse performance.+ */+#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136)++/*+ * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits.+ * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes.+ * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially.+ */+#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136)++#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table)+MLD_INTERNAL_DATA_DECLARATION const uint8_t mld_rej_uniform_table[256][8];++#define mld_ntt_avx2_asm MLD_NAMESPACE(ntt_avx2_asm)+MLD_SYSV_ABI+void mld_ntt_avx2_asm(int32_t *r, const int32_t *qdata)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_ntt_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ /* check-magic: 8380417 == MLDSA_Q */+ requires(array_abs_bound(r, 0, MLDSA_N, 8380417))+ requires(qdata == mld_qdata)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ /* check-magic: off */+ ensures(array_abs_bound(r, 0, MLDSA_N, 42035262))+ /* check-magic: on */+);++#define mld_invntt_avx2_asm MLD_NAMESPACE(invntt_avx2_asm)+MLD_SYSV_ABI+void mld_invntt_avx2_asm(int32_t *r, const int32_t *qdata)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_intt_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(r, 0, MLDSA_N, 8380417))+ requires(qdata == mld_qdata)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ /* check-magic: off */+ ensures(array_abs_bound(r, 0, MLDSA_N, 6285313))+ /* check-magic: on */+);++#define mld_nttunpack_avx2_asm MLD_NAMESPACE(nttunpack_avx2_asm)+MLD_SYSV_ABI+void mld_nttunpack_avx2_asm(int32_t *r)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_nttunpack_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(r, 0, MLDSA_N, 8380417))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ /* Output is a permutation of input: every output coefficient+ * is some input coefficient */+ ensures(forall(i, 0, MLDSA_N, exists(j, 0, MLDSA_N,+ r[i] == old(*(int32_t (*)[MLDSA_N])r)[j])))+);++#define mld_rej_uniform_avx2_asm MLD_NAMESPACE(rej_uniform_avx2_asm)+/* This contract must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_avx2_asm.ml */+MLD_MUST_CHECK_RETURN_VALUE MLD_SYSV_ABI+unsigned mld_rej_uniform_avx2_asm(+ int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN],+ const uint8_t table[256][8])+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(buf, 840))+ requires(table == mld_rej_uniform_table)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(return_value <= MLDSA_N)+ ensures(array_bound(r, 0, return_value, 0, MLDSA_Q))+);++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_rej_uniform_eta2_avx2_asm MLD_NAMESPACE(rej_uniform_eta2_avx2_asm)+/* This contract must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta2_avx2_asm.ml */+MLD_MUST_CHECK_RETURN_VALUE MLD_SYSV_ABI+unsigned mld_rej_uniform_eta2_avx2_asm(+ int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN],+ const uint8_t table[256][8])+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(buf, MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN))+ requires(table == mld_rej_uniform_table)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(return_value <= MLDSA_N)+ ensures(array_abs_bound(r, 0, return_value, 3))+);++#define mld_rej_uniform_eta4_avx2_asm MLD_NAMESPACE(rej_uniform_eta4_avx2_asm)+/* This contract must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta4_avx2_asm.ml */+MLD_MUST_CHECK_RETURN_VALUE MLD_SYSV_ABI+unsigned mld_rej_uniform_eta4_avx2_asm(+ int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN],+ const uint8_t table[256][8])+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(buf, MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN))+ requires(table == mld_rej_uniform_table)+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(return_value <= MLDSA_N)+ ensures(array_abs_bound(r, 0, return_value, 5))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_poly_decompose_32_avx2_asm MLD_NAMESPACE(poly_decompose_32_avx2_asm)+MLD_SYSV_ABI+void mld_poly_decompose_32_avx2_asm(int32_t *a1, int32_t *a0)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_poly_decompose_32_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N))+ assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N))+ /* check-magic: 16 == (MLDSA_Q - 1) / (2 * ((MLDSA_Q - 1) / 32)) */+ ensures(array_bound(a1, 0, MLDSA_N, 0, 16))+ /* check-magic: 261889 == (MLDSA_Q - 1) / 32 + 1 */+ ensures(array_abs_bound(a0, 0, MLDSA_N, 261889))+);++#define mld_poly_decompose_88_avx2_asm MLD_NAMESPACE(poly_decompose_88_avx2_asm)+MLD_SYSV_ABI+void mld_poly_decompose_88_avx2_asm(int32_t *a1, int32_t *a0)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_poly_decompose_88_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N))+ assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N))+ /* check-magic: 44 == (MLDSA_Q - 1) / (2 * ((MLDSA_Q - 1) / 88)) */+ ensures(array_bound(a1, 0, MLDSA_N, 0, 44))+ /* check-magic: 95233 == (MLDSA_Q - 1) / 88 + 1 */+ ensures(array_abs_bound(a0, 0, MLDSA_N, 95233))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#define mld_poly_caddq_avx2_asm MLD_NAMESPACE(poly_caddq_avx2_asm)+MLD_SYSV_ABI+void mld_poly_caddq_avx2_asm(int32_t *r)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_poly_caddq_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(r, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_bound(r, 0, MLDSA_N, 0, MLDSA_Q))+);++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_poly_use_hint_32_avx2_asm MLD_NAMESPACE(poly_use_hint_32_avx2_asm)+MLD_SYSV_ABI+void mld_poly_use_hint_32_avx2_asm(int32_t *a, const int32_t *h)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_poly_use_hint_32_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))+ requires(array_bound(h, 0, MLDSA_N, 0, 2))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ /* check-magic: 16 == (MLDSA_Q - 1) / (2 * ((MLDSA_Q - 1) / 32)) */+ ensures(array_bound(a, 0, MLDSA_N, 0, 16))+);++#define mld_poly_use_hint_88_avx2_asm MLD_NAMESPACE(poly_use_hint_88_avx2_asm)+MLD_SYSV_ABI+void mld_poly_use_hint_88_avx2_asm(int32_t *a, const int32_t *h)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_poly_use_hint_88_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N))+ requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))+ requires(array_bound(h, 0, MLDSA_N, 0, 2))+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ /* check-magic: 44 == (MLDSA_Q - 1) / (2 * ((MLDSA_Q - 1) / 88)) */+ ensures(array_bound(a, 0, MLDSA_N, 0, 44))+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#define mld_poly_chknorm_avx2_asm MLD_NAMESPACE(poly_chknorm_avx2_asm)+MLD_MUST_CHECK_RETURN_VALUE MLD_SYSV_ABI+int mld_poly_chknorm_avx2_asm(const int32_t *a, int32_t B)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_poly_chknorm_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ /* HOL Light precondition: abs(ival(x i)) < 2^31, i.e., a[i] != INT32_MIN */+ requires(forall(k0, 0, MLDSA_N, a[k0] > INT32_MIN))+ /* HOL Light precondition: 0 <= ival bound (asm computes B-1 internally) */+ requires(B >= 0)+ ensures(return_value == 0 || return_value == 1)+ ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B))+);++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_polyz_unpack_17_avx2_asm MLD_NAMESPACE(polyz_unpack_17_avx2_asm)+MLD_SYSV_ABI+void mld_polyz_unpack_17_avx2_asm(int32_t *r, const uint8_t *a)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_polyz_unpack_17_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, 576))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_bound(r, 0, MLDSA_N, -((1 << 17) - 1), (1 << 17) + 1))+);++#define mld_polyz_unpack_19_avx2_asm MLD_NAMESPACE(polyz_unpack_19_avx2_asm)+MLD_SYSV_ABI+void mld_polyz_unpack_19_avx2_asm(int32_t *r, const uint8_t *a)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_polyz_unpack_19_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, 640))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_bound(r, 0, MLDSA_N, -((1 << 19) - 1), (1 << 19) + 1))+);+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#define mld_pointwise_avx2_asm MLD_NAMESPACE(pointwise_avx2_asm)+MLD_SYSV_ABI+void mld_pointwise_avx2_asm(int32_t *a, const int32_t *b, const int32_t *qdata)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_pointwise_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N))+ /* Input bound MLD_NTT_BOUND = 9 * MLD_FQMUL_BOUND, the guaranteed bound of+ * any forward NTT implementation. Hardcoded here to keep this header free+ * of poly.h. */+ /* check-magic: 94279698 == 9 * ((5 * MLDSA_Q + 3) / 4) */+ requires(array_abs_bound(a, 0, MLDSA_N, 94279698))+ requires(array_abs_bound(b, 0, MLDSA_N, 94279698))+ requires(qdata == mld_qdata)+ assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(a, 0, MLDSA_N, 8380417))+);++#define mld_pointwise_acc_l4_avx2_asm MLD_NAMESPACE(pointwise_acc_l4_avx2_asm)+MLD_SYSV_ABI+void mld_pointwise_acc_l4_avx2_asm(int32_t c[MLDSA_N],+ const int32_t a[4][MLDSA_N],+ const int32_t b[4][MLDSA_N],+ const int32_t *qdata)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_pointwise_acc_l4_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, sizeof(int32_t) * 4 * MLDSA_N))+ requires(memory_no_alias(b, sizeof(int32_t) * 4 * MLDSA_N))+ requires(forall(l0, 0, 4, array_abs_bound(a[l0], 0, MLDSA_N, 8380417)))+ /* check-magic: 94279698 == 9 * ((5 * MLDSA_Q + 3) / 4) */+ requires(forall(l1, 0, 4, array_abs_bound(b[l1], 0, MLDSA_N, 94279698)))+ requires(qdata == mld_qdata)+ assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(c, 0, MLDSA_N, 8380417))+);++#define mld_pointwise_acc_l5_avx2_asm MLD_NAMESPACE(pointwise_acc_l5_avx2_asm)+MLD_SYSV_ABI+void mld_pointwise_acc_l5_avx2_asm(int32_t c[MLDSA_N],+ const int32_t a[5][MLDSA_N],+ const int32_t b[5][MLDSA_N],+ const int32_t *qdata)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_pointwise_acc_l5_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, sizeof(int32_t) * 5 * MLDSA_N))+ requires(memory_no_alias(b, sizeof(int32_t) * 5 * MLDSA_N))+ requires(forall(l0, 0, 5, array_abs_bound(a[l0], 0, MLDSA_N, 8380417)))+ /* check-magic: 94279698 == 9 * ((5 * MLDSA_Q + 3) / 4) */+ requires(forall(l1, 0, 5, array_abs_bound(b[l1], 0, MLDSA_N, 94279698)))+ requires(qdata == mld_qdata)+ assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(c, 0, MLDSA_N, 8380417))+);++#define mld_pointwise_acc_l7_avx2_asm MLD_NAMESPACE(pointwise_acc_l7_avx2_asm)+MLD_SYSV_ABI+void mld_pointwise_acc_l7_avx2_asm(int32_t c[MLDSA_N],+ const int32_t a[7][MLDSA_N],+ const int32_t b[7][MLDSA_N],+ const int32_t *qdata)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mldsa_pointwise_acc_l7_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N))+ requires(memory_no_alias(a, sizeof(int32_t) * 7 * MLDSA_N))+ requires(memory_no_alias(b, sizeof(int32_t) * 7 * MLDSA_N))+ requires(forall(l0, 0, 7, array_abs_bound(a[l0], 0, MLDSA_N, 8380417)))+ /* check-magic: 94279698 == 9 * ((5 * MLDSA_Q + 3) / 4) */+ requires(forall(l1, 0, 7, array_abs_bound(b[l1], 0, MLDSA_N, 94279698)))+ requires(qdata == mld_qdata)+ assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(c, 0, MLDSA_N, 8380417))+);++#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */
@@ -0,0 +1,157 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#include "consts.h"++/*+ * Table of zeta values used in the AVX2 forward and inverse NTT+ * See autogen for details.+ */+MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const int32_t mld_qdata[624] = {+ 8380417, 8380417, 8380417, 8380417, 8380417,+ 8380417, 8380417, 8380417, 58728449, 58728449,+ 58728449, 58728449, 58728449, 58728449, 58728449,+ 58728449, -8395782, -8395782, -8395782, -8395782,+ -8395782, -8395782, -8395782, -8395782, 41978,+ 41978, 41978, 41978, 41978, 41978,+ 41978, 41978, -151046689, 1830765815, -1929875198,+ -1927777021, 1640767044, 1477910808, 1612161320, 1640734244,+ 308362795, 308362795, 308362795, 308362795, -1815525077,+ -1815525077, -1815525077, -1815525077, -1374673747, -1374673747,+ -1374673747, -1374673747, -1091570561, -1091570561, -1091570561,+ -1091570561, -1929495947, -1929495947, -1929495947, -1929495947,+ 515185417, 515185417, 515185417, 515185417, -285697463,+ -285697463, -285697463, -285697463, 625853735, 625853735,+ 625853735, 625853735, 1727305304, 1727305304, 2082316400,+ 2082316400, -1364982364, -1364982364, 858240904, 858240904,+ 1806278032, 1806278032, 222489248, 222489248, -346752664,+ -346752664, 684667771, 684667771, 1654287830, 1654287830,+ -878576921, -878576921, -1257667337, -1257667337, -748618600,+ -748618600, 329347125, 329347125, 1837364258, 1837364258,+ -1443016191, -1443016191, -1170414139, -1170414139, -1846138265,+ -1631226336, -1404529459, 1838055109, 1594295555, -1076973524,+ -1898723372, -594436433, -202001019, -475984260, -561427818,+ 1797021249, -1061813248, 2059733581, -1661512036, -1104976547,+ -1750224323, -901666090, 418987550, 1831915353, -1925356481,+ 992097815, 879957084, 2024403852, 1484874664, -1636082790,+ -285388938, -1983539117, -1495136972, -950076368, -1714807468,+ -952438995, -1574918427, 1350681039, -2143979939, 1599739335,+ -1285853323, -993005454, -1440787840, 568627424, -783134478,+ -588790216, 289871779, -1262003603, 2135294594, -1018755525,+ -889861155, 1665705315, 1321868265, 1225434135, -1784632064,+ 666258756, 675310538, -1555941048, -1999506068, -1499481951,+ -695180180, -1375177022, 1777179795, 334803717, -178766299,+ -518252220, 1957047970, 1146323031, -654783359, -1974159335,+ 1651689966, 140455867, -1039411342, 1955560694, 1529189038,+ -2131021878, -247357819, 1518161567, -86965173, 1708872713,+ 1787797779, 1638590967, -120646188, -1669960606, -916321552,+ 1155548552, 2143745726, 1210558298, -1261461890, -318346816,+ 628664287, -1729304568, 1422575624, 1424130038, -1185330464,+ 235321234, 168022240, 1206536194, 985155484, -894060583,+ -898413, -1363460238, -605900043, 2027833504, 14253662,+ 1014493059, 863641633, 1819892093, 2124962073, -1223601433,+ -1920467227, -1637785316, -1536588520, 694382729, 235104446,+ -1045062172, 831969619, -300448763, 756955444, -260312805,+ 1554794072, 1339088280, -2040058690, -853476187, -2047270596,+ -1723816713, -1591599803, -440824168, 1119856484, 1544891539,+ 155290192, -973777462, 991903578, 912367099, -44694137,+ 1176904444, -421552614, -818371958, 1747917558, -325927722,+ 908452108, 1851023419, -1176751719, -1354528380, -72690498,+ -314284737, 985022747, 963438279, -1078959975, 604552167,+ -1021949428, 608791570, 173440395, -2126092136, -1316619236,+ -1039370342, 6087993, -110126092, 565464272, -1758099917,+ -1600929361, 879867909, -1809756372, 400711272, 1363007700,+ 30313375, -326425360, 1683520342, -517299994, 2027935492,+ -1372618620, 128353682, -1123881663, 137583815, -635454918,+ -642772911, 45766801, 671509323, -2070602178, 419615363,+ 1216882040, -270590488, -1276805128, 371462360, -1357098057,+ -384158533, 827959816, -596344473, 702390549, -279505433,+ -260424530, -71875110, -1208667171, -1499603926, 2036925262,+ -540420426, 746144248, -1420958686, 2032221021, 1904936414,+ 1257750362, 1926727420, 1931587462, 1258381762, 885133339,+ 1629985060, 1967222129, 6363718, -1287922800, 1136965286,+ 1779436847, 1116720494, 1042326957, 1405999311, 713994583,+ 940195359, -1542497137, 2061661095, -883155599, 1726753853,+ -1547952704, 394851342, 283780712, 776003547, 1123958025,+ 201262505, 1934038751, 374860238, -3975713, 25847,+ -2608894, -518909, 237124, -777960, -876248,+ 466468, 1826347, 1826347, 1826347, 1826347,+ 2353451, 2353451, 2353451, 2353451, -359251,+ -359251, -359251, -359251, -2091905, -2091905,+ -2091905, -2091905, 3119733, 3119733, 3119733,+ 3119733, -2884855, -2884855, -2884855, -2884855,+ 3111497, 3111497, 3111497, 3111497, 2680103,+ 2680103, 2680103, 2680103, 2725464, 2725464,+ 1024112, 1024112, -1079900, -1079900, 3585928,+ 3585928, -549488, -549488, -1119584, -1119584,+ 2619752, 2619752, -2108549, -2108549, -2118186,+ -2118186, -3859737, -3859737, -1399561, -1399561,+ -3277672, -3277672, 1757237, 1757237, -19422,+ -19422, 4010497, 4010497, 280005, 280005,+ 2706023, 95776, 3077325, 3530437, -1661693,+ -3592148, -2537516, 3915439, -3861115, -3043716,+ 3574422, -2867647, 3539968, -300467, 2348700,+ -539299, -1699267, -1643818, 3505694, -3821735,+ 3507263, -2140649, -1600420, 3699596, 811944,+ 531354, 954230, 3881043, 3900724, -2556880,+ 2071892, -2797779, -3930395, -3677745, -1452451,+ 2176455, -1257611, -4083598, -3190144, -3632928,+ 3412210, 2147896, -2967645, -411027, -671102,+ -22981, -381987, 1852771, -3343383, 508951,+ 44288, 904516, -3724342, 1653064, 2389356,+ 759969, 189548, 3159746, -2409325, 1315589,+ 1285669, -812732, -3019102, -3628969, -1528703,+ -3041255, 3475950, -1585221, 1939314, -1000202,+ -3157330, 126922, -983419, 2715295, -3693493,+ -2477047, -1228525, -1308169, 1349076, -1430430,+ 264944, 3097992, -1100098, 3958618, -8578,+ -3249728, -210977, -1316856, -3553272, -1851402,+ -177440, 1341330, -1584928, -1439742, -3881060,+ 3839961, 2091667, -3342478, 266997, -3520352,+ 900702, 495491, -655327, -3556995, 342297,+ 3437287, 2842341, 4055324, -3767016, -2994039,+ -1333058, -451100, -1279661, 1500165, -542412,+ -2584293, -2013608, 1957272, -3183426, 810149,+ -3038916, 2213111, -426683, -1667432, -2939036,+ 183443, -554416, 3937738, 3407706, 2244091,+ 2434439, -3759364, 1859098, -1613174, -3122442,+ -525098, 286988, -3342277, 2691481, 1247620,+ 1250494, 1869119, 1237275, 1312455, 1917081,+ 777191, -2831860, -3724270, 2432395, 3369112,+ 162844, 1652634, 3523897, -975884, 1723600,+ -1104333, -2235985, -976891, 3919660, 1400424,+ 2316500, -2446433, -1235728, -1197226, 909542,+ -43260, 2031748, -768622, -2437823, 1735879,+ -2590150, 2486353, 2635921, 1903435, -3318210,+ 3306115, -2546312, 2235880, -1671176, 594136,+ 2454455, 185531, 1616392, -3694233, 3866901,+ 1717735, -1803090, -260646, -420899, 1612842,+ -48306, -846154, 3817976, -3562462, 3513181,+ -3193378, 819034, -522500, 3207046, -3595838,+ 4108315, 203044, 1265009, 1595974, -3548272,+ -1050970, -1430225, -1962642, -1374803, 3406031,+ -1846953, -3776993, -164721, -1207385, 3014001,+ -1799107, 269760, 472078, 1910376, -3833893,+ -2286327, -3545687, -1362209, 1976782,+};++#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++MLD_EMPTY_CU(avx2_consts)++#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,27 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H+#define MLD_NATIVE_X86_64_SRC_CONSTS_H+#include "../../../common.h"+#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0+#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8+#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16+#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24+#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32+#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328++#ifndef __ASSEMBLER__+#define mld_qdata MLD_NAMESPACE(qdata)+MLD_INTERNAL_DATA_DECLARATION const int32_t mld_qdata[624];+#endif++#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */
@@ -0,0 +1,2333 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++ /*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: invntt_avx2_asm+ Description: x86_64 AVX2 inverse NTT+ Signature: void mld_invntt_avx2_asm(int32_t *r, const int32_t *qdata)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t *r+ description: Input/output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 2496+ permissions: read-only+ c_parameter: const int32_t *qdata+ description: Precomputed constants (624 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_intt_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(invntt_avx2_asm)+MLD_ASM_FN_SYMBOL(invntt_avx2_asm)++ .cfi_startproc+ vmovdqa (%rsi), %ymm0+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x20(%rdi), %ymm5+ vmovdqa 0x40(%rdi), %ymm6+ vmovdqa 0x60(%rdi), %ymm7+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm9+ vmovdqa 0xc0(%rdi), %ymm10+ vmovdqa 0xe0(%rdi), %ymm11+ vpermq $0x1b, 0x500(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x9a0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm5, %ymm12+ vpaddd %ymm5, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpermq $0x1b, 0x480(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x920(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm7, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpermq $0x1b, 0x400(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x8a0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm8, %ymm9, %ymm12+ vpaddd %ymm9, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpermq $0x1b, 0x380(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x820(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm10, %ymm11, %ymm12+ vpaddd %ymm11, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpermq $0x1b, 0x300(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x7a0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm6, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm6 # ymm6 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm6, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm6, %ymm6+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm6, %ymm6+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm6, %ymm12, %ymm6 # ymm6 = ymm12[0],ymm6[1],ymm12[2],ymm6[3],ymm12[4],ymm6[5],ymm12[6],ymm6[7]+ vpsubd %ymm5, %ymm7, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpermq $0x1b, 0x280(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x720(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm8, %ymm10, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm9, %ymm11, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpermq $0x1b, 0x200(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x6a0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm6, %ymm10, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm7, %ymm11, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovsldup %ymm5, %ymm3 # ymm3 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7]+ vpsrlq $0x20, %ymm4, %ymm4+ vpblendd $0xaa, %ymm5, %ymm4, %ymm5 # ymm5 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7]+ vmovsldup %ymm7, %ymm4 # ymm4 = ymm7[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7]+ vmovsldup %ymm9, %ymm6 # ymm6 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7]+ vpsrlq $0x20, %ymm8, %ymm8+ vpblendd $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7]+ vmovsldup %ymm11, %ymm8 # ymm8 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm8, %ymm10, %ymm8 # ymm8 = ymm10[0],ymm8[1],ymm10[2],ymm8[3],ymm10[4],ymm8[5],ymm10[6],ymm8[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vpermq $0x1b, 0x180(%rsi), %ymm1 # ymm1 = mem[3,2,1,0]+ vpermq $0x1b, 0x620(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpsubd %ymm3, %ymm5, %ymm12+ vpaddd %ymm5, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpsubd %ymm4, %ymm7, %ymm12+ vpaddd %ymm7, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpsubd %ymm6, %ymm9, %ymm12+ vpaddd %ymm6, %ymm9, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm8, %ymm11, %ymm12+ vpaddd %ymm11, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpunpcklqdq %ymm4, %ymm3, %ymm10 # ymm10 = ymm3[0],ymm4[0],ymm3[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[1],ymm4[1],ymm3[3],ymm4[3]+ vpunpcklqdq %ymm8, %ymm6, %ymm3 # ymm3 = ymm6[0],ymm8[0],ymm6[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm6, %ymm8 # ymm8 = ymm6[1],ymm8[1],ymm6[3],ymm8[3]+ vpunpcklqdq %ymm7, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm7[0],ymm5[2],ymm7[2]+ vpunpckhqdq %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[1],ymm7[1],ymm5[3],ymm7[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vpermq $0x1b, 0x100(%rsi), %ymm1 # ymm1 = mem[3,2,1,0]+ vpermq $0x1b, 0x5a0(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpsubd %ymm10, %ymm4, %ymm12+ vpaddd %ymm4, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm4 # ymm4 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm4, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm4, %ymm4+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm4, %ymm12, %ymm4 # ymm4 = ymm12[0],ymm4[1],ymm12[2],ymm4[3],ymm12[4],ymm4[5],ymm12[6],ymm4[7]+ vpsubd %ymm3, %ymm8, %ymm12+ vpaddd %ymm3, %ymm8, %ymm3+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm7, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpsubd %ymm5, %ymm11, %ymm12+ vpaddd %ymm5, %ymm11, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vperm2i128 $0x20, %ymm3, %ymm10, %ymm9 # ymm9 = ymm10[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm5, %ymm6, %ymm10 # ymm10 = ymm6[0,1],ymm5[0,1]+ vperm2i128 $0x31, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[2,3],ymm5[2,3]+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm6 # ymm6 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm4 # ymm4 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpbroadcastd 0x9c(%rsi), %ymm1+ vpbroadcastd 0x53c(%rsi), %ymm2+ vpsubd %ymm9, %ymm3, %ymm12+ vpaddd %ymm3, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm3 # ymm3 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm3, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm3, %ymm3+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm3, %ymm12, %ymm3 # ymm3 = ymm12[0],ymm3[1],ymm12[2],ymm3[3],ymm12[4],ymm3[5],ymm12[6],ymm3[7]+ vpsubd %ymm10, %ymm5, %ymm12+ vpaddd %ymm5, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpsubd %ymm6, %ymm8, %ymm12+ vpaddd %ymm6, %ymm8, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm4, %ymm11, %ymm12+ vpaddd %ymm4, %ymm11, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovdqa %ymm9, (%rdi)+ vmovdqa %ymm10, 0x20(%rdi)+ vmovdqa %ymm6, 0x40(%rdi)+ vmovdqa %ymm4, 0x60(%rdi)+ vmovdqa %ymm3, 0x80(%rdi)+ vmovdqa %ymm5, 0xa0(%rdi)+ vmovdqa %ymm8, 0xc0(%rdi)+ vmovdqa %ymm11, 0xe0(%rdi)+ vmovdqa 0x100(%rdi), %ymm4+ vmovdqa 0x120(%rdi), %ymm5+ vmovdqa 0x140(%rdi), %ymm6+ vmovdqa 0x160(%rdi), %ymm7+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm9+ vmovdqa 0x1c0(%rdi), %ymm10+ vmovdqa 0x1e0(%rdi), %ymm11+ vpermq $0x1b, 0x4e0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x980(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm5, %ymm12+ vpaddd %ymm5, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpermq $0x1b, 0x460(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x900(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm7, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpermq $0x1b, 0x3e0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x880(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm8, %ymm9, %ymm12+ vpaddd %ymm9, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpermq $0x1b, 0x360(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x800(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm10, %ymm11, %ymm12+ vpaddd %ymm11, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpermq $0x1b, 0x2e0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x780(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm6, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm6 # ymm6 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm6, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm6, %ymm6+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm6, %ymm6+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm6, %ymm12, %ymm6 # ymm6 = ymm12[0],ymm6[1],ymm12[2],ymm6[3],ymm12[4],ymm6[5],ymm12[6],ymm6[7]+ vpsubd %ymm5, %ymm7, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpermq $0x1b, 0x260(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x700(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm8, %ymm10, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm9, %ymm11, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpermq $0x1b, 0x1e0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x680(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm6, %ymm10, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm7, %ymm11, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovsldup %ymm5, %ymm3 # ymm3 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7]+ vpsrlq $0x20, %ymm4, %ymm4+ vpblendd $0xaa, %ymm5, %ymm4, %ymm5 # ymm5 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7]+ vmovsldup %ymm7, %ymm4 # ymm4 = ymm7[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7]+ vmovsldup %ymm9, %ymm6 # ymm6 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7]+ vpsrlq $0x20, %ymm8, %ymm8+ vpblendd $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7]+ vmovsldup %ymm11, %ymm8 # ymm8 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm8, %ymm10, %ymm8 # ymm8 = ymm10[0],ymm8[1],ymm10[2],ymm8[3],ymm10[4],ymm8[5],ymm10[6],ymm8[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vpermq $0x1b, 0x160(%rsi), %ymm1 # ymm1 = mem[3,2,1,0]+ vpermq $0x1b, 0x600(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpsubd %ymm3, %ymm5, %ymm12+ vpaddd %ymm5, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpsubd %ymm4, %ymm7, %ymm12+ vpaddd %ymm7, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpsubd %ymm6, %ymm9, %ymm12+ vpaddd %ymm6, %ymm9, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm8, %ymm11, %ymm12+ vpaddd %ymm11, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpunpcklqdq %ymm4, %ymm3, %ymm10 # ymm10 = ymm3[0],ymm4[0],ymm3[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[1],ymm4[1],ymm3[3],ymm4[3]+ vpunpcklqdq %ymm8, %ymm6, %ymm3 # ymm3 = ymm6[0],ymm8[0],ymm6[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm6, %ymm8 # ymm8 = ymm6[1],ymm8[1],ymm6[3],ymm8[3]+ vpunpcklqdq %ymm7, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm7[0],ymm5[2],ymm7[2]+ vpunpckhqdq %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[1],ymm7[1],ymm5[3],ymm7[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vpermq $0x1b, 0xe0(%rsi), %ymm1 # ymm1 = mem[3,2,1,0]+ vpermq $0x1b, 0x580(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpsubd %ymm10, %ymm4, %ymm12+ vpaddd %ymm4, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm4 # ymm4 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm4, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm4, %ymm4+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm4, %ymm12, %ymm4 # ymm4 = ymm12[0],ymm4[1],ymm12[2],ymm4[3],ymm12[4],ymm4[5],ymm12[6],ymm4[7]+ vpsubd %ymm3, %ymm8, %ymm12+ vpaddd %ymm3, %ymm8, %ymm3+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm7, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpsubd %ymm5, %ymm11, %ymm12+ vpaddd %ymm5, %ymm11, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vperm2i128 $0x20, %ymm3, %ymm10, %ymm9 # ymm9 = ymm10[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm5, %ymm6, %ymm10 # ymm10 = ymm6[0,1],ymm5[0,1]+ vperm2i128 $0x31, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[2,3],ymm5[2,3]+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm6 # ymm6 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm4 # ymm4 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpbroadcastd 0x98(%rsi), %ymm1+ vpbroadcastd 0x538(%rsi), %ymm2+ vpsubd %ymm9, %ymm3, %ymm12+ vpaddd %ymm3, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm3 # ymm3 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm3, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm3, %ymm3+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm3, %ymm12, %ymm3 # ymm3 = ymm12[0],ymm3[1],ymm12[2],ymm3[3],ymm12[4],ymm3[5],ymm12[6],ymm3[7]+ vpsubd %ymm10, %ymm5, %ymm12+ vpaddd %ymm5, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpsubd %ymm6, %ymm8, %ymm12+ vpaddd %ymm6, %ymm8, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm4, %ymm11, %ymm12+ vpaddd %ymm4, %ymm11, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovdqa %ymm9, 0x100(%rdi)+ vmovdqa %ymm10, 0x120(%rdi)+ vmovdqa %ymm6, 0x140(%rdi)+ vmovdqa %ymm4, 0x160(%rdi)+ vmovdqa %ymm3, 0x180(%rdi)+ vmovdqa %ymm5, 0x1a0(%rdi)+ vmovdqa %ymm8, 0x1c0(%rdi)+ vmovdqa %ymm11, 0x1e0(%rdi)+ vmovdqa 0x200(%rdi), %ymm4+ vmovdqa 0x220(%rdi), %ymm5+ vmovdqa 0x240(%rdi), %ymm6+ vmovdqa 0x260(%rdi), %ymm7+ vmovdqa 0x280(%rdi), %ymm8+ vmovdqa 0x2a0(%rdi), %ymm9+ vmovdqa 0x2c0(%rdi), %ymm10+ vmovdqa 0x2e0(%rdi), %ymm11+ vpermq $0x1b, 0x4c0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x960(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm5, %ymm12+ vpaddd %ymm5, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpermq $0x1b, 0x440(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x8e0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm7, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpermq $0x1b, 0x3c0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x860(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm8, %ymm9, %ymm12+ vpaddd %ymm9, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpermq $0x1b, 0x340(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x7e0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm10, %ymm11, %ymm12+ vpaddd %ymm11, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpermq $0x1b, 0x2c0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x760(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm6, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm6 # ymm6 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm6, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm6, %ymm6+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm6, %ymm6+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm6, %ymm12, %ymm6 # ymm6 = ymm12[0],ymm6[1],ymm12[2],ymm6[3],ymm12[4],ymm6[5],ymm12[6],ymm6[7]+ vpsubd %ymm5, %ymm7, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpermq $0x1b, 0x240(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x6e0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm8, %ymm10, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm9, %ymm11, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpermq $0x1b, 0x1c0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x660(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm6, %ymm10, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm7, %ymm11, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovsldup %ymm5, %ymm3 # ymm3 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7]+ vpsrlq $0x20, %ymm4, %ymm4+ vpblendd $0xaa, %ymm5, %ymm4, %ymm5 # ymm5 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7]+ vmovsldup %ymm7, %ymm4 # ymm4 = ymm7[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7]+ vmovsldup %ymm9, %ymm6 # ymm6 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7]+ vpsrlq $0x20, %ymm8, %ymm8+ vpblendd $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7]+ vmovsldup %ymm11, %ymm8 # ymm8 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm8, %ymm10, %ymm8 # ymm8 = ymm10[0],ymm8[1],ymm10[2],ymm8[3],ymm10[4],ymm8[5],ymm10[6],ymm8[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vpermq $0x1b, 0x140(%rsi), %ymm1 # ymm1 = mem[3,2,1,0]+ vpermq $0x1b, 0x5e0(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpsubd %ymm3, %ymm5, %ymm12+ vpaddd %ymm5, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpsubd %ymm4, %ymm7, %ymm12+ vpaddd %ymm7, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpsubd %ymm6, %ymm9, %ymm12+ vpaddd %ymm6, %ymm9, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm8, %ymm11, %ymm12+ vpaddd %ymm11, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpunpcklqdq %ymm4, %ymm3, %ymm10 # ymm10 = ymm3[0],ymm4[0],ymm3[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[1],ymm4[1],ymm3[3],ymm4[3]+ vpunpcklqdq %ymm8, %ymm6, %ymm3 # ymm3 = ymm6[0],ymm8[0],ymm6[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm6, %ymm8 # ymm8 = ymm6[1],ymm8[1],ymm6[3],ymm8[3]+ vpunpcklqdq %ymm7, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm7[0],ymm5[2],ymm7[2]+ vpunpckhqdq %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[1],ymm7[1],ymm5[3],ymm7[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vpermq $0x1b, 0xc0(%rsi), %ymm1 # ymm1 = mem[3,2,1,0]+ vpermq $0x1b, 0x560(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpsubd %ymm10, %ymm4, %ymm12+ vpaddd %ymm4, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm4 # ymm4 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm4, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm4, %ymm4+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm4, %ymm12, %ymm4 # ymm4 = ymm12[0],ymm4[1],ymm12[2],ymm4[3],ymm12[4],ymm4[5],ymm12[6],ymm4[7]+ vpsubd %ymm3, %ymm8, %ymm12+ vpaddd %ymm3, %ymm8, %ymm3+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm7, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpsubd %ymm5, %ymm11, %ymm12+ vpaddd %ymm5, %ymm11, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vperm2i128 $0x20, %ymm3, %ymm10, %ymm9 # ymm9 = ymm10[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm5, %ymm6, %ymm10 # ymm10 = ymm6[0,1],ymm5[0,1]+ vperm2i128 $0x31, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[2,3],ymm5[2,3]+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm6 # ymm6 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm4 # ymm4 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpbroadcastd 0x94(%rsi), %ymm1+ vpbroadcastd 0x534(%rsi), %ymm2+ vpsubd %ymm9, %ymm3, %ymm12+ vpaddd %ymm3, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm3 # ymm3 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm3, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm3, %ymm3+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm3, %ymm12, %ymm3 # ymm3 = ymm12[0],ymm3[1],ymm12[2],ymm3[3],ymm12[4],ymm3[5],ymm12[6],ymm3[7]+ vpsubd %ymm10, %ymm5, %ymm12+ vpaddd %ymm5, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpsubd %ymm6, %ymm8, %ymm12+ vpaddd %ymm6, %ymm8, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm4, %ymm11, %ymm12+ vpaddd %ymm4, %ymm11, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovdqa %ymm9, 0x200(%rdi)+ vmovdqa %ymm10, 0x220(%rdi)+ vmovdqa %ymm6, 0x240(%rdi)+ vmovdqa %ymm4, 0x260(%rdi)+ vmovdqa %ymm3, 0x280(%rdi)+ vmovdqa %ymm5, 0x2a0(%rdi)+ vmovdqa %ymm8, 0x2c0(%rdi)+ vmovdqa %ymm11, 0x2e0(%rdi)+ vmovdqa 0x300(%rdi), %ymm4+ vmovdqa 0x320(%rdi), %ymm5+ vmovdqa 0x340(%rdi), %ymm6+ vmovdqa 0x360(%rdi), %ymm7+ vmovdqa 0x380(%rdi), %ymm8+ vmovdqa 0x3a0(%rdi), %ymm9+ vmovdqa 0x3c0(%rdi), %ymm10+ vmovdqa 0x3e0(%rdi), %ymm11+ vpermq $0x1b, 0x4a0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x940(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm5, %ymm12+ vpaddd %ymm5, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpermq $0x1b, 0x420(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x8c0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm7, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpermq $0x1b, 0x3a0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x840(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm8, %ymm9, %ymm12+ vpaddd %ymm9, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpermq $0x1b, 0x320(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x7c0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm10, %ymm11, %ymm12+ vpaddd %ymm11, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpermq $0x1b, 0x2a0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x740(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm6, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm6 # ymm6 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm6, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm6, %ymm6+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm6, %ymm6+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm6, %ymm12, %ymm6 # ymm6 = ymm12[0],ymm6[1],ymm12[2],ymm6[3],ymm12[4],ymm6[5],ymm12[6],ymm6[7]+ vpsubd %ymm5, %ymm7, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpermq $0x1b, 0x220(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x6c0(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm8, %ymm10, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm9, %ymm11, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpermq $0x1b, 0x1a0(%rsi), %ymm3 # ymm3 = mem[3,2,1,0]+ vpermq $0x1b, 0x640(%rsi), %ymm15 # ymm15 = mem[3,2,1,0]+ vmovshdup %ymm3, %ymm1 # ymm1 = ymm3[1,1,3,3,5,5,7,7]+ vmovshdup %ymm15, %ymm2 # ymm2 = ymm15[1,1,3,3,5,5,7,7]+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm6, %ymm10, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm7, %ymm11, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm3, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm15, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovsldup %ymm5, %ymm3 # ymm3 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7]+ vpsrlq $0x20, %ymm4, %ymm4+ vpblendd $0xaa, %ymm5, %ymm4, %ymm5 # ymm5 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7]+ vmovsldup %ymm7, %ymm4 # ymm4 = ymm7[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7]+ vmovsldup %ymm9, %ymm6 # ymm6 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7]+ vpsrlq $0x20, %ymm8, %ymm8+ vpblendd $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7]+ vmovsldup %ymm11, %ymm8 # ymm8 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm8, %ymm10, %ymm8 # ymm8 = ymm10[0],ymm8[1],ymm10[2],ymm8[3],ymm10[4],ymm8[5],ymm10[6],ymm8[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vpermq $0x1b, 0x120(%rsi), %ymm1 # ymm1 = mem[3,2,1,0]+ vpermq $0x1b, 0x5c0(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpsubd %ymm3, %ymm5, %ymm12+ vpaddd %ymm5, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpsubd %ymm4, %ymm7, %ymm12+ vpaddd %ymm7, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpsubd %ymm6, %ymm9, %ymm12+ vpaddd %ymm6, %ymm9, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm8, %ymm11, %ymm12+ vpaddd %ymm11, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpunpcklqdq %ymm4, %ymm3, %ymm10 # ymm10 = ymm3[0],ymm4[0],ymm3[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[1],ymm4[1],ymm3[3],ymm4[3]+ vpunpcklqdq %ymm8, %ymm6, %ymm3 # ymm3 = ymm6[0],ymm8[0],ymm6[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm6, %ymm8 # ymm8 = ymm6[1],ymm8[1],ymm6[3],ymm8[3]+ vpunpcklqdq %ymm7, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm7[0],ymm5[2],ymm7[2]+ vpunpckhqdq %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[1],ymm7[1],ymm5[3],ymm7[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vpermq $0x1b, 0xa0(%rsi), %ymm1 # ymm1 = mem[3,2,1,0]+ vpermq $0x1b, 0x540(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpsubd %ymm10, %ymm4, %ymm12+ vpaddd %ymm4, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm4 # ymm4 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm4, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm4, %ymm4+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm4, %ymm12, %ymm4 # ymm4 = ymm12[0],ymm4[1],ymm12[2],ymm4[3],ymm12[4],ymm4[5],ymm12[6],ymm4[7]+ vpsubd %ymm3, %ymm8, %ymm12+ vpaddd %ymm3, %ymm8, %ymm3+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm7, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpsubd %ymm5, %ymm11, %ymm12+ vpaddd %ymm5, %ymm11, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vperm2i128 $0x20, %ymm3, %ymm10, %ymm9 # ymm9 = ymm10[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm5, %ymm6, %ymm10 # ymm10 = ymm6[0,1],ymm5[0,1]+ vperm2i128 $0x31, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[2,3],ymm5[2,3]+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm6 # ymm6 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm4 # ymm4 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpbroadcastd 0x90(%rsi), %ymm1+ vpbroadcastd 0x530(%rsi), %ymm2+ vpsubd %ymm9, %ymm3, %ymm12+ vpaddd %ymm3, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm3 # ymm3 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm3, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm3, %ymm3+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm3, %ymm12, %ymm3 # ymm3 = ymm12[0],ymm3[1],ymm12[2],ymm3[3],ymm12[4],ymm3[5],ymm12[6],ymm3[7]+ vpsubd %ymm10, %ymm5, %ymm12+ vpaddd %ymm5, %ymm10, %ymm10+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm5 # ymm5 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm5, %ymm5+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm5, %ymm12, %ymm5 # ymm5 = ymm12[0],ymm5[1],ymm12[2],ymm5[3],ymm12[4],ymm5[5],ymm12[6],ymm5[7]+ vpsubd %ymm6, %ymm8, %ymm12+ vpaddd %ymm6, %ymm8, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm4, %ymm11, %ymm12+ vpaddd %ymm4, %ymm11, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovdqa %ymm9, 0x300(%rdi)+ vmovdqa %ymm10, 0x320(%rdi)+ vmovdqa %ymm6, 0x340(%rdi)+ vmovdqa %ymm4, 0x360(%rdi)+ vmovdqa %ymm3, 0x380(%rdi)+ vmovdqa %ymm5, 0x3a0(%rdi)+ vmovdqa %ymm8, 0x3c0(%rdi)+ vmovdqa %ymm11, 0x3e0(%rdi)+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x80(%rdi), %ymm5+ vmovdqa 0x100(%rdi), %ymm6+ vmovdqa 0x180(%rdi), %ymm7+ vmovdqa 0x200(%rdi), %ymm8+ vmovdqa 0x280(%rdi), %ymm9+ vmovdqa 0x300(%rdi), %ymm10+ vmovdqa 0x380(%rdi), %ymm11+ vpbroadcastd 0x8c(%rsi), %ymm1+ vpbroadcastd 0x52c(%rsi), %ymm2+ vpsubd %ymm4, %ymm6, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm6 # ymm6 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm6, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm6, %ymm6+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm6, %ymm12, %ymm6 # ymm6 = ymm12[0],ymm6[1],ymm12[2],ymm6[3],ymm12[4],ymm6[5],ymm12[6],ymm6[7]+ vpsubd %ymm5, %ymm7, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpbroadcastd 0x88(%rsi), %ymm1+ vpbroadcastd 0x528(%rsi), %ymm2+ vpsubd %ymm8, %ymm10, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm9, %ymm11, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpbroadcastd 0x80(%rsi), %ymm1+ vpbroadcastd 0x520(%rsi), %ymm2+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm6, %ymm10, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm7, %ymm11, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovdqa %ymm8, 0x200(%rdi)+ vmovdqa %ymm9, 0x280(%rdi)+ vmovdqa %ymm10, 0x300(%rdi)+ vmovdqa %ymm11, 0x380(%rdi)+ vmovdqa 0x40(%rsi), %ymm1+ vmovdqa 0x60(%rsi), %ymm2+ vpmuldq %ymm1, %ymm4, %ymm12+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm4, %ymm8 # ymm8 = ymm4[1,1,3,3,5,5,7,7]+ vmovshdup %ymm5, %ymm9 # ymm9 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm1, %ymm9, %ymm15+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpmuldq %ymm0, %ymm15, %ymm15+ vpsubd %ymm12, %ymm4, %ymm4+ vpsubd %ymm13, %ymm5, %ymm5+ vpsubd %ymm14, %ymm8, %ymm8+ vpsubd %ymm15, %ymm9, %ymm9+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm8[1],ymm4[2],ymm8[3],ymm4[4],ymm8[5],ymm4[6],ymm8[7]+ vpblendd $0xaa, %ymm9, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm9[1],ymm5[2],ymm9[3],ymm5[4],ymm9[5],ymm5[6],ymm9[7]+ vpmuldq %ymm1, %ymm6, %ymm12+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm6, %ymm8 # ymm8 = ymm6[1,1,3,3,5,5,7,7]+ vmovshdup %ymm7, %ymm9 # ymm9 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm1, %ymm9, %ymm15+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpmuldq %ymm0, %ymm15, %ymm15+ vpsubd %ymm12, %ymm6, %ymm6+ vpsubd %ymm13, %ymm7, %ymm7+ vpsubd %ymm14, %ymm8, %ymm8+ vpsubd %ymm15, %ymm9, %ymm9+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm8[1],ymm6[2],ymm8[3],ymm6[4],ymm8[5],ymm6[6],ymm8[7]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vmovdqa %ymm4, (%rdi)+ vmovdqa %ymm5, 0x80(%rdi)+ vmovdqa %ymm6, 0x100(%rdi)+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa 0x20(%rdi), %ymm4+ vmovdqa 0xa0(%rdi), %ymm5+ vmovdqa 0x120(%rdi), %ymm6+ vmovdqa 0x1a0(%rdi), %ymm7+ vmovdqa 0x220(%rdi), %ymm8+ vmovdqa 0x2a0(%rdi), %ymm9+ vmovdqa 0x320(%rdi), %ymm10+ vmovdqa 0x3a0(%rdi), %ymm11+ vpbroadcastd 0x8c(%rsi), %ymm1+ vpbroadcastd 0x52c(%rsi), %ymm2+ vpsubd %ymm4, %ymm6, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm6 # ymm6 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm6, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm6, %ymm6+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm6, %ymm12, %ymm6 # ymm6 = ymm12[0],ymm6[1],ymm12[2],ymm6[3],ymm12[4],ymm6[5],ymm12[6],ymm6[7]+ vpsubd %ymm5, %ymm7, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpbroadcastd 0x88(%rsi), %ymm1+ vpbroadcastd 0x528(%rsi), %ymm2+ vpsubd %ymm8, %ymm10, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm9, %ymm11, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpbroadcastd 0x80(%rsi), %ymm1+ vpbroadcastd 0x520(%rsi), %ymm2+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm6, %ymm10, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm7, %ymm11, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovdqa %ymm8, 0x220(%rdi)+ vmovdqa %ymm9, 0x2a0(%rdi)+ vmovdqa %ymm10, 0x320(%rdi)+ vmovdqa %ymm11, 0x3a0(%rdi)+ vmovdqa 0x40(%rsi), %ymm1+ vmovdqa 0x60(%rsi), %ymm2+ vpmuldq %ymm1, %ymm4, %ymm12+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm4, %ymm8 # ymm8 = ymm4[1,1,3,3,5,5,7,7]+ vmovshdup %ymm5, %ymm9 # ymm9 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm1, %ymm9, %ymm15+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpmuldq %ymm0, %ymm15, %ymm15+ vpsubd %ymm12, %ymm4, %ymm4+ vpsubd %ymm13, %ymm5, %ymm5+ vpsubd %ymm14, %ymm8, %ymm8+ vpsubd %ymm15, %ymm9, %ymm9+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm8[1],ymm4[2],ymm8[3],ymm4[4],ymm8[5],ymm4[6],ymm8[7]+ vpblendd $0xaa, %ymm9, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm9[1],ymm5[2],ymm9[3],ymm5[4],ymm9[5],ymm5[6],ymm9[7]+ vpmuldq %ymm1, %ymm6, %ymm12+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm6, %ymm8 # ymm8 = ymm6[1,1,3,3,5,5,7,7]+ vmovshdup %ymm7, %ymm9 # ymm9 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm1, %ymm9, %ymm15+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpmuldq %ymm0, %ymm15, %ymm15+ vpsubd %ymm12, %ymm6, %ymm6+ vpsubd %ymm13, %ymm7, %ymm7+ vpsubd %ymm14, %ymm8, %ymm8+ vpsubd %ymm15, %ymm9, %ymm9+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm8[1],ymm6[2],ymm8[3],ymm6[4],ymm8[5],ymm6[6],ymm8[7]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vmovdqa %ymm4, 0x20(%rdi)+ vmovdqa %ymm5, 0xa0(%rdi)+ vmovdqa %ymm6, 0x120(%rdi)+ vmovdqa %ymm7, 0x1a0(%rdi)+ vmovdqa 0x40(%rdi), %ymm4+ vmovdqa 0xc0(%rdi), %ymm5+ vmovdqa 0x140(%rdi), %ymm6+ vmovdqa 0x1c0(%rdi), %ymm7+ vmovdqa 0x240(%rdi), %ymm8+ vmovdqa 0x2c0(%rdi), %ymm9+ vmovdqa 0x340(%rdi), %ymm10+ vmovdqa 0x3c0(%rdi), %ymm11+ vpbroadcastd 0x8c(%rsi), %ymm1+ vpbroadcastd 0x52c(%rsi), %ymm2+ vpsubd %ymm4, %ymm6, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm6 # ymm6 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm6, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm6, %ymm6+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm6, %ymm12, %ymm6 # ymm6 = ymm12[0],ymm6[1],ymm12[2],ymm6[3],ymm12[4],ymm6[5],ymm12[6],ymm6[7]+ vpsubd %ymm5, %ymm7, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpbroadcastd 0x88(%rsi), %ymm1+ vpbroadcastd 0x528(%rsi), %ymm2+ vpsubd %ymm8, %ymm10, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm9, %ymm11, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpbroadcastd 0x80(%rsi), %ymm1+ vpbroadcastd 0x520(%rsi), %ymm2+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm6, %ymm10, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm7, %ymm11, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovdqa %ymm8, 0x240(%rdi)+ vmovdqa %ymm9, 0x2c0(%rdi)+ vmovdqa %ymm10, 0x340(%rdi)+ vmovdqa %ymm11, 0x3c0(%rdi)+ vmovdqa 0x40(%rsi), %ymm1+ vmovdqa 0x60(%rsi), %ymm2+ vpmuldq %ymm1, %ymm4, %ymm12+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm4, %ymm8 # ymm8 = ymm4[1,1,3,3,5,5,7,7]+ vmovshdup %ymm5, %ymm9 # ymm9 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm1, %ymm9, %ymm15+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpmuldq %ymm0, %ymm15, %ymm15+ vpsubd %ymm12, %ymm4, %ymm4+ vpsubd %ymm13, %ymm5, %ymm5+ vpsubd %ymm14, %ymm8, %ymm8+ vpsubd %ymm15, %ymm9, %ymm9+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm8[1],ymm4[2],ymm8[3],ymm4[4],ymm8[5],ymm4[6],ymm8[7]+ vpblendd $0xaa, %ymm9, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm9[1],ymm5[2],ymm9[3],ymm5[4],ymm9[5],ymm5[6],ymm9[7]+ vpmuldq %ymm1, %ymm6, %ymm12+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm6, %ymm8 # ymm8 = ymm6[1,1,3,3,5,5,7,7]+ vmovshdup %ymm7, %ymm9 # ymm9 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm1, %ymm9, %ymm15+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpmuldq %ymm0, %ymm15, %ymm15+ vpsubd %ymm12, %ymm6, %ymm6+ vpsubd %ymm13, %ymm7, %ymm7+ vpsubd %ymm14, %ymm8, %ymm8+ vpsubd %ymm15, %ymm9, %ymm9+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm8[1],ymm6[2],ymm8[3],ymm6[4],ymm8[5],ymm6[6],ymm8[7]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vmovdqa %ymm4, 0x40(%rdi)+ vmovdqa %ymm5, 0xc0(%rdi)+ vmovdqa %ymm6, 0x140(%rdi)+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa 0x60(%rdi), %ymm4+ vmovdqa 0xe0(%rdi), %ymm5+ vmovdqa 0x160(%rdi), %ymm6+ vmovdqa 0x1e0(%rdi), %ymm7+ vmovdqa 0x260(%rdi), %ymm8+ vmovdqa 0x2e0(%rdi), %ymm9+ vmovdqa 0x360(%rdi), %ymm10+ vmovdqa 0x3e0(%rdi), %ymm11+ vpbroadcastd 0x8c(%rsi), %ymm1+ vpbroadcastd 0x52c(%rsi), %ymm2+ vpsubd %ymm4, %ymm6, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm6 # ymm6 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm6, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm6, %ymm6+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm6, %ymm12, %ymm6 # ymm6 = ymm12[0],ymm6[1],ymm12[2],ymm6[3],ymm12[4],ymm6[5],ymm12[6],ymm6[7]+ vpsubd %ymm5, %ymm7, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm7 # ymm7 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm7, %ymm7+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm7, %ymm12, %ymm7 # ymm7 = ymm12[0],ymm7[1],ymm12[2],ymm7[3],ymm12[4],ymm7[5],ymm12[6],ymm7[7]+ vpbroadcastd 0x88(%rsi), %ymm1+ vpbroadcastd 0x528(%rsi), %ymm2+ vpsubd %ymm8, %ymm10, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm9, %ymm11, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vpbroadcastd 0x80(%rsi), %ymm1+ vpbroadcastd 0x520(%rsi), %ymm2+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm8 # ymm8 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm8, %ymm8+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm12, %ymm8 # ymm8 = ymm12[0],ymm8[1],ymm12[2],ymm8[3],ymm12[4],ymm8[5],ymm12[6],ymm8[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm9 # ymm9 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm9, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm9, %ymm9+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm9, %ymm12, %ymm9 # ymm9 = ymm12[0],ymm9[1],ymm12[2],ymm9[3],ymm12[4],ymm9[5],ymm12[6],ymm9[7]+ vpsubd %ymm6, %ymm10, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm10 # ymm10 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm10, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm10, %ymm10+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm10, %ymm12, %ymm10 # ymm10 = ymm12[0],ymm10[1],ymm12[2],ymm10[3],ymm12[4],ymm10[5],ymm12[6],ymm10[7]+ vpsubd %ymm7, %ymm11, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vpmuldq %ymm1, %ymm12, %ymm13+ vmovshdup %ymm12, %ymm11 # ymm11 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm14+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpsubd %ymm13, %ymm12, %ymm12+ vpsubd %ymm14, %ymm11, %ymm11+ vmovshdup %ymm12, %ymm12 # ymm12 = ymm12[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm11, %ymm12, %ymm11 # ymm11 = ymm12[0],ymm11[1],ymm12[2],ymm11[3],ymm12[4],ymm11[5],ymm12[6],ymm11[7]+ vmovdqa %ymm8, 0x260(%rdi)+ vmovdqa %ymm9, 0x2e0(%rdi)+ vmovdqa %ymm10, 0x360(%rdi)+ vmovdqa %ymm11, 0x3e0(%rdi)+ vmovdqa 0x40(%rsi), %ymm1+ vmovdqa 0x60(%rsi), %ymm2+ vpmuldq %ymm1, %ymm4, %ymm12+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm4, %ymm8 # ymm8 = ymm4[1,1,3,3,5,5,7,7]+ vmovshdup %ymm5, %ymm9 # ymm9 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm1, %ymm9, %ymm15+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpmuldq %ymm0, %ymm15, %ymm15+ vpsubd %ymm12, %ymm4, %ymm4+ vpsubd %ymm13, %ymm5, %ymm5+ vpsubd %ymm14, %ymm8, %ymm8+ vpsubd %ymm15, %ymm9, %ymm9+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm8[1],ymm4[2],ymm8[3],ymm4[4],ymm8[5],ymm4[6],ymm8[7]+ vpblendd $0xaa, %ymm9, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm9[1],ymm5[2],ymm9[3],ymm5[4],ymm9[5],ymm5[6],ymm9[7]+ vpmuldq %ymm1, %ymm6, %ymm12+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm6, %ymm8 # ymm8 = ymm6[1,1,3,3,5,5,7,7]+ vmovshdup %ymm7, %ymm9 # ymm9 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm14+ vpmuldq %ymm1, %ymm9, %ymm15+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm0, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vpmuldq %ymm0, %ymm15, %ymm15+ vpsubd %ymm12, %ymm6, %ymm6+ vpsubd %ymm13, %ymm7, %ymm7+ vpsubd %ymm14, %ymm8, %ymm8+ vpsubd %ymm15, %ymm9, %ymm9+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm8, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm8[1],ymm6[2],ymm8[3],ymm6[4],ymm8[5],ymm6[6],ymm8[7]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vmovdqa %ymm4, 0x60(%rdi)+ vmovdqa %ymm5, 0xe0(%rdi)+ vmovdqa %ymm6, 0x160(%rdi)+ vmovdqa %ymm7, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(invntt_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,2405 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++ /*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: ntt_avx2_asm+ Description: x86_64 AVX2 forward NTT+ Signature: void mld_ntt_avx2_asm(int32_t *r, const int32_t *qdata)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t *r+ description: Input/output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 2496+ permissions: read-only+ c_parameter: const int32_t *qdata+ description: Precomputed constants (624 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_ntt_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(ntt_avx2_asm)+MLD_ASM_FN_SYMBOL(ntt_avx2_asm)++ .cfi_startproc+ vmovdqa (%rsi), %ymm0+ vpbroadcastd 0x84(%rsi), %ymm1+ vpbroadcastd 0x524(%rsi), %ymm2+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x80(%rdi), %ymm5+ vmovdqa 0x100(%rdi), %ymm6+ vmovdqa 0x180(%rdi), %ymm7+ vmovdqa 0x200(%rdi), %ymm8+ vmovdqa 0x280(%rdi), %ymm9+ vmovdqa 0x300(%rdi), %ymm10+ vmovdqa 0x380(%rdi), %ymm11+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm4, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm9, %ymm13+ vmovshdup %ymm9, %ymm12 # ymm12 = ymm9[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm9, %ymm9 # ymm9 = ymm9[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm9, %ymm9 # ymm9 = ymm9[0],ymm12[1],ymm9[2],ymm12[3],ymm9[4],ymm12[5],ymm9[6],ymm12[7]+ vpsubd %ymm9, %ymm5, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm9+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm6, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm7, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm7, %ymm7+ vpbroadcastd 0x88(%rsi), %ymm1+ vpbroadcastd 0x528(%rsi), %ymm2+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm4, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm7, %ymm12 # ymm12 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm12[1],ymm7[2],ymm12[3],ymm7[4],ymm12[5],ymm7[6],ymm12[7]+ vpsubd %ymm7, %ymm5, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm7+ vpsubd %ymm13, %ymm5, %ymm5+ vpbroadcastd 0x8c(%rsi), %ymm1+ vpbroadcastd 0x52c(%rsi), %ymm2+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm8, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm9, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm9, %ymm9+ vmovdqa %ymm4, (%rdi)+ vmovdqa %ymm5, 0x80(%rdi)+ vmovdqa %ymm6, 0x100(%rdi)+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm8, 0x200(%rdi)+ vmovdqa %ymm9, 0x280(%rdi)+ vmovdqa %ymm10, 0x300(%rdi)+ vmovdqa %ymm11, 0x380(%rdi)+ vpbroadcastd 0x84(%rsi), %ymm1+ vpbroadcastd 0x524(%rsi), %ymm2+ vmovdqa 0x20(%rdi), %ymm4+ vmovdqa 0xa0(%rdi), %ymm5+ vmovdqa 0x120(%rdi), %ymm6+ vmovdqa 0x1a0(%rdi), %ymm7+ vmovdqa 0x220(%rdi), %ymm8+ vmovdqa 0x2a0(%rdi), %ymm9+ vmovdqa 0x320(%rdi), %ymm10+ vmovdqa 0x3a0(%rdi), %ymm11+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm4, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm9, %ymm13+ vmovshdup %ymm9, %ymm12 # ymm12 = ymm9[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm9, %ymm9 # ymm9 = ymm9[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm9, %ymm9 # ymm9 = ymm9[0],ymm12[1],ymm9[2],ymm12[3],ymm9[4],ymm12[5],ymm9[6],ymm12[7]+ vpsubd %ymm9, %ymm5, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm9+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm6, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm7, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm7, %ymm7+ vpbroadcastd 0x88(%rsi), %ymm1+ vpbroadcastd 0x528(%rsi), %ymm2+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm4, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm7, %ymm12 # ymm12 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm12[1],ymm7[2],ymm12[3],ymm7[4],ymm12[5],ymm7[6],ymm12[7]+ vpsubd %ymm7, %ymm5, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm7+ vpsubd %ymm13, %ymm5, %ymm5+ vpbroadcastd 0x8c(%rsi), %ymm1+ vpbroadcastd 0x52c(%rsi), %ymm2+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm8, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm9, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm9, %ymm9+ vmovdqa %ymm4, 0x20(%rdi)+ vmovdqa %ymm5, 0xa0(%rdi)+ vmovdqa %ymm6, 0x120(%rdi)+ vmovdqa %ymm7, 0x1a0(%rdi)+ vmovdqa %ymm8, 0x220(%rdi)+ vmovdqa %ymm9, 0x2a0(%rdi)+ vmovdqa %ymm10, 0x320(%rdi)+ vmovdqa %ymm11, 0x3a0(%rdi)+ vpbroadcastd 0x84(%rsi), %ymm1+ vpbroadcastd 0x524(%rsi), %ymm2+ vmovdqa 0x40(%rdi), %ymm4+ vmovdqa 0xc0(%rdi), %ymm5+ vmovdqa 0x140(%rdi), %ymm6+ vmovdqa 0x1c0(%rdi), %ymm7+ vmovdqa 0x240(%rdi), %ymm8+ vmovdqa 0x2c0(%rdi), %ymm9+ vmovdqa 0x340(%rdi), %ymm10+ vmovdqa 0x3c0(%rdi), %ymm11+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm4, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm9, %ymm13+ vmovshdup %ymm9, %ymm12 # ymm12 = ymm9[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm9, %ymm9 # ymm9 = ymm9[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm9, %ymm9 # ymm9 = ymm9[0],ymm12[1],ymm9[2],ymm12[3],ymm9[4],ymm12[5],ymm9[6],ymm12[7]+ vpsubd %ymm9, %ymm5, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm9+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm6, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm7, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm7, %ymm7+ vpbroadcastd 0x88(%rsi), %ymm1+ vpbroadcastd 0x528(%rsi), %ymm2+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm4, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm7, %ymm12 # ymm12 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm12[1],ymm7[2],ymm12[3],ymm7[4],ymm12[5],ymm7[6],ymm12[7]+ vpsubd %ymm7, %ymm5, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm7+ vpsubd %ymm13, %ymm5, %ymm5+ vpbroadcastd 0x8c(%rsi), %ymm1+ vpbroadcastd 0x52c(%rsi), %ymm2+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm8, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm9, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm9, %ymm9+ vmovdqa %ymm4, 0x40(%rdi)+ vmovdqa %ymm5, 0xc0(%rdi)+ vmovdqa %ymm6, 0x140(%rdi)+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm8, 0x240(%rdi)+ vmovdqa %ymm9, 0x2c0(%rdi)+ vmovdqa %ymm10, 0x340(%rdi)+ vmovdqa %ymm11, 0x3c0(%rdi)+ vpbroadcastd 0x84(%rsi), %ymm1+ vpbroadcastd 0x524(%rsi), %ymm2+ vmovdqa 0x60(%rdi), %ymm4+ vmovdqa 0xe0(%rdi), %ymm5+ vmovdqa 0x160(%rdi), %ymm6+ vmovdqa 0x1e0(%rdi), %ymm7+ vmovdqa 0x260(%rdi), %ymm8+ vmovdqa 0x2e0(%rdi), %ymm9+ vmovdqa 0x360(%rdi), %ymm10+ vmovdqa 0x3e0(%rdi), %ymm11+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm4, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm9, %ymm13+ vmovshdup %ymm9, %ymm12 # ymm12 = ymm9[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm9, %ymm9 # ymm9 = ymm9[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm9, %ymm9 # ymm9 = ymm9[0],ymm12[1],ymm9[2],ymm12[3],ymm9[4],ymm12[5],ymm9[6],ymm12[7]+ vpsubd %ymm9, %ymm5, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm9+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm6, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm7, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm7, %ymm7+ vpbroadcastd 0x88(%rsi), %ymm1+ vpbroadcastd 0x528(%rsi), %ymm2+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm4, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm7, %ymm12 # ymm12 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm12[1],ymm7[2],ymm12[3],ymm7[4],ymm12[5],ymm7[6],ymm12[7]+ vpsubd %ymm7, %ymm5, %ymm12+ vpaddd %ymm7, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm7+ vpsubd %ymm13, %ymm5, %ymm5+ vpbroadcastd 0x8c(%rsi), %ymm1+ vpbroadcastd 0x52c(%rsi), %ymm2+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm8, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm9, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm9, %ymm9+ vmovdqa %ymm4, 0x60(%rdi)+ vmovdqa %ymm5, 0xe0(%rdi)+ vmovdqa %ymm6, 0x160(%rdi)+ vmovdqa %ymm7, 0x1e0(%rdi)+ vmovdqa %ymm8, 0x260(%rdi)+ vmovdqa %ymm9, 0x2e0(%rdi)+ vmovdqa %ymm10, 0x360(%rdi)+ vmovdqa %ymm11, 0x3e0(%rdi)+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x20(%rdi), %ymm5+ vmovdqa 0x40(%rdi), %ymm6+ vmovdqa 0x60(%rdi), %ymm7+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm9+ vmovdqa 0xc0(%rdi), %ymm10+ vmovdqa 0xe0(%rdi), %ymm11+ vpbroadcastd 0x90(%rsi), %ymm1+ vpbroadcastd 0x530(%rsi), %ymm2+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm4, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm9, %ymm13+ vmovshdup %ymm9, %ymm12 # ymm12 = ymm9[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm9, %ymm9 # ymm9 = ymm9[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm9, %ymm9 # ymm9 = ymm9[0],ymm12[1],ymm9[2],ymm12[3],ymm9[4],ymm12[5],ymm9[6],ymm12[7]+ vpsubd %ymm9, %ymm5, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm9+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm6, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm7, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm7, %ymm7+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vmovdqa 0xa0(%rsi), %ymm1+ vmovdqa 0x540(%rsi), %ymm2+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm5, %ymm12 # ymm12 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm12[1],ymm5[2],ymm12[3],ymm5[4],ymm12[5],ymm5[6],ymm12[7]+ vpsubd %ymm5, %ymm3, %ymm12+ vpaddd %ymm5, %ymm3, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm5+ vpsubd %ymm13, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm8, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm4, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm9, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm9, %ymm9+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovdqa 0x120(%rsi), %ymm1+ vmovdqa 0x5c0(%rsi), %ymm2+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm7, %ymm12+ vpaddd %ymm7, %ymm8, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm7, %ymm7+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm5, %ymm12+ vpaddd %ymm6, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm3, %ymm12+ vpaddd %ymm4, %ymm3, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm10, %ymm12+ vpaddd %ymm11, %ymm10, %ymm10+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm10, %ymm10+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vmovdqa 0x1a0(%rsi), %ymm1+ vmovdqa 0x640(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm5, %ymm12 # ymm12 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm12[1],ymm5[2],ymm12[3],ymm5[4],ymm12[5],ymm5[6],ymm12[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm5+ vpsubd %ymm13, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm3, %ymm13+ vmovshdup %ymm3, %ymm12 # ymm12 = ymm3[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm3, %ymm3 # ymm3 = ymm3[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm3, %ymm3 # ymm3 = ymm3[0],ymm12[1],ymm3[2],ymm12[3],ymm3[4],ymm12[5],ymm3[6],ymm12[7]+ vpsubd %ymm3, %ymm7, %ymm12+ vpaddd %ymm3, %ymm7, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm3+ vpsubd %ymm13, %ymm7, %ymm7+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm6, %ymm12+ vpaddd %ymm6, %ymm11, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm6, %ymm6+ vmovdqa 0x220(%rsi), %ymm1+ vmovdqa 0x6c0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm7, %ymm12 # ymm12 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm12[1],ymm7[2],ymm12[3],ymm7[4],ymm12[5],ymm7[6],ymm12[7]+ vpsubd %ymm7, %ymm9, %ymm12+ vpaddd %ymm7, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm7+ vpsubd %ymm13, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm8, %ymm12+ vpaddd %ymm6, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm8, %ymm8+ vmovdqa 0x2a0(%rsi), %ymm1+ vmovdqa 0x740(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm3, %ymm13+ vmovshdup %ymm3, %ymm12 # ymm12 = ymm3[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm3, %ymm3 # ymm3 = ymm3[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm3, %ymm3 # ymm3 = ymm3[0],ymm12[1],ymm3[2],ymm12[3],ymm3[4],ymm12[5],ymm3[6],ymm12[7]+ vpsubd %ymm3, %ymm5, %ymm12+ vpaddd %ymm3, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm3+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm4, %ymm12+ vpaddd %ymm4, %ymm11, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm4, %ymm4+ vmovdqa 0x320(%rsi), %ymm1+ vmovdqa 0x7c0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm9, %ymm12+ vpaddd %ymm8, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm9, %ymm9+ vmovdqa 0x3a0(%rsi), %ymm1+ vmovdqa 0x840(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm6, %ymm7, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm7, %ymm7+ vmovdqa 0x420(%rsi), %ymm1+ vmovdqa 0x8c0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm5, %ymm12+ vpaddd %ymm4, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm5, %ymm5+ vmovdqa 0x4a0(%rsi), %ymm1+ vmovdqa 0x940(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm3, %ymm12+ vpaddd %ymm3, %ymm11, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm3, %ymm3+ vmovdqa %ymm9, (%rdi)+ vmovdqa %ymm8, 0x20(%rdi)+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm6, 0x60(%rdi)+ vmovdqa %ymm5, 0x80(%rdi)+ vmovdqa %ymm4, 0xa0(%rdi)+ vmovdqa %ymm3, 0xc0(%rdi)+ vmovdqa %ymm11, 0xe0(%rdi)+ vmovdqa 0x100(%rdi), %ymm4+ vmovdqa 0x120(%rdi), %ymm5+ vmovdqa 0x140(%rdi), %ymm6+ vmovdqa 0x160(%rdi), %ymm7+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm9+ vmovdqa 0x1c0(%rdi), %ymm10+ vmovdqa 0x1e0(%rdi), %ymm11+ vpbroadcastd 0x94(%rsi), %ymm1+ vpbroadcastd 0x534(%rsi), %ymm2+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm4, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm9, %ymm13+ vmovshdup %ymm9, %ymm12 # ymm12 = ymm9[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm9, %ymm9 # ymm9 = ymm9[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm9, %ymm9 # ymm9 = ymm9[0],ymm12[1],ymm9[2],ymm12[3],ymm9[4],ymm12[5],ymm9[6],ymm12[7]+ vpsubd %ymm9, %ymm5, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm9+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm6, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm7, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm7, %ymm7+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vmovdqa 0xc0(%rsi), %ymm1+ vmovdqa 0x560(%rsi), %ymm2+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm5, %ymm12 # ymm12 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm12[1],ymm5[2],ymm12[3],ymm5[4],ymm12[5],ymm5[6],ymm12[7]+ vpsubd %ymm5, %ymm3, %ymm12+ vpaddd %ymm5, %ymm3, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm5+ vpsubd %ymm13, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm8, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm4, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm9, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm9, %ymm9+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovdqa 0x140(%rsi), %ymm1+ vmovdqa 0x5e0(%rsi), %ymm2+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm7, %ymm12+ vpaddd %ymm7, %ymm8, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm7, %ymm7+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm5, %ymm12+ vpaddd %ymm6, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm3, %ymm12+ vpaddd %ymm4, %ymm3, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm10, %ymm12+ vpaddd %ymm11, %ymm10, %ymm10+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm10, %ymm10+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vmovdqa 0x1c0(%rsi), %ymm1+ vmovdqa 0x660(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm5, %ymm12 # ymm12 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm12[1],ymm5[2],ymm12[3],ymm5[4],ymm12[5],ymm5[6],ymm12[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm5+ vpsubd %ymm13, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm3, %ymm13+ vmovshdup %ymm3, %ymm12 # ymm12 = ymm3[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm3, %ymm3 # ymm3 = ymm3[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm3, %ymm3 # ymm3 = ymm3[0],ymm12[1],ymm3[2],ymm12[3],ymm3[4],ymm12[5],ymm3[6],ymm12[7]+ vpsubd %ymm3, %ymm7, %ymm12+ vpaddd %ymm3, %ymm7, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm3+ vpsubd %ymm13, %ymm7, %ymm7+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm6, %ymm12+ vpaddd %ymm6, %ymm11, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm6, %ymm6+ vmovdqa 0x240(%rsi), %ymm1+ vmovdqa 0x6e0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm7, %ymm12 # ymm12 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm12[1],ymm7[2],ymm12[3],ymm7[4],ymm12[5],ymm7[6],ymm12[7]+ vpsubd %ymm7, %ymm9, %ymm12+ vpaddd %ymm7, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm7+ vpsubd %ymm13, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm8, %ymm12+ vpaddd %ymm6, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm8, %ymm8+ vmovdqa 0x2c0(%rsi), %ymm1+ vmovdqa 0x760(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm3, %ymm13+ vmovshdup %ymm3, %ymm12 # ymm12 = ymm3[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm3, %ymm3 # ymm3 = ymm3[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm3, %ymm3 # ymm3 = ymm3[0],ymm12[1],ymm3[2],ymm12[3],ymm3[4],ymm12[5],ymm3[6],ymm12[7]+ vpsubd %ymm3, %ymm5, %ymm12+ vpaddd %ymm3, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm3+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm4, %ymm12+ vpaddd %ymm4, %ymm11, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm4, %ymm4+ vmovdqa 0x340(%rsi), %ymm1+ vmovdqa 0x7e0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm9, %ymm12+ vpaddd %ymm8, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm9, %ymm9+ vmovdqa 0x3c0(%rsi), %ymm1+ vmovdqa 0x860(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm6, %ymm7, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm7, %ymm7+ vmovdqa 0x440(%rsi), %ymm1+ vmovdqa 0x8e0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm5, %ymm12+ vpaddd %ymm4, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm5, %ymm5+ vmovdqa 0x4c0(%rsi), %ymm1+ vmovdqa 0x960(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm3, %ymm12+ vpaddd %ymm3, %ymm11, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm3, %ymm3+ vmovdqa %ymm9, 0x100(%rdi)+ vmovdqa %ymm8, 0x120(%rdi)+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm6, 0x160(%rdi)+ vmovdqa %ymm5, 0x180(%rdi)+ vmovdqa %ymm4, 0x1a0(%rdi)+ vmovdqa %ymm3, 0x1c0(%rdi)+ vmovdqa %ymm11, 0x1e0(%rdi)+ vmovdqa 0x200(%rdi), %ymm4+ vmovdqa 0x220(%rdi), %ymm5+ vmovdqa 0x240(%rdi), %ymm6+ vmovdqa 0x260(%rdi), %ymm7+ vmovdqa 0x280(%rdi), %ymm8+ vmovdqa 0x2a0(%rdi), %ymm9+ vmovdqa 0x2c0(%rdi), %ymm10+ vmovdqa 0x2e0(%rdi), %ymm11+ vpbroadcastd 0x98(%rsi), %ymm1+ vpbroadcastd 0x538(%rsi), %ymm2+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm4, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm9, %ymm13+ vmovshdup %ymm9, %ymm12 # ymm12 = ymm9[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm9, %ymm9 # ymm9 = ymm9[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm9, %ymm9 # ymm9 = ymm9[0],ymm12[1],ymm9[2],ymm12[3],ymm9[4],ymm12[5],ymm9[6],ymm12[7]+ vpsubd %ymm9, %ymm5, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm9+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm6, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm7, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm7, %ymm7+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vmovdqa 0xe0(%rsi), %ymm1+ vmovdqa 0x580(%rsi), %ymm2+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm5, %ymm12 # ymm12 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm12[1],ymm5[2],ymm12[3],ymm5[4],ymm12[5],ymm5[6],ymm12[7]+ vpsubd %ymm5, %ymm3, %ymm12+ vpaddd %ymm5, %ymm3, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm5+ vpsubd %ymm13, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm8, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm4, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm9, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm9, %ymm9+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovdqa 0x160(%rsi), %ymm1+ vmovdqa 0x600(%rsi), %ymm2+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm7, %ymm12+ vpaddd %ymm7, %ymm8, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm7, %ymm7+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm5, %ymm12+ vpaddd %ymm6, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm3, %ymm12+ vpaddd %ymm4, %ymm3, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm10, %ymm12+ vpaddd %ymm11, %ymm10, %ymm10+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm10, %ymm10+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vmovdqa 0x1e0(%rsi), %ymm1+ vmovdqa 0x680(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm5, %ymm12 # ymm12 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm12[1],ymm5[2],ymm12[3],ymm5[4],ymm12[5],ymm5[6],ymm12[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm5+ vpsubd %ymm13, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm3, %ymm13+ vmovshdup %ymm3, %ymm12 # ymm12 = ymm3[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm3, %ymm3 # ymm3 = ymm3[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm3, %ymm3 # ymm3 = ymm3[0],ymm12[1],ymm3[2],ymm12[3],ymm3[4],ymm12[5],ymm3[6],ymm12[7]+ vpsubd %ymm3, %ymm7, %ymm12+ vpaddd %ymm3, %ymm7, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm3+ vpsubd %ymm13, %ymm7, %ymm7+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm6, %ymm12+ vpaddd %ymm6, %ymm11, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm6, %ymm6+ vmovdqa 0x260(%rsi), %ymm1+ vmovdqa 0x700(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm7, %ymm12 # ymm12 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm12[1],ymm7[2],ymm12[3],ymm7[4],ymm12[5],ymm7[6],ymm12[7]+ vpsubd %ymm7, %ymm9, %ymm12+ vpaddd %ymm7, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm7+ vpsubd %ymm13, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm8, %ymm12+ vpaddd %ymm6, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm8, %ymm8+ vmovdqa 0x2e0(%rsi), %ymm1+ vmovdqa 0x780(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm3, %ymm13+ vmovshdup %ymm3, %ymm12 # ymm12 = ymm3[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm3, %ymm3 # ymm3 = ymm3[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm3, %ymm3 # ymm3 = ymm3[0],ymm12[1],ymm3[2],ymm12[3],ymm3[4],ymm12[5],ymm3[6],ymm12[7]+ vpsubd %ymm3, %ymm5, %ymm12+ vpaddd %ymm3, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm3+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm4, %ymm12+ vpaddd %ymm4, %ymm11, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm4, %ymm4+ vmovdqa 0x360(%rsi), %ymm1+ vmovdqa 0x800(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm9, %ymm12+ vpaddd %ymm8, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm9, %ymm9+ vmovdqa 0x3e0(%rsi), %ymm1+ vmovdqa 0x880(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm6, %ymm7, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm7, %ymm7+ vmovdqa 0x460(%rsi), %ymm1+ vmovdqa 0x900(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm5, %ymm12+ vpaddd %ymm4, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm5, %ymm5+ vmovdqa 0x4e0(%rsi), %ymm1+ vmovdqa 0x980(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm3, %ymm12+ vpaddd %ymm3, %ymm11, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm3, %ymm3+ vmovdqa %ymm9, 0x200(%rdi)+ vmovdqa %ymm8, 0x220(%rdi)+ vmovdqa %ymm7, 0x240(%rdi)+ vmovdqa %ymm6, 0x260(%rdi)+ vmovdqa %ymm5, 0x280(%rdi)+ vmovdqa %ymm4, 0x2a0(%rdi)+ vmovdqa %ymm3, 0x2c0(%rdi)+ vmovdqa %ymm11, 0x2e0(%rdi)+ vmovdqa 0x300(%rdi), %ymm4+ vmovdqa 0x320(%rdi), %ymm5+ vmovdqa 0x340(%rdi), %ymm6+ vmovdqa 0x360(%rdi), %ymm7+ vmovdqa 0x380(%rdi), %ymm8+ vmovdqa 0x3a0(%rdi), %ymm9+ vmovdqa 0x3c0(%rdi), %ymm10+ vmovdqa 0x3e0(%rdi), %ymm11+ vpbroadcastd 0x9c(%rsi), %ymm1+ vpbroadcastd 0x53c(%rsi), %ymm2+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm4, %ymm12+ vpaddd %ymm4, %ymm8, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm9, %ymm13+ vmovshdup %ymm9, %ymm12 # ymm12 = ymm9[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm9, %ymm9+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm9, %ymm9 # ymm9 = ymm9[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm9, %ymm9 # ymm9 = ymm9[0],ymm12[1],ymm9[2],ymm12[3],ymm9[4],ymm12[5],ymm9[6],ymm12[7]+ vpsubd %ymm9, %ymm5, %ymm12+ vpaddd %ymm5, %ymm9, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm9+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm6, %ymm12+ vpaddd %ymm6, %ymm10, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm6, %ymm6+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm7, %ymm12+ vpaddd %ymm7, %ymm11, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm7, %ymm7+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vmovdqa 0x100(%rsi), %ymm1+ vmovdqa 0x5a0(%rsi), %ymm2+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm5, %ymm12 # ymm12 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm12[1],ymm5[2],ymm12[3],ymm5[4],ymm12[5],ymm5[6],ymm12[7]+ vpsubd %ymm5, %ymm3, %ymm12+ vpaddd %ymm5, %ymm3, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm5+ vpsubd %ymm13, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm10, %ymm13+ vmovshdup %ymm10, %ymm12 # ymm12 = ymm10[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm10, %ymm10+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm10, %ymm10 # ymm10 = ymm10[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm10, %ymm10 # ymm10 = ymm10[0],ymm12[1],ymm10[2],ymm12[3],ymm10[4],ymm12[5],ymm10[6],ymm12[7]+ vpsubd %ymm10, %ymm8, %ymm12+ vpaddd %ymm10, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm10+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm4, %ymm12+ vpaddd %ymm6, %ymm4, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm4, %ymm4+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm9, %ymm12+ vpaddd %ymm11, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm9, %ymm9+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovdqa 0x180(%rsi), %ymm1+ vmovdqa 0x620(%rsi), %ymm2+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm7, %ymm12+ vpaddd %ymm7, %ymm8, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm7, %ymm7+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm5, %ymm12+ vpaddd %ymm6, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm3, %ymm12+ vpaddd %ymm4, %ymm3, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm3, %ymm3+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm2, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm10, %ymm12+ vpaddd %ymm11, %ymm10, %ymm10+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm10, %ymm10+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vmovdqa 0x200(%rsi), %ymm1+ vmovdqa 0x6a0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm5, %ymm13+ vmovshdup %ymm5, %ymm12 # ymm12 = ymm5[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm5, %ymm5+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm5, %ymm5 # ymm5 = ymm5[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm5, %ymm5 # ymm5 = ymm5[0],ymm12[1],ymm5[2],ymm12[3],ymm5[4],ymm12[5],ymm5[6],ymm12[7]+ vpsubd %ymm5, %ymm9, %ymm12+ vpaddd %ymm5, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm5+ vpsubd %ymm13, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm8, %ymm12+ vpaddd %ymm4, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm8, %ymm8+ vpmuldq %ymm1, %ymm3, %ymm13+ vmovshdup %ymm3, %ymm12 # ymm12 = ymm3[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm3, %ymm3 # ymm3 = ymm3[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm3, %ymm3 # ymm3 = ymm3[0],ymm12[1],ymm3[2],ymm12[3],ymm3[4],ymm12[5],ymm3[6],ymm12[7]+ vpsubd %ymm3, %ymm7, %ymm12+ vpaddd %ymm3, %ymm7, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm3+ vpsubd %ymm13, %ymm7, %ymm7+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm6, %ymm12+ vpaddd %ymm6, %ymm11, %ymm6+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm6, %ymm6+ vmovdqa 0x280(%rsi), %ymm1+ vmovdqa 0x720(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm7, %ymm13+ vmovshdup %ymm7, %ymm12 # ymm12 = ymm7[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm7, %ymm7+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm7, %ymm7 # ymm7 = ymm7[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm7, %ymm7 # ymm7 = ymm7[0],ymm12[1],ymm7[2],ymm12[3],ymm7[4],ymm12[5],ymm7[6],ymm12[7]+ vpsubd %ymm7, %ymm9, %ymm12+ vpaddd %ymm7, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm7+ vpsubd %ymm13, %ymm9, %ymm9+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm8, %ymm12+ vpaddd %ymm6, %ymm8, %ymm8+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm8, %ymm8+ vmovdqa 0x300(%rsi), %ymm1+ vmovdqa 0x7a0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm3, %ymm13+ vmovshdup %ymm3, %ymm12 # ymm12 = ymm3[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm3, %ymm3+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm3, %ymm3 # ymm3 = ymm3[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm3, %ymm3 # ymm3 = ymm3[0],ymm12[1],ymm3[2],ymm12[3],ymm3[4],ymm12[5],ymm3[6],ymm12[7]+ vpsubd %ymm3, %ymm5, %ymm12+ vpaddd %ymm3, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm3+ vpsubd %ymm13, %ymm5, %ymm5+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm4, %ymm12+ vpaddd %ymm4, %ymm11, %ymm4+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm4, %ymm4+ vmovdqa 0x380(%rsi), %ymm1+ vmovdqa 0x820(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm8, %ymm13+ vmovshdup %ymm8, %ymm12 # ymm12 = ymm8[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm8, %ymm8+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm8, %ymm8 # ymm8 = ymm8[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm8, %ymm8 # ymm8 = ymm8[0],ymm12[1],ymm8[2],ymm12[3],ymm8[4],ymm12[5],ymm8[6],ymm12[7]+ vpsubd %ymm8, %ymm9, %ymm12+ vpaddd %ymm8, %ymm9, %ymm9+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm8+ vpsubd %ymm13, %ymm9, %ymm9+ vmovdqa 0x400(%rsi), %ymm1+ vmovdqa 0x8a0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm6, %ymm13+ vmovshdup %ymm6, %ymm12 # ymm12 = ymm6[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm6, %ymm6+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm12[1],ymm6[2],ymm12[3],ymm6[4],ymm12[5],ymm6[6],ymm12[7]+ vpsubd %ymm6, %ymm7, %ymm12+ vpaddd %ymm6, %ymm7, %ymm7+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm6+ vpsubd %ymm13, %ymm7, %ymm7+ vmovdqa 0x480(%rsi), %ymm1+ vmovdqa 0x920(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm4, %ymm13+ vmovshdup %ymm4, %ymm12 # ymm12 = ymm4[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm4, %ymm4+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm12[1],ymm4[2],ymm12[3],ymm4[4],ymm12[5],ymm4[6],ymm12[7]+ vpsubd %ymm4, %ymm5, %ymm12+ vpaddd %ymm4, %ymm5, %ymm5+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm4+ vpsubd %ymm13, %ymm5, %ymm5+ vmovdqa 0x500(%rsi), %ymm1+ vmovdqa 0x9a0(%rsi), %ymm2+ vpsrlq $0x20, %ymm1, %ymm10+ vmovshdup %ymm2, %ymm15 # ymm15 = ymm2[1,1,3,3,5,5,7,7]+ vpmuldq %ymm1, %ymm11, %ymm13+ vmovshdup %ymm11, %ymm12 # ymm12 = ymm11[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm12, %ymm14+ vpmuldq %ymm2, %ymm11, %ymm11+ vpmuldq %ymm15, %ymm12, %ymm12+ vpmuldq %ymm0, %ymm13, %ymm13+ vpmuldq %ymm0, %ymm14, %ymm14+ vmovshdup %ymm11, %ymm11 # ymm11 = ymm11[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm12, %ymm11, %ymm11 # ymm11 = ymm11[0],ymm12[1],ymm11[2],ymm12[3],ymm11[4],ymm12[5],ymm11[6],ymm12[7]+ vpsubd %ymm11, %ymm3, %ymm12+ vpaddd %ymm3, %ymm11, %ymm3+ vmovshdup %ymm13, %ymm13 # ymm13 = ymm13[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm14, %ymm13, %ymm13 # ymm13 = ymm13[0],ymm14[1],ymm13[2],ymm14[3],ymm13[4],ymm14[5],ymm13[6],ymm14[7]+ vpaddd %ymm13, %ymm12, %ymm11+ vpsubd %ymm13, %ymm3, %ymm3+ vmovdqa %ymm9, 0x300(%rdi)+ vmovdqa %ymm8, 0x320(%rdi)+ vmovdqa %ymm7, 0x340(%rdi)+ vmovdqa %ymm6, 0x360(%rdi)+ vmovdqa %ymm5, 0x380(%rdi)+ vmovdqa %ymm4, 0x3a0(%rdi)+ vmovdqa %ymm3, 0x3c0(%rdi)+ vmovdqa %ymm11, 0x3e0(%rdi)+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(ntt_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,254 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: nttunpack_avx2_asm+ Description: x86_64 AVX2 NTT coefficient unpacking/permutation+ Signature: void mld_nttunpack_avx2_asm(int32_t *r)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t *r+ description: Input/output polynomial (256 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_nttunpack_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(nttunpack_avx2_asm)+MLD_ASM_FN_SYMBOL(nttunpack_avx2_asm)++ .cfi_startproc+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x20(%rdi), %ymm5+ vmovdqa 0x40(%rdi), %ymm6+ vmovdqa 0x60(%rdi), %ymm7+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm9+ vmovdqa 0xc0(%rdi), %ymm10+ vmovdqa 0xe0(%rdi), %ymm11+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vmovdqa %ymm9, (%rdi)+ vmovdqa %ymm8, 0x20(%rdi)+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm6, 0x60(%rdi)+ vmovdqa %ymm5, 0x80(%rdi)+ vmovdqa %ymm4, 0xa0(%rdi)+ vmovdqa %ymm3, 0xc0(%rdi)+ vmovdqa %ymm11, 0xe0(%rdi)+ vmovdqa 0x100(%rdi), %ymm4+ vmovdqa 0x120(%rdi), %ymm5+ vmovdqa 0x140(%rdi), %ymm6+ vmovdqa 0x160(%rdi), %ymm7+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm9+ vmovdqa 0x1c0(%rdi), %ymm10+ vmovdqa 0x1e0(%rdi), %ymm11+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vmovdqa %ymm9, 0x100(%rdi)+ vmovdqa %ymm8, 0x120(%rdi)+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm6, 0x160(%rdi)+ vmovdqa %ymm5, 0x180(%rdi)+ vmovdqa %ymm4, 0x1a0(%rdi)+ vmovdqa %ymm3, 0x1c0(%rdi)+ vmovdqa %ymm11, 0x1e0(%rdi)+ vmovdqa 0x200(%rdi), %ymm4+ vmovdqa 0x220(%rdi), %ymm5+ vmovdqa 0x240(%rdi), %ymm6+ vmovdqa 0x260(%rdi), %ymm7+ vmovdqa 0x280(%rdi), %ymm8+ vmovdqa 0x2a0(%rdi), %ymm9+ vmovdqa 0x2c0(%rdi), %ymm10+ vmovdqa 0x2e0(%rdi), %ymm11+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vmovdqa %ymm9, 0x200(%rdi)+ vmovdqa %ymm8, 0x220(%rdi)+ vmovdqa %ymm7, 0x240(%rdi)+ vmovdqa %ymm6, 0x260(%rdi)+ vmovdqa %ymm5, 0x280(%rdi)+ vmovdqa %ymm4, 0x2a0(%rdi)+ vmovdqa %ymm3, 0x2c0(%rdi)+ vmovdqa %ymm11, 0x2e0(%rdi)+ vmovdqa 0x300(%rdi), %ymm4+ vmovdqa 0x320(%rdi), %ymm5+ vmovdqa 0x340(%rdi), %ymm6+ vmovdqa 0x360(%rdi), %ymm7+ vmovdqa 0x380(%rdi), %ymm8+ vmovdqa 0x3a0(%rdi), %ymm9+ vmovdqa 0x3c0(%rdi), %ymm10+ vmovdqa 0x3e0(%rdi), %ymm11+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vmovdqa %ymm9, 0x300(%rdi)+ vmovdqa %ymm8, 0x320(%rdi)+ vmovdqa %ymm7, 0x340(%rdi)+ vmovdqa %ymm6, 0x360(%rdi)+ vmovdqa %ymm5, 0x380(%rdi)+ vmovdqa %ymm4, 0x3a0(%rdi)+ vmovdqa %ymm3, 0x3c0(%rdi)+ vmovdqa %ymm11, 0x3e0(%rdi)+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(nttunpack_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,173 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: pointwise_acc_l4_avx2_asm+ Description: x86_64 AVX2 pointwise multiply-accumulate of length-4 polynomial vectors+ Signature: void mld_pointwise_acc_l4_avx2_asm(int32_t *c, const int32_t a[4][256], const int32_t b[4][256], const int32_t *qdata)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *c+ description: Output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 4096+ permissions: read-only+ c_parameter: const int32_t a[4][256]+ description: Input polynomial vector a (4 x 256 x int32_t)+ rdx:+ type: buffer+ size_bytes: 4096+ permissions: read-only+ c_parameter: const int32_t b[4][256]+ description: Input polynomial vector b (4 x 256 x int32_t)+ rcx:+ type: buffer+ size_bytes: 2496+ permissions: read-only+ c_parameter: const int32_t *qdata+ description: Precomputed constants (624 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 4)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_pointwise_acc_l4_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(pointwise_acc_l4_avx2_asm)+MLD_ASM_FN_SYMBOL(pointwise_acc_l4_avx2_asm)++ .cfi_startproc+ vmovdqa 0x20(%rcx), %ymm0+ vmovdqa (%rcx), %ymm1+ xorl %eax, %eax++Lmld_pointwise_acc_l4_avx2_looptop2:+ vmovdqa (%rsi), %ymm6+ vmovdqa 0x20(%rsi), %ymm8+ vmovdqa (%rdx), %ymm10+ vmovdqa 0x20(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vmovdqa %ymm6, %ymm2+ vmovdqa %ymm7, %ymm3+ vmovdqa %ymm8, %ymm4+ vmovdqa %ymm9, %ymm5+ vmovdqa 0x400(%rsi), %ymm6+ vmovdqa 0x420(%rsi), %ymm8+ vmovdqa 0x400(%rdx), %ymm10+ vmovdqa 0x420(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0x800(%rsi), %ymm6+ vmovdqa 0x820(%rsi), %ymm8+ vmovdqa 0x800(%rdx), %ymm10+ vmovdqa 0x820(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0xc00(%rsi), %ymm6+ vmovdqa 0xc20(%rsi), %ymm8+ vmovdqa 0xc00(%rdx), %ymm10+ vmovdqa 0xc20(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vpmuldq %ymm2, %ymm0, %ymm6+ vpmuldq %ymm3, %ymm0, %ymm7+ vpmuldq %ymm4, %ymm0, %ymm8+ vpmuldq %ymm5, %ymm0, %ymm9+ vpmuldq %ymm6, %ymm1, %ymm6+ vpmuldq %ymm7, %ymm1, %ymm7+ vpmuldq %ymm8, %ymm1, %ymm8+ vpmuldq %ymm9, %ymm1, %ymm9+ vpsubq %ymm6, %ymm2, %ymm2+ vpsubq %ymm7, %ymm3, %ymm3+ vpsubq %ymm8, %ymm4, %ymm4+ vpsubq %ymm9, %ymm5, %ymm5+ vpsrlq $0x20, %ymm2, %ymm2+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm3, %ymm2, %ymm2 # ymm2 = ymm2[0],ymm3[1],ymm2[2],ymm3[3],ymm2[4],ymm3[5],ymm2[6],ymm3[7]+ vpblendd $0xaa, %ymm5, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7]+ vmovdqa %ymm2, (%rdi)+ vmovdqa %ymm4, 0x20(%rdi)+ addq $0x40, %rsi+ addq $0x40, %rdx+ addq $0x40, %rdi+ addl $0x1, %eax+ cmpl $0x10, %eax+ jb Lmld_pointwise_acc_l4_avx2_looptop2+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(pointwise_acc_l4_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ && (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 4) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,189 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: pointwise_acc_l5_avx2_asm+ Description: x86_64 AVX2 pointwise multiply-accumulate of length-5 polynomial vectors+ Signature: void mld_pointwise_acc_l5_avx2_asm(int32_t *c, const int32_t a[5][256], const int32_t b[5][256], const int32_t *qdata)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *c+ description: Output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 5120+ permissions: read-only+ c_parameter: const int32_t a[5][256]+ description: Input polynomial vector a (5 x 256 x int32_t)+ rdx:+ type: buffer+ size_bytes: 5120+ permissions: read-only+ c_parameter: const int32_t b[5][256]+ description: Input polynomial vector b (5 x 256 x int32_t)+ rcx:+ type: buffer+ size_bytes: 2496+ permissions: read-only+ c_parameter: const int32_t *qdata+ description: Precomputed constants (624 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 5)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_pointwise_acc_l5_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(pointwise_acc_l5_avx2_asm)+MLD_ASM_FN_SYMBOL(pointwise_acc_l5_avx2_asm)++ .cfi_startproc+ vmovdqa 0x20(%rcx), %ymm0+ vmovdqa (%rcx), %ymm1+ xorl %eax, %eax++Lmld_pointwise_acc_l5_avx2_looptop2:+ vmovdqa (%rsi), %ymm6+ vmovdqa 0x20(%rsi), %ymm8+ vmovdqa (%rdx), %ymm10+ vmovdqa 0x20(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vmovdqa %ymm6, %ymm2+ vmovdqa %ymm7, %ymm3+ vmovdqa %ymm8, %ymm4+ vmovdqa %ymm9, %ymm5+ vmovdqa 0x400(%rsi), %ymm6+ vmovdqa 0x420(%rsi), %ymm8+ vmovdqa 0x400(%rdx), %ymm10+ vmovdqa 0x420(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0x800(%rsi), %ymm6+ vmovdqa 0x820(%rsi), %ymm8+ vmovdqa 0x800(%rdx), %ymm10+ vmovdqa 0x820(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0xc00(%rsi), %ymm6+ vmovdqa 0xc20(%rsi), %ymm8+ vmovdqa 0xc00(%rdx), %ymm10+ vmovdqa 0xc20(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0x1000(%rsi), %ymm6+ vmovdqa 0x1020(%rsi), %ymm8+ vmovdqa 0x1000(%rdx), %ymm10+ vmovdqa 0x1020(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vpmuldq %ymm2, %ymm0, %ymm6+ vpmuldq %ymm3, %ymm0, %ymm7+ vpmuldq %ymm4, %ymm0, %ymm8+ vpmuldq %ymm5, %ymm0, %ymm9+ vpmuldq %ymm6, %ymm1, %ymm6+ vpmuldq %ymm7, %ymm1, %ymm7+ vpmuldq %ymm8, %ymm1, %ymm8+ vpmuldq %ymm9, %ymm1, %ymm9+ vpsubq %ymm6, %ymm2, %ymm2+ vpsubq %ymm7, %ymm3, %ymm3+ vpsubq %ymm8, %ymm4, %ymm4+ vpsubq %ymm9, %ymm5, %ymm5+ vpsrlq $0x20, %ymm2, %ymm2+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm3, %ymm2, %ymm2 # ymm2 = ymm2[0],ymm3[1],ymm2[2],ymm3[3],ymm2[4],ymm3[5],ymm2[6],ymm3[7]+ vpblendd $0xaa, %ymm5, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7]+ vmovdqa %ymm2, (%rdi)+ vmovdqa %ymm4, 0x20(%rdi)+ addq $0x40, %rsi+ addq $0x40, %rdx+ addq $0x40, %rdi+ addl $0x1, %eax+ cmpl $0x10, %eax+ jb Lmld_pointwise_acc_l5_avx2_looptop2+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(pointwise_acc_l5_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ && (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 5) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,221 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: pointwise_acc_l7_avx2_asm+ Description: x86_64 AVX2 pointwise multiply-accumulate of length-7 polynomial vectors+ Signature: void mld_pointwise_acc_l7_avx2_asm(int32_t *c, const int32_t a[7][256], const int32_t b[7][256], const int32_t *qdata)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *c+ description: Output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 7168+ permissions: read-only+ c_parameter: const int32_t a[7][256]+ description: Input polynomial vector a (7 x 256 x int32_t)+ rdx:+ type: buffer+ size_bytes: 7168+ permissions: read-only+ c_parameter: const int32_t b[7][256]+ description: Input polynomial vector b (7 x 256 x int32_t)+ rcx:+ type: buffer+ size_bytes: 2496+ permissions: read-only+ c_parameter: const int32_t *qdata+ description: Precomputed constants (624 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 7)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_pointwise_acc_l7_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(pointwise_acc_l7_avx2_asm)+MLD_ASM_FN_SYMBOL(pointwise_acc_l7_avx2_asm)++ .cfi_startproc+ vmovdqa 0x20(%rcx), %ymm0+ vmovdqa (%rcx), %ymm1+ xorl %eax, %eax++Lmld_pointwise_acc_l7_avx2_looptop2:+ vmovdqa (%rsi), %ymm6+ vmovdqa 0x20(%rsi), %ymm8+ vmovdqa (%rdx), %ymm10+ vmovdqa 0x20(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vmovdqa %ymm6, %ymm2+ vmovdqa %ymm7, %ymm3+ vmovdqa %ymm8, %ymm4+ vmovdqa %ymm9, %ymm5+ vmovdqa 0x400(%rsi), %ymm6+ vmovdqa 0x420(%rsi), %ymm8+ vmovdqa 0x400(%rdx), %ymm10+ vmovdqa 0x420(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0x800(%rsi), %ymm6+ vmovdqa 0x820(%rsi), %ymm8+ vmovdqa 0x800(%rdx), %ymm10+ vmovdqa 0x820(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0xc00(%rsi), %ymm6+ vmovdqa 0xc20(%rsi), %ymm8+ vmovdqa 0xc00(%rdx), %ymm10+ vmovdqa 0xc20(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0x1000(%rsi), %ymm6+ vmovdqa 0x1020(%rsi), %ymm8+ vmovdqa 0x1000(%rdx), %ymm10+ vmovdqa 0x1020(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0x1400(%rsi), %ymm6+ vmovdqa 0x1420(%rsi), %ymm8+ vmovdqa 0x1400(%rdx), %ymm10+ vmovdqa 0x1420(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vmovdqa 0x1800(%rsi), %ymm6+ vmovdqa 0x1820(%rsi), %ymm8+ vmovdqa 0x1800(%rdx), %ymm10+ vmovdqa 0x1820(%rdx), %ymm12+ vpsrlq $0x20, %ymm6, %ymm7+ vpsrlq $0x20, %ymm8, %ymm9+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm6, %ymm6+ vpmuldq %ymm11, %ymm7, %ymm7+ vpmuldq %ymm12, %ymm8, %ymm8+ vpmuldq %ymm13, %ymm9, %ymm9+ vpaddq %ymm2, %ymm6, %ymm2+ vpaddq %ymm3, %ymm7, %ymm3+ vpaddq %ymm4, %ymm8, %ymm4+ vpaddq %ymm5, %ymm9, %ymm5+ vpmuldq %ymm2, %ymm0, %ymm6+ vpmuldq %ymm3, %ymm0, %ymm7+ vpmuldq %ymm4, %ymm0, %ymm8+ vpmuldq %ymm5, %ymm0, %ymm9+ vpmuldq %ymm6, %ymm1, %ymm6+ vpmuldq %ymm7, %ymm1, %ymm7+ vpmuldq %ymm8, %ymm1, %ymm8+ vpmuldq %ymm9, %ymm1, %ymm9+ vpsubq %ymm6, %ymm2, %ymm2+ vpsubq %ymm7, %ymm3, %ymm3+ vpsubq %ymm8, %ymm4, %ymm4+ vpsubq %ymm9, %ymm5, %ymm5+ vpsrlq $0x20, %ymm2, %ymm2+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm3, %ymm2, %ymm2 # ymm2 = ymm2[0],ymm3[1],ymm2[2],ymm3[3],ymm2[4],ymm3[5],ymm2[6],ymm3[7]+ vpblendd $0xaa, %ymm5, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7]+ vmovdqa %ymm2, (%rdi)+ vmovdqa %ymm4, 0x20(%rdi)+ addq $0x40, %rsi+ addq $0x40, %rdx+ addq $0x40, %rdi+ addl $0x1, %eax+ cmpl $0x10, %eax+ jb Lmld_pointwise_acc_l7_avx2_looptop2+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(pointwise_acc_l7_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ && (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLDSA_L == 7) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,158 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: pointwise_avx2_asm+ Description: x86_64 AVX2 pointwise Montgomery multiplication+ Signature: void mld_pointwise_avx2_asm(int32_t *a, const int32_t *b, const int32_t *qdata)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t *a+ description: Input/output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int32_t *b+ description: Input polynomial (256 x int32_t)+ rdx:+ type: buffer+ size_bytes: 2496+ permissions: read-only+ c_parameter: const int32_t *qdata+ description: Precomputed constants (624 x int32_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_pointwise_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(pointwise_avx2_asm)+MLD_ASM_FN_SYMBOL(pointwise_avx2_asm)++ .cfi_startproc+ vmovdqa 0x20(%rdx), %ymm0+ vmovdqa (%rdx), %ymm1+ xorl %eax, %eax++Lmld_pointwise_avx2_looptop1:+ vmovdqa (%rdi), %ymm2+ vmovdqa 0x20(%rdi), %ymm4+ vmovdqa 0x40(%rdi), %ymm6+ vmovdqa (%rsi), %ymm10+ vmovdqa 0x20(%rsi), %ymm12+ vmovdqa 0x40(%rsi), %ymm14+ vpsrlq $0x20, %ymm2, %ymm3+ vpsrlq $0x20, %ymm4, %ymm5+ vmovshdup %ymm6, %ymm7 # ymm7 = ymm6[1,1,3,3,5,5,7,7]+ vpsrlq $0x20, %ymm10, %ymm11+ vpsrlq $0x20, %ymm12, %ymm13+ vmovshdup %ymm14, %ymm15 # ymm15 = ymm14[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm2, %ymm2+ vpmuldq %ymm11, %ymm3, %ymm3+ vpmuldq %ymm12, %ymm4, %ymm4+ vpmuldq %ymm13, %ymm5, %ymm5+ vpmuldq %ymm14, %ymm6, %ymm6+ vpmuldq %ymm15, %ymm7, %ymm7+ vpmuldq %ymm2, %ymm0, %ymm10+ vpmuldq %ymm3, %ymm0, %ymm11+ vpmuldq %ymm4, %ymm0, %ymm12+ vpmuldq %ymm5, %ymm0, %ymm13+ vpmuldq %ymm6, %ymm0, %ymm14+ vpmuldq %ymm7, %ymm0, %ymm15+ vpmuldq %ymm10, %ymm1, %ymm10+ vpmuldq %ymm11, %ymm1, %ymm11+ vpmuldq %ymm12, %ymm1, %ymm12+ vpmuldq %ymm13, %ymm1, %ymm13+ vpmuldq %ymm14, %ymm1, %ymm14+ vpmuldq %ymm15, %ymm1, %ymm15+ vpsubq %ymm10, %ymm2, %ymm2+ vpsubq %ymm11, %ymm3, %ymm3+ vpsubq %ymm12, %ymm4, %ymm4+ vpsubq %ymm13, %ymm5, %ymm5+ vpsubq %ymm14, %ymm6, %ymm6+ vpsubq %ymm15, %ymm7, %ymm7+ vpsrlq $0x20, %ymm2, %ymm2+ vpsrlq $0x20, %ymm4, %ymm4+ vmovshdup %ymm6, %ymm6 # ymm6 = ymm6[1,1,3,3,5,5,7,7]+ vpblendd $0xaa, %ymm3, %ymm2, %ymm2 # ymm2 = ymm2[0],ymm3[1],ymm2[2],ymm3[3],ymm2[4],ymm3[5],ymm2[6],ymm3[7]+ vpblendd $0xaa, %ymm5, %ymm4, %ymm4 # ymm4 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7]+ vpblendd $0xaa, %ymm7, %ymm6, %ymm6 # ymm6 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7]+ vmovdqa %ymm2, (%rdi)+ vmovdqa %ymm4, 0x20(%rdi)+ vmovdqa %ymm6, 0x40(%rdi)+ addq $0x60, %rdi+ addq $0x60, %rsi+ addl $0x1, %eax+ cmpl $0xa, %eax+ jb Lmld_pointwise_avx2_looptop1+ vmovdqa (%rdi), %ymm2+ vmovdqa 0x20(%rdi), %ymm4+ vmovdqa (%rsi), %ymm10+ vmovdqa 0x20(%rsi), %ymm12+ vpsrlq $0x20, %ymm2, %ymm3+ vpsrlq $0x20, %ymm4, %ymm5+ vmovshdup %ymm10, %ymm11 # ymm11 = ymm10[1,1,3,3,5,5,7,7]+ vmovshdup %ymm12, %ymm13 # ymm13 = ymm12[1,1,3,3,5,5,7,7]+ vpmuldq %ymm10, %ymm2, %ymm2+ vpmuldq %ymm11, %ymm3, %ymm3+ vpmuldq %ymm12, %ymm4, %ymm4+ vpmuldq %ymm13, %ymm5, %ymm5+ vpmuldq %ymm2, %ymm0, %ymm10+ vpmuldq %ymm3, %ymm0, %ymm11+ vpmuldq %ymm4, %ymm0, %ymm12+ vpmuldq %ymm5, %ymm0, %ymm13+ vpmuldq %ymm10, %ymm1, %ymm10+ vpmuldq %ymm11, %ymm1, %ymm11+ vpmuldq %ymm12, %ymm1, %ymm12+ vpmuldq %ymm13, %ymm1, %ymm13+ vpsubq %ymm10, %ymm2, %ymm2+ vpsubq %ymm11, %ymm3, %ymm3+ vpsubq %ymm12, %ymm4, %ymm4+ vpsubq %ymm13, %ymm5, %ymm5+ vpsrlq $0x20, %ymm2, %ymm2+ vmovshdup %ymm4, %ymm4 # ymm4 = ymm4[1,1,3,3,5,5,7,7]+ vpblendd $0x55, %ymm2, %ymm3, %ymm2 # ymm2 = ymm2[0],ymm3[1],ymm2[2],ymm3[3],ymm2[4],ymm3[5],ymm2[6],ymm3[7]+ vpblendd $0x55, %ymm4, %ymm5, %ymm4 # ymm4 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7]+ vmovdqa %ymm2, (%rdi)+ vmovdqa %ymm4, 0x20(%rdi)+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(pointwise_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,199 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */+++/*yaml+ Name: poly_caddq_avx2_asm+ Description: x86_64 AVX2 conditional addition of q to each coefficient.+ For all coefficients of the in/out polynomial, add Q if the coefficient+ is negative.+ Signature: void mld_poly_caddq_avx2_asm(int32_t *r)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t *r+ description: Input/output polynomial (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)+++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_poly_caddq_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_caddq_avx2_asm)+MLD_ASM_FN_SYMBOL(poly_caddq_avx2_asm)++ .cfi_startproc+ vpxor %xmm2, %xmm2, %xmm2+ movl $0x7fe001, %eax # imm = 0x7FE001+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ vpcmpgtd (%rdi), %ymm2, %ymm0+ vpand %ymm1, %ymm0, %ymm0+ vpaddd (%rdi), %ymm0, %ymm0+ vmovdqa %ymm0, (%rdi)+ vpcmpgtd 0x20(%rdi), %ymm2, %ymm3+ vpand %ymm1, %ymm3, %ymm3+ vpaddd 0x20(%rdi), %ymm3, %ymm3+ vmovdqa %ymm3, 0x20(%rdi)+ vpcmpgtd 0x40(%rdi), %ymm2, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpaddd 0x40(%rdi), %ymm4, %ymm4+ vmovdqa %ymm4, 0x40(%rdi)+ vpcmpgtd 0x60(%rdi), %ymm2, %ymm5+ vpand %ymm1, %ymm5, %ymm5+ vpaddd 0x60(%rdi), %ymm5, %ymm5+ vmovdqa %ymm5, 0x60(%rdi)+ vpcmpgtd 0x80(%rdi), %ymm2, %ymm0+ vpand %ymm1, %ymm0, %ymm0+ vpaddd 0x80(%rdi), %ymm0, %ymm0+ vmovdqa %ymm0, 0x80(%rdi)+ vpcmpgtd 0xa0(%rdi), %ymm2, %ymm3+ vpand %ymm1, %ymm3, %ymm3+ vpaddd 0xa0(%rdi), %ymm3, %ymm3+ vmovdqa %ymm3, 0xa0(%rdi)+ vpcmpgtd 0xc0(%rdi), %ymm2, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpaddd 0xc0(%rdi), %ymm4, %ymm4+ vmovdqa %ymm4, 0xc0(%rdi)+ vpcmpgtd 0xe0(%rdi), %ymm2, %ymm5+ vpand %ymm1, %ymm5, %ymm5+ vpaddd 0xe0(%rdi), %ymm5, %ymm5+ vmovdqa %ymm5, 0xe0(%rdi)+ vpcmpgtd 0x100(%rdi), %ymm2, %ymm0+ vpand %ymm1, %ymm0, %ymm0+ vpaddd 0x100(%rdi), %ymm0, %ymm0+ vmovdqa %ymm0, 0x100(%rdi)+ vpcmpgtd 0x120(%rdi), %ymm2, %ymm3+ vpand %ymm1, %ymm3, %ymm3+ vpaddd 0x120(%rdi), %ymm3, %ymm3+ vmovdqa %ymm3, 0x120(%rdi)+ vpcmpgtd 0x140(%rdi), %ymm2, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpaddd 0x140(%rdi), %ymm4, %ymm4+ vmovdqa %ymm4, 0x140(%rdi)+ vpcmpgtd 0x160(%rdi), %ymm2, %ymm5+ vpand %ymm1, %ymm5, %ymm5+ vpaddd 0x160(%rdi), %ymm5, %ymm5+ vmovdqa %ymm5, 0x160(%rdi)+ vpcmpgtd 0x180(%rdi), %ymm2, %ymm0+ vpand %ymm1, %ymm0, %ymm0+ vpaddd 0x180(%rdi), %ymm0, %ymm0+ vmovdqa %ymm0, 0x180(%rdi)+ vpcmpgtd 0x1a0(%rdi), %ymm2, %ymm3+ vpand %ymm1, %ymm3, %ymm3+ vpaddd 0x1a0(%rdi), %ymm3, %ymm3+ vmovdqa %ymm3, 0x1a0(%rdi)+ vpcmpgtd 0x1c0(%rdi), %ymm2, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpaddd 0x1c0(%rdi), %ymm4, %ymm4+ vmovdqa %ymm4, 0x1c0(%rdi)+ vpcmpgtd 0x1e0(%rdi), %ymm2, %ymm5+ vpand %ymm1, %ymm5, %ymm5+ vpaddd 0x1e0(%rdi), %ymm5, %ymm5+ vmovdqa %ymm5, 0x1e0(%rdi)+ vpcmpgtd 0x200(%rdi), %ymm2, %ymm0+ vpand %ymm1, %ymm0, %ymm0+ vpaddd 0x200(%rdi), %ymm0, %ymm0+ vmovdqa %ymm0, 0x200(%rdi)+ vpcmpgtd 0x220(%rdi), %ymm2, %ymm3+ vpand %ymm1, %ymm3, %ymm3+ vpaddd 0x220(%rdi), %ymm3, %ymm3+ vmovdqa %ymm3, 0x220(%rdi)+ vpcmpgtd 0x240(%rdi), %ymm2, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpaddd 0x240(%rdi), %ymm4, %ymm4+ vmovdqa %ymm4, 0x240(%rdi)+ vpcmpgtd 0x260(%rdi), %ymm2, %ymm5+ vpand %ymm1, %ymm5, %ymm5+ vpaddd 0x260(%rdi), %ymm5, %ymm5+ vmovdqa %ymm5, 0x260(%rdi)+ vpcmpgtd 0x280(%rdi), %ymm2, %ymm0+ vpand %ymm1, %ymm0, %ymm0+ vpaddd 0x280(%rdi), %ymm0, %ymm0+ vmovdqa %ymm0, 0x280(%rdi)+ vpcmpgtd 0x2a0(%rdi), %ymm2, %ymm3+ vpand %ymm1, %ymm3, %ymm3+ vpaddd 0x2a0(%rdi), %ymm3, %ymm3+ vmovdqa %ymm3, 0x2a0(%rdi)+ vpcmpgtd 0x2c0(%rdi), %ymm2, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpaddd 0x2c0(%rdi), %ymm4, %ymm4+ vmovdqa %ymm4, 0x2c0(%rdi)+ vpcmpgtd 0x2e0(%rdi), %ymm2, %ymm5+ vpand %ymm1, %ymm5, %ymm5+ vpaddd 0x2e0(%rdi), %ymm5, %ymm5+ vmovdqa %ymm5, 0x2e0(%rdi)+ vpcmpgtd 0x300(%rdi), %ymm2, %ymm0+ vpand %ymm1, %ymm0, %ymm0+ vpaddd 0x300(%rdi), %ymm0, %ymm0+ vmovdqa %ymm0, 0x300(%rdi)+ vpcmpgtd 0x320(%rdi), %ymm2, %ymm3+ vpand %ymm1, %ymm3, %ymm3+ vpaddd 0x320(%rdi), %ymm3, %ymm3+ vmovdqa %ymm3, 0x320(%rdi)+ vpcmpgtd 0x340(%rdi), %ymm2, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpaddd 0x340(%rdi), %ymm4, %ymm4+ vmovdqa %ymm4, 0x340(%rdi)+ vpcmpgtd 0x360(%rdi), %ymm2, %ymm5+ vpand %ymm1, %ymm5, %ymm5+ vpaddd 0x360(%rdi), %ymm5, %ymm5+ vmovdqa %ymm5, 0x360(%rdi)+ vpcmpgtd 0x380(%rdi), %ymm2, %ymm0+ vpand %ymm1, %ymm0, %ymm0+ vpaddd 0x380(%rdi), %ymm0, %ymm0+ vmovdqa %ymm0, 0x380(%rdi)+ vpcmpgtd 0x3a0(%rdi), %ymm2, %ymm3+ vpand %ymm1, %ymm3, %ymm3+ vpaddd 0x3a0(%rdi), %ymm3, %ymm3+ vmovdqa %ymm3, 0x3a0(%rdi)+ vpcmpgtd 0x3c0(%rdi), %ymm2, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpaddd 0x3c0(%rdi), %ymm4, %ymm4+ vmovdqa %ymm4, 0x3c0(%rdi)+ vpcmpgtd 0x3e0(%rdi), %ymm2, %ymm5+ vpand %ymm1, %ymm5, %ymm5+ vpaddd 0x3e0(%rdi), %ymm5, %ymm5+ vmovdqa %ymm5, 0x3e0(%rdi)+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_caddq_avx2_asm)+++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,176 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */+++/*yaml+ Name: poly_chknorm_avx2_asm+ Description: x86_64 AVX2 infinity-norm bound check on polynomial coefficients.+ Check the infinity norm of the polynomial against the given bound B.+ Returns 0 if the norm is strictly smaller than B; otherwise returns 1+ (i.e. returns 1 if any |coefficient| >= B, 0 otherwise).+ Signature: int mld_poly_chknorm_avx2_asm(const int32_t *a, int32_t B)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int32_t *a+ description: Input polynomial (256 x int32_t)+ rsi:+ type: scalar+ c_parameter: int32_t B+ description: Norm bound (must be non-negative)+ test_with: 131072 # representative non-negative bound (1 << 17)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)+++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_poly_chknorm_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_chknorm_avx2_asm)+MLD_ASM_FN_SYMBOL(poly_chknorm_avx2_asm)++ .cfi_startproc+ subl $0x1, %esi+ vpxor %xmm1, %xmm1, %xmm1+ vmovd %esi, %xmm2+ vpbroadcastd %xmm2, %ymm2+ vpabsd (%rdi), %ymm0+ vpcmpgtd %ymm2, %ymm0, %ymm0+ vpor %ymm0, %ymm1, %ymm1+ vpabsd 0x20(%rdi), %ymm3+ vpcmpgtd %ymm2, %ymm3, %ymm3+ vpor %ymm3, %ymm1, %ymm1+ vpabsd 0x40(%rdi), %ymm4+ vpcmpgtd %ymm2, %ymm4, %ymm4+ vpor %ymm4, %ymm1, %ymm1+ vpabsd 0x60(%rdi), %ymm5+ vpcmpgtd %ymm2, %ymm5, %ymm5+ vpor %ymm5, %ymm1, %ymm1+ vpabsd 0x80(%rdi), %ymm0+ vpcmpgtd %ymm2, %ymm0, %ymm0+ vpor %ymm0, %ymm1, %ymm1+ vpabsd 0xa0(%rdi), %ymm3+ vpcmpgtd %ymm2, %ymm3, %ymm3+ vpor %ymm3, %ymm1, %ymm1+ vpabsd 0xc0(%rdi), %ymm4+ vpcmpgtd %ymm2, %ymm4, %ymm4+ vpor %ymm4, %ymm1, %ymm1+ vpabsd 0xe0(%rdi), %ymm5+ vpcmpgtd %ymm2, %ymm5, %ymm5+ vpor %ymm5, %ymm1, %ymm1+ vpabsd 0x100(%rdi), %ymm0+ vpcmpgtd %ymm2, %ymm0, %ymm0+ vpor %ymm0, %ymm1, %ymm1+ vpabsd 0x120(%rdi), %ymm3+ vpcmpgtd %ymm2, %ymm3, %ymm3+ vpor %ymm3, %ymm1, %ymm1+ vpabsd 0x140(%rdi), %ymm4+ vpcmpgtd %ymm2, %ymm4, %ymm4+ vpor %ymm4, %ymm1, %ymm1+ vpabsd 0x160(%rdi), %ymm5+ vpcmpgtd %ymm2, %ymm5, %ymm5+ vpor %ymm5, %ymm1, %ymm1+ vpabsd 0x180(%rdi), %ymm0+ vpcmpgtd %ymm2, %ymm0, %ymm0+ vpor %ymm0, %ymm1, %ymm1+ vpabsd 0x1a0(%rdi), %ymm3+ vpcmpgtd %ymm2, %ymm3, %ymm3+ vpor %ymm3, %ymm1, %ymm1+ vpabsd 0x1c0(%rdi), %ymm4+ vpcmpgtd %ymm2, %ymm4, %ymm4+ vpor %ymm4, %ymm1, %ymm1+ vpabsd 0x1e0(%rdi), %ymm5+ vpcmpgtd %ymm2, %ymm5, %ymm5+ vpor %ymm5, %ymm1, %ymm1+ vpabsd 0x200(%rdi), %ymm0+ vpcmpgtd %ymm2, %ymm0, %ymm0+ vpor %ymm0, %ymm1, %ymm1+ vpabsd 0x220(%rdi), %ymm3+ vpcmpgtd %ymm2, %ymm3, %ymm3+ vpor %ymm3, %ymm1, %ymm1+ vpabsd 0x240(%rdi), %ymm4+ vpcmpgtd %ymm2, %ymm4, %ymm4+ vpor %ymm4, %ymm1, %ymm1+ vpabsd 0x260(%rdi), %ymm5+ vpcmpgtd %ymm2, %ymm5, %ymm5+ vpor %ymm5, %ymm1, %ymm1+ vpabsd 0x280(%rdi), %ymm0+ vpcmpgtd %ymm2, %ymm0, %ymm0+ vpor %ymm0, %ymm1, %ymm1+ vpabsd 0x2a0(%rdi), %ymm3+ vpcmpgtd %ymm2, %ymm3, %ymm3+ vpor %ymm3, %ymm1, %ymm1+ vpabsd 0x2c0(%rdi), %ymm4+ vpcmpgtd %ymm2, %ymm4, %ymm4+ vpor %ymm4, %ymm1, %ymm1+ vpabsd 0x2e0(%rdi), %ymm5+ vpcmpgtd %ymm2, %ymm5, %ymm5+ vpor %ymm5, %ymm1, %ymm1+ vpabsd 0x300(%rdi), %ymm0+ vpcmpgtd %ymm2, %ymm0, %ymm0+ vpor %ymm0, %ymm1, %ymm1+ vpabsd 0x320(%rdi), %ymm3+ vpcmpgtd %ymm2, %ymm3, %ymm3+ vpor %ymm3, %ymm1, %ymm1+ vpabsd 0x340(%rdi), %ymm4+ vpcmpgtd %ymm2, %ymm4, %ymm4+ vpor %ymm4, %ymm1, %ymm1+ vpabsd 0x360(%rdi), %ymm5+ vpcmpgtd %ymm2, %ymm5, %ymm5+ vpor %ymm5, %ymm1, %ymm1+ vpabsd 0x380(%rdi), %ymm0+ vpcmpgtd %ymm2, %ymm0, %ymm0+ vpor %ymm0, %ymm1, %ymm1+ vpabsd 0x3a0(%rdi), %ymm3+ vpcmpgtd %ymm2, %ymm3, %ymm3+ vpor %ymm3, %ymm1, %ymm1+ vpabsd 0x3c0(%rdi), %ymm4+ vpcmpgtd %ymm2, %ymm4, %ymm4+ vpor %ymm4, %ymm1, %ymm1+ vpabsd 0x3e0(%rdi), %ymm5+ vpcmpgtd %ymm2, %ymm5, %ymm5+ vpor %ymm5, %ymm1, %ymm1+ xorl %eax, %eax+ vptest %ymm1, %ymm1+ setne %al+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_chknorm_avx2_asm)+++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,490 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ *+ * The algorithm for Decompose(r) (more specifically the handling for the+ * wrap-around cases) is modified. See the AVX2 intrinsics version+ * (poly_decompose_32_avx2.c, predecessor of this file) for a more detailed+ * comparison.+ */+++/*yaml+ Name: poly_decompose_32_avx2_asm+ Description: x86_64 AVX2 coefficient decomposition (alpha = 2*(Q-1)/32).+ For all coefficients c of the input polynomial, compute high and low bits+ c0, c1 such that c = c1*ALPHA + c0 with -ALPHA/2 < c0 <= ALPHA/2, except if+ c1 = (Q-1)/ALPHA where we set c1 = 0 and -ALPHA/2 <= c0 = c - Q < 0.+ Assumes coefficients to be standard (unsigned canonical) representatives,+ i.e. 0 <= c < Q. For ML-DSA-65 / ML-DSA-87 (gamma2 = (Q-1)/32,+ alpha = 2*gamma2).+ Signature: void mld_poly_decompose_32_avx2_asm(int32_t *a1, int32_t *a0)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *a1+ description: Output high-part polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t *a0+ description: Input polynomial / output low-part (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_NO_SIGN_API) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87))+++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_poly_decompose_32_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_decompose_32_avx2_asm)+MLD_ASM_FN_SYMBOL(poly_decompose_32_avx2_asm)++ .cfi_startproc+ movl $0x7f, %eax+ vmovd %eax, %xmm10+ vpbroadcastd %xmm10, %ymm10+ movl $0x401, %eax # imm = 0x401+ vmovd %eax, %xmm11+ vpbroadcastd %xmm11, %ymm11+ movl $0x200, %eax # imm = 0x200+ vmovd %eax, %xmm12+ vpbroadcastd %xmm12, %ymm12+ movl $0x7be100, %eax # imm = 0x7BE100+ vmovd %eax, %xmm13+ vpbroadcastd %xmm13, %ymm13+ movl $0x7fe00, %eax # imm = 0x7FE00+ vmovd %eax, %xmm14+ vpbroadcastd %xmm14, %ymm14+ vmovdqa (%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, (%rdi)+ vmovdqa %ymm2, (%rsi)+ vmovdqa 0x20(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x20(%rdi)+ vmovdqa %ymm2, 0x20(%rsi)+ vmovdqa 0x40(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x40(%rdi)+ vmovdqa %ymm2, 0x40(%rsi)+ vmovdqa 0x60(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x60(%rdi)+ vmovdqa %ymm2, 0x60(%rsi)+ vmovdqa 0x80(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x80(%rdi)+ vmovdqa %ymm2, 0x80(%rsi)+ vmovdqa 0xa0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0xa0(%rdi)+ vmovdqa %ymm2, 0xa0(%rsi)+ vmovdqa 0xc0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0xc0(%rdi)+ vmovdqa %ymm2, 0xc0(%rsi)+ vmovdqa 0xe0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0xe0(%rdi)+ vmovdqa %ymm2, 0xe0(%rsi)+ vmovdqa 0x100(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x100(%rdi)+ vmovdqa %ymm2, 0x100(%rsi)+ vmovdqa 0x120(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x120(%rdi)+ vmovdqa %ymm2, 0x120(%rsi)+ vmovdqa 0x140(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x140(%rdi)+ vmovdqa %ymm2, 0x140(%rsi)+ vmovdqa 0x160(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x160(%rdi)+ vmovdqa %ymm2, 0x160(%rsi)+ vmovdqa 0x180(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x180(%rdi)+ vmovdqa %ymm2, 0x180(%rsi)+ vmovdqa 0x1a0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x1a0(%rdi)+ vmovdqa %ymm2, 0x1a0(%rsi)+ vmovdqa 0x1c0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x1c0(%rdi)+ vmovdqa %ymm2, 0x1c0(%rsi)+ vmovdqa 0x1e0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x1e0(%rdi)+ vmovdqa %ymm2, 0x1e0(%rsi)+ vmovdqa 0x200(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x200(%rdi)+ vmovdqa %ymm2, 0x200(%rsi)+ vmovdqa 0x220(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x220(%rdi)+ vmovdqa %ymm2, 0x220(%rsi)+ vmovdqa 0x240(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x240(%rdi)+ vmovdqa %ymm2, 0x240(%rsi)+ vmovdqa 0x260(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x260(%rdi)+ vmovdqa %ymm2, 0x260(%rsi)+ vmovdqa 0x280(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x280(%rdi)+ vmovdqa %ymm2, 0x280(%rsi)+ vmovdqa 0x2a0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x2a0(%rdi)+ vmovdqa %ymm2, 0x2a0(%rsi)+ vmovdqa 0x2c0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x2c0(%rdi)+ vmovdqa %ymm2, 0x2c0(%rsi)+ vmovdqa 0x2e0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x2e0(%rdi)+ vmovdqa %ymm2, 0x2e0(%rsi)+ vmovdqa 0x300(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x300(%rdi)+ vmovdqa %ymm2, 0x300(%rsi)+ vmovdqa 0x320(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x320(%rdi)+ vmovdqa %ymm2, 0x320(%rsi)+ vmovdqa 0x340(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x340(%rdi)+ vmovdqa %ymm2, 0x340(%rsi)+ vmovdqa 0x360(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x360(%rdi)+ vmovdqa %ymm2, 0x360(%rsi)+ vmovdqa 0x380(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x380(%rdi)+ vmovdqa %ymm2, 0x380(%rsi)+ vmovdqa 0x3a0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x3a0(%rdi)+ vmovdqa %ymm2, 0x3a0(%rsi)+ vmovdqa 0x3c0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x3c0(%rdi)+ vmovdqa %ymm2, 0x3c0(%rsi)+ vmovdqa 0x3e0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x3e0(%rdi)+ vmovdqa %ymm2, 0x3e0(%rsi)+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_decompose_32_avx2_asm)+++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_NO_SIGN_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,489 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ *+ * The algorithm for Decompose(r) (more specifically the handling for the+ * wrap-around cases) is modified. See the AVX2 intrinsics version+ * (poly_decompose_88_avx2.c, predecessor of this file) for a more detailed+ * comparison.+ */+++/*yaml+ Name: poly_decompose_88_avx2_asm+ Description: x86_64 AVX2 coefficient decomposition (alpha = 2*(Q-1)/88).+ For all coefficients c of the input polynomial, compute high and low bits+ c0, c1 such that c = c1*ALPHA + c0 with -ALPHA/2 < c0 <= ALPHA/2, except if+ c1 = (Q-1)/ALPHA where we set c1 = 0 and -ALPHA/2 <= c0 = c - Q < 0.+ Assumes coefficients to be standard (unsigned canonical) representatives,+ i.e. 0 <= c < Q. For ML-DSA-44 (gamma2 = (Q-1)/88, alpha = 2*gamma2).+ Signature: void mld_poly_decompose_88_avx2_asm(int32_t *a1, int32_t *a0)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *a1+ description: Output high-part polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t *a0+ description: Input polynomial / output low-part (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_NO_SIGN_API) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ MLD_CONFIG_PARAMETER_SET == 44)+++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_poly_decompose_88_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_decompose_88_avx2_asm)+MLD_ASM_FN_SYMBOL(poly_decompose_88_avx2_asm)++ .cfi_startproc+ movl $0x7f, %eax+ vmovd %eax, %xmm10+ vpbroadcastd %xmm10, %ymm10+ movl $0x2c0b, %eax # imm = 0x2C0B+ vmovd %eax, %xmm11+ vpbroadcastd %xmm11, %ymm11+ movl $0x80, %eax+ vmovd %eax, %xmm12+ vpbroadcastd %xmm12, %ymm12+ movl $0x7e6c00, %eax # imm = 0x7E6C00+ vmovd %eax, %xmm13+ vpbroadcastd %xmm13, %ymm13+ movl $0x2e800, %eax # imm = 0x2E800+ vmovd %eax, %xmm14+ vpbroadcastd %xmm14, %ymm14+ vmovdqa (%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, (%rdi)+ vmovdqa %ymm2, (%rsi)+ vmovdqa 0x20(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x20(%rdi)+ vmovdqa %ymm2, 0x20(%rsi)+ vmovdqa 0x40(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x40(%rdi)+ vmovdqa %ymm2, 0x40(%rsi)+ vmovdqa 0x60(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x60(%rdi)+ vmovdqa %ymm2, 0x60(%rsi)+ vmovdqa 0x80(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x80(%rdi)+ vmovdqa %ymm2, 0x80(%rsi)+ vmovdqa 0xa0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0xa0(%rdi)+ vmovdqa %ymm2, 0xa0(%rsi)+ vmovdqa 0xc0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0xc0(%rdi)+ vmovdqa %ymm2, 0xc0(%rsi)+ vmovdqa 0xe0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0xe0(%rdi)+ vmovdqa %ymm2, 0xe0(%rsi)+ vmovdqa 0x100(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x100(%rdi)+ vmovdqa %ymm2, 0x100(%rsi)+ vmovdqa 0x120(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x120(%rdi)+ vmovdqa %ymm2, 0x120(%rsi)+ vmovdqa 0x140(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x140(%rdi)+ vmovdqa %ymm2, 0x140(%rsi)+ vmovdqa 0x160(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x160(%rdi)+ vmovdqa %ymm2, 0x160(%rsi)+ vmovdqa 0x180(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x180(%rdi)+ vmovdqa %ymm2, 0x180(%rsi)+ vmovdqa 0x1a0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x1a0(%rdi)+ vmovdqa %ymm2, 0x1a0(%rsi)+ vmovdqa 0x1c0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x1c0(%rdi)+ vmovdqa %ymm2, 0x1c0(%rsi)+ vmovdqa 0x1e0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x1e0(%rdi)+ vmovdqa %ymm2, 0x1e0(%rsi)+ vmovdqa 0x200(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x200(%rdi)+ vmovdqa %ymm2, 0x200(%rsi)+ vmovdqa 0x220(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x220(%rdi)+ vmovdqa %ymm2, 0x220(%rsi)+ vmovdqa 0x240(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x240(%rdi)+ vmovdqa %ymm2, 0x240(%rsi)+ vmovdqa 0x260(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x260(%rdi)+ vmovdqa %ymm2, 0x260(%rsi)+ vmovdqa 0x280(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x280(%rdi)+ vmovdqa %ymm2, 0x280(%rsi)+ vmovdqa 0x2a0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x2a0(%rdi)+ vmovdqa %ymm2, 0x2a0(%rsi)+ vmovdqa 0x2c0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x2c0(%rdi)+ vmovdqa %ymm2, 0x2c0(%rsi)+ vmovdqa 0x2e0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x2e0(%rdi)+ vmovdqa %ymm2, 0x2e0(%rsi)+ vmovdqa 0x300(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x300(%rdi)+ vmovdqa %ymm2, 0x300(%rsi)+ vmovdqa 0x320(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x320(%rdi)+ vmovdqa %ymm2, 0x320(%rsi)+ vmovdqa 0x340(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x340(%rdi)+ vmovdqa %ymm2, 0x340(%rsi)+ vmovdqa 0x360(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x360(%rdi)+ vmovdqa %ymm2, 0x360(%rsi)+ vmovdqa 0x380(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x380(%rdi)+ vmovdqa %ymm2, 0x380(%rsi)+ vmovdqa 0x3a0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x3a0(%rdi)+ vmovdqa %ymm2, 0x3a0(%rsi)+ vmovdqa 0x3c0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x3c0(%rdi)+ vmovdqa %ymm2, 0x3c0(%rsi)+ vmovdqa 0x3e0(%rsi), %ymm0+ vpaddd %ymm10, %ymm0, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm11, %ymm1, %ymm1+ vpmulhrsw %ymm12, %ymm1, %ymm1+ vpcmpgtd %ymm13, %ymm0, %ymm3+ vpmulld %ymm14, %ymm1, %ymm2+ vpsubd %ymm2, %ymm0, %ymm2+ vpandn %ymm1, %ymm3, %ymm1+ vpaddd %ymm3, %ymm2, %ymm2+ vmovdqa %ymm1, 0x3e0(%rdi)+ vmovdqa %ymm2, 0x3e0(%rsi)+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_decompose_88_avx2_asm)+++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_NO_SIGN_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44) \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,123 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */+++/*yaml+ Name: poly_use_hint_32_avx2_asm+ Description: x86_64 AVX2 hint application (alpha = (Q-1)/32).+ Use the hint polynomial h to correct the high bits of the polynomial a,+ in place. Variant for parameter sets ML-DSA-65 and ML-DSA-87+ (GAMMA2 = (Q-1)/32).+ Signature: void mld_poly_use_hint_32_avx2_asm(int32_t *a, const int32_t *h)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t *a+ description: Input/output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int32_t *h+ description: Hint polynomial (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_NO_VERIFY_API) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87))+++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_poly_use_hint_32_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_use_hint_32_avx2_asm)+MLD_ASM_FN_SYMBOL(poly_use_hint_32_avx2_asm)++ .cfi_startproc+ movl $0x7f, %ecx+ movl $0x401, %r8d # imm = 0x401+ vmovd %r8d, %xmm8+ vpbroadcastd %xmm8, %ymm8+ xorl %eax, %eax+ vpxor %xmm6, %xmm6, %xmm6+ vmovd %ecx, %xmm5+ movl $0x7be100, %ecx # imm = 0x7BE100+ movl $0x200, %r9d # imm = 0x200+ vmovd %r9d, %xmm7+ vpbroadcastd %xmm7, %ymm7+ vmovd %ecx, %xmm4+ movl $0xf, %ecx+ vpbroadcastd %xmm5, %ymm5+ vmovd %ecx, %xmm3+ vpbroadcastd %xmm4, %ymm4+ vpbroadcastd %xmm3, %ymm3++Lmld_poly_use_hint_32_avx2_asm_loop:+ vmovdqa (%rdi), %ymm0+ vmovdqa (%rsi), %ymm2+ vpaddd %ymm0, %ymm5, %ymm1+ vpsrld $0x7, %ymm1, %ymm1+ vpmulhuw %ymm8, %ymm1, %ymm1+ vpmulhrsw %ymm7, %ymm1, %ymm1+ vpcmpgtd %ymm4, %ymm0, %ymm11+ vpandn %ymm1, %ymm11, %ymm9+ vpslld $0xa, %ymm1, %ymm10+ vpsubd %ymm1, %ymm10, %ymm1+ vpslld $0x9, %ymm1, %ymm1+ vpsubd %ymm1, %ymm0, %ymm0+ vpaddd %ymm11, %ymm0, %ymm0+ vpcmpgtd %ymm6, %ymm0, %ymm0+ vpandn %ymm2, %ymm0, %ymm0+ vpslld $0x1, %ymm0, %ymm0+ vpsubd %ymm0, %ymm2, %ymm2+ vpaddd %ymm9, %ymm2, %ymm2+ vpand %ymm3, %ymm2, %ymm2+ vmovdqa %ymm2, (%rdi)+ addq $0x20, %rdi+ addq $0x20, %rsi+ addq $0x20, %rax+ cmpq $0x400, %rax # imm = 0x400+ jne Lmld_poly_use_hint_32_avx2_asm_loop+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_use_hint_32_avx2_asm)+++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_NO_VERIFY_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,125 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */+++/*yaml+ Name: poly_use_hint_88_avx2_asm+ Description: x86_64 AVX2 hint application (alpha = (Q-1)/88).+ Use the hint polynomial h to correct the high bits of the polynomial a,+ in place. Variant for parameter set ML-DSA-44 (GAMMA2 = (Q-1)/88).+ Signature: void mld_poly_use_hint_88_avx2_asm(int32_t *a, const int32_t *h)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: read/write+ c_parameter: int32_t *a+ description: Input/output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int32_t *h+ description: Hint polynomial (256 x int32_t)+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_NO_VERIFY_API) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ MLD_CONFIG_PARAMETER_SET == 44)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_poly_use_hint_88_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(poly_use_hint_88_avx2_asm)+MLD_ASM_FN_SYMBOL(poly_use_hint_88_avx2_asm)++ .cfi_startproc+ movl $0x7f, %ecx+ xorl %eax, %eax+ vpxor %xmm5, %xmm5, %xmm5+ movl $0x2c0b, %r8d # imm = 0x2C0B+ vmovd %r8d, %xmm8+ vpbroadcastd %xmm8, %ymm8+ vmovd %ecx, %xmm4+ movl $0x7e6c00, %ecx # imm = 0x7E6C00+ movl $0x80, %r9d+ vmovd %r9d, %xmm7+ vpbroadcastd %xmm7, %ymm7+ movl $0x2b, %r10d+ vmovd %r10d, %xmm6+ vpbroadcastd %xmm6, %ymm6+ vmovd %ecx, %xmm3+ vpbroadcastd %xmm4, %ymm4+ vpbroadcastd %xmm3, %ymm3++Lmld_poly_use_hint_88_avx2_asm_loop:+ vmovdqa (%rdi), %ymm0+ vmovdqa (%rsi), %ymm1+ vpaddd %ymm0, %ymm4, %ymm10+ vpsrld $0x7, %ymm10, %ymm10+ vpmulhuw %ymm8, %ymm10, %ymm10+ vpmulhrsw %ymm7, %ymm10, %ymm10+ vpcmpgtd %ymm3, %ymm0, %ymm11+ vpandn %ymm10, %ymm11, %ymm9+ vpslld $0x1, %ymm10, %ymm12+ vpaddd %ymm10, %ymm12, %ymm12+ vpslld $0x5, %ymm12, %ymm10+ vpsubd %ymm12, %ymm10, %ymm10+ vpslld $0xb, %ymm10, %ymm10+ vpsubd %ymm10, %ymm0, %ymm0+ vpaddd %ymm11, %ymm0, %ymm0+ vpcmpgtd %ymm5, %ymm0, %ymm0+ vpandn %ymm1, %ymm0, %ymm0+ vpslld $0x1, %ymm0, %ymm0+ vpsubd %ymm0, %ymm1, %ymm0+ vpaddd %ymm9, %ymm0, %ymm0+ vpblendvb %ymm0, %ymm6, %ymm0, %ymm0+ vpcmpgtd %ymm6, %ymm0, %ymm1+ vpandn %ymm0, %ymm1, %ymm0+ vmovdqa %ymm0, (%rdi)+ addq $0x20, %rdi+ addq $0x20, %rsi+ addq $0x20, %rax+ cmpq $0x400, %rax # imm = 0x400+ jne Lmld_poly_use_hint_88_avx2_asm_loop+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(poly_use_hint_88_avx2_asm)+++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_NO_VERIFY_API && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44) \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,355 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */+++/*yaml+ Name: polyz_unpack_17_avx2_asm+ Description: x86_64 AVX2 unpacking of 17-bit packed coefficients.+ Unpack polynomial z with 18-bit packed coefficients (GAMMA1 = 2^17),+ mapping packed [0, 2^18-1] to signed [-(2^17-1), 2^17] via GAMMA1 - x.+ Signature: void mld_polyz_unpack_17_avx2_asm(int32_t *r, const uint8_t *a)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *r+ description: Output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 576+ permissions: read-only+ c_parameter: const uint8_t *a+ description: Packed input bytes+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ (!defined(MLD_CONFIG_NO_SIGN_API) || \+ !defined(MLD_CONFIG_NO_VERIFY_API)) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ MLD_CONFIG_PARAMETER_SET == 44)+++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_polyz_unpack_17_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(polyz_unpack_17_avx2_asm)+MLD_ASM_FN_SYMBOL(polyz_unpack_17_avx2_asm)++ .cfi_startproc+ movabsq $-0xfbfcfd00fdff00, %rax # imm = 0xFF040302FF020100+ vmovq %rax, %xmm1+ movabsq $-0xf7f8f900f9fafc, %rax # imm = 0xFF080706FF060504+ vpinsrq $0x1, %rax, %xmm1, %xmm1+ movabsq $-0xe4e5e600e6e7e9, %rax # imm = 0xFF1B1A19FF191817+ vmovq %rax, %xmm5+ movabsq $-0xe0e1e200e2e3e5, %rax # imm = 0xFF1F1E1DFF1D1C1B+ vpinsrq $0x1, %rax, %xmm5, %xmm5+ vinserti128 $0x1, %xmm5, %ymm1, %ymm1+ movabsq $0x200000000, %rax # imm = 0x200000000+ vmovq %rax, %xmm2+ movabsq $0x600000004, %rax # imm = 0x600000004+ vpinsrq $0x1, %rax, %xmm2, %xmm2+ vinserti128 $0x1, %xmm2, %ymm2, %ymm2+ movl $0x3ffff, %eax # imm = 0x3FFFF+ vmovd %eax, %xmm3+ vpbroadcastd %xmm3, %ymm3+ movl $0x20000, %eax # imm = 0x20000+ vmovd %eax, %xmm4+ vpbroadcastd %xmm4, %ymm4+ vmovdqu (%rsi), %xmm0+ vmovdqu 0x2(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, (%rdi)+ vmovdqu 0x12(%rsi), %xmm0+ vmovdqu 0x14(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x20(%rdi)+ vmovdqu 0x24(%rsi), %xmm0+ vmovdqu 0x26(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x40(%rdi)+ vmovdqu 0x36(%rsi), %xmm0+ vmovdqu 0x38(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x60(%rdi)+ vmovdqu 0x48(%rsi), %xmm0+ vmovdqu 0x4a(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x80(%rdi)+ vmovdqu 0x5a(%rsi), %xmm0+ vmovdqu 0x5c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0xa0(%rdi)+ vmovdqu 0x6c(%rsi), %xmm0+ vmovdqu 0x6e(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0xc0(%rdi)+ vmovdqu 0x7e(%rsi), %xmm0+ vmovdqu 0x80(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0xe0(%rdi)+ vmovdqu 0x90(%rsi), %xmm0+ vmovdqu 0x92(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x100(%rdi)+ vmovdqu 0xa2(%rsi), %xmm0+ vmovdqu 0xa4(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x120(%rdi)+ vmovdqu 0xb4(%rsi), %xmm0+ vmovdqu 0xb6(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x140(%rdi)+ vmovdqu 0xc6(%rsi), %xmm0+ vmovdqu 0xc8(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x160(%rdi)+ vmovdqu 0xd8(%rsi), %xmm0+ vmovdqu 0xda(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x180(%rdi)+ vmovdqu 0xea(%rsi), %xmm0+ vmovdqu 0xec(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x1a0(%rdi)+ vmovdqu 0xfc(%rsi), %xmm0+ vmovdqu 0xfe(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x1c0(%rdi)+ vmovdqu 0x10e(%rsi), %xmm0+ vmovdqu 0x110(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x1e0(%rdi)+ vmovdqu 0x120(%rsi), %xmm0+ vmovdqu 0x122(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x200(%rdi)+ vmovdqu 0x132(%rsi), %xmm0+ vmovdqu 0x134(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x220(%rdi)+ vmovdqu 0x144(%rsi), %xmm0+ vmovdqu 0x146(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x240(%rdi)+ vmovdqu 0x156(%rsi), %xmm0+ vmovdqu 0x158(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x260(%rdi)+ vmovdqu 0x168(%rsi), %xmm0+ vmovdqu 0x16a(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x280(%rdi)+ vmovdqu 0x17a(%rsi), %xmm0+ vmovdqu 0x17c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x2a0(%rdi)+ vmovdqu 0x18c(%rsi), %xmm0+ vmovdqu 0x18e(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x2c0(%rdi)+ vmovdqu 0x19e(%rsi), %xmm0+ vmovdqu 0x1a0(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x2e0(%rdi)+ vmovdqu 0x1b0(%rsi), %xmm0+ vmovdqu 0x1b2(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x300(%rdi)+ vmovdqu 0x1c2(%rsi), %xmm0+ vmovdqu 0x1c4(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x320(%rdi)+ vmovdqu 0x1d4(%rsi), %xmm0+ vmovdqu 0x1d6(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x340(%rdi)+ vmovdqu 0x1e6(%rsi), %xmm0+ vmovdqu 0x1e8(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x360(%rdi)+ vmovdqu 0x1f8(%rsi), %xmm0+ vmovdqu 0x1fa(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x380(%rdi)+ vmovdqu 0x20a(%rsi), %xmm0+ vmovdqu 0x20c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x3a0(%rdi)+ vmovdqu 0x21c(%rsi), %xmm0+ vmovdqu 0x21e(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x3c0(%rdi)+ vmovdqu 0x22e(%rsi), %xmm0+ vmovdqu 0x230(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x3e0(%rdi)+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(polyz_unpack_17_avx2_asm)+++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && (!MLD_CONFIG_NO_SIGN_API || \+ !MLD_CONFIG_NO_VERIFY_API) && !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44) \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,355 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */+++/*yaml+ Name: polyz_unpack_19_avx2_asm+ Description: x86_64 AVX2 unpacking of 19-bit packed coefficients.+ Unpack polynomial z with 20-bit packed coefficients (GAMMA1 = 2^19),+ mapping packed [0, 2^20-1] to signed [-(2^19-1), 2^19] via GAMMA1 - x.+ Signature: void mld_polyz_unpack_19_avx2_asm(int32_t *r, const uint8_t *a)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *r+ description: Output polynomial (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 640+ permissions: read-only+ c_parameter: const uint8_t *a+ description: Packed input bytes+*/++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ (!defined(MLD_CONFIG_NO_SIGN_API) || \+ !defined(MLD_CONFIG_NO_VERIFY_API)) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87))+++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_polyz_unpack_19_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(polyz_unpack_19_avx2_asm)+MLD_ASM_FN_SYMBOL(polyz_unpack_19_avx2_asm)++ .cfi_startproc+ movabsq $-0xfbfcfd00fdff00, %rax # imm = 0xFF040302FF020100+ vmovq %rax, %xmm1+ movabsq $-0xf6f7f800f8f9fb, %rax # imm = 0xFF090807FF070605+ vpinsrq $0x1, %rax, %xmm1, %xmm1+ movabsq $-0xe5e6e700e7e8ea, %rax # imm = 0xFF1A1918FF181716+ vmovq %rax, %xmm5+ movabsq $-0xe0e1e200e2e3e5, %rax # imm = 0xFF1F1E1DFF1D1C1B+ vpinsrq $0x1, %rax, %xmm5, %xmm5+ vinserti128 $0x1, %xmm5, %ymm1, %ymm1+ movabsq $0x400000000, %rax # imm = 0x400000000+ vmovq %rax, %xmm2+ movabsq $0x400000000, %rax # imm = 0x400000000+ vpinsrq $0x1, %rax, %xmm2, %xmm2+ vinserti128 $0x1, %xmm2, %ymm2, %ymm2+ movl $0xfffff, %eax # imm = 0xFFFFF+ vmovd %eax, %xmm3+ vpbroadcastd %xmm3, %ymm3+ movl $0x80000, %eax # imm = 0x80000+ vmovd %eax, %xmm4+ vpbroadcastd %xmm4, %ymm4+ vmovdqu (%rsi), %xmm0+ vmovdqu 0x4(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, (%rdi)+ vmovdqu 0x14(%rsi), %xmm0+ vmovdqu 0x18(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x20(%rdi)+ vmovdqu 0x28(%rsi), %xmm0+ vmovdqu 0x2c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x40(%rdi)+ vmovdqu 0x3c(%rsi), %xmm0+ vmovdqu 0x40(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x60(%rdi)+ vmovdqu 0x50(%rsi), %xmm0+ vmovdqu 0x54(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x80(%rdi)+ vmovdqu 0x64(%rsi), %xmm0+ vmovdqu 0x68(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0xa0(%rdi)+ vmovdqu 0x78(%rsi), %xmm0+ vmovdqu 0x7c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0xc0(%rdi)+ vmovdqu 0x8c(%rsi), %xmm0+ vmovdqu 0x90(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0xe0(%rdi)+ vmovdqu 0xa0(%rsi), %xmm0+ vmovdqu 0xa4(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x100(%rdi)+ vmovdqu 0xb4(%rsi), %xmm0+ vmovdqu 0xb8(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x120(%rdi)+ vmovdqu 0xc8(%rsi), %xmm0+ vmovdqu 0xcc(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x140(%rdi)+ vmovdqu 0xdc(%rsi), %xmm0+ vmovdqu 0xe0(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x160(%rdi)+ vmovdqu 0xf0(%rsi), %xmm0+ vmovdqu 0xf4(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x180(%rdi)+ vmovdqu 0x104(%rsi), %xmm0+ vmovdqu 0x108(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x1a0(%rdi)+ vmovdqu 0x118(%rsi), %xmm0+ vmovdqu 0x11c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x1c0(%rdi)+ vmovdqu 0x12c(%rsi), %xmm0+ vmovdqu 0x130(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x1e0(%rdi)+ vmovdqu 0x140(%rsi), %xmm0+ vmovdqu 0x144(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x200(%rdi)+ vmovdqu 0x154(%rsi), %xmm0+ vmovdqu 0x158(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x220(%rdi)+ vmovdqu 0x168(%rsi), %xmm0+ vmovdqu 0x16c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x240(%rdi)+ vmovdqu 0x17c(%rsi), %xmm0+ vmovdqu 0x180(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x260(%rdi)+ vmovdqu 0x190(%rsi), %xmm0+ vmovdqu 0x194(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x280(%rdi)+ vmovdqu 0x1a4(%rsi), %xmm0+ vmovdqu 0x1a8(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x2a0(%rdi)+ vmovdqu 0x1b8(%rsi), %xmm0+ vmovdqu 0x1bc(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x2c0(%rdi)+ vmovdqu 0x1cc(%rsi), %xmm0+ vmovdqu 0x1d0(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x2e0(%rdi)+ vmovdqu 0x1e0(%rsi), %xmm0+ vmovdqu 0x1e4(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x300(%rdi)+ vmovdqu 0x1f4(%rsi), %xmm0+ vmovdqu 0x1f8(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x320(%rdi)+ vmovdqu 0x208(%rsi), %xmm0+ vmovdqu 0x20c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x340(%rdi)+ vmovdqu 0x21c(%rsi), %xmm0+ vmovdqu 0x220(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x360(%rdi)+ vmovdqu 0x230(%rsi), %xmm0+ vmovdqu 0x234(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x380(%rdi)+ vmovdqu 0x244(%rsi), %xmm0+ vmovdqu 0x248(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x3a0(%rdi)+ vmovdqu 0x258(%rsi), %xmm0+ vmovdqu 0x25c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x3c0(%rdi)+ vmovdqu 0x26c(%rsi), %xmm0+ vmovdqu 0x270(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm0, %ymm0+ vpshufb %ymm1, %ymm0, %ymm0+ vpsrlvd %ymm2, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubd %ymm0, %ymm4, %ymm0+ vmovdqa %ymm0, 0x3e0(%rdi)+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(polyz_unpack_19_avx2_asm)+++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && (!MLD_CONFIG_NO_SIGN_API || \+ !MLD_CONFIG_NO_VERIFY_API) && !MLD_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,132 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: rej_uniform_avx2_asm+ Description: x86_64 AVX2 rejection sampling of uniform coefficients mod q.+ Extract 23-bit values from the input byte buffer and accept those that are+ < MLDSA_Q, writing accepted coefficients to the output buffer. Returns the+ number of valid coefficients written (at most 256).+ Signature: unsigned mld_rej_uniform_avx2_asm(int32_t *r, const uint8_t buf[840], const uint8_t table[256][8])+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *r+ description: Output buffer (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 840+ permissions: read-only+ c_parameter: const uint8_t buf[840]+ description: Input buffer (MLD_POLY_UNIFORM_NBLOCKS * SHAKE128_RATE = 5 * 168)+ rdx:+ type: buffer+ size_bytes: 2048+ permissions: read-only+ c_parameter: const uint8_t table[256][8]+ description: Lookup table (256 x 8 x uint8_t)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_rej_uniform_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(rej_uniform_avx2_asm)+MLD_ASM_FN_SYMBOL(rej_uniform_avx2_asm)++ .cfi_startproc+ movabsq $-0xfafbfc00fdff00, %r10 # imm = 0xFF050403FF020100+ vmovq %r10, %xmm0+ movabsq $-0xf4f5f600f7f8fa, %r10 # imm = 0xFF0B0A09FF080706+ vpinsrq $0x1, %r10, %xmm0, %xmm0+ movabsq $-0xf6f7f800f9fafc, %r10 # imm = 0xFF090807FF060504+ vmovq %r10, %xmm3+ movabsq $-0xf0f1f200f3f4f6, %r10 # imm = 0xFF0F0E0DFF0C0B0A+ vpinsrq $0x1, %r10, %xmm3, %xmm3+ vinserti128 $0x1, %xmm3, %ymm0, %ymm0+ movl $0x7fffff, %r8d # imm = 0x7FFFFF+ vmovd %r8d, %xmm1+ vpbroadcastd %xmm1, %ymm1+ movl $0x7fe001, %r8d # imm = 0x7FE001+ vmovd %r8d, %xmm2+ vpbroadcastd %xmm2, %ymm2+ xorl %eax, %eax+ xorl %ecx, %ecx++Lmld_rej_uniform_avx2_asm_loop:+ cmpl $0xf8, %eax+ ja Lmld_rej_uniform_avx2_asm_scalar+ cmpl $0x328, %ecx # imm = 0x328+ ja Lmld_rej_uniform_avx2_asm_scalar+ vmovdqu (%rsi,%rcx), %ymm3+ addl $0x18, %ecx+ vpermq $0x94, %ymm3, %ymm3 # ymm3 = ymm3[0,1,1,2]+ vpshufb %ymm0, %ymm3, %ymm3+ vpand %ymm1, %ymm3, %ymm3+ vpsubd %ymm2, %ymm3, %ymm4+ vmovmskps %ymm4, %r8d+ popcntl %r8d, %r9d+ vmovq (%rdx,%r8,8), %xmm4+ vpmovzxbd %xmm4, %ymm4 # ymm4 = xmm4[0],zero,zero,zero,xmm4[1],zero,zero,zero,xmm4[2],zero,zero,zero,xmm4[3],zero,zero,zero,xmm4[4],zero,zero,zero,xmm4[5],zero,zero,zero,xmm4[6],zero,zero,zero,xmm4[7],zero,zero,zero+ vpermd %ymm3, %ymm4, %ymm3+ vmovdqu %ymm3, (%rdi,%rax,4)+ addl %r9d, %eax+ jmp Lmld_rej_uniform_avx2_asm_loop++Lmld_rej_uniform_avx2_asm_scalar:+ cmpl $0x100, %eax # imm = 0x100+ jae Lmld_rej_uniform_avx2_asm_done+ cmpl $0x345, %ecx # imm = 0x345+ ja Lmld_rej_uniform_avx2_asm_done+ movzwl (%rsi,%rcx), %r8d+ movzbl 0x2(%rsi,%rcx), %r9d+ shll $0x10, %r9d+ orl %r9d, %r8d+ andl $0x7fffff, %r8d # imm = 0x7FFFFF+ addl $0x3, %ecx+ cmpl $0x7fe001, %r8d # imm = 0x7FE001+ jae Lmld_rej_uniform_avx2_asm_scalar+ movl %r8d, (%rdi,%rax,4)+ addl $0x1, %eax+ jmp Lmld_rej_uniform_avx2_asm_scalar++Lmld_rej_uniform_avx2_asm_done:+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(rej_uniform_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,205 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: rej_uniform_eta2_avx2_asm+ Description: x86_64 AVX2 rejection sampling of eta=2 secret coefficients.+ Extracts 4-bit nibbles from the input byte buffer, accepts those < 15,+ and maps an accepted nibble n to the coefficient 2 - (n mod 5) via a+ centered modulo-5 reduction, producing values in [-2, 2].+ Signature: unsigned mld_rej_uniform_eta2_avx2_asm(int32_t *r, const uint8_t *buf, const uint8_t table[256][8])+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *r+ description: Output coefficient buffer (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 136+ permissions: read-only+ c_parameter: const uint8_t *buf+ description: Input byte buffer (MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN = 136)+ rdx:+ type: buffer+ size_bytes: 2048+ permissions: read-only+ c_parameter: const uint8_t *table+ description: Lookup table (256 x 8 uint8_t = mld_rej_uniform_table)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_rej_uniform_eta2_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(rej_uniform_eta2_avx2_asm)+MLD_ASM_FN_SYMBOL(rej_uniform_eta2_avx2_asm)++ .cfi_startproc+ movl $0xf0f0f0f, %r8d # imm = 0xF0F0F0F+ vmovd %r8d, %xmm3+ vpbroadcastd %xmm3, %ymm3+ movl $0x2020202, %r8d # imm = 0x2020202+ vmovd %r8d, %xmm4+ vpbroadcastd %xmm4, %ymm4+ movl $0xf0f0f0f, %r8d # imm = 0xF0F0F0F+ vmovd %r8d, %xmm5+ vpbroadcastd %xmm5, %ymm5+ movl $0xffffe660, %r8d # imm = 0xFFFFE660+ vpinsrw $0x0, %r8d, %xmm6, %xmm6+ vpbroadcastw %xmm6, %ymm6+ movl $0x5, %r8d+ vpinsrw $0x0, %r8d, %xmm7, %xmm7+ vpbroadcastw %xmm7, %ymm7+ xorl %eax, %eax+ xorl %ecx, %ecx++Lmld_rej_uniform_eta2_avx2_asm_loop:+ cmpl $0xf8, %eax+ ja Lmld_rej_uniform_eta2_avx2_asm_scalar+ cmpl $0x78, %ecx+ ja Lmld_rej_uniform_eta2_avx2_asm_scalar+ vpmovzxbw (%rsi,%rcx), %ymm0+ vpsllw $0x4, %ymm0, %ymm1+ vpor %ymm1, %ymm0, %ymm0+ vpand %ymm3, %ymm0, %ymm0+ vpsubb %ymm5, %ymm0, %ymm1+ vpsubb %ymm0, %ymm4, %ymm0+ vpmovmskb %ymm1, %r8d+ vextracti128 $0x0, %ymm0, %xmm8+ movzbl %r8b, %r10d+ vmovq (%rdx,%r10,8), %xmm9+ vpshufb %xmm9, %xmm8, %xmm9+ vpmovsxbd %xmm9, %ymm1+ vpmulhrsw %ymm6, %ymm1, %ymm2+ vpmullw %ymm7, %ymm2, %ymm2+ vpaddd %ymm2, %ymm1, %ymm1+ vmovdqu %ymm1, (%rdi,%rax,4)+ popcntl %r10d, %r9d+ addl %r9d, %eax+ shrl $0x8, %r8d+ addl $0x4, %ecx+ cmpl $0xf8, %eax+ ja Lmld_rej_uniform_eta2_avx2_asm_scalar+ vpsrldq $0x8, %xmm8, %xmm8 # xmm8 = xmm8[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero+ movzbl %r8b, %r10d+ vmovq (%rdx,%r10,8), %xmm9+ vpshufb %xmm9, %xmm8, %xmm9+ vpmovsxbd %xmm9, %ymm1+ vpmulhrsw %ymm6, %ymm1, %ymm2+ vpmullw %ymm7, %ymm2, %ymm2+ vpaddd %ymm2, %ymm1, %ymm1+ vmovdqu %ymm1, (%rdi,%rax,4)+ popcntl %r10d, %r9d+ addl %r9d, %eax+ shrl $0x8, %r8d+ addl $0x4, %ecx+ cmpl $0xf8, %eax+ ja Lmld_rej_uniform_eta2_avx2_asm_scalar+ vextracti128 $0x1, %ymm0, %xmm8+ movzbl %r8b, %r10d+ vmovq (%rdx,%r10,8), %xmm9+ vpshufb %xmm9, %xmm8, %xmm9+ vpmovsxbd %xmm9, %ymm1+ vpmulhrsw %ymm6, %ymm1, %ymm2+ vpmullw %ymm7, %ymm2, %ymm2+ vpaddd %ymm2, %ymm1, %ymm1+ vmovdqu %ymm1, (%rdi,%rax,4)+ popcntl %r10d, %r9d+ addl %r9d, %eax+ shrl $0x8, %r8d+ addl $0x4, %ecx+ cmpl $0xf8, %eax+ ja Lmld_rej_uniform_eta2_avx2_asm_scalar+ vpsrldq $0x8, %xmm8, %xmm8 # xmm8 = xmm8[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero+ movzbl %r8b, %r10d+ vmovq (%rdx,%r10,8), %xmm9+ vpshufb %xmm9, %xmm8, %xmm9+ vpmovsxbd %xmm9, %ymm1+ vpmulhrsw %ymm6, %ymm1, %ymm2+ vpmullw %ymm7, %ymm2, %ymm2+ vpaddd %ymm2, %ymm1, %ymm1+ vmovdqu %ymm1, (%rdi,%rax,4)+ popcntl %r10d, %r9d+ addl %r9d, %eax+ addl $0x4, %ecx+ jmp Lmld_rej_uniform_eta2_avx2_asm_loop++Lmld_rej_uniform_eta2_avx2_asm_scalar:+ cmpl $0x100, %eax # imm = 0x100+ jae Lmld_rej_uniform_eta2_avx2_asm_done+ cmpl $0x88, %ecx+ jae Lmld_rej_uniform_eta2_avx2_asm_done+ movzbl (%rsi,%rcx), %r11d+ incl %ecx+ movl %r11d, %r10d+ andl $0xf, %r10d+ cmpl $0xf, %r10d+ jae Lmld_rej_uniform_eta2_avx2_asm_high_nibble+ movl %r10d, %r11d+ imull $0xcd, %r11d, %r11d+ shrl $0xa, %r11d+ imull $0x5, %r11d, %r11d+ subl %r11d, %r10d+ movl $0x2, %r11d+ subl %r10d, %r11d+ movl %r11d, (%rdi,%rax,4)+ incl %eax+ cmpl $0x100, %eax # imm = 0x100+ jae Lmld_rej_uniform_eta2_avx2_asm_done++Lmld_rej_uniform_eta2_avx2_asm_high_nibble:+ movzbl -0x1(%rsi,%rcx), %r11d+ shrl $0x4, %r11d+ andl $0xf, %r11d+ cmpl $0xf, %r11d+ jae Lmld_rej_uniform_eta2_avx2_asm_scalar+ movl %r11d, %r10d+ imull $0xcd, %r10d, %r10d+ shrl $0xa, %r10d+ imull $0x5, %r10d, %r10d+ subl %r10d, %r11d+ movl $0x2, %r10d+ subl %r11d, %r10d+ movl %r10d, (%rdi,%rax,4)+ incl %eax+ jmp Lmld_rej_uniform_eta2_avx2_asm_scalar++Lmld_rej_uniform_eta2_avx2_asm_done:+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(rej_uniform_eta2_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,176 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Dilithium optimized AVX2 implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Dilithium implementation @[REF_AVX2].+ */++/*yaml+ Name: rej_uniform_eta4_avx2_asm+ Description: x86_64 AVX2 rejection sampling of eta=4 secret coefficients.+ Extracts 4-bit nibbles from the input byte buffer, accepts those < 9,+ and maps an accepted nibble n to the coefficient 4 - n, producing+ values in [-4, 4].+ Signature: unsigned mld_rej_uniform_eta4_avx2_asm(int32_t *r, const uint8_t *buf, const uint8_t table[256][8])+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 1024+ permissions: write-only+ c_parameter: int32_t *r+ description: Output coefficient buffer (256 x int32_t)+ rsi:+ type: buffer+ size_bytes: 272+ permissions: read-only+ c_parameter: const uint8_t *buf+ description: Input byte buffer (MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN = 272)+ rdx:+ type: buffer+ size_bytes: 2048+ permissions: read-only+ c_parameter: const uint8_t *table+ description: Lookup table (256 x 8 uint8_t = mld_rej_uniform_table)+*/++#include "../../../common.h"+#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mldsa-native source file+ * dev/x86_64/src/mldsa_rej_uniform_eta4_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLD_ASM_NAMESPACE(rej_uniform_eta4_avx2_asm)+MLD_ASM_FN_SYMBOL(rej_uniform_eta4_avx2_asm)++ .cfi_startproc+ movl $0xf0f0f0f, %r8d # imm = 0xF0F0F0F+ vmovd %r8d, %xmm2+ vpbroadcastd %xmm2, %ymm2+ movl $0x4040404, %r8d # imm = 0x4040404+ vmovd %r8d, %xmm3+ vpbroadcastd %xmm3, %ymm3+ movl $0x9090909, %r8d # imm = 0x9090909+ vmovd %r8d, %xmm4+ vpbroadcastd %xmm4, %ymm4+ xorl %eax, %eax+ xorl %ecx, %ecx++Lmld_rej_uniform_eta4_avx2_asm_loop:+ cmpl $0xf8, %eax+ ja Lmld_rej_uniform_eta4_avx2_asm_scalar+ cmpl $0x100, %ecx # imm = 0x100+ ja Lmld_rej_uniform_eta4_avx2_asm_scalar+ vpmovzxbw (%rsi,%rcx), %ymm0+ vpsllw $0x4, %ymm0, %ymm1+ vpor %ymm1, %ymm0, %ymm0+ vpand %ymm2, %ymm0, %ymm0+ vpsubb %ymm4, %ymm0, %ymm1+ vpsubb %ymm0, %ymm3, %ymm0+ vpmovmskb %ymm1, %r8d+ vextracti128 $0x0, %ymm0, %xmm5+ movzbl %r8b, %r10d+ vmovq (%rdx,%r10,8), %xmm6+ vpshufb %xmm6, %xmm5, %xmm6+ vpmovsxbd %xmm6, %ymm1+ vmovdqu %ymm1, (%rdi,%rax,4)+ popcntl %r10d, %r9d+ addl %r9d, %eax+ shrl $0x8, %r8d+ addl $0x4, %ecx+ cmpl $0xf8, %eax+ ja Lmld_rej_uniform_eta4_avx2_asm_scalar+ vpsrldq $0x8, %xmm5, %xmm5 # xmm5 = xmm5[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero+ movzbl %r8b, %r10d+ vmovq (%rdx,%r10,8), %xmm6+ vpshufb %xmm6, %xmm5, %xmm6+ vpmovsxbd %xmm6, %ymm1+ vmovdqu %ymm1, (%rdi,%rax,4)+ popcntl %r10d, %r9d+ addl %r9d, %eax+ shrl $0x8, %r8d+ addl $0x4, %ecx+ cmpl $0xf8, %eax+ ja Lmld_rej_uniform_eta4_avx2_asm_scalar+ vextracti128 $0x1, %ymm0, %xmm5+ movzbl %r8b, %r10d+ vmovq (%rdx,%r10,8), %xmm6+ vpshufb %xmm6, %xmm5, %xmm6+ vpmovsxbd %xmm6, %ymm1+ vmovdqu %ymm1, (%rdi,%rax,4)+ popcntl %r10d, %r9d+ addl %r9d, %eax+ shrl $0x8, %r8d+ addl $0x4, %ecx+ cmpl $0xf8, %eax+ ja Lmld_rej_uniform_eta4_avx2_asm_scalar+ vpsrldq $0x8, %xmm5, %xmm5 # xmm5 = xmm5[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero+ movzbl %r8b, %r10d+ vmovq (%rdx,%r10,8), %xmm6+ vpshufb %xmm6, %xmm5, %xmm6+ vpmovsxbd %xmm6, %ymm1+ vmovdqu %ymm1, (%rdi,%rax,4)+ popcntl %r10d, %r9d+ addl %r9d, %eax+ addl $0x4, %ecx+ jmp Lmld_rej_uniform_eta4_avx2_asm_loop++Lmld_rej_uniform_eta4_avx2_asm_scalar:+ cmpl $0x100, %eax # imm = 0x100+ jae Lmld_rej_uniform_eta4_avx2_asm_done+ cmpl $0x110, %ecx # imm = 0x110+ jae Lmld_rej_uniform_eta4_avx2_asm_done+ movzbl (%rsi,%rcx), %r11d+ incl %ecx+ movl %r11d, %r10d+ andl $0xf, %r10d+ cmpl $0x9, %r10d+ jae Lmld_rej_uniform_eta4_avx2_asm_high_nibble+ movl $0x4, %r9d+ subl %r10d, %r9d+ movl %r9d, (%rdi,%rax,4)+ incl %eax+ cmpl $0x100, %eax # imm = 0x100+ jae Lmld_rej_uniform_eta4_avx2_asm_done++Lmld_rej_uniform_eta4_avx2_asm_high_nibble:+ shrl $0x4, %r11d+ andl $0xf, %r11d+ cmpl $0x9, %r11d+ jae Lmld_rej_uniform_eta4_avx2_asm_scalar+ movl $0x4, %r10d+ subl %r11d, %r10d+ movl %r10d, (%rdi,%rax,4)+ incl %eax+ jmp Lmld_rej_uniform_eta4_avx2_asm_scalar++Lmld_rej_uniform_eta4_avx2_asm_done:+ retq+ .cfi_endproc++MLD_ASM_FN_SIZE(rej_uniform_eta4_avx2_asm)++#endif /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,161 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)++#include "arith_native_x86_64.h"++/*+ * Lookup table used by rejection sampling.+ * See autogen for details.+ */+MLD_ALIGN MLD_INTERNAL_DATA_DEFINITION const uint8_t+ mld_rej_uniform_table[256][8] = {+ {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0},+ {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0},+ {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0},+ {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0},+ {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0},+ {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0},+ {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0},+ {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0},+ {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0},+ {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0},+ {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0},+ {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0},+ {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0},+ {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0},+ {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0},+ {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0},+ {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0},+ {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0},+ {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0},+ {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0},+ {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0},+ {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0},+ {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0},+ {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0},+ {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0},+ {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0},+ {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0},+ {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0},+ {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0},+ {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0},+ {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0},+ {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0},+ {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0},+ {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0},+ {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0},+ {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0},+ {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0},+ {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0},+ {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0},+ {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0},+ {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0},+ {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0},+ {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0},+ {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0},+ {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0},+ {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0},+ {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0},+ {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0},+ {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0},+ {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0},+ {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0},+ {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0},+ {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0},+ {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0},+ {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0},+ {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0},+ {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0},+ {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0},+ {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0},+ {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0},+ {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0},+ {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0},+ {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0},+ {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0},+ {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0},+ {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0},+ {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0},+ {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0},+ {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0},+ {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0},+ {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0},+ {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0},+ {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0},+ {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0},+ {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0},+ {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0},+ {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0},+ {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0},+ {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0},+ {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0},+ {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0},+ {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0},+ {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0},+ {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0},+ {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0},+ {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0},+ {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0},+ {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0},+ {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0},+ {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0},+ {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0},+ {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0},+ {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0},+ {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0},+ {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0},+ {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0},+ {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0},+ {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0},+ {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0},+ {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0},+ {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0},+ {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0},+ {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0},+ {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0},+ {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0},+ {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0},+ {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0},+ {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0},+ {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0},+ {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0},+ {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0},+ {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0},+ {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0},+ {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0},+ {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0},+ {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0},+ {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0},+ {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0},+ {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0},+ {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0},+ {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0},+ {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0},+ {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0},+ {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0},+ {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0},+ {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0},+ {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0},+ {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7},+};++#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \+ */++MLD_EMPTY_CU(avx2_rej_uniform_table)++#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \+ !MLD_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,213 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#include <string.h>++#include "common.h"+#include "packing.h"+#include "poly.h"+#include "polyvec.h"+#include "rounding.h"++/* Parameter set namespacing+ * This is to facilitate building multiple instances+ * of mldsa-native (e.g. with varying parameter sets)+ * within a single compilation unit. */+/* End of parameter set namespacing */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_INTERNAL_API+void mld_unpack_pk_t1(mld_poly *t1,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ unsigned int i)+{+ mld_polyt1_unpack(t1, pk + MLDSA_PK_T1_OFFSET + i * MLDSA_POLYT1_PACKEDBYTES);+}+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+MLD_INTERNAL_API+void mld_pack_sk_s1(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ const mld_polyvecl *s1)+{+ mld_polyvecl_pack_eta(sk + MLDSA_SK_S1_OFFSET, s1);+}++MLD_INTERNAL_API+void mld_pack_sk_rho_key_tr_s2(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ const uint8_t rho[MLDSA_SEEDBYTES],+ const uint8_t tr[MLDSA_TRBYTES],+ const uint8_t key[MLDSA_SEEDBYTES],+ const mld_polyveck *s2)+{+ mld_memcpy(sk + MLDSA_SK_RHO_OFFSET, rho, MLDSA_SEEDBYTES);+ mld_memcpy(sk + MLDSA_SK_KEY_OFFSET, key, MLDSA_SEEDBYTES);+ mld_memcpy(sk + MLDSA_SK_TR_OFFSET, tr, MLDSA_TRBYTES);+ /* s1 already packed via mld_pack_sk_s1 */+ mld_polyveck_pack_eta(sk + MLDSA_SK_S2_OFFSET, s2);+ /* t0 already packed via mld_compute_pack_t0_t1 */+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+MLD_INTERNAL_API+void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES],+ uint8_t key[MLDSA_SEEDBYTES], mld_sk_t0hat *t0,+ mld_sk_s1hat *s1, mld_sk_s2hat *s2,+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES])+{+ mld_memcpy(rho, sk + MLDSA_SK_RHO_OFFSET, MLDSA_SEEDBYTES);+ mld_memcpy(key, sk + MLDSA_SK_KEY_OFFSET, MLDSA_SEEDBYTES);+ mld_memcpy(tr, sk + MLDSA_SK_TR_OFFSET, MLDSA_TRBYTES);+ mld_unpack_sk_s1hat(s1, sk + MLDSA_SK_S1_OFFSET);+ mld_unpack_sk_s2hat(s2, sk + MLDSA_SK_S2_OFFSET);+ mld_unpack_sk_t0hat(t0, sk + MLDSA_SK_T0_OFFSET);+}++MLD_INTERNAL_API+void mld_pack_sig_c(uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t c[MLDSA_CTILDEBYTES])+{+ mld_memcpy(sig, c, MLDSA_CTILDEBYTES);+}++MLD_INTERNAL_API+int mld_pack_sig_h(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_polyveck *w0,+ const mld_polyveck *w1)+{+ unsigned int j, k, n;++ /* The hint section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where+ * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K.+ *+ * The first OMEGA bytes record the index numbers of the coefficients+ * that are not equal to 0.+ *+ * The final K bytes record a running tally of the number of hints+ * coming from each of the K polynomials. */+ uint8_t *sig_h = sig + MLDSA_SIG_H_OFFSET;++ mld_memset(sig_h, 0, MLDSA_POLYVECH_PACKEDBYTES);+ n = 0;++ /* For each coefficient of each polynomial, compute its hint bit and, if+ * non-zero, record the index in the hint section of sig. If recording the+ * hint would overflow the OMEGA-sized index array, abort early and return+ * MLD_ERR_FAIL. The caller is expected to reject the signature in that case.+ *+ * Constant time: At this point w0/w1 are public (see comment in sign.c+ * before the call), so a data-dependent early return is fine. */+ for (k = 0; k < MLDSA_K; k++)+ __loop__(+ assigns(k, j, n, memory_slice(sig_h, MLDSA_POLYVECH_PACKEDBYTES))+ invariant(k <= MLDSA_K && n <= MLDSA_OMEGA)+ decreases(MLDSA_K - k)+ )+ {+ for (j = 0; j < MLDSA_N; j++)+ __loop__(+ assigns(j, n, memory_slice(sig_h, MLDSA_POLYVECH_PACKEDBYTES))+ invariant(j <= MLDSA_N && n <= MLDSA_OMEGA)+ decreases(MLDSA_N - j)+ )+ {+ const unsigned int hint_bit =+ mld_make_hint(w0->vec[k].coeffs[j], w1->vec[k].coeffs[j]);+ if (hint_bit)+ {+ if (n == MLDSA_OMEGA)+ {+ return MLD_ERR_FAIL;+ }+ /* Safety: branch above ensures n < MLDSA_OMEGA so n is a valid index+ * into the OMEGA-sized index array; j < MLDSA_N <= 256 fits in+ * uint8_t. */+ sig_h[n] = (uint8_t)j;+ n++;+ }+ }+ /* Record the running tally into the correct slot for this polynomial.+ * Safety: k < MLDSA_K, so MLDSA_OMEGA + k is a valid index into the+ * K-byte tally tail; n <= MLDSA_OMEGA fits in uint8_t. */+ sig_h[MLDSA_OMEGA + k] = (uint8_t)n;+ }+ return 0;+}++MLD_INTERNAL_API+void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi,+ unsigned i)+{+ mld_polyz_pack(sig + MLDSA_SIG_Z_OFFSET + i * MLDSA_POLYZ_PACKEDBYTES, zi);+}+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_INTERNAL_API+int mld_sig_unpack_hints(mld_poly *h, const uint8_t sig[MLDSA_CRYPTO_BYTES],+ unsigned int i)+{+ const uint8_t *packed_hints = sig + MLDSA_SIG_H_OFFSET;+ const unsigned int old_hint_count =+ (i == 0) ? 0 : packed_hints[MLDSA_OMEGA + i - 1];+ const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i];+ unsigned int j;++ if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA)+ {+ return MLD_ERR_FAIL;+ }++ mld_memset(h, 0, sizeof(mld_poly));++ for (j = old_hint_count; j < new_hint_count; ++j)+ __loop__(+ invariant(j >= old_hint_count && j <= new_hint_count &&+ new_hint_count <= MLDSA_OMEGA)+ invariant(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))+ invariant(forall(p, 0, MLDSA_N,+ (h->coeffs[p] == 1) ==+ exists(hj, old_hint_count, j, packed_hints[hj] == p)))+ decreases(new_hint_count - j)+ )+ {+ if (j > old_hint_count && packed_hints[j] <= packed_hints[j - 1])+ {+ return MLD_ERR_FAIL;+ }+ /* Safety: packed_hints[j] is uint8_t (<= 255) and MLDSA_N == 256. */+ h->coeffs[packed_hints[j]] = 1;+ }++ /* On the last row, also verify that the trailing index slots are zero. */+ if (i == MLDSA_K - 1)+ {+ for (j = new_hint_count; j < MLDSA_OMEGA; ++j)+ __loop__(+ invariant(j <= MLDSA_OMEGA)+ decreases(MLDSA_OMEGA - j)+ )+ {+ if (packed_hints[j] != 0)+ {+ return MLD_ERR_FAIL;+ }+ }+ }++ /* On success, h->coeffs[p] is 1 exactly for the hint indices decoded for this+ * row, i.e. packed_hints[old_hint_count, new_hint_count). Asserted here+ * rather than posted as a contract to not unnecessarily increase proof+ * complexity at callers that do not need the functional description. */+ cassert(forall(+ p, 0, MLDSA_N,+ (h->coeffs[p] == 1) ==+ exists(hj, old_hint_count, new_hint_count, packed_hints[hj] == p)));++ return 0;+}+#endif /* !MLD_CONFIG_NO_VERIFY_API */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */
@@ -0,0 +1,277 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#ifndef MLD_PACKING_H+#define MLD_PACKING_H++#include "polyvec.h"+#include "polyvec_lazy.h"++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_pack_sk_s1 MLD_NAMESPACE_KL(pack_sk_s1)+/**+ * Bit-pack the s1 component into the secret key.+ *+ * @spec{Partially implements @[FIPS204, Algorithm 24, skEncode] (s1+ * component).}+ *+ * @param[out] sk Output byte array.+ * @param[in] s1 Pointer to vector s1.+ */+MLD_INTERNAL_API+void mld_pack_sk_s1(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ const mld_polyvecl *s1)+__contract__(+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ requires(memory_no_alias(s1, sizeof(mld_polyvecl)))+ requires(forall(k1, 0, MLDSA_L,+ array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))+ assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+);++#define mld_pack_sk_rho_key_tr_s2 MLD_NAMESPACE_KL(pack_sk_rho_key_tr_s2)+/**+ * Bit-pack rho, key, tr, s2 into the secret key.+ *+ * s1 must already be packed via mld_pack_sk_s1, and t0 via+ * mld_compute_pack_t0_t1.+ *+ * @spec{Partially implements @[FIPS204, Algorithm 24, skEncode] (rho, key, tr,+ * s2 components).}+ *+ * @param[out] sk Output byte array.+ * @param[in] rho Byte array containing rho.+ * @param[in] tr Byte array containing tr.+ * @param[in] key Byte array containing key.+ * @param[in] s2 Pointer to vector s2.+ */+MLD_INTERNAL_API+void mld_pack_sk_rho_key_tr_s2(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ const uint8_t rho[MLDSA_SEEDBYTES],+ const uint8_t tr[MLDSA_TRBYTES],+ const uint8_t key[MLDSA_SEEDBYTES],+ const mld_polyveck *s2)+__contract__(+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ requires(memory_no_alias(rho, MLDSA_SEEDBYTES))+ requires(memory_no_alias(tr, MLDSA_TRBYTES))+ requires(memory_no_alias(key, MLDSA_SEEDBYTES))+ requires(memory_no_alias(s2, sizeof(mld_polyveck)))+ requires(forall(k2, 0, MLDSA_K,+ array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))+ assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */+++#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_pack_sig_c MLD_NAMESPACE_KL(pack_sig_c)+/**+ * Bit-pack challenge c into sig = (c, z, h).+ *+ * @spec{Partially implements @[FIPS204, Algorithm 26, sigEncode] (c+ * component).}+ *+ * @param[out] sig Output byte array.+ * @param[in] c Pointer to challenge hash.+ */+MLD_INTERNAL_API+void mld_pack_sig_c(uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t c[MLDSA_CTILDEBYTES])+__contract__(+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(c, MLDSA_CTILDEBYTES))+ assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))+);++#define mld_pack_sig_h MLD_NAMESPACE_KL(pack_sig_h)+/**+ * Compute hints from (w0, w1) and pack them into the hint section of sig.+ *+ * @spec{Combines the hint computation @[FIPS204, Algorithm 39, MakeHint] with+ * the packing @[FIPS204, Algorithm 20, HintBitPack] (the h component of+ * @[FIPS204, Algorithm 26, sigEncode]): it computes the hint vector h from+ * (w0, w1) and packs it, rather than receiving a ready-made h as HintBitPack+ * does. The hints are computed via mld_make_hint (rounding.h), a specialized+ * MakeHint valid only for the values arising during signing; see the block+ * comment in mld_attempt_signature_generation (sign.c).}+ *+ * @param[in,out] sig Byte array containing signature.+ * @param[in] w0 Pointer to low part of input vector.+ * @param[in] w1 Pointer to high part of input vector.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_FAIL The total number of hints exceeds MLDSA_OMEGA. In this+ * case the hint section of sig is left in a+ * partially-written state and the caller must reject the+ * signature.+ */+MLD_INTERNAL_API+MLD_MUST_CHECK_RETURN_VALUE+int mld_pack_sig_h(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_polyveck *w0,+ const mld_polyveck *w1)+__contract__(+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(w0, sizeof(mld_polyveck)))+ requires(memory_no_alias(w1, sizeof(mld_polyveck)))+ assigns(memory_slice(sig + MLDSA_SIG_H_OFFSET, MLDSA_POLYVECH_PACKEDBYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_FAIL)+);++#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z)+/**+ * Bit-pack single polynomial of z component of sig = (c, z, h).+ *+ * The c and h components are packed separately using mld_pack_sig_c and+ * mld_pack_sig_h.+ *+ * @spec{Partially implements @[FIPS204, Algorithm 26, sigEncode] (one+ * polynomial of the z component).}+ *+ * @param[in,out] sig Output byte array.+ * @param[in] zi Pointer to a single polynomial in z.+ * @param i Index of zi in vector z.+ */+MLD_INTERNAL_API+void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi,+ unsigned i)+__contract__(+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(zi, sizeof(mld_poly)))+ requires(i < MLDSA_L)+ requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_unpack_pk_t1 MLD_NAMESPACE_KL(unpack_pk_t1)+/**+ * Unpack a single polynomial of the t1 component of a public key+ * pk = (rho, t1).+ *+ * @spec{Partially implements @[FIPS204, Algorithm 23, pkDecode] (one polynomial+ * of t1).}+ *+ * @param[out] t1 Pointer to output polynomial t1[i].+ * @param[in] pk Byte array containing bit-packed pk.+ * @param i Row index, must be < MLDSA_K.+ */+MLD_INTERNAL_API+void mld_unpack_pk_t1(mld_poly *t1,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ unsigned int i)+__contract__(+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ requires(memory_no_alias(t1, sizeof(mld_poly)))+ requires(i < MLDSA_K)+ assigns(memory_slice(t1, sizeof(mld_poly)))+ ensures(array_bound(t1->coeffs, 0, MLDSA_N, 0, 1 << 10))+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk)+/**+ * Unpack secret key sk = (rho, tr, key, t0, s1, s2).+ *+ * NOTE: In REDUCE_RAM mode, s1/s2/t0 borrow from sk rather than copying.+ *+ * @spec{Implements @[FIPS204, Algorithm 25, skDecode].}+ *+ * @param[out] rho Output byte array for rho.+ * @param[out] tr Output byte array for tr.+ * @param[out] key Output byte array for key.+ * @param[out] t0 Pointer to output vector t0.+ * @param[out] s1 Pointer to output vector s1.+ * @param[out] s2 Pointer to output vector s2.+ * @param[in] sk Byte array containing bit-packed sk.+ */+MLD_INTERNAL_API+void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES],+ uint8_t key[MLDSA_SEEDBYTES], mld_sk_t0hat *t0,+ mld_sk_s1hat *s1, mld_sk_s2hat *s2,+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES])+__contract__(+ requires(memory_no_alias(rho, MLDSA_SEEDBYTES))+ requires(memory_no_alias(tr, MLDSA_TRBYTES))+ requires(memory_no_alias(key, MLDSA_SEEDBYTES))+ requires(memory_no_alias(t0, sizeof(mld_sk_t0hat)))+ requires(memory_no_alias(s1, sizeof(mld_sk_s1hat)))+ requires(memory_no_alias(s2, sizeof(mld_sk_s2hat)))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ assigns(memory_slice(rho, MLDSA_SEEDBYTES))+ assigns(memory_slice(tr, MLDSA_TRBYTES))+ assigns(memory_slice(key, MLDSA_SEEDBYTES))+ assigns(memory_slice(t0, sizeof(mld_sk_t0hat)))+ assigns(memory_slice(s1, sizeof(mld_sk_s1hat)))+ assigns(memory_slice(s2, sizeof(mld_sk_s2hat)))+ MLD_IF_NOT_REDUCE_RAM(+ ensures(forall(k0, 0, MLDSA_K,+ array_abs_bound(t0->vec.vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ ensures(forall(k1, 0, MLDSA_L,+ array_abs_bound(s1->vec.vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ ensures(forall(k2, 0, MLDSA_K,+ array_abs_bound(s2->vec.vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ )+ MLD_IF_REDUCE_RAM(+ ensures(s1->packed == old(sk) + MLDSA_SK_S1_OFFSET)+ ensures(s2->packed == old(sk) + MLDSA_SK_S2_OFFSET)+ ensures(t0->packed == old(sk) + MLDSA_SK_T0_OFFSET)+ )+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_sig_unpack_hints MLD_NAMESPACE_KL(sig_unpack_hints)+/**+ * Decode and validate a single row of the hint vector h from a signature+ * buffer.+ *+ * The hint encoding is shared across all rows (a count array followed by a+ * single index list), so this function performs the validation relevant to+ * row i:+ * - the i'th hint count is non-decreasing and bounded by MLDSA_OMEGA;+ * - the indices for row i are strictly ascending;+ * - on i == MLDSA_K - 1, the trailing index slots are zero.+ *+ * Callers must invoke this for every i in [0, 1, .., MLDSA_K - 1]; if any+ * call returns MLD_ERR_FAIL the encoding is malformed and the signature must+ * be rejected.+ *+ * @spec{Implements @[FIPS204, Algorithm 21, HintBitUnpack] (one row; part of+ * @[FIPS204, Algorithm 27, sigDecode]).}+ *+ * @param[out] h Pointer to output polynomial h[i].+ * @param[in] sig Signature buffer.+ * @param i Row index, must be < MLDSA_K.+ *+ * @retval 0 Hints were decoded successfully.+ * @retval MLD_ERR_FAIL Hints are malformed.+ */+MLD_INTERNAL_API+MLD_MUST_CHECK_RETURN_VALUE+int mld_sig_unpack_hints(mld_poly *h, const uint8_t sig[MLDSA_CRYPTO_BYTES],+ unsigned int i)+__contract__(+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(h, sizeof(mld_poly)))+ requires(i < MLDSA_K)+ assigns(memory_slice(h, sizeof(mld_poly)))+ ensures(return_value == 0 || return_value == MLD_ERR_FAIL)+ ensures(return_value == 0 ==> array_bound(h->coeffs, 0, MLDSA_N, 0, 2))+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#endif /* !MLD_PACKING_H */
@@ -0,0 +1,153 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_PARAMS_H+#define MLD_PARAMS_H++#define MLDSA_SEEDBYTES 32+#define MLDSA_CRHBYTES 64+#define MLDSA_TRBYTES 64+#define MLDSA_RNDBYTES 32+#define MLDSA_N 256+#define MLDSA_Q 8380417+#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2)+#define MLDSA_D 13++#define MLDSA_GAMMA2_88 ((MLDSA_Q - 1) / 88)+#define MLDSA_GAMMA2_32 ((MLDSA_Q - 1) / 32)+#define MLDSA_POLYW1_PACKEDBYTES_88 192+#define MLDSA_POLYW1_PACKEDBYTES_32 128++#if MLD_CONFIG_PARAMETER_SET == 44++#define MLDSA_K 4+#define MLDSA_L 4+#define MLDSA_ETA 2+#define MLDSA_TAU 39+#define MLDSA_BETA 78+#define MLDSA_GAMMA1 ((int32_t)1 << 17)+#define MLDSA_GAMMA2 MLDSA_GAMMA2_88+#define MLDSA_OMEGA 80+#define MLDSA_CTILDEBYTES 32+#define MLDSA_POLYZ_PACKEDBYTES 576+#define MLDSA_POLYW1_PACKEDBYTES MLDSA_POLYW1_PACKEDBYTES_88+#define MLDSA_POLYETA_PACKEDBYTES 96++#elif MLD_CONFIG_PARAMETER_SET == 65++#define MLDSA_K 6+#define MLDSA_L 5+#define MLDSA_ETA 4+#define MLDSA_TAU 49+#define MLDSA_BETA 196+#define MLDSA_GAMMA1 ((int32_t)1 << 19)+#define MLDSA_GAMMA2 MLDSA_GAMMA2_32+#define MLDSA_OMEGA 55+#define MLDSA_CTILDEBYTES 48+#define MLDSA_POLYZ_PACKEDBYTES 640+#define MLDSA_POLYW1_PACKEDBYTES MLDSA_POLYW1_PACKEDBYTES_32+#define MLDSA_POLYETA_PACKEDBYTES 128++#elif MLD_CONFIG_PARAMETER_SET == 87++#define MLDSA_K 8+#define MLDSA_L 7+#define MLDSA_ETA 2+#define MLDSA_TAU 60+#define MLDSA_BETA 120+#define MLDSA_GAMMA1 ((int32_t)1 << 19)+#define MLDSA_GAMMA2 MLDSA_GAMMA2_32+#define MLDSA_OMEGA 75+#define MLDSA_CTILDEBYTES 64+#define MLDSA_POLYZ_PACKEDBYTES 640+#define MLDSA_POLYW1_PACKEDBYTES MLDSA_POLYW1_PACKEDBYTES_32+#define MLDSA_POLYETA_PACKEDBYTES 96++#endif /* MLD_CONFIG_PARAMETER_SET == 87 */++#define MLDSA_POLYT1_PACKEDBYTES 320+#define MLDSA_POLYT0_PACKEDBYTES 416+#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K)++/* Sampling y from counter kappa uses nonces kappa, ..., kappa+L-1, which fit in+ * uint16_t iff kappa <= UINT16_MAX - MLDSA_L. With kappa = attempt*MLDSA_L this+ * bounds the number of signing attempts by MLD_MAX_KAPPA / MLDSA_L; see+ * MLD_MAX_SIGNING_ATTEMPTS in sign.c. */+#define MLD_MAX_KAPPA (UINT16_MAX - MLDSA_L)++/* Layout of the packed public key pk[MLDSA_CRYPTO_PUBLICKEYBYTES] = (rho, t1):+ *+ * +-------------+--------------------------++ * | rho | t1 |+ * +-------------+--------------------------++ * | SEEDBYTES | K * POLYT1_PACKEDBYTES |+ * +-------------+--------------------------++ */+#define MLDSA_PK_RHO_OFFSET 0+#define MLDSA_PK_RHO_BYTES MLDSA_SEEDBYTES++#define MLDSA_PK_T1_OFFSET (MLDSA_PK_RHO_OFFSET + MLDSA_PK_RHO_BYTES)+#define MLDSA_PK_T1_BYTES (MLDSA_K * MLDSA_POLYT1_PACKEDBYTES)++#define MLDSA_PK_END (MLDSA_PK_T1_OFFSET + MLDSA_PK_T1_BYTES)++#define MLDSA_CRYPTO_PUBLICKEYBYTES MLDSA_PK_END++/* Layout of the packed secret key+ * sk[MLDSA_CRYPTO_SECRETKEYBYTES] = (rho, key, tr, s1, s2, t0):+ *+ * +-----------+-----------+-----------+-----------+-----------+-----------++ * | rho | key | tr | s1 | s2 | t0 |+ * +-----------+-----------+-----------+-----------+-----------+-----------++ * | SEEDBYTES | SEEDBYTES | TRBYTES | L * | K * | K * |+ * | | | | POLYETA_ | POLYETA_ | POLYT0_ |+ * | | | | PACKED- | PACKED- | PACKED- |+ * | | | | BYTES | BYTES | BYTES |+ * +-----------+-----------+-----------+-----------+-----------+-----------++ */+#define MLDSA_SK_RHO_OFFSET 0+#define MLDSA_SK_RHO_BYTES MLDSA_SEEDBYTES++#define MLDSA_SK_KEY_OFFSET (MLDSA_SK_RHO_OFFSET + MLDSA_SK_RHO_BYTES)+#define MLDSA_SK_KEY_BYTES MLDSA_SEEDBYTES++#define MLDSA_SK_TR_OFFSET (MLDSA_SK_KEY_OFFSET + MLDSA_SK_KEY_BYTES)+#define MLDSA_SK_TR_BYTES MLDSA_TRBYTES++#define MLDSA_SK_S1_OFFSET (MLDSA_SK_TR_OFFSET + MLDSA_SK_TR_BYTES)+#define MLDSA_SK_S1_BYTES (MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)++#define MLDSA_SK_S2_OFFSET (MLDSA_SK_S1_OFFSET + MLDSA_SK_S1_BYTES)+#define MLDSA_SK_S2_BYTES (MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)++#define MLDSA_SK_T0_OFFSET (MLDSA_SK_S2_OFFSET + MLDSA_SK_S2_BYTES)+#define MLDSA_SK_T0_BYTES (MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)++#define MLDSA_SK_END (MLDSA_SK_T0_OFFSET + MLDSA_SK_T0_BYTES)++#define MLDSA_CRYPTO_SECRETKEYBYTES MLDSA_SK_END++/* Layout of the packed signature sig[MLDSA_CRYPTO_BYTES] = (c, z, h):+ *+ * +----------------+-------------------+----------------------++ * | c (challenge) | z | h (hints) |+ * +----------------+-------------------+----------------------++ * | CTILDEBYTES | L * | POLYVECH_PACKEDBYTES |+ * | | POLYZ_PACKEDBYTES | (= OMEGA + K) |+ * +----------------+-------------------+----------------------++ */+#define MLDSA_SIG_C_OFFSET 0+#define MLDSA_SIG_C_BYTES MLDSA_CTILDEBYTES++#define MLDSA_SIG_Z_OFFSET (MLDSA_SIG_C_OFFSET + MLDSA_SIG_C_BYTES)+#define MLDSA_SIG_Z_BYTES (MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)++#define MLDSA_SIG_H_OFFSET (MLDSA_SIG_Z_OFFSET + MLDSA_SIG_Z_BYTES)+#define MLDSA_SIG_H_BYTES MLDSA_POLYVECH_PACKEDBYTES++#define MLDSA_SIG_END (MLDSA_SIG_H_OFFSET + MLDSA_SIG_H_BYTES)++#define MLDSA_CRYPTO_BYTES MLDSA_SIG_END++#endif /* !MLD_PARAMS_H */
@@ -0,0 +1,1066 @@+/*+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ *+ * - [REF]+ * CRYSTALS-Dilithium reference implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/ref+ */++#include "poly.h"++#include "common.h"+#include "ct.h"+#include "debug.h"+#include "reduce.h"+#include "rounding.h"+#include "symmetric.h"++#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)+#include "zetas.inc"++MLD_INTERNAL_API+void mld_poly_reduce(mld_poly *a)+{+ unsigned int i;+ mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX);++ for (i = 0; i < MLDSA_N; ++i)+ __loop__(+ invariant(i <= MLDSA_N)+ invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))+ invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))+ decreases(MLDSA_N - i))+ {+ a->coeffs[i] = mld_reduce32(a->coeffs[i]);+ }++ mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,+ MLD_REDUCE32_RANGE_MAX);+}++MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+)+{+ unsigned int i;+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);++ for (i = 0; i < MLDSA_N; ++i)+ __loop__(+ invariant(i <= MLDSA_N)+ invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))+ invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q))+ decreases(MLDSA_N - i)+ )+ {+ a->coeffs[i] = mld_caddq(a->coeffs[i]);+ }++ mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);+}++MLD_INTERNAL_API+void mld_poly_caddq(mld_poly *a)+{+#if defined(MLD_USE_NATIVE_POLY_CADDQ)+ int ret;+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);+ ret = mld_poly_caddq_native(a->coeffs);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);+ return;+ }+#endif /* MLD_USE_NATIVE_POLY_CADDQ */+ mld_poly_caddq_c(a);+}++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_SIGN_API) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+/* Reference: We use destructive version (output=first input) to avoid+ * reasoning about aliasing in the CBMC specification */+MLD_INTERNAL_API+void mld_poly_add(mld_poly *r, const mld_poly *b)+{+ unsigned int i;+ for (i = 0; i < MLDSA_N; ++i)+ __loop__(+ assigns(i, memory_slice(r, sizeof(mld_poly)))+ invariant(i <= MLDSA_N)+ invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0]))+ invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1]))+ invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX))+ invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN))+ decreases(MLDSA_N - i)+ )+ {+ r->coeffs[i] = r->coeffs[i] + b->coeffs[i];+ }+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_SIGN_API || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+/* Reference: We use destructive version (output=first input) to avoid+ * reasoning about aliasing in the CBMC specification */+MLD_INTERNAL_API+void mld_poly_sub(mld_poly *r, const mld_poly *b)+{+ unsigned int i;+ mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q);+ mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q);++ for (i = 0; i < MLDSA_N; ++i)+ __loop__(+ invariant(i <= MLDSA_N)+ invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))+ invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0]))+ decreases(MLDSA_N - i)+ )+ {+ r->coeffs[i] = r->coeffs[i] - b->coeffs[i];+ }++ mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX);+}+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_INTERNAL_API+void mld_poly_shiftl(mld_poly *a)+{+ unsigned int i;+ mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10);++ for (i = 0; i < MLDSA_N; i++)+ __loop__(+ invariant(i <= MLDSA_N)+ invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q))+ invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))+ decreases(MLDSA_N - i))+ {+ /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in+ * C90/C99+ */+ a->coeffs[i] *= (1 << MLDSA_D);+ }+ mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);+}+#endif /* !MLD_CONFIG_NO_VERIFY_API */++static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b)+__contract__(+ requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF)+ ensures(return_value > -MLD_FQMUL_BOUND && return_value < MLD_FQMUL_BOUND)+)+{+ /* Bounds: We argue in mld_montgomery_reduce() that the result+ * of Montgomery reduction is < MLDSA_Q if the input is smaller+ * than 2^31 * MLDSA_Q in absolute value. Indeed, we have:+ *+ * |a * b| = |a| * |b|+ * < 2^31 * MLDSA_Q_HALF+ * < 2^31 * MLDSA_Q+ *+ * So the output is < MLDSA_Q < MLD_FQMUL_BOUND.+ */+ return mld_montgomery_reduce((int64_t)a * (int64_t)b);+}++/* mld_ntt_butterfly_block()+ *+ * Computes a block CT butterflies with a fixed twiddle factor,+ * using Montgomery multiplication.+ *+ * Parameters:+ * - r: Pointer to base of polynomial (_not_ the base of butterfly block)+ * - zeta: Twiddle factor to use for the butterfly. This must be in+ * Montgomery form and signed canonical.+ * - start: Offset to the beginning of the butterfly block+ * - len: Index difference between coefficients subject to a butterfly+ * - bound: Ghost variable describing coefficient bound: Prior to `start`,+ * coefficients must be bound by `bound + MLDSA_Q`. Post `start`,+ * they must be bound by `bound`.+ * When this function returns, output coefficients in the index range+ * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`.+ * Example:+ * - start=8, len=4+ * This would compute the following four butterflies+ * 8 -- 12+ * 9 -- 13+ * 10 -- 14+ * 11 -- 15+ * - start=4, len=2+ * This would compute the following two butterflies+ * 4 -- 6+ * 5 -- 7+ */++/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */+static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N],+ const int32_t zeta,+ const unsigned start,+ const unsigned len,+ const uint32_t bound)+__contract__(+ requires(start < MLDSA_N)+ requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N)+ requires(0 <= bound && bound < INT32_MAX - MLD_FQMUL_BOUND)+ requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF)+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(array_abs_bound(r, 0, start, bound + MLD_FQMUL_BOUND))+ requires(array_abs_bound(r, start, MLDSA_N, bound))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(r, 0, start + 2*len, bound + MLD_FQMUL_BOUND))+ ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound)))+{+ /* `bound` is a ghost variable only needed in the CBMC specification */+ unsigned j;+ ((void)bound);+ for (j = start; j < start + len; j++)+ __loop__(+ invariant(start <= j && j <= start + len)+ /*+ * Coefficients are updated in strided pairs, so the bounds for the+ * intermediate states alternate twice between the old and new bound+ */+ invariant(array_abs_bound(r, 0, j, bound + MLD_FQMUL_BOUND))+ invariant(array_abs_bound(r, j, start + len, bound))+ invariant(array_abs_bound(r, start + len, j + len, bound + MLD_FQMUL_BOUND))+ invariant(array_abs_bound(r, j + len, MLDSA_N, bound))+ decreases(start + len - j))+ {+ int32_t t;+ t = mld_fqmul(r[j + len], zeta);+ r[j + len] = r[j] - t;+ r[j] = r[j] + t;+ }+}++/* mld_ntt_layer()+ *+ * Compute one layer of forward NTT+ *+ * Parameters:+ * - r: Pointer to base of polynomial+ * - layer: Indicates which layer is being applied.+ */++/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */+static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer)+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(1 <= layer && layer <= 8)+ requires(array_abs_bound(r, 0, MLDSA_N, layer * MLD_FQMUL_BOUND))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLD_FQMUL_BOUND)))+{+ unsigned start, k, len;+ /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */+ k = 1u << (layer - 1);+ len = (unsigned)MLDSA_N >> layer;+ for (start = 0; start < MLDSA_N; start += 2 * len)+ __loop__(+ invariant(start < MLDSA_N + 2 * len)+ invariant(k <= MLDSA_N)+ invariant(2 * len * k == start + MLDSA_N)+ invariant(array_abs_bound(r, 0, start, layer * MLD_FQMUL_BOUND + MLD_FQMUL_BOUND))+ invariant(array_abs_bound(r, start, MLDSA_N, layer * MLD_FQMUL_BOUND))+ decreases(MLDSA_N - start))+ {+ int32_t zeta = mld_zetas[k++];+ mld_ntt_butterfly_block(r, zeta, start, len, layer * MLD_FQMUL_BOUND);+ }+}++MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+)+{+ unsigned int layer;+ int32_t *r;+++ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);+ r = a->coeffs;++ for (layer = 1; layer < 9; layer++)+ __loop__(+ invariant(1 <= layer && layer <= 9)+ invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLD_FQMUL_BOUND))+ decreases(9 - layer)+ )+ {+ mld_ntt_layer(r, layer);+ }++ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND);+}++MLD_INTERNAL_API+void mld_poly_ntt(mld_poly *a)+{+#if defined(MLD_USE_NATIVE_NTT)+ int ret;+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);+ ret = mld_ntt_native(a->coeffs);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND);+ return;+ }+#endif /* MLD_USE_NATIVE_NTT */+ mld_poly_ntt_c(a);+}++/**+ * Scale a field element by mont/256, i.e., perform Montgomery multiplication+ * by mont^2/256.+ *+ * Input is expected to have absolute value smaller than 256 * MLDSA_Q. Output+ * has absolute value smaller than MLD_INTT_BOUND.+ *+ * @param a Field element to be scaled.+ */+static MLD_INLINE int32_t mld_fqscale(int32_t a)+__contract__(+ requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q)+ ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND)+)+{+ /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */+ const int32_t f = 41978;+ /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just+ * a special case of that in mld_fqmul(). */+ return mld_montgomery_reduce((int64_t)a * f);+}++/* Reference: Embedded into `invntt_tomont()` in the reference implementation+ * @[REF] */+static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer)+__contract__(+ requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))+ requires(1 <= layer && layer <= 8)+ requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))+ assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))+ ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q)))+{+ unsigned start, k, len;+ len = (unsigned)MLDSA_N >> layer;+ k = (1u << layer) - 1;+ for (start = 0; start < MLDSA_N; start += 2 * len)+ __loop__(+ invariant(start <= MLDSA_N && k <= 255)+ invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len)+ invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q))+ invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))+ decreases(MLDSA_N - start))+ {+ unsigned j;+ int32_t zeta = -mld_zetas[k--];++ /* The bound `(MLDSA_N >> (layer - 1)) * MLDSA_Q` is loose enough to+ * cover both the input bound `(MLDSA_N >> layer) * MLDSA_Q`+ * (for layers >= 1) and the fqmul output bound `MLD_FQMUL_BOUND`+ * (which is < 2 * MLDSA_Q <= (MLDSA_N >> (layer - 1)) * MLDSA_Q). */+ for (j = start; j < start + len; j++)+ __loop__(+ invariant(start <= j && j <= start + len)+ invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q))+ invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q))+ invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q))+ invariant(array_abs_bound(r, start + len, j + len, (MLDSA_N >> (layer - 1)) * MLDSA_Q))+ invariant(array_abs_bound(r, j + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))+ decreases(start + len - j))+ {+ int32_t t = r[j];+ r[j] = t + r[j + len];+ r[j + len] = t - r[j + len];+ r[j + len] = mld_fqmul(r[j + len], zeta);+ }+ }+}++MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND))+)+{+ unsigned int layer, j;+ int32_t *r;++ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);++ r = a->coeffs;+ for (layer = 8; layer >= 1; layer--)+ __loop__(+ invariant(layer <= 8)+ /* Absolute bounds increase from 1Q before layer 8 */+ /* up to 256Q after layer 1 */+ invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))+ decreases(layer))+ {+ mld_invntt_layer(r, layer);+ }++ /* Coefficient bounds are now at 256Q. We now scale by mont / 256,+ * i.e., compute the Montgomery multiplication by mont^2 / 256.+ * mont corrects the mont^-1 factor introduced in the basemul.+ * 1/256 performs that scaling of the inverse NTT.+ * The reduced value is bounded by MLD_INTT_BOUND in absolute+ * value.*/+ for (j = 0; j < MLDSA_N; ++j)+ __loop__(+ invariant(j <= MLDSA_N)+ invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND))+ invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q))+ decreases(MLDSA_N - j)+ )+ {+ r[j] = mld_fqscale(r[j]);+ }++ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND);+}+++MLD_INTERNAL_API+void mld_poly_invntt_tomont(mld_poly *a)+{+#if defined(MLD_USE_NATIVE_INTT)+ int ret;+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);+ ret = mld_intt_native(a->coeffs);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND);+ return;+ }+#endif /* MLD_USE_NATIVE_INTT */+ mld_poly_invntt_tomont_c(a);+}++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *a,+ const mld_poly *b)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(memory_no_alias(b, sizeof(mld_poly)))+ requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+ requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))+)+{+ unsigned int i;+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND);+ mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND);++ for (i = 0; i < MLDSA_N; ++i)+ __loop__(+ invariant(i <= MLDSA_N)+ invariant(array_abs_bound(a->coeffs, 0, i, MLDSA_Q))+ invariant(array_abs_bound(a->coeffs, i, MLDSA_N, MLD_NTT_BOUND))+ decreases(MLDSA_N - i)+ )+ {+ a->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]);+ }+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);+}++MLD_INTERNAL_API+void mld_poly_pointwise_montgomery(mld_poly *a, const mld_poly *b)+{+#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY)+ int ret;+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND);+ mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND);+ ret = mld_poly_pointwise_montgomery_native(a->coeffs, b->coeffs);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);+ return;+ }+#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */+ mld_poly_pointwise_montgomery_c(a, b);+}+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+MLD_INTERNAL_API+void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a)+{+ unsigned int i;+ mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);++ for (i = 0; i < MLDSA_N; ++i)+ __loop__(+ assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly)))+ invariant(i <= MLDSA_N)+ invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))+ invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))+ invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))+ decreases(MLDSA_N - i)+ )+ {+ mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]);+ }++ mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1,+ (MLD_2_POW_D / 2) + 1);+ mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1);+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#ifndef MLD_POLY_UNIFORM_NBLOCKS+#define MLD_POLY_UNIFORM_NBLOCKS \+ ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES)+#endif+/* Reference: `mld_rej_uniform()` in the reference implementation @[REF].+ * - Our signature differs from the reference implementation+ * in that it adds the offset and always expects the base of the+ * target buffer. This avoids shifting the buffer base in the+ * caller, which appears tricky to reason about. */+MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a,+ unsigned int target,+ unsigned int offset,+ const uint8_t *buf,+ unsigned int buflen)+__contract__(+ requires(offset <= target && target <= MLDSA_N)+ requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0)+ requires(memory_no_alias(a, sizeof(int32_t) * target))+ requires(memory_no_alias(buf, buflen))+ requires(array_bound(a, 0, offset, 0, MLDSA_Q))+ assigns(memory_slice(a, sizeof(int32_t) * target))+ ensures(offset <= return_value && return_value <= target)+ ensures(array_bound(a, 0, return_value, 0, MLDSA_Q))+)+{+ unsigned int ctr, pos;+ uint32_t t;+ mld_assert_bound(a, offset, 0, MLDSA_Q);++ ctr = offset;+ pos = 0;+ /* pos + 3 cannot overflow due to the assumption+ buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */+ while (ctr < target && pos + 3 <= buflen)+ __loop__(+ invariant(offset <= ctr && ctr <= target && pos <= buflen)+ invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))+ decreases(buflen - pos))+ {+ t = buf[pos++];+ t |= (uint32_t)buf[pos++] << 8;+ t |= (uint32_t)buf[pos++] << 16;+ t &= 0x7FFFFF;++ if (t < MLDSA_Q)+ {+ a[ctr++] = (int32_t)t;+ }+ }++ mld_assert_bound(a, ctr, 0, MLDSA_Q);++ return ctr;+}+/**+ * Sample uniformly random coefficients in [0, MLDSA_Q-1] by performing+ * rejection sampling on an array of random bytes.+ *+ * @param[out] a Pointer to output array (allocated).+ * @param target Requested number of coefficients to sample.+ * @param offset Number of coefficients already sampled.+ * @param[in] buf Array of random bytes to sample from.+ * @param buflen Length of array of random bytes (must be multiple of 3).+ *+ * @return Number of sampled coefficients. Can be smaller than len if not+ * enough random bytes were given.+ */++/* Reference: `mld_rej_uniform()` in the reference implementation @[REF].+ * - Our signature differs from the reference implementation+ * in that it adds the offset and always expects the base of the+ * target buffer. This avoids shifting the buffer base in the+ * caller, which appears tricky to reason about. */+static unsigned int mld_rej_uniform(int32_t *a, unsigned int target,+ unsigned int offset, const uint8_t *buf,+ unsigned int buflen)+__contract__(+ requires(offset <= target && target <= MLDSA_N)+ requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0)+ requires(memory_no_alias(a, sizeof(int32_t) * target))+ requires(memory_no_alias(buf, buflen))+ requires(array_bound(a, 0, offset, 0, MLDSA_Q))+ assigns(memory_slice(a, sizeof(int32_t) * target))+ ensures(offset <= return_value && return_value <= target)+ ensures(array_bound(a, 0, return_value, 0, MLDSA_Q))+)+{+#if defined(MLD_USE_NATIVE_REJ_UNIFORM)+ int ret;+ mld_assert_bound(a, offset, 0, MLDSA_Q);+ if (offset == 0)+ {+ ret = mld_rej_uniform_native(a, target, buf, buflen);+ if (ret != MLD_NATIVE_FUNC_FALLBACK)+ {+ unsigned res = (unsigned)ret;+ mld_assert_bound(a, res, 0, MLDSA_Q);+ return res;+ }+ }+#endif /* MLD_USE_NATIVE_REJ_UNIFORM */++ return mld_rej_uniform_c(a, target, offset, buf, buflen);+}++/* Reference: poly_uniform() in the reference implementation @[REF].+ * - Simplified from reference by removing buffer tail handling+ * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES+ * = 168).+ * - Modified rej_uniform interface to track offset directly.+ * - Pass nonce packed in the extended seed array instead of a third+ * argument.+ * */+MLD_INTERNAL_API+void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2])+{+ unsigned int ctr;+ unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES;+ MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES];+ mld_xof128_ctx state;++ mld_xof128_init(&state);+ mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2);+ mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state);++ ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen);+ buflen = MLD_STREAM128_BLOCKBYTES;+ while (ctr < MLDSA_N)+ __loop__(+ assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf))+ invariant(ctr <= MLDSA_N)+ invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q))+ invariant(state.pos <= SHAKE128_RATE)+ )+ {+ mld_xof128_squeezeblocks(buf, 1, &state);+ ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen);+ }+ mld_xof128_release(&state);+ mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(buf, sizeof(buf));+}++#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+MLD_INTERNAL_API+void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2,+ mld_poly *vec3,+ uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)])+{+ /* Temporary buffers for XOF output before rejection sampling */+ MLD_ALIGN uint8_t+ buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)];++ /* Tracks the number of coefficients we have already sampled */+ unsigned ctr[4];+ mld_xof128_x4_ctx state;+ unsigned buflen;++ mld_xof128_x4_init(&state);+ mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2);++ /*+ * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS.+ * This should generate the matrix entries with high probability.+ */++ mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state);+ buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES;+ ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen);+ ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen);+ ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen);+ ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen);++ /*+ * So long as not all matrix entries have been generated, squeeze+ * one more block a time until we're done.+ */+ buflen = MLD_STREAM128_BLOCKBYTES;+ while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N ||+ ctr[3] < MLDSA_N)+ __loop__(+ assigns(ctr, state, object_whole(buf),+ memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)),+ memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly)))+ invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N)+ invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N)+ invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q))+ invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q))+ invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q))+ invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q)))+ {+ mld_xof128_x4_squeezeblocks(buf, 1, &state);+ ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen);+ ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen);+ ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen);+ ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen);+ }+ mld_xof128_x4_release(&state);++ mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q);+ mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q);+ mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q);+ mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(buf, sizeof(buf));+}++#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && (!MLD_CONFIG_REDUCE_RAM || \+ MLD_UNIT_TEST) */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+MLD_INTERNAL_API+void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a)+{+ unsigned int i;+ mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10);++ for (i = 0; i < MLDSA_N / 4; ++i)+ __loop__(+ invariant(i <= MLDSA_N/4)+ decreases(MLDSA_N / 4 - i))+ {+ r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF);+ r[5 * i + 1] =+ (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) &+ 0xFF);+ r[5 * i + 2] =+ (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) &+ 0xFF);+ r[5 * i + 3] =+ (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) &+ 0xFF);+ r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF);+ }+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_INTERNAL_API+void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES])+{+ unsigned int i;++ for (i = 0; i < MLDSA_N / 4; ++i)+ __loop__(+ invariant(i <= MLDSA_N/4)+ invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))+ decreases(MLDSA_N / 4 - i))+ {+ r->coeffs[4 * i + 0] =+ ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF;+ r->coeffs[4 * i + 1] =+ ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF;+ r->coeffs[4 * i + 2] =+ ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF;+ r->coeffs[4 * i + 3] =+ ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF;+ }++ mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10);+}+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+MLD_INTERNAL_API+void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a)+{+ unsigned int i;+ uint32_t t[8];++ mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1,+ (1 << (MLDSA_D - 1)) + 1);++ for (i = 0; i < MLDSA_N / 8; ++i)+ __loop__(+ invariant(i <= MLDSA_N/8)+ decreases(MLDSA_N / 8 - i))+ {+ /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of+ * power2round, hence, these casts are safe. */+ t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]);+ t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]);+ t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]);+ t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]);+ t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]);+ t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]);+ t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]);+ t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]);++ r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF);+ r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF);+ r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF);+ r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF);+ r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF);+ r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF);+ r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF);+ r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF);+ r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF);+ r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF);+ r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF);+ r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF);+ r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF);+ r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF);+ r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF);+ r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF);+ r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF);+ r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF);+ r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF);+ r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF);+ }+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)+MLD_INTERNAL_API+void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES])+{+ unsigned int i;++ for (i = 0; i < MLDSA_N / 8; ++i)+ __loop__(+ invariant(i <= MLDSA_N/8)+ invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))+ decreases(MLDSA_N / 8 - i))+ {+ r->coeffs[8 * i + 0] = a[13 * i + 0];+ r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8;+ r->coeffs[8 * i + 0] &= 0x1FFF;++ r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5;+ r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3;+ r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11;+ r->coeffs[8 * i + 1] &= 0x1FFF;++ r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2;+ r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6;+ r->coeffs[8 * i + 2] &= 0x1FFF;++ r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7;+ r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1;+ r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9;+ r->coeffs[8 * i + 3] &= 0x1FFF;++ r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4;+ r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4;+ r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12;+ r->coeffs[8 * i + 4] &= 0x1FFF;++ r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1;+ r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7;+ r->coeffs[8 * i + 5] &= 0x1FFF;++ r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6;+ r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2;+ r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10;+ r->coeffs[8 * i + 6] &= 0x1FFF;++ r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3;+ r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5;+ r->coeffs[8 * i + 7] &= 0x1FFF;++ r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0];+ r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1];+ r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2];+ r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3];+ r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4];+ r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5];+ r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6];+ r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7];+ }++ mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1,+ (1 << (MLDSA_D - 1)) + 1);+}+#endif /* !MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST */++MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX)+ requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))+ ensures(return_value == 0 || return_value == 0xFFFFFFFF)+ ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B))+)+{+ unsigned int i;+ uint32_t t = 0;+ mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,+ MLD_REDUCE32_RANGE_MAX);+ for (i = 0; i < MLDSA_N; ++i)+ __loop__(+ invariant(i <= MLDSA_N)+ invariant(t == 0 || t == 0xFFFFFFFF)+ invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B))+ decreases(MLDSA_N - i)+ )+ {+ /*+ * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX,+ * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if+ * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B.+ *+ * We prove this to be true using the following CBMC assertions.+ * a ==> b expressed as !a || b to also allow run-time assertion.+ */+ mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B);+ mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B);++ /* Reference: Leaks which coefficient violates the bound via a conditional.+ * We are more conservative to reduce the number of declassifications in+ * constant-time testing.+ */++ /* if (abs(a[i]) >= B) */+ t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i]));+ }++ return t;+}++/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8).+ * This is unnecessary as it's always a compile-time constant.+ * We instead model it as a precondition.+ * Checking the bound is performed using a conditional arguing+ * that it is okay to leak which coefficient violates the bound (while the+ * coefficient itself must remain secret).+ * We instead perform everything in constant-time.+ * Also it is sufficient to check that it is smaller than+ * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8).+ */+MLD_INTERNAL_API+uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B)+{+#if defined(MLD_USE_NATIVE_POLY_CHKNORM)+ int ret;+ int success;+ mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,+ MLD_REDUCE32_RANGE_MAX);+ /* The native backend returns 0 if all coefficients are within the bound,+ * 1 if at least one coefficient exceeds the bound, and+ * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the+ * required capabilities to run the native function.+ */+ ret = mld_poly_chknorm_native(a->coeffs, B);++ success = (ret != MLD_NATIVE_FUNC_FALLBACK);+ /* Constant-time: It would be fine to leak the return value of chknorm+ * entirely (as it is fine to leak if any coefficient exceeded the bound or+ * not). However, it is cleaner to perform declassification in sign.c.+ * Hence, here we only declassify if the native function returned+ * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system+ * capabilities).+ */+ MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int));+ if (success)+ {+ /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */+ return mld_ct_cmask_nonzero_u32((uint32_t)ret);+ }+#endif /* MLD_USE_NATIVE_POLY_CHKNORM */+ return mld_poly_chknorm_c(a, B);+}++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ MLD_CONFIG_PARAMETER_SET == 44+MLD_INTERNAL_API+void mld_polyw1_pack_88(uint8_t r[MLDSA_POLYW1_PACKEDBYTES_88],+ const mld_poly *a)+{+ unsigned int i;++ mld_assert_bound(a->coeffs, MLDSA_N, 0,+ (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2_88));++ for (i = 0; i < MLDSA_N / 4; ++i)+ __loop__(+ invariant(i <= MLDSA_N/4)+ decreases(MLDSA_N / 4 - i))+ {+ r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF);+ r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF);+ r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF);+ r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF);+ r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF);+ r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF);+ }+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+MLD_INTERNAL_API+void mld_polyw1_pack_32(uint8_t r[MLDSA_POLYW1_PACKEDBYTES_32],+ const mld_poly *a)+{+ unsigned int i;++ mld_assert_bound(a->coeffs, MLDSA_N, 0,+ (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2_32));++ for (i = 0; i < MLDSA_N / 2; ++i)+ __loop__(+ invariant(i <= MLDSA_N/2)+ decreases(MLDSA_N / 2 - i))+ {+ r[i] =+ (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF);+ }+}+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */+MLD_EMPTY_CU(mld_poly)+#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef MLD_POLY_UNIFORM_NBLOCKS
@@ -0,0 +1,464 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#ifndef MLD_POLY_H+#define MLD_POLY_H++#include "cbmc.h"+#include "common.h"+#include "reduce.h"+#include "rounding.h"++/* Absolute exclusive upper bound for the output of fqmul */+#define MLD_FQMUL_BOUND ((5 * MLDSA_Q + 3) / 4)+/* Absolute exclusive upper bound for the output of the forward NTT */+#define MLD_NTT_BOUND (9 * MLD_FQMUL_BOUND)+/* Absolute exclusive upper bound for the output of the inverse NTT*/+#define MLD_INTT_BOUND MLDSA_Q++/**+ * Element of R_q = Z_q[X]/(X^n + 1). Represents polynomial+ * coeffs[0] + X*coeffs[1] + X^2*coeffs[2] + ... + X^{n-1}*coeffs[n-1].+ */+typedef struct+{+ int32_t coeffs[MLDSA_N]; /**< Polynomial coefficients. */+} MLD_ALIGN mld_poly;++#define mld_poly_reduce MLD_NAMESPACE(poly_reduce)+/**+ * In-place reduction of all coefficients of polynomial to representative in+ * [-MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX].+ *+ * @param[in,out] a Pointer to input/output polynomial.+ */+MLD_INTERNAL_API+void mld_poly_reduce(mld_poly *a)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))+);++#define mld_poly_caddq MLD_NAMESPACE(poly_caddq)+/**+ * For all coefficients of in/out polynomial add MLDSA_Q if coefficient is+ * negative.+ *+ * @param[in,out] a Pointer to input/output polynomial.+ */+MLD_INTERNAL_API+void mld_poly_caddq(mld_poly *a)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+);++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_SIGN_API) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+#define mld_poly_add MLD_NAMESPACE(poly_add)+/**+ * Add polynomials. No modular reduction is performed.+ *+ * @spec{Implements @[FIPS204, Algorithm 44, AddNTT] (coefficientwise+ * polynomial addition; also used for addition in the normal domain).}+ *+ * @param[in,out] r Pointer to input-output polynomial to be added to.+ * @param[in] b Pointer to input polynomial that should be added to r.+ * Must be disjoint from r.+ */++/*+ * NOTE: The reference implementation uses a 3-argument poly_add.+ * We specialize to the accumulator form to avoid reasoning about aliasing.+ */+MLD_INTERNAL_API+void mld_poly_add(mld_poly *r, const mld_poly *b)+__contract__(+ requires(memory_no_alias(b, sizeof(mld_poly)))+ requires(memory_no_alias(r, sizeof(mld_poly)))+ requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX))+ requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN))+ assigns(memory_slice(r, sizeof(mld_poly)))+ ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2]))+ ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX))+ ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_SIGN_API || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_poly_sub MLD_NAMESPACE(poly_sub)+/**+ * Subtract polynomials. No modular reduction is performed.+ *+ * @param[in,out] r Pointer to input-output polynomial.+ * @param[in] b Pointer to input polynomial that should be subtracted from+ * r. Must be disjoint from r.+ */+/*+ * NOTE: The reference implementation uses a 3-argument poly_sub.+ * We specialize to the accumulator form to avoid reasoning about aliasing.+ */+MLD_INTERNAL_API+void mld_poly_sub(mld_poly *r, const mld_poly *b)+__contract__(+ requires(memory_no_alias(b, sizeof(mld_poly)))+ requires(memory_no_alias(r, sizeof(mld_poly)))+ requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q))+ requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(r, sizeof(mld_poly)))+ ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))+);+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl)+/**+ * Multiply polynomial by 2^MLDSA_D without modular reduction. Assumes input+ * coefficients to be less than 2^{31-MLDSA_D} in absolute value.+ *+ * @param[in,out] a Pointer to input/output polynomial.+ */+MLD_INTERNAL_API+void mld_poly_shiftl(mld_poly *a)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#define mld_poly_ntt MLD_NAMESPACE(poly_ntt)+/**+ * In-place forward NTT. Output coefficients are bounded by MLD_NTT_BOUND in+ * absolute value.+ *+ * @spec{Implements @[FIPS204, Algorithm 41, NTT].}+ *+ * @param[in,out] a Pointer to input/output polynomial.+ */+MLD_INTERNAL_API+void mld_poly_ntt(mld_poly *a)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+);+++#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont)+/**+ * In-place inverse NTT.+ *+ * Input coefficients need to be less than MLDSA_Q in absolute value and+ * output coefficients are bounded by MLD_INTT_BOUND.+ *+ * @spec{Implements @[FIPS204, Algorithm 42, NTT^{-1}] up to scaling:+ * The input is scaled by 2^{-32} as a result of the Montgomery base+ * multiplication. The output is in normal domain. In other words, this+ * function implements `NTT^{-1} o mult(2^32)`.}+ *+ * @param[in,out] a Pointer to input/output polynomial.+ */+MLD_INTERNAL_API+void mld_poly_invntt_tomont(mld_poly *a)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND))+);++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery)+/**+ * Pointwise multiplication of polynomials. Destructive in the first argument.+ *+ * @spec{Implements @[FIPS204, Algorithm 45, MultiplyNTT], up to scaling: The+ * input is in normal domain, the output is scaled by 2^{-32} as a result of+ * the use of Montgomery multiplication. In other words, this function+ * implements `mult(2^{-32}) o MultiplyNTT`.}+ *+ * @param[in,out] a Pointer to first input/output polynomial. On entry, holds+ * the first multiplicand; on exit, holds the product+ * a * b * 2^{-32}.+ * @param[in] b Pointer to second input polynomial.+ */+MLD_INTERNAL_API+void mld_poly_pointwise_montgomery(mld_poly *a, const mld_poly *b)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(memory_no_alias(b, sizeof(mld_poly)))+ requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+ requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))+);+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_poly_power2round MLD_NAMESPACE(poly_power2round)+/**+ * For all coefficients c of the input polynomial, compute c0, c1 such that+ * c mod MLDSA_Q = c1*2^MLDSA_D + c0 with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}.+ * Assumes coefficients to be standard representatives.+ *+ * @param[out] a1 Pointer to output polynomial with coefficients c1.+ * @param[out] a0 Pointer to output polynomial with coefficients c0; may alias+ * the input polynomial a.+ * @param[in] a Pointer to input polynomial.+ */+MLD_INTERNAL_API+void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a)+__contract__(+ requires(memory_no_alias(a0, sizeof(mld_poly)))+ requires(memory_no_alias(a1, sizeof(mld_poly)))+ /* The implementation does not require a0 == a, but the single call site+ * aliases them and asserting equality simplifies the proof. */+ requires(a0 == a)+ requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(a1, sizeof(mld_poly)))+ assigns(memory_slice(a0, sizeof(mld_poly)))+ ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))+ ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#define mld_poly_uniform MLD_NAMESPACE(poly_uniform)+/**+ * Sample polynomial with uniformly random coefficients in [0, MLDSA_Q-1] by+ * performing rejection sampling on the output stream of SHAKE128(seed|nonce).+ *+ * @spec{Implements @[FIPS204, Algorithm 30, RejNTTPoly].}+ *+ * @param[out] a Pointer to output polynomial.+ * @param[in] seed Byte array with seed of length MLDSA_SEEDBYTES and the+ * packed 2-byte nonce.+ */+MLD_INTERNAL_API+void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2])+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+);++#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x)+/**+ * Generate four polynomials using rejection sampling on (pseudo-)uniformly+ * random bytes sampled from a seed.+ *+ * @spec{Implements @[FIPS204, Algorithm 30, RejNTTPoly] (four-way batched).}+ *+ * @param[out] vec0 Pointer to first polynomial to be sampled.+ * @param[out] vec1 Pointer to second polynomial to be sampled.+ * @param[out] vec2 Pointer to third polynomial to be sampled.+ * @param[out] vec3 Pointer to fourth polynomial to be sampled.+ * @param[in] seed Pointer to consecutive array of seed buffers of size+ * MLDSA_SEEDBYTES + 2 each, plus padding for alignment.+ */+MLD_INTERNAL_API+void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2,+ mld_poly *vec3,+ uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)])+__contract__(+ requires(memory_no_alias(vec0, sizeof(mld_poly)))+ requires(memory_no_alias(vec1, sizeof(mld_poly)))+ requires(memory_no_alias(vec2, sizeof(mld_poly)))+ requires(memory_no_alias(vec3, sizeof(mld_poly)))+ requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)))+ assigns(memory_slice(vec0, sizeof(mld_poly)))+ assigns(memory_slice(vec1, sizeof(mld_poly)))+ assigns(memory_slice(vec2, sizeof(mld_poly)))+ assigns(memory_slice(vec3, sizeof(mld_poly)))+ ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+ ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+ ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+ ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+);+#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && (!MLD_CONFIG_REDUCE_RAM || \+ MLD_UNIT_TEST) */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack)+/**+ * Bit-pack polynomial t1 with coefficients fitting in 10 bits. Input+ * coefficients are assumed to be standard representatives.+ *+ * @spec{Implements @[FIPS204, Algorithm 16, SimpleBitPack].}+ *+ * @param[out] r Pointer to output byte array with at least+ * MLDSA_POLYT1_PACKEDBYTES bytes.+ * @param[in] a Pointer to input polynomial.+ */+MLD_INTERNAL_API+void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a)+__contract__(+ requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES))+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10))+ assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack)+/**+ * Unpack polynomial t1 with 10-bit coefficients. Output coefficients are+ * standard representatives.+ *+ * @spec{Implements @[FIPS204, Algorithm 18, SimpleBitUnpack].}+ *+ * @param[out] r Pointer to output polynomial.+ * @param[in] a Byte array with bit-packed polynomial.+ */+MLD_INTERNAL_API+void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(r, sizeof(mld_poly)))+ requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES))+ assigns(memory_slice(r, sizeof(mld_poly)))+ ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10))+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack)+/**+ * Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}].+ *+ * @spec{Implements @[FIPS204, Algorithm 17, BitPack].}+ *+ * @param[out] r Pointer to output byte array with at least+ * MLDSA_POLYT0_PACKEDBYTES bytes.+ * @param[in] a Pointer to input polynomial.+ */+MLD_INTERNAL_API+void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a)+__contract__(+ requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES))+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))+ assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)+#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack)+/**+ * Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}].+ *+ * @spec{Implements @[FIPS204, Algorithm 19, BitUnpack].}+ *+ * @param[out] r Pointer to output polynomial.+ * @param[in] a Byte array with bit-packed polynomial.+ */+MLD_INTERNAL_API+void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(r, sizeof(mld_poly)))+ requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES))+ assigns(memory_slice(r, sizeof(mld_poly)))+ ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))+);+#endif /* !MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST */++#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm)+/**+ * Check infinity norm of polynomial against given bound. Assumes input+ * coefficients were reduced by mld_reduce32().+ *+ * @spec{@[FIPS204] defines the infinity norm via signed canonical reduction+ * (mod± MLDSA_Q) prior to applying the bounds check. However,+ * `-B < (a mod± MLDSA_Q) < B` is equivalent to `-B < a < B` under the+ * assumption that `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in+ * the code). Hence, this contract and implementation are correct without+ * reduction.}+ *+ * @param[in] a Pointer to polynomial.+ * @param B Norm bound.+ *+ * @return 0 if norm is strictly smaller than+ * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise.+ */+MLD_INTERNAL_API+MLD_MUST_CHECK_RETURN_VALUE+uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX)+ requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))+ ensures(return_value == 0 || return_value == 0xFFFFFFFF)+ ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B))+);++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44+#define mld_polyw1_pack_88 MLD_NAMESPACE(polyw1_pack_88)+/**+ * Bit-pack polynomial w1, using 6 bits per coefficient.+ * This is the variant for parameter sets with MLDSA_GAMMA2 = (MLDSA_Q-1)/88+ * (ML-DSA-44), for which w1 coefficients lie in [0, 43].+ *+ * @param[out] r Pointer to output byte array (MLDSA_POLYW1_PACKEDBYTES_88).+ * @param[in] a Pointer to input polynomial.+ */+MLD_INTERNAL_API+void mld_polyw1_pack_88(uint8_t r[MLDSA_POLYW1_PACKEDBYTES_88],+ const mld_poly *a)+__contract__(+ requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES_88))+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2_88)))+ assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES_88))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 44 \+ */++#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+#define mld_polyw1_pack_32 MLD_NAMESPACE(polyw1_pack_32)+/**+ * Bit-pack polynomial w1, using 4 bits per coefficient.+ * This is the variant for parameter sets with MLDSA_GAMMA2 = (MLDSA_Q-1)/32+ * (ML-DSA-65 and ML-DSA-87), for which w1 coefficients lie in [0, 15].+ *+ * @param[out] r Pointer to output byte array (MLDSA_POLYW1_PACKEDBYTES_32).+ * @param[in] a Pointer to input polynomial.+ */+MLD_INTERNAL_API+void mld_polyw1_pack_32(uint8_t r[MLDSA_POLYW1_PACKEDBYTES_32],+ const mld_poly *a)+__contract__(+ requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES_32))+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2_32)))+ assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES_32))+);+#endif /* MLD_CONFIG_MULTILEVEL_WITH_SHARED || MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87 */+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#endif /* !MLD_POLY_H */
@@ -0,0 +1,910 @@+/*+ * Copyright (c) The mldsa-native project authors+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ *+ * - [REF]+ * CRYSTALS-Dilithium reference implementation+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/dilithium/tree/master/ref+ */++#include "poly_kl.h"++#include "ct.h"+#include "debug.h"+#include "rounding.h"+#include "symmetric.h"++/* Parameter set namespacing+ * This is to facilitate building multiple instances+ * of mldsa-native (e.g. with varying parameter sets)+ * within a single compilation unit. */+#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta)+#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c)+#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c)+#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c)+#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c)+/* End of parameter set namespacing */+++#if !defined(MLD_CONFIG_NO_SIGN_API)+MLD_STATIC_TESTABLE+void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0)+__contract__(+ requires(memory_no_alias(a1, sizeof(mld_poly)))+ requires(memory_no_alias(a0, sizeof(mld_poly)))+ requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(a1, sizeof(mld_poly)))+ assigns(memory_slice(a0, sizeof(mld_poly)))+ ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+ ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))+)+{+ unsigned int i;+ mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q);+ for (i = 0; i < MLDSA_N; ++i)+ __loop__(+ assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly)))+ invariant(i <= MLDSA_N)+ invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q))+ invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+ invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1))+ decreases(MLDSA_N - i)+ )+ {+ mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]);+ }++ mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1);+ mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));+}++MLD_INTERNAL_API+void mld_poly_decompose(mld_poly *a1, mld_poly *a0)+{+#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44+ int ret;+ mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q);+ ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1);+ mld_assert_bound(a1->coeffs, MLDSA_N, 0,+ (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));+ return;+ }+#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+ int ret;+ mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q);+ ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1);+ mld_assert_bound(a1->coeffs, MLDSA_N, 0,+ (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));+ return;+ }+#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \+ 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \+ == 65 || MLD_CONFIG_PARAMETER_SET == 87) */+ mld_poly_decompose_c(a1, a0);+}++#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *a, const mld_poly *h)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(memory_no_alias(h, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+ requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+)+{+ unsigned int i;+ mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);+ mld_assert_bound(h->coeffs, MLDSA_N, 0, 2);++ for (i = 0; i < MLDSA_N; ++i)+ __loop__(+ invariant(i <= MLDSA_N)+ invariant(array_bound(a->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+ invariant(array_bound(a->coeffs, i, MLDSA_N, 0, MLDSA_Q))+ decreases(MLDSA_N - i)+ )+ {+ a->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]);+ }+ mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));+}++MLD_INTERNAL_API+void mld_poly_use_hint(mld_poly *a, const mld_poly *h)+{+#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44+ int ret;+ mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);+ mld_assert_bound(h->coeffs, MLDSA_N, 0, 2);+ ret = mld_poly_use_hint_88_native(a->coeffs, h->coeffs);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));+ return;+ }+#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+ int ret;+ mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);+ mld_assert_bound(h->coeffs, MLDSA_N, 0, 2);+ ret = mld_poly_use_hint_32_native(a->coeffs, h->coeffs);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));+ return;+ }+#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \+ && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \+ 65 || MLD_CONFIG_PARAMETER_SET == 87) */+ mld_poly_use_hint_c(a, h);+}+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+/**+ * Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] by+ * performing rejection sampling on an array of random bytes.+ *+ * @param[out] a Pointer to output array (allocated).+ * @param target Requested number of coefficients to sample.+ * @param offset Number of coefficients already sampled.+ * @param[in] buf Array of random bytes to sample from.+ * @param buflen Length of array of random bytes.+ *+ * @return Number of sampled coefficients. Can be smaller than target if not+ * enough random bytes were given.+ */++/* Reference: `mld_rej_eta()` in the reference implementation @[REF].+ * - Our signature differs from the reference implementation+ * in that it adds the offset and always expects the base of the+ * target buffer. This avoids shifting the buffer base in the+ * caller, which appears tricky to reason about. */+#if MLDSA_ETA == 2+/*+ * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits.+ * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes.+ * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially.+ * Sampling 2 blocks initially results in slightly worse performance.+ */+#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1+#elif MLDSA_ETA == 4+/*+ * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits.+ * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes.+ * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially.+ */+#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2+#else /* MLDSA_ETA == 4 */+#error "Invalid value of MLDSA_ETA"+#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */++MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target,+ unsigned int offset,+ const uint8_t *buf,+ unsigned int buflen)+__contract__(+ requires(offset <= target && target <= MLDSA_N)+ requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES))+ requires(memory_no_alias(a, sizeof(int32_t) * target))+ requires(memory_no_alias(buf, buflen))+ requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1))+ assigns(memory_slice(a, sizeof(int32_t) * target))+ ensures(offset <= return_value && return_value <= target)+ ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1))+)+{+ unsigned int ctr, pos;+ int t_valid;+ uint32_t t0, t1;+ mld_assert_abs_bound(a, offset, MLDSA_ETA + 1);+ ctr = offset;+ pos = 0;+ while (ctr < target && pos < buflen)+ __loop__(+ invariant(offset <= ctr && ctr <= target && pos <= buflen)+ invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1))+ decreases(buflen - pos)+ )+ {+ t0 = buf[pos] & 0x0F;+ t1 = buf[pos++] >> 4;++ /* Constant time: The inputs and outputs to the rejection sampling are+ * secret. However, it is fine to leak which coefficients have been+ * rejected. For constant-time testing, we declassify the result of+ * the comparison.+ */+#if MLDSA_ETA == 2+ t_valid = t0 < 15;+ MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int));+ if (t_valid) /* t0 < 15 */+ {+ t0 = t0 - (205 * t0 >> 10) * 5;+ a[ctr++] = 2 - (int32_t)t0;+ }+ t_valid = t1 < 15;+ MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int));+ if (t_valid && ctr < target) /* t1 < 15 */+ {+ t1 = t1 - (205 * t1 >> 10) * 5;+ a[ctr++] = 2 - (int32_t)t1;+ }+#elif MLDSA_ETA == 4+ t_valid = t0 < 9;+ MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int));+ if (t_valid) /* t0 < 9 */+ {+ a[ctr++] = 4 - (int32_t)t0;+ }+ t_valid = t1 < 9; /* t1 < 9 */+ MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int));+ if (t_valid && ctr < target)+ {+ a[ctr++] = 4 - (int32_t)t1;+ }+#else /* MLDSA_ETA == 4 */+#error "Invalid value of MLDSA_ETA"+#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */+ }++ mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1);++ return ctr;+}++static unsigned int mld_rej_eta(int32_t *a, unsigned int target,+ unsigned int offset, const uint8_t *buf,+ unsigned int buflen)+__contract__(+ requires(offset <= target && target <= MLDSA_N)+ requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES))+ requires(memory_no_alias(a, sizeof(int32_t) * target))+ requires(memory_no_alias(buf, buflen))+ requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1))+ assigns(memory_slice(a, sizeof(int32_t) * target))+ ensures(offset <= return_value && return_value <= target)+ ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1))+)+{+#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2)+ int ret;+ mld_assert_abs_bound(a, offset, MLDSA_ETA + 1);+ if (offset == 0)+ {+ ret = mld_rej_uniform_eta2_native(a, target, buf, buflen);+ if (ret != MLD_NATIVE_FUNC_FALLBACK)+ {+ unsigned res = (unsigned)ret;+ mld_assert_abs_bound(a, res, MLDSA_ETA + 1);+ return res;+ }+ }+#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4)+ int ret;+ mld_assert_abs_bound(a, offset, MLDSA_ETA + 1);+ if (offset == 0)+ {+ ret = mld_rej_uniform_eta4_native(a, target, buf, buflen);+ if (ret != MLD_NATIVE_FUNC_FALLBACK)+ {+ unsigned res = (unsigned)ret;+ mld_assert_abs_bound(a, res, MLDSA_ETA + 1);+ return res;+ }+ }+#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \+ 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */++ return mld_rej_eta_c(a, target, offset, buf, buflen);+}++#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+MLD_INTERNAL_API+void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2,+ mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES],+ uint8_t nonce0, uint8_t nonce1, uint8_t nonce2,+ uint8_t nonce3)+{+ /* Temporary buffers for XOF output before rejection sampling */+ MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS *+ MLD_STREAM256_BLOCKBYTES)];++ MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)];++ /* Tracks the number of coefficients we have already sampled */+ unsigned ctr[4];+ mld_xof256_x4_ctx state;+ unsigned buflen;++ mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES);+ mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES);+ mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES);+ mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES);+ extseed[0][MLDSA_CRHBYTES] = nonce0;+ extseed[1][MLDSA_CRHBYTES] = nonce1;+ extseed[2][MLDSA_CRHBYTES] = nonce2;+ extseed[3][MLDSA_CRHBYTES] = nonce3;+ extseed[0][MLDSA_CRHBYTES + 1] = 0;+ extseed[1][MLDSA_CRHBYTES + 1] = 0;+ extseed[2][MLDSA_CRHBYTES + 1] = 0;+ extseed[3][MLDSA_CRHBYTES + 1] = 0;++ mld_xof256_x4_init(&state);+ mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2);++ /*+ * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS.+ * This should generate the coefficients with high probability.+ */+ mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state);+ buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES;++ ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen);+ ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen);+ ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen);+ ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen);++ /*+ * So long as not all entries have been generated, squeeze+ * one more block at a time until we're done.+ */+ buflen = MLD_STREAM256_BLOCKBYTES;+ while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N ||+ ctr[3] < MLDSA_N)+ __loop__(+ assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)),+ memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)),+ memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]),+ object_whole(buf[1]), object_whole(buf[2]),+ object_whole(buf[3]))+ invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N)+ invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N)+ invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1))+ invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1))+ invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1))+ invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1)))+ {+ mld_xof256_x4_squeezeblocks(buf, 1, &state);+ ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen);+ ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen);+ ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen);+ ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen);+ }++ mld_xof256_x4_release(&state);++ mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1);+ mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1);+ mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1);+ mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(buf, sizeof(buf));+ mld_zeroize(extseed, sizeof(extseed));+}+#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */++MLD_INTERNAL_API+void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES],+ uint8_t nonce)+{+ /* Temporary buffer for XOF output before rejection sampling */+ MLD_ALIGN uint8_t+ buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES];+ MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2];++ /* Tracks the number of coefficients we have already sampled */+ unsigned ctr;+ mld_xof256_ctx state;+ unsigned buflen;++ mld_memcpy(extseed, seed, MLDSA_CRHBYTES);+ extseed[MLDSA_CRHBYTES] = nonce;+ extseed[MLDSA_CRHBYTES + 1] = 0;++ mld_xof256_init(&state);+ mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2);++ /*+ * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS.+ * This should generate the coefficients with high probability.+ */+ mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state);+ buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES;++ ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen);++ /*+ * So long as not all entries have been generated, squeeze+ * one more block at a time until we're done.+ */+ buflen = MLD_STREAM256_BLOCKBYTES;+ while (ctr < MLDSA_N)+ __loop__(+ assigns(ctr, object_whole(&state),+ object_whole(buf), memory_slice(r, sizeof(mld_poly)))+ invariant(ctr <= MLDSA_N)+ invariant(state.pos <= SHAKE256_RATE)+ invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1)))+ {+ mld_xof256_squeezeblocks(buf, 1, &state);+ ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen);+ }++ mld_xof256_release(&state);++ mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(buf, sizeof(buf));+ mld_zeroize(extseed, sizeof(extseed));+}+#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \+ ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \+ MLD_STREAM256_BLOCKBYTES)++#if MLD_CONFIG_PARAMETER_SET == 65 || \+ defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+MLD_INTERNAL_API+void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES],+ uint16_t nonce)+{+ MLD_ALIGN uint8_t+ buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES];+ MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2];+ mld_xof256_ctx state;++ mld_memcpy(extseed, seed, MLDSA_CRHBYTES);+ extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF);+ extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8);++ mld_xof256_init(&state);+ mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2);++ mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state);+ mld_polyz_unpack(a, buf);++ mld_xof256_release(&state);++ mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(buf, sizeof(buf));+ mld_zeroize(extseed, sizeof(extseed));+}+#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */+++#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+MLD_INTERNAL_API+void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2,+ mld_poly *r3,+ const uint8_t seed[MLDSA_CRHBYTES],+ uint16_t nonce0, uint16_t nonce1,+ uint16_t nonce2, uint16_t nonce3)+{+ /* Temporary buffers for XOF output before rejection sampling */+ MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS *+ MLD_STREAM256_BLOCKBYTES)];++ MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)];++ /* Tracks the number of coefficients we have already sampled */+ mld_xof256_x4_ctx state;++ mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES);+ mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES);+ mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES);+ mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES);+ extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF);+ extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF);+ extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF);+ extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF);+ extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8);+ extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8);+ extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8);+ extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8);++ mld_xof256_x4_init(&state);+ mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2);+ mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state);++ mld_polyz_unpack(r0, buf[0]);+ mld_polyz_unpack(r1, buf[1]);+ mld_polyz_unpack(r2, buf[2]);+ mld_polyz_unpack(r3, buf[3]);+ mld_xof256_x4_release(&state);++ mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);+ mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);+ mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);+ mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(buf, sizeof(buf));+ mld_zeroize(extseed, sizeof(extseed));+}+#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && (!MLD_CONFIG_REDUCE_RAM || \+ MLD_UNIT_TEST) */+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_INTERNAL_API+void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES])+{+ unsigned int i, j, pos;+ uint64_t signs;+ uint64_t offset;+ MLD_ALIGN uint8_t buf[SHAKE256_RATE];+ mld_shake256ctx state;++ mld_shake256_init(&state);+ mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES);+ mld_shake256_finalize(&state);+ mld_shake256_squeeze(buf, SHAKE256_RATE, &state);++ /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */+ /* Each bit of that dictates the sign of the resulting challenge value */+ signs = 0;+ for (i = 0; i < 8; ++i)+ __loop__(+ assigns(i, signs)+ invariant(i <= 8)+ decreases(8 - i)+ )+ {+ signs |= (uint64_t)buf[i] << 8 * i;+ }+ pos = 8;++ mld_memset(c, 0, sizeof(mld_poly));++ for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i)+ __loop__(+ assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs)+ invariant(i >= MLDSA_N - MLDSA_TAU)+ invariant(i <= MLDSA_N)+ invariant(pos >= 1)+ invariant(pos <= SHAKE256_RATE)+ invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2))+ invariant(state.pos <= SHAKE256_RATE)+ decreases(MLDSA_N - i)+ )+ {+ /* This loop terminates only probabilistically, hence no decreases+ * clause. */+ do+ __loop__(+ assigns(j, object_whole(buf), state, pos)+ invariant(state.pos <= SHAKE256_RATE)+ )+ {+ if (pos >= SHAKE256_RATE)+ {+ mld_shake256_squeeze(buf, SHAKE256_RATE, &state);+ pos = 0;+ }+ j = buf[pos++];+ } while (j > i);++ c->coeffs[i] = c->coeffs[j];++ /* Reference: Compute coefficient value here in two steps to */+ /* avoid mixing unsigned and signed arithmetic with implicit */+ /* conversions, and so that CBMC can keep track of ranges */+ /* to complete type-safety proof here. */++ /* The least-significant bit of signs tells us if we want -1 or +1 */+ offset = 2 * (signs & 1);++ /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has+ * value -1 or +1 */+ c->coeffs[j] = 1 - (int32_t)offset;++ /* Move to the next bit of signs for next time */+ signs >>= 1;+ }++ mld_assert_bound(c->coeffs, MLDSA_N, -1, 2);+ mld_shake256_release(&state);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(buf, sizeof(buf));+ mld_zeroize(&signs, sizeof(signs));+}+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+MLD_INTERNAL_API+void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a)+{+ unsigned int i;+ uint8_t t[8];++ mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1);++#if MLDSA_ETA == 2+ for (i = 0; i < MLDSA_N / 8; ++i)+ __loop__(+ invariant(i <= MLDSA_N/8)+ decreases(MLDSA_N / 8 - i))+ {+ /* The casts are safe since we assume that the coefficients+ * of a are <= MLDSA_ETA in absolute value. */+ t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]);+ t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]);+ t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]);+ t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]);+ t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]);+ t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]);+ t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]);+ t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]);++ r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF);+ r[3 * i + 1] =+ (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) &+ 0xFF);+ r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF);+ }+#elif MLDSA_ETA == 4+ for (i = 0; i < MLDSA_N / 2; ++i)+ __loop__(+ invariant(i <= MLDSA_N/2)+ decreases(MLDSA_N / 2 - i))+ {+ /* The casts are safe since we assume that the coefficients+ * of a are <= MLDSA_ETA in absolute value. */+ t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]);+ t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]);+ r[i] = (uint8_t)(t[0] | (t[1] << 4));+ }+#else /* MLDSA_ETA == 4 */+#error "Invalid value of MLDSA_ETA"+#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_SIGN_API)+MLD_INTERNAL_API+void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES])+{+ unsigned int i;++#if MLDSA_ETA == 2+ for (i = 0; i < MLDSA_N / 8; ++i)+ __loop__(+ invariant(i <= MLDSA_N/8)+ invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))+ decreases(MLDSA_N / 8 - i))+ {+ r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7;+ r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7;+ r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7;+ r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7;+ r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7;+ r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7;+ r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7;+ r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7;++ r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0];+ r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1];+ r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2];+ r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3];+ r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4];+ r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5];+ r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6];+ r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7];+ }+#elif MLDSA_ETA == 4+ for (i = 0; i < MLDSA_N / 2; ++i)+ __loop__(+ invariant(i <= MLDSA_N/2)+ invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))+ decreases(MLDSA_N / 2 - i))+ {+ r->coeffs[2 * i + 0] = a[i] & 0x0F;+ r->coeffs[2 * i + 1] = a[i] >> 4;+ r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0];+ r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1];+ }+#else /* MLDSA_ETA == 4 */+#error "Invalid value of MLDSA_ETA"+#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */++ mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND,+ MLDSA_ETA + 1);+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+MLD_INTERNAL_API+void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a)+{+ unsigned int i;+ uint32_t t[4];++ mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);++#if MLD_CONFIG_PARAMETER_SET == 44+ for (i = 0; i < MLDSA_N / 4; ++i)+ __loop__(+ invariant(i <= MLDSA_N/4)+ decreases(MLDSA_N / 4 - i))+ {+ /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */+ t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]);+ t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]);+ t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]);+ t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]);++ r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF);+ r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF);+ r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF);+ r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF);+ r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF);+ r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF);+ r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF);+ r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF);+ r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF);+ r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF);+ r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF);+ r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF);+ }+#else /* MLD_CONFIG_PARAMETER_SET == 44 */+ for (i = 0; i < MLDSA_N / 2; ++i)+ __loop__(+ invariant(i <= MLDSA_N/2)+ decreases(MLDSA_N / 2 - i))+ {+ /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */+ t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]);+ t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]);++ r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF);+ r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF);+ r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF);+ r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF);+ r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF);+ r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF);+ }+#endif /* MLD_CONFIG_PARAMETER_SET != 44 */+}+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_STATIC_TESTABLE void mld_polyz_unpack_c(+ mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(r, sizeof(mld_poly)))+ requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES))+ assigns(memory_slice(r, sizeof(mld_poly)))+ ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+)+{+ unsigned int i;+#if MLD_CONFIG_PARAMETER_SET == 44+ for (i = 0; i < MLDSA_N / 4; ++i)+ __loop__(+ invariant(i <= MLDSA_N/4)+ invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ decreases(MLDSA_N / 4 - i))+ {+ r->coeffs[4 * i + 0] = a[9 * i + 0];+ r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8;+ r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16;+ r->coeffs[4 * i + 0] &= 0x3FFFF;++ r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2;+ r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6;+ r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14;+ r->coeffs[4 * i + 1] &= 0x3FFFF;++ r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4;+ r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4;+ r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12;+ r->coeffs[4 * i + 2] &= 0x3FFFF;++ r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6;+ r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2;+ r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10;+ r->coeffs[4 * i + 3] &= 0x3FFFF;++ r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0];+ r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1];+ r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2];+ r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3];+ }+#else /* MLD_CONFIG_PARAMETER_SET == 44 */+ for (i = 0; i < MLDSA_N / 2; ++i)+ __loop__(+ invariant(i <= MLDSA_N/2)+ invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ decreases(MLDSA_N / 2 - i))+ {+ r->coeffs[2 * i + 0] = a[5 * i + 0];+ r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8;+ r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16;+ r->coeffs[2 * i + 0] &= 0xFFFFF;++ r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4;+ r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4;+ r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12;+ /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20+ bits */++ r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0];+ r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1];+ }+#endif /* MLD_CONFIG_PARAMETER_SET != 44 */+ mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);+}++MLD_INTERNAL_API+void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES])+{+#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44+ int ret;+ ret = mld_polyz_unpack_17_native(r->coeffs, a);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);+ return;+ }+#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \+ (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)+ int ret;+ ret = mld_polyz_unpack_19_native(r->coeffs, a);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);+ return;+ }+#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \+ && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \+ || MLD_CONFIG_PARAMETER_SET == 87) */++ mld_polyz_unpack_c(r, a);+}+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef mld_rej_eta+#undef mld_rej_eta_c+#undef mld_poly_decompose_c+#undef mld_poly_use_hint_c+#undef mld_polyz_unpack_c+#undef MLD_POLY_UNIFORM_ETA_NBLOCKS+#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS
@@ -0,0 +1,367 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#ifndef MLD_POLY_KL_H+#define MLD_POLY_KL_H++#include "cbmc.h"+#include "common.h"+#include "poly.h"++#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose)+/**+ * For all coefficients c of the input polynomial, compute high and low bits+ * c0, c1 such c mod MLDSA_Q = c1*ALPHA + c0 with -ALPHA/2 < c0 <= ALPHA/2+ * except c1 = (MLDSA_Q-1)/ALPHA where we set c1 = 0 and+ * -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients to be+ * standard representatives.+ *+ * @reference{The reference implementation has the input polynomial as a+ * separate argument that may be aliased with either of the outputs. Removing+ * the aliasing eases CBMC proofs.}+ *+ * @param[out] a1 Pointer to output polynomial with coefficients c1.+ * @param[in,out] a0 Pointer to input/output polynomial. Output polynomial has+ * coefficients c0.+ */+MLD_INTERNAL_API+void mld_poly_decompose(mld_poly *a1, mld_poly *a0)+__contract__(+ requires(memory_no_alias(a1, sizeof(mld_poly)))+ requires(memory_no_alias(a0, sizeof(mld_poly)))+ requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(a1, sizeof(mld_poly)))+ assigns(memory_slice(a0, sizeof(mld_poly)))+ ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+ ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))+);++#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint)+/**+ * Use hint polynomial h to correct the high bits of a in-place.+ *+ * @param[in,out] a Input/output polynomial.+ * @param[in] h Hint polynomial.+ */+MLD_INTERNAL_API+void mld_poly_use_hint(mld_poly *a, const mld_poly *h)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(memory_no_alias(h, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+ requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x)+/**+ * Sample four polynomials with uniformly random coefficients in+ * [-MLDSA_ETA, MLDSA_ETA] by performing rejection sampling on the output+ * stream from SHAKE256(seed|nonce_i).+ *+ * @spec{Implements @[FIPS204, Algorithm 31, RejBoundedPoly] (four-way+ * batched).}+ *+ * @param[out] r0 Pointer to first output polynomial.+ * @param[out] r1 Pointer to second output polynomial.+ * @param[out] r2 Pointer to third output polynomial.+ * @param[out] r3 Pointer to fourth output polynomial.+ * @param[in] seed Byte array with seed of length MLDSA_CRHBYTES.+ * @param nonce0 First nonce.+ * @param nonce1 Second nonce.+ * @param nonce2 Third nonce.+ * @param nonce3 Fourth nonce.+ */+MLD_INTERNAL_API+void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2,+ mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES],+ uint8_t nonce0, uint8_t nonce1, uint8_t nonce2,+ uint8_t nonce3)+__contract__(+ requires(memory_no_alias(r0, sizeof(mld_poly)))+ requires(memory_no_alias(r1, sizeof(mld_poly)))+ requires(memory_no_alias(r2, sizeof(mld_poly)))+ requires(memory_no_alias(r3, sizeof(mld_poly)))+ requires(memory_no_alias(seed, MLDSA_CRHBYTES))+ assigns(memory_slice(r0, sizeof(mld_poly)))+ assigns(memory_slice(r1, sizeof(mld_poly)))+ assigns(memory_slice(r2, sizeof(mld_poly)))+ assigns(memory_slice(r3, sizeof(mld_poly)))+ ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))+ ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))+ ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))+ ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))+);+#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */++#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta)+/**+ * Sample polynomial with uniformly random coefficients in+ * [-MLDSA_ETA, MLDSA_ETA] by performing rejection sampling on the output+ * stream from SHAKE256(seed|nonce).+ *+ * @spec{Implements @[FIPS204, Algorithm 31, RejBoundedPoly].}+ *+ * @param[out] r Pointer to output polynomial.+ * @param[in] seed Byte array with seed of length MLDSA_CRHBYTES.+ * @param nonce Nonce.+ */+MLD_INTERNAL_API+void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES],+ uint8_t nonce)+__contract__(+ requires(memory_no_alias(r, sizeof(mld_poly)))+ requires(memory_no_alias(seed, MLDSA_CRHBYTES))+ assigns(memory_slice(r, sizeof(mld_poly)))+ ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))+);+#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#if MLD_CONFIG_PARAMETER_SET == 65 || \+ defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) || \+ defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1)+/**+ * Sample polynomial with uniformly random coefficients in+ * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output stream of+ * SHAKE256(seed|nonce).+ *+ * @spec{Partially implements @[FIPS204, Algorithm 34, ExpandMask] (one+ * polynomial, i.e. the loop body of lines 3-5).}+ *+ * @param[out] a Pointer to output polynomial.+ * @param[in] seed Byte array with seed of length MLDSA_CRHBYTES.+ * @param nonce 16-bit nonce.+ */+MLD_INTERNAL_API+void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES],+ uint16_t nonce)+__contract__(+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(memory_no_alias(seed, MLDSA_CRHBYTES))+ assigns(memory_slice(a, sizeof(mld_poly)))+ ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+);+#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY || \+ MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x)+/**+ * Sample four polynomials with uniformly random coefficients in+ * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output streams of+ * SHAKE256(seed|nonce_i).+ *+ * @spec{Partially implements @[FIPS204, Algorithm 34, ExpandMask] (four-way+ * batched, i.e. four iterations of the loop body of lines 3-5).}+ *+ * @param[out] r0 Pointer to first output polynomial.+ * @param[out] r1 Pointer to second output polynomial.+ * @param[out] r2 Pointer to third output polynomial.+ * @param[out] r3 Pointer to fourth output polynomial.+ * @param[in] seed Byte array with seed of length MLDSA_CRHBYTES.+ * @param nonce0 First 16-bit nonce.+ * @param nonce1 Second 16-bit nonce.+ * @param nonce2 Third 16-bit nonce.+ * @param nonce3 Fourth 16-bit nonce.+ */+MLD_INTERNAL_API+void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2,+ mld_poly *r3,+ const uint8_t seed[MLDSA_CRHBYTES],+ uint16_t nonce0, uint16_t nonce1,+ uint16_t nonce2, uint16_t nonce3)+__contract__(+ requires(memory_no_alias(r0, sizeof(mld_poly)))+ requires(memory_no_alias(r1, sizeof(mld_poly)))+ requires(memory_no_alias(r2, sizeof(mld_poly)))+ requires(memory_no_alias(r3, sizeof(mld_poly)))+ requires(memory_no_alias(seed, MLDSA_CRHBYTES))+ assigns(memory_slice(r0, sizeof(mld_poly)))+ assigns(memory_slice(r1, sizeof(mld_poly)))+ assigns(memory_slice(r2, sizeof(mld_poly)))+ assigns(memory_slice(r3, sizeof(mld_poly)))+ ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+);+#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && (!MLD_CONFIG_REDUCE_RAM || \+ MLD_UNIT_TEST) */+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge)+/**+ * Samples polynomial with MLDSA_TAU nonzero coefficients in {-1, 1} using the+ * output stream of SHAKE256(seed).+ *+ * @spec{Implements @[FIPS204, Algorithm 29, SampleInBall].}+ *+ * @param[out] c Pointer to output polynomial.+ * @param[in] seed Byte array containing seed of length MLDSA_CTILDEBYTES.+ */+MLD_INTERNAL_API+void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES])+__contract__(+ requires(memory_no_alias(c, sizeof(mld_poly)))+ requires(memory_no_alias(seed, MLDSA_CTILDEBYTES))+ assigns(memory_slice(c, sizeof(mld_poly)))+ /* All coefficients of c are -1, 0 or +1 */+ ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2))+);+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack)+/**+ * Bit-pack polynomial with coefficients in [-MLDSA_ETA, MLDSA_ETA].+ *+ * @spec{Implements @[FIPS204, Algorithm 17, BitPack].}+ *+ * @param[out] r Pointer to output byte array with at least+ * MLDSA_POLYETA_PACKEDBYTES bytes.+ * @param[in] a Pointer to input polynomial.+ */+MLD_INTERNAL_API+void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a)+__contract__(+ requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES))+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))+ assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_SIGN_API)+/*+ * polyeta_unpack produces coefficients in [-MLDSA_ETA, MLDSA_ETA] for+ * well-formed inputs (i.e., those produced by polyeta_pack).+ * However, when passed an arbitrary byte array, it may produce smaller values,+ * i.e., values in [MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA].+ * Even though this should never happen, we use use the bound for arbitrary+ * inputs in the CBMC proofs.+ */+#if MLDSA_ETA == 2+#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5)+#elif MLDSA_ETA == 4+#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11)+#else+#error "Invalid value of MLDSA_ETA"+#endif++#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack)+/**+ * Unpack polynomial with coefficients in [-MLDSA_ETA, MLDSA_ETA].+ *+ * @spec{Implements @[FIPS204, Algorithm 19, BitUnpack].}+ *+ * @param[out] r Pointer to output polynomial.+ * @param[in] a Byte array with bit-packed polynomial.+ */+MLD_INTERNAL_API+void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(r, sizeof(mld_poly)))+ requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES))+ assigns(memory_slice(r, sizeof(mld_poly)))+ ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack)+/**+ * Bit-pack polynomial with coefficients in+ * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1].+ *+ * @spec{Implements @[FIPS204, Algorithm 17, BitPack].}+ *+ * @param[out] r Pointer to output byte array with at least+ * MLDSA_POLYZ_PACKEDBYTES bytes.+ * @param[in] a Pointer to input polynomial.+ */+MLD_INTERNAL_API+void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a)+__contract__(+ requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES))+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack)+/**+ * Unpack polynomial z with coefficients in+ * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1].+ *+ * @spec{Implements @[FIPS204, Algorithm 19, BitUnpack].}+ *+ * @param[out] r Pointer to output polynomial.+ * @param[in] a Byte array with bit-packed polynomial.+ */+MLD_INTERNAL_API+void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(r, sizeof(mld_poly)))+ requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES))+ assigns(memory_slice(r, sizeof(mld_poly)))+ ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+);++#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack)+/**+ * Bit-pack polynomial w1. Input coefficients must be in+ * [0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)), i.e. [0, 43] for ML-DSA-44 and [0, 15]+ * for ML-DSA-65/87. Dispatches to the value-specialized variant for the+ * selected parameter set.+ *+ * @spec{Implements @[FIPS204, Algorithm 16, SimpleBitPack].}+ *+ * @param[out] r Pointer to output byte array with at least+ * MLDSA_POLYW1_PACKEDBYTES bytes.+ * @param[in] a Pointer to input polynomial.+ */+static MLD_INLINE void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES],+ const mld_poly *a)+__contract__(+ requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES))+ requires(memory_no_alias(a, sizeof(mld_poly)))+ requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))+ assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES))+)+{+#if MLD_CONFIG_PARAMETER_SET == 44+ mld_polyw1_pack_88(r, a);+#else+ mld_polyw1_pack_32(r, a);+#endif+}+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#endif /* !MLD_POLY_KL_H */
@@ -0,0 +1,509 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#include "polyvec.h"++#include "debug.h"+#include "polyvec_lazy.h"++/* This namespacing is not done at the top to avoid a naming conflict+ * with native backends, which are currently not yet namespaced. */+#define mld_polyvecl_pointwise_acc_montgomery_c \+ MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c)++/**************************************************************/+/************ Vectors of polynomials of length MLDSA_L **************/+/**************************************************************/+#if !defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+MLD_INTERNAL_API+void mld_polyvecl_uniform_gamma1(mld_polyvecl *v,+ const uint8_t seed[MLDSA_CRHBYTES],+ uint16_t kappa)+{+#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+ int i;+#endif++ /* The caller passes the base counter kappa; component i is sampled from+ * kappa + i. Safety: kappa <= MLD_MAX_KAPPA and i < MLDSA_L, so the+ * casts below are safe. See MLD_MAX_KAPPA comment in params.h. */+#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+ for (i = 0; i < MLDSA_L; i++)+ {+ mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(kappa + i));+ }+#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */+#if MLDSA_L == 4+ mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3],+ seed, kappa, (uint16_t)(kappa + 1),+ (uint16_t)(kappa + 2), (uint16_t)(kappa + 3));+#elif MLDSA_L == 5+ mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3],+ seed, kappa, (uint16_t)(kappa + 1),+ (uint16_t)(kappa + 2), (uint16_t)(kappa + 3));+ mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(kappa + 4));+#elif MLDSA_L == 7+ mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2],+ &v->vec[3 /* irrelevant */], seed, kappa,+ (uint16_t)(kappa + 1), (uint16_t)(kappa + 2),+ 0xFF /* irrelevant */);+ mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6],+ seed, (uint16_t)(kappa + 3), (uint16_t)(kappa + 4),+ (uint16_t)(kappa + 5), (uint16_t)(kappa + 6));+#endif /* MLDSA_L == 7 */+#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */++ mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1),+ MLDSA_GAMMA1 + 1);+}+#endif /* !MLD_CONFIG_NO_SIGN_API && (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST) \+ */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ !defined(MLD_CONFIG_NO_VERIFY_API) || \+ (!defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)))+MLD_INTERNAL_API+void mld_polyvecl_ntt(mld_polyvecl *v)+{+ unsigned int i;+ mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q);++ for (i = 0; i < MLDSA_L; ++i)+ __loop__(+ assigns(i, memory_slice(v, sizeof(mld_polyvecl)))+ invariant(i <= MLDSA_L)+ invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))+ invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ decreases(MLDSA_L - i))+ {+ mld_poly_ntt(&v->vec[i]);+ }++ mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_VERIFY_API || \+ (!MLD_CONFIG_NO_SIGN_API && (!MLD_CONFIG_REDUCE_RAM || \+ MLD_UNIT_TEST)) */++#if !defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c(+ mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v)+__contract__(+ requires(memory_no_alias(w, sizeof(mld_poly)))+ requires(memory_no_alias(u, sizeof(mld_polyvecl)))+ requires(memory_no_alias(v, sizeof(mld_polyvecl)))+ requires(forall(l0, 0, MLDSA_L,+ array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))+ requires(forall(l1, 0, MLDSA_L,+ array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ assigns(memory_slice(w, sizeof(mld_poly)))+ ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q))+)+{+ unsigned int i, j;+ mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q);+ mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);+ for (i = 0; i < MLDSA_N; i++)+ __loop__(+ assigns(i, j, memory_slice(w, sizeof(mld_poly)))+ invariant(i <= MLDSA_N)+ invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q))+ decreases(MLDSA_N - i)+ )+ {+ int64_t t = 0;+ int32_t r;+ for (j = 0; j < MLDSA_L; j++)+ __loop__(+ assigns(j, t)+ invariant(j <= MLDSA_L)+ invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1))+ invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1))+ decreases(MLDSA_L - j)+ )+ {+ t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i];+ }++ r = mld_montgomery_reduce(t);+ w->coeffs[i] = r;+ }++ mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q);+}++MLD_INTERNAL_API+void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u,+ const mld_polyvecl *v)+{+#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \+ MLD_CONFIG_PARAMETER_SET == 44+ int ret;+ mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q);+ mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);+ ret = mld_polyvecl_pointwise_acc_montgomery_l4_native(+ w->coeffs, (const int32_t (*)[MLDSA_N])u->vec,+ (const int32_t (*)[MLDSA_N])v->vec);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q);+ return;+ }+#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \+ MLD_CONFIG_PARAMETER_SET == 65+ int ret;+ mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q);+ mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);+ ret = mld_polyvecl_pointwise_acc_montgomery_l5_native(+ w->coeffs, (const int32_t (*)[MLDSA_N])u->vec,+ (const int32_t (*)[MLDSA_N])v->vec);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q);+ return;+ }+#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \+ MLD_CONFIG_PARAMETER_SET == 87+ int ret;+ mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q);+ mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);+ ret = mld_polyvecl_pointwise_acc_montgomery_l7_native(+ w->coeffs, (const int32_t (*)[MLDSA_N])u->vec,+ (const int32_t (*)[MLDSA_N])v->vec);+ if (ret == MLD_NATIVE_FUNC_SUCCESS)+ {+ mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q);+ return;+ }+#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \+ MLD_CONFIG_PARAMETER_SET == 44) && \+ !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \+ MLD_CONFIG_PARAMETER_SET == 65) && \+ MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \+ MLD_CONFIG_PARAMETER_SET == 87 */+ /* The first input is bounded by [0, MLDSA_Q-1] inclusive.+ * The second input is bounded by [-(MLD_NTT_BOUND-1), MLD_NTT_BOUND-1].+ * Hence, we can safely accumulate in 64-bits without intermediate reductions+ * as MLDSA_L * (MLD_NTT_BOUND-1) * (MLDSA_Q-1) < INT64_MAX.+ *+ * The worst case is ML-DSA-87: 7 * (MLD_NTT_BOUND-1) * (MLDSA_Q-1) < 2**53+ * (and likewise for negative values).+ */+ mld_polyvecl_pointwise_acc_montgomery_c(w, u, v);+}+#endif /* !MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \+ defined(MLD_UNIT_TEST)+MLD_INTERNAL_API+uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound)+{+ unsigned int i;+ uint32_t t = 0;+ mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,+ MLD_REDUCE32_RANGE_MAX);++ for (i = 0; i < MLDSA_L; ++i)+ __loop__(+ invariant(i <= MLDSA_L)+ invariant(t == 0 || t == 0xFFFFFFFF)+ invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound)))+ decreases(MLDSA_L - i)+ )+ {+ /* Reference: Leaks which polynomial violates the bound via a conditional.+ * We are more conservative to reduce the number of declassifications in+ * constant-time testing.+ */+ t |= mld_poly_chknorm(&v->vec[i], bound);+ }+ return t;+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_VERIFY_API || \+ MLD_UNIT_TEST */++/**************************************************************/+/************ Vectors of polynomials of length MLDSA_K **************/+/**************************************************************/+#if (!defined(MLD_CONFIG_NO_SIGN_API) && \+ defined(MLD_CONFIG_REDUCE_RAM)) || \+ defined(MLD_UNIT_TEST)+MLD_INTERNAL_API+void mld_polyveck_reduce(mld_polyveck *v)+{+ unsigned int i;+ mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN,+ MLD_REDUCE32_DOMAIN_MAX);++ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(i, memory_slice(v, sizeof(mld_polyveck)))+ invariant(i <= MLDSA_K)+ invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))+ invariant(forall(k2, 0, i,+ array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))+ decreases(MLDSA_K - i)+ )+ {+ mld_poly_reduce(&v->vec[i]);+ }++ mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,+ MLD_REDUCE32_RANGE_MAX);+}+#endif /* (!MLD_CONFIG_NO_SIGN_API && MLD_CONFIG_REDUCE_RAM) || MLD_UNIT_TEST \+ */++#if !defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)+MLD_INTERNAL_API+void mld_polyveck_caddq(mld_polyveck *v)+{+ unsigned int i;+ mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q);++ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(i, memory_slice(v, sizeof(mld_polyveck)))+ invariant(i <= MLDSA_K)+ invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))+ invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))+ decreases(MLDSA_K - i))+ {+ mld_poly_caddq(&v->vec[i]);+ }++ mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q);+}+#endif /* !MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST */++#if (!defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+MLD_INTERNAL_API+void mld_polyveck_ntt(mld_polyveck *v)+{+ unsigned int i;+ mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q);++ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(i, memory_slice(v, sizeof(mld_polyveck)))+ invariant(i <= MLDSA_K)+ invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))+ invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ decreases(MLDSA_K - i))+ {+ mld_poly_ntt(&v->vec[i]);+ }+ mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND);+}+#endif /* (!MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST) && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST) */++#if !defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)+MLD_INTERNAL_API+void mld_polyveck_invntt_tomont(mld_polyveck *v)+{+ unsigned int i;+ mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q);++ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(i, memory_slice(v, sizeof(mld_polyveck)))+ invariant(i <= MLDSA_K)+ invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))+ invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))+ decreases(MLDSA_K - i))+ {+ mld_poly_invntt_tomont(&v->vec[i]);+ }++ mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND);+}+#endif /* !MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+MLD_INTERNAL_API+uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound)+{+ unsigned int i;+ uint32_t t = 0;+ mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,+ MLD_REDUCE32_RANGE_MAX);++ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ invariant(i <= MLDSA_K)+ invariant(t == 0 || t == 0xFFFFFFFF)+ invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound)))+ decreases(MLDSA_K - i)+ )+ {+ /* Reference: Leaks which polynomial violates the bound via a conditional.+ * We are more conservative to reduce the number of declassifications in+ * constant-time testing.+ */+ t |= mld_poly_chknorm(&v->vec[i], bound);+ }++ return t;+}++#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+MLD_INTERNAL_API+void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0)+{+ unsigned int i;+ mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q);++ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck)))+ invariant(i <= MLDSA_K)+ invariant(forall(k1, 0, i,+ array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))))+ invariant(forall(k2, 0, i,+ array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)))+ invariant(forall(k3, i, MLDSA_K,+ array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))+ decreases(MLDSA_K - i)+ )+ {+ mld_poly_decompose(&v1->vec[i], &v0->vec[i]);+ }++ mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0,+ (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));+ mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1);+}+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+MLD_INTERNAL_API+void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES],+ const mld_polyveck *w1)+{+ unsigned int i;+ mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0,+ (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));++ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES))+ invariant(i <= MLDSA_K)+ decreases(MLDSA_K - i)+ )+ {+ mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]);+ }+}+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+MLD_INTERNAL_API+void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES],+ const mld_polyveck *p)+{+ unsigned int i;+ mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1);+ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))+ invariant(i <= MLDSA_K)+ decreases(MLDSA_K - i)+ )+ {+ mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]);+ }+}++MLD_INTERNAL_API+void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES],+ const mld_polyvecl *p)+{+ unsigned int i;+ mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1);+ for (i = 0; i < MLDSA_L; ++i)+ __loop__(+ assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))+ invariant(i <= MLDSA_L)+ decreases(MLDSA_L - i)+ )+ {+ mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]);+ }+}++#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ (!defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)))+MLD_INTERNAL_API+void mld_polyvecl_unpack_eta(+ mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES])+{+ unsigned int i;+ for (i = 0; i < MLDSA_L; ++i)+ {+ mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES);+ }++ mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND,+ MLDSA_ETA + 1);+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || (!MLD_CONFIG_NO_SIGN_API && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST)) */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_INTERNAL_API+void mld_polyvecl_unpack_z(mld_polyvecl *z,+ const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES])+{+ unsigned int i;+ for (i = 0; i < MLDSA_L; ++i)+ {+ mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES);+ }++ mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1),+ MLDSA_GAMMA1 + 1);+}+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ (!defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)))+MLD_INTERNAL_API+void mld_polyveck_unpack_eta(+ mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES])+{+ unsigned int i;+ for (i = 0; i < MLDSA_K; ++i)+ {+ mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES);+ }++ mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND,+ MLDSA_ETA + 1);+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || (!MLD_CONFIG_NO_SIGN_API && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST)) */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef mld_polyvecl_pointwise_acc_montgomery_c
@@ -0,0 +1,435 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#ifndef MLD_POLYVEC_H+#define MLD_POLYVEC_H++#include "cbmc.h"+#include "common.h"+#include "poly.h"+#include "poly_kl.h"++/* Parameter set namespacing+ * This is to facilitate building multiple instances+ * of mldsa-native (e.g. with varying parameter sets)+ * within a single compilation unit. */+#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl)+#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck)+/* End of parameter set namespacing */++/** Vector of MLDSA_L polynomials. */+typedef struct+{+ mld_poly vec[MLDSA_L]; /**< Component polynomials. */+} mld_polyvecl;+++#if !defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1)+/**+ * Sample vector of polynomials with uniformly random coefficients in+ * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output stream of+ * SHAKE256(seed|kappa+i) for component i.+ *+ * @spec{Implements @[FIPS204, Algorithm 34, ExpandMask].}+ *+ * @param[out] v Pointer to output vector.+ * @param[in] seed Byte array with seed of length MLDSA_CRHBYTES.+ * @param kappa Base counter; component i uses kappa + i.+ */+MLD_INTERNAL_API+void mld_polyvecl_uniform_gamma1(mld_polyvecl *v,+ const uint8_t seed[MLDSA_CRHBYTES],+ uint16_t kappa)+__contract__(+ requires(memory_no_alias(v, sizeof(mld_polyvecl)))+ requires(memory_no_alias(seed, MLDSA_CRHBYTES))+ requires(kappa <= MLD_MAX_KAPPA)+ assigns(memory_slice(v, sizeof(mld_polyvecl)))+ ensures(forall(k0, 0, MLDSA_L,+ array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))+);+#endif /* !MLD_CONFIG_NO_SIGN_API && (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST) \+ */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ !defined(MLD_CONFIG_NO_VERIFY_API) || \+ (!defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)))+#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt)+/**+ * Forward NTT of all polynomials in vector of length MLDSA_L. Output+ * coefficients are bounded by MLD_NTT_BOUND in absolute value.+ *+ * @param[in,out] v Pointer to input/output vector.+ */+MLD_INTERNAL_API+void mld_polyvecl_ntt(mld_polyvecl *v)+__contract__(+ requires(memory_no_alias(v, sizeof(mld_polyvecl)))+ requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))+ assigns(memory_slice(v, sizeof(mld_polyvecl)))+ ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_VERIFY_API || \+ (!MLD_CONFIG_NO_SIGN_API && (!MLD_CONFIG_REDUCE_RAM || \+ MLD_UNIT_TEST)) */++#if !defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+#define mld_polyvecl_pointwise_acc_montgomery \+ MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery)+/**+ * Pointwise multiply vectors of polynomials of length MLDSA_L, multiply+ * resulting vector by 2^{-32} and add (accumulate) polynomials in it.+ * Input/output vectors are in NTT domain representation.+ *+ * The first input "u" must be the output of polyvec_matrix_expand() and so+ * have coefficients in [0, MLDSA_Q-1] inclusive.+ *+ * The second input "v" is assumed to be output of an NTT, and hence must have+ * coefficients bounded by [-(MLD_NTT_BOUND-1), MLD_NTT_BOUND-1] inclusive.+ *+ * @spec{Partially implements @[FIPS204, Algorithm 48, MatrixVectorNTT]+ * (one output polynomial; multiply-accumulate of two NTT-domain vectors).}+ *+ * @param[out] w Output polynomial.+ * @param[in] u Pointer to first input vector.+ * @param[in] v Pointer to second input vector.+ */+MLD_INTERNAL_API+void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u,+ const mld_polyvecl *v)+__contract__(+ requires(memory_no_alias(w, sizeof(mld_poly)))+ requires(memory_no_alias(u, sizeof(mld_polyvecl)))+ requires(memory_no_alias(v, sizeof(mld_polyvecl)))+ requires(forall(l0, 0, MLDSA_L,+ array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))+ requires(forall(l1, 0, MLDSA_L,+ array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ assigns(memory_slice(w, sizeof(mld_poly)))+ ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q))+);+#endif /* !MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm)+/**+ * Check infinity norm of polynomials in vector of length MLDSA_L. Assumes+ * input mld_polyvecl to be reduced by polyvecl_reduce().+ *+ * @param[in] v Pointer to vector.+ * @param B Norm bound.+ *+ * @return 0 if norm of all polynomials is strictly smaller than+ * B <= (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise.+ */+MLD_INTERNAL_API+MLD_MUST_CHECK_RETURN_VALUE+uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B)+__contract__(+ requires(memory_no_alias(v, sizeof(mld_polyvecl)))+ requires(0 <= B && B <= (MLDSA_Q - 1) / 8)+ requires(forall(k0, 0, MLDSA_L,+ array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))+ ensures(return_value == 0 || return_value == 0xFFFFFFFF)+ ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B)))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_VERIFY_API */++/** Vector of MLDSA_K polynomials. */+typedef struct+{+ mld_poly vec[MLDSA_K]; /**< Component polynomials. */+} mld_polyveck;++#if (!defined(MLD_CONFIG_NO_SIGN_API) && defined(MLD_CONFIG_REDUCE_RAM)) || \+ defined(MLD_UNIT_TEST)+#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce)+/**+ * Reduce coefficients of polynomials in vector of length MLDSA_K to+ * representatives in [-MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX].+ *+ * @param[in,out] v Pointer to input/output vector.+ */+MLD_INTERNAL_API+void mld_polyveck_reduce(mld_polyveck *v)+__contract__(+ requires(memory_no_alias(v, sizeof(mld_polyveck)))+ requires(forall(k0, 0, MLDSA_K,+ array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)))+ assigns(memory_slice(v, sizeof(mld_polyveck)))+ ensures(forall(k1, 0, MLDSA_K,+ array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))+);+#endif /* (!MLD_CONFIG_NO_SIGN_API && MLD_CONFIG_REDUCE_RAM) || MLD_UNIT_TEST \+ */++#if !defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)+#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq)+/**+ * For all coefficients of polynomials in vector of length MLDSA_K add MLDSA_Q+ * if coefficient is negative.+ *+ * @param[in,out] v Pointer to input/output vector.+ */+MLD_INTERNAL_API+void mld_polyveck_caddq(mld_polyveck *v)+__contract__(+ requires(memory_no_alias(v, sizeof(mld_polyveck)))+ requires(forall(k0, 0, MLDSA_K,+ array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))+ assigns(memory_slice(v, sizeof(mld_polyveck)))+ ensures(forall(k1, 0, MLDSA_K,+ array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))+);+#endif /* !MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST */++#if (!defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt)+/**+ * Forward NTT of all polynomials in vector of length MLDSA_K. Output+ * coefficients are bounded by MLD_NTT_BOUND in absolute value.+ *+ * @param[in,out] v Pointer to input/output vector.+ */+MLD_INTERNAL_API+void mld_polyveck_ntt(mld_polyveck *v)+__contract__(+ requires(memory_no_alias(v, sizeof(mld_polyveck)))+ requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))+ assigns(memory_slice(v, sizeof(mld_polyveck)))+ ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+);+#endif /* (!MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST) && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST) */++#if !defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)+#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont)+/**+ * Inverse NTT and multiplication by 2^{32} of polynomials in vector of+ * length MLDSA_K.+ *+ * Input coefficients need to be less than MLDSA_Q, and output coefficients+ * are bounded by MLD_INTT_BOUND.+ *+ * @param[in,out] v Pointer to input/output vector.+ */+MLD_INTERNAL_API+void mld_polyveck_invntt_tomont(mld_polyveck *v)+__contract__(+ requires(memory_no_alias(v, sizeof(mld_polyveck)))+ requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))+ assigns(memory_slice(v, sizeof(mld_polyveck)))+ ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))+);+#endif /* !MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm)+/**+ * Check infinity norm of polynomials in vector of length MLDSA_K. Assumes+ * input mld_polyveck to be reduced by polyveck_reduce().+ *+ * @param[in] v Pointer to vector.+ * @param B Norm bound.+ *+ * @return 0 if norm of all polynomials are strictly smaller than+ * B <= (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise.+ */+MLD_INTERNAL_API+MLD_MUST_CHECK_RETURN_VALUE+uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B)+__contract__(+ requires(memory_no_alias(v, sizeof(mld_polyveck)))+ requires(0 <= B && B <= (MLDSA_Q - 1) / 8)+ requires(forall(k0, 0, MLDSA_K,+ array_bound(v->vec[k0].coeffs, 0, MLDSA_N,+ -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))+ ensures(return_value == 0 || return_value == 0xFFFFFFFF)+ ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B)))+);++#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose)+/**+ * For all coefficients a of polynomials in vector of length MLDSA_K, compute+ * high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + a0 with+ * -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set+ * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes+ * coefficients to be standard representatives.+ *+ * @reference{The reference implementation has the input polynomial as a+ * separate argument that may be aliased with either of the outputs. Removing+ * the aliasing eases CBMC proofs.}+ *+ * @param[out] v1 Pointer to output vector of polynomials with+ * coefficients a1.+ * @param[in,out] v0 Pointer to input/output vector of polynomials. Output+ * polynomial has coefficients a0.+ */+MLD_INTERNAL_API+void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0)+__contract__(+ requires(memory_no_alias(v1, sizeof(mld_polyveck)))+ requires(memory_no_alias(v0, sizeof(mld_polyveck)))+ requires(forall(k0, 0, MLDSA_K,+ array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))+ assigns(memory_slice(v1, sizeof(mld_polyveck)))+ assigns(memory_slice(v0, sizeof(mld_polyveck)))+ ensures(forall(k1, 0, MLDSA_K,+ array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))))+ ensures(forall(k2, 0, MLDSA_K,+ array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1)+/**+ * Bit-pack polynomial vector w1 with coefficients in [0, 15] or [0, 43]. Input+ * coefficients are assumed to be standard representatives.+ *+ * @spec{Implements @[FIPS204, Algorithm 28, w1Encode].}+ *+ * @param[out] r Pointer to output byte array with at least+ * MLDSA_K * MLDSA_POLYW1_PACKEDBYTES bytes.+ * @param[in] w1 Pointer to input polynomial vector.+ */+MLD_INTERNAL_API+void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES],+ const mld_polyveck *w1)+__contract__(+ requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES))+ requires(memory_no_alias(w1, sizeof(mld_polyveck)))+ requires(forall(k1, 0, MLDSA_K,+ array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))))+ assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta)+/**+ * Bit-pack polynomial vector with coefficients in [-MLDSA_ETA, MLDSA_ETA].+ *+ * @param[out] r Pointer to output byte array with+ * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes.+ * @param[in] p Pointer to input polynomial vector.+ */+MLD_INTERNAL_API+void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES],+ const mld_polyveck *p)+__contract__(+ requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))+ requires(memory_no_alias(p, sizeof(mld_polyveck)))+ requires(forall(k1, 0, MLDSA_K,+ array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))+ assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))+);++#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta)+/**+ * Bit-pack polynomial vector with coefficients in [-MLDSA_ETA, MLDSA_ETA].+ *+ * @param[out] r Pointer to output byte array with+ * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes.+ * @param[in] p Pointer to input polynomial vector.+ */+MLD_INTERNAL_API+void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES],+ const mld_polyvecl *p)+__contract__(+ requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))+ requires(memory_no_alias(p, sizeof(mld_polyvecl)))+ requires(forall(k1, 0, MLDSA_L,+ array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))+ assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))+);++#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ (!defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)))+#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta)+/**+ * Unpack polynomial vector with coefficients in [-MLDSA_ETA, MLDSA_ETA].+ *+ * @param[out] p Pointer to output polynomial vector.+ * @param[in] r Input byte array with bit-packed polynomial vector.+ */+MLD_INTERNAL_API+void mld_polyvecl_unpack_eta(+ mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))+ requires(memory_no_alias(p, sizeof(mld_polyvecl)))+ assigns(memory_slice(p, sizeof(mld_polyvecl)))+ ensures(forall(k1, 0, MLDSA_L,+ array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || (!MLD_CONFIG_NO_SIGN_API && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST)) */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z)+/**+ * Unpack polynomial vector with coefficients in+ * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1].+ *+ * @param[out] z Pointer to output polynomial vector.+ * @param[in] r Input byte array with bit-packed polynomial vector.+ */+MLD_INTERNAL_API+void mld_polyvecl_unpack_z(mld_polyvecl *z,+ const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES))+ requires(memory_no_alias(z, sizeof(mld_polyvecl)))+ assigns(memory_slice(z, sizeof(mld_polyvecl)))+ ensures(forall(k1, 0, MLDSA_L,+ array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || \+ (!defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)))+#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta)+/**+ * Unpack polynomial vector with coefficients in [-MLDSA_ETA, MLDSA_ETA].+ *+ * @param[out] p Pointer to output polynomial vector.+ * @param[in] r Input byte array with bit-packed polynomial vector.+ */+MLD_INTERNAL_API+void mld_polyveck_unpack_eta(+ mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))+ requires(memory_no_alias(p, sizeof(mld_polyveck)))+ assigns(memory_slice(p, sizeof(mld_polyveck)))+ ensures(forall(k1, 0, MLDSA_K,+ array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || (!MLD_CONFIG_NO_SIGN_API && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST)) */+++#endif /* !MLD_POLYVEC_H */
@@ -0,0 +1,311 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#include "polyvec_lazy.h"++#include "debug.h"++/* This namespacing is not done at the top to avoid a naming conflict+ * with native backends, which are currently not yet namespaced. */+#define mld_polymat_expand_entry MLD_ADD_PARAM_SET(mld_polymat_expand_entry)++/**+ * Sample a single matrix entry A[k][l] of ExpandA(rho) by rejection sampling+ * from SHAKE128(rho|l|k), and apply the custom-order permutation when a+ * native NTT backend is in use.+ *+ * The caller is expected to have copied rho into the first MLDSA_SEEDBYTES+ * of seed_ext. This function writes the domain-separation bytes+ * seed_ext[SEEDBYTES..+2] = {l, k} before sampling.+ *+ * @spec{Partially implements @[FIPS204, Algorithm 32, ExpandA] (samples one+ * matrix entry via @[FIPS204, Algorithm 30, RejNTTPoly]).}+ *+ * @param[out] p Pointer to output polynomial.+ * @param[in,out] seed_ext Seed buffer pre-filled with rho in the first+ * MLDSA_SEEDBYTES; the final two bytes are+ * overwritten.+ * @param l Column index (inner, aka nonce low byte).+ * @param k Row index (outer, aka nonce high byte).+ */+static MLD_INLINE void mld_polymat_expand_entry(+ mld_poly *p, uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)], uint8_t l,+ uint8_t k)+__contract__(+ requires(memory_no_alias(p, sizeof(mld_poly)))+ requires(memory_no_alias(seed_ext, MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)))+ assigns(memory_slice(p, sizeof(mld_poly)))+ assigns(memory_slice(seed_ext, MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)))+ ensures(array_bound(p->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+)+{+ seed_ext[MLDSA_SEEDBYTES + 0] = l;+ seed_ext[MLDSA_SEEDBYTES + 1] = k;+ mld_poly_uniform(p, seed_ext);+ mld_poly_permute_bitrev_to_custom_optional(p);+}++#if !defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)++MLD_INTERNAL_API+void mld_polyvec_matrix_expand_eager(mld_polymat_eager *mat,+ const uint8_t rho[MLDSA_SEEDBYTES])+{+ unsigned int i, j;+ MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)];++ for (j = 0; j < 4; j++)+ __loop__(+ assigns(j, object_whole(seed_ext))+ invariant(j <= 4)+ decreases(4 - j)+ )+ {+ mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES);+ }++#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+ /* Sample 4 matrix entries a time. */+ for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4)+ __loop__(+ assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat_eager)))+ invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0)+ /* vectors 0 .. i / MLDSA_L are completely sampled */+ invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L,+ array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))+ /* last vector is sampled up to i % MLDSA_L */+ invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L,+ array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))+ decreases((MLDSA_K * MLDSA_L / 4) * 4 - i)+ )+ {+ for (j = 0; j < 4; j++)+ __loop__(+ assigns(j, object_whole(seed_ext))+ invariant(j <= 4)+ decreases(4 - j)+ )+ {+ uint8_t x = (uint8_t)((i + j) / MLDSA_L);+ uint8_t y = (uint8_t)((i + j) % MLDSA_L);++ seed_ext[j][MLDSA_SEEDBYTES + 0] = y;+ seed_ext[j][MLDSA_SEEDBYTES + 1] = x;+ }++ mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L],+ &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L],+ &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L],+ &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L],+ seed_ext);+ mld_poly_permute_bitrev_to_custom_optional(+ &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]);+ mld_poly_permute_bitrev_to_custom_optional(+ &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L]);+ mld_poly_permute_bitrev_to_custom_optional(+ &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L]);+ mld_poly_permute_bitrev_to_custom_optional(+ &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L]);+ }+#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */+ i = 0;+#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */++ /* Entries omitted by the batch-sampling are sampled individually. */+ while (i < MLDSA_K * MLDSA_L)+ __loop__(+ assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat_eager)))+ invariant(i <= MLDSA_K * MLDSA_L)+ /* vectors 0 .. i / MLDSA_L are completely sampled */+ invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L,+ array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))+ /* last vector is sampled up to i % MLDSA_L */+ invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L,+ array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))+ decreases(MLDSA_K * MLDSA_L - i)+ )+ {+ uint8_t x = (uint8_t)(i / MLDSA_L);+ uint8_t y = (uint8_t)(i % MLDSA_L);+ mld_polymat_expand_entry(&mat->vec[x].vec[y], seed_ext[0], y, x);+ i++;+ }++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(seed_ext, sizeof(seed_ext));+}++MLD_INTERNAL_API+void mld_polyvec_matrix_pointwise_montgomery_row_eager(mld_poly *t_row,+ mld_polymat_eager *mat,+ const mld_polyvecl *v,+ unsigned int i)+{+ mld_polyvecl_pointwise_acc_montgomery(t_row, &mat->vec[i], v);+}++#if !defined(MLD_CONFIG_NO_SIGN_API)+MLD_INTERNAL_API+void mld_polyvec_matrix_pointwise_montgomery_yvec_eager(mld_polyveck *w,+ mld_polymat_eager *mat,+ const mld_yvec_eager *y,+ mld_polyvecl *scratch)+{+ unsigned int i;+ *scratch = y->vec;+ mld_polyvecl_ntt(scratch);++ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(i, memory_slice(w, sizeof(mld_polyveck)))+ invariant(i <= MLDSA_K)+ invariant(forall(k0, 0, i,+ array_abs_bound(w->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))+ decreases(MLDSA_K - i)+ )+ {+ mld_polyvec_matrix_pointwise_montgomery_row_eager(&w->vec[i], mat, scratch,+ i);+ }++ mld_polyveck_invntt_tomont(w);+}+#endif /* !MLD_CONFIG_NO_SIGN_API */++#endif /* !MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)++MLD_INTERNAL_API+void mld_polyvec_matrix_expand_lazy(mld_polymat_lazy *mat,+ const uint8_t rho[MLDSA_SEEDBYTES])+{+ mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES);+}++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_INTERNAL_API+void mld_polyvec_matrix_pointwise_montgomery_row_lazy(mld_poly *t_row,+ mld_polymat_lazy *mat,+ const mld_polyvecl *v,+ unsigned int i)+{+ unsigned int l;+ MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)];+ mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES);++ mld_polymat_expand_entry(t_row, seed_ext, 0, (uint8_t)i);+ mld_poly_pointwise_montgomery(t_row, &v->vec[0]);++ for (l = 1; l < MLDSA_L; ++l)+ __loop__(+ assigns(l, object_whole(seed_ext),+ memory_slice(t_row, sizeof(mld_poly)),+ memory_slice(mat, sizeof(mld_polymat_lazy)))+ invariant(l >= 1 && l <= MLDSA_L)+ invariant(array_abs_bound(t_row->coeffs, 0, MLDSA_N, l * MLDSA_Q))+ decreases(MLDSA_L - l)+ )+ {+ mld_polymat_expand_entry(&mat->cur, seed_ext, (uint8_t)l, (uint8_t)i);+ mld_poly_pointwise_montgomery(&mat->cur, &v->vec[l]);+ mld_poly_add(t_row, &mat->cur);+ }+ mld_poly_reduce(t_row);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(seed_ext, sizeof(seed_ext));+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+MLD_INTERNAL_API+void mld_polyvec_matrix_pointwise_montgomery_yvec_lazy(mld_polyveck *w,+ mld_polymat_lazy *mat,+ const mld_yvec_lazy *y,+ mld_polyvecl *scratch)+{+ unsigned int k, l;+ MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)];+ /* Only the first poly of the polyvecl scratch is used. The polyvecl type+ * matches the eager variant for API uniformity; in REDUCE_RAM mode the+ * polyvecl storage is provided "for free" by the caller's polyveck/polyvecl+ * union. */+ mld_poly *y_ntt = &scratch->vec[0];++ mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES);++ /* Column-by-column: sample y[l], NTT, accumulate column l of A into w. */+ for (l = 0; l < MLDSA_L; l++)+ __loop__(+ assigns(k, l, object_whole(seed_ext),+ memory_slice(w, sizeof(mld_polyveck)),+ memory_slice(mat, sizeof(mld_polymat_lazy)),+ memory_slice(scratch, sizeof(mld_polyvecl)))+ invariant(l <= MLDSA_L)+ invariant(l == 0 ||+ forall(k0, 0, MLDSA_K,+ array_abs_bound(w->vec[k0].coeffs, 0, MLDSA_N,+ (int)l * MLDSA_Q)))+ decreases(MLDSA_L - l)+ )+ {+ mld_yvec_get_poly_lazy(y_ntt, y, l);+ mld_poly_ntt(y_ntt);+ for (k = 0; k < MLDSA_K; k++)+ __loop__(+ assigns(k, object_whole(seed_ext),+ memory_slice(w, sizeof(mld_polyveck)),+ memory_slice(mat, sizeof(mld_polymat_lazy)))+ invariant(k <= MLDSA_K)+ invariant(l != 0 ||+ forall(k1, 0, k,+ array_abs_bound(w->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q)))+ invariant(l == 0 ||+ forall(k2, 0, k,+ array_abs_bound(w->vec[k2].coeffs, 0, MLDSA_N,+ ((int)l + 1) * MLDSA_Q)))+ invariant(l == 0 ||+ forall(k3, k, MLDSA_K,+ array_abs_bound(w->vec[k3].coeffs, 0, MLDSA_N,+ (int)l * MLDSA_Q)))+ decreases(MLDSA_K - k)+ )+ {+ if (l == 0)+ {+ mld_polymat_expand_entry(&w->vec[k], seed_ext, 0, (uint8_t)k);+ mld_poly_pointwise_montgomery(&w->vec[k], y_ntt);+ }+ else+ {+ mld_polymat_expand_entry(&mat->cur, seed_ext, (uint8_t)l, (uint8_t)k);+ mld_poly_pointwise_montgomery(&mat->cur, y_ntt);+ mld_poly_add(&w->vec[k], &mat->cur);+ }+ }+ }++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(seed_ext, sizeof(seed_ext));+ mld_polyveck_reduce(w);+ mld_polyveck_invntt_tomont(w);+}+#endif /* !MLD_CONFIG_NO_SIGN_API */++#endif /* MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef mld_polymat_expand_entry
@@ -0,0 +1,652 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++/*+ * Eager and lazy variants of polynomial vector types.+ *+ * In eager mode, full vectors are precomputed and stored in memory.+ * In lazy mode, data is stored in packed form and expanded on demand,+ * trading computation for reduced memory usage.+ *+ * MLD_CONFIG_REDUCE_RAM selects which variant is used.+ */++#ifndef MLD_POLYVEC_LAZY_H+#define MLD_POLYVEC_LAZY_H++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_SIGN_API) || \+ !defined(MLD_CONFIG_NO_VERIFY_API)++#include "poly.h"+#include "poly_kl.h"+#include "polyvec.h"++/* Parameter set namespacing */+#define mld_sk_s1hat_eager MLD_ADD_PARAM_SET(mld_sk_s1hat_eager)+#define mld_sk_s1hat_lazy MLD_ADD_PARAM_SET(mld_sk_s1hat_lazy)+#define mld_sk_s1hat MLD_ADD_PARAM_SET(mld_sk_s1hat)+#define mld_unpack_sk_s1hat_eager MLD_ADD_PARAM_SET(mld_unpack_sk_s1hat_eager)+#define mld_unpack_sk_s1hat_lazy MLD_ADD_PARAM_SET(mld_unpack_sk_s1hat_lazy)+#define mld_sk_s1hat_get_poly_eager \+ MLD_ADD_PARAM_SET(mld_sk_s1hat_get_poly_eager)+#define mld_sk_s1hat_get_poly_lazy MLD_ADD_PARAM_SET(mld_sk_s1hat_get_poly_lazy)+#define mld_sk_s2hat_eager MLD_ADD_PARAM_SET(mld_sk_s2hat_eager)+#define mld_sk_s2hat_lazy MLD_ADD_PARAM_SET(mld_sk_s2hat_lazy)+#define mld_sk_s2hat MLD_ADD_PARAM_SET(mld_sk_s2hat)+#define mld_unpack_sk_s2hat_eager MLD_ADD_PARAM_SET(mld_unpack_sk_s2hat_eager)+#define mld_unpack_sk_s2hat_lazy MLD_ADD_PARAM_SET(mld_unpack_sk_s2hat_lazy)+#define mld_sk_s2hat_get_poly_eager \+ MLD_ADD_PARAM_SET(mld_sk_s2hat_get_poly_eager)+#define mld_sk_s2hat_get_poly_lazy MLD_ADD_PARAM_SET(mld_sk_s2hat_get_poly_lazy)+#define mld_sk_t0hat_eager MLD_ADD_PARAM_SET(mld_sk_t0hat_eager)+#define mld_sk_t0hat_lazy MLD_ADD_PARAM_SET(mld_sk_t0hat_lazy)+#define mld_sk_t0hat MLD_ADD_PARAM_SET(mld_sk_t0hat)+#define mld_unpack_sk_t0hat_eager MLD_ADD_PARAM_SET(mld_unpack_sk_t0hat_eager)+#define mld_unpack_sk_t0hat_lazy MLD_ADD_PARAM_SET(mld_unpack_sk_t0hat_lazy)+#define mld_sk_t0hat_get_poly_eager \+ MLD_ADD_PARAM_SET(mld_sk_t0hat_get_poly_eager)+#define mld_sk_t0hat_get_poly_lazy MLD_ADD_PARAM_SET(mld_sk_t0hat_get_poly_lazy)+#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat)+#define mld_polymat_eager MLD_ADD_PARAM_SET(mld_polymat_eager)+#define mld_polymat_lazy MLD_ADD_PARAM_SET(mld_polymat_lazy)+#define mld_poly_permute_bitrev_to_custom_optional \+ MLD_ADD_PARAM_SET(mld_poly_permute_bitrev_to_custom_optional)+#define mld_polyvec_matrix_expand_eager \+ MLD_NAMESPACE_KL(polyvec_matrix_expand_eager)+#define mld_polyvec_matrix_expand_lazy \+ MLD_NAMESPACE_KL(polyvec_matrix_expand_lazy)+#define mld_polyvec_matrix_pointwise_montgomery \+ MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery)+#define mld_polyvec_matrix_pointwise_montgomery_row_eager \+ MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery_row_eager)+#define mld_polyvec_matrix_pointwise_montgomery_row_lazy \+ MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery_row_lazy)+#define mld_polyvec_matrix_pointwise_montgomery_yvec_eager \+ MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery_yvec_eager)+#define mld_polyvec_matrix_pointwise_montgomery_yvec_lazy \+ MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery_yvec_lazy)+#define mld_yvec_eager MLD_ADD_PARAM_SET(mld_yvec_eager)+#define mld_yvec_lazy MLD_ADD_PARAM_SET(mld_yvec_lazy)+#define mld_yvec MLD_ADD_PARAM_SET(mld_yvec)+#define mld_yvec_init_eager MLD_ADD_PARAM_SET(mld_yvec_init_eager)+#define mld_yvec_init_lazy MLD_ADD_PARAM_SET(mld_yvec_init_lazy)+#define mld_yvec_get_poly_eager MLD_ADD_PARAM_SET(mld_yvec_get_poly_eager)+#define mld_yvec_get_poly_lazy MLD_ADD_PARAM_SET(mld_yvec_get_poly_lazy)+/* End of parameter set namespacing */++/** Eager s1hat: precomputed s1 vector in NTT domain. */+typedef struct+{+ mld_polyvecl vec; /**< s1 vector in NTT domain. */+} mld_sk_s1hat_eager;++/** Eager s2hat: precomputed s2 vector in NTT domain. */+typedef struct+{+ mld_polyveck vec; /**< s2 vector in NTT domain. */+} mld_sk_s2hat_eager;++/** Eager t0hat: precomputed t0 vector in NTT domain. */+typedef struct+{+ mld_polyveck vec; /**< t0 vector in NTT domain. */+} mld_sk_t0hat_eager;++/** Lazy s1hat: borrow packed s1, unpack and convert to NTT domain on demand. */+typedef struct+{+ const uint8_t *packed; /**< Pointer to packed s1 in the secret key. */+} mld_sk_s1hat_lazy;++/** Lazy s2hat: borrow packed s2, unpack and convert to NTT domain on demand. */+typedef struct+{+ const uint8_t *packed; /**< Pointer to packed s2 in the secret key. */+} mld_sk_s2hat_lazy;++/** Lazy t0hat: borrow packed t0, unpack and convert to NTT domain on demand. */+typedef struct+{+ const uint8_t *packed; /**< Pointer to packed t0 in the secret key. */+} mld_sk_t0hat_lazy;++/** Eager yvec: precomputed and stored full signing masking vector y. */+typedef struct+{+ mld_polyvecl vec; /**< Masking vector y. */+} mld_yvec_eager;++/** Lazy yvec: store seed and base counter kappa, regenerate y[i] on demand. */+typedef struct+{+ const uint8_t *rhoprime; /**< Pointer to seed used to derive y. */+ uint16_t kappa; /**< Base counter; component i uses kappa + i. */+} mld_yvec_lazy;++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_SIGN_API)+/* s1vec */++#if !defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+static MLD_INLINE void mld_unpack_sk_s1hat_eager(+ mld_sk_s1hat_eager *s1,+ const uint8_t packed_s1[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(s1, sizeof(mld_sk_s1hat_eager)))+ requires(memory_no_alias(packed_s1, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))+ assigns(memory_slice(s1, sizeof(mld_sk_s1hat_eager)))+ ensures(forall(k1, 0, MLDSA_L,+ array_abs_bound(s1->vec.vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+)+{+ mld_polyvecl_unpack_eta(&s1->vec, packed_s1);+ mld_polyvecl_ntt(&s1->vec);+}++#if !defined(MLD_CONFIG_NO_SIGN_API)+static MLD_INLINE void mld_sk_s1hat_get_poly_eager(mld_poly *buf,+ const mld_sk_s1hat_eager *s1,+ unsigned int i)+__contract__(+ requires(memory_no_alias(buf, sizeof(mld_poly)))+ requires(memory_no_alias(s1, sizeof(mld_sk_s1hat_eager)))+ requires(i < MLDSA_L)+ requires(array_abs_bound(s1->vec.vec[i].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+ assigns(memory_slice(buf, sizeof(mld_poly)))+ ensures(array_abs_bound(buf->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+) { *buf = s1->vec.vec[i]; }+#endif /* !MLD_CONFIG_NO_SIGN_API */+#endif /* !MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */+#if defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+static MLD_INLINE void mld_unpack_sk_s1hat_lazy(+ mld_sk_s1hat_lazy *s1,+ const uint8_t packed_s1[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(s1, sizeof(mld_sk_s1hat_lazy)))+ assigns(memory_slice(s1, sizeof(mld_sk_s1hat_lazy)))+ ensures(s1->packed == old(packed_s1))+) { s1->packed = packed_s1; }++#if !defined(MLD_CONFIG_NO_SIGN_API)+static MLD_INLINE void mld_sk_s1hat_get_poly_lazy(mld_poly *buf,+ const mld_sk_s1hat_lazy *s1,+ unsigned int i)+__contract__(+ requires(memory_no_alias(buf, sizeof(mld_poly)))+ requires(memory_no_alias(s1, sizeof(mld_sk_s1hat_lazy)))+ requires(i < MLDSA_L)+ requires(memory_no_alias(s1->packed, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))+ assigns(memory_slice(buf, sizeof(mld_poly)))+ ensures(array_abs_bound(buf->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+)+{+ mld_polyeta_unpack(buf, s1->packed + i * MLDSA_POLYETA_PACKEDBYTES);+ mld_poly_ntt(buf);+}+#endif /* !MLD_CONFIG_NO_SIGN_API */+#endif /* MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++/* s2vec */++#if (!defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+static MLD_INLINE void mld_unpack_sk_s2hat_eager(+ mld_sk_s2hat_eager *s2,+ const uint8_t packed_s2[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(s2, sizeof(mld_sk_s2hat_eager)))+ requires(memory_no_alias(packed_s2, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))+ assigns(memory_slice(s2, sizeof(mld_sk_s2hat_eager)))+ ensures(forall(k1, 0, MLDSA_K,+ array_abs_bound(s2->vec.vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+)+{+ mld_polyveck_unpack_eta(&s2->vec, packed_s2);+ mld_polyveck_ntt(&s2->vec);+}++#if !defined(MLD_CONFIG_NO_SIGN_API)+static MLD_INLINE void mld_sk_s2hat_get_poly_eager(mld_poly *buf,+ const mld_sk_s2hat_eager *s2,+ unsigned int i)+__contract__(+ requires(memory_no_alias(buf, sizeof(mld_poly)))+ requires(memory_no_alias(s2, sizeof(mld_sk_s2hat_eager)))+ requires(i < MLDSA_K)+ requires(array_abs_bound(s2->vec.vec[i].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+ assigns(memory_slice(buf, sizeof(mld_poly)))+ ensures(array_abs_bound(buf->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+) { *buf = s2->vec.vec[i]; }+#endif /* !MLD_CONFIG_NO_SIGN_API */+#endif /* (!MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST) && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST) */+#if defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+static MLD_INLINE void mld_unpack_sk_s2hat_lazy(+ mld_sk_s2hat_lazy *s2,+ const uint8_t packed_s2[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(s2, sizeof(mld_sk_s2hat_lazy)))+ assigns(memory_slice(s2, sizeof(mld_sk_s2hat_lazy)))+ ensures(s2->packed == old(packed_s2))+) { s2->packed = packed_s2; }++#if !defined(MLD_CONFIG_NO_SIGN_API)+static MLD_INLINE void mld_sk_s2hat_get_poly_lazy(mld_poly *buf,+ const mld_sk_s2hat_lazy *s2,+ unsigned int i)+__contract__(+ requires(memory_no_alias(buf, sizeof(mld_poly)))+ requires(memory_no_alias(s2, sizeof(mld_sk_s2hat_lazy)))+ requires(i < MLDSA_K)+ requires(memory_no_alias(s2->packed, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))+ assigns(memory_slice(buf, sizeof(mld_poly)))+ ensures(array_abs_bound(buf->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+)+{+ mld_polyeta_unpack(buf, s2->packed + i * MLDSA_POLYETA_PACKEDBYTES);+ mld_poly_ntt(buf);+}+#endif /* !MLD_CONFIG_NO_SIGN_API */+#endif /* MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++/* t0vec */++#if (!defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+static MLD_INLINE void mld_unpack_sk_t0hat_eager(+ mld_sk_t0hat_eager *t0,+ const uint8_t packed_t0[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(t0, sizeof(mld_sk_t0hat_eager)))+ requires(memory_no_alias(packed_t0, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))+ assigns(memory_slice(t0, sizeof(mld_sk_t0hat_eager)))+ ensures(forall(k1, 0, MLDSA_K,+ array_abs_bound(t0->vec.vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+)+{+ unsigned int i;+ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(i, memory_slice(t0, sizeof(mld_sk_t0hat_eager)))+ invariant(i <= MLDSA_K)+ invariant(forall(k0, 0, i,+ array_bound(t0->vec.vec[k0].coeffs, 0, MLDSA_N,+ -(1 << (MLDSA_D - 1)) + 1, (1 << (MLDSA_D - 1)) + 1)))+ decreases(MLDSA_K - i)+ )+ {+ mld_polyt0_unpack(&t0->vec.vec[i],+ packed_t0 + i * MLDSA_POLYT0_PACKEDBYTES);+ }+ mld_polyveck_ntt(&t0->vec);+}++#if !defined(MLD_CONFIG_NO_SIGN_API)+static MLD_INLINE void mld_sk_t0hat_get_poly_eager(mld_poly *buf,+ const mld_sk_t0hat_eager *t0,+ unsigned int i)+__contract__(+ requires(memory_no_alias(buf, sizeof(mld_poly)))+ requires(memory_no_alias(t0, sizeof(mld_sk_t0hat_eager)))+ requires(i < MLDSA_K)+ requires(array_abs_bound(t0->vec.vec[i].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+ assigns(memory_slice(buf, sizeof(mld_poly)))+ ensures(array_abs_bound(buf->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+) { *buf = t0->vec.vec[i]; }+#endif /* !MLD_CONFIG_NO_SIGN_API */+#endif /* (!MLD_CONFIG_NO_SIGN_API || MLD_UNIT_TEST) && \+ (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST) */+#if defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+static MLD_INLINE void mld_unpack_sk_t0hat_lazy(+ mld_sk_t0hat_lazy *t0,+ const uint8_t packed_t0[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES])+__contract__(+ requires(memory_no_alias(t0, sizeof(mld_sk_t0hat_lazy)))+ assigns(memory_slice(t0, sizeof(mld_sk_t0hat_lazy)))+ ensures(t0->packed == old(packed_t0))+) { t0->packed = packed_t0; }++#if !defined(MLD_CONFIG_NO_SIGN_API)+static MLD_INLINE void mld_sk_t0hat_get_poly_lazy(mld_poly *buf,+ const mld_sk_t0hat_lazy *t0,+ unsigned int i)+__contract__(+ requires(memory_no_alias(buf, sizeof(mld_poly)))+ requires(memory_no_alias(t0, sizeof(mld_sk_t0hat_lazy)))+ requires(i < MLDSA_K)+ requires(memory_no_alias(t0->packed, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))+ assigns(memory_slice(buf, sizeof(mld_poly)))+ ensures(array_abs_bound(buf->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+)+{+ mld_polyt0_unpack(buf, t0->packed + i * MLDSA_POLYT0_PACKEDBYTES);+ mld_poly_ntt(buf);+}+#endif /* !MLD_CONFIG_NO_SIGN_API */+#endif /* MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_SIGN_API */++/* yvec */++#if !defined(MLD_CONFIG_NO_SIGN_API) && \+ (!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+static MLD_INLINE void mld_yvec_init_eager(+ mld_yvec_eager *y, const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t kappa)+__contract__(+ requires(memory_no_alias(y, sizeof(mld_yvec_eager)))+ requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES))+ requires(kappa <= MLD_MAX_KAPPA)+ assigns(memory_slice(y, sizeof(mld_yvec_eager)))+ ensures(forall(k1, 0, MLDSA_L,+ array_bound(y->vec.vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))+)+{+ mld_polyvecl_uniform_gamma1(&y->vec, rhoprime, kappa);+}++static MLD_INLINE void mld_yvec_get_poly_eager(mld_poly *buf,+ const mld_yvec_eager *y,+ unsigned int i)+__contract__(+ requires(memory_no_alias(buf, sizeof(mld_poly)))+ requires(memory_no_alias(y, sizeof(mld_yvec_eager)))+ requires(i < MLDSA_L)+ requires(array_bound(y->vec.vec[i].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+ assigns(memory_slice(buf, sizeof(mld_poly)))+ ensures(array_bound(buf->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+) { *buf = y->vec.vec[i]; }+#endif /* !MLD_CONFIG_NO_SIGN_API && (!MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST) \+ */+#if !defined(MLD_CONFIG_NO_SIGN_API) && \+ (defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))+static MLD_INLINE void mld_yvec_init_lazy(+ mld_yvec_lazy *y, const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t kappa)+__contract__(+ requires(memory_no_alias(y, sizeof(mld_yvec_lazy)))+ assigns(memory_slice(y, sizeof(mld_yvec_lazy)))+ ensures(y->rhoprime == old(rhoprime))+ ensures(y->kappa == old(kappa))+)+{+ y->rhoprime = rhoprime;+ y->kappa = kappa;+}++static MLD_INLINE void mld_yvec_get_poly_lazy(mld_poly *buf,+ const mld_yvec_lazy *y,+ unsigned int i)+__contract__(+ requires(memory_no_alias(buf, sizeof(mld_poly)))+ requires(memory_no_alias(y, sizeof(mld_yvec_lazy)))+ requires(i < MLDSA_L)+ requires(memory_no_alias(y->rhoprime, MLDSA_CRHBYTES))+ requires(y->kappa <= MLD_MAX_KAPPA)+ assigns(memory_slice(buf, sizeof(mld_poly)))+ ensures(array_bound(buf->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))+)+{+ /* Safety: y->kappa <= MLD_MAX_KAPPA and i < MLDSA_L, so y->kappa + i+ * fits in uint16_t. See MLD_MAX_KAPPA comment in params.h. */+ mld_poly_uniform_gamma1(buf, y->rhoprime, (uint16_t)(y->kappa + i));+}+#endif /* !MLD_CONFIG_NO_SIGN_API && (MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST) \+ */++/* polymat */++#if !defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+/** Eager polymat: precomputed and stored full MLDSA_K x MLDSA_L matrix. */+typedef struct+{+ mld_polyvecl vec[MLDSA_K]; /**< Rows of the matrix. */+} mld_polymat_eager;+#endif /* !MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++/** Lazy polymat: store seed, sample elements A[k][l] on demand. */+typedef struct+{+ mld_poly cur; /**< On-demand sampled matrix element A[k][l]. */+ uint8_t rho[MLDSA_SEEDBYTES]; /**< Public seed used to expand A. */+} mld_polymat_lazy;++static MLD_INLINE void mld_poly_permute_bitrev_to_custom_optional(mld_poly *p)+__contract__(+ /* We don't specify that this is a permutation, only that it preserves+ * the bounds.+ * When the native NTT backend does not use the custom order, this is a no-op. */+ requires(memory_no_alias(p, sizeof(mld_poly)))+ requires(array_bound(p->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+ assigns(memory_slice(p, sizeof(mld_poly)))+ ensures(array_bound(p->coeffs, 0, MLDSA_N, 0, MLDSA_Q))+)+{+#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER)+ mld_poly_permute_bitrev_to_custom(p->coeffs);+#else+ (void)p;+#endif+}++#if !defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+/**+ * Generates matrix A with uniformly random coefficients a_{i,j} by performing+ * rejection sampling on the output stream of SHAKE128(rho|j|i).+ *+ * @spec{Implements @[FIPS204, Algorithm 32, ExpandA].}+ *+ * @param[out] mat Pointer to output matrix.+ * @param[in] rho Byte array containing seed rho.+ */+MLD_INTERNAL_API+void mld_polyvec_matrix_expand_eager(mld_polymat_eager *mat,+ const uint8_t rho[MLDSA_SEEDBYTES])+__contract__(+ requires(memory_no_alias(mat, sizeof(mld_polymat_eager)))+ requires(memory_no_alias(rho, MLDSA_SEEDBYTES))+ assigns(memory_slice(mat, sizeof(mld_polymat_eager)))+ ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,+ array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))+);++/**+ * Compute row i of matrix-vector multiplication in NTT domain with pointwise+ * multiplication and multiplication by 2^{-32}.+ *+ * Input matrix and vector must be in NTT domain representation. Output+ * coefficients are bounded by MLDSA_Q in absolute value.+ *+ * @param[out] t_row Pointer to output row polynomial.+ * @param[in] mat Pointer to input matrix.+ * @param[in] v Pointer to input vector v.+ * @param i Row index, 0 <= i < MLDSA_K.+ */+MLD_INTERNAL_API+void mld_polyvec_matrix_pointwise_montgomery_row_eager(mld_poly *t_row,+ mld_polymat_eager *mat,+ const mld_polyvecl *v,+ unsigned int i)+__contract__(+ requires(memory_no_alias(t_row, sizeof(mld_poly)))+ requires(memory_no_alias(mat, sizeof(mld_polymat_eager)))+ requires(memory_no_alias(v, sizeof(mld_polyvecl)))+ requires(i < MLDSA_K)+ requires(forall(l1, 0, MLDSA_L,+ array_bound(mat->vec[i].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))+ requires(forall(l2, 0, MLDSA_L,+ array_abs_bound(v->vec[l2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ assigns(memory_slice(t_row, sizeof(mld_poly)))+ ensures(array_abs_bound(t_row->coeffs, 0, MLDSA_N, MLDSA_Q))+);++#if !defined(MLD_CONFIG_NO_SIGN_API)+/**+ * Compute w = invNTT(A * NTT(y)) for the signing y vector.+ *+ * The eager variant copies y into the scratch polyvecl, NTTs it in place,+ * calls the standard matrix-vector multiply, and finally inverse-NTTs the+ * result into w.+ *+ * @param[out] w Pointer to output vector.+ * @param[in] mat Pointer to input matrix.+ * @param[in] y Pointer to (non-NTT) y vector.+ * @param[out] scratch Scratch polyvecl for NTT'd copy of y.+ */+MLD_INTERNAL_API+void mld_polyvec_matrix_pointwise_montgomery_yvec_eager(mld_polyveck *w,+ mld_polymat_eager *mat,+ const mld_yvec_eager *y,+ mld_polyvecl *scratch)+__contract__(+ requires(memory_no_alias(w, sizeof(mld_polyveck)))+ requires(memory_no_alias(mat, sizeof(mld_polymat_eager)))+ requires(memory_no_alias(y, sizeof(mld_yvec_eager)))+ requires(memory_no_alias(scratch, sizeof(mld_polyvecl)))+ requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,+ array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))+ requires(forall(l2, 0, MLDSA_L,+ array_bound(y->vec.vec[l2].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))+ assigns(memory_slice(w, sizeof(mld_polyveck)))+ assigns(memory_slice(scratch, sizeof(mld_polyvecl)))+ ensures(forall(k0, 0, MLDSA_K,+ array_abs_bound(w->vec[k0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */+#endif /* !MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++#if defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)+MLD_INTERNAL_API+void mld_polyvec_matrix_expand_lazy(mld_polymat_lazy *mat,+ const uint8_t rho[MLDSA_SEEDBYTES])+__contract__(+ requires(memory_no_alias(mat, sizeof(mld_polymat_lazy)))+ requires(memory_no_alias(rho, MLDSA_SEEDBYTES))+ assigns(memory_slice(mat, sizeof(mld_polymat_lazy)))+);++#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+/**+ * Compute row i of matrix-vector multiplication in NTT domain with pointwise+ * multiplication and multiplication by 2^{-32}.+ *+ * Input vector must be in NTT domain representation; the matrix entries are+ * sampled on demand from the seed stored in mat->rho, using mat->cur as+ * scratch. Output coefficients are bounded by MLDSA_Q in absolute value.+ *+ * @param[out] t_row Pointer to output row polynomial.+ * @param[in,out] mat Pointer to input matrix (seed + scratch).+ * @param[in] v Pointer to input vector v.+ * @param i Row index, 0 <= i < MLDSA_K.+ */+MLD_INTERNAL_API+void mld_polyvec_matrix_pointwise_montgomery_row_lazy(mld_poly *t_row,+ mld_polymat_lazy *mat,+ const mld_polyvecl *v,+ unsigned int i)+__contract__(+ requires(memory_no_alias(t_row, sizeof(mld_poly)))+ requires(memory_no_alias(mat, sizeof(mld_polymat_lazy)))+ requires(memory_no_alias(v, sizeof(mld_polyvecl)))+ requires(i < MLDSA_K)+ requires(forall(l1, 0, MLDSA_L,+ array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ assigns(memory_slice(t_row, sizeof(mld_poly)))+ assigns(memory_slice(mat, sizeof(mld_polymat_lazy)))+ ensures(array_abs_bound(t_row->coeffs, 0, MLDSA_N, MLDSA_Q))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+/**+ * Compute w = invNTT(A * NTT(y)) for the signing y vector.+ *+ * The lazy variant samples one column of y at a time, NTTs it into+ * &scratch->vec[0], and accumulates the matrix-vector product+ * column-by-column with on-demand sampling of A[k][l]. Only the first poly of+ * the polyvecl scratch is used; the polyvecl type is shared with the eager+ * variant for API uniformity (the storage is provided "for free" by the+ * caller's polyveck/polyvecl union in REDUCE_RAM mode).+ *+ * @param[out] w Pointer to output vector.+ * @param[in,out] mat Pointer to input matrix.+ * @param[in] y Pointer to y seed/kappa.+ * @param[out] scratch Scratch (only &scratch->vec[0] used).+ */+MLD_INTERNAL_API+void mld_polyvec_matrix_pointwise_montgomery_yvec_lazy(mld_polyveck *w,+ mld_polymat_lazy *mat,+ const mld_yvec_lazy *y,+ mld_polyvecl *scratch)+__contract__(+ requires(memory_no_alias(w, sizeof(mld_polyveck)))+ requires(memory_no_alias(mat, sizeof(mld_polymat_lazy)))+ requires(memory_no_alias(y, sizeof(mld_yvec_lazy)))+ requires(memory_no_alias(scratch, sizeof(mld_polyvecl)))+ requires(memory_no_alias(y->rhoprime, MLDSA_CRHBYTES))+ requires(y->kappa <= MLD_MAX_KAPPA)+ assigns(memory_slice(w, sizeof(mld_polyveck)))+ assigns(memory_slice(mat, sizeof(mld_polymat_lazy)))+ assigns(memory_slice(scratch, sizeof(mld_polyvecl)))+ ensures(forall(k0, 0, MLDSA_K,+ array_abs_bound(w->vec[k0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */+#endif /* MLD_CONFIG_REDUCE_RAM || MLD_UNIT_TEST */++/* Dispatch: typedef and define based on MLD_CONFIG_REDUCE_RAM */+#if defined(MLD_CONFIG_REDUCE_RAM)+typedef mld_sk_s1hat_lazy mld_sk_s1hat;+typedef mld_sk_s2hat_lazy mld_sk_s2hat;+typedef mld_sk_t0hat_lazy mld_sk_t0hat;+typedef mld_polymat_lazy mld_polymat;+typedef mld_yvec_lazy mld_yvec;+#define mld_unpack_sk_s1hat mld_unpack_sk_s1hat_lazy+#define mld_unpack_sk_s2hat mld_unpack_sk_s2hat_lazy+#define mld_unpack_sk_t0hat mld_unpack_sk_t0hat_lazy+#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_sk_s1hat_get_poly mld_sk_s1hat_get_poly_lazy+#define mld_sk_s2hat_get_poly mld_sk_s2hat_get_poly_lazy+#define mld_sk_t0hat_get_poly mld_sk_t0hat_get_poly_lazy+#endif+#define mld_polyvec_matrix_expand mld_polyvec_matrix_expand_lazy+#define mld_polyvec_matrix_pointwise_montgomery_row \+ mld_polyvec_matrix_pointwise_montgomery_row_lazy+#define mld_yvec_init mld_yvec_init_lazy+#define mld_yvec_get_poly mld_yvec_get_poly_lazy+#define mld_polyvec_matrix_pointwise_montgomery_yvec \+ mld_polyvec_matrix_pointwise_montgomery_yvec_lazy+#else /* MLD_CONFIG_REDUCE_RAM */+typedef mld_sk_s1hat_eager mld_sk_s1hat;+typedef mld_sk_s2hat_eager mld_sk_s2hat;+typedef mld_sk_t0hat_eager mld_sk_t0hat;+typedef mld_polymat_eager mld_polymat;+typedef mld_yvec_eager mld_yvec;+#define mld_unpack_sk_s1hat mld_unpack_sk_s1hat_eager+#define mld_unpack_sk_s2hat mld_unpack_sk_s2hat_eager+#define mld_unpack_sk_t0hat mld_unpack_sk_t0hat_eager+#if !defined(MLD_CONFIG_NO_SIGN_API)+#define mld_sk_s2hat_get_poly mld_sk_s2hat_get_poly_eager+#define mld_sk_s1hat_get_poly mld_sk_s1hat_get_poly_eager+#define mld_sk_t0hat_get_poly mld_sk_t0hat_get_poly_eager+#endif+#define mld_polyvec_matrix_expand mld_polyvec_matrix_expand_eager+#define mld_polyvec_matrix_pointwise_montgomery_row \+ mld_polyvec_matrix_pointwise_montgomery_row_eager+#define mld_yvec_init mld_yvec_init_eager+#define mld_yvec_get_poly mld_yvec_get_poly_eager+#define mld_polyvec_matrix_pointwise_montgomery_yvec \+ mld_polyvec_matrix_pointwise_montgomery_yvec_eager+#endif /* !MLD_CONFIG_REDUCE_RAM */++#endif /* !MLD_CONFIG_NO_KEYPAIR_API || !MLD_CONFIG_NO_SIGN_API || \+ !MLD_CONFIG_NO_VERIFY_API */+#endif /* !MLD_POLYVEC_LAZY_H */
@@ -0,0 +1,26 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_RANDOMBYTES_H+#define MLD_RANDOMBYTES_H++#include <stddef.h>++#include "cbmc.h"+#include "common.h"++#if !defined(MLD_CONFIG_NO_RANDOMIZED_API)+#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES)+MLD_MUST_CHECK_RETURN_VALUE+int randombytes(uint8_t *out, size_t outlen);++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen)+__contract__(+ requires(memory_no_alias(out, outlen))+ assigns(memory_slice(out, outlen))+) { return randombytes(out, outlen); }+#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */+#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLD_RANDOMBYTES_H */
@@ -0,0 +1,144 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#ifndef MLD_REDUCE_H+#define MLD_REDUCE_H++#include "cbmc.h"+#include "common.h"+#include "ct.h"+#include "debug.h"++/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */+#define MLD_MONT (-4186625)++/* Upper bound for domain of mld_reduce32() */+#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - ((int32_t)1 << 22))++/* Absolute bound for range of mld_reduce32() */+/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */+#define MLD_REDUCE32_RANGE_MAX 6283009++/**+ * Generic Montgomery reduction; given a 64-bit integer a, computes a 32-bit+ * integer congruent to a * R^-1 mod MLDSA_Q, where R=2^32.+ *+ * @spec{Implements @[FIPS204, Algorithm 49, MontgomeryReduce].}+ *+ * @param a Input integer to be reduced, of absolute value smaller or equal+ * to INT64_MAX - 2^31 * MLDSA_Q.+ *+ * @return Integer congruent to a * R^-1 modulo MLDSA_Q, with absolute value+ * <= |a| / 2^32 + MLDSA_Q / 2.+ * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value of the+ * return value is < MLDSA_Q.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a)+__contract__(+ /* We don't attempt to express an input-dependent output bound+ * as the post-condition here, as all call-sites satisfy the+ * absolute input bound 2^31 * MLDSA_Q and higher-level+ * reasoning can be conducted using |return_value| < MLDSA_Q. */+ requires(a > -(((int64_t)1 << 31) * MLDSA_Q) &&+ a < (((int64_t)1 << 31) * MLDSA_Q))+ ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q)+)+{+ /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */+ const uint64_t QINV = 58728449;++ /* Compute a*q^{-1} mod 2^32 in unsigned representatives */+ const uint32_t a_reduced = mld_cast_int64_to_uint32(a);+ const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX;++ /* Lift to signed canonical representative mod 2^32. */+ const int32_t t = mld_cast_uint32_to_int32(a_inverted);++ int64_t r;++ mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) &&+ a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)));++ r = a - (int64_t)t * MLDSA_Q;++ /*+ * PORTABILITY: Right-shift on a signed integer is, strictly-speaking,+ * implementation-defined for negative left argument. Here,+ * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5))+ */+ r = r >> 32;++ /* Bounds:+ *+ * By construction of the Montgomery multiplication, by the time we+ * compute r >> 32, r is divisible by 2^32, and hence+ *+ * |r >> 32| = |r| / 2^32+ * <= |a| / 2^32 + MLDSA_Q / 2+ *+ * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)).+ *+ * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q.+ */+ return (int32_t)r;+}++/**+ * For finite field element a with a <= 2^{31} - 2^{22} - 1, compute+ * r congruent to a (mod MLDSA_Q) such that+ * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX.+ *+ * @param a Finite field element.+ *+ * @return r.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int32_t mld_reduce32(int32_t a)+__contract__(+ requires(a <= MLD_REDUCE32_DOMAIN_MAX)+ ensures(return_value >= -MLD_REDUCE32_RANGE_MAX)+ ensures(return_value < MLD_REDUCE32_RANGE_MAX)+)+{+ int32_t t;++ t = (a + ((int32_t)1 << 22)) >> 23;+ t = a - t * MLDSA_Q;+ mld_assert((t - a) % MLDSA_Q == 0);+ return t;+}++/**+ * Add MLDSA_Q if input coefficient is negative.+ *+ * @param a Finite field element.+ *+ * @return r.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int32_t mld_caddq(int32_t a)+__contract__(+ requires(a > -MLDSA_Q)+ requires(a < MLDSA_Q)+ ensures(return_value >= 0)+ ensures(return_value < MLDSA_Q)+ ensures(return_value == ((a >= 0) ? a : (a + MLDSA_Q)))+)+{+ return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a));+}+++#endif /* !MLD_REDUCE_H */
@@ -0,0 +1,265 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#ifndef MLD_ROUNDING_H+#define MLD_ROUNDING_H++#include "cbmc.h"+#include "common.h"+#include "ct.h"+#include "debug.h"++/* Parameter set namespacing+ * This is to facilitate building multiple instances+ * of mldsa-native (e.g. with varying parameter sets)+ * within a single compilation unit. */+#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round)+#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose)+#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint)+#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint)+/* End of parameter set namespacing */++#define MLD_2_POW_D (1 << MLDSA_D)++/**+ * For finite field element a, compute a0, a1 such that+ * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with+ * -2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes a to be standard+ * representative.+ *+ * @spec{Implements @[FIPS204, Algorithm 35, Power2Round].}+ *+ * @reference{In the reference implementation, a1 is passed as a return value+ * instead.}+ *+ * @param[out] a0 Pointer to output element a0.+ * @param[out] a1 Pointer to output element a1.+ * @param a Input element.+ */+static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a)+__contract__(+ requires(memory_no_alias(a0, sizeof(int32_t)))+ requires(memory_no_alias(a1, sizeof(int32_t)))+ requires(a >= 0 && a < MLDSA_Q)+ assigns(memory_slice(a0, sizeof(int32_t)))+ assigns(memory_slice(a1, sizeof(int32_t)))+ ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2))+ ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D)+ ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0)+)+{+ *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D;+ *a0 = a - (*a1 << MLDSA_D);+}++/**+ * For finite field element a, compute high and low bits a0, a1 such that+ * a mod^+ MLDSA_Q = a1 * 2 * MLDSA_GAMMA2 + a0 with+ * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except if+ * a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and+ * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. Assumes a to be+ * standard representative.+ *+ * @spec{Implements @[FIPS204, Algorithm 36, Decompose].}+ *+ * @reference{In the reference implementation, a1 is passed as a return value+ * instead.}+ *+ * @param[out] a0 Pointer to output element a0.+ * @param[out] a1 Pointer to output element a1.+ * @param a Input element.+ */+static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a)+__contract__(+ requires(memory_no_alias(a0, sizeof(int32_t)))+ requires(memory_no_alias(a1, sizeof(int32_t)))+ requires(a >= 0 && a < MLDSA_Q)+ assigns(memory_slice(a0, sizeof(int32_t)))+ assigns(memory_slice(a1, sizeof(int32_t)))+ /* a0 = -MLDSA_GAMMA2 occurs exactly when a = MLDSA_Q - MLDSA_GAMMA2: the+ * border case of Decompose where a1 = (MLDSA_Q-1)/(2*MLDSA_GAMMA2) is+ * wrapped to 0 and a0 = a - MLDSA_Q (@[FIPS204, Algorithm 36, Decompose]) */+ ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2)+ ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2))+ ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0)+)+{+ /*+ * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed+ * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where+ * B = 2*GAMMA2 / 128. Here round-() denotes "round half down".+ *+ * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced+ * as follows. Since changing f to align-up(f, 128) can move f onto but not+ * across a rounding boundary for division by 128*B (note that we need B to be+ * even for this to work), and round- rounds down on the boundary, we have+ *+ * round-(f / (128B)) = round-(align-up(f, 128) / (128B))+ * = round-((align-up(f, 128) / 128) / B)+ * = round-(ceil(f / 128) / B).+ */+ *a1 = (a + 127) >> 7;+ /* We know a >= 0 and a < MLDSA_Q, so... */+ /* check-magic: 65472 == round((MLDSA_Q-1)/128) */+ mld_assert(*a1 >= 0 && *a1 <= 65472);++#if MLD_CONFIG_PARAMETER_SET == 44+ /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */+ /* check-magic: 11275 == floor(2**24 / 1488) */+ /* check-magic: 1560281088 == 1 / (1 / 1488 - 11275 / 2**24) */+ /*+ * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact for+ * 0 <= f1' < 2^16.+ *+ * To see this, consider the (signed) error f1' * (1 / B - 11275 / 2^24)+ * between f1' / B and the (under-)approximation f1' * 11275 / 2^24. Because+ * eps := 1 / B - 11275 / 2^24 is 1 / 1560281088 ≈ 2^(-30.54) < 2^(-30), we+ * have 0 <= f1' * eps < 2^16 * 2^(-30) = 1 / 2^14 < 1 / 2^11 < 1 / B (note+ * that f1' is non-negative).+ *+ * On the other hand, 1 / B is the spacing between the integral multiples+ * of 1 / B, which includes all rounding boundaries n + 0.5 (since B is even).+ * Hence, if f1' / B is not of the form n + 0.5, then it is at least 1 / B+ * away from the nearest rounding boundary, so moving from f1' / B to+ * f1' * 11275 / 2^24 does not affect the rounding result, no matter the type+ * of rounding used in either side. In particular, we have round-(f1' / B) =+ * round(f1' * 11275 / 2^24) as claimed.+ *+ * As for the remaining case where f1' / B _is_ of the form n + 0.5, because+ * f1' * 11275 / 2^24 is slightly but strictly below f1' / B = n + 0.5 (note+ * that f1' and thus the error f1' * eps cannot be 0 here), it is always+ * rounded down to n. More precisely, we have round-(f1' / B) =+ * round(f1' * 11275 / 2^24), where the round-down on the LHS is essential,+ * and on the RHS the type of rounding again does not matter. This concludes+ * the proof.+ *+ * See proofs/isabelle/compress for a formalization of the above argument.+ */+ *a1 = (*a1 * 11275 + ((int32_t)1 << 23)) >> 24;+ mld_assert(*a1 >= 0 && *a1 <= 44);++ *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1));+ mld_assert(*a1 >= 0 && *a1 <= 43);+#else /* MLD_CONFIG_PARAMETER_SET == 44 */+ /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */+ /* check-magic: 1025 == floor(2**22 / 4092) */+ /* check-magic: 4290772992 == 1 / (1 / 4092 - 1025 / 2**22) */+ /*+ * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact for+ * 0 <= f1' < 2^16. Following the same argument above, it suffices to show+ * that f1' * eps < 1 / B, where eps := 1 / B - 1025 / 2^22. Indeed, we have+ * eps = 1 / 4290772992 ≈ 2^(-31.99) < 2^(-31), therefore f1' * eps <+ * 2^16 * 2^(-31) = 1 / 2^15 < 1 / 2^12 < 1 / B.+ */+ *a1 = (*a1 * 1025 + ((int32_t)1 << 21)) >> 22;+ mld_assert(*a1 >= 0 && *a1 <= 16);++ *a1 &= 15;+ mld_assert(*a1 >= 0 && *a1 <= 15);++#endif /* MLD_CONFIG_PARAMETER_SET != 44 */++ *a0 = a - *a1 * 2 * MLDSA_GAMMA2;+ *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0,+ mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0));+}++/**+ * Decide a single hint bit from the low part a0 and high part a1 of a+ * coefficient: return 1 unless a0 lies in the range (-GAMMA2, GAMMA2] that+ * LowBits would produce, with the boundary value -GAMMA2 also admitted when+ * a1 == 0 (the Decompose border case).+ *+ * @note This is not a line-for-line implementation of FIPS 204's MakeHint(z, r)+ * (@[FIPS204, Algorithm 39, MakeHint]), which takes two ring elements and+ * returns [[HighBits(r) != HighBits(r + z)]]. Instead, it takes the already+ * decomposed low/high parts (a0, a1) of a coefficient and decides the hint bit+ * from them directly. As explained in the block comment of+ * mld_attempt_signature_generation (sign.c), for the specific values that arise+ * during signing -- a0 = w0 - cs2 + ct0 and a1 = w1 = HighBits(w) -- this is+ * equivalent to the spec's MakeHint(-ct0, w - cs2 + ct0) coefficient-wise.+ * Because it consumes (a0, a1) rather than (z, r), it relies on the caller+ * having computed a compatible decomposition.+ *+ * @param a0 Low bits of input element.+ * @param a1 High bits of input element.+ *+ * @return 1 if overflow, 0 otherwise.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1)+__contract__(+ ensures(return_value >= 0 && return_value <= 1)+ ensures(return_value == (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 ||+ (a0 == -MLDSA_GAMMA2 && a1 != 0)))+)+{+ if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 ||+ (a0 == -MLDSA_GAMMA2 && a1 != 0))+ {+ return 1;+ }++ return 0;+}++/**+ * Correct high bits according to hint.+ *+ * @spec{Implements @[FIPS204, Algorithm 40, UseHint].}+ *+ * @param a Input element.+ * @param hint Hint bit.+ *+ * @return Corrected high bits.+ */+MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint)+__contract__(+ requires(hint >= 0 && hint <= 1)+ requires(a >= 0 && a < MLDSA_Q)+ ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2))+)+{+ int32_t a0, a1;++ mld_decompose(&a0, &a1, a);+ if (hint == 0)+ {+ return a1;+ }++#if MLD_CONFIG_PARAMETER_SET == 44+ if (a0 > 0)+ {+ return (a1 == 43) ? 0 : a1 + 1;+ }+ else+ {+ return (a1 == 0) ? 43 : a1 - 1;+ }+#else /* MLD_CONFIG_PARAMETER_SET == 44 */+ if (a0 > 0)+ {+ return (a1 + 1) & 15;+ }+ else+ {+ return (a1 - 1) & 15;+ }+#endif /* MLD_CONFIG_PARAMETER_SET != 44 */+}+++#endif /* !MLD_ROUNDING_H */
@@ -0,0 +1,1720 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS140_3_IG]+ * Implementation Guidance for FIPS 140-3 and the Cryptographic Module+ * Validation Program+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ *+ * - [FIPS204_UPDATES]+ * FIPS 204 Potential Updates (Errata)+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/files/pubs/fips/204/final/docs/fips-204-potential-updates.xlsx+ *+ * - [Round3_Spec]+ * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation+ * (Version 3.1)+ * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé+ * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf+ */++#include "sign.h"++#include "cbmc.h"+#include "ct.h"+#include "debug.h"+#include "packing.h"+#include "poly.h"+#include "poly_kl.h"+#include "polyvec.h"+#include "randombytes.h"+#include "symmetric.h"++/* Parameter set namespacing+ * This is to facilitate building multiple instances+ * of mldsa-native (e.g. with varying parameter sets)+ * within a single compilation unit. */+#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2+#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2)+#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length)+#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid)+#define mld_H MLD_ADD_PARAM_SET(mld_H)+#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z)+#define mld_attempt_signature_generation \+ MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8+#define mld_compute_pack_t0_t1 \+ MLD_ADD_PARAM_SET(mld_compute_pack_t0_t1) MLD_CONTEXT_PARAMETERS_5+#define mld_get_max_signing_attempts \+ MLD_ADD_PARAM_SET(mld_get_max_signing_attempts)++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY ||+ return_value == MLD_ERR_RNG_FAIL ||+ return_value == MLD_ERR_SIGNING_PAUSED ||+ return_value == MLD_ERR_PCT_FAIL)+);++#if defined(MLD_CONFIG_KEYGEN_PCT)+/**+ * Pair-wise Consistency Test (PCT) for DSA keypairs.+ *+ * @[FIPS140_3_IG] TE10.35.02+ * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf).+ *+ * Validates that a generated public/private key pair can correctly sign and+ * verify data. Performs signature generation using the private key (sk),+ * followed by signature verification using the public key (pk).+ *+ * @note @[FIPS204] requires that public/private key pairs are to be used+ * only for the calculation and/or verification of digital signatures.+ *+ * @param[in] pk Public key.+ * @param[in] sk Secret key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was used and an+ * allocation via MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_RNG_FAIL Random number generation failed.+ * @retval MLD_ERR_SIGNING_PAUSED The PCT's signing step was paused by a+ * MLD_CONFIG_SIGN_HOOK_ATTEMPT hook.+ * @retval MLD_ERR_PCT_FAIL The consistency check failed.+ */+static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ MLD_ALIGN uint8_t message[1] = {0};+ int ret;+ MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context);+ MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context);++ if (signature == NULL || pk_test == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* Copy public key for testing */+ mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES);++ /* Sign a test message using the original secret key */+ ret = mld_sign_signature(signature, message, sizeof(message), NULL, 0, sk,+ context);+ if (ret != 0)+ {+ goto cleanup;+ }++#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST)+ /* Deliberately break public key for testing purposes */+ if (mld_break_pct())+ {+ pk_test[0] = ~pk_test[0];+ }+#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */++ /* Verify the signature using the (potentially corrupted) public key. */+ ret = mld_sign_verify(signature, message, sizeof(message), NULL, 0, pk_test,+ context);+ if (ret != 0)+ {+ goto cleanup;+ }++cleanup:+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context);+ MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context);++ /* A failed signing operation or an invalid signature hint at a faulty+ * implementation and map to a dedicated error code for PCT failure. */+ if (ret == MLD_ERR_INVALID_SIGNATURE ||+ ret == MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED)+ {+ ret = MLD_ERR_PCT_FAIL;+ }++ /* Other error codes, e.g. platform failures like out of memory or+ * randomness failure, are passed on unmodified. */++ return ret;+}+#else /* MLD_CONFIG_KEYGEN_PCT */+static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ /* Skip PCT */+ ((void)pk);+ ((void)sk);+ MLD_CONTEXT_UNUSED(context);+ return 0;+}+#endif /* !MLD_CONFIG_KEYGEN_PCT */++/**+ * Sample the short secret vectors s1 (length MLDSA_L) and s2 (length MLDSA_K)+ * with coefficients in [-MLDSA_ETA, MLDSA_ETA] from the seed.+ *+ * @spec{Implements @[FIPS204, Algorithm 33, ExpandS].}+ *+ * @param[out] s1 Output vector s1.+ * @param[out] s2 Output vector s2.+ * @param[in] seed Byte array with seed of length MLDSA_CRHBYTES.+ */+static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2,+ const uint8_t seed[MLDSA_CRHBYTES])+__contract__(+ requires(memory_no_alias(s1, sizeof(mld_polyvecl)))+ requires(memory_no_alias(s2, sizeof(mld_polyveck)))+ requires(memory_no_alias(seed, MLDSA_CRHBYTES))+ assigns(object_whole(s1), object_whole(s2))+ ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))+ ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))+)+{+/* Sample short vectors s1 and s2 */+#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+ int i;+ uint16_t nonce = 0;+ /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the+ * casts are safe. */+ for (i = 0; i < MLDSA_L; i++)+ {+ mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i));+ }+ for (i = 0; i < MLDSA_K; i++)+ {+ mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i));+ }+#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */+#if MLD_CONFIG_PARAMETER_SET == 44+ mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3],+ seed, 0, 1, 2, 3);+ mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3],+ seed, 4, 5, 6, 7);+#elif MLD_CONFIG_PARAMETER_SET == 65+ mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3],+ seed, 0, 1, 2, 3);+ mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1],+ &s2->vec[2] /* irrelevant */, seed, 4, 5, 6,+ 0xFF /* irrelevant */);+ mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5],+ seed, 7, 8, 9, 10);+#elif MLD_CONFIG_PARAMETER_SET == 87+ mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3],+ seed, 0, 1, 2, 3);+ mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6],+ &s2->vec[0] /* irrelevant */, seed, 4, 5, 6,+ 0xFF /* irrelevant */);+ mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3],+ seed, 7, 8, 9, 10);+ mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7],+ seed, 11, 12, 13, 14);+#endif /* MLD_CONFIG_PARAMETER_SET == 87 */+#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */+}++/**+ * Compute t = A*s1hat + s2 row by row, decompose each row into t0[k] and+ * t1[k] via power2round, and bit-pack t1[k] into pk_t1 and t0[k] into the+ * t0_packed buffer. Used by both keygen and pk_from_sk.+ *+ * @spec{Partially implements @[FIPS204, Algorithm 22, pkEncode] (t1) and+ * @[FIPS204, Algorithm 24, skEncode] (t0).}+ *+ * @param[out] pk_t1 Output buffer for packed t1 (size+ * MLDSA_K * MLDSA_POLYT1_PACKEDBYTES; i.e. the t1+ * region of pk).+ * @param[out] t0_packed Output buffer for packed t0 (size+ * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES).+ * @param[in] s1hat s1 in NTT domain.+ * @param[in] s2 s2.+ * @param[in] rho Byte array containing seed rho.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @return - 0: Success.+ * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is used and+ * an allocation via MLD_CUSTOM_ALLOC returned NULL.+ */+MLD_MUST_CHECK_RETURN_VALUE+static int mld_compute_pack_t0_t1(+ uint8_t pk_t1[MLDSA_K * MLDSA_POLYT1_PACKEDBYTES],+ uint8_t t0_packed[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES],+ const mld_polyvecl *s1hat, const mld_polyveck *s2,+ const uint8_t rho[MLDSA_SEEDBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk_t1, MLDSA_K * MLDSA_POLYT1_PACKEDBYTES))+ requires(memory_no_alias(t0_packed, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))+ requires(memory_no_alias(s1hat, sizeof(mld_polyvecl)))+ requires(memory_no_alias(s2, sizeof(mld_polyveck)))+ requires(memory_no_alias(rho, MLDSA_SEEDBYTES))+ requires(forall(l1, 0, MLDSA_L,+ array_abs_bound(s1hat->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ requires(forall(k2, 0, MLDSA_K,+ array_bound(s2->vec[k2].coeffs, 0, MLDSA_N,+ MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))+ assigns(memory_slice(pk_t1, MLDSA_K * MLDSA_POLYT1_PACKEDBYTES))+ assigns(memory_slice(t0_packed, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY))+{+ unsigned int k;+ int ret;+ MLD_ALLOC(mat, mld_polymat, 1, context);+ MLD_ALLOC(t0k, mld_poly, 1, context);+ MLD_ALLOC(t1k, mld_poly, 1, context);++ if (mat == NULL || t0k == NULL || t1k == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* Expand matrix */+ mld_polyvec_matrix_expand(mat, rho);++ for (k = 0; k < MLDSA_K; k++)+ __loop__(+ assigns(k, memory_slice(pk_t1, MLDSA_K * MLDSA_POLYT1_PACKEDBYTES),+ memory_slice(t0_packed, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES),+ memory_slice(t0k, sizeof(mld_poly)),+ memory_slice(t1k, sizeof(mld_poly))+ MLD_IF_REDUCE_RAM(, memory_slice(mat, sizeof(mld_polymat))))+ invariant(k <= MLDSA_K)+ decreases(MLDSA_K - k)+ )+ {+ /* t0k = (A * s1hat)_k in NTT domain */+ mld_polyvec_matrix_pointwise_montgomery_row(t0k, mat, s1hat, k);++ /* t0k = invNTT(t0k) */+ mld_poly_invntt_tomont(t0k);++ /* t0k += s2[k] */+ mld_poly_add(t0k, &s2->vec[k]);++ /* Reference: The following reduction is not present in the reference+ * implementation. Omitting this reduction requires the output+ * of the invntt to be small enough such that the addition of+ * s2 does not result in absolute values >= MLDSA_Q. While our+ * C, x86_64, and AArch64 invntt implementations produce small+ * enough values for this to work out, it complicates the+ * bounds reasoning. We instead add an additional reduction,+ * and can consequently, relax the bounds requirements for the+ * invntt.+ */+ mld_poly_reduce(t0k);++ /* Decompose into t1[k] and t0[k] (in place into t0k). */+ mld_poly_caddq(t0k);+ mld_poly_power2round(t1k, t0k, t0k);++ /* Pack t1[k] into pk and t0[k] into the t0 output buffer. */+ mld_polyt1_pack(pk_t1 + k * MLDSA_POLYT1_PACKEDBYTES, t1k);+ mld_polyt0_pack(t0_packed + k * MLDSA_POLYT0_PACKEDBYTES, t0k);+ }++ ret = 0;+cleanup:+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(t1k, mld_poly, 1, context);+ MLD_FREE(t0k, mld_poly, 1, context);+ MLD_FREE(mat, mld_polymat, 1, context);+ return ret;+}++MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ const uint8_t seed[MLDSA_SEEDBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret;+ const uint8_t *rho, *rhoprime, *key;++ MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context);+ MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context);+ MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context);+ MLD_ALLOC(s1, mld_polyvecl, 1, context);+ MLD_ALLOC(s2, mld_polyveck, 1, context);++ if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL ||+ s2 == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* Get randomness for rho, rhoprime and key */+ mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES);+ inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K;+ inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L;+ mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf,+ MLDSA_SEEDBYTES + 2);+ rho = seedbuf;+ rhoprime = rho + MLDSA_SEEDBYTES;+ key = rhoprime + MLDSA_CRHBYTES;++ /* Constant time: rho is part of the public key and, hence, public. */+ MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES);++ /* Sample s1 and s2 */+ mld_sample_s1_s2(s1, s2, rhoprime);++ /* Pack s1 into sk before NTT */+ mld_pack_sk_s1(sk, s1);++ /* NTT s1 in place to use as s1hat */+ mld_polyvecl_ntt(s1);++ /* Pack rho into pk */+ mld_memcpy(pk + MLDSA_PK_RHO_OFFSET, rho, MLDSA_SEEDBYTES);++ /* Compute t = A*s1hat + s2 row by row, decompose into t1/t0, and pack+ * t1 into pk and t0 directly into the t0 region of sk. */+ ret = mld_compute_pack_t0_t1(pk + MLDSA_PK_T1_OFFSET, sk + MLDSA_SK_T0_OFFSET,+ s1, s2, rho, context);+ if (ret != 0)+ {+ goto cleanup;+ }++ /* Compute tr = H(pk) */+ mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES);++ /* Pack remaining secret key components (s1 and t0 already packed) */+ mld_pack_sk_rho_key_tr_s2(sk, rho, tr, key, s2);++ /* Constant time: pk is the public key, inherently public data */+ MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES);++cleanup:+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(s2, mld_polyveck, 1, context);+ MLD_FREE(s1, mld_polyvecl, 1, context);+ MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context);+ MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context);+ MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context);++ /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */+ /* Do this after freeing all temporaries. */+ if (ret == 0)+ {+ ret = mld_check_pct(pk, sk, context);+ }++ if (ret != 0)+ {+ /* Clear caller outputs on failure. */+ mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES);+ mld_zeroize(sk, MLDSA_CRYPTO_SECRETKEYBYTES);+ }++ return ret;+}++#if !defined(MLD_CONFIG_CORE_API_ONLY)+#if !defined(MLD_CONFIG_NO_RANDOMIZED_API)+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret;+ MLD_ALLOC(seed, uint8_t, MLDSA_SEEDBYTES, context);++ if (seed == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0)+ {+ ret = MLD_ERR_RNG_FAIL;+ goto cleanup;+ }+ MLD_CT_TESTING_SECRET(seed, MLDSA_SEEDBYTES);+ ret = mld_sign_keypair_internal(pk, sk, seed, context);++cleanup:+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(seed, uint8_t, MLDSA_SEEDBYTES, context);+ return ret;+}+#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+/**+ * Abstracts application of SHAKE256 to one, two or three blocks of data,+ * yielding a user-requested size of output.+ *+ * @param[out] out Pointer to output.+ * @param outlen Requested output length in bytes.+ * @param[in] in1 Pointer to input block 1. Must NOT be NULL.+ * @param in1len Length of input in1 in bytes.+ * @param[in] in2 Pointer to input block 2. May be NULL if in2len == 0,+ * in which case this block is ignored.+ * @param in2len Length of input in2 in bytes.+ * @param[in] in3 Pointer to input block 3. May be NULL if in3len == 0,+ * in which case this block is ignored.+ * @param in3len Length of input in3 in bytes.+ */+static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1,+ size_t in1len, const uint8_t *in2, size_t in2len,+ const uint8_t *in3, size_t in3len)+__contract__(+ requires(in1len <= MLD_MAX_BUFFER_SIZE)+ requires(in2len <= MLD_MAX_BUFFER_SIZE)+ requires(in3len <= MLD_MAX_BUFFER_SIZE)+ requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */)+ requires(memory_no_alias(in1, in1len))+ requires(in2len == 0 || memory_no_alias(in2, in2len))+ requires(in3len == 0 || memory_no_alias(in3, in3len))+ requires(memory_no_alias(out, outlen))+ assigns(memory_slice(out, outlen))+)+{+ mld_shake256ctx state;+ mld_shake256_init(&state);+ mld_shake256_absorb(&state, in1, in1len);+ if (in2len != 0)+ {+ mld_shake256_absorb(&state, in2, in2len);+ }+ if (in3len != 0)+ {+ mld_shake256_absorb(&state, in3, in3len);+ }+ mld_shake256_finalize(&state);+ mld_shake256_squeeze(out, outlen, &state);+ mld_shake256_release(&state);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(&state, sizeof(state));+}+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+/* MLD_MAX_KAPPA (see params.h) bounds the rejection-sampling counter kappa;+ * MLD_MAX_SIGNING_ATTEMPTS below turns that into a bound on attempts. */++/**+ * Compute z = y + s1*c, check that z has coefficients smaller than+ * MLDSA_GAMMA1 - MLDSA_BETA, and pack z into the signature buffer.+ *+ * @reference{This function is inlined into mld_sign_signature in the+ * reference implementation.}+ *+ * @param[in,out] sig Output signature.+ * @param[in] cp Challenge polynomial.+ * @param[in] s1hat Secret vector s1 in NTT domain.+ * @param[in] y Masking vector y (or seed in REDUCE_RAM mode).+ * @param[out] z Scratch polynomial for z computation.+ * @param[out] tmp Scratch polynomial.+ *+ * @return - 0: Success (z has coefficients smaller than+ * MLDSA_GAMMA1 - MLDSA_BETA).+ * - MLD_ERR_FAIL: z rejected (norm check failed).+ * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is used and+ * an allocation via MLD_CUSTOM_ALLOC returned NULL.+ */+MLD_MUST_CHECK_RETURN_VALUE+static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES],+ const mld_poly *cp, const mld_sk_s1hat *s1hat,+ const mld_yvec *y, mld_poly *z, mld_poly *tmp)+__contract__(+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(cp, sizeof(mld_poly)))+ requires(memory_no_alias(s1hat, sizeof(mld_sk_s1hat)))+ requires(memory_no_alias(y, sizeof(mld_yvec)))+ requires(memory_no_alias(z, sizeof(mld_poly)))+ requires(memory_no_alias(tmp, sizeof(mld_poly)))+ requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))+ MLD_IF_NOT_REDUCE_RAM(+ requires(forall(k0, 0, MLDSA_L,+ array_bound(y->vec.vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))+ requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1hat->vec.vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ )+ MLD_IF_REDUCE_RAM(+ requires(memory_no_alias(s1hat->packed, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))+ requires(memory_no_alias(y->rhoprime, MLDSA_CRHBYTES))+ requires(y->kappa <= MLD_MAX_KAPPA)+ )+ assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))+ assigns(memory_slice(z, sizeof(mld_poly)))+ assigns(memory_slice(tmp, sizeof(mld_poly)))+ ensures(return_value == 0 || return_value == MLD_ERR_FAIL ||+ return_value == MLD_ERR_OUT_OF_MEMORY)+)+{+ unsigned int i;+ uint32_t z_invalid;+ for (i = 0; i < MLDSA_L; i++)+ __loop__(+ assigns(i, memory_slice(z, sizeof(mld_poly)),+ memory_slice(tmp, sizeof(mld_poly)),+ memory_slice(sig, MLDSA_CRYPTO_BYTES))+ invariant(i <= MLDSA_L)+ decreases(MLDSA_L - i)+ )+ {+ mld_sk_s1hat_get_poly(z, s1hat, i);+ mld_poly_pointwise_montgomery(z, cp);+ mld_poly_invntt_tomont(z);+ mld_yvec_get_poly(tmp, y, i);+ mld_poly_add(z, tmp);+ mld_poly_reduce(z);++ z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA);+ /* Constant time: It is fine (and prohibitively expensive to avoid)+ * to leak the result of the norm check and which polynomial in z caused a+ * rejection. It would even be okay to leak which coefficient led to+ * rejection as the candidate signature will be discarded anyway.+ * See Section 5.5 of @[Round3_Spec]. */+ MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t));+ if (z_invalid)+ {+ return MLD_ERR_FAIL; /* reject */+ }+ /* If z is valid, then its coefficients are bounded by+ * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below+ * to prove the pre-condition of pack_sig_z() */+ mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA));++ /* After the norm check, the distribution of each coefficient of z is+ * independent of the secret key and it can, hence, be considered+ * public. It is, hence, okay to immediately pack it into the user-provided+ * signature buffer. */+ mld_pack_sig_z(sig, z, i);+ }+ return 0;+}++/* Effective bound on signing attempts: the configured bound+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS (see mldsa_native_config.h) if set, otherwise+ * the hard type-safety bound MLD_MAX_KAPPA / MLDSA_L (see MLD_MAX_KAPPA in+ * params.h). */+#if defined(MLD_CONFIG_MAX_SIGNING_ATTEMPTS)++#if !defined(MLD_ALLOW_NONCOMPLIANT_SIGNING_BOUND) && \+ MLD_CONFIG_MAX_SIGNING_ATTEMPTS < 821+#error Bad configuration: MLD_CONFIG_MAX_SIGNING_ATTEMPTS must be >= 821 for FIPS 204 compliance @[FIPS204, Appendix C] @[FIPS204_UPDATES]+#endif++#if MLD_CONFIG_MAX_SIGNING_ATTEMPTS < 1+#error Bad configuration: MLD_CONFIG_MAX_SIGNING_ATTEMPTS must be >= 1+#endif++#if MLD_CONFIG_MAX_SIGNING_ATTEMPTS > MLD_MAX_KAPPA / MLDSA_L+#error Bad configuration: MLD_CONFIG_MAX_SIGNING_ATTEMPTS exceeds the maximum allowed value.+#endif++#define MLD_MAX_SIGNING_ATTEMPTS MLD_CONFIG_MAX_SIGNING_ATTEMPTS+#else /* MLD_CONFIG_MAX_SIGNING_ATTEMPTS */+#define MLD_MAX_SIGNING_ATTEMPTS (MLD_MAX_KAPPA / MLDSA_L)+#endif /* !MLD_CONFIG_MAX_SIGNING_ATTEMPTS */++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE uint16_t mld_get_max_signing_attempts(void)+__contract__(+ ensures(return_value >= 1)+ ensures(return_value <= MLD_MAX_KAPPA / MLDSA_L)+)+{+ /* cassert(0) ensures CBMC uses the contract rather than inlining the body,+ * keeping proofs agnostic of the configured value. */+ cassert(0);+ return MLD_MAX_SIGNING_ATTEMPTS;+}++/**+ * Attempt to generate a single signature: one iteration of the+ * ML-DSA.Sign_internal rejection-sampling loop.+ *+ * @spec{Implements one iteration of the rejection-sampling loop body of+ * @[FIPS204, Algorithm 7, ML-DSA.Sign_internal] (lines 11-30) plus, on success,+ * the sigEncode step (line 33). The per-signature setup (Algorithm 7 lines 1-7:+ * skDecode, NTT of s1/s2/t0, ExpandA, and computation of mu and rhoprime) and+ * the loop itself (lines 8-10, 31-32) live in the caller+ * mld_sign_signature_internal; kappa is this iteration's counter, used to+ * sample y.}+ *+ * @reference{This code differs from the reference implementation in that it+ * factors out the core signature generation step into a distinct function+ * here in order to improve efficiency of CBMC proof.}+ *+ * @param[out] sig Pointer to output signature.+ * @param[in] mu Pointer to message or hash of exactly MLDSA_CRHBYTES+ * bytes.+ * @param[in] rhoprime Pointer to randomness seed.+ * @param kappa Counter for this iteration (= attempt*MLDSA_L).+ * @param[in] mat Expanded matrix.+ * @param[in] s1hat Secret vector s1 in NTT domain.+ * @param[in] s2hat Secret vector s2 in NTT domain.+ * @param[in] t0hat Vector t0 in NTT domain.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @return - 0: Signature generation succeeded.+ * - MLD_ERR_FAIL: Signature rejected (norm check failed).+ * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is used and+ * an allocation via MLD_CUSTOM_ALLOC returned NULL.+ */+MLD_MUST_CHECK_RETURN_VALUE+/* NOLINTNEXTLINE(readability-function-cognitive-complexity) */+static int mld_attempt_signature_generation(+ uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu,+ const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t kappa, mld_polymat *mat,+ const mld_sk_s1hat *s1hat, const mld_sk_s2hat *s2hat,+ const mld_sk_t0hat *t0hat, MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(mu, MLDSA_CRHBYTES))+ requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES))+ requires(memory_no_alias(mat, sizeof(mld_polymat)))+ requires(memory_no_alias(s1hat, sizeof(mld_sk_s1hat)))+ requires(memory_no_alias(s2hat, sizeof(mld_sk_s2hat)))+ requires(memory_no_alias(t0hat, sizeof(mld_sk_t0hat)))+ requires(kappa <= MLD_MAX_KAPPA)+ MLD_IF_NOT_REDUCE_RAM(+ requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,+ array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))+ requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0hat->vec.vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1hat->vec.vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2hat->vec.vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ )+ MLD_IF_REDUCE_RAM(+ requires(memory_no_alias(s1hat->packed, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))+ requires(memory_no_alias(s2hat->packed, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))+ requires(memory_no_alias(t0hat->packed, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))+ )+ assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))+ MLD_IF_REDUCE_RAM(+ assigns(memory_slice(mat, sizeof(mld_polymat)))+ )+ ensures(return_value == 0 || return_value == MLD_ERR_FAIL ||+ return_value == MLD_ERR_OUT_OF_MEMORY)+)+{+ unsigned int k;+ uint32_t w0_invalid, h_invalid;+ int ret;++ typedef union+ {+ mld_polyveck w1;+ mld_polyvecl tmp;+ } w1tmp_u;+ mld_polyveck *w1;+ mld_polyvecl *tmp;++ MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context);+ MLD_ALLOC(y, mld_yvec, 1, context);+ MLD_ALLOC(z, mld_poly, 1, context);+ MLD_ALLOC(w1tmp, w1tmp_u, 1, context);+ MLD_ALLOC(w0, mld_polyveck, 1, context);+ MLD_ALLOC(cp, mld_poly, 1, context);+ MLD_ALLOC(t, mld_poly, 1, context);++ if (challenge_bytes == NULL || y == NULL || z == NULL || w1tmp == NULL ||+ w0 == NULL || cp == NULL || t == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }+ w1 = &w1tmp->w1;+ tmp = &w1tmp->tmp;++ /* @[FIPS204, Algorithm 7, line 11] y <- ExpandMask(rhoprime, kappa). */+ mld_yvec_init(y, rhoprime, kappa);++ /* @[FIPS204, Algorithm 7, line 12] w <- invNTT(A_hat o NTT(y)). This call+ * performs the whole line: it NTTs y, accumulates the pointwise product with+ * A_hat, and applies the inverse NTT. In REDUCE_RAM mode the y sampling is+ * fused into the same pass. */+ mld_polyvec_matrix_pointwise_montgomery_yvec(w0, mat, y, tmp);++ /* @[FIPS204, Algorithm 7, line 13] w1 <- HighBits(w), here together with the+ * low part: Decompose yields w = 2*GAMMA2*w1 + w0, keeping both w1 and w0+ * (w0 is reused below in the line-21/26 alternative, see further down). */+ mld_polyveck_caddq(w0);+ mld_polyveck_decompose(w1, w0);++ /* @[FIPS204, Algorithm 7, line 15] ctilde <- H(mu || w1Encode(w1), lambda/4).+ * w1Encode(w1) is packed into the w1 region of sig (mld_polyveck_pack_w1),+ * then absorbed by H together with mu. */+ mld_polyveck_pack_w1(sig, w1);++ mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig,+ MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0);+ /* Constant time: Leaking challenge_bytes does not reveal any information+ * about the secret key as H() is modelled as random oracle.+ * This also applies to challenges for rejected signatures.+ * See Section 5.5 of @[Round3_Spec]. */+ MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES);+ /* @[FIPS204, Algorithm 7, line 16] c <- SampleInBall(ctilde) and+ * @[FIPS204, Algorithm 7, line 17] c_hat <- NTT(c). */+ mld_poly_challenge(cp, challenge_bytes);+ mld_poly_ntt(cp);++ /* @[FIPS204, Algorithm 7, lines 18+20] cs1 <- invNTT(c_hat o s1_hat) and+ * z <- y + cs1, followed by the line-23 norm check ||z||_inf >= GAMMA1 -+ * BETA. mld_compute_pack_z fuses all three per polynomial and, on success,+ * packs z into sig; it returns MLD_ERR_FAIL if the norm check rejects z. */+ ret = mld_compute_pack_z(sig, cp, s1hat, y, t, z);+ if (ret != 0)+ {+ goto cleanup;+ }++ /* The remaining steps realize @[FIPS204, Algorithm 7, lines 21-28] (the+ * low-bits norm check and the hint h) via the faster alternative formulation+ * of @[Round3_Spec, Section 5.1]. @[FIPS204] explicitly permits this: the+ * note accompanying Algorithm 7 states that the validity checks on z and the+ * computation of h may instead be implemented "as described in Section 5.1 of+ * [6]", and that reference is @[Round3_Spec, Section 5.1].+ *+ * The loop below builds w0 - cs2 + ct0 in place in w0; w1 is unmodified, and+ * is HighBits(w) from line 13. Those are the inputs to the streamlined+ * computation of MakeHint explained below.+ *+ * Low-bits norm check:+ * @[FIPS204, Algorithm 7, line 21] computes r0 = LowBits(w - cs2) and line+ * 23 rejects when ||r0||_inf >= GAMMA2 - BETA. By @[Round3_Spec, Section+ * 5.1] (Lemma 3), this line-23 check on r0 = LowBits(w - cs2) is implied by+ * ||w0 - cs2||_inf < GAMMA2 - BETA, where w0 is the low part of w. In our+ * context, w0 already holds the low part of w from the line-13 Decompose;+ * after subtracting cs2 from it in place, the mld_poly_chknorm(w0, GAMMA2 -+ * BETA) call below is exactly that check.+ *+ * Hint:+ * @[FIPS204, Algorithm 7, line 26] sets h = MakeHint(-ct0, w - cs2 + ct0),+ * and line 28 rejects when ||ct0||_inf >= GAMMA2 or h has more than OMEGA+ * nonzero coefficients. @[Round3_Spec, Section 5.1] provides the following+ * alternative description for MakeHint(-ct0, w - cs2 + ct0): a hint bit is+ * zero exactly when the coefficient of w0 - cs2 + ct0 lies in+ * (-GAMMA2, GAMMA2], or equals -GAMMA2 while the matching w1 coefficient is+ * zero (the Decompose border case), and is set otherwise. This equivalence+ * is precisely what mld_pack_sig_h -> mld_make_hint compute from w0+ * (= w0 - cs2 + ct0) and w1. The line-28 ||ct0||_inf >= GAMMA2 check is the+ * mld_poly_chknorm(z, GAMMA2) call on ct0 below; the weight bound is+ * enforced by mld_pack_sig_h.+ *+ * Building w0 per-component and checking norms incrementally also avoids+ * allocating a full polyveck for h. */+ for (k = 0; k < MLDSA_K; k++)+ __loop__(+ assigns(k,+ object_whole(z),+ object_whole(w0))+ invariant(k <= MLDSA_K)+ invariant(forall(k0, k, MLDSA_K,+ array_abs_bound(w0->vec[k0].coeffs, 0, MLDSA_N, MLDSA_GAMMA2 + 1)))+ decreases(MLDSA_K - k)+ )+ {+ /* @[FIPS204, Algorithm 7, line 19] cs2[k] <- invNTT(c_hat o s2_hat)[k],+ * then subtract from w0[k] to form (w0 - cs2)[k]. */+ mld_sk_s2hat_get_poly(z, s2hat, k);+ mld_poly_pointwise_montgomery(z, cp);+ mld_poly_invntt_tomont(z);++ mld_poly_sub(&w0->vec[k], z);+ mld_poly_reduce(&w0->vec[k]);++ /* Low-bits norm check (see block comment above): the line-23 check on+ * r0 = LowBits(w - cs2) holds via ||w0 - cs2||_inf < GAMMA2 - BETA. */+ w0_invalid = mld_poly_chknorm(&w0->vec[k], MLDSA_GAMMA2 - MLDSA_BETA);+ /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */+ MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t));+ if (w0_invalid)+ {+ ret = MLD_ERR_FAIL; /* reject */+ goto cleanup;+ }++ /* @[FIPS204, Algorithm 7, line 25] ct0[k] <- invNTT(c_hat o t0_hat)[k]. */+ mld_sk_t0hat_get_poly(z, t0hat, k);+ mld_poly_pointwise_montgomery(z, cp);+ mld_poly_invntt_tomont(z);+ mld_poly_reduce(z);++ /* @[FIPS204, Algorithm 7, line 28] reject when ||ct0||_inf >= GAMMA2 (the+ * second part, the OMEGA weight bound, is enforced by mld_pack_sig_h). */+ h_invalid = mld_poly_chknorm(z, MLDSA_GAMMA2);+ /* Constant time: h_invalid may be leaked - see comment for z_invalid. */+ MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t));+ if (h_invalid)+ {+ ret = MLD_ERR_FAIL; /* reject */+ goto cleanup;+ }++ /* Add ct0[k] to (w0 - cs2)[k], leaving (w0 - cs2 + ct0)[k] in w0[k] -- the+ * MakeHint input prepared for mld_pack_sig_h (see block comment above). */+ mld_poly_add(&w0->vec[k], z);+ }++ /* Constant time: At this point all norm checks have passed and we, hence,+ * know that the signature does not leak any secret information.+ * Consequently, any value that can be computed from the signature and public+ * key is considered public.+ * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0.+ * h=c*t0 is public as both c and t0 are considered public.+ * While t0 is not part of the public key, it can be reconstructed from+ * a small number of signatures and need not be regarded as secret+ * (see @[FIPS204, Section 6.1]).+ */+ MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0));+ MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1));++ /* @[FIPS204, Algorithm 7, line 33] sigEncode(ctilde, z mod+/- q, h) is split+ * across three calls: z was already packed by mld_compute_pack_z, this call+ * packs ctilde, and mld_pack_sig_h below packs the hint h. */+ mld_pack_sig_c(sig, challenge_bytes);++ /* @[FIPS204, Algorithm 7, line 26] h <- MakeHint(-ct0, w - cs2 + ct0),+ * computed from (w0 = w0 - cs2 + ct0, w1) as described in the block comment+ * above, and packed as the h component of the line-33 sigEncode. Returns+ * MLD_ERR_FAIL if h would exceed OMEGA nonzero coefficients (the remaining+ * part of the line-28 check), in which case we reject. */+ ret = mld_pack_sig_h(sig, w0, w1);+ if (ret != 0)+ {+ goto cleanup;+ }++ /* Constant time: At this point it is clear that the signature is valid - it+ * can, hence, be considered public. */+ MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES);+ ret = 0; /* success */++cleanup:+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(t, mld_poly, 1, context);+ MLD_FREE(cp, mld_poly, 1, context);+ MLD_FREE(w0, mld_polyveck, 1, context);+ MLD_FREE(w1tmp, w1tmp_u, 1, context);+ MLD_FREE(z, mld_poly, 1, context);+ MLD_FREE(y, mld_yvec, 1, context);+ MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context);++ return ret;+}+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t *m, size_t mlen,+ const uint8_t *pre, size_t prelen,+ const uint8_t rnd[MLDSA_RNDBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ int externalmu,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret;+ uint8_t *rho, *tr, *key, *mu, *rhoprime;+ uint16_t attempt;+ const uint16_t max_signing_attempts = mld_get_max_signing_attempts();+ MLD_ALLOC(seedbuf, uint8_t,+ 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context);+ MLD_ALLOC(mat, mld_polymat, 1, context);+ MLD_ALLOC(s1hat, mld_sk_s1hat, 1, context);+ MLD_ALLOC(t0hat, mld_sk_t0hat, 1, context);+ MLD_ALLOC(s2hat, mld_sk_s2hat, 1, context);++ if (seedbuf == NULL || mat == NULL || s1hat == NULL || t0hat == NULL ||+ s2hat == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* If a resume hook is configured via MLD_CONFIG_SIGN_HOOK_RESUME, it provides+ * the attempt to resume from after an earlier pause. Otherwise, we start at+ * 0. Clamp to max_signing_attempts. */+ attempt = mld_sign_resume(context);+ if (attempt > max_signing_attempts)+ {+ attempt = max_signing_attempts;+ }++ rho = seedbuf;+ tr = rho + MLDSA_SEEDBYTES;+ key = tr + MLDSA_TRBYTES;+ mu = key + MLDSA_SEEDBYTES;+ rhoprime = mu + MLDSA_CRHBYTES;+ /* @[FIPS204, Algorithm 7, line 1] (rho, K, tr, s1, s2, t0) <- skDecode(sk)+ * and @[FIPS204, Algorithm 7, lines 2-4] s1_hat/s2_hat/t0_hat <- NTT(...):+ * mld_unpack_sk returns s1hat, s2hat, t0hat already in NTT domain. The spec's+ * private random seed K is held in the local variable key. */+ mld_unpack_sk(rho, tr, key, t0hat, s1hat, s2hat, sk);++ if (!externalmu)+ {+ /* @[FIPS204, Algorithm 7, line 6] mu <- H(BytesToBits(tr) || M', 64). */+ mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen);+ }+ else+ {+ /* mu has been provided directly (external-mu variant; line 6 done by the+ * caller in a separate cryptographic module). */+ mld_memcpy(mu, m, MLDSA_CRHBYTES);+ }++ /* @[FIPS204, Algorithm 7, line 7] rhoprime <- H(K || rnd || mu, 64). */+ mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu,+ MLDSA_CRHBYTES);++ /* Constant time: rho is part of the public key and, hence, public. */+ MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES);+ /* @[FIPS204, Algorithm 7, line 5] A_hat <- ExpandA(rho). */+ mld_polyvec_matrix_expand(mat, rho);++ /* @[FIPS204, Algorithm 7, lines 8-10 and 31-32] the rejection-sampling loop,+ * tracked by attempt (kappa = attempt*MLDSA_L). Each iteration's body (lines+ * 11-30) plus, on success, the line-33 sigEncode are performed by+ * mld_attempt_signature_generation. */++ /* Reference: the reference loops unboundedly; we instead iterate over the+ * bounded range [0, max_signing_attempts) for predictable termination.+ * A success or fatal error exits via goto cleanup; running to completion+ * means every attempt was rejected; with a FIPS compliant choice of+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS, this should never happen. */+ for (; attempt < max_signing_attempts; attempt++)+ __loop__(+ MLD_IF_NOT_REDUCE_RAM(+ assigns(attempt, ret, memory_slice(sig, MLDSA_CRYPTO_BYTES))+ )+ MLD_IF_REDUCE_RAM(+ assigns(attempt, ret, memory_slice(sig, MLDSA_CRYPTO_BYTES),+ memory_slice(mat, sizeof(mld_polymat)))+ )+ invariant(attempt <= max_signing_attempts)++ /* t0, s1, s2, and mat are initialized above and are NOT changed by this */+ /* loop. We can therefore re-assert their bounds here as part of the */+ /* loop invariant. This makes proof noticeably faster with CBMC */+ MLD_IF_NOT_REDUCE_RAM(+ invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,+ array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))+ invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0hat->vec.vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1hat->vec.vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2hat->vec.vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))+ )+ decreases(max_signing_attempts - attempt)+ )+ {+ /* Safety: attempt < max_signing_attempts <= MLD_MAX_KAPPA / MLDSA_L, so+ * kappa <= MLD_MAX_KAPPA and the cast is safe. */+ const uint16_t kappa = (uint16_t)(attempt * MLDSA_L);++ /* Query configurable signing hook whether signing should be paused.+ * This is skipped by default and only used if the user sets the+ * configuration option MLD_CONFIG_SIGN_HOOK_ATTEMPT. */+ if (mld_sign_attempt(attempt, context) != 0)+ {+ ret = MLD_ERR_SIGNING_PAUSED;+ goto cleanup;+ }++ ret = mld_attempt_signature_generation(sig, mu, rhoprime, kappa, mat, s1hat,+ s2hat, t0hat, context);++ /* Decide whether to keep trying based on the return value:+ * - ret == 0: a valid signature was produced; we are done.+ * - ret == MLD_ERR_FAIL: this candidate was rejected by one of the norm+ * or hint checks. We continue the loop and try again with the next+ * nonce.+ * - any other value (e.g. MLD_ERR_OUT_OF_MEMORY): an unrecoverable error+ * occurred, so we propagate it to the caller. */+ if (ret == 0)+ {+ /* Signing succeeded: record the attempt that succeeded. No-op in the+ * default build. */+ mld_sign_finish(attempt, context);+ goto cleanup;+ }+ if (ret != MLD_ERR_FAIL)+ {+ goto cleanup;+ }+ }++ /* Loop ran to completion: all attempts rejected, budget exhausted.+ * This should never happen with a FIPS compliant choice of+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS. */+ ret = MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED;++cleanup:++ if (ret != 0)+ {+ /* To be on the safe-side, we zeroize the signature buffer. */+ mld_zeroize(sig, MLDSA_CRYPTO_BYTES);+ }++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(s2hat, mld_sk_s2hat, 1, context);+ MLD_FREE(t0hat, mld_sk_t0hat, 1, context);+ MLD_FREE(s1hat, mld_sk_s1hat, 1, context);+ MLD_FREE(mat, mld_polymat, 1, context);+ MLD_FREE(seedbuf, uint8_t,+ 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context);+ return ret;+}++#if !defined(MLD_CONFIG_CORE_API_ONLY)+#if !defined(MLD_CONFIG_NO_RANDOMIZED_API)+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *m,+ size_t mlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ size_t pre_len;+ int ret;+ MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context);+ MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context);++ if (pre == NULL || rnd == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* Prepare domain separation prefix for pure ML-DSA */+ pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen,+ MLD_PREHASH_NONE);+ if (pre_len == 0)+ {+ ret = MLD_ERR_INVALID_ARG;+ goto cleanup;+ }++ /* Randomized variant of ML-DSA. If you need the deterministic variant,+ * call mld_sign_signature_internal directly with all-zero rnd. */+ if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0)+ {+ ret = MLD_ERR_RNG_FAIL;+ goto cleanup;+ }+ MLD_CT_TESTING_SECRET(rnd, MLDSA_RNDBYTES);++ ret = mld_sign_signature_internal(sig, m, mlen, pre, pre_len, rnd, sk, 0,+ context);++cleanup:+ if (ret != 0)+ {+ /* To be on the safe-side, make sure sig has a well-defined value, even in+ * the case of error.+ *+ * If we come from mld_sign_signature_internal, this is redundant, but the+ * error case should not be the norm, and the added cost of the zeroization+ * insignificant. */+ mld_zeroize(sig, MLDSA_CRYPTO_BYTES);+ }++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context);+ MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context);++ return ret;+}+#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */++#if !defined(MLD_CONFIG_NO_RANDOMIZED_API)+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t mu[MLDSA_CRHBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret;+ MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context);++ if (rnd == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* Randomized variant of ML-DSA. If you need the deterministic variant,+ * call mld_sign_signature_internal directly with all-zero rnd. */+ if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0)+ {+ ret = MLD_ERR_RNG_FAIL;+ goto cleanup;+ }+ MLD_CT_TESTING_SECRET(rnd, MLDSA_RNDBYTES);++ ret = mld_sign_signature_internal(sig, mu, MLDSA_CRHBYTES, NULL, 0, rnd, sk,+ 1, context);++cleanup:+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context);++ return ret;+}+#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify_internal(const uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t *m, size_t mlen, const uint8_t *pre,+ size_t prelen,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ int externalmu,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret, cmp;+ unsigned int i;++ MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context);+ MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context);+ MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context);+ MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context);+ MLD_ALLOC(z, mld_polyvecl, 1, context);+ MLD_ALLOC(cp, mld_poly, 1, context);+ MLD_ALLOC(mat, mld_polymat, 1, context);+ MLD_ALLOC(w1, mld_poly, 1, context);+ MLD_ALLOC(tmp, mld_poly, 1, context);++ if (buf == NULL || mu == NULL || c == NULL || c2 == NULL || z == NULL ||+ cp == NULL || mat == NULL || w1 == NULL || tmp == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ mld_memcpy(c, sig, MLDSA_CTILDEBYTES);+ mld_polyvecl_unpack_z(z, sig + MLDSA_SIG_Z_OFFSET);++ /* mld_polyvecl_chknorm signals failure through a single non-zero error code+ * that's not yet aligned with MLD_ERR_XXX. A norm-check failure here means+ * the signature is invalid, so map it to MLD_ERR_INVALID_SIGNATURE. */+ if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA))+ {+ ret = MLD_ERR_INVALID_SIGNATURE;+ goto cleanup;+ }++ if (!externalmu)+ {+ /* Compute CRH(H(rho, t1), pre, msg) */+ MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES];+ mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL,+ 0);+ mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(hpk, sizeof(hpk));+ }+ else+ {+ /* mu has been provided directly */+ mld_memcpy(mu, m, MLDSA_CRHBYTES);+ }++ /* Matrix-vector multiplication and per-row reconstruction of w1. */+ mld_polyvecl_ntt(z);+ mld_polyvec_matrix_expand(mat, pk);+ mld_poly_challenge(cp, c);+ mld_poly_ntt(cp);++ for (i = 0; i < MLDSA_K; ++i)+ __loop__(+ assigns(MLD_IF_REDUCE_RAM(memory_slice(mat, sizeof(mld_polymat)),)+ i, ret,+ memory_slice(w1, sizeof(mld_poly)),+ memory_slice(tmp, sizeof(mld_poly)),+ memory_slice(buf, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)+ )+ invariant(i <= MLDSA_K)+ decreases(MLDSA_K - i)+ )+ {+ /* w1 = (A * z)_i in NTT domain */+ mld_polyvec_matrix_pointwise_montgomery_row(w1, mat, z, i);++ /* tmp = c * t1_i * 2^d in NTT domain */+ mld_unpack_pk_t1(tmp, pk, i);+ mld_poly_shiftl(tmp);+ mld_poly_ntt(tmp);+ mld_poly_pointwise_montgomery(tmp, cp);++ /* w1 = invNTT(w1 - c * t1_i * 2^d) */+ mld_poly_sub(w1, tmp);+ mld_poly_reduce(w1);+ mld_poly_invntt_tomont(w1);+ mld_poly_caddq(w1);++ /* tmp = h_i (decoded and validated from signature). A non-zero return+ * means the hint encoding is malformed, i.e. the signature is invalid. */+ if (mld_sig_unpack_hints(tmp, sig, i) != 0)+ {+ ret = MLD_ERR_INVALID_SIGNATURE;+ goto cleanup;+ }++ /* w1 = use_hint(w1, tmp), then pack into buf[i] */+ mld_poly_use_hint(w1, tmp);+ mld_polyw1_pack(buf + i * MLDSA_POLYW1_PACKEDBYTES, w1);+ }++ /* Call random oracle and verify challenge */+ mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf,+ MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0);++ cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES);++ /* Declassify the result of the verification. */+ MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp));++ ret = cmp == 0 ? 0 : MLD_ERR_INVALID_SIGNATURE;++cleanup:+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(tmp, mld_poly, 1, context);+ MLD_FREE(w1, mld_poly, 1, context);+ MLD_FREE(mat, mld_polymat, 1, context);+ MLD_FREE(cp, mld_poly, 1, context);+ MLD_FREE(z, mld_polyvecl, 1, context);+ MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context);+ MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context);+ MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context);+ MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context);+ return ret;+}++#if !defined(MLD_CONFIG_CORE_API_ONLY)+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify(const uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *m,+ size_t mlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES];+ size_t pre_len;+ int ret;++ pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen,+ MLD_PREHASH_NONE);+ if (pre_len == 0)+ {+ ret = MLD_ERR_INVALID_ARG;+ goto cleanup;+ }++ ret = mld_sign_verify_internal(sig, m, mlen, pre, pre_len, pk, 0, context);++cleanup:+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(pre, sizeof(pre));++ return ret;+}++MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify_extmu(const uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t mu[MLDSA_CRHBYTES],+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ return mld_sign_verify_internal(sig, mu, MLDSA_CRHBYTES, NULL, 0, pk, 1,+ context);+}+#endif /* !MLD_CONFIG_CORE_API_ONLY */+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_CORE_API_ONLY)+#if !defined(MLD_CONFIG_NO_SIGN_API)+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature_pre_hash_internal(+ uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *ph, size_t phlen,+ const uint8_t *ctx, size_t ctxlen, const uint8_t rnd[MLDSA_RNDBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES];+ size_t pre_len;+ int ret;++ if (hashalg == MLD_PREHASH_NONE)+ {+ ret = MLD_ERR_INVALID_ARG;+ goto cleanup;+ }++ pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen,+ hashalg);+ if (pre_len == 0)+ {+ ret = MLD_ERR_INVALID_ARG;+ goto cleanup;+ }++ ret = mld_sign_signature_internal(sig, pre, pre_len, NULL, 0, rnd, sk, 0,+ context);+cleanup:+ if (ret != 0)+ {+ /* To be on the safe-side, make sure sig has a well-defined value, even in+ * the case of error.+ *+ * If we come from mld_sign_signature_internal, this is redundant, but the+ * error case should not be the norm, and the added cost of the zeroization+ * insignificant. */+ mld_zeroize(sig, MLDSA_CRYPTO_BYTES);+ }++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(pre, sizeof(pre));+ return ret;+}+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify_pre_hash_internal(+ const uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *ph, size_t phlen,+ const uint8_t *ctx, size_t ctxlen,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES];+ size_t pre_len;+ int ret;++ if (hashalg == MLD_PREHASH_NONE)+ {+ ret = MLD_ERR_INVALID_ARG;+ goto cleanup;+ }++ pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen,+ hashalg);+ if (pre_len == 0)+ {+ ret = MLD_ERR_INVALID_ARG;+ goto cleanup;+ }++ ret = mld_sign_verify_internal(sig, pre, pre_len, NULL, 0, pk, 0, context);++cleanup:+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(pre, sizeof(pre));+ return ret;+}+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature_pre_hash_shake256(+ uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *m, size_t mlen,+ const uint8_t *ctx, size_t ctxlen, const uint8_t rnd[MLDSA_RNDBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ MLD_ALIGN uint8_t ph[64];+ int ret;+ mld_shake256(ph, sizeof(ph), m, mlen);+ ret = mld_sign_signature_pre_hash_internal(sig, ph, sizeof(ph), ctx, ctxlen,+ rnd, sk, MLD_PREHASH_SHAKE_256,+ context);+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(ph, sizeof(ph));+ return ret;+}+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify_pre_hash_shake256(+ const uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *m, size_t mlen,+ const uint8_t *ctx, size_t ctxlen,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ MLD_ALIGN uint8_t ph[64];+ int ret;+ mld_shake256(ph, sizeof(ph), m, mlen);+ ret = mld_sign_verify_pre_hash_internal(sig, ph, sizeof(ph), ctx, ctxlen, pk,+ MLD_PREHASH_SHAKE_256, context);+ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ mld_zeroize(ph, sizeof(ph));+ return ret;+}+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+#define MLD_PRE_HASH_OID_LEN 11++/**+ * Return the OID of a given SHA-2/SHA-3 hash function.+ *+ * @param[out] oid Pointer to output OID.+ * @param hashalg Hash algorithm constant (MLD_PREHASH_*).+ */+static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg)+{+ unsigned int i;+ static const struct+ {+ int alg;+ uint8_t oid[MLD_PRE_HASH_OID_LEN];+ } oid_map[] = {+ {MLD_PREHASH_SHA2_224,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}},+ {MLD_PREHASH_SHA2_256,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}},+ {MLD_PREHASH_SHA2_384,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}},+ {MLD_PREHASH_SHA2_512,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}},+ {MLD_PREHASH_SHA2_512_224,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}},+ {MLD_PREHASH_SHA2_512_256,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}},+ {MLD_PREHASH_SHA3_224,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}},+ {MLD_PREHASH_SHA3_256,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}},+ {MLD_PREHASH_SHA3_384,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}},+ {MLD_PREHASH_SHA3_512,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}},+ {MLD_PREHASH_SHAKE_128,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}},+ {MLD_PREHASH_SHAKE_256,+ {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}};++ for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++)+ __loop__(+ invariant(i <= sizeof(oid_map) / sizeof(oid_map[0]))+ decreases(sizeof(oid_map) / sizeof(oid_map[0]) - i)+ )+ {+ if (oid_map[i].alg == hashalg)+ {+ mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN);+ return;+ }+ }+}++static int mld_validate_hash_length(int hashalg, size_t len)+{+ switch (hashalg)+ {+ case MLD_PREHASH_SHA2_224:+ return (len == 224 / 8) ? 0 : -1;+ case MLD_PREHASH_SHA2_256:+ return (len == 256 / 8) ? 0 : -1;+ case MLD_PREHASH_SHA2_384:+ return (len == 384 / 8) ? 0 : -1;+ case MLD_PREHASH_SHA2_512:+ return (len == 512 / 8) ? 0 : -1;+ case MLD_PREHASH_SHA2_512_224:+ return (len == 224 / 8) ? 0 : -1;+ case MLD_PREHASH_SHA2_512_256:+ return (len == 256 / 8) ? 0 : -1;+ case MLD_PREHASH_SHA3_224:+ return (len == 224 / 8) ? 0 : -1;+ case MLD_PREHASH_SHA3_256:+ return (len == 256 / 8) ? 0 : -1;+ case MLD_PREHASH_SHA3_384:+ return (len == 384 / 8) ? 0 : -1;+ case MLD_PREHASH_SHA3_512:+ return (len == 512 / 8) ? 0 : -1;+ case MLD_PREHASH_SHAKE_128:+ return (len == 256 / 8) ? 0 : -1;+ case MLD_PREHASH_SHAKE_256:+ return (len == 512 / 8) ? 0 : -1;+ default:+ return -1;+ }+}++MLD_EXTERNAL_API+size_t mld_prepare_domain_separation_prefix(+ uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph,+ size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg)+{+ if (ctxlen > 255)+ {+ return 0;+ }++ if (hashalg != MLD_PREHASH_NONE)+ {+ if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0)+ {+ return 0;+ }+ }++ /* Common prefix: 0x00/0x01 || ctxlen || ctx */+ prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1;+ prefix[1] = (uint8_t)ctxlen;+ if (ctxlen > 0)+ {+ mld_memcpy(prefix + 2, ctx, ctxlen);+ }++ if (hashalg == MLD_PREHASH_NONE)+ {+ return 2 + ctxlen;+ }++ /* HashML-DSA: append oid || ph */+ mld_get_hash_oid(prefix + 2 + ctxlen, hashalg);+ mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen);+ return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen;+}+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+MLD_EXTERNAL_API+int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ uint8_t check, cmp0, cmp1, chk1, chk2;+ int ret;+ MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context);+ MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context);+ MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context);+ MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context);+ MLD_ALLOC(s1, mld_polyvecl, 1, context);+ MLD_ALLOC(s2, mld_polyveck, 1, context);+ MLD_ALLOC(t0_packed, uint8_t, MLDSA_K *MLDSA_POLYT0_PACKEDBYTES, context);++ if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL ||+ s1 == NULL || s2 == NULL || t0_packed == NULL)+ {+ ret = MLD_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* Inline unpack_sk: mld_unpack_sk uses lazy types for s1/s2/t0 which+ * we cannot use here. t0 stays in packed form -- we compare it against+ * the recomputed value below. */+ mld_memcpy(rho, sk + MLDSA_SK_RHO_OFFSET, MLDSA_SEEDBYTES);+ mld_memcpy(key, sk + MLDSA_SK_KEY_OFFSET, MLDSA_SEEDBYTES);+ mld_memcpy(tr, sk + MLDSA_SK_TR_OFFSET, MLDSA_TRBYTES);+ mld_polyvecl_unpack_eta(s1, sk + MLDSA_SK_S1_OFFSET);+ mld_polyveck_unpack_eta(s2, sk + MLDSA_SK_S2_OFFSET);++ /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */+ chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF;+ chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF;++ /* NTT s1 in place to use as s1hat */+ mld_polyvecl_ntt(s1);++ /* Pack rho into pk */+ mld_memcpy(pk + MLDSA_PK_RHO_OFFSET, rho, MLDSA_SEEDBYTES);++ /* Recompute t row by row, decompose, and pack t1 into pk and t0 into+ * t0_packed. */+ ret = mld_compute_pack_t0_t1(pk + MLDSA_PK_T1_OFFSET, t0_packed, s1, s2, rho,+ context);+ if (ret != 0)+ {+ goto cleanup;+ }++ /* Compare recomputed packed t0 against the t0 region of sk. */+ cmp0 = mld_ct_memcmp(t0_packed, sk + MLDSA_SK_T0_OFFSET,+ MLDSA_K * MLDSA_POLYT0_PACKEDBYTES);++ /* Compute tr_computed = H(pk) and compare to the stored tr */+ mld_shake256(tr_computed, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES);+ cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed,+ MLDSA_TRBYTES);+ check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2);++ /* Declassify the final result of the validity check. */+ MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check));+ ret = (check != 0) ? MLD_ERR_INVALID_KEY : 0;++cleanup:++ if (ret != 0)+ {+ mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES);+ }++ /* Constant time: pk is either the valid public key or zeroed on error */+ MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES);++ /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */+ MLD_FREE(t0_packed, uint8_t, MLDSA_K *MLDSA_POLYT0_PACKEDBYTES, context);+ MLD_FREE(s2, mld_polyveck, 1, context);+ MLD_FREE(s1, mld_polyvecl, 1, context);+ MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context);+ MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context);+ MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context);+ MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context);++ return ret;+}+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef mld_check_pct+#undef mld_sample_s1_s2+#undef mld_validate_hash_length+#undef mld_get_hash_oid+#undef mld_H+#undef mld_compute_pack_z+#undef mld_attempt_signature_generation+#undef mld_compute_pack_t0_t1+#undef mld_get_max_signing_attempts+#undef MLD_MAX_SIGNING_ATTEMPTS+#undef MLD_PRE_HASH_OID_LEN
@@ -0,0 +1,850 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS204]+ * FIPS 204 Module-Lattice-Based Digital Signature Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/204/final+ */++#ifndef MLD_SIGN_H+#define MLD_SIGN_H++#include <stddef.h>+#include "cbmc.h"+#include "common.h"+#include "poly.h"+#include "polyvec.h"+#include "sys.h"++#if defined(MLD_CHECK_APIS)+/* Include to ensure consistency between internal sign.h+ * and external mldsa_native.h. */+#include "mldsa_native.h"++#if MLDSA_CRYPTO_SECRETKEYBYTES != \+ MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)+#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h+#endif++#if MLDSA_CRYPTO_PUBLICKEYBYTES != \+ MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)+#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h+#endif++#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)+#error Mismatch for BYTES between sign.h and mldsa_native.h+#endif++#endif /* MLD_CHECK_APIS */++#define mld_sign_keypair_internal \+ MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3+#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2+#define mld_sign_signature_internal \+ MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_8+#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_6+#define mld_sign_signature_extmu \+ MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_3+#define mld_sign_verify_internal \+ MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_7+#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_6+#define mld_sign_verify_extmu \+ MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_3+#define mld_sign_signature_pre_hash_internal \+ MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8+#define mld_sign_verify_pre_hash_internal \+ MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_7+#define mld_sign_signature_pre_hash_shake256 \+ MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7+#define mld_sign_verify_pre_hash_shake256 \+ MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_6+#define mld_prepare_domain_separation_prefix \+ MLD_NAMESPACE_KL(prepare_domain_separation_prefix)+#define mld_sign_pk_from_sk \+ MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2++/* Hash algorithm constants for domain separation */+#define MLD_PREHASH_NONE 0+#define MLD_PREHASH_SHA2_224 1+#define MLD_PREHASH_SHA2_256 2+#define MLD_PREHASH_SHA2_384 3+#define MLD_PREHASH_SHA2_512 4+#define MLD_PREHASH_SHA2_512_224 5+#define MLD_PREHASH_SHA2_512_256 6+#define MLD_PREHASH_SHA3_224 7+#define MLD_PREHASH_SHA3_256 8+#define MLD_PREHASH_SHA3_384 9+#define MLD_PREHASH_SHA3_512 10+#define MLD_PREHASH_SHAKE_128 11+#define MLD_PREHASH_SHAKE_256 12++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+/**+ * Generate a public-private key pair from a seed.+ *+ * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise Consistency Test+ * (PCT) as required by FIPS 140-3 IG.+ *+ * @spec{Implements @[FIPS204, Algorithm 6, ML-DSA.KeyGen_internal].}+ *+ * @param[out] pk Output public key.+ * @param[out] sk Output private key.+ * @param[in] seed Input random seed.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_RNG_FAIL Random number generation failed+ * during the PCT. Only possible when+ * MLD_CONFIG_KEYGEN_PCT is enabled.+ * @retval MLD_ERR_SIGNING_PAUSED The PCT's signing step was paused by+ * a MLD_CONFIG_SIGN_HOOK_ATTEMPT hook.+ * This should currently never happen:+ * signing hooks require+ * MLD_CONFIG_NO_RANDOMIZED_API, which+ * is incompatible with+ * MLD_CONFIG_KEYGEN_PCT, so the two+ * cannot be enabled simultaneously.+ * @retval MLD_ERR_PCT_FAIL MLD_CONFIG_KEYGEN_PCT is enabled and+ * the PCT check failed.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ const uint8_t seed[MLDSA_SEEDBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ requires(memory_no_alias(seed, MLDSA_SEEDBYTES))+ assigns(object_whole(pk))+ assigns(object_whole(sk))+ ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY ||+ return_value == MLD_ERR_RNG_FAIL ||+ return_value == MLD_ERR_SIGNING_PAUSED ||+ return_value == MLD_ERR_PCT_FAIL)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+);++#if !defined(MLD_CONFIG_CORE_API_ONLY)+#if !defined(MLD_CONFIG_NO_RANDOMIZED_API)+/**+ * Generate a public-private key pair.+ *+ * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise Consistency Test+ * (PCT) as required by FIPS 140-3 IG.+ *+ * @spec{Implements @[FIPS204, Algorithm 1, ML-DSA.KeyGen].}+ *+ * @param[out] pk Output public key.+ * @param[out] sk Output private key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_RNG_FAIL Random number generation failed.+ * @retval MLD_ERR_SIGNING_PAUSED The PCT's signing step was paused by+ * a MLD_CONFIG_SIGN_HOOK_ATTEMPT hook.+ * This should currently never happen:+ * signing hooks require+ * MLD_CONFIG_NO_RANDOMIZED_API, which+ * is incompatible with+ * MLD_CONFIG_KEYGEN_PCT, so the two+ * cannot be enabled simultaneously.+ * @retval MLD_ERR_PCT_FAIL MLD_CONFIG_KEYGEN_PCT is enabled and+ * the PCT check failed.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ assigns(object_whole(pk))+ assigns(object_whole(sk))+ ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY ||+ return_value == MLD_ERR_RNG_FAIL ||+ return_value == MLD_ERR_SIGNING_PAUSED ||+ return_value == MLD_ERR_PCT_FAIL)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+);+#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+/**+ * Compute signature using a caller-supplied random seed and prefix.+ *+ * On error (non-zero return value), the signature buffer sig is zeroized.+ *+ * @spec{Implements @[FIPS204, Algorithm 7, ML-DSA.Sign_internal].}+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use mld_sign_pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Pointer to buffer to hold the generated signature of+ * MLDSA_CRYPTO_BYTES bytes.+ * @param[in] m Pointer to message to be signed (when+ * externalmu == 0), or to a precomputed+ * message representative mu (when externalmu != 0).+ * @param mlen Length of m. Must equal MLDSA_CRHBYTES when+ * externalmu != 0.+ * @param[in] pre Pointer to prefix string. Ignored when+ * externalmu != 0.+ * @param prelen Length of prefix string. Ignored when+ * externalmu != 0.+ * @param[in] rnd Random seed.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param externalmu 0: m/mlen is the raw message; mu = H(tr, pre, m) is+ * computed internally.+ * non-zero: m points to a precomputed mu of+ * MLDSA_CRHBYTES bytes; pre/prelen unused.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t *m, size_t mlen,+ const uint8_t *pre, size_t prelen,+ const uint8_t rnd[MLDSA_RNDBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ int externalmu,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(mlen <= MLD_MAX_BUFFER_SIZE)+ requires(prelen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(m, mlen))+ requires(memory_no_alias(rnd, MLDSA_RNDBYTES))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ requires((externalmu == 0) ==> ((prelen == 0) || memory_no_alias(pre, prelen)))+ requires((externalmu != 0) ==> (mlen == MLDSA_CRHBYTES))+ assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))+ ensures(return_value == 0 ||+ return_value == MLD_ERR_OUT_OF_MEMORY ||+ return_value == MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED ||+ return_value == MLD_ERR_SIGNING_PAUSED)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sig, MLDSA_CRYPTO_BYTES)));++#if !defined(MLD_CONFIG_CORE_API_ONLY)+#if !defined(MLD_CONFIG_NO_RANDOMIZED_API)+/**+ * Compute signature. This function implements the randomized variant of+ * ML-DSA. If you require the deterministic variant, use+ * mld_sign_signature_internal directly.+ *+ * @spec{Implements @[FIPS204, Algorithm 2, ML-DSA.Sign].}+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use mld_sign_pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Output signature.+ * @param[in] m Pointer to message to be signed.+ * @param mlen Length of message.+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string. Should be <= 255.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_RNG_FAIL Random number generation failed.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ * @retval MLD_ERR_INVALID_ARG The context string exceeded 255+ * bytes.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *m,+ size_t mlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(mlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(m, mlen))+ requires(ctxlen <= MLD_MAX_BUFFER_SIZE)+ requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY ||+ return_value == MLD_ERR_RNG_FAIL ||+ return_value == MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED ||+ return_value == MLD_ERR_SIGNING_PAUSED ||+ return_value == MLD_ERR_INVALID_ARG)+ ensures((return_value == MLD_ERR_INVALID_ARG) ==> (ctxlen > 255))+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sig, MLDSA_CRYPTO_BYTES))+);++/**+ * Compute signature in "external mu" mode: the caller has already computed+ * the message representative mu = SHAKE256(tr || M', 64), where+ * tr = SHAKE256(pk, 64) and M' is the FIPS 204 formatted message (e.g.+ * 0x00 || ctxlen || ctx || msg for pure ML-DSA). This is the randomized+ * variant; for the deterministic variant, use mld_sign_signature_internal+ * directly with externalmu set to non-zero and an all-zero rnd.+ *+ * @spec{Implements @[FIPS204, Algorithm 2, ML-DSA.Sign external mu variant].}+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use mld_sign_pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Output signature.+ * @param[in] mu Precomputed message representative.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_RNG_FAIL Random number generation failed.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t mu[MLDSA_CRHBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(mu, MLDSA_CRHBYTES))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY ||+ return_value == MLD_ERR_RNG_FAIL ||+ return_value == MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED ||+ return_value == MLD_ERR_SIGNING_PAUSED)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sig, MLDSA_CRYPTO_BYTES))+);++#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+/**+ * Verify signature.+ *+ * @spec{Implements @[FIPS204, Algorithm 8, ML-DSA.Verify_internal].}+ *+ * @param[in] sig Pointer to input signature of+ * MLDSA_CRYPTO_BYTES bytes.+ * @param[in] m Pointer to message (when externalmu == 0), or to a+ * precomputed message representative mu (when+ * externalmu != 0).+ * @param mlen Length of m. Must equal MLDSA_CRHBYTES when+ * externalmu != 0.+ * @param[in] pre Pointer to prefix string. Ignored when externalmu != 0.+ * @param prelen Length of prefix string. Ignored when externalmu != 0.+ * @param[in] pk Bit-packed public key.+ * @param externalmu 0: m/mlen is the raw message; mu = H(H(pk), pre, m) is+ * computed internally.+ * non-zero: m points to a precomputed mu of+ * MLDSA_CRHBYTES bytes; pre/prelen unused.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify_internal(const uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t *m, size_t mlen, const uint8_t *pre,+ size_t prelen,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ int externalmu,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(prelen <= MLD_MAX_BUFFER_SIZE)+ requires(mlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(m, mlen))+ requires((externalmu == 0) ==> ((prelen == 0) || memory_no_alias(pre, prelen)))+ requires((externalmu != 0) ==> (mlen == MLDSA_CRHBYTES))+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_INVALID_SIGNATURE || return_value == MLD_ERR_OUT_OF_MEMORY)+);++#if !defined(MLD_CONFIG_CORE_API_ONLY)+/**+ * Verify signature.+ *+ * @spec{Implements @[FIPS204, Algorithm 3, ML-DSA.Verify].}+ *+ * @param[in] sig Pointer to input signature.+ * @param[in] m Pointer to message.+ * @param mlen Length of message.+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] pk Bit-packed public key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ * @retval MLD_ERR_INVALID_ARG The context string exceeded 255 bytes.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify(const uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *m,+ size_t mlen, const uint8_t *ctx, size_t ctxlen,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(mlen <= MLD_MAX_BUFFER_SIZE)+ requires(ctxlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(m, mlen))+ requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_INVALID_SIGNATURE || return_value == MLD_ERR_INVALID_ARG || return_value == MLD_ERR_OUT_OF_MEMORY)+ ensures((return_value == MLD_ERR_INVALID_ARG) ==> (ctxlen > 255))+);++/**+ * Verify signature in "external mu" mode: the caller has already computed+ * the message representative mu = SHAKE256(tr || M', 64), where+ * tr = SHAKE256(pk, 64) and M' is the FIPS 204 formatted message (e.g.+ * 0x00 || ctxlen || ctx || msg for pure ML-DSA). The same mu must have been+ * used at signing time.+ *+ * @spec{Implements @[FIPS204, Algorithm 3, ML-DSA.Verify external mu variant].}+ *+ * @param[in] sig Pointer to input signature.+ * @param[in] mu Precomputed message representative.+ * @param[in] pk Bit-packed public key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify_extmu(const uint8_t sig[MLDSA_CRYPTO_BYTES],+ const uint8_t mu[MLDSA_CRHBYTES],+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__( requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(mu, MLDSA_CRHBYTES))+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_INVALID_SIGNATURE || return_value == MLD_ERR_OUT_OF_MEMORY)+);++#endif /* !MLD_CONFIG_CORE_API_ONLY */+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_CORE_API_ONLY)+#if !defined(MLD_CONFIG_NO_SIGN_API)+/**+ * Compute signature with pre-hashed message.+ *+ * @spec{Implements @[FIPS204, Algorithm 4, HashML-DSA.Sign].}+ *+ * Supported hash algorithm constants:+ * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384,+ * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256,+ * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384,+ * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256.+ *+ * MLD_PREHASH_NONE is rejected by this API.+ *+ * @warning This is an unstable API that may change in the future. If you need+ * a stable API use mld_sign_signature_pre_hash_shake256.+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use mld_sign_pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Output signature.+ * @param[in] ph Pointer to pre-hashed message.+ * @param phlen Length of pre-hashed message. Must match the output+ * length of hashalg (the digest size for SHA-2/SHA-3,+ * 32 bytes for MLD_PREHASH_SHAKE_128, 64 bytes for+ * MLD_PREHASH_SHAKE_256).+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] rnd Random seed.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param hashalg Hash algorithm constant (one of MLD_PREHASH_*).+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ * @retval MLD_ERR_INVALID_ARG The pre-hash algorithm was+ * MLD_PREHASH_NONE or unsupported,+ * phlen did not match the output+ * length of hashalg, or the context+ * string exceeded 255 bytes.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature_pre_hash_internal(+ uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *ph, size_t phlen,+ const uint8_t *ctx, size_t ctxlen, const uint8_t rnd[MLDSA_RNDBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(ctxlen <= MLD_MAX_BUFFER_SIZE)+ requires(phlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(ph, phlen))+ requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))+ requires(memory_no_alias(rnd, MLDSA_RNDBYTES))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED || return_value == MLD_ERR_SIGNING_PAUSED || return_value == MLD_ERR_INVALID_ARG)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sig, MLDSA_CRYPTO_BYTES))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+/**+ * Verify signature with pre-hashed message.+ *+ * @spec{Implements @[FIPS204, Algorithm 5, HashML-DSA.Verify].}+ *+ * Supported hash algorithm constants:+ * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384,+ * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256,+ * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384,+ * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256.+ *+ * MLD_PREHASH_NONE is rejected by this API.+ *+ * @warning This is an unstable API that may change in the future. If you need+ * a stable API use mld_sign_verify_pre_hash_shake256.+ *+ * @param[in] sig Pointer to input signature.+ * @param[in] ph Pointer to pre-hashed message.+ * @param phlen Length of pre-hashed message. Must match the output+ * length of hashalg (the digest size for SHA-2/SHA-3,+ * 32 bytes for MLD_PREHASH_SHAKE_128, 64 bytes for+ * MLD_PREHASH_SHAKE_256).+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] pk Bit-packed public key.+ * @param hashalg Hash algorithm constant (one of MLD_PREHASH_*).+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ * @retval MLD_ERR_INVALID_ARG The pre-hash algorithm was+ * MLD_PREHASH_NONE or unsupported, phlen+ * did not match the output length of+ * hashalg, or the context string exceeded+ * 255 bytes.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify_pre_hash_internal(+ const uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *ph, size_t phlen,+ const uint8_t *ctx, size_t ctxlen,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg,+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(phlen <= MLD_MAX_BUFFER_SIZE)+ requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77)+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(ph, phlen))+ requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_INVALID_SIGNATURE || return_value == MLD_ERR_INVALID_ARG || return_value == MLD_ERR_OUT_OF_MEMORY)+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API)+/**+ * Compute signature with pre-hashed message using SHAKE256. This function+ * computes the SHAKE256 hash of the message internally.+ *+ * @spec{Implements @[FIPS204, Algorithm 4, HashML-DSA.Sign] with SHAKE256 as+ * the pre-hash.}+ *+ * @warning This function does not perform secret key validation.+ * Callers importing serialized keys can use mld_sign_pk_from_sk+ * to validate them before signing.+ *+ * @param[out] sig Output signature.+ * @param[in] m Pointer to message to be hashed and signed.+ * @param mlen Length of message.+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] rnd Random seed.+ * @param[in] sk Bit-packed secret key; assumed to be valid.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED The rejection-sampling loop exceeded+ * MLD_CONFIG_MAX_SIGNING_ATTEMPTS+ * iterations.+ * @retval MLD_ERR_SIGNING_PAUSED A MLD_CONFIG_SIGN_HOOK_ATTEMPT hook+ * paused signing; re-invoke to resume.+ * @retval MLD_ERR_INVALID_ARG The context string exceeded 255+ * bytes.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_signature_pre_hash_shake256(+ uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *m, size_t mlen,+ const uint8_t *ctx, size_t ctxlen, const uint8_t rnd[MLDSA_RNDBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(mlen <= MLD_MAX_BUFFER_SIZE)+ requires(ctxlen <= MLD_MAX_BUFFER_SIZE)+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(m, mlen))+ requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))+ requires(memory_no_alias(rnd, MLDSA_RNDBYTES))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED || return_value == MLD_ERR_SIGNING_PAUSED || return_value == MLD_ERR_INVALID_ARG)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sig, MLDSA_CRYPTO_BYTES))+);+#endif /* !MLD_CONFIG_NO_SIGN_API */++#if !defined(MLD_CONFIG_NO_VERIFY_API)+/**+ * Verify signature with pre-hashed message using SHAKE256. This function+ * computes the SHAKE256 hash of the message internally.+ *+ * @spec{Implements @[FIPS204, Algorithm 5, HashML-DSA.Verify] with SHAKE256 as+ * the pre-hash.}+ *+ * @param[in] sig Pointer to input signature.+ * @param[in] m Pointer to message to be hashed and verified.+ * @param mlen Length of message.+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param[in] pk Bit-packed public key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was+ * used and an allocation via+ * MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_SIGNATURE Signature verification failed.+ * @retval MLD_ERR_INVALID_ARG The context string exceeded 255 bytes.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_verify_pre_hash_shake256(+ const uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *m, size_t mlen,+ const uint8_t *ctx, size_t ctxlen,+ const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(mlen <= MLD_MAX_BUFFER_SIZE)+ requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77)+ requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))+ requires(memory_no_alias(m, mlen))+ requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_INVALID_SIGNATURE || return_value == MLD_ERR_INVALID_ARG || return_value == MLD_ERR_OUT_OF_MEMORY)+);+#endif /* !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)+/* Maximum formatted domain separation message length:+ * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255)+ * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */+#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64)++/**+ * Prepare domain separation prefix for ML-DSA signing.+ *+ * For pure ML-DSA (hashalg == MLD_PREHASH_NONE):+ * Format: 0x00 || ctxlen (1 byte) || ctx.+ *+ * For HashML-DSA (hashalg != MLD_PREHASH_NONE):+ * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph.+ *+ * This function is useful for building incremental signing APIs.+ *+ * @spec{For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements+ * @[FIPS204, Algorithm 4, line 23]. For Pure ML-DSA+ * (hashalg == MLD_PREHASH_NONE), implements+ * ```+ * M' <- BytesToBits(IntegerToBytes(0, 1)+ * || IntegerToBytes(|ctx|, 1)+ * || ctx+ * ```+ * which is part of @[FIPS204, Algorithm 2, ML-DSA.Sign, line 10] and+ * @[FIPS204, Algorithm 3, ML-DSA.Verify, line 5].}+ *+ * @param[out] prefix Output domain separation prefix buffer.+ * @param[in] ph Pointer to pre-hashed message (ignored for pure+ * ML-DSA).+ * @param phlen Length of pre-hashed message; must match the output+ * length of hashalg (ignored for pure ML-DSA).+ * @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.+ * @param ctxlen Length of context string.+ * @param hashalg Hash algorithm constant (MLD_PREHASH_NONE for pure+ * ML-DSA, or MLD_PREHASH_* for HashML-DSA).+ *+ * @return The total length of the formatted prefix, or 0 on error.+ * Errors are:+ * - The context string exceeded 255 bytes.+ * - For HashML-DSA: hashalg was unsupported, ph was NULL, or phlen+ * did not match the output length of hashalg.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+size_t mld_prepare_domain_separation_prefix(+ uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph,+ size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg)+__contract__(+ requires(ctxlen <= 255)+ requires(phlen <= MLD_MAX_BUFFER_SIZE)+ requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))+ requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen))+ requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES))+ assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES))+ ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES)+);+#endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */++#if !defined(MLD_CONFIG_NO_KEYPAIR_API)+/**+ * Perform basic validity checks on secret key, and derive public key.+ *+ * Referring to the decoding of the secret key `sk=(rho, K, tr, s1, s2, t0)`+ * (cf. @[FIPS204, Algorithm 25, skDecode]), the following checks are+ * performed:+ * - Check that s1 and s2 have coefficients in [-MLDSA_ETA, MLDSA_ETA].+ * - Check that t0 and tr stored in sk match recomputed values.+ *+ * @note This function leaks whether the secret key is valid or invalid+ * through its return value and timing.+ *+ * @param[out] pk Output public key.+ * @param[in] sk Input secret key.+ * @param context Application context. Only present when+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLD_ERR_OUT_OF_MEMORY MLD_CONFIG_CUSTOM_ALLOC_FREE was used and an+ * allocation via MLD_CUSTOM_ALLOC returned NULL.+ * @retval MLD_ERR_INVALID_KEY Secret key validation failed.+ */+MLD_MUST_CHECK_RETURN_VALUE+MLD_EXTERNAL_API+int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],+ const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],+ MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))+ assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+ ensures(return_value == 0 || return_value == MLD_ERR_INVALID_KEY || return_value == MLD_ERR_OUT_OF_MEMORY)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))+);+#endif /* !MLD_CONFIG_NO_KEYPAIR_API */+#endif /* !MLD_CONFIG_CORE_API_ONLY */++#endif /* !MLD_SIGN_H */
@@ -0,0 +1,68 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLD_SYMMETRIC_H+#define MLD_SYMMETRIC_H++#include "cbmc.h"+#include "common.h"++#include MLD_FIPS202_HEADER_FILE+#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)+#include MLD_FIPS202X4_HEADER_FILE+#endif++#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE+#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE++#define mld_xof256_ctx mld_shake256ctx+#define mld_xof256_init(CTX) mld_shake256_init(CTX)++#define mld_xof256_absorb_once(CTX, IN, INBYTES) \+ do \+ { \+ mld_shake256_absorb(CTX, IN, INBYTES); \+ mld_shake256_finalize(CTX); \+ } while (0)+++#define mld_xof256_release(CTX) mld_shake256_release(CTX)+#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \+ mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE)++#define mld_xof128_ctx mld_shake128ctx+#define mld_xof128_init(CTX) mld_shake128_init(CTX)++#define mld_xof128_absorb_once(CTX, IN, INBYTES) \+ do \+ { \+ mld_shake128_absorb(CTX, IN, INBYTES); \+ mld_shake128_finalize(CTX); \+ } while (0)++#define mld_xof128_release(CTX) mld_shake128_release(CTX)+#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \+ mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE)++#define mld_xof256_x4_ctx mld_shake256x4ctx+#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX))+#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \+ mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \+ (INBYTES))+#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \+ mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \+ (NBLOCKS), (CTX))+#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX))++#define mld_xof128_x4_ctx mld_shake128x4ctx+#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX))+#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \+ mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \+ (INBYTES))+#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \+ mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \+ (NBLOCKS), (CTX))+#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX))++#endif /* !MLD_SYMMETRIC_H */
@@ -0,0 +1,327 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLD_SYS_H+#define MLD_SYS_H++#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__))+#define MLD_HAVE_INLINE_ASM+#endif++/* Try to find endianness, if not forced through CFLAGS already */+#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN)+#if defined(__BYTE_ORDER__)+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__+#define MLD_SYS_LITTLE_ENDIAN+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__+#define MLD_SYS_BIG_ENDIAN+#else+#error "__BYTE_ORDER__ defined, but don't recognize value."+#endif+#endif /* __BYTE_ORDER__ */++/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports+ * little endian x86, x86_64, and AArch64. It is, hence, safe to assume+ * little endian. */+#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \+ defined(_M_IX86) || defined(_M_ARM64))+#define MLD_SYS_LITTLE_ENDIAN+#endif++#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */++/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by+ * MSVC. */+#if defined(__AARCH64EL__) || defined(_M_ARM64)+#define MLD_SYS_AARCH64+#endif++/* Check if the AArch64 compilation target supports NEON (Advanced SIMD).+ *+ * Some compilers also define __ARM_NEON__, but __ARM_NEON is the most reliable+ * signal. Specifically, clang on Apple appears to keep __ARM_NEON__ set even if+ * -march=armv8-a+nosimd is set.+ *+ * gcc 4.8 -- the first gcc version introducing Neon support -- sets neither+ * __ARM_NEON nor __ARM_NEON__; in fact, there is no preprocessor signal that+ * Neon is enabled. If you use gcc 4.8 and need Neon, you should set+ * MLD_SYS_AARCH64_NEON manually. gcc 4.9 onwards do set __ARM_NEON.+ */+#if defined(MLD_SYS_AARCH64) && defined(__ARM_NEON)+#define MLD_SYS_AARCH64_NEON+#endif++/* Check if we're running on an AArch64 big endian system. */+#if defined(__AARCH64EB__)+#define MLD_SYS_AARCH64_EB+#endif++/* Check if we're running on an Armv8.1-M system with MVE */+#if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_FEATURE_MVE)+#define MLD_SYS_ARMV81M_MVE+#endif++/* Check if we're running on an x86_64 system. */+#if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64)+#define MLD_SYS_X86_64+#if defined(__AVX2__)+#define MLD_SYS_X86_64_AVX2+#endif+#endif /* __x86_64__ || _M_X64 || _M_AMD64 */++#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__)+#define MLD_SYS_PPC64LE+#endif++#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64+#define MLD_SYS_RISCV64+#endif++#if defined(MLD_SYS_RISCV64) && defined(__riscv_vector) && \+ defined(__riscv_v_intrinsic)+#define MLD_SYS_RISCV64_RVV+#endif++#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32+#define MLD_SYS_RISCV32+#endif++#if defined(_WIN64) || defined(_WIN32)+#define MLD_SYS_WINDOWS+#endif++#if defined(__linux__)+#define MLD_SYS_LINUX+#endif++#if defined(__APPLE__)+#define MLD_SYS_APPLE+#endif++/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system.+ */+#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64)+#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system."+#endif++/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian+ * AArch64 system. */+#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB)+#error \+ "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system."+#endif++/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */+#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64)+#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system."+#endif++#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE)+#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system."+#endif++#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64)+#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system."+#endif++#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32)+#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system."+#endif++/*+ * MLD_INLINE: Hint for inlining.+ * - MSVC: __inline+ * - C99+: inline+ * - GCC/Clang C90: __attribute__((unused)) to silence warnings+ * - Other C90: empty+ */+#if !defined(MLD_INLINE)+#if defined(_MSC_VER)+#define MLD_INLINE __inline+#elif defined(inline) || \+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)+#define MLD_INLINE inline+#elif defined(__GNUC__) || defined(__clang__)+#define MLD_INLINE __attribute__((unused))+#else+#define MLD_INLINE+#endif+#endif /* !MLD_INLINE */++/*+ * MLD_ALWAYS_INLINE: Force inlining.+ * - MSVC: __forceinline+ * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline))+ * - Other: MLD_INLINE (no forced inlining)+ */+#if !defined(MLD_ALWAYS_INLINE)+#if defined(_MSC_VER)+#define MLD_ALWAYS_INLINE __forceinline+#elif (defined(__GNUC__) || defined(__clang__)) && \+ (defined(inline) || \+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L))+#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline))+#else+#define MLD_ALWAYS_INLINE MLD_INLINE+#endif+#endif /* !MLD_ALWAYS_INLINE */++/*+ * MLD_NOINLINE: Prevent inlining.+ * - MSVC: __declspec(noinline)+ * - GCC/Clang: __attribute__((noinline))+ * - Other: empty+ */+#if !defined(MLD_NOINLINE)+#if defined(_MSC_VER)+#define MLD_NOINLINE __declspec(noinline)+#elif defined(__GNUC__) || defined(__clang__)+#define MLD_NOINLINE __attribute__((noinline))+#else+#define MLD_NOINLINE+#endif+#endif /* !MLD_NOINLINE */++#ifndef MLD_STATIC_TESTABLE+#define MLD_STATIC_TESTABLE static+#endif++/*+ * C90 does not have the restrict compiler directive yet.+ * We don't use it in C90 builds.+ */+#if !defined(restrict)+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L+#define MLD_RESTRICT restrict+#else+#define MLD_RESTRICT+#endif++#else /* !restrict */++#define MLD_RESTRICT restrict+#endif /* restrict */++#define MLD_DEFAULT_ALIGN 32+#define MLD_ALIGN_UP(N) \+ ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN)+#if defined(__GNUC__)+#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN)))+#elif defined(_MSC_VER)+#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN))+#else+#define MLD_ALIGN /* No known support for alignment constraints */+#endif+++/* New X86_64 CPUs support control-flow protection using the CET instructions.+ * When enabled (through -fcf-protection=), all compilation units (including+ * empty ones) need to support CET for this to work.+ * For assembly, this means that source files need to signal support for+ * CET by setting the appropriate note.gnu.property section.+ * This can be achieved by including the <cet.h> header in all assembly file.+ * This file also provides the _CET_ENDBR macro which needs to be placed at+ * every potential target of an indirect branch.+ * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise+ * it is empty.+ * In case the compiler does not support CET (e.g., <gcc8, <clang11),+ * the __CET__ macro is not set and we default to nothing.+ * Note that we only issue _CET_ENDBR instructions through the MLD_ASM_FN_SYMBOL+ * macro as the global symbols are the only possible targets of indirect+ * branches in our code.+ */+#if defined(MLD_SYS_X86_64)+#if defined(__CET__)+#include <cet.h>+#define MLD_CET_ENDBR _CET_ENDBR+#else+#define MLD_CET_ENDBR+#endif+#endif /* MLD_SYS_X86_64 */++#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__)+#include <valgrind/memcheck.h>+#define MLD_CT_TESTING_SECRET(ptr, len) \+ VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len))+#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \+ VALGRIND_MAKE_MEM_DEFINED((ptr), (len))+#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */+#define MLD_CT_TESTING_SECRET(ptr, len) \+ do \+ { \+ } while (0)+#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \+ do \+ { \+ } while (0)+#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */++#if defined(__GNUC__) || defined(__clang__)+#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result))+#else+#define MLD_MUST_CHECK_RETURN_VALUE+#endif++/* The x86_64 assembly backend uses the SysV calling convention. On Windows,+ * where the Microsoft x64 calling convention is the default, it can still be+ * used with compilers that allow choosing the calling convention per+ * function: GCC and Clang support __attribute__((sysv_abi)), which makes+ * calls to the annotated function follow the SysV calling convention.+ *+ * MLD_SYSV_ABI_SUPPORTED signals that the toolchain can call SysV assembly+ * routines; the x86_64 assembly backend is only enabled if it is defined.+ * MLD_SYSV_ABI is the attribute carried by declarations of x86_64 assembly+ * routines. Both macros can be set externally for toolchains offering an+ * equivalent mechanism that is not recognized here. */+#if defined(MLD_SYS_X86_64) && !defined(MLD_SYSV_ABI_SUPPORTED)+#if !defined(MLD_SYS_WINDOWS) || defined(__GNUC__) || defined(__clang__)+#define MLD_SYSV_ABI_SUPPORTED+#endif+#endif++#if !defined(MLD_SYSV_ABI)+#if defined(MLD_SYS_WINDOWS) && defined(MLD_SYSV_ABI_SUPPORTED)+#define MLD_SYSV_ABI __attribute__((sysv_abi))+#else+#define MLD_SYSV_ABI+#endif+#endif /* !MLD_SYSV_ABI */++#if !defined(__ASSEMBLER__)+/* System capability enumeration */+typedef enum+{+ /* x86_64 */+ MLD_SYS_CAP_X86_64_AVX2,+ /* AArch64 */+ MLD_SYS_CAP_AARCH64_NEON,+ MLD_SYS_CAP_AARCH64_SHA3,+ /* Armv8.1-M */+ MLD_SYS_CAP_ARMV81M_MVE+} mld_sys_cap;++#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC)+#include "cbmc.h"++MLD_MUST_CHECK_RETURN_VALUE+static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap)+__contract__(+ ensures(return_value == 0 || return_value == 1)+)+{+ /* By default, we rely on compile-time feature detection/specification:+ * If a feature is enabled at compile-time, we assume it is supported by+ * the host that the resulting library/binary will be built on.+ * If this assumption is not true, you MUST overwrite this function.+ * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in+ * mldsa_native_config.h for more information. */+ (void)cap;+ return 1;+}+#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */+#endif /* !__ASSEMBLER__ */++#endif /* !MLD_SYS_H */
@@ -0,0 +1,55 @@+/*+ * Copyright (c) The mldsa-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mldsa-native repository.+ * Do not modify it directly.+ */+++/*+ * Table of zeta values used in the reference NTT and inverse NTT.+ * See autogen for details.+ */+static const int32_t mld_zetas[MLDSA_N] = {+ 0, 25847, -2608894, -518909, 237124, -777960, -876248,+ 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855,+ 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488,+ -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672,+ 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325,+ 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716,+ 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267,+ -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596,+ 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892,+ -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950,+ 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144,+ -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295,+ -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981,+ -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944,+ 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342,+ -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856,+ 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589,+ 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060,+ -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478,+ 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181,+ -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542,+ 819034, 495491, -1613174, -43260, -522500, -655327, -3122442,+ 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297,+ 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044,+ 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353,+ 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119,+ 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100,+ 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803,+ 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176,+ -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395,+ 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426,+ 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107,+ -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735,+ 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333,+ -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443,+ -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209,+ 3937738, 1400424, -846154, 1976782,+};
@@ -0,0 +1,2 @@+d1b2fe782888bdb761a50336012923180be7f502+v2.0.0
@@ -0,0 +1,312 @@+mlkem-native is a fork of the public domain Kyber reference+implementation, available on https://github.com/pq-crystals/kyber.++All source code in mlkem/* and dev/* is licensed under your choice+of the Apache-2.0 license OR the ISC license OR the MIT license.+These licenses are reproduced at the bottom of this file.+The copyright holders are indicated at the top of each file.++Files outside the library itself may carry different terms. Every file+states its own SPDX-License-Identifier, which determines the terms that+apply to it. In particular:++The code in test/notrandombytes/*, and its copies in+examples/*/test_only_rng/* and scripts/notrandombytes, is derived from+https://cr.yp.to/papers.html#surf and licensed under+LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT.+It is only used for testing purposes.++The benchmarking code in test/hal/* carries the+MIT license. It is only used for testing purposes.++The tiny_sha3 code in+examples/bring_your_own_fips202/custom_fips202/tiny_sha3/* and+examples/custom_backend/mlkem_native/src/fips202/native/custom/src/*+carries the MIT license. It is only used to demonstrate custom+FIPS-202 implementations.++The proofs in proofs/* are in part derived from Amazon Web Services+verification infrastructure. Individual files carry, among others,+Apache-2.0 OR ISC OR MIT-0, MIT-0, and MIT-0 AND Apache-2.0. None of the+proofs are part of the library.++Documentation is licensed under CC-BY-4.0.++```+Copyright (c) The mlkem-native project authors+Copyright (c) 2020 Dougall Johnson+Copyright (c) 2022 Arm Limited+SPDX-License-Identifier: MIT++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.+```++The tiny_sha3 implementation in examples/custom_backend/mlkem_native/src/fips202/native/custom/src/+carries the MIT license. It is only used for testing purposes.++```+SPDX-License-Identifier: MIT++19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>+```++ISC license+-----------++Copyright <YEAR> <OWNER>++Permission to use, copy, modify, and/or distribute this software for any purpose+with or without fee is hereby granted, provided that the above copyright notice+and this permission notice appear in all copies.++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF+THIS SOFTWARE.+++MIT license+-----------++Copyright <YEAR> <COPYRIGHT HOLDER>++Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the “Software”), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of+the Software, and to permit persons to whom the Software is furnished to do so,+subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.++Apache-2.0 license+------------------++ Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++ 1. Definitions.++ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document.++ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License.++ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity.++ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License.++ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files.++ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types.++ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below).++ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof.++ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution."++ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work.++ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form.++ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed.++ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions:++ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and++ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and++ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and++ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License.++ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License.++ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions.++ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file.++ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License.++ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages.++ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability.++ END OF TERMS AND CONDITIONS++ APPENDIX: How to apply the Apache License to your work.++ To apply the Apache License to your work, attach the following+ boilerplate notice, with the fields enclosed by brackets "[]"+ replaced with your own identifying information. (Don't include+ the brackets!) The text should be enclosed in the appropriate+ comment syntax for the file format. We also recommend that a+ file or class name and description of purpose be included on the+ same "printed page" as the copyright notice for easier+ identification within third-party archives.++ Copyright [yyyy] [name of copyright owner]++ Licensed under the Apache License, Version 2.0 (the "License");+ you may not use this file except in compliance with the License.+ You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++ Unless required by applicable law or agreed to in writing, software+ distributed under the License is distributed on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ See the License for the specific language governing permissions and+ limitations under the License.
@@ -0,0 +1,59 @@+# mlkem-native++ML-KEM (FIPS 203) from the PQ Code Package, vendored here and built for all+three parameter sets.++## Where it comes from++<https://github.com/pq-code-package/mlkem-native>. `COMMIT` holds the+revision this tree is at; `import.sh` puts it there and is how the tree is+refreshed. Nothing here is edited by hand -- every choice crypton makes is+made in `crypton_mlkem.h`, `crypton_mlkem.c` and `crypton.cabal`, so that a+re-import is a straight overwrite.++## Licence++`Apache-2.0 OR ISC OR MIT`, the same three-way form as `cbits/s2n` and by+some of the same authors. crypton takes it under ISC, which is already in+the package's `license:` field. `LICENSE` is the upstream file and is+listed in `license-files:`.++## What is taken and what is not++The whole of `mlkem/`, less the backends for architectures crypton does not+build for: `src/native/riscv64`, `src/native/ppc64le` and the 32-bit+`src/fips202/native/armv81m`. Every reference to those is behind an+`MLK_SYS_` guard that cannot be true on the architectures crypton does+build for, so dropping them changes no build and keeps a few dozen files of+unreachable assembly out of the release tarball. To take one back, delete+its line from `import.sh` and add its directory to `extra-source-files:`.++## How it is built++Upstream builds for one parameter set at a time. `crypton_mlkem.c`+includes the amalgamation once per set -- the level-independent half kept by+exactly one of them -- which is how a single crypton offers ML-KEM-512, 768+and 1024. `crypton_mlkem_asm.S` does the same for the assembly, which is+level-independent and so is included once.++This is the shape `cbits/aes/armv8.c` already uses for the three AES key+sizes, and it has the same hazard: **cabal does not know that the wrapper+depends on the tree it includes.** After changing anything under+`cbits/mlkem`, touch `crypton_mlkem.c`, or the build keeps the object it+already has and the change is not tested.++The hand-written backends are selected by `CRYPTON_MLKEM_NATIVE_BACKEND`,+which `crypton.cabal` defines on x86-64 and AArch64 other than Windows --+the same exclusion, and for the same reasons, as `cbits/s2n`. Everywhere+else the portable C is built, which is the same code and passes the same+tests.++There is no randomised API: `MLK_CONFIG_NO_RANDOMIZED_API` is set, no+`randombytes()` is needed, and randomness is drawn in Haskell through+`MonadRandom` as it is for every other key crypton generates.++The symbols are `crypton_mlkem512_*`, `crypton_mlkem768_*` and+`crypton_mlkem1024_*` rather than upstream's defaults, so that an+application linking another copy of mlkem-native -- through some other+library, or its own -- does not present the linker with two sets of+functions answering to one set of names.
@@ -0,0 +1,31 @@+/*+ * All three ML-KEM parameter sets in one translation unit.+ *+ * mlkem-native is built for one parameter set at a time; a build wanting+ * several includes the amalgamation once per set, with the level-independent+ * half kept by exactly one of them. This is the same shape as+ * cbits/aes/armv8.c, which includes cbits/aes/armv8_impl.c three times for+ * the three AES key sizes.+ *+ * NOTE, as there: cabal does not know that this file depends on the tree it+ * includes. After changing anything under cbits/mlkem, touch this file, or+ * the build will quietly keep the object it already has.+ */+#include "crypton_mlkem.h"++#define MLK_CONFIG_MULTILEVEL_WITH_SHARED 1+#define MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+#define MLK_CONFIG_PARAMETER_SET 512+#include "mlkem_native.c"+#undef MLK_CONFIG_MULTILEVEL_WITH_SHARED+#undef MLK_CONFIG_PARAMETER_SET++#define MLK_CONFIG_MULTILEVEL_NO_SHARED+#define MLK_CONFIG_PARAMETER_SET 768+#include "mlkem_native.c"+#undef MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+#undef MLK_CONFIG_PARAMETER_SET++#define MLK_CONFIG_PARAMETER_SET 1024+#include "mlkem_native.c"+#undef MLK_CONFIG_PARAMETER_SET
@@ -0,0 +1,79 @@+/*+ * What crypton asks of the vendored mlkem-native, in one place. The tree+ * under cbits/mlkem is upstream's and is overwritten by import.sh, so every+ * choice crypton makes is made here instead of by editing it.+ *+ * Included first by both crypton_mlkem.c and crypton_mlkem_asm.S, so it must+ * hold nothing the assembler cannot read: directives, and C behind+ * __ASSEMBLER__.+ */+#ifndef CRYPTON_MLKEM_H+#define CRYPTON_MLKEM_H++/*+ * The symbols are crypton's own, not the default PQCP_MLKEM_NATIVE_*. An+ * application is free to link another copy of mlkem-native -- through some+ * other library, or its own -- and two copies answering to one set of names+ * is a problem the linker resolves silently and in nobody's favour. With+ * MLK_CONFIG_MULTILEVEL_BUILD the level is appended, so the entry points+ * are crypton_mlkem512_*, crypton_mlkem768_* and crypton_mlkem1024_*.+ */+#define MLK_CONFIG_NAMESPACE_PREFIX crypton_mlkem+#define MLK_CONFIG_MULTILEVEL_BUILD++/*+ * No randomised API, so no randombytes() to provide. Randomness is drawn+ * in Haskell through MonadRandom, the way every other key in crypton is+ * generated, and the deterministic entry points are what the FFI calls.+ * That also keeps the C free of any opinion about where entropy comes from.+ */+#define MLK_CONFIG_NO_RANDOMIZED_API++/*+ * The hand-written backends, where crypton.cabal says the architecture has+ * them. Without this the portable C is built, which is correct everywhere+ * and is what every other architecture gets.+ */+#ifdef CRYPTON_MLKEM_NATIVE_BACKEND+#define MLK_CONFIG_USE_NATIVE_BACKEND_ARITH+#define MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202++/*+ * Which of the backend's instructions this processor actually has.+ *+ * Without this both packages decide at compile time: the backend is built+ * because the architecture has the instructions in principle, and is then+ * called with no check. Upstream says so plainly -- if the machine that+ * runs the binary may differ from the one that built it, this function+ * MUST be provided -- and crypton is a library whose builds are copied+ * between machines and shipped by distributions. Without it a binary+ * built on a host with AVX2 dies with SIGILL on one without (#316).+ *+ * The dispatch sites are upstream's; each falls back to the portable C+ * when this answers no. The answers come from crypton's own detection,+ * the same that AES-NI, PCLMUL and the s2n-bignum variants use.+ */+#define MLK_CONFIG_CUSTOM_CAPABILITY_FUNC+#ifndef __ASSEMBLER__+#include "src/sys.h"+#include "crypton_cpu.h"++static MLK_INLINE int mlk_sys_check_capability(mlk_sys_cap cap)+{+#if defined(__x86_64__)+ if (cap == MLK_SYS_CAP_X86_64_AVX2)+ return (crypton_x86_simd_features() & CRYPTON_X86_AVX2) != 0;+#elif defined(__aarch64__)+ /* NEON is not optional on AArch64; the Keccak instructions are. */+ if (cap == MLK_SYS_CAP_AARCH64_NEON)+ return 1;+ if (cap == MLK_SYS_CAP_AARCH64_SHA3)+ return (crypton_arm_features() & CRYPTON_ARM_SHA3) != 0;+#endif+ (void)cap;+ return 0;+}+#endif /* !__ASSEMBLER__ */+#endif++#endif /* CRYPTON_MLKEM_H */
@@ -0,0 +1,14 @@+/*+ * The assembly half, which is level-independent: it is included once, with+ * the shared directives kept, and covers all three parameter sets. See the+ * comment at the top of mlkem_native_asm.S.+ *+ * Built only where crypton.cabal defines CRYPTON_MLKEM_NATIVE_BACKEND; on+ * every other architecture this file is not in asm-sources at all.+ */+#include "crypton_mlkem.h"++#define MLK_CONFIG_MULTILEVEL_WITH_SHARED 1+#define MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+#define MLK_CONFIG_PARAMETER_SET 768+#include "mlkem_native_asm.S"
@@ -0,0 +1,42 @@+#!/bin/sh+# Re-import the vendored parts of the PQ Code Package's mlkem-native.+#+# The files are kept unmodified. Everything crypton decides -- which+# parameter sets exist, what the symbols are called, that there is no+# randomised API -- is decided in cbits/mlkem/crypton_mlkem.c and in+# crypton.cabal, not by editing anything here. Run this from cbits/mlkem:+#+# ./import.sh [tag-or-commit]+#+# and commit the result together with the COMMIT line it writes, so that the+# tree always says which upstream revision it holds.+set -eu++REPO=https://github.com/pq-code-package/mlkem-native+REV=${1:-v2.0.0}+HERE=$(cd "$(dirname "$0")" && pwd)+TMP=$(mktemp -d)+trap 'rm -rf "$TMP"' EXIT++git clone -q "$REPO" "$TMP/u"+git -C "$TMP/u" checkout -q "$REV"++rm -rf "$HERE/src"+cp "$TMP/u/mlkem/mlkem_native.c" "$HERE/"+cp "$TMP/u/mlkem/mlkem_native.h" "$HERE/"+cp "$TMP/u/mlkem/mlkem_native_asm.S" "$HERE/"+cp "$TMP/u/mlkem/mlkem_native_config.h" "$HERE/"+cp -R "$TMP/u/mlkem/src" "$HERE/src"+cp "$TMP/u/LICENSE" "$HERE/LICENSE"++# The backends for architectures crypton does not build for. Every+# reference to them is behind an MLK_SYS_ guard that cannot be true on the+# two it does, so dropping them changes no build and keeps a few dozen files+# of unreachable assembly out of the release tarball. If crypton ever+# wants one of them, delete its line here rather than patching anything.+rm -rf "$HERE/src/native/riscv64" "$HERE/src/native/ppc64le"+rm -rf "$HERE/src/fips202/native/armv81m"++git -C "$TMP/u" rev-parse HEAD > "$HERE/COMMIT"+git -C "$TMP/u" describe --tags --exact-match 2>/dev/null >> "$HERE/COMMIT" || true+echo "imported $(head -1 "$HERE/COMMIT")"
@@ -0,0 +1,692 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++/******************************************************************************+ *+ * Single compilation unit (SCU) for fixed-level build of mlkem-native+ *+ * This compilation unit bundles together all source files for a build+ * of mlkem-native for a fixed security level (MLKEM-512/768/1024).+ *+ * # API+ *+ * The API exposed by this file is described in mlkem_native.h.+ *+ * # Multi-level build+ *+ * If you want an SCU build of mlkem-native with support for multiple security+ * levels, you need to include this file multiple times, and set+ * MLK_CONFIG_MULTILEVEL_WITH_SHARED and MLK_CONFIG_MULTILEVEL_NO_SHARED+ * appropriately. This is exemplified in examples/monolithic_build_multilevel+ * and examples/monolithic_build_multilevel_native.+ *+ * # Configuration+ *+ * The following options from the mlkem-native configuration are relevant:+ *+ * - MLK_CONFIG_FIPS202_CUSTOM_HEADER+ * Set this option if you use a custom FIPS202 implementation.+ *+ * - MLK_CONFIG_USE_NATIVE_BACKEND_ARITH+ * Set this option if you want to include the native arithmetic backends+ * in your build.+ *+ * - MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202+ * Set this option if you want to include the native FIPS202 backends+ * in your build.+ *+ * - MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+ * Set this option if you want to keep the directives defined in+ * level-independent headers. This is needed for a multi-level build.+ */++/* If parts of the mlkem-native source tree are not used,+ * consider reducing this header via `unifdef`.+ *+ * Example:+ * ```bash+ * unifdef -UMLK_CONFIG_USE_NATIVE_BACKEND_ARITH mlkem_native.c+ * ```+ */++#include "src/common.h"++#include "src/compress.c"+#include "src/debug.c"+#include "src/indcpa.c"+#include "src/kem.c"+#include "src/poly.c"+#include "src/poly_k.c"+#include "src/sampling.c"+#include "src/verify.c"++#if !defined(MLK_CONFIG_FIPS202_CUSTOM_HEADER)+#include "src/fips202/fips202.c"+#include "src/fips202/fips202x4.c"+#include "src/fips202/keccakf1600.c"+#endif++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_ARITH)+#if defined(MLK_SYS_AARCH64)+#include "src/native/aarch64/src/aarch64_zetas.c"+#include "src/native/aarch64/src/rej_uniform_table.c"+#endif+#if defined(MLK_SYS_X86_64)+#include "src/native/x86_64/src/compress_consts.c"+#include "src/native/x86_64/src/consts.c"+#include "src/native/x86_64/src/rej_uniform_table.c"+#endif+#if defined(MLK_SYS_RISCV64)+#include "src/native/riscv64/src/rv64v_debug.c"+#include "src/native/riscv64/src/rv64v_poly.c"+#endif+#if defined(MLK_SYS_PPC64LE)+#include "src/native/ppc64le/src/consts.c"+#endif+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202)+#if defined(MLK_SYS_AARCH64)+#include "src/fips202/native/aarch64/src/keccakf1600_round_constants.c"+#endif+#if defined(MLK_SYS_X86_64)+#include "src/fips202/native/x86_64/src/keccakf1600_constants.c"+#endif+#if defined(MLK_SYS_ARMV81M_MVE)+#include "src/fips202/native/armv81m/src/keccak_f1600_x4_mve.c"+#include "src/fips202/native/armv81m/src/keccakf1600_round_constants.c"+#endif+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 */++/* Macro #undef's+ *+ * The following undefines macros from headers+ * included by the source files imported above.+ *+ * This is to allow building and linking multiple builds+ * of mlkem-native for varying parameter sets through concatenation+ * of this file, as if the files had been compiled separately.+ * If this is not relevant to you, you may remove the following.+ */++/*+ * Undefine macros from MLK_CONFIG_PARAMETER_SET-specific files+ */+/* mlkem/mlkem_native.h */+#undef MLKEM1024_BYTES+#undef MLKEM1024_CIPHERTEXTBYTES+#undef MLKEM1024_PUBLICKEYBYTES+#undef MLKEM1024_SECRETKEYBYTES+#undef MLKEM1024_SYMBYTES+#undef MLKEM512_BYTES+#undef MLKEM512_CIPHERTEXTBYTES+#undef MLKEM512_PUBLICKEYBYTES+#undef MLKEM512_SECRETKEYBYTES+#undef MLKEM512_SYMBYTES+#undef MLKEM768_BYTES+#undef MLKEM768_CIPHERTEXTBYTES+#undef MLKEM768_PUBLICKEYBYTES+#undef MLKEM768_SECRETKEYBYTES+#undef MLKEM768_SYMBYTES+#undef MLKEM_BYTES+#undef MLKEM_CIPHERTEXTBYTES+#undef MLKEM_CIPHERTEXTBYTES_+#undef MLKEM_PUBLICKEYBYTES+#undef MLKEM_PUBLICKEYBYTES_+#undef MLKEM_SECRETKEYBYTES+#undef MLKEM_SECRETKEYBYTES_+#undef MLKEM_SYMBYTES+#undef MLK_API_CONCAT+#undef MLK_API_CONCAT_+#undef MLK_API_CONCAT_UNDERSCORE+#undef MLK_API_MUST_CHECK_RETURN_VALUE+#undef MLK_API_NAMESPACE+#undef MLK_API_NAMESPACE_PREFIX+#undef MLK_API_QUALIFIER+#undef MLK_ERR_FAIL+#undef MLK_ERR_INVALID_PK+#undef MLK_ERR_INVALID_SK+#undef MLK_ERR_OUT_OF_MEMORY+#undef MLK_ERR_PCT_FAIL+#undef MLK_ERR_RNG_FAIL+#undef MLK_H+#undef MLK_MAX3_+#undef MLK_TOTAL_ALLOC_1024+#undef MLK_TOTAL_ALLOC_1024_DECAPS+#undef MLK_TOTAL_ALLOC_1024_ENCAPS+#undef MLK_TOTAL_ALLOC_1024_KEYPAIR+#undef MLK_TOTAL_ALLOC_1024_KEYPAIR_NO_PCT+#undef MLK_TOTAL_ALLOC_1024_KEYPAIR_PCT+#undef MLK_TOTAL_ALLOC_512+#undef MLK_TOTAL_ALLOC_512_DECAPS+#undef MLK_TOTAL_ALLOC_512_ENCAPS+#undef MLK_TOTAL_ALLOC_512_KEYPAIR+#undef MLK_TOTAL_ALLOC_512_KEYPAIR_NO_PCT+#undef MLK_TOTAL_ALLOC_512_KEYPAIR_PCT+#undef MLK_TOTAL_ALLOC_768+#undef MLK_TOTAL_ALLOC_768_DECAPS+#undef MLK_TOTAL_ALLOC_768_ENCAPS+#undef MLK_TOTAL_ALLOC_768_KEYPAIR+#undef MLK_TOTAL_ALLOC_768_KEYPAIR_NO_PCT+#undef MLK_TOTAL_ALLOC_768_KEYPAIR_PCT+/* mlkem/src/common.h */+#undef MLK_ADD_PARAM_SET+#undef MLK_ALLOC+#undef MLK_APPLY+#undef MLK_ASM_FN_SIZE+#undef MLK_ASM_FN_SYMBOL+#undef MLK_ASM_NAMESPACE+#undef MLK_BUILD_INTERNAL+#undef MLK_COMMON_H+#undef MLK_CONCAT+#undef MLK_CONCAT_+#undef MLK_EMPTY_CU+#undef MLK_ERR_FAIL+#undef MLK_ERR_INVALID_PK+#undef MLK_ERR_INVALID_SK+#undef MLK_ERR_OUT_OF_MEMORY+#undef MLK_ERR_PCT_FAIL+#undef MLK_ERR_RNG_FAIL+#undef MLK_EXTERNAL_API+#undef MLK_FIPS202X4_HEADER_FILE+#undef MLK_FIPS202_HEADER_FILE+#undef MLK_FREE+#undef MLK_INTERNAL_API+#undef MLK_INTERNAL_DATA_DECLARATION+#undef MLK_INTERNAL_DATA_DEFINITION+#undef MLK_NAMESPACE+#undef MLK_NAMESPACE_K+#undef MLK_NAMESPACE_PREFIX+#undef MLK_NAMESPACE_PREFIX_K+#undef mlk_memcpy+#undef mlk_memset+/* mlkem/src/indcpa.h */+#undef MLK_INDCPA_H+#undef mlk_gen_matrix+#undef mlk_indcpa_dec+#undef mlk_indcpa_enc+#undef mlk_indcpa_keypair_derand+/* mlkem/src/kem.h */+#undef MLK_KEM_H+#undef mlk_kem_check_pk+#undef mlk_kem_check_sk+#undef mlk_kem_dec+#undef mlk_kem_enc+#undef mlk_kem_enc_derand+#undef mlk_kem_keypair+#undef mlk_kem_keypair_derand+/* mlkem/src/params.h */+#undef MLKEM_DU+#undef MLKEM_DV+#undef MLKEM_ETA1+#undef MLKEM_ETA2+#undef MLKEM_INDCCA_CIPHERTEXTBYTES+#undef MLKEM_INDCCA_PUBLICKEYBYTES+#undef MLKEM_INDCCA_SECRETKEYBYTES+#undef MLKEM_INDCPA_BYTES+#undef MLKEM_INDCPA_MSGBYTES+#undef MLKEM_INDCPA_PUBLICKEYBYTES+#undef MLKEM_INDCPA_SECRETKEYBYTES+#undef MLKEM_K+#undef MLKEM_N+#undef MLKEM_POLYBYTES+#undef MLKEM_POLYCOMPRESSEDBYTES_D10+#undef MLKEM_POLYCOMPRESSEDBYTES_D11+#undef MLKEM_POLYCOMPRESSEDBYTES_D4+#undef MLKEM_POLYCOMPRESSEDBYTES_D5+#undef MLKEM_POLYCOMPRESSEDBYTES_DU+#undef MLKEM_POLYCOMPRESSEDBYTES_DV+#undef MLKEM_POLYVECBYTES+#undef MLKEM_POLYVECCOMPRESSEDBYTES_DU+#undef MLKEM_Q+#undef MLKEM_Q_HALF+#undef MLKEM_SSBYTES+#undef MLKEM_SYMBYTES+#undef MLKEM_UINT12_LIMIT+#undef MLK_PARAMS_H+/* mlkem/src/poly_k.h */+#undef MLK_POLY_K_H+#undef mlk_poly_compress_du+#undef mlk_poly_compress_dv+#undef mlk_poly_decompress_du+#undef mlk_poly_decompress_dv+#undef mlk_poly_getnoise_eta1122_4x+#undef mlk_poly_getnoise_eta1_4x+#undef mlk_poly_getnoise_eta2+#undef mlk_poly_getnoise_eta2_4x+#undef mlk_polymat+#undef mlk_polyvec+#undef mlk_polyvec_add+#undef mlk_polyvec_basemul_acc_montgomery_cached+#undef mlk_polyvec_compress_du+#undef mlk_polyvec_decompress_du+#undef mlk_polyvec_frombytes+#undef mlk_polyvec_invntt_tomont+#undef mlk_polyvec_mulcache+#undef mlk_polyvec_mulcache_compute+#undef mlk_polyvec_ntt+#undef mlk_polyvec_reduce+#undef mlk_polyvec_tobytes+#undef mlk_polyvec_tomont++#if !defined(MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS)+/*+ * Undefine macros from MLK_CONFIG_PARAMETER_SET-generic files+ */+/* mlkem/src/compress.h */+#undef MLK_COMPRESS_H+#undef mlk_poly_compress_d10+#undef mlk_poly_compress_d11+#undef mlk_poly_compress_d4+#undef mlk_poly_compress_d5+#undef mlk_poly_decompress_d10+#undef mlk_poly_decompress_d11+#undef mlk_poly_decompress_d4+#undef mlk_poly_decompress_d5+#undef mlk_poly_frombytes+#undef mlk_poly_frommsg+#undef mlk_poly_tobytes+#undef mlk_poly_tomsg+/* mlkem/src/context.h */+#undef MLK_CONTEXT_H+#undef MLK_CONTEXT_PARAMETERS_0+#undef MLK_CONTEXT_PARAMETERS_1+#undef MLK_CONTEXT_PARAMETERS_2+#undef MLK_CONTEXT_PARAMETERS_3+#undef MLK_CONTEXT_PARAMETERS_4+#undef MLK_CONTEXT_UNUSED+/* mlkem/src/debug.h */+#undef MLK_DEBUG_H+#undef mlk_assert+#undef mlk_assert_abs_bound+#undef mlk_assert_abs_bound_2d+#undef mlk_assert_bound+#undef mlk_assert_bound_2d+#undef mlk_debug_check_assert+#undef mlk_debug_check_bounds+/* mlkem/src/poly.h */+#undef MLK_INVNTT_BOUND+#undef MLK_NTT_BOUND+#undef MLK_POLY_H+#undef mlk_poly_add+#undef mlk_poly_invntt_tomont+#undef mlk_poly_mulcache_compute+#undef mlk_poly_ntt+#undef mlk_poly_reduce+#undef mlk_poly_sub+#undef mlk_poly_tomont+/* mlkem/src/randombytes.h */+#undef MLK_RANDOMBYTES_H+/* mlkem/src/sampling.h */+#undef MLK_SAMPLING_H+#undef mlk_poly_cbd2+#undef mlk_poly_cbd3+#undef mlk_poly_rej_uniform+#undef mlk_poly_rej_uniform_x4+/* mlkem/src/symmetric.h */+#undef MLK_SYMMETRIC_H+#undef MLK_XOF_RATE+#undef mlk_hash_g+#undef mlk_hash_h+#undef mlk_hash_j+#undef mlk_prf_eta+#undef mlk_prf_eta1+#undef mlk_prf_eta1_x4+#undef mlk_prf_eta2+#undef mlk_xof_absorb+#undef mlk_xof_ctx+#undef mlk_xof_init+#undef mlk_xof_release+#undef mlk_xof_squeezeblocks+#undef mlk_xof_x4_absorb+#undef mlk_xof_x4_ctx+#undef mlk_xof_x4_init+#undef mlk_xof_x4_release+#undef mlk_xof_x4_squeezeblocks+/* mlkem/src/sys.h */+#undef MLK_ALIGN+#undef MLK_ALIGN_UP+#undef MLK_ALWAYS_INLINE+#undef MLK_CET_ENDBR+#undef MLK_CT_TESTING_DECLASSIFY+#undef MLK_CT_TESTING_SECRET+#undef MLK_DEFAULT_ALIGN+#undef MLK_HAVE_INLINE_ASM+#undef MLK_INLINE+#undef MLK_MUST_CHECK_RETURN_VALUE+#undef MLK_NOINLINE+#undef MLK_RESTRICT+#undef MLK_STATIC_TESTABLE+#undef MLK_SYSV_ABI+#undef MLK_SYSV_ABI_SUPPORTED+#undef MLK_SYS_AARCH64+#undef MLK_SYS_AARCH64_EB+#undef MLK_SYS_AARCH64_NEON+#undef MLK_SYS_APPLE+#undef MLK_SYS_ARMV81M_MVE+#undef MLK_SYS_BIG_ENDIAN+#undef MLK_SYS_H+#undef MLK_SYS_LINUX+#undef MLK_SYS_LITTLE_ENDIAN+#undef MLK_SYS_PPC64LE+#undef MLK_SYS_RISCV32+#undef MLK_SYS_RISCV64+#undef MLK_SYS_RISCV64_RVV+#undef MLK_SYS_WINDOWS+#undef MLK_SYS_X86_64+#undef MLK_SYS_X86_64_AVX2+/* mlkem/src/verify.h */+#undef MLK_USE_ASM_VALUE_BARRIER+#undef MLK_VERIFY_H+#undef mlk_ct_opt_blocker_u64+/* mlkem/src/cbmc.h */+#undef MLK_CBMC_H+#undef __contract__+#undef __loop__++#if !defined(MLK_CONFIG_FIPS202_CUSTOM_HEADER)+/*+ * Undefine macros from FIPS-202 files+ */+/* mlkem/src/fips202/fips202.h */+#undef FIPS202_X4_DEFAULT_IMPLEMENTATION+#undef MLK_FIPS202_FIPS202_H+#undef SHA3_256_HASHBYTES+#undef SHA3_256_RATE+#undef SHA3_384_RATE+#undef SHA3_512_HASHBYTES+#undef SHA3_512_RATE+#undef SHAKE128_RATE+#undef SHAKE256_RATE+#undef mlk_sha3_256+#undef mlk_sha3_512+#undef mlk_shake128_absorb_once+#undef mlk_shake128_init+#undef mlk_shake128_release+#undef mlk_shake128_squeezeblocks+#undef mlk_shake256+/* mlkem/src/fips202/fips202x4.h */+#undef MLK_FIPS202_FIPS202X4_H+#undef mlk_shake128x4_absorb_once+#undef mlk_shake128x4_init+#undef mlk_shake128x4_release+#undef mlk_shake128x4_squeezeblocks+#undef mlk_shake256x4+/* mlkem/src/fips202/keccakf1600.h */+#undef MLK_FIPS202_KECCAKF1600_H+#undef MLK_KECCAK_LANES+#undef MLK_KECCAK_WAY+#undef mlk_keccakf1600_extract_bytes+#undef mlk_keccakf1600_permute+#undef mlk_keccakf1600_xor_bytes+#undef mlk_keccakf1600x4_extract_bytes+#undef mlk_keccakf1600x4_permute+#undef mlk_keccakf1600x4_xor_bytes+#endif /* !MLK_CONFIG_FIPS202_CUSTOM_HEADER */++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202)+/* mlkem/src/fips202/native/api.h */+#undef MLK_FIPS202_NATIVE_API_H+#undef MLK_NATIVE_FUNC_FALLBACK+#undef MLK_NATIVE_FUNC_SUCCESS+/* mlkem/src/fips202/native/auto.h */+#undef MLK_FIPS202_NATIVE_AUTO_H+#if defined(MLK_SYS_AARCH64)+/*+ * Undefine macros from native code (FIPS202, AArch64)+ */+/* mlkem/src/fips202/native/aarch64/auto.h */+#undef MLK_FIPS202_NATIVE_AARCH64_AUTO_H+/* mlkem/src/fips202/native/aarch64/src/fips202_native_aarch64.h */+#undef MLK_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H+#undef mlk_keccak_f1600_x1_scalar_aarch64_asm+#undef mlk_keccak_f1600_x1_v84a_aarch64_asm+#undef mlk_keccak_f1600_x2_v84a_aarch64_asm+#undef mlk_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm+#undef mlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm+#undef mlk_keccakf1600_round_constants+/* mlkem/src/fips202/native/aarch64/x1_scalar.h */+#undef MLK_FIPS202_AARCH64_NEED_X1_SCALAR+#undef MLK_FIPS202_NATIVE_AARCH64_X1_SCALAR_H+#undef MLK_USE_NATIVE_FIPS202_X1+/* mlkem/src/fips202/native/aarch64/x1_v84a.h */+#undef MLK_FIPS202_AARCH64_NEED_X1_V84A+#undef MLK_FIPS202_NATIVE_AARCH64_X1_V84A_H+#undef MLK_USE_NATIVE_FIPS202_X1+/* mlkem/src/fips202/native/aarch64/x2_v84a.h */+#undef MLK_FIPS202_AARCH64_NEED_X2_V84A+#undef MLK_FIPS202_NATIVE_AARCH64_X2_V84A_H+#undef MLK_USE_NATIVE_FIPS202_X4+/* mlkem/src/fips202/native/aarch64/x4_v8a_scalar.h */+#undef MLK_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID+#undef MLK_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H+#undef MLK_USE_NATIVE_FIPS202_X4+/* mlkem/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h */+#undef MLK_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID+#undef MLK_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H+#undef MLK_USE_NATIVE_FIPS202_X4+#endif /* MLK_SYS_AARCH64 */+#if defined(MLK_SYS_X86_64)+/*+ * Undefine macros from native code (FIPS202, x86_64)+ */+/* mlkem/src/fips202/native/x86_64/keccak_f1600_x4_avx2.h */+#undef MLK_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H+#undef MLK_FIPS202_X86_64_NEED_X4_AVX2+#undef MLK_USE_NATIVE_FIPS202_X4+/* mlkem/src/fips202/native/x86_64/src/fips202_native_x86_64.h */+#undef MLK_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H+#undef mlk_keccak_f1600_x4_avx2_asm+#undef mlk_keccak_rho56+#undef mlk_keccak_rho8+#undef mlk_keccakf1600_round_constants+#endif /* MLK_SYS_X86_64 */+#if defined(MLK_SYS_ARMV81M_MVE)+/*+ * Undefine macros from native code (FIPS202, Armv8.1-M)+ */+/* mlkem/src/fips202/native/armv81m/mve.h */+#undef MLK_FIPS202_ARMV81M_NEED_X4+#undef MLK_FIPS202_NATIVE_ARMV81M+#undef MLK_FIPS202_NATIVE_ARMV81M_MVE_H+#undef MLK_USE_NATIVE_FIPS202_X4+#undef MLK_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES+#undef MLK_USE_NATIVE_FIPS202_X4_XOR_BYTES+#undef mlk_keccak_f1600_x4_native_impl+/* mlkem/src/fips202/native/armv81m/src/fips202_native_armv81m.h */+#undef MLK_FIPS202_NATIVE_ARMV81M_SRC_FIPS202_NATIVE_ARMV81M_H+#undef mlk_keccak_f1600_x4_mve_asm+#undef mlk_keccak_f1600_x4_state_extract_bytes_asm+#undef mlk_keccak_f1600_x4_state_xor_bytes_asm+#undef mlk_keccakf1600_round_constants+#endif /* MLK_SYS_ARMV81M_MVE */+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 */+#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_ARITH)+/* mlkem/src/native/api.h */+#undef MLK_INVNTT_BOUND+#undef MLK_NATIVE_API_H+#undef MLK_NATIVE_FUNC_FALLBACK+#undef MLK_NATIVE_FUNC_SUCCESS+#undef MLK_NTT_BOUND+/* mlkem/src/native/meta.h */+#undef MLK_NATIVE_META_H+#if defined(MLK_SYS_AARCH64)+/*+ * Undefine macros from native code (Arith, AArch64)+ */+/* mlkem/src/native/aarch64/meta.h */+#undef MLK_ARITH_BACKEND_AARCH64+#undef MLK_NATIVE_AARCH64_META_H+#undef MLK_USE_NATIVE_INTT+#undef MLK_USE_NATIVE_NTT+#undef MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED+#undef MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE+#undef MLK_USE_NATIVE_POLY_REDUCE+#undef MLK_USE_NATIVE_POLY_TOBYTES+#undef MLK_USE_NATIVE_POLY_TOMONT+#undef MLK_USE_NATIVE_REJ_UNIFORM+/* mlkem/src/native/aarch64/src/arith_native_aarch64.h */+#undef MLK_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H+#undef mlk_aarch64_invntt_zetas_layer12345+#undef mlk_aarch64_invntt_zetas_layer67+#undef mlk_aarch64_ntt_zetas_layer12345+#undef mlk_aarch64_ntt_zetas_layer67+#undef mlk_aarch64_zetas_mulcache_native+#undef mlk_aarch64_zetas_mulcache_twisted_native+#undef mlk_intt_aarch64_asm+#undef mlk_ntt_aarch64_asm+#undef mlk_poly_mulcache_compute_aarch64_asm+#undef mlk_poly_reduce_aarch64_asm+#undef mlk_poly_tobytes_aarch64_asm+#undef mlk_poly_tomont_aarch64_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm+#undef mlk_rej_uniform_aarch64_asm+#undef mlk_rej_uniform_table+#endif /* MLK_SYS_AARCH64 */+#if defined(MLK_SYS_X86_64)+/*+ * Undefine macros from native code (Arith, X86_64)+ */+/* mlkem/src/native/x86_64/meta.h */+#undef MLK_ARITH_BACKEND_X86_64_DEFAULT+#undef MLK_NATIVE_X86_64_META_H+#undef MLK_USE_NATIVE_INTT+#undef MLK_USE_NATIVE_NTT+#undef MLK_USE_NATIVE_NTT_CUSTOM_ORDER+#undef MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED+#undef MLK_USE_NATIVE_POLY_COMPRESS_D10+#undef MLK_USE_NATIVE_POLY_COMPRESS_D11+#undef MLK_USE_NATIVE_POLY_COMPRESS_D4+#undef MLK_USE_NATIVE_POLY_COMPRESS_D5+#undef MLK_USE_NATIVE_POLY_DECOMPRESS_D10+#undef MLK_USE_NATIVE_POLY_DECOMPRESS_D11+#undef MLK_USE_NATIVE_POLY_DECOMPRESS_D4+#undef MLK_USE_NATIVE_POLY_DECOMPRESS_D5+#undef MLK_USE_NATIVE_POLY_FROMBYTES+#undef MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE+#undef MLK_USE_NATIVE_POLY_REDUCE+#undef MLK_USE_NATIVE_POLY_TOBYTES+#undef MLK_USE_NATIVE_POLY_TOMONT+#undef MLK_USE_NATIVE_REJ_UNIFORM+/* mlkem/src/native/x86_64/src/arith_native_x86_64.h */+#undef MLK_AVX2_REJ_UNIFORM_BUFLEN+#undef MLK_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H+#undef mlk_invntt_avx2_asm+#undef mlk_ntt_avx2_asm+#undef mlk_nttfrombytes_avx2_asm+#undef mlk_ntttobytes_avx2_asm+#undef mlk_nttunpack_avx2_asm+#undef mlk_poly_compress_d10_avx2_asm+#undef mlk_poly_compress_d11_avx2_asm+#undef mlk_poly_compress_d4_avx2_asm+#undef mlk_poly_compress_d5_avx2_asm+#undef mlk_poly_decompress_d10_avx2_asm+#undef mlk_poly_decompress_d11_avx2_asm+#undef mlk_poly_decompress_d4_avx2_asm+#undef mlk_poly_decompress_d5_avx2_asm+#undef mlk_poly_mulcache_compute_avx2_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm+#undef mlk_reduce_avx2_asm+#undef mlk_rej_uniform_avx2_asm+#undef mlk_rej_uniform_table+#undef mlk_tomont_avx2_asm+/* mlkem/src/native/x86_64/src/compress_consts.h */+#undef MLK_NATIVE_X86_64_SRC_COMPRESS_CONSTS_H+#undef mlk_compress_d10_data+#undef mlk_compress_d11_data+#undef mlk_compress_d4_data+#undef mlk_compress_d5_data+#undef mlk_decompress_d10_data+#undef mlk_decompress_d11_data+#undef mlk_decompress_d4_data+#undef mlk_decompress_d5_data+/* mlkem/src/native/x86_64/src/consts.h */+#undef MLK_AVX2_BACKEND_DATA_OFFSET_MULCACHE_TWIDDLES+#undef MLK_AVX2_BACKEND_DATA_OFFSET_REVIDXB+#undef MLK_AVX2_BACKEND_DATA_OFFSET_REVIDXD+#undef MLK_AVX2_BACKEND_DATA_OFFSET_ZETAS_EXP+#undef MLK_NATIVE_X86_64_SRC_CONSTS_H+#undef mlk_qdata+#endif /* MLK_SYS_X86_64 */+#if defined(MLK_SYS_RISCV64)+/*+ * Undefine macros from native code (Arith, RISC-V 64)+ */+/* mlkem/src/native/riscv64/meta.h */+#undef MLK_ARITH_BACKEND_RISCV64+#undef MLK_NATIVE_RISCV64_META_H+#undef MLK_USE_NATIVE_INTT+#undef MLK_USE_NATIVE_NTT+#undef MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED+#undef MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE+#undef MLK_USE_NATIVE_POLY_REDUCE+#undef MLK_USE_NATIVE_POLY_TOMONT+#undef MLK_USE_NATIVE_REJ_UNIFORM+/* mlkem/src/native/riscv64/src/arith_native_riscv64.h */+#undef MLK_NATIVE_RISCV64_SRC_ARITH_NATIVE_RISCV64_H+#undef mlk_rv64v_poly_add+#undef mlk_rv64v_poly_basemul_mont_add_k2+#undef mlk_rv64v_poly_basemul_mont_add_k3+#undef mlk_rv64v_poly_basemul_mont_add_k4+#undef mlk_rv64v_poly_invntt_tomont+#undef mlk_rv64v_poly_ntt+#undef mlk_rv64v_poly_reduce+#undef mlk_rv64v_poly_sub+#undef mlk_rv64v_poly_tomont+#undef mlk_rv64v_rej_uniform+/* mlkem/src/native/riscv64/src/rv64v_debug.h */+#undef MLK_NATIVE_RISCV64_SRC_RV64V_DEBUG_H+#undef mlk_assert_abs_bound_int16m1+#undef mlk_assert_abs_bound_int16m2+#undef mlk_assert_bound_int16m1+#undef mlk_assert_bound_int16m2+#undef mlk_debug_check_bounds_int16m1+#undef mlk_debug_check_bounds_int16m2+#endif /* MLK_SYS_RISCV64 */+#if defined(MLK_SYS_PPC64LE)+/*+ * Undefine macros from native code (Arith, PPC64LE)+ */+/* mlkem/src/native/ppc64le/meta.h */+#undef MLK_ARITH_BACKEND_NAME+#undef MLK_ARITH_BACKEND_PPC64LE_DEFAULT+#undef MLK_NATIVE_PPC64LE_META_H+#undef MLK_USE_NATIVE_INTT+#undef MLK_USE_NATIVE_NTT+#undef MLK_USE_NATIVE_POLY_REDUCE+#undef MLK_USE_NATIVE_POLY_TOMONT+/* mlkem/src/native/ppc64le/src/arith_native_ppc64le.h */+#undef MLK_NATIVE_PPC64LE_SRC_ARITH_NATIVE_PPC64LE_H+#undef mlk_intt_ppc_asm+#undef mlk_ntt_ppc_asm+#undef mlk_poly_tomont_ppc_asm+#undef mlk_reduce_ppc_asm+/* mlkem/src/native/ppc64le/src/consts.h */+#undef MLK_NATIVE_PPC64LE_SRC_CONSTS_H+#undef MLK_PPC_C20159_OFFSET+#undef MLK_PPC_NQ_OFFSET+#undef MLK_PPC_N_INV_OFFSET+#undef MLK_PPC_N_INV_TW_OFFSET+#undef MLK_PPC_Q_OFFSET+#undef MLK_PPC_TOMONT_OFFSET+#undef MLK_PPC_TOMONT_TW_OFFSET+#undef MLK_PPC_ZETA_INTT_OFFSET+#undef MLK_PPC_ZETA_INTT_TW_OFFSET+#undef MLK_PPC_ZETA_NTT_OFFSET+#undef MLK_PPC_ZETA_NTT_TW_OFFSET+#undef mlk_ppc_qdata+#endif /* MLK_SYS_PPC64LE */+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */+#endif /* !MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */
@@ -0,0 +1,464 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS140_3_IG]+ * Implementation Guidance for FIPS 140-3 and the Cryptographic Module+ * Validation Program+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#ifndef MLK_H+#define MLK_H++/*+ * Public API for mlkem-native.+ *+ * This header defines the public API of a single build of mlkem-native.+ *+ * Make sure the configuration file is in the include path+ * (this is "mlkem_native_config.h" by default, or MLK_CONFIG_FILE if defined).+ *+ * # API conventions+ *+ * Conventions shared by all functions below (return values, pointer validity,+ * output buffers on error) are documented in API-CONVENTIONS.md.+ *+ * # Multi-level builds+ *+ * This header specifies a build of mlkem-native for a fixed security level.+ * If you need multiple security levels, leave the security level unspecified+ * in the configuration file and include this header multiple times, setting+ * MLK_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLK_H+ * guard to allow multiple inclusions.+ *+ * In this case, the configuration file must also set+ * MLK_CONFIG_MULTILEVEL_BUILD. Without it, the parameter set is not appended+ * to the namespace prefix and all inclusions declare the same symbol names.+ */++/******************************* Key sizes ************************************/++/* Sizes of cryptographic material, per parameter set */+/* See mlkem/src/params.h for the arithmetic expressions giving rise to these */+/* check-magic: off */+#define MLKEM512_SECRETKEYBYTES 1632+#define MLKEM512_PUBLICKEYBYTES 800+#define MLKEM512_CIPHERTEXTBYTES 768++#define MLKEM768_SECRETKEYBYTES 2400+#define MLKEM768_PUBLICKEYBYTES 1184+#define MLKEM768_CIPHERTEXTBYTES 1088++#define MLKEM1024_SECRETKEYBYTES 3168+#define MLKEM1024_PUBLICKEYBYTES 1568+#define MLKEM1024_CIPHERTEXTBYTES 1568+/* check-magic: on */++/* Size of randomness coins in bytes (level-independent) */+#define MLKEM_SYMBYTES 32+#define MLKEM512_SYMBYTES MLKEM_SYMBYTES+#define MLKEM768_SYMBYTES MLKEM_SYMBYTES+#define MLKEM1024_SYMBYTES MLKEM_SYMBYTES+/* Size of shared secret in bytes (level-independent) */+#define MLKEM_BYTES 32+#define MLKEM512_BYTES MLKEM_BYTES+#define MLKEM768_BYTES MLKEM_BYTES+#define MLKEM1024_BYTES MLKEM_BYTES++/* Sizes of cryptographic material, as a function of LVL=512,768,1024 */+#define MLKEM_SECRETKEYBYTES_(LVL) MLKEM##LVL##_SECRETKEYBYTES+#define MLKEM_PUBLICKEYBYTES_(LVL) MLKEM##LVL##_PUBLICKEYBYTES+#define MLKEM_CIPHERTEXTBYTES_(LVL) MLKEM##LVL##_CIPHERTEXTBYTES+#define MLKEM_SECRETKEYBYTES(LVL) MLKEM_SECRETKEYBYTES_(LVL)+#define MLKEM_PUBLICKEYBYTES(LVL) MLKEM_PUBLICKEYBYTES_(LVL)+#define MLKEM_CIPHERTEXTBYTES(LVL) MLKEM_CIPHERTEXTBYTES_(LVL)++/****************************** Error codes ***********************************/++/* Generic failure condition. Currently not returned by any function;+ * reserved for failures that no more specific code covers. */+#define MLK_ERR_FAIL (-1)+/* An allocation failed. This can only happen if MLK_CONFIG_CUSTOM_ALLOC_FREE+ * is defined and the provided MLK_CUSTOM_ALLOC can fail. */+#define MLK_ERR_OUT_OF_MEMORY (-2)+/* An RNG failure occurred. Might be due to insufficient entropy or+ * system misconfiguration. */+#define MLK_ERR_RNG_FAIL (-3)+/* Public key validation failed: the @[FIPS203, Section 7.2, 'modulus check']+ * found a coefficient outside [0,q-1]. Returned by check_pk and by the+ * encapsulation API. */+#define MLK_ERR_INVALID_PK (-4)+/* Secret key validation failed: the @[FIPS203, Section 7.3, 'hash check']+ * found the embedded public key hash inconsistent. Returned by check_sk and+ * by the decapsulation API. */+#define MLK_ERR_INVALID_SK (-5)+/* The 'Pairwise Consistency Test' @[FIPS140_3_IG, p.87] and+ * @[FIPS203, Section 7.1, Pairwise Consistency] failed. Only possible when+ * MLK_CONFIG_KEYGEN_PCT is enabled; signals that the freshly generated key+ * pair failed its encaps/decaps self-test. */+#define MLK_ERR_PCT_FAIL (-6)++/********************* Namespacing and Qualifiers *****************************/++#define MLK_API_CONCAT_(x, y) x##y+#define MLK_API_CONCAT(x, y) MLK_API_CONCAT_(x, y)+#define MLK_API_CONCAT_UNDERSCORE(x, y) MLK_API_CONCAT(MLK_API_CONCAT(x, _), y)++/* You need to make sure the config file is in the include path. */+#if defined(MLK_CONFIG_FILE)+#include MLK_CONFIG_FILE+#else+#include "mlkem_native_config.h"+#endif++/* Namespace prefix for the public API symbols. For multi-level builds, the+ * parameter set is appended to disambiguate the security levels. */+#if defined(MLK_CONFIG_MULTILEVEL_BUILD)+#define MLK_API_NAMESPACE_PREFIX \+ MLK_API_CONCAT(MLK_CONFIG_NAMESPACE_PREFIX, MLK_CONFIG_PARAMETER_SET)+#else+#define MLK_API_NAMESPACE_PREFIX MLK_CONFIG_NAMESPACE_PREFIX+#endif++#define MLK_API_NAMESPACE(sym) \+ MLK_API_CONCAT_UNDERSCORE(MLK_API_NAMESPACE_PREFIX, sym)++#if defined(__GNUC__) || defined(__clang__)+#define MLK_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result))+#else+#define MLK_API_MUST_CHECK_RETURN_VALUE+#endif++#if defined(MLK_CONFIG_EXTERNAL_API_QUALIFIER)+#define MLK_API_QUALIFIER MLK_CONFIG_EXTERNAL_API_QUALIFIER+#else+#define MLK_API_QUALIFIER+#endif++/****************************** Function API **********************************/++#if !defined(MLK_CONFIG_CONSTANTS_ONLY)++#include <stdint.h>++#ifdef __cplusplus+extern "C"+{+#endif++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+/**+ * Generate a public/private keypair for the ML-KEM key encapsulation mechanism.+ *+ * @spec{Implements @[FIPS203, Algorithm 16, ML-KEM.KeyGen_Internal].}+ *+ * @param[out] pk Output public key, an array of+ * MLKEM{512,768,1024}_PUBLICKEYBYTES bytes.+ * @param[out] sk Output private key, an array of+ * MLKEM{512,768,1024}_SECRETKEYBYTES bytes.+ * @param[in] coins Input randomness, an array of 2*MLKEM_SYMBYTES uniformly+ * random bytes.+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_PCT_FAIL MLK_CONFIG_KEYGEN_PCT enabled and PCT failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ * @retval MLK_ERR_RNG_FAIL MLK_CONFIG_KEYGEN_PCT enabled and random+ * number generation failed within the PCT.+ */+MLK_API_QUALIFIER+MLK_API_MUST_CHECK_RETURN_VALUE+int MLK_API_NAMESPACE(keypair_derand)(+ uint8_t pk[MLKEM_PUBLICKEYBYTES(MLK_CONFIG_PARAMETER_SET)],+ uint8_t sk[MLKEM_SECRETKEYBYTES(MLK_CONFIG_PARAMETER_SET)],+ const uint8_t coins[2 * MLKEM_SYMBYTES]+#ifdef MLK_CONFIG_CONTEXT_PARAMETER+ ,+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+++#if !defined(MLK_CONFIG_NO_RANDOMIZED_API)+/**+ * Generate a public/private keypair for the ML-KEM key encapsulation mechanism.+ *+ * @spec{Implements @[FIPS203, Algorithm 19, ML-KEM.KeyGen].}+ *+ * @param[out] pk Output public key, an array of+ * MLKEM{512,768,1024}_PUBLICKEYBYTES bytes.+ * @param[out] sk Output private key, an array of+ * MLKEM{512,768,1024}_SECRETKEYBYTES bytes.+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_PCT_FAIL MLK_CONFIG_KEYGEN_PCT enabled and PCT failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ * @retval MLK_ERR_RNG_FAIL Random number generation failed.+ */+MLK_API_QUALIFIER+MLK_API_MUST_CHECK_RETURN_VALUE+int MLK_API_NAMESPACE(keypair)(+ uint8_t pk[MLKEM_PUBLICKEYBYTES(MLK_CONFIG_PARAMETER_SET)],+ uint8_t sk[MLKEM_SECRETKEYBYTES(MLK_CONFIG_PARAMETER_SET)]+#ifdef MLK_CONFIG_CONTEXT_PARAMETER+ ,+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLK_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API)+/**+ * Generate ciphertext and shared secret for a given public key.+ *+ * @spec{Implements @[FIPS203, Algorithm 17, ML-KEM.Encaps_Internal].}+ *+ * @param[out] ct Output ciphertext, an array of+ * MLKEM{512,768,1024}_CIPHERTEXTBYTES bytes.+ * @param[out] ss Output shared secret, an array of MLKEM_BYTES bytes.+ * @param[in] pk Input public key, an array of+ * MLKEM{512,768,1024}_PUBLICKEYBYTES bytes.+ * @param[in] coins Input randomness, an array of MLKEM_SYMBYTES bytes.+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_INVALID_PK The 'modulus check' @[FIPS203, Section 7.2]+ * for the public key failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+MLK_API_QUALIFIER+MLK_API_MUST_CHECK_RETURN_VALUE+int MLK_API_NAMESPACE(enc_derand)(+ uint8_t ct[MLKEM_CIPHERTEXTBYTES(MLK_CONFIG_PARAMETER_SET)],+ uint8_t ss[MLKEM_BYTES],+ const uint8_t pk[MLKEM_PUBLICKEYBYTES(MLK_CONFIG_PARAMETER_SET)],+ const uint8_t coins[MLKEM_SYMBYTES]+#ifdef MLK_CONFIG_CONTEXT_PARAMETER+ ,+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);++#if !defined(MLK_CONFIG_NO_RANDOMIZED_API)+/**+ * Generate ciphertext and shared secret for a given public key.+ *+ * @spec{Implements @[FIPS203, Algorithm 20, ML-KEM.Encaps].}+ *+ * @param[out] ct Output ciphertext, an array of+ * MLKEM{512,768,1024}_CIPHERTEXTBYTES bytes.+ * @param[out] ss Output shared secret, an array of MLKEM_BYTES bytes.+ * @param[in] pk Input public key, an array of+ * MLKEM{512,768,1024}_PUBLICKEYBYTES bytes.+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_INVALID_PK The 'modulus check' @[FIPS203, Section 7.2]+ * for the public key failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ * @retval MLK_ERR_RNG_FAIL Random number generation failed.+ */+MLK_API_QUALIFIER+MLK_API_MUST_CHECK_RETURN_VALUE+int MLK_API_NAMESPACE(enc)(+ uint8_t ct[MLKEM_CIPHERTEXTBYTES(MLK_CONFIG_PARAMETER_SET)],+ uint8_t ss[MLKEM_BYTES],+ const uint8_t pk[MLKEM_PUBLICKEYBYTES(MLK_CONFIG_PARAMETER_SET)]+#ifdef MLK_CONFIG_CONTEXT_PARAMETER+ ,+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLK_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLK_CONFIG_NO_ENCAPS_API */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/**+ * Generate shared secret for a given ciphertext and private key.+ *+ * @spec{Implements @[FIPS203, Algorithm 21, ML-KEM.Decaps].}+ *+ * @param[out] ss Output shared secret, an array of MLKEM_BYTES bytes.+ * @param[in] ct Input ciphertext, an array of+ * MLKEM{512,768,1024}_CIPHERTEXTBYTES bytes.+ * @param[in] sk Input private key, an array of+ * MLKEM{512,768,1024}_SECRETKEYBYTES bytes.+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_INVALID_SK The 'hash check' @[FIPS203, Section 7.3]+ * for the secret key failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+MLK_API_QUALIFIER+MLK_API_MUST_CHECK_RETURN_VALUE+int MLK_API_NAMESPACE(dec)(+ uint8_t ss[MLKEM_BYTES],+ const uint8_t ct[MLKEM_CIPHERTEXTBYTES(MLK_CONFIG_PARAMETER_SET)],+ const uint8_t sk[MLKEM_SECRETKEYBYTES(MLK_CONFIG_PARAMETER_SET)]+#ifdef MLK_CONFIG_CONTEXT_PARAMETER+ ,+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLK_CONFIG_NO_DECAPS_API */+++/**+ * Implements modulus check mandated by FIPS 203, i.e., ensures that+ * coefficients are in [0,q-1].+ *+ * @spec{Implements @[FIPS203, Section 7.2, 'modulus check'].}+ *+ * @param[in] pk Input public key, an array of+ * MLKEM{512,768,1024}_PUBLICKEYBYTES bytes.+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_INVALID_PK Modulus check failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+#if !defined(MLK_CONFIG_NO_ENCAPS_API)+MLK_API_QUALIFIER+MLK_API_MUST_CHECK_RETURN_VALUE+int MLK_API_NAMESPACE(check_pk)(+ const uint8_t pk[MLKEM_PUBLICKEYBYTES(MLK_CONFIG_PARAMETER_SET)]+#ifdef MLK_CONFIG_CONTEXT_PARAMETER+ ,+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLK_CONFIG_NO_ENCAPS_API */++/**+ * Implements public key hash check mandated by FIPS 203, i.e., ensures that+ * sk[768𝑘+32 ∶ 768𝑘+64] = H(pk) = H(sk[384𝑘 : 768𝑘+32]).+ *+ * @spec{Implements @[FIPS203, Section 7.3, 'hash check'].}+ *+ * @param[in] sk Input private key, an array of+ * MLKEM{512,768,1024}_SECRETKEYBYTES bytes.+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_INVALID_SK Public key hash check failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+#if !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_API_QUALIFIER+MLK_API_MUST_CHECK_RETURN_VALUE+int MLK_API_NAMESPACE(check_sk)(+ const uint8_t sk[MLKEM_SECRETKEYBYTES(MLK_CONFIG_PARAMETER_SET)]+#ifdef MLK_CONFIG_CONTEXT_PARAMETER+ ,+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context+#endif+);+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#ifdef __cplusplus+}+#endif++#undef MLK_API_NAMESPACE_PREFIX++#endif /* !MLK_CONFIG_CONSTANTS_ONLY */+++/***************************** Memory Usage **********************************/++/*+ * By default mlkem-native performs all memory allocations on the stack.+ * Alternatively, mlkem-native supports custom allocation of large structures+ * through the `MLK_CONFIG_CUSTOM_ALLOC_FREE` configuration option.+ * See mlkem_native_config.h for details.+ *+ * `MLK_TOTAL_ALLOC_{512,768,1024}_{KEYPAIR,ENCAPS,DECAPS}` indicates the+ * maximum (accumulative) allocation via MLK_ALLOC for each parameter set and+ * operation. Note that some stack allocation remains even when using custom+ * allocators, so these values are lower than total stack usage with the default+ * stack-only allocation.+ *+ * These constants may be used to implement custom allocations using a+ * fixed-sized buffer and a simple allocator (e.g., bump allocator).+ */+/* check-magic: off */+#define MLK_TOTAL_ALLOC_512_KEYPAIR_NO_PCT 5824+#define MLK_TOTAL_ALLOC_512_KEYPAIR_PCT 10048+#define MLK_TOTAL_ALLOC_512_ENCAPS 8384+#define MLK_TOTAL_ALLOC_512_DECAPS 9152+#define MLK_TOTAL_ALLOC_768_KEYPAIR_NO_PCT 10176+#define MLK_TOTAL_ALLOC_768_KEYPAIR_PCT 15552+#define MLK_TOTAL_ALLOC_768_ENCAPS 13248+#define MLK_TOTAL_ALLOC_768_DECAPS 14336+#define MLK_TOTAL_ALLOC_1024_KEYPAIR_NO_PCT 15552+#define MLK_TOTAL_ALLOC_1024_KEYPAIR_PCT 22400+#define MLK_TOTAL_ALLOC_1024_ENCAPS 19136+#define MLK_TOTAL_ALLOC_1024_DECAPS 20704+/* check-magic: on */++/*+ * MLK_TOTAL_ALLOC_*_KEYPAIR adapts based on MLK_CONFIG_KEYGEN_PCT.+ */+#if defined(MLK_CONFIG_KEYGEN_PCT)+#define MLK_TOTAL_ALLOC_512_KEYPAIR MLK_TOTAL_ALLOC_512_KEYPAIR_PCT+#define MLK_TOTAL_ALLOC_768_KEYPAIR MLK_TOTAL_ALLOC_768_KEYPAIR_PCT+#define MLK_TOTAL_ALLOC_1024_KEYPAIR MLK_TOTAL_ALLOC_1024_KEYPAIR_PCT+#else+#define MLK_TOTAL_ALLOC_512_KEYPAIR MLK_TOTAL_ALLOC_512_KEYPAIR_NO_PCT+#define MLK_TOTAL_ALLOC_768_KEYPAIR MLK_TOTAL_ALLOC_768_KEYPAIR_NO_PCT+#define MLK_TOTAL_ALLOC_1024_KEYPAIR MLK_TOTAL_ALLOC_1024_KEYPAIR_NO_PCT+#endif++#define MLK_MAX3_(a, b, c) \+ ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c)))++/*+ * `MLK_TOTAL_ALLOC_{512,768,1024}` is the maximum across all operations for+ * each parameter set.+ */+#define MLK_TOTAL_ALLOC_512 \+ MLK_MAX3_(MLK_TOTAL_ALLOC_512_KEYPAIR, MLK_TOTAL_ALLOC_512_ENCAPS, \+ MLK_TOTAL_ALLOC_512_DECAPS)+#define MLK_TOTAL_ALLOC_768 \+ MLK_MAX3_(MLK_TOTAL_ALLOC_768_KEYPAIR, MLK_TOTAL_ALLOC_768_ENCAPS, \+ MLK_TOTAL_ALLOC_768_DECAPS)+#define MLK_TOTAL_ALLOC_1024 \+ MLK_MAX3_(MLK_TOTAL_ALLOC_1024_KEYPAIR, MLK_TOTAL_ALLOC_1024_ENCAPS, \+ MLK_TOTAL_ALLOC_1024_DECAPS)++#endif /* !MLK_H */
@@ -0,0 +1,716 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++/******************************************************************************+ *+ * Single assembly unit for fixed-level build of mlkem-native+ *+ * This assembly unit bundles together all assembly files for a build+ * of mlkem-native for a fixed security level (MLKEM-512/768/1024).+ *+ * # Multi-level build+ *+ * If you want an SCU build of mlkem-native with support for multiple security+ * levels, you should include this file once with+ * MLK_CONFIG_MULTILEVEL_WITH_SHARED set.+ *+ * (You could also follow the same pattern as for mlkem_native.c+ * and include it for every level, setting MLK_CONFIG_MULTILEVEL_NO_SHARED+ * for all but one. For builds with MLK_CONFIG_MULTILEVEL_NO_SHARED, this+ * file will then be ignored.)+ *+ * # Configuration+ *+ * The following options from the mlkem-native configuration are relevant:+ *+ * - MLK_CONFIG_FIPS202_CUSTOM_HEADER+ * Set this option if you use a custom FIPS202 implementation.+ *+ * - MLK_CONFIG_USE_NATIVE_BACKEND_ARITH+ * Set this option if you want to include the native arithmetic backends+ * in your build.+ *+ * - MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202+ * Set this option if you want to include the native FIPS202 backends+ * in your build.+ *+ * - MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+ * Set this option if you want to keep the directives defined in+ * level-independent headers. This is needed for a multi-level build.+ */++/* If parts of the mlkem-native source tree are not used,+ * consider reducing this header via `unifdef`.+ *+ * Example:+ * ```bash+ * unifdef -UMLK_CONFIG_USE_NATIVE_BACKEND_ARITH mlkem_native_asm.S+ * ```+ */++#include "src/common.h"++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_ARITH)+#if defined(MLK_SYS_AARCH64)+#include "src/native/aarch64/src/mlkem_intt_aarch64_asm.S"+#include "src/native/aarch64/src/mlkem_ntt_aarch64_asm.S"+#include "src/native/aarch64/src/mlkem_poly_mulcache_compute_aarch64_asm.S"+#include "src/native/aarch64/src/mlkem_poly_reduce_aarch64_asm.S"+#include "src/native/aarch64/src/mlkem_poly_tobytes_aarch64_asm.S"+#include "src/native/aarch64/src/mlkem_poly_tomont_aarch64_asm.S"+#include "src/native/aarch64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm.S"+#include "src/native/aarch64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm.S"+#include "src/native/aarch64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm.S"+#include "src/native/aarch64/src/mlkem_rej_uniform_aarch64_asm.S"+#endif /* MLK_SYS_AARCH64 */+#if defined(MLK_SYS_X86_64)+#include "src/native/x86_64/src/mlkem_intt_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_ntt_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_nttfrombytes_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_ntttobytes_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_nttunpack_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_poly_compress_d10_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_poly_compress_d11_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_poly_compress_d4_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_poly_compress_d5_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_poly_decompress_d10_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_poly_decompress_d11_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_poly_decompress_d4_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_poly_decompress_d5_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_poly_mulcache_compute_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_reduce_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_rej_uniform_avx2_asm.S"+#include "src/native/x86_64/src/mlkem_tomont_avx2_asm.S"+#endif /* MLK_SYS_X86_64 */+#if defined(MLK_SYS_RISCV64)+#endif+#if defined(MLK_SYS_PPC64LE)+#include "src/native/ppc64le/src/mlkem_intt_ppc_asm.S"+#include "src/native/ppc64le/src/mlkem_ntt_ppc_asm.S"+#include "src/native/ppc64le/src/mlkem_poly_tomont_ppc_asm.S"+#include "src/native/ppc64le/src/mlkem_reduce_ppc_asm.S"+#endif /* MLK_SYS_PPC64LE */+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202)+#if defined(MLK_SYS_AARCH64)+#include "src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_aarch64_asm.S"+#include "src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_aarch64_asm.S"+#include "src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_aarch64_asm.S"+#include "src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.S"+#include "src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.S"+#endif /* MLK_SYS_AARCH64 */+#if defined(MLK_SYS_X86_64)+#include "src/fips202/native/x86_64/src/keccak_f1600_x4_avx2_asm.S"+#endif+#if defined(MLK_SYS_ARMV81M_MVE)+#include "src/fips202/native/armv81m/src/keccak_f1600_x4_mve.S"+#include "src/fips202/native/armv81m/src/keccak_f1600_x4_state_extract_bytes_mve.S"+#include "src/fips202/native/armv81m/src/keccak_f1600_x4_state_xor_bytes_mve.S"+#endif+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 */+++/* Macro #undef's+ *+ * The following undefines macros from headers+ * included by the source files imported above.+ *+ * This is to allow building and linking multiple builds+ * of mlkem-native for varying parameter sets through concatenation+ * of this file, as if the files had been compiled separately.+ * If this is not relevant to you, you may remove the following.+ *+ * NOTE: This is not needed for the assembly SCU since, at present,+ * there is no need to include it multiple times.+ * We keep it for uniformity with mlkem_native.c only.+ *+ * NOTE: To avoid having to distinguish between which headers are included+ * from the assembly files, we #undef the same set of directives+ * as in mlkem_native.c+ */++/*+ * Undefine macros from MLK_CONFIG_PARAMETER_SET-specific files+ */+/* mlkem/mlkem_native.h */+#undef MLKEM1024_BYTES+#undef MLKEM1024_CIPHERTEXTBYTES+#undef MLKEM1024_PUBLICKEYBYTES+#undef MLKEM1024_SECRETKEYBYTES+#undef MLKEM1024_SYMBYTES+#undef MLKEM512_BYTES+#undef MLKEM512_CIPHERTEXTBYTES+#undef MLKEM512_PUBLICKEYBYTES+#undef MLKEM512_SECRETKEYBYTES+#undef MLKEM512_SYMBYTES+#undef MLKEM768_BYTES+#undef MLKEM768_CIPHERTEXTBYTES+#undef MLKEM768_PUBLICKEYBYTES+#undef MLKEM768_SECRETKEYBYTES+#undef MLKEM768_SYMBYTES+#undef MLKEM_BYTES+#undef MLKEM_CIPHERTEXTBYTES+#undef MLKEM_CIPHERTEXTBYTES_+#undef MLKEM_PUBLICKEYBYTES+#undef MLKEM_PUBLICKEYBYTES_+#undef MLKEM_SECRETKEYBYTES+#undef MLKEM_SECRETKEYBYTES_+#undef MLKEM_SYMBYTES+#undef MLK_API_CONCAT+#undef MLK_API_CONCAT_+#undef MLK_API_CONCAT_UNDERSCORE+#undef MLK_API_MUST_CHECK_RETURN_VALUE+#undef MLK_API_NAMESPACE+#undef MLK_API_NAMESPACE_PREFIX+#undef MLK_API_QUALIFIER+#undef MLK_ERR_FAIL+#undef MLK_ERR_INVALID_PK+#undef MLK_ERR_INVALID_SK+#undef MLK_ERR_OUT_OF_MEMORY+#undef MLK_ERR_PCT_FAIL+#undef MLK_ERR_RNG_FAIL+#undef MLK_H+#undef MLK_MAX3_+#undef MLK_TOTAL_ALLOC_1024+#undef MLK_TOTAL_ALLOC_1024_DECAPS+#undef MLK_TOTAL_ALLOC_1024_ENCAPS+#undef MLK_TOTAL_ALLOC_1024_KEYPAIR+#undef MLK_TOTAL_ALLOC_1024_KEYPAIR_NO_PCT+#undef MLK_TOTAL_ALLOC_1024_KEYPAIR_PCT+#undef MLK_TOTAL_ALLOC_512+#undef MLK_TOTAL_ALLOC_512_DECAPS+#undef MLK_TOTAL_ALLOC_512_ENCAPS+#undef MLK_TOTAL_ALLOC_512_KEYPAIR+#undef MLK_TOTAL_ALLOC_512_KEYPAIR_NO_PCT+#undef MLK_TOTAL_ALLOC_512_KEYPAIR_PCT+#undef MLK_TOTAL_ALLOC_768+#undef MLK_TOTAL_ALLOC_768_DECAPS+#undef MLK_TOTAL_ALLOC_768_ENCAPS+#undef MLK_TOTAL_ALLOC_768_KEYPAIR+#undef MLK_TOTAL_ALLOC_768_KEYPAIR_NO_PCT+#undef MLK_TOTAL_ALLOC_768_KEYPAIR_PCT+/* mlkem/src/common.h */+#undef MLK_ADD_PARAM_SET+#undef MLK_ALLOC+#undef MLK_APPLY+#undef MLK_ASM_FN_SIZE+#undef MLK_ASM_FN_SYMBOL+#undef MLK_ASM_NAMESPACE+#undef MLK_BUILD_INTERNAL+#undef MLK_COMMON_H+#undef MLK_CONCAT+#undef MLK_CONCAT_+#undef MLK_EMPTY_CU+#undef MLK_ERR_FAIL+#undef MLK_ERR_INVALID_PK+#undef MLK_ERR_INVALID_SK+#undef MLK_ERR_OUT_OF_MEMORY+#undef MLK_ERR_PCT_FAIL+#undef MLK_ERR_RNG_FAIL+#undef MLK_EXTERNAL_API+#undef MLK_FIPS202X4_HEADER_FILE+#undef MLK_FIPS202_HEADER_FILE+#undef MLK_FREE+#undef MLK_INTERNAL_API+#undef MLK_INTERNAL_DATA_DECLARATION+#undef MLK_INTERNAL_DATA_DEFINITION+#undef MLK_NAMESPACE+#undef MLK_NAMESPACE_K+#undef MLK_NAMESPACE_PREFIX+#undef MLK_NAMESPACE_PREFIX_K+#undef mlk_memcpy+#undef mlk_memset+/* mlkem/src/indcpa.h */+#undef MLK_INDCPA_H+#undef mlk_gen_matrix+#undef mlk_indcpa_dec+#undef mlk_indcpa_enc+#undef mlk_indcpa_keypair_derand+/* mlkem/src/kem.h */+#undef MLK_KEM_H+#undef mlk_kem_check_pk+#undef mlk_kem_check_sk+#undef mlk_kem_dec+#undef mlk_kem_enc+#undef mlk_kem_enc_derand+#undef mlk_kem_keypair+#undef mlk_kem_keypair_derand+/* mlkem/src/params.h */+#undef MLKEM_DU+#undef MLKEM_DV+#undef MLKEM_ETA1+#undef MLKEM_ETA2+#undef MLKEM_INDCCA_CIPHERTEXTBYTES+#undef MLKEM_INDCCA_PUBLICKEYBYTES+#undef MLKEM_INDCCA_SECRETKEYBYTES+#undef MLKEM_INDCPA_BYTES+#undef MLKEM_INDCPA_MSGBYTES+#undef MLKEM_INDCPA_PUBLICKEYBYTES+#undef MLKEM_INDCPA_SECRETKEYBYTES+#undef MLKEM_K+#undef MLKEM_N+#undef MLKEM_POLYBYTES+#undef MLKEM_POLYCOMPRESSEDBYTES_D10+#undef MLKEM_POLYCOMPRESSEDBYTES_D11+#undef MLKEM_POLYCOMPRESSEDBYTES_D4+#undef MLKEM_POLYCOMPRESSEDBYTES_D5+#undef MLKEM_POLYCOMPRESSEDBYTES_DU+#undef MLKEM_POLYCOMPRESSEDBYTES_DV+#undef MLKEM_POLYVECBYTES+#undef MLKEM_POLYVECCOMPRESSEDBYTES_DU+#undef MLKEM_Q+#undef MLKEM_Q_HALF+#undef MLKEM_SSBYTES+#undef MLKEM_SYMBYTES+#undef MLKEM_UINT12_LIMIT+#undef MLK_PARAMS_H+/* mlkem/src/poly_k.h */+#undef MLK_POLY_K_H+#undef mlk_poly_compress_du+#undef mlk_poly_compress_dv+#undef mlk_poly_decompress_du+#undef mlk_poly_decompress_dv+#undef mlk_poly_getnoise_eta1122_4x+#undef mlk_poly_getnoise_eta1_4x+#undef mlk_poly_getnoise_eta2+#undef mlk_poly_getnoise_eta2_4x+#undef mlk_polymat+#undef mlk_polyvec+#undef mlk_polyvec_add+#undef mlk_polyvec_basemul_acc_montgomery_cached+#undef mlk_polyvec_compress_du+#undef mlk_polyvec_decompress_du+#undef mlk_polyvec_frombytes+#undef mlk_polyvec_invntt_tomont+#undef mlk_polyvec_mulcache+#undef mlk_polyvec_mulcache_compute+#undef mlk_polyvec_ntt+#undef mlk_polyvec_reduce+#undef mlk_polyvec_tobytes+#undef mlk_polyvec_tomont++#if !defined(MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS)+/*+ * Undefine macros from MLK_CONFIG_PARAMETER_SET-generic files+ */+/* mlkem/src/compress.h */+#undef MLK_COMPRESS_H+#undef mlk_poly_compress_d10+#undef mlk_poly_compress_d11+#undef mlk_poly_compress_d4+#undef mlk_poly_compress_d5+#undef mlk_poly_decompress_d10+#undef mlk_poly_decompress_d11+#undef mlk_poly_decompress_d4+#undef mlk_poly_decompress_d5+#undef mlk_poly_frombytes+#undef mlk_poly_frommsg+#undef mlk_poly_tobytes+#undef mlk_poly_tomsg+/* mlkem/src/context.h */+#undef MLK_CONTEXT_H+#undef MLK_CONTEXT_PARAMETERS_0+#undef MLK_CONTEXT_PARAMETERS_1+#undef MLK_CONTEXT_PARAMETERS_2+#undef MLK_CONTEXT_PARAMETERS_3+#undef MLK_CONTEXT_PARAMETERS_4+#undef MLK_CONTEXT_UNUSED+/* mlkem/src/debug.h */+#undef MLK_DEBUG_H+#undef mlk_assert+#undef mlk_assert_abs_bound+#undef mlk_assert_abs_bound_2d+#undef mlk_assert_bound+#undef mlk_assert_bound_2d+#undef mlk_debug_check_assert+#undef mlk_debug_check_bounds+/* mlkem/src/poly.h */+#undef MLK_INVNTT_BOUND+#undef MLK_NTT_BOUND+#undef MLK_POLY_H+#undef mlk_poly_add+#undef mlk_poly_invntt_tomont+#undef mlk_poly_mulcache_compute+#undef mlk_poly_ntt+#undef mlk_poly_reduce+#undef mlk_poly_sub+#undef mlk_poly_tomont+/* mlkem/src/randombytes.h */+#undef MLK_RANDOMBYTES_H+/* mlkem/src/sampling.h */+#undef MLK_SAMPLING_H+#undef mlk_poly_cbd2+#undef mlk_poly_cbd3+#undef mlk_poly_rej_uniform+#undef mlk_poly_rej_uniform_x4+/* mlkem/src/symmetric.h */+#undef MLK_SYMMETRIC_H+#undef MLK_XOF_RATE+#undef mlk_hash_g+#undef mlk_hash_h+#undef mlk_hash_j+#undef mlk_prf_eta+#undef mlk_prf_eta1+#undef mlk_prf_eta1_x4+#undef mlk_prf_eta2+#undef mlk_xof_absorb+#undef mlk_xof_ctx+#undef mlk_xof_init+#undef mlk_xof_release+#undef mlk_xof_squeezeblocks+#undef mlk_xof_x4_absorb+#undef mlk_xof_x4_ctx+#undef mlk_xof_x4_init+#undef mlk_xof_x4_release+#undef mlk_xof_x4_squeezeblocks+/* mlkem/src/sys.h */+#undef MLK_ALIGN+#undef MLK_ALIGN_UP+#undef MLK_ALWAYS_INLINE+#undef MLK_CET_ENDBR+#undef MLK_CT_TESTING_DECLASSIFY+#undef MLK_CT_TESTING_SECRET+#undef MLK_DEFAULT_ALIGN+#undef MLK_HAVE_INLINE_ASM+#undef MLK_INLINE+#undef MLK_MUST_CHECK_RETURN_VALUE+#undef MLK_NOINLINE+#undef MLK_RESTRICT+#undef MLK_STATIC_TESTABLE+#undef MLK_SYSV_ABI+#undef MLK_SYSV_ABI_SUPPORTED+#undef MLK_SYS_AARCH64+#undef MLK_SYS_AARCH64_EB+#undef MLK_SYS_AARCH64_NEON+#undef MLK_SYS_APPLE+#undef MLK_SYS_ARMV81M_MVE+#undef MLK_SYS_BIG_ENDIAN+#undef MLK_SYS_H+#undef MLK_SYS_LINUX+#undef MLK_SYS_LITTLE_ENDIAN+#undef MLK_SYS_PPC64LE+#undef MLK_SYS_RISCV32+#undef MLK_SYS_RISCV64+#undef MLK_SYS_RISCV64_RVV+#undef MLK_SYS_WINDOWS+#undef MLK_SYS_X86_64+#undef MLK_SYS_X86_64_AVX2+/* mlkem/src/verify.h */+#undef MLK_USE_ASM_VALUE_BARRIER+#undef MLK_VERIFY_H+#undef mlk_ct_opt_blocker_u64+/* mlkem/src/cbmc.h */+#undef MLK_CBMC_H+#undef __contract__+#undef __loop__++#if !defined(MLK_CONFIG_FIPS202_CUSTOM_HEADER)+/*+ * Undefine macros from FIPS-202 files+ */+/* mlkem/src/fips202/fips202.h */+#undef FIPS202_X4_DEFAULT_IMPLEMENTATION+#undef MLK_FIPS202_FIPS202_H+#undef SHA3_256_HASHBYTES+#undef SHA3_256_RATE+#undef SHA3_384_RATE+#undef SHA3_512_HASHBYTES+#undef SHA3_512_RATE+#undef SHAKE128_RATE+#undef SHAKE256_RATE+#undef mlk_sha3_256+#undef mlk_sha3_512+#undef mlk_shake128_absorb_once+#undef mlk_shake128_init+#undef mlk_shake128_release+#undef mlk_shake128_squeezeblocks+#undef mlk_shake256+/* mlkem/src/fips202/fips202x4.h */+#undef MLK_FIPS202_FIPS202X4_H+#undef mlk_shake128x4_absorb_once+#undef mlk_shake128x4_init+#undef mlk_shake128x4_release+#undef mlk_shake128x4_squeezeblocks+#undef mlk_shake256x4+/* mlkem/src/fips202/keccakf1600.h */+#undef MLK_FIPS202_KECCAKF1600_H+#undef MLK_KECCAK_LANES+#undef MLK_KECCAK_WAY+#undef mlk_keccakf1600_extract_bytes+#undef mlk_keccakf1600_permute+#undef mlk_keccakf1600_xor_bytes+#undef mlk_keccakf1600x4_extract_bytes+#undef mlk_keccakf1600x4_permute+#undef mlk_keccakf1600x4_xor_bytes+#endif /* !MLK_CONFIG_FIPS202_CUSTOM_HEADER */++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202)+/* mlkem/src/fips202/native/api.h */+#undef MLK_FIPS202_NATIVE_API_H+#undef MLK_NATIVE_FUNC_FALLBACK+#undef MLK_NATIVE_FUNC_SUCCESS+/* mlkem/src/fips202/native/auto.h */+#undef MLK_FIPS202_NATIVE_AUTO_H+#if defined(MLK_SYS_AARCH64)+/*+ * Undefine macros from native code (FIPS202, AArch64)+ */+/* mlkem/src/fips202/native/aarch64/auto.h */+#undef MLK_FIPS202_NATIVE_AARCH64_AUTO_H+/* mlkem/src/fips202/native/aarch64/src/fips202_native_aarch64.h */+#undef MLK_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H+#undef mlk_keccak_f1600_x1_scalar_aarch64_asm+#undef mlk_keccak_f1600_x1_v84a_aarch64_asm+#undef mlk_keccak_f1600_x2_v84a_aarch64_asm+#undef mlk_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm+#undef mlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm+#undef mlk_keccakf1600_round_constants+/* mlkem/src/fips202/native/aarch64/x1_scalar.h */+#undef MLK_FIPS202_AARCH64_NEED_X1_SCALAR+#undef MLK_FIPS202_NATIVE_AARCH64_X1_SCALAR_H+#undef MLK_USE_NATIVE_FIPS202_X1+/* mlkem/src/fips202/native/aarch64/x1_v84a.h */+#undef MLK_FIPS202_AARCH64_NEED_X1_V84A+#undef MLK_FIPS202_NATIVE_AARCH64_X1_V84A_H+#undef MLK_USE_NATIVE_FIPS202_X1+/* mlkem/src/fips202/native/aarch64/x2_v84a.h */+#undef MLK_FIPS202_AARCH64_NEED_X2_V84A+#undef MLK_FIPS202_NATIVE_AARCH64_X2_V84A_H+#undef MLK_USE_NATIVE_FIPS202_X4+/* mlkem/src/fips202/native/aarch64/x4_v8a_scalar.h */+#undef MLK_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID+#undef MLK_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H+#undef MLK_USE_NATIVE_FIPS202_X4+/* mlkem/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h */+#undef MLK_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID+#undef MLK_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H+#undef MLK_USE_NATIVE_FIPS202_X4+#endif /* MLK_SYS_AARCH64 */+#if defined(MLK_SYS_X86_64)+/*+ * Undefine macros from native code (FIPS202, x86_64)+ */+/* mlkem/src/fips202/native/x86_64/keccak_f1600_x4_avx2.h */+#undef MLK_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H+#undef MLK_FIPS202_X86_64_NEED_X4_AVX2+#undef MLK_USE_NATIVE_FIPS202_X4+/* mlkem/src/fips202/native/x86_64/src/fips202_native_x86_64.h */+#undef MLK_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H+#undef mlk_keccak_f1600_x4_avx2_asm+#undef mlk_keccak_rho56+#undef mlk_keccak_rho8+#undef mlk_keccakf1600_round_constants+#endif /* MLK_SYS_X86_64 */+#if defined(MLK_SYS_ARMV81M_MVE)+/*+ * Undefine macros from native code (FIPS202, Armv8.1-M)+ */+/* mlkem/src/fips202/native/armv81m/mve.h */+#undef MLK_FIPS202_ARMV81M_NEED_X4+#undef MLK_FIPS202_NATIVE_ARMV81M+#undef MLK_FIPS202_NATIVE_ARMV81M_MVE_H+#undef MLK_USE_NATIVE_FIPS202_X4+#undef MLK_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES+#undef MLK_USE_NATIVE_FIPS202_X4_XOR_BYTES+#undef mlk_keccak_f1600_x4_native_impl+/* mlkem/src/fips202/native/armv81m/src/fips202_native_armv81m.h */+#undef MLK_FIPS202_NATIVE_ARMV81M_SRC_FIPS202_NATIVE_ARMV81M_H+#undef mlk_keccak_f1600_x4_mve_asm+#undef mlk_keccak_f1600_x4_state_extract_bytes_asm+#undef mlk_keccak_f1600_x4_state_xor_bytes_asm+#undef mlk_keccakf1600_round_constants+#endif /* MLK_SYS_ARMV81M_MVE */+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 */+#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_ARITH)+/* mlkem/src/native/api.h */+#undef MLK_INVNTT_BOUND+#undef MLK_NATIVE_API_H+#undef MLK_NATIVE_FUNC_FALLBACK+#undef MLK_NATIVE_FUNC_SUCCESS+#undef MLK_NTT_BOUND+/* mlkem/src/native/meta.h */+#undef MLK_NATIVE_META_H+#if defined(MLK_SYS_AARCH64)+/*+ * Undefine macros from native code (Arith, AArch64)+ */+/* mlkem/src/native/aarch64/meta.h */+#undef MLK_ARITH_BACKEND_AARCH64+#undef MLK_NATIVE_AARCH64_META_H+#undef MLK_USE_NATIVE_INTT+#undef MLK_USE_NATIVE_NTT+#undef MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED+#undef MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE+#undef MLK_USE_NATIVE_POLY_REDUCE+#undef MLK_USE_NATIVE_POLY_TOBYTES+#undef MLK_USE_NATIVE_POLY_TOMONT+#undef MLK_USE_NATIVE_REJ_UNIFORM+/* mlkem/src/native/aarch64/src/arith_native_aarch64.h */+#undef MLK_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H+#undef mlk_aarch64_invntt_zetas_layer12345+#undef mlk_aarch64_invntt_zetas_layer67+#undef mlk_aarch64_ntt_zetas_layer12345+#undef mlk_aarch64_ntt_zetas_layer67+#undef mlk_aarch64_zetas_mulcache_native+#undef mlk_aarch64_zetas_mulcache_twisted_native+#undef mlk_intt_aarch64_asm+#undef mlk_ntt_aarch64_asm+#undef mlk_poly_mulcache_compute_aarch64_asm+#undef mlk_poly_reduce_aarch64_asm+#undef mlk_poly_tobytes_aarch64_asm+#undef mlk_poly_tomont_aarch64_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm+#undef mlk_rej_uniform_aarch64_asm+#undef mlk_rej_uniform_table+#endif /* MLK_SYS_AARCH64 */+#if defined(MLK_SYS_X86_64)+/*+ * Undefine macros from native code (Arith, X86_64)+ */+/* mlkem/src/native/x86_64/meta.h */+#undef MLK_ARITH_BACKEND_X86_64_DEFAULT+#undef MLK_NATIVE_X86_64_META_H+#undef MLK_USE_NATIVE_INTT+#undef MLK_USE_NATIVE_NTT+#undef MLK_USE_NATIVE_NTT_CUSTOM_ORDER+#undef MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED+#undef MLK_USE_NATIVE_POLY_COMPRESS_D10+#undef MLK_USE_NATIVE_POLY_COMPRESS_D11+#undef MLK_USE_NATIVE_POLY_COMPRESS_D4+#undef MLK_USE_NATIVE_POLY_COMPRESS_D5+#undef MLK_USE_NATIVE_POLY_DECOMPRESS_D10+#undef MLK_USE_NATIVE_POLY_DECOMPRESS_D11+#undef MLK_USE_NATIVE_POLY_DECOMPRESS_D4+#undef MLK_USE_NATIVE_POLY_DECOMPRESS_D5+#undef MLK_USE_NATIVE_POLY_FROMBYTES+#undef MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE+#undef MLK_USE_NATIVE_POLY_REDUCE+#undef MLK_USE_NATIVE_POLY_TOBYTES+#undef MLK_USE_NATIVE_POLY_TOMONT+#undef MLK_USE_NATIVE_REJ_UNIFORM+/* mlkem/src/native/x86_64/src/arith_native_x86_64.h */+#undef MLK_AVX2_REJ_UNIFORM_BUFLEN+#undef MLK_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H+#undef mlk_invntt_avx2_asm+#undef mlk_ntt_avx2_asm+#undef mlk_nttfrombytes_avx2_asm+#undef mlk_ntttobytes_avx2_asm+#undef mlk_nttunpack_avx2_asm+#undef mlk_poly_compress_d10_avx2_asm+#undef mlk_poly_compress_d11_avx2_asm+#undef mlk_poly_compress_d4_avx2_asm+#undef mlk_poly_compress_d5_avx2_asm+#undef mlk_poly_decompress_d10_avx2_asm+#undef mlk_poly_decompress_d11_avx2_asm+#undef mlk_poly_decompress_d4_avx2_asm+#undef mlk_poly_decompress_d5_avx2_asm+#undef mlk_poly_mulcache_compute_avx2_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm+#undef mlk_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm+#undef mlk_reduce_avx2_asm+#undef mlk_rej_uniform_avx2_asm+#undef mlk_rej_uniform_table+#undef mlk_tomont_avx2_asm+/* mlkem/src/native/x86_64/src/compress_consts.h */+#undef MLK_NATIVE_X86_64_SRC_COMPRESS_CONSTS_H+#undef mlk_compress_d10_data+#undef mlk_compress_d11_data+#undef mlk_compress_d4_data+#undef mlk_compress_d5_data+#undef mlk_decompress_d10_data+#undef mlk_decompress_d11_data+#undef mlk_decompress_d4_data+#undef mlk_decompress_d5_data+/* mlkem/src/native/x86_64/src/consts.h */+#undef MLK_AVX2_BACKEND_DATA_OFFSET_MULCACHE_TWIDDLES+#undef MLK_AVX2_BACKEND_DATA_OFFSET_REVIDXB+#undef MLK_AVX2_BACKEND_DATA_OFFSET_REVIDXD+#undef MLK_AVX2_BACKEND_DATA_OFFSET_ZETAS_EXP+#undef MLK_NATIVE_X86_64_SRC_CONSTS_H+#undef mlk_qdata+#endif /* MLK_SYS_X86_64 */+#if defined(MLK_SYS_RISCV64)+/*+ * Undefine macros from native code (Arith, RISC-V 64)+ */+/* mlkem/src/native/riscv64/meta.h */+#undef MLK_ARITH_BACKEND_RISCV64+#undef MLK_NATIVE_RISCV64_META_H+#undef MLK_USE_NATIVE_INTT+#undef MLK_USE_NATIVE_NTT+#undef MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED+#undef MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE+#undef MLK_USE_NATIVE_POLY_REDUCE+#undef MLK_USE_NATIVE_POLY_TOMONT+#undef MLK_USE_NATIVE_REJ_UNIFORM+/* mlkem/src/native/riscv64/src/arith_native_riscv64.h */+#undef MLK_NATIVE_RISCV64_SRC_ARITH_NATIVE_RISCV64_H+#undef mlk_rv64v_poly_add+#undef mlk_rv64v_poly_basemul_mont_add_k2+#undef mlk_rv64v_poly_basemul_mont_add_k3+#undef mlk_rv64v_poly_basemul_mont_add_k4+#undef mlk_rv64v_poly_invntt_tomont+#undef mlk_rv64v_poly_ntt+#undef mlk_rv64v_poly_reduce+#undef mlk_rv64v_poly_sub+#undef mlk_rv64v_poly_tomont+#undef mlk_rv64v_rej_uniform+/* mlkem/src/native/riscv64/src/rv64v_debug.h */+#undef MLK_NATIVE_RISCV64_SRC_RV64V_DEBUG_H+#undef mlk_assert_abs_bound_int16m1+#undef mlk_assert_abs_bound_int16m2+#undef mlk_assert_bound_int16m1+#undef mlk_assert_bound_int16m2+#undef mlk_debug_check_bounds_int16m1+#undef mlk_debug_check_bounds_int16m2+#endif /* MLK_SYS_RISCV64 */+#if defined(MLK_SYS_PPC64LE)+/*+ * Undefine macros from native code (Arith, PPC64LE)+ */+/* mlkem/src/native/ppc64le/meta.h */+#undef MLK_ARITH_BACKEND_NAME+#undef MLK_ARITH_BACKEND_PPC64LE_DEFAULT+#undef MLK_NATIVE_PPC64LE_META_H+#undef MLK_USE_NATIVE_INTT+#undef MLK_USE_NATIVE_NTT+#undef MLK_USE_NATIVE_POLY_REDUCE+#undef MLK_USE_NATIVE_POLY_TOMONT+/* mlkem/src/native/ppc64le/src/arith_native_ppc64le.h */+#undef MLK_NATIVE_PPC64LE_SRC_ARITH_NATIVE_PPC64LE_H+#undef mlk_intt_ppc_asm+#undef mlk_ntt_ppc_asm+#undef mlk_poly_tomont_ppc_asm+#undef mlk_reduce_ppc_asm+/* mlkem/src/native/ppc64le/src/consts.h */+#undef MLK_NATIVE_PPC64LE_SRC_CONSTS_H+#undef MLK_PPC_C20159_OFFSET+#undef MLK_PPC_NQ_OFFSET+#undef MLK_PPC_N_INV_OFFSET+#undef MLK_PPC_N_INV_TW_OFFSET+#undef MLK_PPC_Q_OFFSET+#undef MLK_PPC_TOMONT_OFFSET+#undef MLK_PPC_TOMONT_TW_OFFSET+#undef MLK_PPC_ZETA_INTT_OFFSET+#undef MLK_PPC_ZETA_INTT_TW_OFFSET+#undef MLK_PPC_ZETA_NTT_OFFSET+#undef MLK_PPC_ZETA_NTT_TW_OFFSET+#undef mlk_ppc_qdata+#endif /* MLK_SYS_PPC64LE */+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */+#endif /* !MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */
@@ -0,0 +1,683 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS140_3_IG]+ * Implementation Guidance for FIPS 140-3 and the Cryptographic Module+ * Validation Program+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#ifndef MLK_CONFIG_H+#define MLK_CONFIG_H++/**+ * Specifies the parameter set for ML-KEM:+ * - MLK_CONFIG_PARAMETER_SET=512 corresponds to ML-KEM-512+ * - MLK_CONFIG_PARAMETER_SET=768 corresponds to ML-KEM-768+ * - MLK_CONFIG_PARAMETER_SET=1024 corresponds to ML-KEM-1024+ *+ * If you want to support multiple parameter sets, build the library multiple+ * times and set MLK_CONFIG_MULTILEVEL_BUILD. See MLK_CONFIG_MULTILEVEL_BUILD+ * for how to do this while minimizing code duplication.+ *+ * This can also be set using CFLAGS.+ */+#ifndef MLK_CONFIG_PARAMETER_SET+#define MLK_CONFIG_PARAMETER_SET \+ 768 /* Change this for different security strengths */+#endif++/**+ * MLK_CONFIG_FILE+ *+ * If defined, this is a header that will be included instead of the default+ * configuration file mlkem/mlkem_native_config.h.+ *+ * When you need to build mlkem-native in multiple configurations, using+ * varying MLK_CONFIG_FILE can be more convenient than configuring everything+ * through CFLAGS.+ *+ * To use, MLK_CONFIG_FILE _must_ be defined prior to the inclusion of any+ * mlkem-native headers. For example, it can be set by passing+ * `-DMLK_CONFIG_FILE="..."` on the command line.+ */+/* #define MLK_CONFIG_FILE "mlkem_native_config.h" */++/**+ * The prefix to use to namespace global symbols from mlkem/.+ *+ * In a multi-level build, level-dependent symbols will additionally be+ * prefixed with the parameter set (512/768/1024).+ *+ * This can also be set using CFLAGS.+ */+#if !defined(MLK_CONFIG_NAMESPACE_PREFIX)+#define MLK_CONFIG_NAMESPACE_PREFIX MLK_DEFAULT_NAMESPACE_PREFIX+#endif++/**+ * MLK_CONFIG_MULTILEVEL_BUILD+ *+ * Set this if the build is part of a multi-level build supporting multiple+ * parameter sets.+ *+ * If you need only a single parameter set, keep this unset.+ *+ * To build mlkem-native with support for all parameter sets, build it three+ * times -- once per parameter set -- and set the option+ * MLK_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of them, and+ * MLK_CONFIG_MULTILEVEL_NO_SHARED for the others.+ * MLK_CONFIG_MULTILEVEL_BUILD should be set for all of them.+ *+ * See examples/multilevel_build for an example.+ *+ * This can also be set using CFLAGS.+ */+/* #define MLK_CONFIG_MULTILEVEL_BUILD */++/**+ * MLK_CONFIG_EXTERNAL_API_QUALIFIER+ *+ * If set, this option provides an additional function qualifier to be added+ * to declarations of mlkem-native's public API.+ *+ * The primary use case for this option are single-CU builds where the public+ * API exposed by mlkem-native is wrapped by another API in the consuming+ * application. In this case, even mlkem-native's public API can be marked+ * `static`.+ */+/* #define MLK_CONFIG_EXTERNAL_API_QUALIFIER */++/**+ * MLK_CONFIG_NO_KEYPAIR_API+ *+ * By default, mlkem-native includes support for generating key pairs.+ * If you don't need this, set MLK_CONFIG_NO_KEYPAIR_API to exclude+ * keypair and keypair_derand, and all internal+ * APIs only needed by those functions.+ */+/* #define MLK_CONFIG_NO_KEYPAIR_API */++/**+ * MLK_CONFIG_NO_ENCAPS_API+ *+ * By default, mlkem-native includes support for encapsulation. If you+ * don't need this, set MLK_CONFIG_NO_ENCAPS_API to exclude+ * enc, enc_derand, check_pk, and+ * all internal APIs only needed by those functions.+ *+ * @note Setting this option is incompatible with MLK_CONFIG_KEYGEN_PCT+ * as the current PCT implementation requires enc().+ */+/* #define MLK_CONFIG_NO_ENCAPS_API */++/**+ * MLK_CONFIG_NO_DECAPS_API+ *+ * By default, mlkem-native includes support for decapsulation. If you+ * don't need this, set MLK_CONFIG_NO_DECAPS_API to exclude+ * dec, check_sk, and all internal APIs only+ * needed by those functions.+ *+ * @note Setting this option is incompatible with MLK_CONFIG_KEYGEN_PCT+ * as the current PCT implementation requires dec().+ */+/* #define MLK_CONFIG_NO_DECAPS_API */++/**+ * MLK_CONFIG_NO_RANDOMIZED_API+ *+ * If this option is set, mlkem-native will be built without the randomized+ * API functions (keypair and enc). This allows users+ * to build mlkem-native without providing a randombytes() implementation+ * if they only need the deterministic API (keypair_derand,+ * enc_derand, dec).+ *+ * @note This option is incompatible with MLK_CONFIG_KEYGEN_PCT as the+ * current PCT implementation requires enc().+ */+/* #define MLK_CONFIG_NO_RANDOMIZED_API */++/**+ * MLK_CONFIG_CONSTANTS_ONLY+ *+ * If you only need the size constants (MLKEM_PUBLICKEYBYTES, etc.) but no+ * function declarations, set MLK_CONFIG_CONSTANTS_ONLY.+ *+ * This only affects the public header mlkem_native.h, not the+ * implementation.+ */+/* #define MLK_CONFIG_CONSTANTS_ONLY */++/******************************************************************************+ *+ * Build-only configuration options+ *+ * The remaining configurations are build-options only.+ * They do not affect the API described in mlkem_native.h.+ *+ *****************************************************************************/++#if defined(MLK_BUILD_INTERNAL)+/**+ * MLK_CONFIG_MULTILEVEL_WITH_SHARED+ *+ * This is for multi-level builds of mlkem-native only. If you need only a+ * single parameter set, keep this unset.+ *+ * If this is set, all MLK_CONFIG_PARAMETER_SET-independent code will be+ * included in the build, including code needed only for other parameter+ * sets.+ *+ * Example: mlk_poly_cbd3 is only needed for MLK_CONFIG_PARAMETER_SET == 512.+ * Yet, if this option is set for a build with+ * MLK_CONFIG_PARAMETER_SET == 768/1024, it would be included.+ *+ * To build mlkem-native with support for all parameter sets, build it three+ * times -- once per parameter set -- and set the option+ * MLK_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of them, and+ * MLK_CONFIG_MULTILEVEL_NO_SHARED for the others.+ * MLK_CONFIG_MULTILEVEL_BUILD should be set for all of them.+ *+ * See examples/multilevel_build for an example.+ *+ * This can also be set using CFLAGS.+ */+/* #define MLK_CONFIG_MULTILEVEL_WITH_SHARED */++/**+ * MLK_CONFIG_MULTILEVEL_NO_SHARED+ *+ * This is for multi-level builds of mlkem-native only. If you need only a+ * single parameter set, keep this unset.+ *+ * If this is set, no MLK_CONFIG_PARAMETER_SET-independent code will be+ * included in the build.+ *+ * To build mlkem-native with support for all parameter sets, build it three+ * times -- once per parameter set -- and set the option+ * MLK_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of them, and+ * MLK_CONFIG_MULTILEVEL_NO_SHARED for the others.+ * MLK_CONFIG_MULTILEVEL_BUILD should be set for all of them.+ *+ * See examples/multilevel_build for an example.+ *+ * This can also be set using CFLAGS.+ */+/* #define MLK_CONFIG_MULTILEVEL_NO_SHARED */++/**+ * MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS+ *+ * This is only relevant for single compilation unit (SCU) builds of+ * mlkem-native. In this case, it determines whether directives defined in+ * parameter-set-independent headers should be #undef'ined or not at the+ * end of the SCU file. This is needed in multilevel builds.+ *+ * See examples/multilevel_build_native for an example.+ *+ * This can also be set using CFLAGS.+ */+/* #define MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */++/**+ * MLK_CONFIG_USE_NATIVE_BACKEND_ARITH+ *+ * Determines whether a native arithmetic backend should be used.+ *+ * The arithmetic backend covers performance-critical functions such as the+ * number-theoretic transform (NTT).+ *+ * If this option is unset, the C backend will be used.+ *+ * If this option is set, the arithmetic backend to be used is determined+ * by MLK_CONFIG_ARITH_BACKEND_FILE: if the latter is unset, the default+ * backend for the target architecture will be used. If set, it must be the+ * name of a backend metadata file.+ *+ * This can also be set using CFLAGS.+ */+#if !defined(MLK_CONFIG_USE_NATIVE_BACKEND_ARITH)+/* #define MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */+#endif++/**+ * MLK_CONFIG_ARITH_BACKEND_FILE+ *+ * The arithmetic backend to use.+ *+ * If MLK_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option is ignored.+ *+ * If MLK_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must either+ * be undefined or the filename of an arithmetic backend. If unset, the+ * default backend will be used.+ *+ * This can be set using CFLAGS.+ */+#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_ARITH) && \+ !defined(MLK_CONFIG_ARITH_BACKEND_FILE)+#define MLK_CONFIG_ARITH_BACKEND_FILE "native/meta.h"+#endif++/**+ * MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202+ *+ * Determines whether a native FIPS202 backend should be used.+ *+ * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is the+ * performance bottleneck of SHA3 and SHAKE.+ *+ * If this option is unset, the C backend will be used.+ *+ * If this option is set, the FIPS202 backend to be used is determined by+ * MLK_CONFIG_FIPS202_BACKEND_FILE: if the latter is unset, the default+ * backend for the target architecture will be used. If set, it must be+ * the name of a backend metadata file.+ *+ * This can also be set using CFLAGS.+ */+#if !defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202)+/* #define MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 */+#endif++/**+ * MLK_CONFIG_FIPS202_BACKEND_FILE+ *+ * The FIPS-202 backend to use.+ *+ * If MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option must either+ * be undefined or the filename of a FIPS202 backend. If unset, the default+ * backend will be used.+ *+ * This can be set using CFLAGS.+ */+#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \+ !defined(MLK_CONFIG_FIPS202_BACKEND_FILE)+#define MLK_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h"+#endif++/**+ * MLK_CONFIG_FIPS202_CUSTOM_HEADER+ *+ * Custom header to use for FIPS-202.+ *+ * This should only be set if you intend to use a custom FIPS-202+ * implementation, different from the one shipped with mlkem-native.+ *+ * If set, it must be the name of a file serving as the replacement for+ * mlkem/src/fips202/fips202.h, and exposing the same API (see FIPS202.md).+ */+/* #define MLK_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */++/**+ * MLK_CONFIG_FIPS202X4_CUSTOM_HEADER+ *+ * Custom header to use for FIPS-202-X4.+ *+ * This should only be set if you intend to use a custom FIPS-202+ * implementation, different from the one shipped with mlkem-native.+ *+ * If set, it must be the name of a file serving as the replacement for+ * mlkem/src/fips202/fips202x4.h, and exposing the same API (see FIPS202.md).+ */+/* #define MLK_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */++/**+ * MLK_CONFIG_CUSTOM_ZEROIZE+ *+ * In compliance with @[FIPS203, Section 3.3], mlkem-native zeroizes+ * intermediate buffers before returning from function calls. By default,+ * those buffers are allocated from the stack; if MLK_CONFIG_CUSTOM_ALLOC_FREE+ * is set, they are (mostly -- few exceptions remain at present) allocated from+ * the configured custom allocator.+ *+ * mlkem-native also zeroizes caller-owned output buffers as needed to uphold+ * the API convention that outputs be either unmodified or zeroized upon+ * failure.+ *+ * Set this option and define `mlk_zeroize` if you want to use a custom+ * method to zeroize intermediate and output buffers.+ *+ * The default implementation uses SecureZeroMemory on Windows and a+ * memset + compiler barrier otherwise. If neither of those is available on+ * the target platform, compilation will fail, and you will need to use+ * MLK_CONFIG_CUSTOM_ZEROIZE to provide a custom implementation of+ * `mlk_zeroize()`.+ *+ * @warning+ * The zeroization conducted by mlkem-native reduces the likelihood of data+ * leaking on the stack or custom allocators, but it does not eliminate it.+ * For example, the C standard makes no guarantee about where a compiler+ * allocates local structures and whether/where it makes copies of them.+ * Also, in addition to entire structures, there may also be potentially+ * exploitable leakage of individual values on the stack. If you need+ * bullet-proof zeroization of the stack, you need to consider additional+ * measures instead of what this feature provides. In this case, you can+ * set mlk_zeroize to a no-op. Note that in this case you are also responsible+ * for zeroizing output buffers upon failure.+ */+/* #define MLK_CONFIG_CUSTOM_ZEROIZE+ #if !defined(__ASSEMBLER__)+ #include <stdint.h>+ #include "src/sys.h"+ static MLK_INLINE void mlk_zeroize(void *ptr, size_t len)+ {+ ... your implementation ...+ }+ #endif+*/++/**+ * MLK_CONFIG_CUSTOM_RANDOMBYTES+ *+ * mlkem-native does not provide a secure randombytes implementation. Such+ * an implementation has to be provided by the consumer.+ *+ * If this option is not set, mlkem-native expects a function+ * int randombytes(uint8_t *out, size_t outlen). It is expected to return+ * zero on success, and non-zero on failure. In case of failure, the+ * top-level APIs will return an MLK_ERR_RNG_FAIL error code.+ *+ * Set this option and define `mlk_randombytes` (with the same signature+ * and behaviour) if you want to use a custom method to sample randombytes+ * with a different name or signature.+ */+/* #define MLK_CONFIG_CUSTOM_RANDOMBYTES+ #if !defined(__ASSEMBLER__)+ #include <stdint.h>+ #include "src/sys.h"+ static MLK_INLINE int mlk_randombytes(uint8_t *ptr, size_t len)+ {+ ... your implementation ...+ return 0;+ }+ #endif+*/++/**+ * MLK_CONFIG_CUSTOM_CAPABILITY_FUNC+ *+ * mlkem-native backends may rely on specific hardware features. Those+ * backends will only be included in an mlkem-native build if support for+ * the respective features is enabled at compile-time. However, when+ * building for a heterogeneous set of CPUs to run the resulting+ * binary/library on, feature detection at _runtime_ is needed to decide+ * whether a backend can be used or not.+ *+ * Set this option and define `mlk_sys_check_capability` if you want to+ * use a custom method to dispatch between implementations.+ *+ * If this option is not set, mlkem-native uses compile-time feature+ * detection only to decide which backend to use.+ *+ * If you compile mlkem-native on a system with different capabilities+ * than the system that the resulting binary/library will be run on, you+ * must use this option.+ */+/* #define MLK_CONFIG_CUSTOM_CAPABILITY_FUNC+ static MLK_INLINE int mlk_sys_check_capability(mlk_sys_cap cap)+ __contract__(+ ensures(return_value == 0 || return_value == 1)+ )+ {+ ... your implementation ...+ }+*/++/**+ * MLK_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL]+ *+ * Set this option and define `MLK_CUSTOM_ALLOC` and `MLK_CUSTOM_FREE` if+ * you want to use custom allocation for large local structures or buffers.+ *+ * By default, all buffers/structures are allocated on the stack. If this+ * option is set, most of them will be allocated via MLK_CUSTOM_ALLOC.+ *+ * Parameters to MLK_CUSTOM_ALLOC:+ * - T* v: Target pointer to declare.+ * - T: Type of structure to be allocated.+ * - N: Number of elements to be allocated.+ *+ * Parameters to MLK_CUSTOM_FREE:+ * - T* v: Target pointer to free. May be NULL.+ * - T: Type of structure to be freed.+ * - N: Number of elements to be freed.+ *+ * @warning This option is experimental. Its scope, configuration and+ * function/macro signatures may change at any time. We expect a+ * stable API in a future version.+ *+ * @note Even if this option is set, some allocations further down the call+ * stack will still be made from the stack, consuming up to 3KB of+ * stack space. Those will likely be added to the scope of this+ * option in the future.+ *+ * @note MLK_CUSTOM_ALLOC need not guarantee a successful allocation nor+ * include error handling. Upon failure, the target pointer should+ * simply be set to NULL. The calling code will handle this case and+ * invoke MLK_CUSTOM_FREE.+ */+/* #define MLK_CONFIG_CUSTOM_ALLOC_FREE+ #if !defined(__ASSEMBLER__)+ #include <stdlib.h>+ #define MLK_CUSTOM_ALLOC(v, T, N) \+ T* (v) = (T *)aligned_alloc(MLK_DEFAULT_ALIGN, \+ MLK_ALIGN_UP(sizeof(T) * (N)))+ #define MLK_CUSTOM_FREE(v, T, N) free(v)+ #endif+*/++/**+ * MLK_CONFIG_CUSTOM_MEMCPY+ *+ * Set this option and define `mlk_memcpy` if you want to use a custom+ * method to copy memory instead of the standard library memcpy function.+ *+ * The custom implementation must have the same signature and behavior as+ * the standard memcpy function:+ * void *mlk_memcpy(void *dest, const void *src, size_t n)+ */+/* #define MLK_CONFIG_CUSTOM_MEMCPY+ #if !defined(__ASSEMBLER__)+ #include <stdint.h>+ #include "src/sys.h"+ static MLK_INLINE void *mlk_memcpy(void *dest, const void *src, size_t n)+ {+ ... your implementation ...+ }+ #endif+*/++/**+ * MLK_CONFIG_CUSTOM_MEMSET+ *+ * Set this option and define `mlk_memset` if you want to use a custom+ * method to set memory instead of the standard library memset function.+ *+ * The custom implementation must have the same signature and behavior as+ * the standard memset function:+ * void *mlk_memset(void *s, int c, size_t n)+ */+/* #define MLK_CONFIG_CUSTOM_MEMSET+ #if !defined(__ASSEMBLER__)+ #include <stdint.h>+ #include "src/sys.h"+ static MLK_INLINE void *mlk_memset(void *s, int c, size_t n)+ {+ ... your implementation ...+ }+ #endif+*/++/**+ * MLK_CONFIG_INTERNAL_API_QUALIFIER+ *+ * If set, this option provides an additional qualifier to be added to+ * declarations of internal API functions and data.+ *+ * The primary use case for this option are single-CU builds, in which case+ * this option can be set to `static`.+ */+/* #define MLK_CONFIG_INTERNAL_API_QUALIFIER */++/**+ * MLK_CONFIG_CT_TESTING_ENABLED+ *+ * If set, mlkem-native annotates data as secret/public using valgrind's+ * annotations VALGRIND_MAKE_MEM_UNDEFINED and VALGRIND_MAKE_MEM_DEFINED,+ * enabling various checks for secret-dependent control flow or+ * variable-time execution (depending on the exact version of valgrind+ * installed).+ */+/* #define MLK_CONFIG_CT_TESTING_ENABLED */++/**+ * MLK_CONFIG_NO_ASM+ *+ * If this option is set, mlkem-native will be built without use of native+ * code or inline assembly.+ *+ * By default, inline assembly is used to implement value barriers. Without+ * inline assembly, mlkem-native will use a global volatile 'opt blocker'+ * instead; see verify.h.+ *+ * Inline assembly is also used to implement a secure zeroization function+ * on non-Windows platforms. If this option is set and the target platform+ * is not Windows, you MUST set MLK_CONFIG_CUSTOM_ZEROIZE and provide a+ * custom zeroization function.+ *+ * If this option is set, MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 and+ * MLK_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no native+ * backends will be used.+ */+/* #define MLK_CONFIG_NO_ASM */++/**+ * MLK_CONFIG_NO_ASM_VALUE_BARRIER+ *+ * If this option is set, mlkem-native will be built without use of native+ * code or inline assembly for value barriers.+ *+ * By default, inline assembly (if available) is used to implement value+ * barriers. Without inline assembly, mlkem-native will use a global+ * volatile 'opt blocker' instead; see verify.h.+ */+/* #define MLK_CONFIG_NO_ASM_VALUE_BARRIER */++/**+ * MLK_CONFIG_KEYGEN_PCT+ *+ * Compliance with @[FIPS140_3_IG, p.87] requires a Pairwise Consistency+ * Test (PCT) to be carried out on a freshly generated keypair before it+ * can be exported.+ *+ * Set this option if such a check should be implemented. In this case,+ * keypair_derand and keypair will return+ * MLK_ERR_PCT_FAIL if the PCT failed.+ *+ * @note This feature will drastically lower the performance of key+ * generation.+ */+/* #define MLK_CONFIG_KEYGEN_PCT */++/**+ * MLK_CONFIG_KEYGEN_PCT_BREAKAGE_TEST+ *+ * If this option is set, the user must provide a runtime function+ * `static inline int mlk_break_pct() { ... }` to indicate whether the PCT+ * should be made to fail.+ *+ * This option only has an effect if MLK_CONFIG_KEYGEN_PCT is set.+ */+/* #define MLK_CONFIG_KEYGEN_PCT_BREAKAGE_TEST+ #if !defined(__ASSEMBLER__)+ #include "src/sys.h"+ static MLK_INLINE int mlk_break_pct(void)+ {+ ... return 0/1 depending on whether PCT should be broken ...+ }+ #endif+*/++/**+ * MLK_CONFIG_SERIAL_FIPS202_ONLY+ *+ * Set this to use a FIPS202 implementation with global state that supports+ * only one active Keccak computation at a time (e.g. some hardware+ * accelerators).+ *+ * If this option is set, batched Keccak operations are disabled for+ * rejection sampling during matrix generation. Instead, matrix entries+ * will be generated one at a time.+ *+ * This allows offloading Keccak computations to a hardware accelerator+ * that holds only a single Keccak state locally, rather than requiring+ * support for batched (4x) Keccak states.+ *+ * @note Depending on the target CPU, disabling batched Keccak may reduce+ * performance when using software FIPS202 implementations. Only+ * enable this when you have to.+ */+/* #define MLK_CONFIG_SERIAL_FIPS202_ONLY */++/**+ * MLK_CONFIG_CONTEXT_PARAMETER+ *+ * Set this to add a context parameter that is provided to public API+ * functions and is then available in custom callbacks.+ *+ * The type of the context parameter is configured via+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ */+/* #define MLK_CONFIG_CONTEXT_PARAMETER */++/**+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE+ *+ * Set this to define the type for the context parameter used by+ * MLK_CONFIG_CONTEXT_PARAMETER.+ *+ * This is only relevant if MLK_CONFIG_CONTEXT_PARAMETER is set.+ */+/* #define MLK_CONFIG_CONTEXT_PARAMETER_TYPE void* */++/************************* Config internals ********************************/++#endif /* MLK_BUILD_INTERNAL */++/* Default namespace+ *+ * Don't change this. If you need a different namespace, re-define+ * MLK_CONFIG_NAMESPACE_PREFIX above instead, and remove the following.+ *+ * The default MLKEM namespace is+ *+ * PQCP_MLKEM_NATIVE_MLKEM<LEVEL>_+ *+ * e.g., PQCP_MLKEM_NATIVE_MLKEM512_+ */++#if defined(MLK_CONFIG_MULTILEVEL_BUILD)+/* In a multi-level build the parameter set is appended by the namespacing+ * machinery, so the default prefix must not embed it. */+#define MLK_DEFAULT_NAMESPACE_PREFIX PQCP_MLKEM_NATIVE_MLKEM+#elif MLK_CONFIG_PARAMETER_SET == 512+#define MLK_DEFAULT_NAMESPACE_PREFIX PQCP_MLKEM_NATIVE_MLKEM512+#elif MLK_CONFIG_PARAMETER_SET == 768+#define MLK_DEFAULT_NAMESPACE_PREFIX PQCP_MLKEM_NATIVE_MLKEM768+#elif MLK_CONFIG_PARAMETER_SET == 1024+#define MLK_DEFAULT_NAMESPACE_PREFIX PQCP_MLKEM_NATIVE_MLKEM1024+#endif++#endif /* !MLK_CONFIG_H */
@@ -0,0 +1,222 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_CBMC_H+#define MLK_CBMC_H+/***************************************************+ * Basic replacements for __CPROVER_XXX contracts+ ***************************************************/+/*+ * The `__contract__` / `__loop__` annotation macros use a+ * leading-double-underscore spelling in line with other CBMC macros.+ * clang-tidy flags these as reserved identifiers; we suppress the diagnostic+ * at each definition site (NOLINT) rather than disabling the check globally,+ * so it stays active for the rest of the tree.+ */+#ifndef CBMC++/* clang-format off */+#define __contract__(x) /* NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */+#define __loop__(x) /* NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */+/* clang-format on */++#else /* !CBMC */+++/* clang-format off */+#define __contract__(x) x /* NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */+#define __loop__(x) x /* NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */+/* clang-format on */++/* https://diffblue.github.io/cbmc/contracts-assigns.html */+#define assigns(...) __CPROVER_assigns(__VA_ARGS__)++/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */+#define requires(...) __CPROVER_requires(__VA_ARGS__)+#define ensures(...) __CPROVER_ensures(__VA_ARGS__)+/* https://diffblue.github.io/cbmc/contracts-loops.html */+#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__)+#define decreases(...) __CPROVER_decreases(__VA_ARGS__)+/* cassert to avoid confusion with in-built assert */+#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed")+#define assume(...) __CPROVER_assume(__VA_ARGS__)++/***************************************************+ * Macros for "expression" forms that may appear+ * _inside_ top-level contracts.+ ***************************************************/++/*+ * function return value - useful inside ensures+ * https://diffblue.github.io/cbmc/contracts-functions.html+ */+#define return_value (__CPROVER_return_value)++/*+ * assigns l-value targets+ * https://diffblue.github.io/cbmc/contracts-assigns.html+ */+#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__)+#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__)++/*+ * Pointer-related predicates+ * https://diffblue.github.io/cbmc/contracts-memory-predicates.html+ */+#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__)+#define readable(...) __CPROVER_r_ok(__VA_ARGS__)+#define writeable(...) __CPROVER_w_ok(__VA_ARGS__)++/* Maximum supported buffer size+ *+ * Larger buffers may be supported, but due to internal modeling constraints+ * in CBMC, the proofs of memory- and type-safety won't be able to run.+ *+ * If you find yourself in need for a buffer size larger than this,+ * please contact the maintainers, so we can prioritize work to relax+ * this somewhat artificial bound.+ */+#define MLK_MAX_BUFFER_SIZE (SIZE_MAX >> 12)++/*+ * History variables+ * https://diffblue.github.io/cbmc/contracts-history-variables.html+ */+#define old(...) __CPROVER_old(__VA_ARGS__)+#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__)++/*+ * Quantifiers+ * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub+ * https://diffblue.github.io/cbmc/contracts-quantifiers.html+ *+ * The quantified variable is declared as uint32_t, so these macros+ * quantify only over indices in [0, UINT32_MAX). Bounds larger than+ * UINT32_MAX (4 GiB) are NOT supported: the explicit (uint32_t) casts+ * on the bounds will trigger CBMC's conversion check if a wider bound+ * (e.g. a size_t > UINT32_MAX) is passed.+ *+ * Quantifying over size_t (64-bit) was found to blow up SMT proof+ * times, so we deliberately keep the index width at 32 bits. Callers+ * dealing with size_t-typed buffers must add an explicit+ * requires(len <= UINT32_MAX)+ * precondition.+ */++/*+ * Prevent clang-format from corrupting CBMC's special ==> operator+ */+/* clang-format off */+#define forall(qvar, qvar_lb, qvar_ub, predicate) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> (predicate) \+ }++#define exists(qvar, qvar_lb, qvar_ub, predicate) \+ __CPROVER_exists \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) && (predicate) \+ }+/* clang-format on */++/***************************************************+ * Convenience macros for common contract patterns+ ***************************************************/++/*+ * Boolean-value predidate that asserts that "all values of array_var are in+ * range value_lb (inclusive) .. value_ub (exclusive)"+ * Example:+ * array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q)+ * expands to+ * __CPROVER_forall { int k; (0 <= k && k <= MLKEM_N-1) ==> (+ * 0 <= a->coeffs[k]) && a->coeffs[k] < MLKEM_Q)) }+ */++/*+ * Prevent clang-format from corrupting CBMC's special ==> operator+ */+/* clang-format off */+#define CBMC_CONCAT_(left, right) left##right+#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right)++#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \+ value_lb, value_ub) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> \+ (((int)(value_lb) <= ((array_var)[(qvar)])) && \+ (((array_var)[(qvar)]) < (int)(value_ub))) \+ }++#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \+ array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \+ (qvar_ub), (array_var), (value_lb), (value_ub))++#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> \+ ((array_var)[(qvar)]) == (old(* (int16_t (*)[(qvar_ub)])(array_var)))[(qvar)] \+ }++#define array_unchanged(array_var, N) \+ array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var))++#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \+ __CPROVER_forall \+ { \+ uint32_t qvar; \+ ((uint32_t) (qvar_lb) <= (qvar) && (qvar) < (uint32_t) (qvar_ub)) ==> \+ ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \+ }++#define array_unchanged_u64(array_var, N) \+ array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var))++#define array_unchanged_u8_core(qvar, array_var, N) \+ forall(qvar, 0, (N), \+ ((array_var)[(qvar)]) == (old(* (uint8_t (*)[(N)])(array_var)))[(qvar)])++#define array_unchanged_u8(array_var, N) \+ array_unchanged_u8_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (array_var), (N))++#define array_zeroized_u8_core(qvar, array_var, N) \+ forall(qvar, 0, (N), ((array_var)[(qvar)]) == 0)++#define array_zeroized_u8(array_var, N) \+ array_zeroized_u8_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (array_var), (N))+/* clang-format on */++/*+ * Output-buffer discipline on failure, as documented in API-CONVENTIONS.md:+ * when a function fails, each caller-owned output buffer is left either+ * fully unchanged or fully zeroized -- never holding partially computed or+ * stale data that could be mistaken for a valid result.+ *+ * Note the disjunction is over the buffer as a whole: it is not enough for+ * each byte to be individually either unchanged or zero.+ */+#define array_unchanged_or_zeroized_u8(array_var, N) \+ (array_unchanged_u8((array_var), (N)) || array_zeroized_u8((array_var), (N)))++/* Wrapper around array_bound operating on absolute values.+ *+ * The absolute value bound `k` is exclusive.+ *+ * Note that since the lower bound in array_bound is inclusive, we have to+ * raise it by 1 here.+ */+#define array_abs_bound(arr, lb, ub, k) \+ array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k))++#endif /* CBMC */++#endif /* !MLK_CBMC_H */
@@ -0,0 +1,296 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS140_3_IG]+ * Implementation Guidance for FIPS 140-3 and the Cryptographic Module+ * Validation Program+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#ifndef MLK_COMMON_H+#define MLK_COMMON_H++#ifndef __ASSEMBLER__+#include <stdint.h>+#endif++#define MLK_BUILD_INTERNAL++#if defined(MLK_CONFIG_FILE)+#include MLK_CONFIG_FILE+#else+#include "mlkem_native_config.h"+#endif++#include "params.h"+#include "sys.h"++/* Internal and public API have external linkage by default, but+ * this can be overwritten by the user, e.g. for single-CU builds. */+#if !defined(MLK_CONFIG_INTERNAL_API_QUALIFIER)+#define MLK_INTERNAL_API+#define MLK_INTERNAL_DATA_DECLARATION extern+#define MLK_INTERNAL_DATA_DEFINITION+#else+#define MLK_INTERNAL_API MLK_CONFIG_INTERNAL_API_QUALIFIER+#define MLK_INTERNAL_DATA_DECLARATION MLK_CONFIG_INTERNAL_API_QUALIFIER+#define MLK_INTERNAL_DATA_DEFINITION MLK_CONFIG_INTERNAL_API_QUALIFIER+#endif++#if !defined(MLK_CONFIG_EXTERNAL_API_QUALIFIER)+#define MLK_EXTERNAL_API+#else+#define MLK_EXTERNAL_API MLK_CONFIG_EXTERNAL_API_QUALIFIER+#endif++#define MLK_CONCAT_(x1, x2) x1##x2+#define MLK_CONCAT(x1, x2) MLK_CONCAT_(x1, x2)++#if (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || \+ defined(MLK_CONFIG_MULTILEVEL_NO_SHARED))+#define MLK_ADD_PARAM_SET(s) MLK_CONCAT(s, MLK_CONFIG_PARAMETER_SET)+#else+#define MLK_ADD_PARAM_SET(s) s+#endif++#define MLK_NAMESPACE_PREFIX MLK_CONCAT(MLK_CONFIG_NAMESPACE_PREFIX, _)+#define MLK_NAMESPACE_PREFIX_K \+ MLK_CONCAT(MLK_ADD_PARAM_SET(MLK_CONFIG_NAMESPACE_PREFIX), _)++/* Functions are prefixed by MLK_CONFIG_NAMESPACE_PREFIX.+ *+ * If multiple parameter sets are used, functions depending on the parameter+ * set are additionally prefixed with 512/768/1024. See mlkem_native_config.h.+ *+ * Example: If MLK_CONFIG_NAMESPACE_PREFIX is mlkem, then+ * MLK_NAMESPACE_K(enc) becomes mlkem512_enc/mlkem768_enc/mlkem1024_enc.+ */+#define MLK_NAMESPACE(s) MLK_CONCAT(MLK_NAMESPACE_PREFIX, s)+#define MLK_NAMESPACE_K(s) MLK_CONCAT(MLK_NAMESPACE_PREFIX_K, s)++/* On Apple platforms, we need to emit leading underscore+ * in front of assembly symbols. We thus introduce a separate+ * namespace wrapper for ASM symbols. */+#if !defined(__APPLE__)+#define MLK_ASM_NAMESPACE(sym) MLK_NAMESPACE(sym)+#else+#define MLK_ASM_NAMESPACE(sym) MLK_CONCAT(_, MLK_NAMESPACE(sym))+#endif++/*+ * On X86_64 if control-flow protections (CET) are enabled (through+ * -fcf-protection=), we add an endbr64 instruction at every global function+ * label. See sys.h for more details+ */+#if defined(MLK_SYS_X86_64)+#define MLK_ASM_FN_SYMBOL(sym) MLK_ASM_NAMESPACE(sym) : MLK_CET_ENDBR+#elif defined(MLK_SYS_ARMV81M_MVE)+/* clang-format off */+#define MLK_ASM_FN_SYMBOL(sym) \+ .type MLK_ASM_NAMESPACE(sym), %function; \+ MLK_ASM_NAMESPACE(sym) :+/* clang-format on */+#else /* !MLK_SYS_X86_64 && MLK_SYS_ARMV81M_MVE */+#define MLK_ASM_FN_SYMBOL(sym) MLK_ASM_NAMESPACE(sym) :+#endif /* !MLK_SYS_X86_64 && !MLK_SYS_ARMV81M_MVE */++/*+ * Output the size of an assembly function.+ */+#if defined(__ELF__)+#define MLK_ASM_FN_SIZE(sym) \+ .size MLK_ASM_NAMESPACE(sym), .- MLK_ASM_NAMESPACE(sym)+#else+#define MLK_ASM_FN_SIZE(sym)+#endif++/* We aim to simplify the user's life by supporting builds where+ * all source files are included, even those that are not needed.+ * Those files are appropriately guarded and will be empty when unneeded.+ * The following is to avoid compilers complaining about this. */+#define MLK_EMPTY_CU(s) extern int MLK_NAMESPACE_K(empty_cu_##s);++/* MLK_CONFIG_NO_ASM takes precedence over MLK_USE_NATIVE_XXX */+#if defined(MLK_CONFIG_NO_ASM)+#undef MLK_CONFIG_USE_NATIVE_BACKEND_ARITH+#undef MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202+#endif++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_ARITH) && \+ !defined(MLK_CONFIG_ARITH_BACKEND_FILE)+#error Bad configuration: MLK_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLK_CONFIG_ARITH_BACKEND_FILE is not.+#endif++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \+ !defined(MLK_CONFIG_FIPS202_BACKEND_FILE)+#error Bad configuration: MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLK_CONFIG_FIPS202_BACKEND_FILE is not.+#endif++#if defined(MLK_CONFIG_NO_RANDOMIZED_API) && defined(MLK_CONFIG_KEYGEN_PCT)+#error Bad configuration: MLK_CONFIG_NO_RANDOMIZED_API is incompatible with MLK_CONFIG_KEYGEN_PCT as the current PCT implementation requires enc()+#endif++#if defined(MLK_CONFIG_NO_ENCAPS_API) && defined(MLK_CONFIG_KEYGEN_PCT)+#error Bad configuration: MLK_CONFIG_NO_ENCAPS_API is incompatible with MLK_CONFIG_KEYGEN_PCT as the current PCT implementation requires enc()+#endif++#if defined(MLK_CONFIG_NO_DECAPS_API) && defined(MLK_CONFIG_KEYGEN_PCT)+#error Bad configuration: MLK_CONFIG_NO_DECAPS_API is incompatible with MLK_CONFIG_KEYGEN_PCT as the current PCT implementation requires dec()+#endif++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_ARITH)+#include MLK_CONFIG_ARITH_BACKEND_FILE+/* Include to enforce consistency of API and implementation,+ * and conduct sanity checks on the backend.+ *+ * Keep this _after_ the inclusion of the backend; otherwise,+ * the sanity checks won't have an effect. */+#if defined(MLK_CHECK_APIS) && !defined(__ASSEMBLER__)+#include "native/api.h"+#endif+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */++#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202)+#include MLK_CONFIG_FIPS202_BACKEND_FILE+/* Include to enforce consistency of API and implementation,+ * and conduct sanity checks on the backend.+ *+ * Keep this _after_ the inclusion of the backend; otherwise,+ * the sanity checks won't have an effect. */+#if defined(MLK_CHECK_APIS) && !defined(__ASSEMBLER__)+#include "fips202/native/api.h"+#endif+#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 */++#if !defined(MLK_CONFIG_FIPS202_CUSTOM_HEADER)+#define MLK_FIPS202_HEADER_FILE "fips202/fips202.h"+#else+#define MLK_FIPS202_HEADER_FILE MLK_CONFIG_FIPS202_CUSTOM_HEADER+#endif++#if !defined(MLK_CONFIG_FIPS202X4_CUSTOM_HEADER)+#define MLK_FIPS202X4_HEADER_FILE "fips202/fips202x4.h"+#else+#define MLK_FIPS202X4_HEADER_FILE MLK_CONFIG_FIPS202X4_CUSTOM_HEADER+#endif++/* Standard library function replacements */+#if !defined(__ASSEMBLER__)+#if !defined(MLK_CONFIG_CUSTOM_MEMCPY)+#include <string.h>+#define mlk_memcpy memcpy+#endif++#if !defined(MLK_CONFIG_CUSTOM_MEMSET)+#include <string.h>+#define mlk_memset memset+#endif+++/* Allocation macros for large local structures+ *+ * MLK_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N]+ * MLK_FREE(v, T, N) zeroizes and frees the allocation+ *+ * Default implementation uses stack allocation.+ * Can be overridden by setting the config option MLK_CONFIG_CUSTOM_ALLOC_FREE+ * and defining MLK_CUSTOM_ALLOC and MLK_CUSTOM_FREE.+ */+#if defined(MLK_CONFIG_CUSTOM_ALLOC_FREE) != \+ (defined(MLK_CUSTOM_ALLOC) && defined(MLK_CUSTOM_FREE))+#error Bad configuration: MLK_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLK_CUSTOM_ALLOC and MLK_CUSTOM_FREE+#endif++/* Context-parameter machinery (MLK_CONTEXT_PARAMETERS_n and related config+ * checks). Kept in a separate, level-generic header for readability; included+ * here so it is available to the allocation macros below and to all consumers+ * of common.h. */+#include "context.h"++#if !defined(MLK_CONFIG_CUSTOM_ALLOC_FREE)+/* Default: stack allocation */++/* This is a declaration macro, not an expression macro: T is a type and v is+ * a declarator, neither of which can be wrapped in parentheses. The+ * bugprone-macro-parentheses diagnostic is therefore a false positive here. */+#define MLK_ALLOC(v, T, N, context) \+ MLK_ALIGN T mlk_alloc_##v[N]; \+ T *v = mlk_alloc_##v /* NOLINT(bugprone-macro-parentheses) */++/* The MLK_FREE macro body references mlk_zeroize(), which is declared in+ * verify.h. We deliberately do NOT include verify.h here: doing so would+ * create a circular dependency (verify.h includes common.h), and common.h+ * itself never calls mlk_zeroize() -- only the macro expansion does. Each+ * translation unit that uses MLK_FREE therefore includes verify.h directly. */+#define MLK_FREE(v, T, N, context) \+ do \+ { \+ MLK_CONTEXT_UNUSED(context); \+ mlk_zeroize(mlk_alloc_##v, sizeof(mlk_alloc_##v)); \+ (v) = NULL; \+ } while (0)++#else /* !MLK_CONFIG_CUSTOM_ALLOC_FREE */++/* Custom allocation */++/*+ * The indirection here is necessary to use MLK_CONTEXT_PARAMETERS_3 here.+ */+#define MLK_APPLY(f, args) f args++#define MLK_ALLOC(v, T, N, context) \+ MLK_APPLY(MLK_CUSTOM_ALLOC, MLK_CONTEXT_PARAMETERS_3(v, T, N, context))++#define MLK_FREE(v, T, N, context) \+ do \+ { \+ if (v != NULL) \+ { \+ mlk_zeroize(v, sizeof(T) * (N)); \+ MLK_APPLY(MLK_CUSTOM_FREE, MLK_CONTEXT_PARAMETERS_3(v, T, N, context)); \+ v = NULL; \+ } \+ } while (0)++#endif /* MLK_CONFIG_CUSTOM_ALLOC_FREE */++/****************************** Error codes ***********************************/++/* Generic failure condition. Currently not returned by any function;+ * reserved for failures that no more specific code covers. */+#define MLK_ERR_FAIL (-1)+/* An allocation failed. This can only happen if MLK_CONFIG_CUSTOM_ALLOC_FREE+ * is defined and the provided MLK_CUSTOM_ALLOC can fail. */+#define MLK_ERR_OUT_OF_MEMORY (-2)+/* An RNG failure occurred. Might be due to insufficient entropy or+ * system misconfiguration. */+#define MLK_ERR_RNG_FAIL (-3)+/* Public key validation failed: the @[FIPS203, Section 7.2, 'modulus check']+ * found a coefficient outside [0,q-1]. Returned by check_pk and by the+ * encapsulation API. */+#define MLK_ERR_INVALID_PK (-4)+/* Secret key validation failed: the @[FIPS203, Section 7.3, 'hash check']+ * found the embedded public key hash inconsistent. Returned by check_sk and+ * by the decapsulation API. */+#define MLK_ERR_INVALID_SK (-5)+/* The 'Pairwise Consistency Test' @[FIPS140_3_IG, p.87] and+ * @[FIPS203, Section 7.1, Pairwise Consistency] failed. Only possible when+ * MLK_CONFIG_KEYGEN_PCT is enabled; signals that the freshly generated key+ * pair failed its encaps/decaps self-test. */+#define MLK_ERR_PCT_FAIL (-6)++#endif /* !__ASSEMBLER__ */++#endif /* !MLK_COMMON_H */
@@ -0,0 +1,763 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ *+ * - [REF]+ * CRYSTALS-Kyber C reference implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/ref+ */++#include "common.h"+#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+++#include "cbmc.h"+#include "compress.h"+#include "debug.h"+#include "verify.h"++#if (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2 || \+ MLKEM_K == 3)+/* Reference: `poly_compress()` in the reference implementation @[REF],+ * for ML-KEM-{512,768}.+ * - In contrast to the reference implementation, we assume+ * unsigned canonical coefficients here.+ * The reference implementation works with coefficients+ * in the range [-(MLKEM_Q-1), MLKEM_Q-1]. */+MLK_STATIC_TESTABLE void mlk_poly_compress_d4_c(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D4], const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D4))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D4))+)+{+ unsigned i;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);++ for (i = 0; i < MLKEM_N / 8; i++)+ __loop__(invariant(i <= MLKEM_N / 8)+ decreases(MLKEM_N / 8 - i))+ {+ unsigned j;+ uint8_t t[8] = {0};+ for (j = 0; j < 8; j++)+ __loop__(+ invariant(i <= MLKEM_N / 8 && j <= 8)+ invariant(array_bound(t, 0, j, 0, 16))+ decreases(8 - j))+ {+ t[j] = mlk_scalar_compress_d4(a->coeffs[8 * i + j]);+ }++ /* All t[i] are 4-bit wide, so the truncations don't alter the value. */+ r[i * 4] = (uint8_t)(t[0] | (t[1] << 4));+ r[i * 4 + 1] = (uint8_t)(t[2] | (t[3] << 4));+ r[i * 4 + 2] = (uint8_t)(t[4] | (t[5] << 4));+ r[i * 4 + 3] = (uint8_t)(t[6] | (t[7] << 4));+ }+}++MLK_INTERNAL_API+void mlk_poly_compress_d4(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D4],+ const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D4))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D4))+)+{+#if defined(MLK_USE_NATIVE_POLY_COMPRESS_D4)+ int ret;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);+ ret = mlk_poly_compress_d4_native(r, a->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_COMPRESS_D4 */++ mlk_poly_compress_d4_c(r, a);+}++/* Reference: Embedded into `polyvec_compress()` in the+ * reference implementation, for ML-KEM-{512,768}.+ * - In contrast to the reference implementation, we assume+ * unsigned canonical coefficients here.+ * The reference implementation works with coefficients+ * in the range [-(MLKEM_Q-1), MLKEM_Q-1]. */+MLK_STATIC_TESTABLE void mlk_poly_compress_d10_c(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D10], const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D10))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D10))+)+{+ unsigned j;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);+ for (j = 0; j < MLKEM_N / 4; j++)+ __loop__(invariant(j <= MLKEM_N / 4)+ decreases(MLKEM_N / 4 - j))+ {+ unsigned k;+ uint16_t t[4];+ for (k = 0; k < 4; k++)+ __loop__(+ invariant(k <= 4)+ invariant(forall(r, 0, k, t[r] < (1u << 10)))+ decreases(4 - k))+ {+ t[k] = mlk_scalar_compress_d10(a->coeffs[4 * j + k]);+ }++ /*+ * Make all implicit truncation explicit. No data is being+ * truncated for the LHS's since each t[i] is 10-bit in size.+ */+ r[5 * j + 0] = (uint8_t)((t[0] >> 0) & 0xFF);+ r[5 * j + 1] = (uint8_t)((t[0] >> 8) | ((t[1] << 2) & 0xFF));+ r[5 * j + 2] = (uint8_t)((t[1] >> 6) | ((t[2] << 4) & 0xFF));+ r[5 * j + 3] = (uint8_t)((t[2] >> 4) | ((t[3] << 6) & 0xFF));+ r[5 * j + 4] = (uint8_t)(t[3] >> 2);+ }+}++MLK_INTERNAL_API+void mlk_poly_compress_d10(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D10],+ const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D10))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D10))+)+{+#if defined(MLK_USE_NATIVE_POLY_COMPRESS_D10)+ int ret;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);+ ret = mlk_poly_compress_d10_native(r, a->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_COMPRESS_D10 */++ mlk_poly_compress_d10_c(r, a);+}++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `poly_decompress()` in the reference implementation @[REF],+ * for ML-KEM-{512,768}. */+MLK_STATIC_TESTABLE void mlk_poly_decompress_d4_c(+ mlk_poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D4])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D4))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+)+{+ unsigned i;+ for (i = 0; i < MLKEM_N / 2; i++)+ __loop__(+ invariant(i <= MLKEM_N / 2)+ invariant(array_bound(r->coeffs, 0, 2 * i, 0, MLKEM_Q))+ decreases(MLKEM_N / 2 - i))+ {+ r->coeffs[2 * i + 0] = mlk_scalar_decompress_d4((a[i] >> 0) & 0xF);+ r->coeffs[2 * i + 1] = mlk_scalar_decompress_d4((a[i] >> 4) & 0xF);+ }++ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+}++MLK_INTERNAL_API+void mlk_poly_decompress_d4(mlk_poly *r,+ const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D4])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D4))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+)+{+#if defined(MLK_USE_NATIVE_POLY_DECOMPRESS_D4)+ int ret;+ ret = mlk_poly_decompress_d4_native(r->coeffs, a);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_DECOMPRESS_D4 */++ mlk_poly_decompress_d4_c(r, a);+}++/* Reference: Embedded into `polyvec_decompress()` in the+ * reference implementation, for ML-KEM-{512,768}. */+MLK_STATIC_TESTABLE void mlk_poly_decompress_d10_c(+ mlk_poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D10])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D10))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+)+{+ unsigned j;+ for (j = 0; j < MLKEM_N / 4; j++)+ __loop__(+ invariant(j <= MLKEM_N / 4)+ invariant(array_bound(r->coeffs, 0, 4 * j, 0, MLKEM_Q))+ decreases(MLKEM_N / 4 - j))+ {+ unsigned k;+ uint16_t t[4];+ uint8_t const *base = &a[5 * j];++ t[0] = 0x3FF & ((base[0] >> 0) | ((uint16_t)base[1] << 8));+ t[1] = 0x3FF & ((base[1] >> 2) | ((uint16_t)base[2] << 6));+ t[2] = 0x3FF & ((base[2] >> 4) | ((uint16_t)base[3] << 4));+ t[3] = 0x3FF & ((base[3] >> 6) | ((uint16_t)base[4] << 2));++ for (k = 0; k < 4; k++)+ __loop__(+ invariant(k <= 4)+ invariant(array_bound(r->coeffs, 0, 4 * j + k, 0, MLKEM_Q))+ decreases(4 - k))+ {+ r->coeffs[4 * j + k] = mlk_scalar_decompress_d10(t[k]);+ }+ }++ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+}++MLK_INTERNAL_API+void mlk_poly_decompress_d10(mlk_poly *r,+ const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D10])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D10))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+)+{+#if defined(MLK_USE_NATIVE_POLY_DECOMPRESS_D10)+ int ret;+ ret = mlk_poly_decompress_d10_native(r->coeffs, a);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_DECOMPRESS_D10 */++ mlk_poly_decompress_d10_c(r, a);+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */+#endif /* (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 || MLKEM_K == 3) \+ */++#if (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4)+/* Reference: `poly_compress()` in the reference implementation @[REF],+ * for ML-KEM-1024.+ * - In contrast to the reference implementation, we assume+ * unsigned canonical coefficients here.+ * The reference implementation works with coefficients+ * in the range [-(MLKEM_Q-1), MLKEM_Q-1]. */+MLK_STATIC_TESTABLE void mlk_poly_compress_d5_c(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D5], const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D5))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D5))+)+{+ unsigned i;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);++ for (i = 0; i < MLKEM_N / 8; i++)+ __loop__(invariant(i <= MLKEM_N / 8)+ decreases(MLKEM_N / 8 - i))+ {+ unsigned j;+ uint8_t t[8] = {0};+ for (j = 0; j < 8; j++)+ __loop__(+ invariant(i <= MLKEM_N / 8 && j <= 8)+ invariant(array_bound(t, 0, j, 0, 32))+ decreases(8 - j))+ {+ t[j] = mlk_scalar_compress_d5(a->coeffs[8 * i + j]);+ }++ r[i * 5] = (uint8_t)(0xFF & ((t[0] >> 0) | (t[1] << 5)));+ r[i * 5 + 1] = (uint8_t)(0xFF & ((t[1] >> 3) | (t[2] << 2) | (t[3] << 7)));+ r[i * 5 + 2] = (uint8_t)(0xFF & ((t[3] >> 1) | (t[4] << 4)));+ r[i * 5 + 3] = (uint8_t)(0xFF & ((t[4] >> 4) | (t[5] << 1) | (t[6] << 6)));+ r[i * 5 + 4] = (uint8_t)(0xFF & ((t[6] >> 2) | (t[7] << 3)));+ }+}++MLK_INTERNAL_API+void mlk_poly_compress_d5(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D5],+ const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D5))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D5))+)+{+#if defined(MLK_USE_NATIVE_POLY_COMPRESS_D5)+ int ret;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);+ ret = mlk_poly_compress_d5_native(r, a->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_COMPRESS_D5 */++ mlk_poly_compress_d5_c(r, a);+}++/* Reference: Embedded into `polyvec_compress()` in the+ * reference implementation, for ML-KEM-1024.+ * - In contrast to the reference implementation, we assume+ * unsigned canonical coefficients here.+ * The reference implementation works with coefficients+ * in the range [-(MLKEM_Q-1), MLKEM_Q-1]. */+MLK_STATIC_TESTABLE void mlk_poly_compress_d11_c(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D11], const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D11))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D11))+)+{+ unsigned j;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);++ for (j = 0; j < MLKEM_N / 8; j++)+ __loop__(invariant(j <= MLKEM_N / 8)+ decreases(MLKEM_N / 8 - j))+ {+ unsigned k;+ uint16_t t[8];+ for (k = 0; k < 8; k++)+ __loop__(+ invariant(k <= 8)+ invariant(forall(r, 0, k, t[r] < (1u << 11)))+ decreases(8 - k))+ {+ t[k] = mlk_scalar_compress_d11(a->coeffs[8 * j + k]);+ }++ /*+ * Make all implicit truncation explicit. No data is being+ * truncated for the LHS's since each t[i] is 11-bit in size.+ */+ r[11 * j + 0] = (uint8_t)((t[0] >> 0) & 0xFF);+ r[11 * j + 1] = (uint8_t)((t[0] >> 8) | ((t[1] << 3) & 0xFF));+ r[11 * j + 2] = (uint8_t)((t[1] >> 5) | ((t[2] << 6) & 0xFF));+ r[11 * j + 3] = (uint8_t)((t[2] >> 2) & 0xFF);+ r[11 * j + 4] = (uint8_t)((t[2] >> 10) | ((t[3] << 1) & 0xFF));+ r[11 * j + 5] = (uint8_t)((t[3] >> 7) | ((t[4] << 4) & 0xFF));+ r[11 * j + 6] = (uint8_t)((t[4] >> 4) | ((t[5] << 7) & 0xFF));+ r[11 * j + 7] = (uint8_t)((t[5] >> 1) & 0xFF);+ r[11 * j + 8] = (uint8_t)((t[5] >> 9) | ((t[6] << 2) & 0xFF));+ r[11 * j + 9] = (uint8_t)((t[6] >> 6) | ((t[7] << 5) & 0xFF));+ r[11 * j + 10] = (uint8_t)(t[7] >> 3);+ }+}++MLK_INTERNAL_API+void mlk_poly_compress_d11(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D11],+ const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D11))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D11))+)+{+#if defined(MLK_USE_NATIVE_POLY_COMPRESS_D11)+ int ret;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);+ ret = mlk_poly_compress_d11_native(r, a->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_COMPRESS_D11 */++ mlk_poly_compress_d11_c(r, a);+}++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `poly_decompress()` in the reference implementation @[REF],+ * for ML-KEM-1024. */+MLK_STATIC_TESTABLE void mlk_poly_decompress_d5_c(+ mlk_poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D5])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D5))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+)+{+ unsigned i;+ for (i = 0; i < MLKEM_N / 8; i++)+ __loop__(+ invariant(i <= MLKEM_N / 8)+ invariant(array_bound(r->coeffs, 0, 8 * i, 0, MLKEM_Q))+ decreases(MLKEM_N / 8 - i))+ {+ unsigned j;+ uint8_t t[8];+ const unsigned offset = i * 5;+ /*+ * Explicitly truncate to avoid warning about+ * implicit truncation in CBMC and unwind loop for ease+ * of proof.+ */++ /*+ * Decompress 5 8-bit bytes (so 40 bits) into+ * 8 5-bit values stored in t[]+ */+ t[0] = 0x1F & (a[offset + 0] >> 0);+ t[1] = 0x1F & ((a[offset + 0] >> 5) | (a[offset + 1] << 3));+ t[2] = 0x1F & (a[offset + 1] >> 2);+ t[3] = 0x1F & ((a[offset + 1] >> 7) | (a[offset + 2] << 1));+ t[4] = 0x1F & ((a[offset + 2] >> 4) | (a[offset + 3] << 4));+ t[5] = 0x1F & (a[offset + 3] >> 1);+ t[6] = 0x1F & ((a[offset + 3] >> 6) | (a[offset + 4] << 2));+ t[7] = 0x1F & (a[offset + 4] >> 3);++ /* and copy to the correct slice in r[] */+ for (j = 0; j < 8; j++)+ __loop__(+ invariant(j <= 8 && i <= MLKEM_N / 8)+ invariant(array_bound(r->coeffs, 0, 8 * i + j, 0, MLKEM_Q))+ decreases(8 - j))+ {+ r->coeffs[8 * i + j] = mlk_scalar_decompress_d5(t[j]);+ }+ }++ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+}++MLK_INTERNAL_API+void mlk_poly_decompress_d5(mlk_poly *r,+ const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D5])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D5))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+)+{+#if defined(MLK_USE_NATIVE_POLY_DECOMPRESS_D5)+ int ret;+ ret = mlk_poly_decompress_d5_native(r->coeffs, a);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_DECOMPRESS_D5 */++ mlk_poly_decompress_d5_c(r, a);+}++/* Reference: Embedded into `polyvec_decompress()` in the+ * reference implementation, for ML-KEM-1024. */+MLK_STATIC_TESTABLE void mlk_poly_decompress_d11_c(+ mlk_poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D11])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D11))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+)+{+ unsigned j;+ for (j = 0; j < MLKEM_N / 8; j++)+ __loop__(+ invariant(j <= MLKEM_N / 8)+ invariant(array_bound(r->coeffs, 0, 8 * j, 0, MLKEM_Q))+ decreases(MLKEM_N / 8 - j))+ {+ unsigned k;+ uint16_t t[8];+ uint8_t const *base = &a[11 * j];+ t[0] = 0x7FF & ((base[0] >> 0) | ((uint16_t)base[1] << 8));+ t[1] = 0x7FF & ((base[1] >> 3) | ((uint16_t)base[2] << 5));+ t[2] = 0x7FF & ((base[2] >> 6) | ((uint16_t)base[3] << 2) |+ ((uint16_t)base[4] << 10));+ t[3] = 0x7FF & ((base[4] >> 1) | ((uint16_t)base[5] << 7));+ t[4] = 0x7FF & ((base[5] >> 4) | ((uint16_t)base[6] << 4));+ t[5] = 0x7FF & ((base[6] >> 7) | ((uint16_t)base[7] << 1) |+ ((uint16_t)base[8] << 9));+ t[6] = 0x7FF & ((base[8] >> 2) | ((uint16_t)base[9] << 6));+ t[7] = 0x7FF & ((base[9] >> 5) | ((uint16_t)base[10] << 3));++ for (k = 0; k < 8; k++)+ __loop__(+ invariant(k <= 8)+ invariant(array_bound(r->coeffs, 0, 8 * j + k, 0, MLKEM_Q))+ decreases(8 - k))+ {+ r->coeffs[8 * j + k] = mlk_scalar_decompress_d11(t[k]);+ }+ }++ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+}++MLK_INTERNAL_API+void mlk_poly_decompress_d11(mlk_poly *r,+ const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D11])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D11))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+)+{+#if defined(MLK_USE_NATIVE_POLY_DECOMPRESS_D11)+ int ret;+ ret = mlk_poly_decompress_d11_native(r->coeffs, a);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_DECOMPRESS_D11 */++ mlk_poly_decompress_d11_c(r, a);+}++#endif /* !MLK_CONFIG_NO_DECAPS_API */+#endif /* (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4) */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API) || !defined(MLK_CONFIG_NO_ENCAPS_API)+/* Reference: `poly_tobytes()` in the reference implementation @[REF].+ * - In contrast to the reference implementation, we assume+ * unsigned canonical coefficients here.+ * The reference implementation works with coefficients+ * in the range [-(MLKEM_Q-1), MLKEM_Q-1]. */+MLK_STATIC_TESTABLE void mlk_poly_tobytes_c(uint8_t r[MLKEM_POLYBYTES],+ const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYBYTES))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYBYTES))+)+{+ unsigned i;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);++ for (i = 0; i < MLKEM_N / 2; i++)+ __loop__(invariant(i <= MLKEM_N / 2)+ decreases(MLKEM_N / 2 - i))+ {+ /* The conversion to uint16_t is safe since we assume that+ * the coefficients of `a` are non-negative. */+ const uint16_t t0 = (uint16_t)a->coeffs[2 * i];+ const uint16_t t1 = (uint16_t)a->coeffs[2 * i + 1];+ /*+ * t0 and t1 are both < MLKEM_Q, so contain at most 12 bits each of+ * significant data, so these can be packed into 24 bits or exactly+ * 3 bytes, as follows.+ */++ /* Least significant bits 0 - 7 of t0. */+ r[3 * i + 0] = (uint8_t)(t0 & 0xFF);++ /*+ * Most significant bits 8 - 11 of t0 become the least significant+ * nibble of the second byte. The least significant 4 bits+ * of t1 become the upper nibble of the second byte.+ *+ * The conversion to uint8_t does not alter the value.+ */+ r[3 * i + 1] = (uint8_t)((t0 >> 8) | ((t1 << 4) & 0xF0));++ /* Bits 4 - 11 of t1 become the third byte. The conversion to uint8_t+ * does not alter the value because t1 is 12-bit wide. */+ r[3 * i + 2] = (uint8_t)(t1 >> 4);+ }+}++MLK_INTERNAL_API+void mlk_poly_tobytes(uint8_t r[MLKEM_POLYBYTES], const mlk_poly *a)+{+#if defined(MLK_USE_NATIVE_POLY_TOBYTES)+ int ret;+ mlk_assert_bound(a, MLKEM_N, 0, MLKEM_Q);+ ret = mlk_poly_tobytes_native(r, a->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_TOBYTES */++ mlk_poly_tobytes_c(r, a);+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API || !MLK_CONFIG_NO_ENCAPS_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `poly_frombytes()` in the reference implementation @[REF]. */+MLK_STATIC_TESTABLE void mlk_poly_frombytes_c(mlk_poly *r,+ const uint8_t a[MLKEM_POLYBYTES])+__contract__(+ requires(memory_no_alias(a, MLKEM_POLYBYTES))+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT))+)+{+ unsigned i;+ for (i = 0; i < MLKEM_N / 2; i++)+ __loop__(+ invariant(i <= MLKEM_N / 2)+ invariant(array_bound(r->coeffs, 0, 2 * i, 0, MLKEM_UINT12_LIMIT))+ decreases(MLKEM_N / 2 - i))+ {+ const uint8_t t0 = a[3 * i + 0];+ const uint8_t t1 = a[3 * i + 1];+ const uint8_t t2 = a[3 * i + 2];+ /* Safety:+ * - The explicit cast to uint16_t ensures that << 8 does+ * not signed-overflow even on a 16-bit system.+ * - The cast to int16_t is safe due to the explicit 0xFFF truncation.+ */+ r->coeffs[2 * i + 0] = (int16_t)(t0 | (((uint16_t)t1 << 8) & 0xFFF));+ r->coeffs[2 * i + 1] = (int16_t)((t1 >> 4) | (t2 << 4));+ }++ /* Note that the coefficients are not canonical */+ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_UINT12_LIMIT);+}++MLK_INTERNAL_API+void mlk_poly_frombytes(mlk_poly *r, const uint8_t a[MLKEM_POLYBYTES])+{+#if defined(MLK_USE_NATIVE_POLY_FROMBYTES)+ int ret;+ ret = mlk_poly_frombytes_native(r->coeffs, a);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_FROMBYTES */++ mlk_poly_frombytes_c(r, a);+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `poly_frommsg()` in the reference implementation @[REF].+ * - We use a value barrier around the bit-selection mask to+ * reduce the risk of compiler-introduced branches.+ * The reference implementation contains the expression+ * `(msg[i] >> j) & 1` which the compiler can reason must+ * be either 0 or 1. */+MLK_INTERNAL_API+void mlk_poly_frommsg(mlk_poly *r, const uint8_t msg[MLKEM_INDCPA_MSGBYTES])+{+ unsigned i;+#if (MLKEM_INDCPA_MSGBYTES != MLKEM_N / 8)+#error "MLKEM_INDCPA_MSGBYTES must be equal to MLKEM_N/8 bytes!"+#endif++ for (i = 0; i < MLKEM_N / 8; i++)+ __loop__(+ invariant(i <= MLKEM_N / 8)+ invariant(array_bound(r->coeffs, 0, 8 * i, 0, MLKEM_Q))+ decreases(MLKEM_N / 8 - i))+ {+ unsigned j;+ for (j = 0; j < 8; j++)+ __loop__(+ invariant(i < MLKEM_N / 8 && j <= 8)+ invariant(array_bound(r->coeffs, 0, 8 * i + j, 0, MLKEM_Q))+ decreases(8 - j))+ {+ /* mlk_ct_sel_int16(MLKEM_Q_HALF, 0, b) is `Decompress_1(b != 0)`+ * as per @[FIPS203, Eq (4.8)]. */++ /* Prevent the compiler from recognizing this as a bit selection */+ uint8_t mask = mlk_value_barrier_u8((uint8_t)(1u << j));+ r->coeffs[8 * i + j] = mlk_ct_sel_int16(MLKEM_Q_HALF, 0, msg[i] & mask);+ }+ }+ mlk_assert_abs_bound(r, MLKEM_N, MLKEM_Q);+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `poly_tomsg()` in the reference implementation @[REF].+ * - In contrast to the reference implementation, we assume+ * unsigned canonical coefficients here.+ * The reference implementation works with coefficients+ * in the range [-(MLKEM_Q-1), MLKEM_Q-1].+ */+MLK_INTERNAL_API+void mlk_poly_tomsg(uint8_t msg[MLKEM_INDCPA_MSGBYTES], const mlk_poly *r)+{+ unsigned i;+ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);++ for (i = 0; i < MLKEM_N / 8; i++)+ __loop__(invariant(i <= MLKEM_N / 8)+ decreases(MLKEM_N / 8 - i))+ {+ unsigned j;+ msg[i] = 0;+ for (j = 0; j < 8; j++)+ __loop__(+ invariant(i <= MLKEM_N / 8 && j <= 8)+ decreases(8 - j))+ {+ uint32_t t = mlk_scalar_compress_d1(r->coeffs[8 * i + j]);+ msg[i] |= (uint8_t)(t << j);+ }+ }+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#else /* !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(compress)++#endif /* MLK_CONFIG_MULTILEVEL_NO_SHARED */
@@ -0,0 +1,613 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ *+ * - [REF]+ * CRYSTALS-Kyber C reference implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/ref+ */++#ifndef MLK_COMPRESS_H+#define MLK_COMPRESS_H+++#include "cbmc.h"+#include "common.h"+#include "debug.h"+#include "poly.h"+#include "verify.h"++/*+ * The multiplication in this routine will exceed UINT32_MAX+ * and wrap around for large values of u. This is expected and required.+ */+#ifdef CBMC+#pragma CPROVER check push+#pragma CPROVER check disable "unsigned-overflow"+#endif++/**+ * Compute round(u * 2 / MLKEM_Q).+ *+ * @spec{Compress_1 from @[FIPS203, Eq (4.7)].}+ *+ * @reference{Part of poly_tomsg() in the reference implementation @[REF].}+ *+ * @param u Unsigned canonical modulus modulo MLKEM_Q to be compressed.+ *+ * @return Compressed value.+ */+static MLK_INLINE uint8_t mlk_scalar_compress_d1(int16_t u)+__contract__(+ requires(0 <= u && u <= MLKEM_Q - 1)+ ensures(return_value < 2)+ ensures(return_value == (((uint32_t)u * 2 + MLKEM_Q / 2) / MLKEM_Q) % 2) )+{+ /* Compute as follows:+ * ```+ * round(u * 2 / MLKEM_Q)+ * = round(u * 2 * (2^31 / MLKEM_Q) / 2^31)+ * ~= round(u * 2 * round(2^31 / MLKEM_Q) / 2^31)+ * ```+ */+ /* check-magic: 1290168 == 2*round(2^31 / MLKEM_Q) */+ uint32_t d0 = (uint32_t)u * 1290168;+ /* Unsigned shifting by 31 positions leaves only the top bit. */+ return (uint8_t)((d0 + ((uint32_t)1u << 30)) >> 31);+}+#ifdef CBMC+#pragma CPROVER check pop+#endif++/*+ * The multiplication in this routine will exceed UINT32_MAX+ * and wrap around for large values of u. This is expected and required.+ */+#ifdef CBMC+#pragma CPROVER check push+#pragma CPROVER check disable "unsigned-overflow"+#endif++/**+ * Compute round(u * 16 / MLKEM_Q) % 16.+ *+ * @spec{Compress_4 from @[FIPS203, Eq (4.7)].}+ *+ * @reference{Embedded into `poly_compress()` in the reference+ * implementation @[REF].}+ *+ * @param u Unsigned canonical modulus modulo MLKEM_Q to be compressed.+ *+ * @return Compressed value.+ */+static MLK_INLINE uint8_t mlk_scalar_compress_d4(int16_t u)+__contract__(+ requires(0 <= u && u <= MLKEM_Q - 1)+ ensures(return_value < 16)+ ensures(return_value == (((uint32_t)u * 16 + MLKEM_Q / 2) / MLKEM_Q) % 16))+{+ /* Compute as follows:+ * ```+ * round(u * 16 / MLKEM_Q)+ * = round(u * 16 * (2^28 / MLKEM_Q) / 2^28)+ * ~= round(u * 16 * round(2^28 / MLKEM_Q) / 2^28)+ * ```+ */+ /* check-magic: 1290160 == 16 * round(2^28 / MLKEM_Q) */+ uint32_t d0 = (uint32_t)u * 1290160;+ /* The return value is < 16, so not altered by the conversion to uint8_t. */+ return (uint8_t)((d0 + ((uint32_t)1u << 27)) >> 28); /* round(d0/2^28) */+}+#ifdef CBMC+#pragma CPROVER check pop+#endif++/**+ * Compute round(u * MLKEM_Q / 16).+ *+ * @spec{Decompress_4 from @[FIPS203, Eq (4.8)].}+ *+ * @reference{Embedded into `poly_decompress()` in the reference+ * implementation @[REF].}+ *+ * @param u Unsigned canonical modulus modulo 16 to be decompressed.+ *+ * @return Decompressed value.+ */+static MLK_INLINE int16_t mlk_scalar_decompress_d4(uint8_t u)+__contract__(+ requires(0 <= u && u < 16)+ ensures(return_value <= (MLKEM_Q - 1))+)+{+ /* The return value is in 0..MLKEM_Q-1, hence not altered by the+ * conversion to int16_t. */+ return (int16_t)((((uint32_t)u * MLKEM_Q) + 8) >> 4);+}++/*+ * The multiplication in this routine will exceed UINT32_MAX+ * and wrap around for large values of u. This is expected and required.+ */+#ifdef CBMC+#pragma CPROVER check push+#pragma CPROVER check disable "unsigned-overflow"+#endif++/**+ * Compute round(u * 32 / MLKEM_Q) % 32.+ *+ * @spec{Compress_5 from @[FIPS203, Eq (4.7)].}+ *+ * @reference{Embedded into `poly_compress()` in the reference+ * implementation @[REF].}+ *+ * @param u Unsigned canonical modulus modulo MLKEM_Q to be compressed.+ *+ * @return Compressed value.+ */+static MLK_INLINE uint8_t mlk_scalar_compress_d5(int16_t u)+__contract__(+ requires(0 <= u && u <= MLKEM_Q - 1)+ ensures(return_value < 32)+ ensures(return_value == (((uint32_t)u * 32 + MLKEM_Q / 2) / MLKEM_Q) % 32) )+{+ /* Compute as follows:+ * ```+ * round(u * 32 / MLKEM_Q)+ * = round(u * 32 * (2^27 / MLKEM_Q) / 2^27)+ * ~= round(u * 32 * round(2^27 / MLKEM_Q) / 2^27)+ * ```+ */+ /* check-magic: 1290176 == 2^5 * round(2^27 / MLKEM_Q) */+ uint32_t d0 = (uint32_t)u * 1290176;+ /* The return value is < 32, so not altered by the conversion to uint8_t. */+ return (uint8_t)((d0 + ((uint32_t)1u << 26)) >> 27); /* round(d0/2^27) */+}+#ifdef CBMC+#pragma CPROVER check pop+#endif++/**+ * Compute round(u * MLKEM_Q / 32).+ *+ * @spec{Decompress_5 from @[FIPS203, Eq (4.8)].}+ *+ * @reference{Embedded into `poly_decompress()` in the reference+ * implementation @[REF].}+ *+ * @param u Unsigned canonical modulus modulo 32 to be decompressed.+ *+ * @return Decompressed value.+ */+static MLK_INLINE int16_t mlk_scalar_decompress_d5(uint8_t u)+__contract__(+ requires(0 <= u && u < 32)+ ensures(0 <= return_value && return_value <= MLKEM_Q - 1)+)+{+ /* The return value is in 0..MLKEM_Q-1, hence not altered by the+ * conversion to int16_t. */+ return (int16_t)((((uint32_t)u * MLKEM_Q) + 16) >> 5);+}++/*+ * The multiplication in this routine will exceed UINT32_MAX+ * and wrap around for large values of u. This is expected and required.+ */+#ifdef CBMC+#pragma CPROVER check push+#pragma CPROVER check disable "unsigned-overflow"+#endif++/**+ * Compute round(u * 2**10 / MLKEM_Q) % 2**10.+ *+ * @spec{Compress_10 from @[FIPS203, Eq (4.7)].}+ *+ * @reference{Embedded into `polyvec_compress()` in the reference+ * implementation @[REF].}+ *+ * @param u Unsigned canonical modulus modulo MLKEM_Q to be compressed.+ *+ * @return Compressed value.+ */+static MLK_INLINE uint16_t mlk_scalar_compress_d10(int16_t u)+__contract__(+ requires(0 <= u && u <= MLKEM_Q - 1)+ ensures(return_value < (1u << 10))+ ensures(return_value == (((uint32_t)u * (1u << 10) + MLKEM_Q / 2) / MLKEM_Q) % (1 << 10)))+{+ /* Compute as follows:+ * ```+ * round(u * 1024 / MLKEM_Q)+ * = round(u * 1024 * (2^33 / MLKEM_Q) / 2^33)+ * ~= round(u * 1024 * round(2^33 / MLKEM_Q) / 2^33)+ * ```+ */+ /* check-magic: 2642263040 == 2^10 * round(2^33 / MLKEM_Q) */+ uint64_t d0 = (uint64_t)u * 2642263040;+ d0 = (d0 + ((uint64_t)1u << 32)) >> 33; /* round(d0/2^33) */+ return (d0 & 0x3FF);+}+#ifdef CBMC+#pragma CPROVER check pop+#endif++/**+ * Compute round(u * MLKEM_Q / 1024).+ *+ * @spec{Decompress_10 from @[FIPS203, Eq (4.8)].}+ *+ * @reference{Embedded into `polyvec_decompress()` in the reference+ * implementation @[REF].}+ *+ * @param u Unsigned canonical modulus modulo 1024 to be decompressed.+ *+ * @return Decompressed value.+ */+static MLK_INLINE int16_t mlk_scalar_decompress_d10(uint16_t u)+__contract__(+ requires(0 <= u && u < 1024)+ ensures(0 <= return_value && return_value <= (MLKEM_Q - 1))+)+{+ /* The return value is in 0..MLKEM_Q-1, hence not altered by the+ * conversion to int16_t. */+ return (int16_t)((((uint32_t)u * MLKEM_Q) + 512) >> 10);+}++/*+ * The multiplication in this routine will exceed UINT32_MAX+ * and wrap around for large values of u. This is expected and required.+ */+#ifdef CBMC+#pragma CPROVER check push+#pragma CPROVER check disable "unsigned-overflow"+#endif++/**+ * Compute round(u * 2**11 / MLKEM_Q) % 2**11.+ *+ * @spec{Compress_11 from @[FIPS203, Eq (4.7)].}+ *+ * @reference{Embedded into `polyvec_compress()` in the reference+ * implementation @[REF].}+ *+ * @param u Unsigned canonical modulus modulo MLKEM_Q to be compressed.+ *+ * @return Compressed value.+ */+static MLK_INLINE uint16_t mlk_scalar_compress_d11(int16_t u)+__contract__(+ requires(0 <= u && u <= MLKEM_Q - 1)+ ensures(return_value < (1u << 11))+ ensures(return_value == (((uint32_t)u * (1u << 11) + MLKEM_Q / 2) / MLKEM_Q) % (1 << 11)))+{+ /* Compute as follows:+ * ```+ * round(u * 2048 / MLKEM_Q)+ * = round(u * 2048 * (2^33 / MLKEM_Q) / 2^33)+ * ~= round(u * 2048 * round(2^33 / MLKEM_Q) / 2^33)+ * ```+ */+ /* check-magic: 5284526080 == 2^11 * round(2^33 / MLKEM_Q) */+ uint64_t d0 = (uint64_t)u * 5284526080;+ d0 = (d0 + ((uint64_t)1u << 32)) >> 33; /* round(d0/2^33) */+ return (d0 & 0x7FF);+}+#ifdef CBMC+#pragma CPROVER check pop+#endif++/**+ * Compute round(u * MLKEM_Q / 2048).+ *+ * @spec{Decompress_11 from @[FIPS203, Eq (4.8)].}+ *+ * @reference{Embedded into `polyvec_decompress()` in the reference+ * implementation @[REF].}+ *+ * @param u Unsigned canonical modulus modulo 2048 to be decompressed.+ *+ * @return Decompressed value.+ */+static MLK_INLINE int16_t mlk_scalar_decompress_d11(uint16_t u)+__contract__(+ requires(0 <= u && u < 2048)+ ensures(0 <= return_value && return_value <= (MLKEM_Q - 1))+)+{+ /* The return value is in 0..MLKEM_Q-1, hence not altered by the+ * conversion to int16_t. */+ return (int16_t)((((uint32_t)u * MLKEM_Q) + 1024) >> 11);+}++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || (MLKEM_K == 2 || MLKEM_K == 3)+#define mlk_poly_compress_d4 MLK_NAMESPACE(poly_compress_d4)+/**+ * Compression (4 bits) and subsequent serialization of a polynomial.+ *+ * @spec{Implements `ByteEncode_4 (Compress_4 (a))`: ByteEncode_d+ * @[FIPS203, Algorithm 5], Compress_d @[FIPS203, Eq (4.7)], extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `ByteEncode_{d_v} (Compress_{d_v} (v))` appears in @[FIPS203, Algorithm+ * 14 (K-PKE.Encrypt), L23], where `d_v=4` for ML-KEM-{512,768} @[FIPS203,+ * Table 2].}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D4+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ */+MLK_INTERNAL_API+void mlk_poly_compress_d4(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D4],+ const mlk_poly *a);++#define mlk_poly_compress_d10 MLK_NAMESPACE(poly_compress_d10)+/**+ * Compression (10 bits) and subsequent serialization of a polynomial.+ *+ * @spec{Implements `ByteEncode_10 (Compress_10 (a))`: ByteEncode_d+ * @[FIPS203, Algorithm 5], Compress_d @[FIPS203, Eq (4.7)], extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `ByteEncode_{d_u} (Compress_{d_u} (u))` appears in @[FIPS203, Algorithm+ * 14 (K-PKE.Encrypt), L22], where `d_u=10` for ML-KEM-{512,768} @[FIPS203,+ * Table 2].}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D10+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ */+MLK_INTERNAL_API+void mlk_poly_compress_d10(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D10],+ const mlk_poly *a);++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_decompress_d4 MLK_NAMESPACE(poly_decompress_d4)+/**+ * De-serialization and subsequent decompression (4 bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_d4.+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @spec{Implements `Decompress_4 (ByteDecode_4 (a))`: ByteDecode_d+ * @[FIPS203, Algorithm 6], Decompress_d @[FIPS203, Eq (4.8)], extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `Decompress_{d_v} (ByteDecode_{d_v} (v))` appears in @[FIPS203, Algorithm+ * 15 (K-PKE.Decrypt), L4], where `d_v=4` for ML-KEM-{512,768} @[FIPS203,+ * Table 2].}+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D4+ * bytes).+ */+MLK_INTERNAL_API+void mlk_poly_decompress_d4(mlk_poly *r,+ const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D4]);++#define mlk_poly_decompress_d10 MLK_NAMESPACE(poly_decompress_d10)+/**+ * De-serialization and subsequent decompression (10 bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_d10.+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @spec{Implements `Decompress_10 (ByteDecode_10 (a))`: ByteDecode_d+ * @[FIPS203, Algorithm 6], Decompress_d @[FIPS203, Eq (4.8)], extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `Decompress_{d_u} (ByteDecode_{d_u} (u))` appears in @[FIPS203, Algorithm+ * 15 (K-PKE.Decrypt), L3], where `d_u=10` for ML-KEM-{512,768} @[FIPS203,+ * Table 2].}+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D10+ * bytes).+ */+MLK_INTERNAL_API+void mlk_poly_decompress_d10(mlk_poly *r,+ const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D10]);+#endif /* !MLK_CONFIG_NO_DECAPS_API */+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 || MLKEM_K == 3 */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4+#define mlk_poly_compress_d5 MLK_NAMESPACE(poly_compress_d5)+/**+ * Compression (5 bits) and subsequent serialization of a polynomial.+ *+ * @spec{Implements `ByteEncode_5 (Compress_5 (a))`: ByteEncode_d+ * @[FIPS203, Algorithm 5], Compress_d @[FIPS203, Eq (4.7)], extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `ByteEncode_{d_v} (Compress_{d_v} (v))` appears in @[FIPS203, Algorithm+ * 14 (K-PKE.Encrypt), L23], where `d_v=5` for ML-KEM-1024 @[FIPS203,+ * Table 2].}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D5+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ */+MLK_INTERNAL_API+void mlk_poly_compress_d5(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D5],+ const mlk_poly *a);++#define mlk_poly_compress_d11 MLK_NAMESPACE(poly_compress_d11)+/**+ * Compression (11 bits) and subsequent serialization of a polynomial.+ *+ * @spec{`ByteEncode_11 (Compress_11 (a))`: ByteEncode_d @[FIPS203,+ * Algorithm 5], Compress_d @[FIPS203, Eq (4.7)], extended to vectors as+ * per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `ByteEncode_{d_u} (Compress_{d_u} (u))` appears in @[FIPS203, Algorithm+ * 14 (K-PKE.Encrypt), L22], where `d_u=11` for ML-KEM-1024 @[FIPS203,+ * Table 2].}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D11+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ */+MLK_INTERNAL_API+void mlk_poly_compress_d11(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D11],+ const mlk_poly *a);++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_decompress_d5 MLK_NAMESPACE(poly_decompress_d5)+/**+ * De-serialization and subsequent decompression (5 bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_d5.+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @spec{Implements `Decompress_5 (ByteDecode_5 (a))`: ByteDecode_d+ * @[FIPS203, Algorithm 6], Decompress_d @[FIPS203, Eq (4.8)], extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `Decompress_{d_v} (ByteDecode_{d_v} (v))` appears in @[FIPS203, Algorithm+ * 15 (K-PKE.Decrypt), L4], where `d_v=5` for ML-KEM-1024 @[FIPS203,+ * Table 2].}+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D5+ * bytes).+ */+MLK_INTERNAL_API+void mlk_poly_decompress_d5(mlk_poly *r,+ const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D5]);++#define mlk_poly_decompress_d11 MLK_NAMESPACE(poly_decompress_d11)+/**+ * De-serialization and subsequent decompression (11 bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_d11.+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @spec{Implements `Decompress_11 (ByteDecode_11 (a))`: ByteDecode_d+ * @[FIPS203, Algorithm 6], Decompress_d @[FIPS203, Eq (4.8)], extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `Decompress_{d_u} (ByteDecode_{d_u} (u))` appears in @[FIPS203, Algorithm+ * 15 (K-PKE.Decrypt), L3], where `d_u=11` for ML-KEM-1024 @[FIPS203,+ * Table 2].}+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D11+ * bytes).+ */+MLK_INTERNAL_API+void mlk_poly_decompress_d11(mlk_poly *r,+ const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D11]);+#endif /* !MLK_CONFIG_NO_DECAPS_API */+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4 */+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API) || !defined(MLK_CONFIG_NO_ENCAPS_API)+#define mlk_poly_tobytes MLK_NAMESPACE(poly_tobytes)+/**+ * Serialization of a polynomial. Signed coefficients are converted to+ * unsigned form before serialization.+ *+ * @spec{Implements ByteEncode_12 @[FIPS203, Algorithm 5]. Extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].}+ *+ * @param[out] r Output byte array (of MLKEM_POLYBYTES bytes).+ * @param[in] a Input polynomial, with each coefficient in the range+ * [0,1,..,MLKEM_Q-1].+ */+MLK_INTERNAL_API+void mlk_poly_tobytes(uint8_t r[MLKEM_POLYBYTES], const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYBYTES))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYBYTES))+);+#endif /* !MLK_CONFIG_NO_KEYPAIR_API || !MLK_CONFIG_NO_ENCAPS_API */+++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_frombytes MLK_NAMESPACE(poly_frombytes)+/**+ * De-serialization of a polynomial.+ *+ * @spec{Implements ByteDecode_12 @[FIPS203, Algorithm 6]. Extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].}+ *+ * @param[out] r Output polynomial, with each coefficient unsigned and in+ * the range 0..4095.+ * @param[in] a Input byte array (of MLKEM_POLYBYTES bytes).+ */+MLK_INTERNAL_API+void mlk_poly_frombytes(mlk_poly *r, const uint8_t a[MLKEM_POLYBYTES])+__contract__(+ requires(memory_no_alias(a, MLKEM_POLYBYTES))+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT))+);+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */+++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_frommsg MLK_NAMESPACE(poly_frommsg)+/**+ * Convert a 32-byte message to a polynomial.+ *+ * @spec{Implements `Decompress_1 (ByteDecode_1 (a))`: ByteDecode_d+ * @[FIPS203, Algorithm 6], Decompress_d @[FIPS203, Eq (4.8)], extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `Decompress_1 (ByteDecode_1 (w))` appears in @[FIPS203, Algorithm 15+ * (K-PKE.Encrypt), L20].}+ *+ * @param[out] r Output polynomial.+ * @param[in] msg Input message.+ */+MLK_INTERNAL_API+void mlk_poly_frommsg(mlk_poly *r, const uint8_t msg[MLKEM_INDCPA_MSGBYTES])+__contract__(+ requires(memory_no_alias(msg, MLKEM_INDCPA_MSGBYTES))+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+);+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_tomsg MLK_NAMESPACE(poly_tomsg)+/**+ * Convert a polynomial to a 32-byte message.+ *+ * @spec{Implements `ByteEncode_1 (Compress_1 (a))`: ByteEncode_d+ * @[FIPS203, Algorithm 5], Compress_d @[FIPS203, Eq (4.7)], extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays].+ * `ByteEncode_1 (Compress_1 (w))` appears in @[FIPS203, Algorithm 14+ * (K-PKE.Decrypt), L7].}+ *+ * @param[out] msg Output message.+ * @param[in] r Input polynomial. Coefficients must be unsigned canonical.+ */+MLK_INTERNAL_API+void mlk_poly_tomsg(uint8_t msg[MLKEM_INDCPA_MSGBYTES], const mlk_poly *r)+__contract__(+ requires(memory_no_alias(msg, MLKEM_INDCPA_MSGBYTES))+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(msg, MLKEM_INDCPA_MSGBYTES))+);+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#endif /* !MLK_COMPRESS_H */
@@ -0,0 +1,51 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_CONTEXT_H+#define MLK_CONTEXT_H++/* This header is included by common.h once the configuration has been pulled+ * in; it is not meant to be included directly. */++/*+ * If the integration wants to provide a context parameter for use in+ * platform-specific hooks, then it should define this parameter.+ *+ * The MLK_CONTEXT_PARAMETERS_n macros are intended to be used with macros+ * defining the function names and expand to either pass or discard the context+ * argument as required by the current build. If there is no context parameter+ * requested then these are removed from the prototypes and from all calls.+ */+#ifdef MLK_CONFIG_CONTEXT_PARAMETER+#define MLK_CONTEXT_PARAMETERS_0(context) (context)+#define MLK_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context)+#define MLK_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context)+#define MLK_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \+ (arg0, arg1, arg2, context)+#define MLK_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \+ (arg0, arg1, arg2, arg3, context)+#else /* MLK_CONFIG_CONTEXT_PARAMETER */+#define MLK_CONTEXT_PARAMETERS_0(context) ()+#define MLK_CONTEXT_PARAMETERS_1(arg0, context) (arg0)+#define MLK_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1)+#define MLK_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2)+#define MLK_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \+ (arg0, arg1, arg2, arg3)+#endif /* !MLK_CONFIG_CONTEXT_PARAMETER */++/* Consume a context parameter carried only for the integration's benefit,+ * avoiding -Wunused-parameter; expands to nothing when no context is+ * configured. */+#if defined(MLK_CONFIG_CONTEXT_PARAMETER)+#define MLK_CONTEXT_UNUSED(context) ((void)(context))+#else+#define MLK_CONTEXT_UNUSED(context) ((void)0)+#endif++#if defined(MLK_CONFIG_CONTEXT_PARAMETER_TYPE) != \+ defined(MLK_CONFIG_CONTEXT_PARAMETER)+#error MLK_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLK_CONFIG_CONTEXT_PARAMETER is defined+#endif++#endif /* !MLK_CONTEXT_H */
@@ -0,0 +1,64 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* NOTE: You can remove this file unless you compile with MLKEM_DEBUG. */++#include "common.h"++#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && defined(MLKEM_DEBUG)+++#include <stdio.h>+#include <stdlib.h>+#include "debug.h"++#define MLK_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] "++void mlk_debug_check_assert(const char *file, int line, const int val)+{+ if (val == 0)+ {+ fprintf(stderr, MLK_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n",+ file, line, val);+ exit(1);+ }+}++void mlk_debug_check_bounds(const char *file, int line, const int16_t *ptr,+ unsigned len, int lower_bound_exclusive,+ int upper_bound_exclusive)+{+ int err = 0;+ unsigned i;+ for (i = 0; i < len; i++)+ {+ int16_t val = ptr[i];+ if (!(val > lower_bound_exclusive && val < upper_bound_exclusive))+ {+ fprintf(+ stderr,+ MLK_DEBUG_ERROR_HEADER+ "Bounds assertion failed: Index %u, value %d out of bounds (%d,%d)\n",+ file, line, i, (int)val, lower_bound_exclusive,+ upper_bound_exclusive);+ err = 1;+ }+ }++ if (err == 1)+ {+ exit(1);+ }+}++#else /* !MLK_CONFIG_MULTILEVEL_NO_SHARED && MLKEM_DEBUG */++MLK_EMPTY_CU(debug)++#endif /* !(!MLK_CONFIG_MULTILEVEL_NO_SHARED && MLKEM_DEBUG) */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef MLK_DEBUG_ERROR_HEADER
@@ -0,0 +1,121 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_DEBUG_H+#define MLK_DEBUG_H+#include "common.h"++#if defined(MLKEM_DEBUG)++/**+ * Check debug assertion.+ *+ * Prints an error message to stderr and calls exit(1) on failure.+ *+ * @param[in] file Filename.+ * @param line Line number.+ * @param val Value asserted to be non-zero.+ */+#define mlk_debug_check_assert MLK_NAMESPACE(mlkem_debug_assert)+void mlk_debug_check_assert(const char *file, int line, const int val);++/**+ * Check whether values in an array of int16_t are within specified bounds.+ *+ * Prints an error message to stderr and calls exit(1) on failure.+ *+ * @param[in] file Filename.+ * @param line Line number.+ * @param[in] ptr Base of array to be checked.+ * @param len Number of int16_t in @p ptr.+ * @param lower_bound_exclusive Exclusive lower bound.+ * @param upper_bound_exclusive Exclusive upper bound.+ */+#define mlk_debug_check_bounds MLK_NAMESPACE(mlkem_debug_check_bounds)+void mlk_debug_check_bounds(const char *file, int line, const int16_t *ptr,+ unsigned len, int lower_bound_exclusive,+ int upper_bound_exclusive);++/* Check assertion, calling exit() upon failure+ *+ * val: Value that's asserted to be non-zero+ */+#define mlk_assert(val) mlk_debug_check_assert(__FILE__, __LINE__, (val))++/* Check bounds in array of int16_t's+ * ptr: Base of int16_t array; will be explicitly cast to int16_t*,+ * so you may pass a byte-compatible type such as mlk_poly or mlk_polyvec.+ * len: Number of int16_t in array+ * value_lb: Inclusive lower value bound+ * value_ub: Exclusive upper value bound */+#define mlk_assert_bound(ptr, len, value_lb, value_ub) \+ mlk_debug_check_bounds(__FILE__, __LINE__, (const int16_t *)(ptr), (len), \+ (value_lb) - 1, (value_ub))++/* Check absolute bounds in array of int16_t's+ * ptr: Base of array, expression of type int16_t*+ * len: Number of int16_t in array+ * value_abs_bd: Exclusive absolute upper bound */+#define mlk_assert_abs_bound(ptr, len, value_abs_bd) \+ mlk_assert_bound((ptr), (len), (-(value_abs_bd) + 1), (value_abs_bd))++/* Version of bounds assertions for 2-dimensional arrays */+#define mlk_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \+ mlk_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub))++#define mlk_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \+ mlk_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd))++/* When running CBMC, convert debug assertions into proof obligations */+#elif defined(CBMC)+#include "cbmc.h"++#define mlk_assert(val) cassert(val)++#define mlk_assert_bound(ptr, len, value_lb, value_ub) \+ cassert(array_bound(((int16_t *)(ptr)), 0, (len), (value_lb), (value_ub)))++#define mlk_assert_abs_bound(ptr, len, value_abs_bd) \+ cassert(array_abs_bound(((int16_t *)(ptr)), 0, (len), (value_abs_bd)))++/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't+ * just use a single flattened array_bound(...) here. */+#define mlk_assert_bound_2d(ptr, M, N, value_lb, value_ub) \+ cassert(forall(kN, 0, (M), \+ array_bound(&((int16_t (*)[(N)])(ptr))[kN][0], 0, (N), \+ (value_lb), (value_ub))))++#define mlk_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \+ cassert(forall(kN, 0, (M), \+ array_abs_bound(&((int16_t (*)[(N)])(ptr))[kN][0], 0, (N), \+ (value_abs_bd))))++#else /* !MLKEM_DEBUG && CBMC */++#define mlk_assert(val) \+ do \+ { \+ } while (0)+#define mlk_assert_bound(ptr, len, value_lb, value_ub) \+ do \+ { \+ } while (0)+#define mlk_assert_abs_bound(ptr, len, value_abs_bd) \+ do \+ { \+ } while (0)++#define mlk_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \+ do \+ { \+ } while (0)++#define mlk_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \+ do \+ { \+ } while (0)+++#endif /* !MLKEM_DEBUG && !CBMC */+#endif /* !MLK_DEBUG_H */
@@ -0,0 +1,249 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ *+ * - [mupq]+ * Common files for pqm4, pqm3, pqriscv+ * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen+ * https://github.com/mupq/mupq+ *+ * - [supercop]+ * SUPERCOP benchmarking framework+ * Daniel J. Bernstein+ * http://bench.cr.yp.to/supercop.html+ *+ * - [tweetfips]+ * 'tweetfips202' FIPS202 implementation+ * Van Assche, Bernstein, Schwabe+ * https://keccak.team/2015/tweetfips202.html+ */++/* Based on the CC0 implementation from @[mupq] and the public domain+ * implementation @[supercop, crypto_hash/keccakc512/simple/]+ * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */++#include "../common.h"+#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+++#include "../verify.h"+#include "fips202.h"+#include "keccakf1600.h"++/**+ * Absorb step of Keccak; non-incremental, starts by zeroeing the state.+ *+ * @warning Must only be called once.+ *+ * @param[out] s Pointer to (uninitialized) output Keccak state.+ * @param r Rate in bytes (e.g., 168 for SHAKE128).+ * @param[in] m Input to be absorbed into @p s.+ * @param mlen Length of input in bytes.+ * @param p Domain-separation byte for different Keccak-derived+ * functions.+ */+static void mlk_keccak_absorb_once(uint64_t *s, unsigned r, const uint8_t *m,+ size_t mlen, uint8_t p)+__contract__(+ requires(mlen <= MLK_MAX_BUFFER_SIZE)+ requires(r > 0)+ requires(r <= sizeof(uint64_t) * MLK_KECCAK_LANES)+ requires(memory_no_alias(s, sizeof(uint64_t) * MLK_KECCAK_LANES))+ requires(memory_no_alias(m, mlen))+ assigns(memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES)))+{+ /* Initialize state */+ size_t i;+ for (i = 0; i < 25; ++i)+ __loop__(invariant(i <= 25)+ decreases(25 - i))+ {+ s[i] = 0;+ }++ while (mlen >= r)+ __loop__(+ assigns(mlen, m, memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES))+ invariant(mlen <= loop_entry(mlen))+ invariant(m == loop_entry(m) + (loop_entry(mlen) - mlen))+ decreases(mlen))+ {+ mlk_keccakf1600_xor_bytes(s, m, 0, r);+ mlk_keccakf1600_permute(s);+ mlen -= r;+ m += r;+ }++ /* At this point, mlen < r, so the truncations to unsigned are safe below. */++ if (mlen > 0)+ {+ mlk_keccakf1600_xor_bytes(s, m, 0, (unsigned int)mlen);+ }++ if (mlen == r - 1)+ {+ p |= 128;+ mlk_keccakf1600_xor_bytes(s, &p, (unsigned int)mlen, 1);+ }+ else+ {+ mlk_keccakf1600_xor_bytes(s, &p, (unsigned int)mlen, 1);+ p = 128;+ mlk_keccakf1600_xor_bytes(s, &p, r - 1, 1);+ }+}++/**+ * Block-level Keccak squeeze.+ *+ * @param[out] h Output bytes.+ * @param nblocks Number of blocks to be squeezed.+ * @param[in,out] s Input/output state.+ * @param r Rate in bytes (e.g., 168 for SHAKE128).+ */+static void mlk_keccak_squeezeblocks(uint8_t *h, size_t nblocks, uint64_t *s,+ unsigned r)+__contract__(+ requires(r <= sizeof(uint64_t) * MLK_KECCAK_LANES)+ requires(nblocks <= 8 /* somewhat arbitrary bound */)+ requires(memory_no_alias(s, sizeof(uint64_t) * MLK_KECCAK_LANES))+ requires(memory_no_alias(h, nblocks * r))+ assigns(memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES))+ assigns(memory_slice(h, nblocks * r)))+{+ while (nblocks > 0)+ __loop__(+ assigns(h, nblocks,+ memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES),+ memory_slice(h, nblocks * r))+ invariant(nblocks <= loop_entry(nblocks) &&+ h == loop_entry(h) + r * (loop_entry(nblocks) - nblocks))+ decreases(nblocks))+ {+ mlk_keccakf1600_permute(s);+ mlk_keccakf1600_extract_bytes(s, h, 0, r);+ h += r;+ nblocks--;+ }+}++/**+ * Keccak squeeze; can be called on byte-level.+ *+ * @warning Must only be called once.+ *+ * @param[out] h Output bytes.+ * @param outlen Number of bytes to be squeezed.+ * @param[in,out] s Keccak state.+ * @param r Rate in bytes (e.g., 168 for SHAKE128).+ */+static void mlk_keccak_squeeze_once(uint8_t *h, size_t outlen, uint64_t *s,+ unsigned r)+__contract__(+ requires(outlen <= MLK_MAX_BUFFER_SIZE)+ requires(r > 0)+ requires(r <= sizeof(uint64_t) * MLK_KECCAK_LANES)+ requires(memory_no_alias(s, sizeof(uint64_t) * MLK_KECCAK_LANES))+ requires(memory_no_alias(h, outlen))+ assigns(memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES))+ assigns(memory_slice(h, outlen)))+{+ size_t len;+ while (outlen > 0)+ __loop__(+ assigns(len, h, outlen,+ memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES),+ memory_slice(h, outlen))+ invariant(outlen <= loop_entry(outlen) &&+ h == loop_entry(h) + (loop_entry(outlen) - outlen))+ decreases(outlen))+ {+ mlk_keccakf1600_permute(s);++ if (outlen < r)+ {+ len = outlen;+ }+ else+ {+ len = r;+ }+ mlk_keccakf1600_extract_bytes(s, h, 0, (unsigned int)len);+ h += len;+ outlen -= len;+ }+}++void mlk_shake128_absorb_once(mlk_shake128ctx *state, const uint8_t *input,+ size_t inlen)+{+ mlk_keccak_absorb_once(state->ctx, SHAKE128_RATE, input, inlen, 0x1F);+}++void mlk_shake128_squeezeblocks(uint8_t *output, size_t nblocks,+ mlk_shake128ctx *state)+{+ mlk_keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE128_RATE);+}++void mlk_shake128_init(mlk_shake128ctx *state) { (void)state; }+void mlk_shake128_release(mlk_shake128ctx *state)+{+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(state, sizeof(mlk_shake128ctx));+}++typedef mlk_shake128ctx mlk_shake256ctx;+void mlk_shake256(uint8_t *output, size_t outlen, const uint8_t *input,+ size_t inlen)+{+ mlk_shake256ctx state;+ /* Absorb input */+ mlk_keccak_absorb_once(state.ctx, SHAKE256_RATE, input, inlen, 0x1F);+ /* Squeeze output */+ mlk_keccak_squeeze_once(output, outlen, state.ctx, SHAKE256_RATE);+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(&state, sizeof(state));+}++void mlk_sha3_256(uint8_t *output, const uint8_t *input, size_t inlen)+{+ uint64_t ctx[25];+ /* Absorb input */+ mlk_keccak_absorb_once(ctx, SHA3_256_RATE, input, inlen, 0x06);+ /* Squeeze output */+ mlk_keccak_squeeze_once(output, 32, ctx, SHA3_256_RATE);+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(ctx, sizeof(ctx));+}++void mlk_sha3_512(uint8_t *output, const uint8_t *input, size_t inlen)+{+ uint64_t ctx[25];+ /* Absorb input */+ mlk_keccak_absorb_once(ctx, SHA3_512_RATE, input, inlen, 0x06);+ /* Squeeze output */+ mlk_keccak_squeeze_once(output, 64, ctx, SHA3_512_RATE);+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(ctx, sizeof(ctx));+}++#else /* !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(fips202)++#endif /* MLK_CONFIG_MULTILEVEL_NO_SHARED */
@@ -0,0 +1,144 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_FIPS202_FIPS202_H+#define MLK_FIPS202_FIPS202_H++#include "../cbmc.h"+#include "../common.h"++#define SHAKE128_RATE 168+#define SHAKE256_RATE 136+#define SHA3_256_RATE 136+#define SHA3_384_RATE 104+#define SHA3_512_RATE 72++/** Context for the non-incremental SHAKE128 API. */+typedef struct+{+ uint64_t ctx[25]; /**< Keccak state. */+} MLK_ALIGN mlk_shake128ctx;++#define mlk_shake128_absorb_once MLK_NAMESPACE(shake128_absorb_once)+/**+ * One-shot absorb step of the SHAKE128 XOF.+ *+ * For call-sites (in mlkem-native):+ * - This function MUST ONLY be called straight after mlk_shake128_init().+ * - This function MUST ONLY be called once.+ *+ * Consequently, for providers of custom FIPS202 code to be used with+ * mlkem-native:+ * - You may assume that the input context is freshly initialized via+ * mlk_shake128_init().+ * - You may assume that this function is called exactly once.+ *+ * @param[in,out] state SHAKE128 context.+ * @param[in] input Input to be absorbed into the state.+ * @param inlen Length of input in bytes.+ */+void mlk_shake128_absorb_once(mlk_shake128ctx *state, const uint8_t *input,+ size_t inlen)+__contract__(+ requires(inlen <= MLK_MAX_BUFFER_SIZE)+ requires(memory_no_alias(state, sizeof(mlk_shake128ctx)))+ requires(memory_no_alias(input, inlen))+ assigns(memory_slice(state, sizeof(mlk_shake128ctx)))+);++#define mlk_shake128_squeezeblocks MLK_NAMESPACE(shake128_squeezeblocks)+/**+ * Squeeze step of SHAKE128 XOF. Squeezes full blocks of SHAKE128_RATE bytes+ * each. Modifies the state. Can be called multiple times to keep squeezing,+ * i.e., is incremental.+ *+ * @param[out] output Output blocks.+ * @param nblocks Number of blocks to be squeezed (written to output).+ * @param[in,out] state Keccak state.+ */+void mlk_shake128_squeezeblocks(uint8_t *output, size_t nblocks,+ mlk_shake128ctx *state)+__contract__(+ requires(nblocks <= 8 /* somewhat arbitrary bound */)+ requires(memory_no_alias(state, sizeof(mlk_shake128ctx)))+ requires(memory_no_alias(output, nblocks * SHAKE128_RATE))+ assigns(memory_slice(output, nblocks * SHAKE128_RATE), memory_slice(state, sizeof(mlk_shake128ctx)))+);++#define mlk_shake128_init MLK_NAMESPACE(shake128_init)+void mlk_shake128_init(mlk_shake128ctx *state);++#define mlk_shake128_release MLK_NAMESPACE(shake128_release)+void mlk_shake128_release(mlk_shake128ctx *state);++/* One-stop SHAKE256 call. Aliasing between input and+ * output is not permitted */+#define mlk_shake256 MLK_NAMESPACE(shake256)+/**+ * SHAKE256 XOF with non-incremental API.+ *+ * @param[out] output Output buffer.+ * @param outlen Requested output length in bytes.+ * @param[in] input Input buffer.+ * @param inlen Length of input in bytes.+ */+void mlk_shake256(uint8_t *output, size_t outlen, const uint8_t *input,+ size_t inlen)+__contract__(+ requires(inlen <= MLK_MAX_BUFFER_SIZE)+ requires(outlen <= MLK_MAX_BUFFER_SIZE)+ requires(memory_no_alias(input, inlen))+ requires(memory_no_alias(output, outlen))+ assigns(memory_slice(output, outlen))+);++/* One-stop SHA3_256 call. Aliasing between input and+ * output is not permitted */+#define SHA3_256_HASHBYTES 32+#define mlk_sha3_256 MLK_NAMESPACE(sha3_256)+/**+ * SHA3-256 with non-incremental API.+ *+ * @param[out] output Output buffer.+ * @param[in] input Input buffer.+ * @param inlen Length of input in bytes.+ */+void mlk_sha3_256(uint8_t *output, const uint8_t *input, size_t inlen)+__contract__(+ requires(inlen <= MLK_MAX_BUFFER_SIZE)+ requires(memory_no_alias(input, inlen))+ requires(memory_no_alias(output, SHA3_256_HASHBYTES))+ assigns(memory_slice(output, SHA3_256_HASHBYTES))+);++/* One-stop SHA3_512 call. Aliasing between input and+ * output is not permitted */+#define SHA3_512_HASHBYTES 64+#define mlk_sha3_512 MLK_NAMESPACE(sha3_512)+/**+ * SHA3-512 with non-incremental API.+ *+ * @param[out] output Output buffer.+ * @param[in] input Input buffer.+ * @param inlen Length of input in bytes.+ */+void mlk_sha3_512(uint8_t *output, const uint8_t *input, size_t inlen)+__contract__(+ requires(inlen <= MLK_MAX_BUFFER_SIZE)+ requires(memory_no_alias(input, inlen))+ requires(memory_no_alias(output, SHA3_512_HASHBYTES))+ assigns(memory_slice(output, SHA3_512_HASHBYTES))+);++#if !defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202) || \+ !defined(MLK_USE_NATIVE_FIPS202_X4)+/* If you provide your own FIPS-202 implementation where the x4-+ * Keccak-f1600-x4 implementation falls back to 4-fold Keccak-f1600,+ * set this to gain a small speedup. */+#define FIPS202_X4_DEFAULT_IMPLEMENTATION+#endif /* !MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 || !MLK_USE_NATIVE_FIPS202_X4 \+ */+++#endif /* !MLK_FIPS202_FIPS202_H */
@@ -0,0 +1,207 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#include "../common.h"+#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#include "../verify.h"+#include "fips202.h"+#include "fips202x4.h"+#include "keccakf1600.h"++typedef mlk_shake128x4ctx mlk_shake256x4_ctx;++static void mlk_keccak_absorb_once_x4(uint64_t *s, unsigned r,+ const uint8_t *in0, const uint8_t *in1,+ const uint8_t *in2, const uint8_t *in3,+ size_t inlen, uint8_t p)+__contract__(+ requires(inlen <= MLK_MAX_BUFFER_SIZE)+ requires(memory_no_alias(s, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+ requires(r > 0)+ requires(r <= sizeof(uint64_t) * MLK_KECCAK_LANES)+ requires(memory_no_alias(in0, inlen))+ requires(memory_no_alias(in1, inlen))+ requires(memory_no_alias(in2, inlen))+ requires(memory_no_alias(in3, inlen))+ assigns(memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY)))+{+ while (inlen >= r)+ __loop__(+ assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+ invariant(inlen <= loop_entry(inlen))+ invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen))+ invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen))+ invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen))+ invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))+ decreases(inlen))+ {+ mlk_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r);+ mlk_keccakf1600x4_permute(s);++ in0 += r;+ in1 += r;+ in2 += r;+ in3 += r;+ inlen -= r;+ }++ /* At this point, inlen < r, so the truncations to unsigned are safe below. */++ if (inlen > 0)+ {+ mlk_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned int)inlen);+ }++ if (inlen == r - 1)+ {+ p |= 128;+ mlk_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned int)inlen, 1);+ }+ else+ {+ mlk_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned int)inlen, 1);+ p = 128;+ mlk_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1);+ }+}++static void mlk_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1,+ uint8_t *out2, uint8_t *out3,+ size_t nblocks, uint64_t *s, unsigned r)+__contract__(+ requires(r <= sizeof(uint64_t) * MLK_KECCAK_LANES)+ requires(r == SHAKE128_RATE || r == SHAKE256_RATE)+ requires(nblocks <= (MLK_MAX_BUFFER_SIZE / SHAKE256_RATE))+ requires(memory_no_alias(s, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+ requires(memory_no_alias(out0, nblocks * r))+ requires(memory_no_alias(out1, nblocks * r))+ requires(memory_no_alias(out2, nblocks * r))+ requires(memory_no_alias(out3, nblocks * r))+ assigns(memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+ assigns(memory_slice(out0, nblocks * r))+ assigns(memory_slice(out1, nblocks * r))+ assigns(memory_slice(out2, nblocks * r))+ assigns(memory_slice(out3, nblocks * r)))+{+ size_t current_offset = 0;+ while (nblocks > 0)+ __loop__(+ assigns(nblocks, current_offset,+ memory_slice(s, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY),+ memory_slice(out0, nblocks * r),+ memory_slice(out1, nblocks * r),+ memory_slice(out2, nblocks * r),+ memory_slice(out3, nblocks * r))+ invariant(nblocks <= loop_entry(nblocks))+ invariant(current_offset == (loop_entry(nblocks) - nblocks) * r)+ decreases(nblocks))+ {+ mlk_keccakf1600x4_permute(s);+ mlk_keccakf1600x4_extract_bytes(+ s, &out0[current_offset], &out1[current_offset], &out2[current_offset],+ &out3[current_offset], 0, r);+ current_offset += r;+ nblocks--;+ }+}++void mlk_shake128x4_absorb_once(mlk_shake128x4ctx *state, const uint8_t *in0,+ const uint8_t *in1, const uint8_t *in2,+ const uint8_t *in3, size_t inlen)+{+ mlk_memset(state, 0, sizeof(mlk_shake128x4ctx));+ mlk_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3,+ inlen, 0x1F);+}++void mlk_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2,+ uint8_t *out3, size_t nblocks,+ mlk_shake128x4ctx *state)+{+ mlk_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx,+ SHAKE128_RATE);+}++void mlk_shake128x4_init(mlk_shake128x4ctx *state) { (void)state; }+void mlk_shake128x4_release(mlk_shake128x4ctx *state)+{+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(state, sizeof(mlk_shake128x4ctx));+}++static void mlk_shake256x4_absorb_once(mlk_shake256x4_ctx *state,+ const uint8_t *in0, const uint8_t *in1,+ const uint8_t *in2, const uint8_t *in3,+ size_t inlen)+{+ mlk_memset(state, 0, sizeof(mlk_shake128x4ctx));+ mlk_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3,+ inlen, 0x1F);+}++static void mlk_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1,+ uint8_t *out2, uint8_t *out3,+ size_t nblocks,+ mlk_shake256x4_ctx *state)+{+ mlk_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx,+ SHAKE256_RATE);+}++void mlk_shake256x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3,+ size_t outlen, const uint8_t *in0, const uint8_t *in1,+ const uint8_t *in2, const uint8_t *in3, size_t inlen)+{+ mlk_shake256x4_ctx statex;+ size_t nblocks = outlen / SHAKE256_RATE;+ uint8_t tmp0[SHAKE256_RATE];+ uint8_t tmp1[SHAKE256_RATE];+ uint8_t tmp2[SHAKE256_RATE];+ uint8_t tmp3[SHAKE256_RATE];++ mlk_shake256x4_absorb_once(&statex, in0, in1, in2, in3, inlen);+ mlk_shake256x4_squeezeblocks(out0, out1, out2, out3, nblocks, &statex);++ out0 += nblocks * SHAKE256_RATE;+ out1 += nblocks * SHAKE256_RATE;+ out2 += nblocks * SHAKE256_RATE;+ out3 += nblocks * SHAKE256_RATE;++ outlen -= nblocks * SHAKE256_RATE;++ if (outlen)+ {+ mlk_shake256x4_squeezeblocks(tmp0, tmp1, tmp2, tmp3, 1, &statex);+ mlk_memcpy(out0, tmp0, outlen);+ mlk_memcpy(out1, tmp1, outlen);+ mlk_memcpy(out2, tmp2, outlen);+ mlk_memcpy(out3, tmp3, outlen);+ }++ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(&statex, sizeof(statex));+ mlk_zeroize(tmp0, sizeof(tmp0));+ mlk_zeroize(tmp1, sizeof(tmp1));+ mlk_zeroize(tmp2, sizeof(tmp2));+ mlk_zeroize(tmp3, sizeof(tmp3));+}++#else /* !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(fips202x4)++#endif /* MLK_CONFIG_MULTILEVEL_NO_SHARED */
@@ -0,0 +1,81 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_FIPS202_FIPS202X4_H+#define MLK_FIPS202_FIPS202X4_H+++#include "../cbmc.h"+#include "../common.h"++#include "fips202.h"+#include "keccakf1600.h"++/** Context for the non-incremental 4-way SHAKE128 API. */+typedef struct+{+ uint64_t ctx[MLK_KECCAK_LANES *+ MLK_KECCAK_WAY]; /**< 4-way Keccak state, stored sequentially. */+} MLK_ALIGN mlk_shake128x4ctx;++#define mlk_shake128x4_absorb_once MLK_NAMESPACE(shake128x4_absorb_once)+void mlk_shake128x4_absorb_once(mlk_shake128x4ctx *state, const uint8_t *in0,+ const uint8_t *in1, const uint8_t *in2,+ const uint8_t *in3, size_t inlen)+__contract__(+ requires(inlen <= MLK_MAX_BUFFER_SIZE)+ requires(memory_no_alias(state, sizeof(mlk_shake128x4ctx)))+ requires(memory_no_alias(in0, inlen))+ requires(memory_no_alias(in1, inlen))+ requires(memory_no_alias(in2, inlen))+ requires(memory_no_alias(in3, inlen))+ assigns(memory_slice(state, sizeof(mlk_shake128x4ctx)))+);++#define mlk_shake128x4_squeezeblocks MLK_NAMESPACE(shake128x4_squeezeblocks)+void mlk_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2,+ uint8_t *out3, size_t nblocks,+ mlk_shake128x4ctx *state)+__contract__(+ requires(nblocks <= 8 /* somewhat arbitrary bound */)+ requires(memory_no_alias(state, sizeof(mlk_shake128x4ctx)))+ requires(memory_no_alias(out0, nblocks * SHAKE128_RATE))+ requires(memory_no_alias(out1, nblocks * SHAKE128_RATE))+ requires(memory_no_alias(out2, nblocks * SHAKE128_RATE))+ requires(memory_no_alias(out3, nblocks * SHAKE128_RATE))+ assigns(memory_slice(out0, nblocks * SHAKE128_RATE),+ memory_slice(out1, nblocks * SHAKE128_RATE),+ memory_slice(out2, nblocks * SHAKE128_RATE),+ memory_slice(out3, nblocks * SHAKE128_RATE),+ memory_slice(state, sizeof(mlk_shake128x4ctx)))+);++#define mlk_shake128x4_init MLK_NAMESPACE(shake128x4_init)+void mlk_shake128x4_init(mlk_shake128x4ctx *state);++#define mlk_shake128x4_release MLK_NAMESPACE(shake128x4_release)+void mlk_shake128x4_release(mlk_shake128x4ctx *state);++#define mlk_shake256x4 MLK_NAMESPACE(shake256x4)+void mlk_shake256x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3,+ size_t outlen, const uint8_t *in0, const uint8_t *in1,+ const uint8_t *in2, const uint8_t *in3, size_t inlen)+__contract__(+ requires(inlen <= MLK_MAX_BUFFER_SIZE)+ requires(outlen <= MLK_MAX_BUFFER_SIZE)+ requires(memory_no_alias(in0, inlen))+ requires(memory_no_alias(in1, inlen))+ requires(memory_no_alias(in2, inlen))+ requires(memory_no_alias(in3, inlen))+ requires(memory_no_alias(out0, outlen))+ requires(memory_no_alias(out1, outlen))+ requires(memory_no_alias(out2, outlen))+ requires(memory_no_alias(out3, outlen))+ assigns(memory_slice(out0, outlen))+ assigns(memory_slice(out1, outlen))+ assigns(memory_slice(out2, outlen))+ assigns(memory_slice(out3, outlen))+);++#endif /* !MLK_FIPS202_FIPS202X4_H */
@@ -0,0 +1,499 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [mupq]+ * Common files for pqm4, pqm3, pqriscv+ * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen+ * https://github.com/mupq/mupq+ *+ * - [supercop]+ * SUPERCOP benchmarking framework+ * Daniel J. Bernstein+ * http://bench.cr.yp.to/supercop.html+ *+ * - [tweetfips]+ * 'tweetfips202' FIPS202 implementation+ * Van Assche, Bernstein, Schwabe+ * https://keccak.team/2015/tweetfips202.html+ */++/* Based on the CC0 implementation from @[mupq] and the public domain+ * implementation @[supercop, crypto_hash/keccakc512/simple/]+ * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */+++#include "keccakf1600.h"+#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#define MLK_KECCAK_NROUNDS 24+#define MLK_KECCAK_ROL(a, offset) (((a) << (offset)) ^ ((a) >> (64 - (offset))))++void mlk_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data,+ unsigned offset, unsigned length)+{+ unsigned i;+#if defined(MLK_SYS_LITTLE_ENDIAN)+ uint8_t *state_ptr = (uint8_t *)state + offset;+ for (i = 0; i < length; i++)+ __loop__(invariant(i <= length)+ decreases(length - i))+ {+ data[i] = state_ptr[i];+ }+#else /* MLK_SYS_LITTLE_ENDIAN */+ /* Portable version */+ for (i = 0; i < length; i++)+ __loop__(invariant(i <= length)+ decreases(length - i))+ {+ data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF;+ }+#endif /* !MLK_SYS_LITTLE_ENDIAN */+}++void mlk_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data,+ unsigned offset, unsigned length)+{+ unsigned i;+#if defined(MLK_SYS_LITTLE_ENDIAN)+ uint8_t *state_ptr = (uint8_t *)state + offset;+ for (i = 0; i < length; i++)+ __loop__(invariant(i <= length)+ decreases(length - i))+ {+ state_ptr[i] ^= data[i];+ }+#else /* MLK_SYS_LITTLE_ENDIAN */+ /* Portable version */+ for (i = 0; i < length; i++)+ __loop__(invariant(i <= length)+ decreases(length - i))+ {+ state[(offset + i) >> 3] ^= (uint64_t)data[i]+ << (8 * ((offset + i) & 0x07));+ }+#endif /* !MLK_SYS_LITTLE_ENDIAN */+}++static void mlk_keccakf1600x4_extract_bytes_c(uint64_t *state,+ unsigned char *data0,+ unsigned char *data1,+ unsigned char *data2,+ unsigned char *data3,+ unsigned offset, unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLK_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLK_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+ requires(memory_no_alias(data0, length))+ requires(memory_no_alias(data1, length))+ requires(memory_no_alias(data2, length))+ requires(memory_no_alias(data3, length))+ assigns(memory_slice(data0, length))+ assigns(memory_slice(data1, length))+ assigns(memory_slice(data2, length))+ assigns(memory_slice(data3, length))+)+{+ mlk_keccakf1600_extract_bytes(state + MLK_KECCAK_LANES * 0, data0, offset,+ length);+ mlk_keccakf1600_extract_bytes(state + MLK_KECCAK_LANES * 1, data1, offset,+ length);+ mlk_keccakf1600_extract_bytes(state + MLK_KECCAK_LANES * 2, data2, offset,+ length);+ mlk_keccakf1600_extract_bytes(state + MLK_KECCAK_LANES * 3, data3, offset,+ length);+}++void mlk_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0,+ unsigned char *data1, unsigned char *data2,+ unsigned char *data3, unsigned offset,+ unsigned length)+{+#if defined(MLK_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES)+ if (mlk_keccakf1600_extract_bytes_x4_native(state, data0, data1, data2, data3,+ offset, length) ==+ MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES */+ mlk_keccakf1600x4_extract_bytes_c(state, data0, data1, data2, data3, offset,+ length);+}++static void mlk_keccakf1600x4_xor_bytes_c(uint64_t *state,+ const unsigned char *data0,+ const unsigned char *data1,+ const unsigned char *data2,+ const unsigned char *data3,+ unsigned offset, unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLK_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLK_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+ requires(memory_no_alias(data0, length))+ /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */+ requires((data0 == data1 &&+ data0 == data2 &&+ data0 == data3) ||+ (memory_no_alias(data1, length) &&+ memory_no_alias(data2, length) &&+ memory_no_alias(data3, length)))+ assigns(memory_slice(state, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+)+{+ mlk_keccakf1600_xor_bytes(state + MLK_KECCAK_LANES * 0, data0, offset,+ length);+ mlk_keccakf1600_xor_bytes(state + MLK_KECCAK_LANES * 1, data1, offset,+ length);+ mlk_keccakf1600_xor_bytes(state + MLK_KECCAK_LANES * 2, data2, offset,+ length);+ mlk_keccakf1600_xor_bytes(state + MLK_KECCAK_LANES * 3, data3, offset,+ length);+}++void mlk_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0,+ const unsigned char *data1,+ const unsigned char *data2,+ const unsigned char *data3, unsigned offset,+ unsigned length)+{+#if defined(MLK_USE_NATIVE_FIPS202_X4_XOR_BYTES)+ if (mlk_keccakf1600_xor_bytes_x4_native(state, data0, data1, data2, data3,+ offset,+ length) == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_FIPS202_X4_XOR_BYTES */+ mlk_keccakf1600x4_xor_bytes_c(state, data0, data1, data2, data3, offset,+ length);+}++void mlk_keccakf1600x4_permute(uint64_t *state)+{+#if defined(MLK_USE_NATIVE_FIPS202_X4)+ if (mlk_keccak_f1600_x4_native(state) == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_FIPS202_X4 */+ mlk_keccakf1600_permute(state + MLK_KECCAK_LANES * 0);+ mlk_keccakf1600_permute(state + MLK_KECCAK_LANES * 1);+ mlk_keccakf1600_permute(state + MLK_KECCAK_LANES * 2);+ mlk_keccakf1600_permute(state + MLK_KECCAK_LANES * 3);+}++static const uint64_t mlk_KeccakF_RoundConstants[MLK_KECCAK_NROUNDS] = {+ (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL,+ (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL,+ (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL,+ (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL,+ (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL,+ (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL,+ (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL,+ (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL,+ (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL,+ (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL,+ (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL,+ (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL};++MLK_STATIC_TESTABLE+void mlk_keccakf1600_permute_c(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * MLK_KECCAK_LANES))+ assigns(memory_slice(state, sizeof(uint64_t) * MLK_KECCAK_LANES))+)+{+ unsigned round;++ uint64_t Aba, Abe, Abi, Abo, Abu;+ uint64_t Aga, Age, Agi, Ago, Agu;+ uint64_t Aka, Ake, Aki, Ako, Aku;+ uint64_t Ama, Ame, Ami, Amo, Amu;+ uint64_t Asa, Ase, Asi, Aso, Asu;+ uint64_t BCa, BCe, BCi, BCo, BCu;+ uint64_t Da, De, Di, Do, Du;+ uint64_t Eba, Ebe, Ebi, Ebo, Ebu;+ uint64_t Ega, Ege, Egi, Ego, Egu;+ uint64_t Eka, Eke, Eki, Eko, Eku;+ uint64_t Ema, Eme, Emi, Emo, Emu;+ uint64_t Esa, Ese, Esi, Eso, Esu;++ /* copyFromState(A, state) */+ Aba = state[0];+ Abe = state[1];+ Abi = state[2];+ Abo = state[3];+ Abu = state[4];+ Aga = state[5];+ Age = state[6];+ Agi = state[7];+ Ago = state[8];+ Agu = state[9];+ Aka = state[10];+ Ake = state[11];+ Aki = state[12];+ Ako = state[13];+ Aku = state[14];+ Ama = state[15];+ Ame = state[16];+ Ami = state[17];+ Amo = state[18];+ Amu = state[19];+ Asa = state[20];+ Ase = state[21];+ Asi = state[22];+ Aso = state[23];+ Asu = state[24];++ for (round = 0; round < MLK_KECCAK_NROUNDS; round += 2)+ __loop__(invariant(round <= MLK_KECCAK_NROUNDS && round % 2 == 0)+ decreases(MLK_KECCAK_NROUNDS - round))+ {+ /* prepareTheta */+ BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa;+ BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase;+ BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi;+ BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso;+ BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu;++ /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */+ Da = BCu ^ MLK_KECCAK_ROL(BCe, 1);+ De = BCa ^ MLK_KECCAK_ROL(BCi, 1);+ Di = BCe ^ MLK_KECCAK_ROL(BCo, 1);+ Do = BCi ^ MLK_KECCAK_ROL(BCu, 1);+ Du = BCo ^ MLK_KECCAK_ROL(BCa, 1);++ Aba ^= Da;+ BCa = Aba;+ Age ^= De;+ BCe = MLK_KECCAK_ROL(Age, 44);+ Aki ^= Di;+ BCi = MLK_KECCAK_ROL(Aki, 43);+ Amo ^= Do;+ BCo = MLK_KECCAK_ROL(Amo, 21);+ Asu ^= Du;+ BCu = MLK_KECCAK_ROL(Asu, 14);+ Eba = BCa ^ ((~BCe) & BCi);+ Eba ^= (uint64_t)mlk_KeccakF_RoundConstants[round];+ Ebe = BCe ^ ((~BCi) & BCo);+ Ebi = BCi ^ ((~BCo) & BCu);+ Ebo = BCo ^ ((~BCu) & BCa);+ Ebu = BCu ^ ((~BCa) & BCe);++ Abo ^= Do;+ BCa = MLK_KECCAK_ROL(Abo, 28);+ Agu ^= Du;+ BCe = MLK_KECCAK_ROL(Agu, 20);+ Aka ^= Da;+ BCi = MLK_KECCAK_ROL(Aka, 3);+ Ame ^= De;+ BCo = MLK_KECCAK_ROL(Ame, 45);+ Asi ^= Di;+ BCu = MLK_KECCAK_ROL(Asi, 61);+ Ega = BCa ^ ((~BCe) & BCi);+ Ege = BCe ^ ((~BCi) & BCo);+ Egi = BCi ^ ((~BCo) & BCu);+ Ego = BCo ^ ((~BCu) & BCa);+ Egu = BCu ^ ((~BCa) & BCe);++ Abe ^= De;+ BCa = MLK_KECCAK_ROL(Abe, 1);+ Agi ^= Di;+ BCe = MLK_KECCAK_ROL(Agi, 6);+ Ako ^= Do;+ BCi = MLK_KECCAK_ROL(Ako, 25);+ Amu ^= Du;+ BCo = MLK_KECCAK_ROL(Amu, 8);+ Asa ^= Da;+ BCu = MLK_KECCAK_ROL(Asa, 18);+ Eka = BCa ^ ((~BCe) & BCi);+ Eke = BCe ^ ((~BCi) & BCo);+ Eki = BCi ^ ((~BCo) & BCu);+ Eko = BCo ^ ((~BCu) & BCa);+ Eku = BCu ^ ((~BCa) & BCe);++ Abu ^= Du;+ BCa = MLK_KECCAK_ROL(Abu, 27);+ Aga ^= Da;+ BCe = MLK_KECCAK_ROL(Aga, 36);+ Ake ^= De;+ BCi = MLK_KECCAK_ROL(Ake, 10);+ Ami ^= Di;+ BCo = MLK_KECCAK_ROL(Ami, 15);+ Aso ^= Do;+ BCu = MLK_KECCAK_ROL(Aso, 56);+ Ema = BCa ^ ((~BCe) & BCi);+ Eme = BCe ^ ((~BCi) & BCo);+ Emi = BCi ^ ((~BCo) & BCu);+ Emo = BCo ^ ((~BCu) & BCa);+ Emu = BCu ^ ((~BCa) & BCe);++ Abi ^= Di;+ BCa = MLK_KECCAK_ROL(Abi, 62);+ Ago ^= Do;+ BCe = MLK_KECCAK_ROL(Ago, 55);+ Aku ^= Du;+ BCi = MLK_KECCAK_ROL(Aku, 39);+ Ama ^= Da;+ BCo = MLK_KECCAK_ROL(Ama, 41);+ Ase ^= De;+ BCu = MLK_KECCAK_ROL(Ase, 2);+ Esa = BCa ^ ((~BCe) & BCi);+ Ese = BCe ^ ((~BCi) & BCo);+ Esi = BCi ^ ((~BCo) & BCu);+ Eso = BCo ^ ((~BCu) & BCa);+ Esu = BCu ^ ((~BCa) & BCe);++ /* prepareTheta */+ BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa;+ BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese;+ BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi;+ BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso;+ BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu;++ /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */+ Da = BCu ^ MLK_KECCAK_ROL(BCe, 1);+ De = BCa ^ MLK_KECCAK_ROL(BCi, 1);+ Di = BCe ^ MLK_KECCAK_ROL(BCo, 1);+ Do = BCi ^ MLK_KECCAK_ROL(BCu, 1);+ Du = BCo ^ MLK_KECCAK_ROL(BCa, 1);++ Eba ^= Da;+ BCa = Eba;+ Ege ^= De;+ BCe = MLK_KECCAK_ROL(Ege, 44);+ Eki ^= Di;+ BCi = MLK_KECCAK_ROL(Eki, 43);+ Emo ^= Do;+ BCo = MLK_KECCAK_ROL(Emo, 21);+ Esu ^= Du;+ BCu = MLK_KECCAK_ROL(Esu, 14);+ Aba = BCa ^ ((~BCe) & BCi);+ Aba ^= (uint64_t)mlk_KeccakF_RoundConstants[round + 1];+ Abe = BCe ^ ((~BCi) & BCo);+ Abi = BCi ^ ((~BCo) & BCu);+ Abo = BCo ^ ((~BCu) & BCa);+ Abu = BCu ^ ((~BCa) & BCe);++ Ebo ^= Do;+ BCa = MLK_KECCAK_ROL(Ebo, 28);+ Egu ^= Du;+ BCe = MLK_KECCAK_ROL(Egu, 20);+ Eka ^= Da;+ BCi = MLK_KECCAK_ROL(Eka, 3);+ Eme ^= De;+ BCo = MLK_KECCAK_ROL(Eme, 45);+ Esi ^= Di;+ BCu = MLK_KECCAK_ROL(Esi, 61);+ Aga = BCa ^ ((~BCe) & BCi);+ Age = BCe ^ ((~BCi) & BCo);+ Agi = BCi ^ ((~BCo) & BCu);+ Ago = BCo ^ ((~BCu) & BCa);+ Agu = BCu ^ ((~BCa) & BCe);++ Ebe ^= De;+ BCa = MLK_KECCAK_ROL(Ebe, 1);+ Egi ^= Di;+ BCe = MLK_KECCAK_ROL(Egi, 6);+ Eko ^= Do;+ BCi = MLK_KECCAK_ROL(Eko, 25);+ Emu ^= Du;+ BCo = MLK_KECCAK_ROL(Emu, 8);+ Esa ^= Da;+ BCu = MLK_KECCAK_ROL(Esa, 18);+ Aka = BCa ^ ((~BCe) & BCi);+ Ake = BCe ^ ((~BCi) & BCo);+ Aki = BCi ^ ((~BCo) & BCu);+ Ako = BCo ^ ((~BCu) & BCa);+ Aku = BCu ^ ((~BCa) & BCe);++ Ebu ^= Du;+ BCa = MLK_KECCAK_ROL(Ebu, 27);+ Ega ^= Da;+ BCe = MLK_KECCAK_ROL(Ega, 36);+ Eke ^= De;+ BCi = MLK_KECCAK_ROL(Eke, 10);+ Emi ^= Di;+ BCo = MLK_KECCAK_ROL(Emi, 15);+ Eso ^= Do;+ BCu = MLK_KECCAK_ROL(Eso, 56);+ Ama = BCa ^ ((~BCe) & BCi);+ Ame = BCe ^ ((~BCi) & BCo);+ Ami = BCi ^ ((~BCo) & BCu);+ Amo = BCo ^ ((~BCu) & BCa);+ Amu = BCu ^ ((~BCa) & BCe);++ Ebi ^= Di;+ BCa = MLK_KECCAK_ROL(Ebi, 62);+ Ego ^= Do;+ BCe = MLK_KECCAK_ROL(Ego, 55);+ Eku ^= Du;+ BCi = MLK_KECCAK_ROL(Eku, 39);+ Ema ^= Da;+ BCo = MLK_KECCAK_ROL(Ema, 41);+ Ese ^= De;+ BCu = MLK_KECCAK_ROL(Ese, 2);+ Asa = BCa ^ ((~BCe) & BCi);+ Ase = BCe ^ ((~BCi) & BCo);+ Asi = BCi ^ ((~BCo) & BCu);+ Aso = BCo ^ ((~BCu) & BCa);+ Asu = BCu ^ ((~BCa) & BCe);+ }++ /* copyToState(state, A) */+ state[0] = Aba;+ state[1] = Abe;+ state[2] = Abi;+ state[3] = Abo;+ state[4] = Abu;+ state[5] = Aga;+ state[6] = Age;+ state[7] = Agi;+ state[8] = Ago;+ state[9] = Agu;+ state[10] = Aka;+ state[11] = Ake;+ state[12] = Aki;+ state[13] = Ako;+ state[14] = Aku;+ state[15] = Ama;+ state[16] = Ame;+ state[17] = Ami;+ state[18] = Amo;+ state[19] = Amu;+ state[20] = Asa;+ state[21] = Ase;+ state[22] = Asi;+ state[23] = Aso;+ state[24] = Asu;+}++void mlk_keccakf1600_permute(uint64_t *state)+{+#if defined(MLK_USE_NATIVE_FIPS202_X1)+ if (mlk_keccak_f1600_x1_native(state) == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_FIPS202_X1 */+ mlk_keccakf1600_permute_c(state);+}++#else /* !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(keccakf1600)++#endif /* MLK_CONFIG_MULTILEVEL_NO_SHARED */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef MLK_KECCAK_NROUNDS+#undef MLK_KECCAK_ROL
@@ -0,0 +1,98 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_FIPS202_KECCAKF1600_H+#define MLK_FIPS202_KECCAKF1600_H+#include "../cbmc.h"+#include "../common.h"++#define MLK_KECCAK_LANES 25+#define MLK_KECCAK_WAY 4++/*+ * WARNING:+ * The contents of this structure, including the placement+ * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED.+ * The struct is only exposed here to allow its construction on the stack.+ */++#define mlk_keccakf1600_extract_bytes MLK_NAMESPACE(keccakf1600_extract_bytes)+void mlk_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data,+ unsigned offset, unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLK_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLK_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLK_KECCAK_LANES))+ requires(memory_no_alias(data, length))+ assigns(memory_slice(data, length))+);++#define mlk_keccakf1600_xor_bytes MLK_NAMESPACE(keccakf1600_xor_bytes)+void mlk_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data,+ unsigned offset, unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLK_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLK_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLK_KECCAK_LANES))+ requires(memory_no_alias(data, length))+ assigns(memory_slice(state, sizeof(uint64_t) * MLK_KECCAK_LANES))+);++#define mlk_keccakf1600x4_extract_bytes \+ MLK_NAMESPACE(keccakf1600x4_extract_bytes)+void mlk_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0,+ unsigned char *data1, unsigned char *data2,+ unsigned char *data3, unsigned offset,+ unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLK_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLK_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+ requires(memory_no_alias(data0, length))+ requires(memory_no_alias(data1, length))+ requires(memory_no_alias(data2, length))+ requires(memory_no_alias(data3, length))+ assigns(memory_slice(data0, length))+ assigns(memory_slice(data1, length))+ assigns(memory_slice(data2, length))+ assigns(memory_slice(data3, length))+);++#define mlk_keccakf1600x4_xor_bytes MLK_NAMESPACE(keccakf1600x4_xor_bytes)+void mlk_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0,+ const unsigned char *data1,+ const unsigned char *data2,+ const unsigned char *data3, unsigned offset,+ unsigned length)+__contract__(+ requires(0 <= offset && offset <= MLK_KECCAK_LANES * sizeof(uint64_t) &&+ 0 <= length && length <= MLK_KECCAK_LANES * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+ requires(memory_no_alias(data0, length))+ /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */+ requires((data0 == data1 &&+ data0 == data2 &&+ data0 == data3) ||+ (memory_no_alias(data1, length) &&+ memory_no_alias(data2, length) &&+ memory_no_alias(data3, length)))+ assigns(memory_slice(state, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+);+++#define mlk_keccakf1600x4_permute MLK_NAMESPACE(keccakf1600x4_permute)+void mlk_keccakf1600x4_permute(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+ assigns(memory_slice(state, sizeof(uint64_t) * MLK_KECCAK_LANES * MLK_KECCAK_WAY))+);++#define mlk_keccakf1600_permute MLK_NAMESPACE(keccakf1600_permute)+void mlk_keccakf1600_permute(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * MLK_KECCAK_LANES))+ assigns(memory_slice(state, sizeof(uint64_t) * MLK_KECCAK_LANES))+);++#endif /* !MLK_FIPS202_KECCAKF1600_H */
@@ -0,0 +1,78 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [HYBRID]+ * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64+ * Becker, Kannwischer+ * https://eprint.iacr.org/2022/1243+ */++#ifndef MLK_FIPS202_NATIVE_AARCH64_AUTO_H+#define MLK_FIPS202_NATIVE_AARCH64_AUTO_H+/* Default FIPS202 assembly profile for AArch64 systems */++/*+ * Default logic to decide which implementation to use.+ *+ */++/*+ * Keccak-f1600+ *+ * - On Arm-based Apple CPUs, or if MLK_SYS_AARCH64_FAST_SHA3 is set,+ * we pick a pure Neon implementation.+ * - Otherwise, unless MLK_SYS_AARCH64_SLOW_BARREL_SHIFTER is set,+ * we use lazy-rotation scalar assembly from @[HYBRID].+ * - Otherwise, if MLK_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we+ * fall back to the standard C implementation.+ */+#if defined(__ARM_FEATURE_SHA3) && \+ (defined(__APPLE__) || defined(MLK_SYS_AARCH64_FAST_SHA3))+#include "x1_v84a.h"+#elif !defined(MLK_SYS_AARCH64_SLOW_BARREL_SHIFTER)+#include "x1_scalar.h"+#endif++/* Batched, SIMD-based Keccak-f1600 implementations. */+#if defined(MLK_SYS_AARCH64_NEON)++/*+ * Keccak-f1600x2/x4+ *+ * The optimal implementation is highly CPU-specific; see @[HYBRID].+ *+ * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600.+ * If v8.4-A is implemented and we are on an Apple CPU or+ * MLK_SYS_AARCH64_FAST_SHA3 is set, we use a plain Neon-based+ * implementation.+ * Otherwise, if v8.4-A is implemented, we use a scalar/Neon/Neon hybrid.+ * The reason for this distinction is that Apple CPUs (and CPUs flagged with+ * MLK_SYS_AARCH64_FAST_SHA3) implement the SHA3 instructions on all SIMD+ * units, while Arm CPUs prior to Cortex-X4 don't, and ordinary Neon+ * instructions are still needed.+ */+#if defined(__ARM_FEATURE_SHA3)+/*+ * For Apple-M cores (and CPUs flagged with MLK_SYS_AARCH64_FAST_SHA3), we+ * use a plain implementation leveraging SHA3 instructions only.+ */+#if defined(__APPLE__) || defined(MLK_SYS_AARCH64_FAST_SHA3)+#include "x2_v84a.h"+#else+#include "x4_v8a_v84a_scalar.h"+#endif++#else /* __ARM_FEATURE_SHA3 */++#include "x4_v8a_scalar.h"++#endif /* !__ARM_FEATURE_SHA3 */++#endif /* MLK_SYS_AARCH64_NEON */++#endif /* !MLK_FIPS202_NATIVE_AARCH64_AUTO_H */
@@ -0,0 +1,80 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H+#define MLK_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H++#include "../../../../cbmc.h"+#include "../../../../common.h"++#define mlk_keccakf1600_round_constants \+ MLK_NAMESPACE(keccakf1600_round_constants)+MLK_INTERNAL_DATA_DECLARATION const uint64_t+ mlk_keccakf1600_round_constants[24];++#define mlk_keccak_f1600_x1_scalar_aarch64_asm \+ MLK_NAMESPACE(keccak_f1600_x1_scalar_aarch64_asm)+void mlk_keccak_f1600_x1_scalar_aarch64_asm(uint64_t state[25],+ const uint64_t rc[24])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/keccak_f1600_x1_scalar_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1))+ requires(rc == mlk_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1))+);++#define mlk_keccak_f1600_x1_v84a_aarch64_asm \+ MLK_NAMESPACE(keccak_f1600_x1_v84a_aarch64_asm)+void mlk_keccak_f1600_x1_v84a_aarch64_asm(uint64_t state[25],+ const uint64_t rc[24])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/keccak_f1600_x1_v84a_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1))+ requires(rc == mlk_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1))+);++#define mlk_keccak_f1600_x2_v84a_aarch64_asm \+ MLK_NAMESPACE(keccak_f1600_x2_v84a_aarch64_asm)+void mlk_keccak_f1600_x2_v84a_aarch64_asm(uint64_t state[50],+ const uint64_t rc[24])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/keccak_f1600_x2_v84a_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2))+ requires(rc == mlk_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2))+);++#define mlk_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm \+ MLK_NAMESPACE(keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm)+void mlk_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm(uint64_t state[100],+ const uint64_t rc[24])+/* This must be kept in sync with the HOL-Light specification+ * in+ * proofs/hol_light/aarch64/proofs/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.ml+ */+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ requires(rc == mlk_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4))+);++#define mlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm \+ MLK_NAMESPACE(keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm)+void mlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm(+ uint64_t state[100], const uint64_t rc[24])+/* This must be kept in sync with the HOL-Light specification+ * in+ * proofs/hol_light/aarch64/proofs/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.ml+ */+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ requires(rc == mlk_keccakf1600_round_constants)+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4))+);++#endif /* !MLK_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */
@@ -0,0 +1,377 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++// Author: Hanno Becker <hanno.becker@arm.com>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>++/*yaml+ Name: keccak_f1600_x1_scalar_aarch64_asm+ Description: AArch64 scalar implementation of Keccak-f[1600] permutation for single state+ Signature: void mlk_keccak_f1600_x1_scalar_aarch64_asm(uint64_t state[25], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ x0:+ type: buffer+ size_bytes: 200+ permissions: read/write+ c_parameter: uint64_t state[25]+ description: Keccak state (25 x uint64_t)+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: uint64_t const *rc+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 128+ description: register preservation and temporary storage+*/++#include "../../../../common.h"+#if defined(MLK_FIPS202_AARCH64_NEED_X1_SCALAR) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x1_scalar_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(keccak_f1600_x1_scalar_aarch64_asm)+MLK_ASM_FN_SYMBOL(keccak_f1600_x1_scalar_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x80+ .cfi_adjust_cfa_offset 0x80+ stp x19, x20, [sp, #0x20]+ .cfi_rel_offset x19, 0x20+ .cfi_rel_offset x20, 0x28+ stp x21, x22, [sp, #0x30]+ .cfi_rel_offset x21, 0x30+ .cfi_rel_offset x22, 0x38+ stp x23, x24, [sp, #0x40]+ .cfi_rel_offset x23, 0x40+ .cfi_rel_offset x24, 0x48+ stp x25, x26, [sp, #0x50]+ .cfi_rel_offset x25, 0x50+ .cfi_rel_offset x26, 0x58+ stp x27, x28, [sp, #0x60]+ .cfi_rel_offset x27, 0x60+ .cfi_rel_offset x28, 0x68+ stp x29, x30, [sp, #0x70]+ .cfi_rel_offset x29, 0x70+ .cfi_rel_offset x30, 0x78++Lmlk_keccak_f1600_x1_scalar_initial:+ mov x26, x1+ str x1, [sp, #0x8]+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ str x0, [sp]+ eor x30, x24, x25+ eor x27, x9, x10+ eor x0, x30, x21+ eor x26, x27, x6+ eor x27, x26, x7+ eor x29, x0, x22+ eor x26, x29, x23+ eor x29, x4, x5+ eor x30, x29, x1+ eor x0, x27, x8+ eor x29, x30, x2+ eor x30, x19, x20+ eor x30, x30, x16+ eor x27, x26, x0, ror #63+ eor x4, x4, x27+ eor x30, x30, x17+ eor x30, x30, x28+ eor x29, x29, x3+ eor x0, x0, x30, ror #63+ eor x30, x30, x29, ror #63+ eor x22, x22, x30+ eor x23, x23, x30+ str x23, [sp, #0x18]+ eor x23, x14, x15+ eor x14, x14, x0+ eor x23, x23, x11+ eor x15, x15, x0+ eor x1, x1, x27+ eor x23, x23, x12+ eor x23, x23, x13+ eor x11, x11, x0+ eor x29, x29, x23, ror #63+ eor x23, x23, x26, ror #63+ eor x26, x13, x0+ eor x13, x28, x23+ eor x28, x24, x30+ eor x24, x16, x23+ eor x16, x21, x30+ eor x21, x25, x30+ eor x30, x19, x23+ eor x19, x20, x23+ eor x20, x17, x23+ eor x17, x12, x0+ eor x0, x2, x27+ eor x2, x6, x29+ eor x6, x8, x29+ bic x8, x28, x13, ror #47+ eor x12, x3, x27+ bic x3, x13, x17, ror #19+ eor x5, x5, x27+ ldr x27, [sp, #0x18]+ bic x25, x17, x2, ror #5+ eor x9, x9, x29+ eor x23, x25, x5, ror #52+ eor x3, x3, x2, ror #24+ eor x8, x8, x17, ror #2+ eor x17, x10, x29+ bic x25, x12, x22, ror #47+ eor x29, x7, x29+ bic x10, x4, x27, ror #2+ bic x7, x5, x28, ror #10+ eor x10, x10, x20, ror #50+ eor x13, x7, x13, ror #57+ bic x7, x2, x5, ror #47+ eor x2, x25, x24, ror #39+ bic x25, x20, x11, ror #57+ bic x5, x17, x4, ror #25+ eor x25, x25, x17, ror #53+ bic x17, x11, x17, ror #60+ eor x28, x7, x28, ror #57+ bic x7, x9, x12, ror #42+ eor x7, x7, x22, ror #25+ bic x22, x22, x24, ror #56+ bic x24, x24, x15, ror #31+ eor x22, x22, x15, ror #23+ bic x20, x27, x20, ror #48+ bic x15, x15, x9, ror #16+ eor x12, x15, x12, ror #58+ eor x15, x5, x27, ror #27+ eor x5, x20, x11, ror #41+ ldr x11, [sp, #0x8]+ eor x20, x17, x4, ror #21+ eor x17, x24, x9, ror #47+ mov x24, #0x1 // =1+ bic x9, x0, x16, ror #9+ str x24, [sp, #0x10]+ bic x24, x29, x1, ror #44+ bic x27, x1, x21, ror #50+ bic x4, x26, x29, ror #63+ eor x1, x1, x4, ror #21+ ldr x11, [x11]+ bic x4, x21, x30, ror #57+ eor x21, x24, x21, ror #30+ eor x24, x9, x19, ror #44+ bic x9, x14, x6, ror #5+ eor x9, x9, x0, ror #43+ bic x0, x6, x0, ror #38+ eor x1, x1, x11+ eor x11, x4, x26, ror #35+ eor x4, x0, x16, ror #47+ bic x0, x16, x19, ror #35+ eor x16, x27, x30, ror #43+ bic x27, x30, x26, ror #42+ bic x26, x19, x14, ror #41+ eor x19, x0, x14, ror #12+ eor x14, x26, x6, ror #46+ eor x6, x27, x29, ror #41++Lmlk_keccak_f1600_x1_scalar_loop:+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ eor x26, x8, x9, ror #57+ eor x27, x0, x14, ror #10+ eor x29, x16, x28, ror #63+ eor x26, x26, x6, ror #51+ eor x30, x23, x22, ror #50+ eor x0, x26, x10, ror #31+ eor x29, x29, x19, ror #37+ eor x27, x27, x12, ror #5+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ eor x26, x30, x21, ror #26+ eor x26, x26, x25, ror #15+ ror x30, x27, #0x3e+ eor x30, x30, x26, ror #57+ ror x26, x26, #0x3a+ eor x16, x30, x16+ eor x28, x30, x28, ror #63+ str x28, [sp, #0x18]+ eor x29, x29, x17, ror #36+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ eor x29, x29, x20, ror #2+ eor x28, x28, x4, ror #54+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ eor x28, x28, x5, ror #25+ ror x0, x0, #0x38+ eor x0, x0, x29, ror #63+ eor x27, x28, x27, ror #61+ eor x13, x0, x13, ror #46+ eor x28, x29, x28, ror #63+ eor x29, x30, x20, ror #2+ eor x20, x26, x3, ror #39+ eor x11, x0, x11, ror #50+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ eor x21, x26, x1+ eor x9, x27, x9, ror #49+ eor x24, x28, x24, ror #28+ eor x1, x30, x17, ror #36+ eor x14, x0, x14, ror #8+ eor x22, x28, x22, ror #44+ eor x8, x27, x8, ror #56+ eor x17, x27, x7, ror #19+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ eor x4, x26, x4, ror #54+ eor x0, x0, x12, ror #3+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ eor x26, x26, x5, ror #25+ eor x2, x7, x16, ror #39+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ eor x7, x7, x22, ror #25+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ eor x30, x27, x6, ror #43+ eor x22, x20, x15, ror #23+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ bic x5, x13, x17, ror #63+ eor x5, x21, x5, ror #21+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ bic x21, x21, x25, ror #50+ bic x20, x27, x4, ror #25+ bic x10, x16, x15, ror #31+ eor x16, x21, x19, ror #43+ eor x21, x17, x25, ror #30+ bic x19, x25, x19, ror #57+ ldr x25, [sp, #0x10]+ eor x17, x10, x9, ror #47+ ldr x9, [sp, #0x8]+ eor x15, x20, x28, ror #27+ bic x20, x4, x28, ror #2+ eor x10, x20, x1, ror #50+ bic x20, x11, x27, ror #60+ eor x20, x20, x4, ror #21+ bic x4, x28, x1, ror #48+ bic x1, x1, x11, ror #57+ ldr x28, [x9, x25, lsl #3]+ ldr x9, [sp, #0x18]+ add x25, x25, #0x1+ str x25, [sp, #0x10]+ cmp x25, #0x17+ eor x25, x1, x27, ror #53+ bic x27, x30, x26, ror #47+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ eor x11, x19, x13, ror #35+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ bic x27, x24, x9, ror #47+ bic x19, x23, x3, ror #9+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ bic x29, x3, x29, ror #35+ eor x13, x13, x9, ror #57+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ bic x14, x14, x8, ror #5+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ b.le Lmlk_keccak_f1600_x1_scalar_loop+ ror x6, x6, #0x2b+ ror x11, x11, #0x32+ ror x21, x21, #0x14+ ror x2, x2, #0x3d+ ror x7, x7, #0x13+ ror x12, x12, #0x3+ ror x17, x17, #0x24+ ror x22, x22, #0x2c+ ror x3, x3, #0x27+ ror x8, x8, #0x38+ ror x13, x13, #0x2e+ ror x28, x28, #0x3f+ ror x23, x23, #0x3a+ ror x4, x4, #0x36+ ror x9, x9, #0x31+ ror x14, x14, #0x8+ ror x19, x19, #0x25+ ror x24, x24, #0x1c+ ror x5, x5, #0x19+ ror x10, x10, #0x17+ ror x15, x15, #0x3e+ ror x20, x20, #0x2+ ror x25, x25, #0x9+ ldr x0, [sp]+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ ldp x19, x20, [sp, #0x20]+ .cfi_restore x19+ .cfi_restore x20+ ldp x21, x22, [sp, #0x30]+ .cfi_restore x21+ .cfi_restore x22+ ldp x23, x24, [sp, #0x40]+ .cfi_restore x23+ .cfi_restore x24+ ldp x25, x26, [sp, #0x50]+ .cfi_restore x25+ .cfi_restore x26+ ldp x27, x28, [sp, #0x60]+ .cfi_restore x27+ .cfi_restore x28+ ldp x29, x30, [sp, #0x70]+ .cfi_restore x29+ .cfi_restore x30+ add sp, sp, #0x80+ .cfi_adjust_cfa_offset -0x80+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(keccak_f1600_x1_scalar_aarch64_asm)++#endif /* MLK_FIPS202_AARCH64_NEED_X1_SCALAR && \+ !MLK_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,206 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [HYBRID]+ * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64+ * Becker, Kannwischer+ * https://eprint.iacr.org/2022/1243+ */++/*yaml+ Name: keccak_f1600_x1_v84a_aarch64_asm+ Description: AArch64 ARMv8.4-A implementation of Keccak-f[1600] permutation for single state+ Signature: void mlk_keccak_f1600_x1_v84a_aarch64_asm(uint64_t state[25], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON, SHA3]+ x0:+ type: buffer+ size_bytes: 200+ permissions: read/write+ c_parameter: uint64_t state[25]+ description: Keccak state (25 x uint64_t)+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: const uint64_t rc[24]+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 64+ description: register preservation+*/++//+// Author: Hanno Becker <hanno.becker@arm.com>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>+//+// This implementation is essentially from the paper @[HYBRID].+// The only difference is interleaving/deinterleaving of Keccak state+// during load and store, so that the caller need not do this.+//++#include "../../../../common.h"+#if defined(MLK_FIPS202_AARCH64_NEED_X1_V84A) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#if defined(__ARM_FEATURE_SHA3)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x1_v84a_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(keccak_f1600_x1_v84a_aarch64_asm)+MLK_ASM_FN_SYMBOL(keccak_f1600_x1_v84a_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ ldp d0, d1, [x0]+ ldp d2, d3, [x0, #0x10]+ ldp d4, d5, [x0, #0x20]+ ldp d6, d7, [x0, #0x30]+ ldp d8, d9, [x0, #0x40]+ ldp d10, d11, [x0, #0x50]+ ldp d12, d13, [x0, #0x60]+ ldp d14, d15, [x0, #0x70]+ ldp d16, d17, [x0, #0x80]+ ldp d18, d19, [x0, #0x90]+ ldp d20, d21, [x0, #0xa0]+ ldp d22, d23, [x0, #0xb0]+ ldr d24, [x0, #0xc0]+ mov x2, #0x18 // =24++Lmlk_keccak_f1600_x1_v84a_loop:+ eor3 v30.16b, v0.16b, v5.16b, v10.16b+ eor3 v29.16b, v1.16b, v6.16b, v11.16b+ eor3 v28.16b, v2.16b, v7.16b, v12.16b+ eor3 v27.16b, v3.16b, v8.16b, v13.16b+ eor3 v26.16b, v4.16b, v9.16b, v14.16b+ eor3 v30.16b, v30.16b, v15.16b, v20.16b+ eor3 v29.16b, v29.16b, v16.16b, v21.16b+ eor3 v28.16b, v28.16b, v17.16b, v22.16b+ eor3 v27.16b, v27.16b, v18.16b, v23.16b+ eor3 v26.16b, v26.16b, v19.16b, v24.16b+ rax1 v25.2d, v30.2d, v28.2d+ rax1 v28.2d, v28.2d, v26.2d+ rax1 v26.2d, v26.2d, v29.2d+ rax1 v29.2d, v29.2d, v27.2d+ rax1 v27.2d, v27.2d, v30.2d+ eor v30.16b, v0.16b, v26.16b+ xar v0.2d, v2.2d, v29.2d, #0x2+ xar v2.2d, v12.2d, v29.2d, #0x15+ xar v12.2d, v13.2d, v28.2d, #0x27+ xar v13.2d, v19.2d, v27.2d, #0x38+ xar v19.2d, v23.2d, v28.2d, #0x8+ xar v23.2d, v15.2d, v26.2d, #0x17+ xar v15.2d, v1.2d, v25.2d, #0x3f+ xar v1.2d, v8.2d, v28.2d, #0x9+ xar v8.2d, v16.2d, v25.2d, #0x13+ xar v16.2d, v7.2d, v29.2d, #0x3a+ xar v7.2d, v10.2d, v26.2d, #0x3d+ xar v10.2d, v3.2d, v28.2d, #0x24+ xar v3.2d, v18.2d, v28.2d, #0x2b+ xar v18.2d, v17.2d, v29.2d, #0x31+ xar v17.2d, v11.2d, v25.2d, #0x36+ xar v11.2d, v9.2d, v27.2d, #0x2c+ xar v9.2d, v22.2d, v29.2d, #0x3+ xar v22.2d, v14.2d, v27.2d, #0x19+ xar v14.2d, v20.2d, v26.2d, #0x2e+ xar v20.2d, v4.2d, v27.2d, #0x25+ xar v4.2d, v24.2d, v27.2d, #0x32+ xar v24.2d, v21.2d, v25.2d, #0x3e+ xar v21.2d, v5.2d, v26.2d, #0x1c+ xar v27.2d, v6.2d, v25.2d, #0x14+ ld1r { v31.2d }, [x1], #8+ bcax v5.16b, v10.16b, v7.16b, v11.16b+ bcax v6.16b, v11.16b, v8.16b, v7.16b+ bcax v7.16b, v7.16b, v9.16b, v8.16b+ bcax v8.16b, v8.16b, v10.16b, v9.16b+ bcax v9.16b, v9.16b, v11.16b, v10.16b+ bcax v10.16b, v15.16b, v12.16b, v16.16b+ bcax v11.16b, v16.16b, v13.16b, v12.16b+ bcax v12.16b, v12.16b, v14.16b, v13.16b+ bcax v13.16b, v13.16b, v15.16b, v14.16b+ bcax v14.16b, v14.16b, v16.16b, v15.16b+ bcax v15.16b, v20.16b, v17.16b, v21.16b+ bcax v16.16b, v21.16b, v18.16b, v17.16b+ bcax v17.16b, v17.16b, v19.16b, v18.16b+ bcax v18.16b, v18.16b, v20.16b, v19.16b+ bcax v19.16b, v19.16b, v21.16b, v20.16b+ bcax v20.16b, v0.16b, v22.16b, v1.16b+ bcax v21.16b, v1.16b, v23.16b, v22.16b+ bcax v22.16b, v22.16b, v24.16b, v23.16b+ bcax v23.16b, v23.16b, v0.16b, v24.16b+ bcax v24.16b, v24.16b, v1.16b, v0.16b+ bcax v0.16b, v30.16b, v2.16b, v27.16b+ bcax v1.16b, v27.16b, v3.16b, v2.16b+ bcax v2.16b, v2.16b, v4.16b, v3.16b+ bcax v3.16b, v3.16b, v30.16b, v4.16b+ bcax v4.16b, v4.16b, v27.16b, v30.16b+ eor v0.16b, v0.16b, v31.16b+ sub x2, x2, #0x1+ cbnz x2, Lmlk_keccak_f1600_x1_v84a_loop+ stp d0, d1, [x0]+ stp d2, d3, [x0, #0x10]+ stp d4, d5, [x0, #0x20]+ stp d6, d7, [x0, #0x30]+ stp d8, d9, [x0, #0x40]+ stp d10, d11, [x0, #0x50]+ stp d12, d13, [x0, #0x60]+ stp d14, d15, [x0, #0x70]+ stp d16, d17, [x0, #0x80]+ stp d18, d19, [x0, #0x90]+ stp d20, d21, [x0, #0xa0]+ stp d22, d23, [x0, #0xb0]+ str d24, [x0, #0xc0]+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(keccak_f1600_x1_v84a_aarch64_asm)++#endif /* __ARM_FEATURE_SHA3 */++#endif /* MLK_FIPS202_AARCH64_NEED_X1_V84A && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,261 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [HYBRID]+ * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64+ * Becker, Kannwischer+ * https://eprint.iacr.org/2022/1243+ */++/*yaml+ Name: keccak_f1600_x2_v84a_aarch64_asm+ Description: AArch64 ARMv8.4-A implementation of Keccak-f[1600] permutation for two sequential states+ Signature: void mlk_keccak_f1600_x2_v84a_aarch64_asm(uint64_t state[50], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON, SHA3]+ x0:+ type: buffer+ size_bytes: 400+ permissions: read/write+ c_parameter: uint64_t state[50]+ description: Two sequential Keccak states (state0[25], state1[25])+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: const uint64_t rc[24]+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 64+ description: register preservation+*/++//+// Author: Hanno Becker <hanno.becker@arm.com>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>+//+// This implementation is essentially from the paper @[HYBRID].+// The only difference is interleaving/deinterleaving of Keccak state+// during load and store, so that the caller need not do this.+//++#include "../../../../common.h"+#if defined(MLK_FIPS202_AARCH64_NEED_X2_V84A) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#if defined(__ARM_FEATURE_SHA3)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x2_v84a_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(keccak_f1600_x2_v84a_aarch64_asm)+MLK_ASM_FN_SYMBOL(keccak_f1600_x2_v84a_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ add x2, x0, #0xc8+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v0.2d, v25.2d, v27.2d+ trn2 v1.2d, v25.2d, v27.2d+ trn1 v2.2d, v26.2d, v28.2d+ trn2 v3.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v4.2d, v25.2d, v27.2d+ trn2 v5.2d, v25.2d, v27.2d+ trn1 v6.2d, v26.2d, v28.2d+ trn2 v7.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v8.2d, v25.2d, v27.2d+ trn2 v9.2d, v25.2d, v27.2d+ trn1 v10.2d, v26.2d, v28.2d+ trn2 v11.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v12.2d, v25.2d, v27.2d+ trn2 v13.2d, v25.2d, v27.2d+ trn1 v14.2d, v26.2d, v28.2d+ trn2 v15.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v16.2d, v25.2d, v27.2d+ trn2 v17.2d, v25.2d, v27.2d+ trn1 v18.2d, v26.2d, v28.2d+ trn2 v19.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x2], #32+ trn1 v20.2d, v25.2d, v27.2d+ trn2 v21.2d, v25.2d, v27.2d+ trn1 v22.2d, v26.2d, v28.2d+ trn2 v23.2d, v26.2d, v28.2d+ ldr d25, [x0]+ ldr d27, [x2]+ trn1 v24.2d, v25.2d, v27.2d+ mov x2, #0x18 // =24++Lmlk_keccak_f1600_x2_v84a_loop:+ eor3 v30.16b, v0.16b, v5.16b, v10.16b+ eor3 v29.16b, v1.16b, v6.16b, v11.16b+ eor3 v28.16b, v2.16b, v7.16b, v12.16b+ eor3 v27.16b, v3.16b, v8.16b, v13.16b+ eor3 v26.16b, v4.16b, v9.16b, v14.16b+ eor3 v30.16b, v30.16b, v15.16b, v20.16b+ eor3 v29.16b, v29.16b, v16.16b, v21.16b+ eor3 v28.16b, v28.16b, v17.16b, v22.16b+ eor3 v27.16b, v27.16b, v18.16b, v23.16b+ eor3 v26.16b, v26.16b, v19.16b, v24.16b+ rax1 v25.2d, v30.2d, v28.2d+ rax1 v28.2d, v28.2d, v26.2d+ rax1 v26.2d, v26.2d, v29.2d+ rax1 v29.2d, v29.2d, v27.2d+ rax1 v27.2d, v27.2d, v30.2d+ eor v30.16b, v0.16b, v26.16b+ xar v0.2d, v2.2d, v29.2d, #0x2+ xar v2.2d, v12.2d, v29.2d, #0x15+ xar v12.2d, v13.2d, v28.2d, #0x27+ xar v13.2d, v19.2d, v27.2d, #0x38+ xar v19.2d, v23.2d, v28.2d, #0x8+ xar v23.2d, v15.2d, v26.2d, #0x17+ xar v15.2d, v1.2d, v25.2d, #0x3f+ xar v1.2d, v8.2d, v28.2d, #0x9+ xar v8.2d, v16.2d, v25.2d, #0x13+ xar v16.2d, v7.2d, v29.2d, #0x3a+ xar v7.2d, v10.2d, v26.2d, #0x3d+ xar v10.2d, v3.2d, v28.2d, #0x24+ xar v3.2d, v18.2d, v28.2d, #0x2b+ xar v18.2d, v17.2d, v29.2d, #0x31+ xar v17.2d, v11.2d, v25.2d, #0x36+ xar v11.2d, v9.2d, v27.2d, #0x2c+ xar v9.2d, v22.2d, v29.2d, #0x3+ xar v22.2d, v14.2d, v27.2d, #0x19+ xar v14.2d, v20.2d, v26.2d, #0x2e+ xar v20.2d, v4.2d, v27.2d, #0x25+ xar v4.2d, v24.2d, v27.2d, #0x32+ xar v24.2d, v21.2d, v25.2d, #0x3e+ xar v21.2d, v5.2d, v26.2d, #0x1c+ xar v27.2d, v6.2d, v25.2d, #0x14+ ld1r { v31.2d }, [x1], #8+ bcax v5.16b, v10.16b, v7.16b, v11.16b+ bcax v6.16b, v11.16b, v8.16b, v7.16b+ bcax v7.16b, v7.16b, v9.16b, v8.16b+ bcax v8.16b, v8.16b, v10.16b, v9.16b+ bcax v9.16b, v9.16b, v11.16b, v10.16b+ bcax v10.16b, v15.16b, v12.16b, v16.16b+ bcax v11.16b, v16.16b, v13.16b, v12.16b+ bcax v12.16b, v12.16b, v14.16b, v13.16b+ bcax v13.16b, v13.16b, v15.16b, v14.16b+ bcax v14.16b, v14.16b, v16.16b, v15.16b+ bcax v15.16b, v20.16b, v17.16b, v21.16b+ bcax v16.16b, v21.16b, v18.16b, v17.16b+ bcax v17.16b, v17.16b, v19.16b, v18.16b+ bcax v18.16b, v18.16b, v20.16b, v19.16b+ bcax v19.16b, v19.16b, v21.16b, v20.16b+ bcax v20.16b, v0.16b, v22.16b, v1.16b+ bcax v21.16b, v1.16b, v23.16b, v22.16b+ bcax v22.16b, v22.16b, v24.16b, v23.16b+ bcax v23.16b, v23.16b, v0.16b, v24.16b+ bcax v24.16b, v24.16b, v1.16b, v0.16b+ bcax v0.16b, v30.16b, v2.16b, v27.16b+ bcax v1.16b, v27.16b, v3.16b, v2.16b+ bcax v2.16b, v2.16b, v4.16b, v3.16b+ bcax v3.16b, v3.16b, v30.16b, v4.16b+ bcax v4.16b, v4.16b, v27.16b, v30.16b+ eor v0.16b, v0.16b, v31.16b+ sub x2, x2, #0x1+ cbnz x2, Lmlk_keccak_f1600_x2_v84a_loop+ sub x0, x0, #0xc0+ add x2, x0, #0xc8+ trn1 v25.2d, v0.2d, v1.2d+ trn1 v26.2d, v2.2d, v3.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v0.2d, v1.2d+ trn2 v28.2d, v2.2d, v3.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v4.2d, v5.2d+ trn1 v26.2d, v6.2d, v7.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v4.2d, v5.2d+ trn2 v28.2d, v6.2d, v7.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v8.2d, v9.2d+ trn1 v26.2d, v10.2d, v11.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v8.2d, v9.2d+ trn2 v28.2d, v10.2d, v11.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v12.2d, v13.2d+ trn1 v26.2d, v14.2d, v15.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v12.2d, v13.2d+ trn2 v28.2d, v14.2d, v15.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v16.2d, v17.2d+ trn1 v26.2d, v18.2d, v19.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v16.2d, v17.2d+ trn2 v28.2d, v18.2d, v19.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ trn1 v25.2d, v20.2d, v21.2d+ trn1 v26.2d, v22.2d, v23.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v20.2d, v21.2d+ trn2 v28.2d, v22.2d, v23.2d+ st1 { v27.2d, v28.2d }, [x2], #32+ str d24, [x0]+ trn2 v25.2d, v24.2d, v24.2d+ str d25, [x2]+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(keccak_f1600_x2_v84a_aarch64_asm)++#endif /* __ARM_FEATURE_SHA3 */++#endif /* MLK_FIPS202_AARCH64_NEED_X2_V84A && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,1079 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++// Author: Hanno Becker <hannobecker@posteo.de>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>++/*yaml+ Name: keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm+ Description: AArch64 hybrid scalar/vector implementation of Keccak-f[1600] permutation for four sequential states+ Signature: void mlk_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm(uint64_t state[100], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 800+ permissions: read/write+ c_parameter: uint64_t state[100]+ description: Four sequential Keccak states (state0[25], state1[25], state2[25], state3[25])+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: const uint64_t rc[24]+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 224+ description: register preservation and temporary storage+*/++#include "../../../../common.h"+#if defined(MLK_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm)+MLK_ASM_FN_SYMBOL(keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0xe0+ .cfi_adjust_cfa_offset 0xe0+ stp x19, x20, [sp, #0x30]+ .cfi_rel_offset x19, 0x30+ .cfi_rel_offset x20, 0x38+ stp x21, x22, [sp, #0x40]+ .cfi_rel_offset x21, 0x40+ .cfi_rel_offset x22, 0x48+ stp x23, x24, [sp, #0x50]+ .cfi_rel_offset x23, 0x50+ .cfi_rel_offset x24, 0x58+ stp x25, x26, [sp, #0x60]+ .cfi_rel_offset x25, 0x60+ .cfi_rel_offset x26, 0x68+ stp x27, x28, [sp, #0x70]+ .cfi_rel_offset x27, 0x70+ .cfi_rel_offset x28, 0x78+ stp x29, x30, [sp, #0x80]+ .cfi_rel_offset x29, 0x80+ .cfi_rel_offset x30, 0x88+ stp d8, d9, [sp, #0x90]+ .cfi_rel_offset d8, 0x90+ .cfi_rel_offset d9, 0x98+ stp d10, d11, [sp, #0xa0]+ .cfi_rel_offset d10, 0xa0+ .cfi_rel_offset d11, 0xa8+ stp d12, d13, [sp, #0xb0]+ .cfi_rel_offset d12, 0xb0+ .cfi_rel_offset d13, 0xb8+ stp d14, d15, [sp, #0xc0]+ .cfi_rel_offset d14, 0xc0+ .cfi_rel_offset d15, 0xc8+ mov x29, x1+ mov x30, #0x0 // =0+ str x30, [sp, #0x20]+ str x29, [sp, #0x8]+ str x29, [sp, #0x10]+ str x0, [sp]+ add x4, x0, #0xc8+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v0.2d, v25.2d, v27.2d+ trn2 v1.2d, v25.2d, v27.2d+ trn1 v2.2d, v26.2d, v28.2d+ trn2 v3.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v4.2d, v25.2d, v27.2d+ trn2 v5.2d, v25.2d, v27.2d+ trn1 v6.2d, v26.2d, v28.2d+ trn2 v7.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v8.2d, v25.2d, v27.2d+ trn2 v9.2d, v25.2d, v27.2d+ trn1 v10.2d, v26.2d, v28.2d+ trn2 v11.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v12.2d, v25.2d, v27.2d+ trn2 v13.2d, v25.2d, v27.2d+ trn1 v14.2d, v26.2d, v28.2d+ trn2 v15.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v16.2d, v25.2d, v27.2d+ trn2 v17.2d, v25.2d, v27.2d+ trn1 v18.2d, v26.2d, v28.2d+ trn2 v19.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v20.2d, v25.2d, v27.2d+ trn2 v21.2d, v25.2d, v27.2d+ trn1 v22.2d, v26.2d, v28.2d+ trn2 v23.2d, v26.2d, v28.2d+ ldr d25, [x0]+ ldr d27, [x4]+ trn1 v24.2d, v25.2d, v27.2d+ sub x0, x0, #0xc0+ add x0, x0, #0x190+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ sub x0, x0, #0x190++Lmlk_keccak_f1600_x4_v8a_scalar_hybrid_initial:+ eor x30, x24, x25+ eor x27, x9, x10+ eor v30.16b, v0.16b, v5.16b+ eor v30.16b, v30.16b, v10.16b+ eor x0, x30, x21+ eor v30.16b, v30.16b, v15.16b+ eor x26, x27, x6+ eor x27, x26, x7+ eor v30.16b, v30.16b, v20.16b+ eor x29, x0, x22+ eor v29.16b, v1.16b, v6.16b+ eor x26, x29, x23+ eor v29.16b, v29.16b, v11.16b+ eor x29, x4, x5+ eor x30, x29, x1+ eor v29.16b, v29.16b, v16.16b+ eor x0, x27, x8+ eor v29.16b, v29.16b, v21.16b+ eor x29, x30, x2+ eor v28.16b, v2.16b, v7.16b+ eor x30, x19, x20+ eor x30, x30, x16+ eor v28.16b, v28.16b, v12.16b+ eor x27, x26, x0, ror #63+ eor v28.16b, v28.16b, v17.16b+ eor x4, x4, x27+ eor v28.16b, v28.16b, v22.16b+ eor x30, x30, x17+ eor x30, x30, x28+ eor v27.16b, v3.16b, v8.16b+ eor x29, x29, x3+ eor v27.16b, v27.16b, v13.16b+ eor x0, x0, x30, ror #63+ eor v27.16b, v27.16b, v18.16b+ eor x30, x30, x29, ror #63+ eor x22, x22, x30+ eor v27.16b, v27.16b, v23.16b+ eor x23, x23, x30+ eor v26.16b, v4.16b, v9.16b+ str x23, [sp, #0xd0]+ eor v26.16b, v26.16b, v14.16b+ eor x23, x14, x15+ eor x14, x14, x0+ eor v26.16b, v26.16b, v19.16b+ eor x23, x23, x11+ eor v26.16b, v26.16b, v24.16b+ eor x15, x15, x0+ eor x1, x1, x27+ add v31.2d, v28.2d, v28.2d+ eor x23, x23, x12+ sri v31.2d, v28.2d, #0x3f+ eor x23, x23, x13+ eor v25.16b, v31.16b, v30.16b+ eor x11, x11, x0+ eor x29, x29, x23, ror #63+ add v31.2d, v26.2d, v26.2d+ eor x23, x23, x26, ror #63+ sri v31.2d, v26.2d, #0x3f+ eor x26, x13, x0+ eor v28.16b, v31.16b, v28.16b+ eor x13, x28, x23+ eor x28, x24, x30+ add v31.2d, v29.2d, v29.2d+ eor x24, x16, x23+ sri v31.2d, v29.2d, #0x3f+ eor x16, x21, x30+ eor v26.16b, v31.16b, v26.16b+ eor x21, x25, x30+ eor x30, x19, x23+ add v31.2d, v27.2d, v27.2d+ eor x19, x20, x23+ sri v31.2d, v27.2d, #0x3f+ eor x20, x17, x23+ eor v29.16b, v31.16b, v29.16b+ eor x17, x12, x0+ eor x0, x2, x27+ add v31.2d, v30.2d, v30.2d+ eor x2, x6, x29+ sri v31.2d, v30.2d, #0x3f+ eor x6, x8, x29+ eor v27.16b, v31.16b, v27.16b+ bic x8, x28, x13, ror #47+ eor x12, x3, x27+ eor v30.16b, v0.16b, v26.16b+ bic x3, x13, x17, ror #19+ eor v31.16b, v2.16b, v29.16b+ eor x5, x5, x27+ ldr x27, [sp, #0xd0]+ shl v0.2d, v31.2d, #0x3e+ bic x25, x17, x2, ror #5+ sri v0.2d, v31.2d, #0x2+ eor x9, x9, x29+ eor v31.16b, v12.16b, v29.16b+ eor x23, x25, x5, ror #52+ eor x3, x3, x2, ror #24+ shl v2.2d, v31.2d, #0x2b+ eor x8, x8, x17, ror #2+ sri v2.2d, v31.2d, #0x15+ eor x17, x10, x29+ eor v31.16b, v13.16b, v28.16b+ bic x25, x12, x22, ror #47+ eor x29, x7, x29+ shl v12.2d, v31.2d, #0x19+ bic x10, x4, x27, ror #2+ sri v12.2d, v31.2d, #0x27+ bic x7, x5, x28, ror #10+ eor v31.16b, v19.16b, v27.16b+ eor x10, x10, x20, ror #50+ eor x13, x7, x13, ror #57+ shl v13.2d, v31.2d, #0x8+ bic x7, x2, x5, ror #47+ sri v13.2d, v31.2d, #0x38+ eor x2, x25, x24, ror #39+ eor v31.16b, v23.16b, v28.16b+ bic x25, x20, x11, ror #57+ bic x5, x17, x4, ror #25+ shl v19.2d, v31.2d, #0x38+ eor x25, x25, x17, ror #53+ sri v19.2d, v31.2d, #0x8+ bic x17, x11, x17, ror #60+ eor v31.16b, v15.16b, v26.16b+ eor x28, x7, x28, ror #57+ bic x7, x9, x12, ror #42+ shl v23.2d, v31.2d, #0x29+ eor x7, x7, x22, ror #25+ sri v23.2d, v31.2d, #0x17+ bic x22, x22, x24, ror #56+ bic x24, x24, x15, ror #31+ eor v31.16b, v1.16b, v25.16b+ eor x22, x22, x15, ror #23+ shl v15.2d, v31.2d, #0x1+ bic x20, x27, x20, ror #48+ sri v15.2d, v31.2d, #0x3f+ bic x15, x15, x9, ror #16+ eor x12, x15, x12, ror #58+ eor v31.16b, v8.16b, v28.16b+ eor x15, x5, x27, ror #27+ shl v1.2d, v31.2d, #0x37+ eor x5, x20, x11, ror #41+ sri v1.2d, v31.2d, #0x9+ ldr x11, [sp, #0x8]+ eor x20, x17, x4, ror #21+ eor v31.16b, v16.16b, v25.16b+ eor x17, x24, x9, ror #47+ shl v8.2d, v31.2d, #0x2d+ mov x24, #0x1 // =1+ sri v8.2d, v31.2d, #0x13+ bic x9, x0, x16, ror #9+ str x24, [sp, #0x18]+ eor v31.16b, v7.16b, v29.16b+ bic x24, x29, x1, ror #44+ shl v16.2d, v31.2d, #0x6+ bic x27, x1, x21, ror #50+ sri v16.2d, v31.2d, #0x3a+ bic x4, x26, x29, ror #63+ eor x1, x1, x4, ror #21+ eor v31.16b, v10.16b, v26.16b+ ldr x11, [x11]+ shl v7.2d, v31.2d, #0x3+ bic x4, x21, x30, ror #57+ sri v7.2d, v31.2d, #0x3d+ eor x21, x24, x21, ror #30+ eor x24, x9, x19, ror #44+ eor v31.16b, v3.16b, v28.16b+ bic x9, x14, x6, ror #5+ shl v10.2d, v31.2d, #0x1c+ eor x9, x9, x0, ror #43+ sri v10.2d, v31.2d, #0x24+ bic x0, x6, x0, ror #38+ eor x1, x1, x11+ eor v31.16b, v18.16b, v28.16b+ eor x11, x4, x26, ror #35+ shl v3.2d, v31.2d, #0x15+ eor x4, x0, x16, ror #47+ bic x0, x16, x19, ror #35+ sri v3.2d, v31.2d, #0x2b+ eor x16, x27, x30, ror #43+ eor v31.16b, v17.16b, v29.16b+ bic x27, x30, x26, ror #42+ shl v18.2d, v31.2d, #0xf+ bic x26, x19, x14, ror #41+ eor x19, x0, x14, ror #12+ sri v18.2d, v31.2d, #0x31+ eor x14, x26, x6, ror #46+ eor v31.16b, v11.16b, v25.16b+ eor x6, x27, x29, ror #41+ shl v17.2d, v31.2d, #0xa+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ sri v17.2d, v31.2d, #0x36+ eor x26, x8, x9, ror #57+ eor v31.16b, v9.16b, v27.16b+ eor x27, x0, x14, ror #10+ shl v11.2d, v31.2d, #0x14+ eor x29, x16, x28, ror #63+ eor x26, x26, x6, ror #51+ sri v11.2d, v31.2d, #0x2c+ eor x30, x23, x22, ror #50+ eor v31.16b, v22.16b, v29.16b+ eor x0, x26, x10, ror #31+ shl v9.2d, v31.2d, #0x3d+ eor x29, x29, x19, ror #37+ eor x27, x27, x12, ror #5+ sri v9.2d, v31.2d, #0x3+ eor x30, x30, x24, ror #34+ eor v31.16b, v14.16b, v27.16b+ eor x0, x0, x7, ror #27+ shl v22.2d, v31.2d, #0x27+ eor x26, x30, x21, ror #26+ eor x26, x26, x25, ror #15+ sri v22.2d, v31.2d, #0x19+ ror x30, x27, #0x3e+ eor v31.16b, v20.16b, v26.16b+ eor x30, x30, x26, ror #57+ ror x26, x26, #0x3a+ shl v14.2d, v31.2d, #0x12+ eor x16, x30, x16+ sri v14.2d, v31.2d, #0x2e+ eor x28, x30, x28, ror #63+ eor v31.16b, v4.16b, v27.16b+ str x28, [sp, #0xd0]+ eor x29, x29, x17, ror #36+ shl v20.2d, v31.2d, #0x1b+ eor x28, x1, x2, ror #61+ sri v20.2d, v31.2d, #0x25+ eor x19, x30, x19, ror #37+ eor v31.16b, v24.16b, v27.16b+ eor x29, x29, x20, ror #2+ eor x28, x28, x4, ror #54+ shl v4.2d, v31.2d, #0xe+ eor x26, x26, x0, ror #55+ sri v4.2d, v31.2d, #0x32+ eor x28, x28, x3, ror #39+ eor v31.16b, v21.16b, v25.16b+ eor x28, x28, x5, ror #25+ ror x0, x0, #0x38+ shl v24.2d, v31.2d, #0x2+ eor x0, x0, x29, ror #63+ sri v24.2d, v31.2d, #0x3e+ eor x27, x28, x27, ror #61+ eor v31.16b, v5.16b, v26.16b+ eor x13, x0, x13, ror #46+ eor x28, x29, x28, ror #63+ shl v21.2d, v31.2d, #0x24+ eor x29, x30, x20, ror #2+ sri v21.2d, v31.2d, #0x1c+ eor x20, x26, x3, ror #39+ eor v31.16b, v6.16b, v25.16b+ eor x11, x0, x11, ror #50+ eor x25, x28, x25, ror #9+ shl v27.2d, v31.2d, #0x2c+ eor x3, x28, x21, ror #20+ sri v27.2d, v31.2d, #0x14+ eor x21, x26, x1+ eor x9, x27, x9, ror #49+ bic v31.16b, v7.16b, v11.16b+ eor x24, x28, x24, ror #28+ eor v5.16b, v31.16b, v10.16b+ eor x1, x30, x17, ror #36+ bic v31.16b, v8.16b, v7.16b+ eor x14, x0, x14, ror #8+ eor x22, x28, x22, ror #44+ eor v6.16b, v31.16b, v11.16b+ eor x8, x27, x8, ror #56+ bic v31.16b, v9.16b, v8.16b+ eor x17, x27, x7, ror #19+ eor v7.16b, v31.16b, v7.16b+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ bic v31.16b, v10.16b, v9.16b+ eor x4, x26, x4, ror #54+ eor v8.16b, v31.16b, v8.16b+ eor x0, x0, x12, ror #3+ bic v31.16b, v11.16b, v10.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ eor v9.16b, v31.16b, v9.16b+ eor x26, x26, x5, ror #25+ bic v31.16b, v12.16b, v16.16b+ eor x2, x7, x16, ror #39+ eor v10.16b, v31.16b, v15.16b+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ bic v31.16b, v13.16b, v12.16b+ eor x7, x7, x22, ror #25+ eor v11.16b, v31.16b, v16.16b+ eor x12, x30, x20, ror #58+ bic v31.16b, v14.16b, v13.16b+ bic x20, x22, x16, ror #56+ eor x30, x27, x6, ror #43+ eor v12.16b, v31.16b, v12.16b+ eor x22, x20, x15, ror #23+ bic v31.16b, v15.16b, v14.16b+ bic x6, x19, x13, ror #42+ eor v13.16b, v31.16b, v13.16b+ eor x6, x6, x17, ror #41+ bic x5, x13, x17, ror #63+ bic v31.16b, v16.16b, v15.16b+ eor x5, x21, x5, ror #21+ eor v14.16b, v31.16b, v14.16b+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ bic v31.16b, v17.16b, v21.16b+ bic x21, x21, x25, ror #50+ eor v15.16b, v31.16b, v20.16b+ bic x20, x27, x4, ror #25+ bic v31.16b, v18.16b, v17.16b+ bic x10, x16, x15, ror #31+ eor x16, x21, x19, ror #43+ eor v16.16b, v31.16b, v21.16b+ eor x21, x17, x25, ror #30+ bic v31.16b, v19.16b, v18.16b+ bic x19, x25, x19, ror #57+ eor v17.16b, v31.16b, v17.16b+ ldr x25, [sp, #0x18]+ eor x17, x10, x9, ror #47+ bic v31.16b, v20.16b, v19.16b+ ldr x9, [sp, #0x8]+ eor v18.16b, v31.16b, v18.16b+ eor x15, x20, x28, ror #27+ bic v31.16b, v21.16b, v20.16b+ bic x20, x4, x28, ror #2+ eor x10, x20, x1, ror #50+ eor v19.16b, v31.16b, v19.16b+ bic x20, x11, x27, ror #60+ bic v31.16b, v22.16b, v1.16b+ eor x20, x20, x4, ror #21+ eor v20.16b, v31.16b, v0.16b+ bic x4, x28, x1, ror #48+ bic x1, x1, x11, ror #57+ bic v31.16b, v23.16b, v22.16b+ ldr x28, [x9, x25, lsl #3]+ eor v21.16b, v31.16b, v1.16b+ ldr x9, [sp, #0xd0]+ bic v31.16b, v24.16b, v23.16b+ add x25, x25, #0x1+ str x25, [sp, #0x18]+ eor v22.16b, v31.16b, v22.16b+ cmp x25, #0x17+ bic v31.16b, v0.16b, v24.16b+ eor x25, x1, x27, ror #53+ bic x27, x30, x26, ror #47+ eor v23.16b, v31.16b, v23.16b+ eor x1, x5, x28+ bic v31.16b, v1.16b, v0.16b+ eor x5, x4, x11, ror #41+ eor v24.16b, v31.16b, v24.16b+ eor x11, x19, x13, ror #35+ bic x13, x26, x24, ror #10+ bic v31.16b, v2.16b, v27.16b+ eor x28, x27, x24, ror #57+ eor v0.16b, v31.16b, v30.16b+ bic x27, x24, x9, ror #47+ bic v31.16b, v3.16b, v2.16b+ bic x19, x23, x3, ror #9+ bic x4, x29, x14, ror #41+ eor v1.16b, v31.16b, v27.16b+ eor x24, x19, x29, ror #44+ bic v31.16b, v4.16b, v3.16b+ bic x29, x3, x29, ror #35+ eor v2.16b, v31.16b, v2.16b+ eor x13, x13, x9, ror #57+ eor x19, x29, x14, ror #12+ bic v31.16b, v30.16b, v4.16b+ bic x29, x9, x0, ror #19+ eor v3.16b, v31.16b, v3.16b+ bic x14, x14, x8, ror #5+ bic v31.16b, v27.16b, v30.16b+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ eor v4.16b, v31.16b, v4.16b+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ ldr x30, [sp, #0x10]+ ld1r { v28.2d }, [x30], #8+ str x30, [sp, #0x10]+ eor v0.16b, v0.16b, v28.16b++Lmlk_keccak_f1600_x4_v8a_scalar_hybrid_loop:+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ eor v30.16b, v0.16b, v5.16b+ eor v30.16b, v30.16b, v10.16b+ eor x26, x8, x9, ror #57+ eor v30.16b, v30.16b, v15.16b+ eor x27, x0, x14, ror #10+ eor x29, x16, x28, ror #63+ eor v30.16b, v30.16b, v20.16b+ eor x26, x26, x6, ror #51+ eor v29.16b, v1.16b, v6.16b+ eor x30, x23, x22, ror #50+ eor v29.16b, v29.16b, v11.16b+ eor x0, x26, x10, ror #31+ eor x29, x29, x19, ror #37+ eor v29.16b, v29.16b, v16.16b+ eor x27, x27, x12, ror #5+ eor v29.16b, v29.16b, v21.16b+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ eor v28.16b, v2.16b, v7.16b+ eor x26, x30, x21, ror #26+ eor v28.16b, v28.16b, v12.16b+ eor x26, x26, x25, ror #15+ eor v28.16b, v28.16b, v17.16b+ ror x30, x27, #0x3e+ eor x30, x30, x26, ror #57+ eor v28.16b, v28.16b, v22.16b+ ror x26, x26, #0x3a+ eor v27.16b, v3.16b, v8.16b+ eor x16, x30, x16+ eor v27.16b, v27.16b, v13.16b+ eor x28, x30, x28, ror #63+ str x28, [sp, #0xd0]+ eor v27.16b, v27.16b, v18.16b+ eor x29, x29, x17, ror #36+ eor v27.16b, v27.16b, v23.16b+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ eor v26.16b, v4.16b, v9.16b+ eor x29, x29, x20, ror #2+ eor v26.16b, v26.16b, v14.16b+ eor x28, x28, x4, ror #54+ eor v26.16b, v26.16b, v19.16b+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ eor v26.16b, v26.16b, v24.16b+ eor x28, x28, x5, ror #25+ add v31.2d, v28.2d, v28.2d+ ror x0, x0, #0x38+ eor x0, x0, x29, ror #63+ sri v31.2d, v28.2d, #0x3f+ eor x27, x28, x27, ror #61+ eor v25.16b, v31.16b, v30.16b+ eor x13, x0, x13, ror #46+ add v31.2d, v26.2d, v26.2d+ eor x28, x29, x28, ror #63+ eor x29, x30, x20, ror #2+ sri v31.2d, v26.2d, #0x3f+ eor x20, x26, x3, ror #39+ eor v28.16b, v31.16b, v28.16b+ eor x11, x0, x11, ror #50+ add v31.2d, v29.2d, v29.2d+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ sri v31.2d, v29.2d, #0x3f+ eor x21, x26, x1+ eor v26.16b, v31.16b, v26.16b+ eor x9, x27, x9, ror #49+ eor x24, x28, x24, ror #28+ add v31.2d, v27.2d, v27.2d+ eor x1, x30, x17, ror #36+ sri v31.2d, v27.2d, #0x3f+ eor x14, x0, x14, ror #8+ eor v29.16b, v31.16b, v29.16b+ eor x22, x28, x22, ror #44+ eor x8, x27, x8, ror #56+ add v31.2d, v30.2d, v30.2d+ eor x17, x27, x7, ror #19+ sri v31.2d, v30.2d, #0x3f+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ eor v27.16b, v31.16b, v27.16b+ eor x4, x26, x4, ror #54+ eor v30.16b, v0.16b, v26.16b+ eor x0, x0, x12, ror #3+ eor v31.16b, v2.16b, v29.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ shl v0.2d, v31.2d, #0x3e+ eor x26, x26, x5, ror #25+ sri v0.2d, v31.2d, #0x2+ eor x2, x7, x16, ror #39+ eor v31.16b, v12.16b, v29.16b+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ shl v2.2d, v31.2d, #0x2b+ eor x7, x7, x22, ror #25+ sri v2.2d, v31.2d, #0x15+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ eor v31.16b, v13.16b, v28.16b+ eor x30, x27, x6, ror #43+ shl v12.2d, v31.2d, #0x19+ eor x22, x20, x15, ror #23+ sri v12.2d, v31.2d, #0x27+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ eor v31.16b, v19.16b, v27.16b+ bic x5, x13, x17, ror #63+ shl v13.2d, v31.2d, #0x8+ eor x5, x21, x5, ror #21+ sri v13.2d, v31.2d, #0x38+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ eor v31.16b, v23.16b, v28.16b+ bic x21, x21, x25, ror #50+ shl v19.2d, v31.2d, #0x38+ bic x20, x27, x4, ror #25+ bic x10, x16, x15, ror #31+ sri v19.2d, v31.2d, #0x8+ eor x16, x21, x19, ror #43+ eor v31.16b, v15.16b, v26.16b+ eor x21, x17, x25, ror #30+ shl v23.2d, v31.2d, #0x29+ bic x19, x25, x19, ror #57+ ldr x25, [sp, #0x18]+ sri v23.2d, v31.2d, #0x17+ eor x17, x10, x9, ror #47+ eor v31.16b, v1.16b, v25.16b+ ldr x9, [sp, #0x8]+ eor x15, x20, x28, ror #27+ shl v15.2d, v31.2d, #0x1+ bic x20, x4, x28, ror #2+ sri v15.2d, v31.2d, #0x3f+ eor x10, x20, x1, ror #50+ eor v31.16b, v8.16b, v28.16b+ bic x20, x11, x27, ror #60+ eor x20, x20, x4, ror #21+ shl v1.2d, v31.2d, #0x37+ bic x4, x28, x1, ror #48+ sri v1.2d, v31.2d, #0x9+ bic x1, x1, x11, ror #57+ eor v31.16b, v16.16b, v25.16b+ ldr x28, [x9, x25, lsl #3]+ ldr x9, [sp, #0xd0]+ shl v8.2d, v31.2d, #0x2d+ add x25, x25, #0x1+ sri v8.2d, v31.2d, #0x13+ str x25, [sp, #0x18]+ cmp x25, #0x17+ eor v31.16b, v7.16b, v29.16b+ eor x25, x1, x27, ror #53+ shl v16.2d, v31.2d, #0x6+ bic x27, x30, x26, ror #47+ sri v16.2d, v31.2d, #0x3a+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ eor v31.16b, v10.16b, v26.16b+ eor x11, x19, x13, ror #35+ shl v7.2d, v31.2d, #0x3+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ sri v7.2d, v31.2d, #0x3d+ bic x27, x24, x9, ror #47+ eor v31.16b, v3.16b, v28.16b+ bic x19, x23, x3, ror #9+ shl v10.2d, v31.2d, #0x1c+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ sri v10.2d, v31.2d, #0x24+ bic x29, x3, x29, ror #35+ eor v31.16b, v18.16b, v28.16b+ eor x13, x13, x9, ror #57+ shl v3.2d, v31.2d, #0x15+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ sri v3.2d, v31.2d, #0x2b+ bic x14, x14, x8, ror #5+ eor v31.16b, v17.16b, v29.16b+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ shl v18.2d, v31.2d, #0xf+ bic x23, x8, x23, ror #38+ sri v18.2d, v31.2d, #0x31+ eor x8, x27, x0, ror #2+ eor v31.16b, v11.16b, v25.16b+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ shl v17.2d, v31.2d, #0xa+ eor x23, x3, x26, ror #52+ sri v17.2d, v31.2d, #0x36+ eor x3, x29, x30, ror #24+ eor x0, x15, x11, ror #52+ eor v31.16b, v9.16b, v27.16b+ eor x0, x0, x13, ror #48+ shl v11.2d, v31.2d, #0x14+ eor x26, x8, x9, ror #57+ sri v11.2d, v31.2d, #0x2c+ eor x27, x0, x14, ror #10+ eor x29, x16, x28, ror #63+ eor v31.16b, v22.16b, v29.16b+ eor x26, x26, x6, ror #51+ shl v9.2d, v31.2d, #0x3d+ eor x30, x23, x22, ror #50+ sri v9.2d, v31.2d, #0x3+ eor x0, x26, x10, ror #31+ eor x29, x29, x19, ror #37+ eor v31.16b, v14.16b, v27.16b+ eor x27, x27, x12, ror #5+ shl v22.2d, v31.2d, #0x27+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ sri v22.2d, v31.2d, #0x19+ eor x26, x30, x21, ror #26+ eor v31.16b, v20.16b, v26.16b+ eor x26, x26, x25, ror #15+ shl v14.2d, v31.2d, #0x12+ ror x30, x27, #0x3e+ eor x30, x30, x26, ror #57+ sri v14.2d, v31.2d, #0x2e+ ror x26, x26, #0x3a+ eor v31.16b, v4.16b, v27.16b+ eor x16, x30, x16+ shl v20.2d, v31.2d, #0x1b+ eor x28, x30, x28, ror #63+ str x28, [sp, #0xd0]+ sri v20.2d, v31.2d, #0x25+ eor x29, x29, x17, ror #36+ eor v31.16b, v24.16b, v27.16b+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ shl v4.2d, v31.2d, #0xe+ eor x29, x29, x20, ror #2+ sri v4.2d, v31.2d, #0x32+ eor x28, x28, x4, ror #54+ eor v31.16b, v21.16b, v25.16b+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ shl v24.2d, v31.2d, #0x2+ eor x28, x28, x5, ror #25+ sri v24.2d, v31.2d, #0x3e+ ror x0, x0, #0x38+ eor x0, x0, x29, ror #63+ eor v31.16b, v5.16b, v26.16b+ eor x27, x28, x27, ror #61+ shl v21.2d, v31.2d, #0x24+ eor x13, x0, x13, ror #46+ sri v21.2d, v31.2d, #0x1c+ eor x28, x29, x28, ror #63+ eor x29, x30, x20, ror #2+ eor v31.16b, v6.16b, v25.16b+ eor x20, x26, x3, ror #39+ shl v27.2d, v31.2d, #0x2c+ eor x11, x0, x11, ror #50+ sri v27.2d, v31.2d, #0x14+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ bic v31.16b, v7.16b, v11.16b+ eor x21, x26, x1+ eor v5.16b, v31.16b, v10.16b+ eor x9, x27, x9, ror #49+ eor x24, x28, x24, ror #28+ bic v31.16b, v8.16b, v7.16b+ eor x1, x30, x17, ror #36+ eor v6.16b, v31.16b, v11.16b+ eor x14, x0, x14, ror #8+ bic v31.16b, v9.16b, v8.16b+ eor x22, x28, x22, ror #44+ eor x8, x27, x8, ror #56+ eor v7.16b, v31.16b, v7.16b+ eor x17, x27, x7, ror #19+ bic v31.16b, v10.16b, v9.16b+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ eor v8.16b, v31.16b, v8.16b+ eor x4, x26, x4, ror #54+ bic v31.16b, v11.16b, v10.16b+ eor x0, x0, x12, ror #3+ eor v9.16b, v31.16b, v9.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ bic v31.16b, v12.16b, v16.16b+ eor x26, x26, x5, ror #25+ eor v10.16b, v31.16b, v15.16b+ eor x2, x7, x16, ror #39+ bic v31.16b, v13.16b, v12.16b+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ eor v11.16b, v31.16b, v16.16b+ eor x7, x7, x22, ror #25+ bic v31.16b, v14.16b, v13.16b+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ eor v12.16b, v31.16b, v12.16b+ eor x30, x27, x6, ror #43+ bic v31.16b, v15.16b, v14.16b+ eor x22, x20, x15, ror #23+ eor v13.16b, v31.16b, v13.16b+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ bic v31.16b, v16.16b, v15.16b+ bic x5, x13, x17, ror #63+ eor v14.16b, v31.16b, v14.16b+ eor x5, x21, x5, ror #21+ bic v31.16b, v17.16b, v21.16b+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ eor v15.16b, v31.16b, v20.16b+ bic x21, x21, x25, ror #50+ bic v31.16b, v18.16b, v17.16b+ bic x20, x27, x4, ror #25+ bic x10, x16, x15, ror #31+ eor v16.16b, v31.16b, v21.16b+ eor x16, x21, x19, ror #43+ bic v31.16b, v19.16b, v18.16b+ eor x21, x17, x25, ror #30+ eor v17.16b, v31.16b, v17.16b+ bic x19, x25, x19, ror #57+ ldr x25, [sp, #0x18]+ bic v31.16b, v20.16b, v19.16b+ eor x17, x10, x9, ror #47+ eor v18.16b, v31.16b, v18.16b+ ldr x9, [sp, #0x8]+ eor x15, x20, x28, ror #27+ bic v31.16b, v21.16b, v20.16b+ bic x20, x4, x28, ror #2+ eor v19.16b, v31.16b, v19.16b+ eor x10, x20, x1, ror #50+ bic v31.16b, v22.16b, v1.16b+ bic x20, x11, x27, ror #60+ eor x20, x20, x4, ror #21+ eor v20.16b, v31.16b, v0.16b+ bic x4, x28, x1, ror #48+ bic v31.16b, v23.16b, v22.16b+ bic x1, x1, x11, ror #57+ eor v21.16b, v31.16b, v1.16b+ ldr x28, [x9, x25, lsl #3]+ ldr x9, [sp, #0xd0]+ bic v31.16b, v24.16b, v23.16b+ add x25, x25, #0x1+ eor v22.16b, v31.16b, v22.16b+ str x25, [sp, #0x18]+ cmp x25, #0x17+ bic v31.16b, v0.16b, v24.16b+ eor x25, x1, x27, ror #53+ eor v23.16b, v31.16b, v23.16b+ bic x27, x30, x26, ror #47+ bic v31.16b, v1.16b, v0.16b+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ eor v24.16b, v31.16b, v24.16b+ eor x11, x19, x13, ror #35+ bic v31.16b, v2.16b, v27.16b+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ eor v0.16b, v31.16b, v30.16b+ bic x27, x24, x9, ror #47+ bic v31.16b, v3.16b, v2.16b+ bic x19, x23, x3, ror #9+ eor v1.16b, v31.16b, v27.16b+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ bic v31.16b, v4.16b, v3.16b+ bic x29, x3, x29, ror #35+ eor v2.16b, v31.16b, v2.16b+ eor x13, x13, x9, ror #57+ bic v31.16b, v30.16b, v4.16b+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ eor v3.16b, v31.16b, v3.16b+ bic x14, x14, x8, ror #5+ bic v31.16b, v27.16b, v30.16b+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ eor v4.16b, v31.16b, v4.16b+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ ldr x30, [sp, #0x10]+ ld1r { v28.2d }, [x30], #8+ str x30, [sp, #0x10]+ eor v0.16b, v0.16b, v28.16b++Lmlk_keccak_f1600_x4_v8a_scalar_hybrid_loop_end:+ b.le Lmlk_keccak_f1600_x4_v8a_scalar_hybrid_loop+ ror x2, x2, #0x3d+ ror x3, x3, #0x27+ ror x4, x4, #0x36+ ror x5, x5, #0x19+ ror x6, x6, #0x2b+ ror x7, x7, #0x13+ ror x8, x8, #0x38+ ror x9, x9, #0x31+ ror x10, x10, #0x17+ ror x11, x11, #0x32+ ror x12, x12, #0x3+ ror x13, x13, #0x2e+ ror x14, x14, #0x8+ ror x15, x15, #0x3e+ ror x17, x17, #0x24+ ror x28, x28, #0x3f+ ror x19, x19, #0x25+ ror x20, x20, #0x2+ ror x21, x21, #0x14+ ror x22, x22, #0x2c+ ror x23, x23, #0x3a+ ror x24, x24, #0x1c+ ror x25, x25, #0x9+ ldr x30, [sp, #0x20]+ cmp x30, #0x1+ b.eq Lmlk_keccak_f1600_x4_v8a_scalar_hybrid_done+ mov x30, #0x1 // =1+ str x30, [sp, #0x20]+ ldr x0, [sp]+ add x0, x0, #0x190+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ sub x0, x0, #0x190+ add x0, x0, #0x258+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ sub x0, x0, #0x258+ b Lmlk_keccak_f1600_x4_v8a_scalar_hybrid_initial++Lmlk_keccak_f1600_x4_v8a_scalar_hybrid_done:+ ldr x0, [sp]+ add x0, x0, #0x258+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ sub x0, x0, #0x258+ add x4, x0, #0xc8+ trn1 v25.2d, v0.2d, v1.2d+ trn1 v26.2d, v2.2d, v3.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v0.2d, v1.2d+ trn2 v28.2d, v2.2d, v3.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v4.2d, v5.2d+ trn1 v26.2d, v6.2d, v7.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v4.2d, v5.2d+ trn2 v28.2d, v6.2d, v7.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v8.2d, v9.2d+ trn1 v26.2d, v10.2d, v11.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v8.2d, v9.2d+ trn2 v28.2d, v10.2d, v11.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v12.2d, v13.2d+ trn1 v26.2d, v14.2d, v15.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v12.2d, v13.2d+ trn2 v28.2d, v14.2d, v15.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v16.2d, v17.2d+ trn1 v26.2d, v18.2d, v19.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v16.2d, v17.2d+ trn2 v28.2d, v18.2d, v19.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v20.2d, v21.2d+ trn1 v26.2d, v22.2d, v23.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v20.2d, v21.2d+ trn2 v28.2d, v22.2d, v23.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ str d24, [x0]+ trn2 v25.2d, v24.2d, v24.2d+ str d25, [x4]+ ldp d8, d9, [sp, #0x90]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0xa0]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0xb0]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0xc0]+ .cfi_restore d14+ .cfi_restore d15+ ldp x19, x20, [sp, #0x30]+ .cfi_restore x19+ .cfi_restore x20+ ldp x21, x22, [sp, #0x40]+ .cfi_restore x21+ .cfi_restore x22+ ldp x23, x24, [sp, #0x50]+ .cfi_restore x23+ .cfi_restore x24+ ldp x25, x26, [sp, #0x60]+ .cfi_restore x25+ .cfi_restore x26+ ldp x27, x28, [sp, #0x70]+ .cfi_restore x27+ .cfi_restore x28+ ldp x29, x30, [sp, #0x80]+ .cfi_restore x29+ .cfi_restore x30+ add sp, sp, #0xe0+ .cfi_adjust_cfa_offset -0xe0+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm)++#endif /* MLK_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID && \+ !MLK_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,989 @@+/*+ * Copyright (c) The mlkem-native project authors+ * Copyright (c) 2021-2022 Arm Limited+ * Copyright (c) 2022 Matthias Kannwischer+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++// Author: Hanno Becker <hannobecker@posteo.de>+// Author: Matthias Kannwischer <matthias@kannwischer.eu>++/*yaml+ Name: keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm+ Description: AArch64 hybrid scalar/vector implementation of Keccak-f[1600] permutation for four sequential states with ARMv8.4-A optimizations+ Signature: void mlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm(uint64_t state[100], const uint64_t rc[24])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON, SHA3]+ x0:+ type: buffer+ size_bytes: 800+ permissions: read/write+ c_parameter: uint64_t state[100]+ description: Four sequential Keccak states (state0[25], state1[25], state2[25], state3[25])+ x1:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: const uint64_t rc[24]+ description: Round constants (24 x uint64_t)+ Stack:+ bytes: 224+ description: register preservation and temporary storage+*/++#include "../../../../common.h"+#if defined(MLK_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#if defined(__ARM_FEATURE_SHA3)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/fips202/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm)+MLK_ASM_FN_SYMBOL(keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0xe0+ .cfi_adjust_cfa_offset 0xe0+ stp x19, x20, [sp, #0x30]+ .cfi_rel_offset x19, 0x30+ .cfi_rel_offset x20, 0x38+ stp x21, x22, [sp, #0x40]+ .cfi_rel_offset x21, 0x40+ .cfi_rel_offset x22, 0x48+ stp x23, x24, [sp, #0x50]+ .cfi_rel_offset x23, 0x50+ .cfi_rel_offset x24, 0x58+ stp x25, x26, [sp, #0x60]+ .cfi_rel_offset x25, 0x60+ .cfi_rel_offset x26, 0x68+ stp x27, x28, [sp, #0x70]+ .cfi_rel_offset x27, 0x70+ .cfi_rel_offset x28, 0x78+ stp x29, x30, [sp, #0x80]+ .cfi_rel_offset x29, 0x80+ .cfi_rel_offset x30, 0x88+ stp d8, d9, [sp, #0x90]+ .cfi_rel_offset d8, 0x90+ .cfi_rel_offset d9, 0x98+ stp d10, d11, [sp, #0xa0]+ .cfi_rel_offset d10, 0xa0+ .cfi_rel_offset d11, 0xa8+ stp d12, d13, [sp, #0xb0]+ .cfi_rel_offset d12, 0xb0+ .cfi_rel_offset d13, 0xb8+ stp d14, d15, [sp, #0xc0]+ .cfi_rel_offset d14, 0xc0+ .cfi_rel_offset d15, 0xc8+ mov x29, x1+ mov x30, #0x0 // =0+ str x30, [sp, #0x20]+ str x29, [sp, #0x8]+ str x29, [sp, #0x10]+ str x0, [sp]+ add x4, x0, #0xc8+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v0.2d, v25.2d, v27.2d+ trn2 v1.2d, v25.2d, v27.2d+ trn1 v2.2d, v26.2d, v28.2d+ trn2 v3.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v4.2d, v25.2d, v27.2d+ trn2 v5.2d, v25.2d, v27.2d+ trn1 v6.2d, v26.2d, v28.2d+ trn2 v7.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v8.2d, v25.2d, v27.2d+ trn2 v9.2d, v25.2d, v27.2d+ trn1 v10.2d, v26.2d, v28.2d+ trn2 v11.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v12.2d, v25.2d, v27.2d+ trn2 v13.2d, v25.2d, v27.2d+ trn1 v14.2d, v26.2d, v28.2d+ trn2 v15.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v16.2d, v25.2d, v27.2d+ trn2 v17.2d, v25.2d, v27.2d+ trn1 v18.2d, v26.2d, v28.2d+ trn2 v19.2d, v26.2d, v28.2d+ ldp q25, q26, [x0], #0x20+ ld1 { v27.2d, v28.2d }, [x4], #32+ trn1 v20.2d, v25.2d, v27.2d+ trn2 v21.2d, v25.2d, v27.2d+ trn1 v22.2d, v26.2d, v28.2d+ trn2 v23.2d, v26.2d, v28.2d+ ldr d25, [x0]+ ldr d27, [x4]+ trn1 v24.2d, v25.2d, v27.2d+ sub x0, x0, #0xc0+ add x0, x0, #0x190+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ sub x0, x0, #0x190++Lmlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_initial:+ eor x30, x24, x25+ eor x27, x9, x10+ eor3 v30.16b, v0.16b, v5.16b, v10.16b+ eor v30.16b, v30.16b, v15.16b+ eor x0, x30, x21+ eor x26, x27, x6+ eor v30.16b, v30.16b, v20.16b+ eor x27, x26, x7+ eor x29, x0, x22+ eor3 v29.16b, v1.16b, v6.16b, v11.16b+ eor x26, x29, x23+ eor x29, x4, x5+ eor v29.16b, v29.16b, v16.16b+ eor x30, x29, x1+ eor x0, x27, x8+ eor v29.16b, v29.16b, v21.16b+ eor x29, x30, x2+ eor x30, x19, x20+ eor3 v28.16b, v2.16b, v7.16b, v12.16b+ eor x30, x30, x16+ eor x27, x26, x0, ror #63+ eor v28.16b, v28.16b, v17.16b+ eor x4, x4, x27+ eor x30, x30, x17+ eor v28.16b, v28.16b, v22.16b+ eor x30, x30, x28+ eor x29, x29, x3+ eor3 v27.16b, v3.16b, v8.16b, v13.16b+ eor x0, x0, x30, ror #63+ eor x30, x30, x29, ror #63+ eor v27.16b, v27.16b, v18.16b+ eor x22, x22, x30+ eor v27.16b, v27.16b, v23.16b+ eor x23, x23, x30+ str x23, [sp, #0xd0]+ eor3 v26.16b, v4.16b, v9.16b, v14.16b+ eor x23, x14, x15+ eor x14, x14, x0+ eor v26.16b, v26.16b, v19.16b+ eor x23, x23, x11+ eor x15, x15, x0+ eor v26.16b, v26.16b, v24.16b+ eor x1, x1, x27+ eor x23, x23, x12+ rax1 v25.2d, v30.2d, v28.2d+ eor x23, x23, x13+ eor x11, x11, x0+ add v31.2d, v26.2d, v26.2d+ eor x29, x29, x23, ror #63+ eor x23, x23, x26, ror #63+ sri v31.2d, v26.2d, #0x3f+ eor x26, x13, x0+ eor x13, x28, x23+ eor v28.16b, v31.16b, v28.16b+ eor x28, x24, x30+ eor x24, x16, x23+ rax1 v26.2d, v26.2d, v29.2d+ eor x16, x21, x30+ eor x21, x25, x30+ add v31.2d, v27.2d, v27.2d+ eor x30, x19, x23+ sri v31.2d, v27.2d, #0x3f+ eor x19, x20, x23+ eor x20, x17, x23+ eor v29.16b, v31.16b, v29.16b+ eor x17, x12, x0+ eor x0, x2, x27+ rax1 v27.2d, v27.2d, v30.2d+ eor x2, x6, x29+ eor x6, x8, x29+ eor v30.16b, v0.16b, v26.16b+ bic x8, x28, x13, ror #47+ eor x12, x3, x27+ eor v31.16b, v2.16b, v29.16b+ bic x3, x13, x17, ror #19+ eor x5, x5, x27+ shl v0.2d, v31.2d, #0x3e+ ldr x27, [sp, #0xd0]+ bic x25, x17, x2, ror #5+ sri v0.2d, v31.2d, #0x2+ eor x9, x9, x29+ eor x23, x25, x5, ror #52+ xar v2.2d, v12.2d, v29.2d, #0x15+ eor x3, x3, x2, ror #24+ eor x8, x8, x17, ror #2+ eor v31.16b, v13.16b, v28.16b+ eor x17, x10, x29+ bic x25, x12, x22, ror #47+ shl v12.2d, v31.2d, #0x19+ eor x29, x7, x29+ bic x10, x4, x27, ror #2+ sri v12.2d, v31.2d, #0x27+ bic x7, x5, x28, ror #10+ xar v13.2d, v19.2d, v27.2d, #0x38+ eor x10, x10, x20, ror #50+ eor x13, x7, x13, ror #57+ eor v31.16b, v23.16b, v28.16b+ bic x7, x2, x5, ror #47+ eor x2, x25, x24, ror #39+ shl v19.2d, v31.2d, #0x38+ bic x25, x20, x11, ror #57+ bic x5, x17, x4, ror #25+ sri v19.2d, v31.2d, #0x8+ eor x25, x25, x17, ror #53+ bic x17, x11, x17, ror #60+ xar v23.2d, v15.2d, v26.2d, #0x17+ eor x28, x7, x28, ror #57+ bic x7, x9, x12, ror #42+ eor v31.16b, v1.16b, v25.16b+ eor x7, x7, x22, ror #25+ bic x22, x22, x24, ror #56+ shl v15.2d, v31.2d, #0x1+ bic x24, x24, x15, ror #31+ eor x22, x22, x15, ror #23+ sri v15.2d, v31.2d, #0x3f+ bic x20, x27, x20, ror #48+ bic x15, x15, x9, ror #16+ xar v1.2d, v8.2d, v28.2d, #0x9+ eor x12, x15, x12, ror #58+ eor x15, x5, x27, ror #27+ eor v31.16b, v16.16b, v25.16b+ eor x5, x20, x11, ror #41+ shl v8.2d, v31.2d, #0x2d+ ldr x11, [sp, #0x8]+ eor x20, x17, x4, ror #21+ sri v8.2d, v31.2d, #0x13+ eor x17, x24, x9, ror #47+ mov x24, #0x1 // =1+ xar v16.2d, v7.2d, v29.2d, #0x3a+ bic x9, x0, x16, ror #9+ str x24, [sp, #0x18]+ eor v31.16b, v10.16b, v26.16b+ bic x24, x29, x1, ror #44+ bic x27, x1, x21, ror #50+ shl v7.2d, v31.2d, #0x3+ bic x4, x26, x29, ror #63+ eor x1, x1, x4, ror #21+ sri v7.2d, v31.2d, #0x3d+ ldr x11, [x11]+ bic x4, x21, x30, ror #57+ xar v10.2d, v3.2d, v28.2d, #0x24+ eor x21, x24, x21, ror #30+ eor x24, x9, x19, ror #44+ eor v31.16b, v18.16b, v28.16b+ bic x9, x14, x6, ror #5+ eor x9, x9, x0, ror #43+ shl v3.2d, v31.2d, #0x15+ bic x0, x6, x0, ror #38+ eor x1, x1, x11+ sri v3.2d, v31.2d, #0x2b+ eor x11, x4, x26, ror #35+ eor x4, x0, x16, ror #47+ xar v18.2d, v17.2d, v29.2d, #0x31+ bic x0, x16, x19, ror #35+ eor v31.16b, v11.16b, v25.16b+ eor x16, x27, x30, ror #43+ bic x27, x30, x26, ror #42+ shl v17.2d, v31.2d, #0xa+ bic x26, x19, x14, ror #41+ eor x19, x0, x14, ror #12+ sri v17.2d, v31.2d, #0x36+ eor x14, x26, x6, ror #46+ eor x6, x27, x29, ror #41+ xar v11.2d, v9.2d, v27.2d, #0x2c+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ eor v31.16b, v22.16b, v29.16b+ eor x26, x8, x9, ror #57+ eor x27, x0, x14, ror #10+ shl v9.2d, v31.2d, #0x3d+ eor x29, x16, x28, ror #63+ eor x26, x26, x6, ror #51+ sri v9.2d, v31.2d, #0x3+ eor x30, x23, x22, ror #50+ eor x0, x26, x10, ror #31+ xar v22.2d, v14.2d, v27.2d, #0x19+ eor x29, x29, x19, ror #37+ eor x27, x27, x12, ror #5+ eor v31.16b, v20.16b, v26.16b+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ shl v14.2d, v31.2d, #0x12+ eor x26, x30, x21, ror #26+ sri v14.2d, v31.2d, #0x2e+ eor x26, x26, x25, ror #15+ ror x30, x27, #0x3e+ xar v20.2d, v4.2d, v27.2d, #0x25+ eor x30, x30, x26, ror #57+ ror x26, x26, #0x3a+ eor v31.16b, v24.16b, v27.16b+ eor x16, x30, x16+ eor x28, x30, x28, ror #63+ shl v4.2d, v31.2d, #0xe+ str x28, [sp, #0xd0]+ eor x29, x29, x17, ror #36+ sri v4.2d, v31.2d, #0x32+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ xar v24.2d, v21.2d, v25.2d, #0x3e+ eor x29, x29, x20, ror #2+ eor x28, x28, x4, ror #54+ eor v31.16b, v5.16b, v26.16b+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ shl v21.2d, v31.2d, #0x24+ eor x28, x28, x5, ror #25+ ror x0, x0, #0x38+ sri v21.2d, v31.2d, #0x1c+ eor x0, x0, x29, ror #63+ eor x27, x28, x27, ror #61+ xar v27.2d, v6.2d, v25.2d, #0x14+ eor x13, x0, x13, ror #46+ eor x28, x29, x28, ror #63+ bic v31.16b, v7.16b, v11.16b+ eor x29, x30, x20, ror #2+ eor v5.16b, v31.16b, v10.16b+ eor x20, x26, x3, ror #39+ eor x11, x0, x11, ror #50+ bcax v6.16b, v11.16b, v8.16b, v7.16b+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ bic v31.16b, v9.16b, v8.16b+ eor x21, x26, x1+ eor x9, x27, x9, ror #49+ eor v7.16b, v31.16b, v7.16b+ eor x24, x28, x24, ror #28+ eor x1, x30, x17, ror #36+ bcax v8.16b, v8.16b, v10.16b, v9.16b+ eor x14, x0, x14, ror #8+ eor x22, x28, x22, ror #44+ bic v31.16b, v11.16b, v10.16b+ eor x8, x27, x8, ror #56+ eor x17, x27, x7, ror #19+ eor v9.16b, v31.16b, v9.16b+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ bcax v10.16b, v15.16b, v12.16b, v16.16b+ eor x4, x26, x4, ror #54+ eor x0, x0, x12, ror #3+ bic v31.16b, v13.16b, v12.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ eor v11.16b, v31.16b, v16.16b+ eor x26, x26, x5, ror #25+ bcax v12.16b, v12.16b, v14.16b, v13.16b+ eor x2, x7, x16, ror #39+ bic x7, x9, x20, ror #42+ bic v31.16b, v15.16b, v14.16b+ bic x30, x15, x9, ror #16+ eor x7, x7, x22, ror #25+ eor v13.16b, v31.16b, v13.16b+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ bic v31.16b, v16.16b, v15.16b+ eor x30, x27, x6, ror #43+ eor x22, x20, x15, ror #23+ eor v14.16b, v31.16b, v14.16b+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ bcax v15.16b, v20.16b, v17.16b, v21.16b+ bic x5, x13, x17, ror #63+ eor x5, x21, x5, ror #21+ bic v31.16b, v18.16b, v17.16b+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ eor v16.16b, v31.16b, v21.16b+ bic x21, x21, x25, ror #50+ bic x20, x27, x4, ror #25+ bcax v17.16b, v17.16b, v19.16b, v18.16b+ bic x10, x16, x15, ror #31+ eor x16, x21, x19, ror #43+ bic v31.16b, v20.16b, v19.16b+ eor x21, x17, x25, ror #30+ bic x19, x25, x19, ror #57+ eor v18.16b, v31.16b, v18.16b+ ldr x25, [sp, #0x18]+ bcax v19.16b, v19.16b, v21.16b, v20.16b+ eor x17, x10, x9, ror #47+ ldr x9, [sp, #0x8]+ bic v31.16b, v22.16b, v1.16b+ eor x15, x20, x28, ror #27+ bic x20, x4, x28, ror #2+ eor v20.16b, v31.16b, v0.16b+ eor x10, x20, x1, ror #50+ bic x20, x11, x27, ror #60+ bcax v21.16b, v1.16b, v23.16b, v22.16b+ eor x20, x20, x4, ror #21+ bic x4, x28, x1, ror #48+ bic v31.16b, v24.16b, v23.16b+ bic x1, x1, x11, ror #57+ ldr x28, [x9, x25, lsl #3]+ eor v22.16b, v31.16b, v22.16b+ ldr x9, [sp, #0xd0]+ add x25, x25, #0x1+ bcax v23.16b, v23.16b, v0.16b, v24.16b+ str x25, [sp, #0x18]+ cmp x25, #0x17+ bic v31.16b, v1.16b, v0.16b+ eor x25, x1, x27, ror #53+ bic x27, x30, x26, ror #47+ eor v24.16b, v31.16b, v24.16b+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ bcax v0.16b, v30.16b, v2.16b, v27.16b+ eor x11, x19, x13, ror #35+ bic v31.16b, v3.16b, v2.16b+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ eor v1.16b, v31.16b, v27.16b+ bic x27, x24, x9, ror #47+ bic x19, x23, x3, ror #9+ bcax v2.16b, v2.16b, v4.16b, v3.16b+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ bic v31.16b, v30.16b, v4.16b+ bic x29, x3, x29, ror #35+ eor x13, x13, x9, ror #57+ eor v3.16b, v31.16b, v3.16b+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ bcax v4.16b, v4.16b, v27.16b, v30.16b+ bic x14, x14, x8, ror #5+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ ldr x30, [sp, #0x10]+ ld1r { v28.2d }, [x30], #8+ str x30, [sp, #0x10]+ eor v0.16b, v0.16b, v28.16b++Lmlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_loop:+ eor x0, x15, x11, ror #52+ eor x0, x0, x13, ror #48+ eor3 v30.16b, v0.16b, v5.16b, v10.16b+ eor v30.16b, v30.16b, v15.16b+ eor x26, x8, x9, ror #57+ eor x27, x0, x14, ror #10+ eor v30.16b, v30.16b, v20.16b+ eor x29, x16, x28, ror #63+ eor x26, x26, x6, ror #51+ eor3 v29.16b, v1.16b, v6.16b, v11.16b+ eor x30, x23, x22, ror #50+ eor x0, x26, x10, ror #31+ eor v29.16b, v29.16b, v16.16b+ eor x29, x29, x19, ror #37+ eor x27, x27, x12, ror #5+ eor v29.16b, v29.16b, v21.16b+ eor x30, x30, x24, ror #34+ eor x0, x0, x7, ror #27+ eor3 v28.16b, v2.16b, v7.16b, v12.16b+ eor x26, x30, x21, ror #26+ eor x26, x26, x25, ror #15+ eor v28.16b, v28.16b, v17.16b+ ror x30, x27, #0x3e+ eor x30, x30, x26, ror #57+ eor v28.16b, v28.16b, v22.16b+ ror x26, x26, #0x3a+ eor x16, x30, x16+ eor3 v27.16b, v3.16b, v8.16b, v13.16b+ eor x28, x30, x28, ror #63+ str x28, [sp, #0xd0]+ eor v27.16b, v27.16b, v18.16b+ eor x29, x29, x17, ror #36+ eor x28, x1, x2, ror #61+ eor v27.16b, v27.16b, v23.16b+ eor x19, x30, x19, ror #37+ eor x29, x29, x20, ror #2+ eor3 v26.16b, v4.16b, v9.16b, v14.16b+ eor x28, x28, x4, ror #54+ eor x26, x26, x0, ror #55+ eor v26.16b, v26.16b, v19.16b+ eor x28, x28, x3, ror #39+ eor x28, x28, x5, ror #25+ eor v26.16b, v26.16b, v24.16b+ ror x0, x0, #0x38+ eor x0, x0, x29, ror #63+ rax1 v25.2d, v30.2d, v28.2d+ eor x27, x28, x27, ror #61+ eor x13, x0, x13, ror #46+ add v31.2d, v26.2d, v26.2d+ eor x28, x29, x28, ror #63+ eor x29, x30, x20, ror #2+ sri v31.2d, v26.2d, #0x3f+ eor x20, x26, x3, ror #39+ eor x11, x0, x11, ror #50+ eor v28.16b, v31.16b, v28.16b+ eor x25, x28, x25, ror #9+ eor x3, x28, x21, ror #20+ rax1 v26.2d, v26.2d, v29.2d+ eor x21, x26, x1+ add v31.2d, v27.2d, v27.2d+ eor x9, x27, x9, ror #49+ eor x24, x28, x24, ror #28+ sri v31.2d, v27.2d, #0x3f+ eor x1, x30, x17, ror #36+ eor x14, x0, x14, ror #8+ eor v29.16b, v31.16b, v29.16b+ eor x22, x28, x22, ror #44+ eor x8, x27, x8, ror #56+ rax1 v27.2d, v27.2d, v30.2d+ eor x17, x27, x7, ror #19+ eor x15, x0, x15, ror #62+ eor v30.16b, v0.16b, v26.16b+ bic x7, x20, x22, ror #47+ eor x4, x26, x4, ror #54+ eor v31.16b, v2.16b, v29.16b+ eor x0, x0, x12, ror #3+ eor x28, x28, x23, ror #58+ shl v0.2d, v31.2d, #0x3e+ eor x23, x26, x2, ror #61+ eor x26, x26, x5, ror #25+ sri v0.2d, v31.2d, #0x2+ eor x2, x7, x16, ror #39+ bic x7, x9, x20, ror #42+ xar v2.2d, v12.2d, v29.2d, #0x15+ bic x30, x15, x9, ror #16+ eor x7, x7, x22, ror #25+ eor v31.16b, v13.16b, v28.16b+ eor x12, x30, x20, ror #58+ bic x20, x22, x16, ror #56+ shl v12.2d, v31.2d, #0x19+ eor x30, x27, x6, ror #43+ eor x22, x20, x15, ror #23+ sri v12.2d, v31.2d, #0x27+ bic x6, x19, x13, ror #42+ eor x6, x6, x17, ror #41+ xar v13.2d, v19.2d, v27.2d, #0x38+ bic x5, x13, x17, ror #63+ eor x5, x21, x5, ror #21+ eor v31.16b, v23.16b, v28.16b+ bic x17, x17, x21, ror #44+ eor x27, x27, x10, ror #23+ shl v19.2d, v31.2d, #0x38+ bic x21, x21, x25, ror #50+ bic x20, x27, x4, ror #25+ sri v19.2d, v31.2d, #0x8+ bic x10, x16, x15, ror #31+ eor x16, x21, x19, ror #43+ xar v23.2d, v15.2d, v26.2d, #0x17+ eor x21, x17, x25, ror #30+ bic x19, x25, x19, ror #57+ eor v31.16b, v1.16b, v25.16b+ ldr x25, [sp, #0x18]+ eor x17, x10, x9, ror #47+ shl v15.2d, v31.2d, #0x1+ ldr x9, [sp, #0x8]+ sri v15.2d, v31.2d, #0x3f+ eor x15, x20, x28, ror #27+ bic x20, x4, x28, ror #2+ xar v1.2d, v8.2d, v28.2d, #0x9+ eor x10, x20, x1, ror #50+ bic x20, x11, x27, ror #60+ eor v31.16b, v16.16b, v25.16b+ eor x20, x20, x4, ror #21+ bic x4, x28, x1, ror #48+ shl v8.2d, v31.2d, #0x2d+ bic x1, x1, x11, ror #57+ ldr x28, [x9, x25, lsl #3]+ sri v8.2d, v31.2d, #0x13+ ldr x9, [sp, #0xd0]+ add x25, x25, #0x1+ xar v16.2d, v7.2d, v29.2d, #0x3a+ str x25, [sp, #0x18]+ cmp x25, #0x17+ eor v31.16b, v10.16b, v26.16b+ eor x25, x1, x27, ror #53+ bic x27, x30, x26, ror #47+ shl v7.2d, v31.2d, #0x3+ eor x1, x5, x28+ eor x5, x4, x11, ror #41+ sri v7.2d, v31.2d, #0x3d+ eor x11, x19, x13, ror #35+ bic x13, x26, x24, ror #10+ xar v10.2d, v3.2d, v28.2d, #0x24+ eor x28, x27, x24, ror #57+ bic x27, x24, x9, ror #47+ eor v31.16b, v18.16b, v28.16b+ bic x19, x23, x3, ror #9+ bic x4, x29, x14, ror #41+ shl v3.2d, v31.2d, #0x15+ eor x24, x19, x29, ror #44+ bic x29, x3, x29, ror #35+ sri v3.2d, v31.2d, #0x2b+ eor x13, x13, x9, ror #57+ eor x19, x29, x14, ror #12+ xar v18.2d, v17.2d, v29.2d, #0x31+ bic x29, x9, x0, ror #19+ bic x14, x14, x8, ror #5+ eor v31.16b, v11.16b, v25.16b+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ shl v17.2d, v31.2d, #0xa+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ sri v17.2d, v31.2d, #0x36+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ xar v11.2d, v9.2d, v27.2d, #0x2c+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ eor v31.16b, v22.16b, v29.16b+ eor x0, x15, x11, ror #52+ shl v9.2d, v31.2d, #0x3d+ eor x0, x0, x13, ror #48+ eor x26, x8, x9, ror #57+ sri v9.2d, v31.2d, #0x3+ eor x27, x0, x14, ror #10+ eor x29, x16, x28, ror #63+ xar v22.2d, v14.2d, v27.2d, #0x19+ eor x26, x26, x6, ror #51+ eor x30, x23, x22, ror #50+ eor v31.16b, v20.16b, v26.16b+ eor x0, x26, x10, ror #31+ eor x29, x29, x19, ror #37+ shl v14.2d, v31.2d, #0x12+ eor x27, x27, x12, ror #5+ eor x30, x30, x24, ror #34+ sri v14.2d, v31.2d, #0x2e+ eor x0, x0, x7, ror #27+ eor x26, x30, x21, ror #26+ xar v20.2d, v4.2d, v27.2d, #0x25+ eor x26, x26, x25, ror #15+ ror x30, x27, #0x3e+ eor v31.16b, v24.16b, v27.16b+ eor x30, x30, x26, ror #57+ ror x26, x26, #0x3a+ shl v4.2d, v31.2d, #0xe+ eor x16, x30, x16+ eor x28, x30, x28, ror #63+ sri v4.2d, v31.2d, #0x32+ str x28, [sp, #0xd0]+ eor x29, x29, x17, ror #36+ xar v24.2d, v21.2d, v25.2d, #0x3e+ eor x28, x1, x2, ror #61+ eor x19, x30, x19, ror #37+ eor v31.16b, v5.16b, v26.16b+ eor x29, x29, x20, ror #2+ eor x28, x28, x4, ror #54+ shl v21.2d, v31.2d, #0x24+ eor x26, x26, x0, ror #55+ eor x28, x28, x3, ror #39+ sri v21.2d, v31.2d, #0x1c+ eor x28, x28, x5, ror #25+ ror x0, x0, #0x38+ xar v27.2d, v6.2d, v25.2d, #0x14+ eor x0, x0, x29, ror #63+ eor x27, x28, x27, ror #61+ bic v31.16b, v7.16b, v11.16b+ eor x13, x0, x13, ror #46+ eor x28, x29, x28, ror #63+ eor v5.16b, v31.16b, v10.16b+ eor x29, x30, x20, ror #2+ eor x20, x26, x3, ror #39+ bcax v6.16b, v11.16b, v8.16b, v7.16b+ eor x11, x0, x11, ror #50+ eor x25, x28, x25, ror #9+ bic v31.16b, v9.16b, v8.16b+ eor x3, x28, x21, ror #20+ eor v7.16b, v31.16b, v7.16b+ eor x21, x26, x1+ eor x9, x27, x9, ror #49+ bcax v8.16b, v8.16b, v10.16b, v9.16b+ eor x24, x28, x24, ror #28+ eor x1, x30, x17, ror #36+ bic v31.16b, v11.16b, v10.16b+ eor x14, x0, x14, ror #8+ eor x22, x28, x22, ror #44+ eor v9.16b, v31.16b, v9.16b+ eor x8, x27, x8, ror #56+ eor x17, x27, x7, ror #19+ bcax v10.16b, v15.16b, v12.16b, v16.16b+ eor x15, x0, x15, ror #62+ bic x7, x20, x22, ror #47+ bic v31.16b, v13.16b, v12.16b+ eor x4, x26, x4, ror #54+ eor x0, x0, x12, ror #3+ eor v11.16b, v31.16b, v16.16b+ eor x28, x28, x23, ror #58+ eor x23, x26, x2, ror #61+ bcax v12.16b, v12.16b, v14.16b, v13.16b+ eor x26, x26, x5, ror #25+ eor x2, x7, x16, ror #39+ bic v31.16b, v15.16b, v14.16b+ bic x7, x9, x20, ror #42+ bic x30, x15, x9, ror #16+ eor v13.16b, v31.16b, v13.16b+ eor x7, x7, x22, ror #25+ eor x12, x30, x20, ror #58+ bic v31.16b, v16.16b, v15.16b+ bic x20, x22, x16, ror #56+ eor x30, x27, x6, ror #43+ eor v14.16b, v31.16b, v14.16b+ eor x22, x20, x15, ror #23+ bic x6, x19, x13, ror #42+ bcax v15.16b, v20.16b, v17.16b, v21.16b+ eor x6, x6, x17, ror #41+ bic x5, x13, x17, ror #63+ bic v31.16b, v18.16b, v17.16b+ eor x5, x21, x5, ror #21+ bic x17, x17, x21, ror #44+ eor v16.16b, v31.16b, v21.16b+ eor x27, x27, x10, ror #23+ bic x21, x21, x25, ror #50+ bcax v17.16b, v17.16b, v19.16b, v18.16b+ bic x20, x27, x4, ror #25+ bic x10, x16, x15, ror #31+ bic v31.16b, v20.16b, v19.16b+ eor x16, x21, x19, ror #43+ eor x21, x17, x25, ror #30+ eor v18.16b, v31.16b, v18.16b+ bic x19, x25, x19, ror #57+ ldr x25, [sp, #0x18]+ bcax v19.16b, v19.16b, v21.16b, v20.16b+ eor x17, x10, x9, ror #47+ bic v31.16b, v22.16b, v1.16b+ ldr x9, [sp, #0x8]+ eor x15, x20, x28, ror #27+ eor v20.16b, v31.16b, v0.16b+ bic x20, x4, x28, ror #2+ eor x10, x20, x1, ror #50+ bcax v21.16b, v1.16b, v23.16b, v22.16b+ bic x20, x11, x27, ror #60+ eor x20, x20, x4, ror #21+ bic v31.16b, v24.16b, v23.16b+ bic x4, x28, x1, ror #48+ bic x1, x1, x11, ror #57+ eor v22.16b, v31.16b, v22.16b+ ldr x28, [x9, x25, lsl #3]+ ldr x9, [sp, #0xd0]+ bcax v23.16b, v23.16b, v0.16b, v24.16b+ add x25, x25, #0x1+ str x25, [sp, #0x18]+ bic v31.16b, v1.16b, v0.16b+ cmp x25, #0x17+ eor x25, x1, x27, ror #53+ eor v24.16b, v31.16b, v24.16b+ bic x27, x30, x26, ror #47+ eor x1, x5, x28+ bcax v0.16b, v30.16b, v2.16b, v27.16b+ eor x5, x4, x11, ror #41+ eor x11, x19, x13, ror #35+ bic v31.16b, v3.16b, v2.16b+ bic x13, x26, x24, ror #10+ eor x28, x27, x24, ror #57+ eor v1.16b, v31.16b, v27.16b+ bic x27, x24, x9, ror #47+ bic x19, x23, x3, ror #9+ bcax v2.16b, v2.16b, v4.16b, v3.16b+ bic x4, x29, x14, ror #41+ eor x24, x19, x29, ror #44+ bic v31.16b, v30.16b, v4.16b+ bic x29, x3, x29, ror #35+ eor x13, x13, x9, ror #57+ eor v3.16b, v31.16b, v3.16b+ eor x19, x29, x14, ror #12+ bic x29, x9, x0, ror #19+ bcax v4.16b, v4.16b, v27.16b, v30.16b+ bic x14, x14, x8, ror #5+ eor x9, x14, x23, ror #43+ eor x14, x4, x8, ror #46+ bic x23, x8, x23, ror #38+ eor x8, x27, x0, ror #2+ eor x4, x23, x3, ror #47+ bic x3, x0, x30, ror #5+ eor x23, x3, x26, ror #52+ eor x3, x29, x30, ror #24+ ldr x30, [sp, #0x10]+ ld1r { v28.2d }, [x30], #8+ str x30, [sp, #0x10]+ eor v0.16b, v0.16b, v28.16b++Lmlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_loop_end:+ b.le Lmlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_loop+ ror x2, x2, #0x3d+ ror x3, x3, #0x27+ ror x4, x4, #0x36+ ror x5, x5, #0x19+ ror x6, x6, #0x2b+ ror x7, x7, #0x13+ ror x8, x8, #0x38+ ror x9, x9, #0x31+ ror x10, x10, #0x17+ ror x11, x11, #0x32+ ror x12, x12, #0x3+ ror x13, x13, #0x2e+ ror x14, x14, #0x8+ ror x15, x15, #0x3e+ ror x17, x17, #0x24+ ror x28, x28, #0x3f+ ror x19, x19, #0x25+ ror x20, x20, #0x2+ ror x21, x21, #0x14+ ror x22, x22, #0x2c+ ror x23, x23, #0x3a+ ror x24, x24, #0x1c+ ror x25, x25, #0x9+ ldr x30, [sp, #0x20]+ cmp x30, #0x1+ b.eq Lmlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_done+ mov x30, #0x1 // =1+ str x30, [sp, #0x20]+ ldr x0, [sp]+ add x0, x0, #0x190+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ sub x0, x0, #0x190+ add x0, x0, #0x258+ ldp x1, x6, [x0]+ ldp x11, x16, [x0, #0x10]+ ldp x21, x2, [x0, #0x20]+ ldp x7, x12, [x0, #0x30]+ ldp x17, x22, [x0, #0x40]+ ldp x3, x8, [x0, #0x50]+ ldp x13, x28, [x0, #0x60]+ ldp x23, x4, [x0, #0x70]+ ldp x9, x14, [x0, #0x80]+ ldp x19, x24, [x0, #0x90]+ ldp x5, x10, [x0, #0xa0]+ ldp x15, x20, [x0, #0xb0]+ ldr x25, [x0, #0xc0]+ sub x0, x0, #0x258+ b Lmlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_initial++Lmlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_done:+ ldr x0, [sp]+ add x0, x0, #0x258+ stp x1, x6, [x0]+ stp x11, x16, [x0, #0x10]+ stp x21, x2, [x0, #0x20]+ stp x7, x12, [x0, #0x30]+ stp x17, x22, [x0, #0x40]+ stp x3, x8, [x0, #0x50]+ stp x13, x28, [x0, #0x60]+ stp x23, x4, [x0, #0x70]+ stp x9, x14, [x0, #0x80]+ stp x19, x24, [x0, #0x90]+ stp x5, x10, [x0, #0xa0]+ stp x15, x20, [x0, #0xb0]+ str x25, [x0, #0xc0]+ sub x0, x0, #0x258+ add x4, x0, #0xc8+ trn1 v25.2d, v0.2d, v1.2d+ trn1 v26.2d, v2.2d, v3.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v0.2d, v1.2d+ trn2 v28.2d, v2.2d, v3.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v4.2d, v5.2d+ trn1 v26.2d, v6.2d, v7.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v4.2d, v5.2d+ trn2 v28.2d, v6.2d, v7.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v8.2d, v9.2d+ trn1 v26.2d, v10.2d, v11.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v8.2d, v9.2d+ trn2 v28.2d, v10.2d, v11.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v12.2d, v13.2d+ trn1 v26.2d, v14.2d, v15.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v12.2d, v13.2d+ trn2 v28.2d, v14.2d, v15.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v16.2d, v17.2d+ trn1 v26.2d, v18.2d, v19.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v16.2d, v17.2d+ trn2 v28.2d, v18.2d, v19.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ trn1 v25.2d, v20.2d, v21.2d+ trn1 v26.2d, v22.2d, v23.2d+ stp q25, q26, [x0], #0x20+ trn2 v27.2d, v20.2d, v21.2d+ trn2 v28.2d, v22.2d, v23.2d+ st1 { v27.2d, v28.2d }, [x4], #32+ str d24, [x0]+ trn2 v25.2d, v24.2d, v24.2d+ str d25, [x4]+ ldp d8, d9, [sp, #0x90]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0xa0]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0xb0]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0xc0]+ .cfi_restore d14+ .cfi_restore d15+ ldp x19, x20, [sp, #0x30]+ .cfi_restore x19+ .cfi_restore x20+ ldp x21, x22, [sp, #0x40]+ .cfi_restore x21+ .cfi_restore x22+ ldp x23, x24, [sp, #0x50]+ .cfi_restore x23+ .cfi_restore x24+ ldp x25, x26, [sp, #0x60]+ .cfi_restore x25+ .cfi_restore x26+ ldp x27, x28, [sp, #0x70]+ .cfi_restore x27+ .cfi_restore x28+ ldp x29, x30, [sp, #0x80]+ .cfi_restore x29+ .cfi_restore x30+ add sp, sp, #0xe0+ .cfi_adjust_cfa_offset -0xe0+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm)++#endif /* __ARM_FEATURE_SHA3 */++#endif /* MLK_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID && \+ !MLK_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,47 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++#include "../../../../common.h"++#if (defined(MLK_FIPS202_AARCH64_NEED_X1_SCALAR) || \+ defined(MLK_FIPS202_AARCH64_NEED_X1_V84A) || \+ defined(MLK_FIPS202_AARCH64_NEED_X2_V84A) || \+ defined(MLK_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \+ defined(MLK_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#include "fips202_native_aarch64.h"++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint64_t+ mlk_keccakf1600_round_constants[24] = {+ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a,+ 0x8000000080008000, 0x000000000000808b, 0x0000000080000001,+ 0x8000000080008081, 0x8000000000008009, 0x000000000000008a,+ 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,+ 0x000000008000808b, 0x800000000000008b, 0x8000000000008089,+ 0x8000000000008003, 0x8000000000008002, 0x8000000000000080,+ 0x000000000000800a, 0x800000008000000a, 0x8000000080008081,+ 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,+};++#else /* (MLK_FIPS202_AARCH64_NEED_X1_SCALAR || \+ MLK_FIPS202_AARCH64_NEED_X1_V84A || MLK_FIPS202_AARCH64_NEED_X2_V84A \+ || MLK_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \+ MLK_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \+ !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(fips202_aarch64_round_constants)++#endif /* !((MLK_FIPS202_AARCH64_NEED_X1_SCALAR || \+ MLK_FIPS202_AARCH64_NEED_X1_V84A || MLK_FIPS202_AARCH64_NEED_X2_V84A \+ || MLK_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \+ MLK_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \+ !MLK_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,26 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_FIPS202_NATIVE_AARCH64_X1_SCALAR_H+#define MLK_FIPS202_NATIVE_AARCH64_X1_SCALAR_H++/* Part of backend API */+#define MLK_USE_NATIVE_FIPS202_X1+/* Guard for assembly file */+#define MLK_FIPS202_AARCH64_NEED_X1_SCALAR++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccak_f1600_x1_native(uint64_t *state)+{+ mlk_keccak_f1600_x1_scalar_aarch64_asm(state,+ mlk_keccakf1600_round_constants);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLK_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */
@@ -0,0 +1,35 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_FIPS202_NATIVE_AARCH64_X1_V84A_H+#define MLK_FIPS202_NATIVE_AARCH64_X1_V84A_H++#if !defined(__ARM_FEATURE_SHA3)+#error This backend can only be used if SHA3 extensions are available.+#endif++/* Part of backend API */+#define MLK_USE_NATIVE_FIPS202_X1+/* Guard for assembly file */+#define MLK_FIPS202_AARCH64_NEED_X1_V84A++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccak_f1600_x1_native(uint64_t *state)+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON) ||+ !mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_SHA3))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_keccak_f1600_x1_v84a_aarch64_asm(state, mlk_keccakf1600_round_constants);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLK_FIPS202_NATIVE_AARCH64_X1_V84A_H */
@@ -0,0 +1,38 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_FIPS202_NATIVE_AARCH64_X2_V84A_H+#define MLK_FIPS202_NATIVE_AARCH64_X2_V84A_H++#if !defined(__ARM_FEATURE_SHA3)+#error This backend can only be used if SHA3 extensions are available.+#endif++/* Part of backend API */+#define MLK_USE_NATIVE_FIPS202_X4+/* Guard for assembly file */+#define MLK_FIPS202_AARCH64_NEED_X2_V84A++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccak_f1600_x4_native(uint64_t *state)+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON) ||+ !mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_SHA3))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_keccak_f1600_x2_v84a_aarch64_asm(state + 0 * 25,+ mlk_keccakf1600_round_constants);+ mlk_keccak_f1600_x2_v84a_aarch64_asm(state + 2 * 25,+ mlk_keccakf1600_round_constants);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLK_FIPS202_NATIVE_AARCH64_X2_V84A_H */
@@ -0,0 +1,31 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H+#define MLK_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H++/* Part of backend API */+#define MLK_USE_NATIVE_FIPS202_X4+/* Guard for assembly file */+#define MLK_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccak_f1600_x4_native(uint64_t *state)+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm(+ state, mlk_keccakf1600_round_constants);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLK_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */
@@ -0,0 +1,36 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H+#define MLK_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H++#if !defined(__ARM_FEATURE_SHA3)+#error This backend can only be used if SHA3 extensions are available.+#endif++/* Part of backend API */+#define MLK_USE_NATIVE_FIPS202_X4+/* Guard for assembly file */+#define MLK_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_aarch64.h"+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccak_f1600_x4_native(uint64_t *state)+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON) ||+ !mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_SHA3))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm(+ state, mlk_keccakf1600_round_constants);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLK_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */
@@ -0,0 +1,117 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_FIPS202_NATIVE_API_H+#define MLK_FIPS202_NATIVE_API_H+/*+ * FIPS-202 native interface+ *+ * This header is primarily for documentation purposes.+ * It should not be included by backend implementations.+ */++#include "../../cbmc.h"++/* Backends must return MLK_NATIVE_FUNC_SUCCESS upon success. */+#define MLK_NATIVE_FUNC_SUCCESS (0)+/* Backends may return MLK_NATIVE_FUNC_FALLBACK to signal to the frontend that+ * the target/parameters are unsupported; typically, this would be because of+ * dependencies on CPU features not detected on the host CPU. In this case,+ * the frontend falls back to the default C implementation. */+#define MLK_NATIVE_FUNC_FALLBACK (-1)++/*+ * This is the C<->native interface allowing for the drop-in+ * of custom Keccak-F1600 implementations.+ *+ * A _backend_ is a specific implementation of parts of this interface.+ *+ * You can replace 1-fold or 4-fold batched Keccak-F1600.+ * To enable, set MLK_USE_NATIVE_FIPS202_X1 or MLK_USE_NATIVE_FIPS202_X4+ * in your backend, and define the inline wrappers mlk_keccak_f1600_x1_native()+ * and/or mlk_keccak_f1600_x4_native(), respectively, to forward to your+ * implementation.+ */++#if defined(MLK_USE_NATIVE_FIPS202_X1)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccak_f1600_x1_native(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1))+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLK_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)));+#endif /* MLK_USE_NATIVE_FIPS202_X1 */+#if defined(MLK_USE_NATIVE_FIPS202_X4)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccak_f1600_x4_native(uint64_t *state)+__contract__(+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLK_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)));+#endif /* MLK_USE_NATIVE_FIPS202_X4 */++/*+ * Native x4 XOR bytes and extract bytes interface.+ *+ * These functions allow backends to provide optimized implementations for+ * XORing input data into the state and extracting output data from the state.+ * This is particularly useful for backends that use a different internal state+ * representation (e.g., bit-interleaved), as conversion can happen during+ * XOR/extract rather than before/after each permutation.+ *+ * NOTE: We assume that the custom representation of the zero state is the+ * all-zero state.+ *+ * MLK_USE_NATIVE_FIPS202_X4_XOR_BYTES: Backend provides native XOR bytes+ * MLK_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES: Backend provides native extract+ * bytes+ */++#if defined(MLK_USE_NATIVE_FIPS202_X4_XOR_BYTES)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccakf1600_xor_bytes_x4_native(+ uint64_t *state, const unsigned char *data0, const unsigned char *data1,+ const unsigned char *data2, const unsigned char *data3, unsigned offset,+ unsigned length)+__contract__(+ requires(0 <= offset && offset <= 25 * sizeof(uint64_t) &&+ 0 <= length && length <= 25 * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ requires(memory_no_alias(data0, length))+ requires((data0 == data1 &&+ data0 == data2 &&+ data0 == data3) ||+ (memory_no_alias(data1, length) &&+ memory_no_alias(data2, length) &&+ memory_no_alias(data3, length)))+ assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLK_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)));+#endif /* MLK_USE_NATIVE_FIPS202_X4_XOR_BYTES */++#if defined(MLK_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccakf1600_extract_bytes_x4_native(+ uint64_t *state, unsigned char *data0, unsigned char *data1,+ unsigned char *data2, unsigned char *data3, unsigned offset,+ unsigned length)+__contract__(+ requires(0 <= offset && offset <= 25 * sizeof(uint64_t) &&+ 0 <= length && length <= 25 * sizeof(uint64_t) - offset)+ requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4))+ requires(memory_no_alias(data0, length))+ requires(memory_no_alias(data1, length))+ requires(memory_no_alias(data2, length))+ requires(memory_no_alias(data3, length))+ assigns(memory_slice(data0, length))+ assigns(memory_slice(data1, length))+ assigns(memory_slice(data2, length))+ assigns(memory_slice(data3, length))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS));+#endif /* MLK_USE_NATIVE_FIPS202_X4_EXTRACT_BYTES */++#endif /* !MLK_FIPS202_NATIVE_API_H */
@@ -0,0 +1,29 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_FIPS202_NATIVE_AUTO_H+#define MLK_FIPS202_NATIVE_AUTO_H++/*+ * Default FIPS202 backend+ */+#include "../../sys.h"++#if defined(MLK_SYS_AARCH64)+#include "aarch64/auto.h"+#endif++/* The x86_64 backend requires toolchain support for the SysV ABI */+#if defined(MLK_SYS_X86_64_AVX2) && defined(MLK_SYSV_ABI_SUPPORTED)+#include "x86_64/keccak_f1600_x4_avx2.h"+#endif++/* We do not yet include the FIPS202 backend for Armv8.1-M+MVE by default+ * as it is still experimental and undergoing review. */+/* #if defined(MLK_SYS_ARMV81M_MVE) */+/* #include "armv81m/mve.h" */+/* #endif */++#endif /* !MLK_FIPS202_NATIVE_AUTO_H */
@@ -0,0 +1,33 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H+#define MLK_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H++#include "../../../common.h"++#define MLK_FIPS202_X86_64_NEED_X4_AVX2++/* Part of backend API */+#define MLK_USE_NATIVE_FIPS202_X4++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/fips202_native_x86_64.h"+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_keccak_f1600_x4_native(uint64_t *state)+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_keccak_f1600_x4_avx2_asm(state, mlk_keccakf1600_round_constants,+ mlk_keccak_rho8, mlk_keccak_rho56);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLK_FIPS202_NATIVE_X86_64_KECCAK_F1600_X4_AVX2_H */
@@ -0,0 +1,44 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H+#define MLK_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H++#include "../../../../cbmc.h"+#include "../../../../common.h"++/* TODO: Reconsider whether this check is needed -- x86_64 is always+ * little-endian, so the backend selection already implies this. */+#ifndef MLK_SYS_LITTLE_ENDIAN+#error Expecting a little-endian platform+#endif++#define mlk_keccakf1600_round_constants \+ MLK_NAMESPACE(keccakf1600_round_constants)+MLK_INTERNAL_DATA_DECLARATION const uint64_t+ mlk_keccakf1600_round_constants[24];++#define mlk_keccak_rho8 MLK_NAMESPACE(keccak_rho8)+MLK_INTERNAL_DATA_DECLARATION const uint64_t mlk_keccak_rho8[4];++#define mlk_keccak_rho56 MLK_NAMESPACE(keccak_rho56)+MLK_INTERNAL_DATA_DECLARATION const uint64_t mlk_keccak_rho56[4];++#define mlk_keccak_f1600_x4_avx2_asm MLK_NAMESPACE(keccak_f1600_x4_avx2_asm)+MLK_SYSV_ABI+void mlk_keccak_f1600_x4_avx2_asm(uint64_t states[100], const uint64_t rc[24],+ const uint64_t rho8[4],+ const uint64_t rho56[4])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/keccak_f1600_x4_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(states, sizeof(uint64_t) * 25 * 4))+ requires(rc == mlk_keccakf1600_round_constants)+ requires(rho8 == mlk_keccak_rho8)+ requires(rho56 == mlk_keccak_rho56)+ assigns(memory_slice(states, sizeof(uint64_t) * 25 * 4))+);++#endif /* !MLK_FIPS202_NATIVE_X86_64_SRC_FIPS202_NATIVE_X86_64_H */
@@ -0,0 +1,487 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#include "../../../../common.h"++#if defined(MLK_FIPS202_X86_64_NEED_X4_AVX2) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+/*yaml+ Name: keccak_f1600_x4_avx2_asm+ Description: x86_64 AVX2 Keccak-f[1600] permutation for four sequential states+ Signature: void mlk_keccak_f1600_x4_avx2_asm(uint64_t states[100], const uint64_t rc[24], const uint64_t rho8[4], const uint64_t rho56[4])+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 800+ permissions: read/write+ c_parameter: uint64_t states[100]+ description: Four sequential Keccak states (4 x 25 x uint64_t)+ rsi:+ type: buffer+ size_bytes: 192+ permissions: read-only+ c_parameter: const uint64_t rc[24]+ description: Round constants (24 x uint64_t)+ rdx:+ type: buffer+ size_bytes: 32+ permissions: read-only+ c_parameter: const uint64_t rho8[4]+ description: Rotation constant rho8 (4 x uint64_t)+ rcx:+ type: buffer+ size_bytes: 32+ permissions: read-only+ c_parameter: const uint64_t rho56[4]+ description: Rotation constant rho56 (4 x uint64_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/fips202/x86_64/src/keccak_f1600_x4_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(keccak_f1600_x4_avx2_asm)+MLK_ASM_FN_SYMBOL(keccak_f1600_x4_avx2_asm)++ .cfi_startproc+ movq %rsp, %r11+ .cfi_def_cfa_register %r11+ andq $-0x20, %rsp+ subq $0x300, %rsp # imm = 0x300+ vmovdqu (%rdi), %ymm0+ vmovdqu 0xc8(%rdi), %ymm3+ vmovdqu 0x190(%rdi), %ymm1+ vmovdqu 0x258(%rdi), %ymm4+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm7 # ymm7 = ymm2[0,1],ymm3[0,1]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm3 # ymm3 = ymm2[2,3],ymm3[2,3]+ vmovdqu 0x278(%rdi), %ymm4+ vmovdqu %ymm3, 0x40(%rsp)+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm3 # ymm3 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm7, (%rsp)+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vmovdqu 0x20(%rdi), %ymm0+ vmovdqu 0x1b0(%rdi), %ymm1+ vmovdqu %ymm3, 0x60(%rsp)+ vmovdqu 0xe8(%rdi), %ymm3+ vmovdqu %ymm7, 0x20(%rsp)+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm7 # ymm7 = ymm2[0,1],ymm3[0,1]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm3 # ymm3 = ymm2[2,3],ymm3[2,3]+ vmovdqu 0x298(%rdi), %ymm4+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm14 # ymm14 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm7, 0x80(%rsp)+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vmovdqu 0x40(%rdi), %ymm0+ vmovdqu 0x1d0(%rdi), %ymm1+ vmovdqu %ymm3, 0xc0(%rsp)+ vmovdqu 0x108(%rdi), %ymm3+ vmovdqu %ymm14, %ymm10+ vmovdqu %ymm7, 0xa0(%rsp)+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm11 # ymm11 = ymm2[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm3 # ymm3 = ymm2[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vmovdqu %ymm3, 0x100(%rsp)+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm8 # ymm8 = ymm0[2,3],ymm1[2,3]+ vmovdqu 0x128(%rdi), %ymm3+ vmovdqu 0x60(%rdi), %ymm0+ vmovdqu 0x1f0(%rdi), %ymm1+ vmovdqu %ymm7, 0xe0(%rsp)+ vmovdqu %ymm11, %ymm14+ vmovdqu 0x2b8(%rdi), %ymm4+ vmovdqu 0x2f8(%rdi), %ymm5+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vmovdqu 0x2d8(%rdi), %ymm4+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm15 # ymm15 = ymm2[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm3 # ymm3 = ymm2[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm9 # ymm9 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm3, 0x140(%rsp)+ vmovdqu 0x80(%rdi), %ymm0+ vmovdqu 0x148(%rdi), %ymm3+ vmovdqu 0x210(%rdi), %ymm1+ vmovdqu %ymm7, 0x120(%rsp)+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm1, %ymm3 # ymm3 = ymm1[0],ymm4[0],ymm1[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm4[1],ymm1[3],ymm4[3]+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm7 # ymm7 = ymm2[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm13 # ymm13 = ymm2[2,3],ymm3[2,3]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm3 # ymm3 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm7, 0x160(%rsp)+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm7 # ymm7 = ymm0[0,1],ymm1[0,1]+ vmovdqu 0xa0(%rdi), %ymm0+ vmovdqu 0x230(%rdi), %ymm1+ vmovdqu %ymm3, 0x1a0(%rsp)+ vmovdqu 0x168(%rdi), %ymm3+ vpunpcklqdq %ymm5, %ymm1, %ymm4 # ymm4 = ymm1[0],ymm5[0],ymm1[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm1, %ymm1 # ymm1 = ymm1[1],ymm5[1],ymm1[3],ymm5[3]+ vmovdqu %ymm7, 0x180(%rsp)+ vpunpcklqdq %ymm3, %ymm0, %ymm2 # ymm2 = ymm0[0],ymm3[0],ymm0[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm3[1],ymm0[3],ymm3[3]+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm12 # ymm12 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm3 # ymm3 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm7 # ymm7 = ymm2[2,3],ymm4[2,3]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm4 # ymm4 = ymm0[2,3],ymm1[2,3]+ vmovq 0x250(%rdi), %xmm0+ vmovq 0xc0(%rdi), %xmm1+ vmovdqu %ymm12, 0x1c0(%rsp)+ vmovdqu %ymm4, 0x1e0(%rsp)+ vpinsrq $0x1, 0x318(%rdi), %xmm0, %xmm0+ vpinsrq $0x1, 0x188(%rdi), %xmm1, %xmm1+ vinserti128 $0x1, %xmm0, %ymm1, %ymm2+ movq $0x0, %r10++LLmlk_keccak_f1600_x4_avx2:+ vmovdqu 0xa0(%rsp), %ymm4+ vpxor 0x1c0(%rsp), %ymm9, %ymm0+ vmovdqu %ymm9, 0x200(%rsp)+ vmovdqu %ymm10, %ymm9+ vmovdqu 0xc0(%rsp), %ymm11+ vmovdqu 0x160(%rsp), %ymm12+ vmovdqu %ymm3, 0x240(%rsp)+ vpxor 0x100(%rsp), %ymm4, %ymm1+ vmovdqu 0x40(%rsp), %ymm10+ vmovdqu %ymm4, 0x220(%rsp)+ vpxor %ymm3, %ymm12, %ymm12+ vmovdqu 0x20(%rsp), %ymm6+ vmovdqu 0x140(%rsp), %ymm4+ vmovdqu %ymm14, 0x2a0(%rsp)+ vpxor %ymm1, %ymm0, %ymm0+ vpxor %ymm8, %ymm11, %ymm1+ vpxor 0x180(%rsp), %ymm7, %ymm11+ vmovdqu %ymm10, 0x280(%rsp)+ vpxor %ymm1, %ymm12, %ymm12+ vpxor %ymm15, %ymm9, %ymm1+ vmovdqu 0xe0(%rsp), %ymm3+ vmovdqu %ymm8, 0x260(%rsp)+ vpxor %ymm1, %ymm11, %ymm11+ vpxor 0x120(%rsp), %ymm14, %ymm1+ vpxor %ymm6, %ymm12, %ymm12+ vmovdqu 0x60(%rsp), %ymm8+ vpxor %ymm10, %ymm11, %ymm11+ vpxor 0x1e0(%rsp), %ymm13, %ymm10+ vpxor %ymm4, %ymm3, %ymm3+ vmovdqu %ymm4, 0x2c0(%rsp)+ vpsrlq $0x3f, %ymm12, %ymm4+ vpsrlq $0x3f, %ymm11, %ymm5+ vpxor (%rsp), %ymm0, %ymm0+ vpxor %ymm1, %ymm10, %ymm10+ vmovdqu 0x80(%rsp), %ymm1+ vpxor %ymm8, %ymm10, %ymm10+ vmovdqu %ymm1, %ymm14+ vpxor 0x1a0(%rsp), %ymm2, %ymm1+ vmovdqu %ymm14, 0x2e0(%rsp)+ vpxor %ymm3, %ymm1, %ymm1+ vpsllq $0x1, %ymm12, %ymm3+ vpor %ymm4, %ymm3, %ymm3+ vpsllq $0x1, %ymm11, %ymm4+ vpxor %ymm14, %ymm1, %ymm1+ vpor %ymm5, %ymm4, %ymm4+ vpsrlq $0x3f, %ymm10, %ymm14+ vpxor %ymm1, %ymm3, %ymm3+ vpsllq $0x1, %ymm10, %ymm5+ vpxor %ymm0, %ymm4, %ymm4+ vpor %ymm14, %ymm5, %ymm5+ vpxor %ymm6, %ymm4, %ymm6+ vpxor %ymm12, %ymm5, %ymm5+ vpsrlq $0x3f, %ymm1, %ymm12+ vpsllq $0x1, %ymm1, %ymm1+ vpxor %ymm7, %ymm5, %ymm7+ vpxor %ymm9, %ymm5, %ymm9+ vpor %ymm12, %ymm1, %ymm1+ vpxor (%rsp), %ymm3, %ymm12+ vpxor %ymm11, %ymm1, %ymm1+ vpsrlq $0x3f, %ymm0, %ymm11+ vpsllq $0x1, %ymm0, %ymm0+ vpxor %ymm13, %ymm1, %ymm13+ vpxor %ymm8, %ymm1, %ymm8+ vpor %ymm11, %ymm0, %ymm0+ vpxor %ymm10, %ymm0, %ymm0+ vpxor 0xc0(%rsp), %ymm4, %ymm10+ vpxor %ymm2, %ymm0, %ymm2+ vpsrlq $0x14, %ymm10, %ymm11+ vpsllq $0x2c, %ymm10, %ymm10+ vpor %ymm11, %ymm10, %ymm10+ vpxor %ymm15, %ymm5, %ymm11+ vpbroadcastq (%rsi), %ymm15+ vpsrlq $0x15, %ymm11, %ymm14+ vpsllq $0x2b, %ymm11, %ymm11+ vpor %ymm14, %ymm11, %ymm11+ vpandn %ymm11, %ymm10, %ymm14+ vpxor %ymm15, %ymm14, %ymm14+ vpxor %ymm12, %ymm14, %ymm15+ vpsrlq $0x2b, %ymm13, %ymm14+ vpsllq $0x15, %ymm13, %ymm13+ vmovdqu %ymm15, (%rsp)+ vpor %ymm14, %ymm13, %ymm13+ vpandn %ymm13, %ymm11, %ymm14+ vpxor %ymm10, %ymm14, %ymm15+ vpsrlq $0x32, %ymm2, %ymm14+ vpsllq $0xe, %ymm2, %ymm2+ vmovdqu %ymm15, 0x20(%rsp)+ vpor %ymm14, %ymm2, %ymm2+ vpandn %ymm2, %ymm13, %ymm14+ vpxor %ymm11, %ymm14, %ymm11+ vmovdqu %ymm11, 0x40(%rsp)+ vpandn %ymm12, %ymm2, %ymm11+ vpandn %ymm10, %ymm12, %ymm12+ vpxor %ymm13, %ymm11, %ymm11+ vmovdqu %ymm11, 0x60(%rsp)+ vpxor %ymm2, %ymm12, %ymm11+ vpsrlq $0x24, %ymm8, %ymm2+ vpsllq $0x1c, %ymm8, %ymm8+ vmovdqu %ymm11, 0x80(%rsp)+ vpor %ymm2, %ymm8, %ymm8+ vpxor 0xe0(%rsp), %ymm0, %ymm2+ vpsrlq $0x2c, %ymm2, %ymm10+ vpsllq $0x14, %ymm2, %ymm2+ vpor %ymm10, %ymm2, %ymm2+ vpxor 0x100(%rsp), %ymm3, %ymm10+ vpsrlq $0x3d, %ymm10, %ymm11+ vpsllq $0x3, %ymm10, %ymm10+ vpor %ymm11, %ymm10, %ymm10+ vpandn %ymm10, %ymm2, %ymm11+ vpxor %ymm8, %ymm11, %ymm11+ vmovdqu %ymm11, 0xa0(%rsp)+ vpxor 0x160(%rsp), %ymm4, %ymm11+ vpsrlq $0x13, %ymm11, %ymm12+ vpsllq $0x2d, %ymm11, %ymm11+ vpor %ymm12, %ymm11, %ymm11+ vpandn %ymm11, %ymm10, %ymm12+ vpxor %ymm2, %ymm12, %ymm12+ vmovdqu %ymm12, 0xc0(%rsp)+ vpsrlq $0x3, %ymm7, %ymm12+ vpsllq $0x3d, %ymm7, %ymm7+ vpor %ymm12, %ymm7, %ymm7+ vpandn %ymm7, %ymm11, %ymm12+ vpxor %ymm10, %ymm12, %ymm10+ vpandn %ymm8, %ymm7, %ymm12+ vpandn %ymm2, %ymm8, %ymm8+ vpsrlq $0x3f, %ymm6, %ymm2+ vpsllq $0x1, %ymm6, %ymm6+ vpxor %ymm11, %ymm12, %ymm14+ vpor %ymm2, %ymm6, %ymm6+ vpsrlq $0x3a, %ymm9, %ymm2+ vpxor %ymm7, %ymm8, %ymm12+ vpsllq $0x6, %ymm9, %ymm9+ vmovdqu %ymm12, 0xe0(%rsp)+ vpxor 0x1a0(%rsp), %ymm0, %ymm7+ vpor %ymm2, %ymm9, %ymm9+ vpxor 0x120(%rsp), %ymm1, %ymm2+ vpshufb (%rdx), %ymm7, %ymm7+ vpsrlq $0x27, %ymm2, %ymm11+ vpsllq $0x19, %ymm2, %ymm2+ vpor %ymm2, %ymm11, %ymm11+ vpandn %ymm11, %ymm9, %ymm2+ vpandn %ymm7, %ymm11, %ymm8+ vpxor %ymm6, %ymm2, %ymm12+ vpxor 0x1c0(%rsp), %ymm3, %ymm2+ vpxor %ymm9, %ymm8, %ymm8+ vmovdqu %ymm12, 0x100(%rsp)+ vpsrlq $0x2e, %ymm2, %ymm12+ vpsllq $0x12, %ymm2, %ymm2+ vpor %ymm2, %ymm12, %ymm2+ vpandn %ymm2, %ymm7, %ymm12+ vpxor %ymm11, %ymm12, %ymm15+ vpandn %ymm6, %ymm2, %ymm11+ vpandn %ymm9, %ymm6, %ymm6+ vpxor %ymm7, %ymm11, %ymm12+ vmovdqu %ymm12, 0x120(%rsp)+ vpxor %ymm2, %ymm6, %ymm12+ vpxor 0x2e0(%rsp), %ymm0, %ymm6+ vpxor 0x2c0(%rsp), %ymm0, %ymm0+ vmovdqu %ymm12, 0x140(%rsp)+ vpsrlq $0x25, %ymm6, %ymm2+ vpsllq $0x1b, %ymm6, %ymm6+ vpor %ymm6, %ymm2, %ymm2+ vpxor 0x220(%rsp), %ymm3, %ymm6+ vpxor 0x200(%rsp), %ymm3, %ymm3+ vpsrlq $0x1c, %ymm6, %ymm7+ vpsllq $0x24, %ymm6, %ymm6+ vpor %ymm6, %ymm7, %ymm7+ vpxor 0x260(%rsp), %ymm4, %ymm6+ vpxor 0x240(%rsp), %ymm4, %ymm4+ vpsrlq $0x36, %ymm6, %ymm12+ vpsllq $0xa, %ymm6, %ymm6+ vpor %ymm6, %ymm12, %ymm12+ vpxor 0x180(%rsp), %ymm5, %ymm6+ vpxor 0x280(%rsp), %ymm5, %ymm5+ vpandn %ymm12, %ymm7, %ymm9+ vpsrlq $0x31, %ymm6, %ymm11+ vpsllq $0xf, %ymm6, %ymm6+ vpxor %ymm2, %ymm9, %ymm9+ vpor %ymm6, %ymm11, %ymm11+ vpandn %ymm11, %ymm12, %ymm6+ vpxor %ymm7, %ymm6, %ymm6+ vmovdqu %ymm6, 0x160(%rsp)+ vpxor 0x1e0(%rsp), %ymm1, %ymm6+ vpxor 0x2a0(%rsp), %ymm1, %ymm1+ vpshufb (%rcx), %ymm6, %ymm6+ vpandn %ymm6, %ymm11, %ymm13+ vpxor %ymm12, %ymm13, %ymm13+ vmovdqu %ymm13, 0x180(%rsp)+ vpandn %ymm2, %ymm6, %ymm13+ vpandn %ymm7, %ymm2, %ymm2+ vpxor %ymm6, %ymm2, %ymm2+ vpsrlq $0x3e, %ymm4, %ymm6+ vpxor %ymm11, %ymm13, %ymm13+ vmovdqu %ymm2, 0x1a0(%rsp)+ vpsrlq $0x2, %ymm5, %ymm2+ vpsllq $0x3e, %ymm5, %ymm5+ vpor %ymm5, %ymm2, %ymm2+ vpsrlq $0x9, %ymm1, %ymm5+ vpsllq $0x37, %ymm1, %ymm1+ vpsllq $0x2, %ymm4, %ymm4+ vpor %ymm1, %ymm5, %ymm1+ vpsrlq $0x19, %ymm0, %ymm5+ vpor %ymm4, %ymm6, %ymm4+ vpsllq $0x27, %ymm0, %ymm0+ vpor %ymm0, %ymm5, %ymm5+ vpandn %ymm5, %ymm1, %ymm0+ vpxor %ymm2, %ymm0, %ymm0+ vmovdqu %ymm0, 0x1c0(%rsp)+ vpsrlq $0x17, %ymm3, %ymm0+ vpsllq $0x29, %ymm3, %ymm3+ vpor %ymm3, %ymm0, %ymm0+ vpandn %ymm4, %ymm0, %ymm7+ vpandn %ymm0, %ymm5, %ymm3+ vpxor %ymm5, %ymm7, %ymm7+ vpandn %ymm2, %ymm4, %ymm5+ vpandn %ymm1, %ymm2, %ymm2+ vpxor %ymm0, %ymm5, %ymm5+ vpxor %ymm1, %ymm3, %ymm3+ vpxor %ymm4, %ymm2, %ymm2+ vmovdqu %ymm5, 0x1e0(%rsp)+ addq $0x8, %rsi+ addq $0x1, %r10+ cmpq $0x18, %r10+ jne LLmlk_keccak_f1600_x4_avx2+ vmovdqu (%rsp), %ymm4+ vmovdqu 0x40(%rsp), %ymm5+ vmovdqu 0x20(%rsp), %ymm0+ vmovdqu 0x60(%rsp), %ymm1+ vmovdqu 0x1c0(%rsp), %ymm12+ vmovdqu %ymm2, 0x1c0(%rsp)+ vpunpcklqdq %ymm0, %ymm4, %ymm2 # ymm2 = ymm4[0],ymm0[0],ymm4[2],ymm0[2]+ vpunpckhqdq %ymm0, %ymm4, %ymm0 # ymm0 = ymm4[1],ymm0[1],ymm4[3],ymm0[3]+ vpunpcklqdq %ymm1, %ymm5, %ymm4 # ymm4 = ymm5[0],ymm1[0],ymm5[2],ymm1[2]+ vpunpckhqdq %ymm1, %ymm5, %ymm1 # ymm1 = ymm5[1],ymm1[1],ymm5[3],ymm1[3]+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vmovdqu 0x80(%rsp), %ymm4+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm5 # ymm5 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm0 # ymm0 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm6, (%rdi)+ vmovdqu %ymm5, 0xc8(%rdi)+ vmovdqu %ymm2, 0x190(%rdi)+ vmovdqu %ymm0, 0x258(%rdi)+ vmovdqu 0xa0(%rsp), %ymm0+ vpunpcklqdq %ymm0, %ymm4, %ymm2 # ymm2 = ymm4[0],ymm0[0],ymm4[2],ymm0[2]+ vpunpckhqdq %ymm0, %ymm4, %ymm1 # ymm1 = ymm4[1],ymm0[1],ymm4[3],ymm0[3]+ vmovdqu 0xc0(%rsp), %ymm0+ vpunpcklqdq %ymm10, %ymm0, %ymm4 # ymm4 = ymm0[0],ymm10[0],ymm0[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm10[1],ymm0[3],ymm10[3]+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x20, %ymm0, %ymm1, %ymm5 # ymm5 = ymm1[0,1],ymm0[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vmovdqu 0xe0(%rsp), %ymm4+ vperm2i128 $0x31, %ymm0, %ymm1, %ymm1 # ymm1 = ymm1[2,3],ymm0[2,3]+ vmovdqu 0x100(%rsp), %ymm0+ vmovdqu %ymm2, 0x1b0(%rdi)+ vmovdqu %ymm1, 0x278(%rdi)+ vpunpcklqdq %ymm4, %ymm14, %ymm2 # ymm2 = ymm14[0],ymm4[0],ymm14[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm14, %ymm1 # ymm1 = ymm14[1],ymm4[1],ymm14[3],ymm4[3]+ vpunpcklqdq %ymm8, %ymm0, %ymm4 # ymm4 = ymm0[0],ymm8[0],ymm0[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm8[1],ymm0[3],ymm8[3]+ vmovdqu %ymm6, 0x20(%rdi)+ vmovdqu %ymm5, 0xe8(%rdi)+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x20, %ymm0, %ymm1, %ymm5 # ymm5 = ymm1[0,1],ymm0[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vperm2i128 $0x31, %ymm0, %ymm1, %ymm1 # ymm1 = ymm1[2,3],ymm0[2,3]+ vmovdqu 0x120(%rsp), %ymm4+ vmovdqu 0x140(%rsp), %ymm0+ vmovdqu %ymm2, 0x1d0(%rdi)+ vmovdqu %ymm1, 0x298(%rdi)+ vpunpcklqdq %ymm4, %ymm15, %ymm2 # ymm2 = ymm15[0],ymm4[0],ymm15[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm15, %ymm1 # ymm1 = ymm15[1],ymm4[1],ymm15[3],ymm4[3]+ vpunpcklqdq %ymm9, %ymm0, %ymm4 # ymm4 = ymm0[0],ymm9[0],ymm0[2],ymm9[2]+ vmovdqu %ymm5, 0x108(%rdi)+ vpunpckhqdq %ymm9, %ymm0, %ymm0 # ymm0 = ymm0[1],ymm9[1],ymm0[3],ymm9[3]+ vmovdqu %ymm6, 0x40(%rdi)+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vperm2i128 $0x20, %ymm0, %ymm1, %ymm5 # ymm5 = ymm1[0,1],ymm0[0,1]+ vmovdqu 0x160(%rsp), %ymm4+ vperm2i128 $0x31, %ymm0, %ymm1, %ymm1 # ymm1 = ymm1[2,3],ymm0[2,3]+ vmovdqu 0x180(%rsp), %ymm0+ vmovdqu %ymm5, 0x128(%rdi)+ vmovdqu 0x1a0(%rsp), %ymm5+ vmovdqu %ymm2, 0x1f0(%rdi)+ vpunpcklqdq %ymm0, %ymm4, %ymm2 # ymm2 = ymm4[0],ymm0[0],ymm4[2],ymm0[2]+ vpunpckhqdq %ymm0, %ymm4, %ymm0 # ymm0 = ymm4[1],ymm0[1],ymm4[3],ymm0[3]+ vpunpcklqdq %ymm5, %ymm13, %ymm4 # ymm4 = ymm13[0],ymm5[0],ymm13[2],ymm5[2]+ vmovdqu %ymm6, 0x60(%rdi)+ vperm2i128 $0x20, %ymm4, %ymm2, %ymm6 # ymm6 = ymm2[0,1],ymm4[0,1]+ vmovdqu %ymm1, 0x2b8(%rdi)+ vperm2i128 $0x31, %ymm4, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm4[2,3]+ vpunpckhqdq %ymm5, %ymm13, %ymm1 # ymm1 = ymm13[1],ymm5[1],ymm13[3],ymm5[3]+ vmovdqu %ymm6, 0x80(%rdi)+ vmovdqu 0x1e0(%rsp), %ymm4+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm5 # ymm5 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm0 # ymm0 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm2, 0x210(%rdi)+ vpunpcklqdq %ymm3, %ymm12, %ymm2 # ymm2 = ymm12[0],ymm3[0],ymm12[2],ymm3[2]+ vmovdqu %ymm0, 0x2d8(%rdi)+ vpunpckhqdq %ymm3, %ymm12, %ymm0 # ymm0 = ymm12[1],ymm3[1],ymm12[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm7, %ymm3 # ymm3 = ymm7[0],ymm4[0],ymm7[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm7, %ymm1 # ymm1 = ymm7[1],ymm4[1],ymm7[3],ymm4[3]+ vmovdqu %ymm5, 0x148(%rdi)+ vperm2i128 $0x20, %ymm3, %ymm2, %ymm5 # ymm5 = ymm2[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm2, %ymm2 # ymm2 = ymm2[2,3],ymm3[2,3]+ vmovdqu 0x1c0(%rsp), %ymm3+ vperm2i128 $0x20, %ymm1, %ymm0, %ymm4 # ymm4 = ymm0[0,1],ymm1[0,1]+ vperm2i128 $0x31, %ymm1, %ymm0, %ymm0 # ymm0 = ymm0[2,3],ymm1[2,3]+ vmovdqu %ymm5, 0xa0(%rdi)+ vextracti128 $0x1, %ymm3, %xmm15+ vmovdqu %ymm4, 0x168(%rdi)+ vmovdqu %ymm2, 0x230(%rdi)+ vmovdqu %ymm0, 0x2f8(%rdi)+ vmovq %xmm3, 0xc0(%rdi)+ vmovhpd %xmm3, 0x188(%rdi)+ vmovq %xmm15, 0x250(%rdi)+ vmovhpd %xmm15, 0x318(%rdi)+ movq %r11, %rsp+ .cfi_def_cfa_register %rsp+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(keccak_f1600_x4_avx2_asm)++#endif /* MLK_FIPS202_X86_64_NEED_X4_AVX2 && !MLK_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,52 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++#include "../../../../common.h"+#if defined(MLK_FIPS202_X86_64_NEED_X4_AVX2) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#include <stdint.h>++#include "fips202_native_x86_64.h"++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint64_t+ mlk_keccakf1600_round_constants[24] = {+ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a,+ 0x8000000080008000, 0x000000000000808b, 0x0000000080000001,+ 0x8000000080008081, 0x8000000000008009, 0x000000000000008a,+ 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,+ 0x000000008000808b, 0x800000000000008b, 0x8000000000008089,+ 0x8000000000008003, 0x8000000000008002, 0x8000000000000080,+ 0x000000000000800a, 0x800000008000000a, 0x8000000080008081,+ 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,+};++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint64_t mlk_keccak_rho8[4] = {+ 0x0605040302010007,+ 0x0e0d0c0b0a09080f,+ 0x1615141312111017,+ 0x1e1d1c1b1a19181f,+};++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint64_t mlk_keccak_rho56[4] = {+ 0x0007060504030201,+ 0x080f0e0d0c0b0a09,+ 0x1017161514131211,+ 0x181f1e1d1c1b1a19,+};++#else /* MLK_FIPS202_X86_64_NEED_X4_AVX2 && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++MLK_EMPTY_CU(fips202_x86_64_constants)++#endif /* !(MLK_FIPS202_X86_64_NEED_X4_AVX2 && \+ !MLK_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,675 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ *+ * - [REF]+ * CRYSTALS-Kyber C reference implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/ref+ */++#include "indcpa.h"++#include "debug.h"+#include "randombytes.h"+#include "sampling.h"+#include "symmetric.h"+#include "verify.h"++/* Parameter set namespacing+ * This is to facilitate building multiple instances+ * of mlkem-native (e.g. with varying parameter sets)+ * within a single compilation unit. */+#define mlk_pack_pk MLK_ADD_PARAM_SET(mlk_pack_pk)+#define mlk_unpack_pk MLK_ADD_PARAM_SET(mlk_unpack_pk)+#define mlk_pack_sk MLK_ADD_PARAM_SET(mlk_pack_sk)+#define mlk_unpack_sk MLK_ADD_PARAM_SET(mlk_unpack_sk)+#define mlk_pack_ciphertext MLK_ADD_PARAM_SET(mlk_pack_ciphertext)+#define mlk_unpack_ciphertext MLK_ADD_PARAM_SET(mlk_unpack_ciphertext)+#define mlk_matvec_mul MLK_ADD_PARAM_SET(mlk_matvec_mul)+#define mlk_polyvec_permute_bitrev_to_custom \+ MLK_ADD_PARAM_SET(mlk_polyvec_permute_bitrev_to_custom)+#define mlk_polymat_permute_bitrev_to_custom \+ MLK_ADD_PARAM_SET(mlk_polymat_permute_bitrev_to_custom)+#define mlk_keypair_getnoise_eta1 MLK_ADD_PARAM_SET(mlk_keypair_getnoise_eta1)+#define mlk_enc_getnoise_eta1_eta2 MLK_ADD_PARAM_SET(mlk_enc_getnoise_eta1_eta2)+/* End of parameter set namespacing */++/**+ * Serialize the public key as the concatenation of the serialized vector of+ * polynomials pk and the public seed used to generate the matrix A.+ *+ * @spec{Implements @[FIPS203, Algorithm 13 (K-PKE.KeyGen), L19].}+ *+ * @param[out] r Output serialized public key.+ * @param[in] pk Input public-key polyvec. Must have coefficients within+ * [0,..,MLKEM_Q-1].+ * @param[in] seed Input public seed.+ */+#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+static void mlk_pack_pk(uint8_t r[MLKEM_INDCPA_PUBLICKEYBYTES],+ const mlk_polyvec *pk,+ const uint8_t seed[MLKEM_SYMBYTES])+{+ mlk_assert_bound_2d(pk->vec, MLKEM_K, MLKEM_N, 0, MLKEM_Q);+ mlk_polyvec_tobytes(r, pk);+ mlk_memcpy(r + MLKEM_POLYVECBYTES, seed, MLKEM_SYMBYTES);+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++/**+ * De-serialize public key from a byte array; approximate inverse of+ * mlk_pack_pk.+ *+ * @spec{Implements @[FIPS203, Algorithm 14 (K-PKE.Encrypt), L2-3].}+ *+ * @param[out] pk Output public-key polynomial vector. Coefficients+ * will be normalized to [0,1,..,MLKEM_Q-1].+ * @param[out] seed Output seed to generate matrix A.+ * @param[in] packedpk Input serialized public key.+ */+#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+static void mlk_unpack_pk(mlk_polyvec *pk, uint8_t seed[MLKEM_SYMBYTES],+ const uint8_t packedpk[MLKEM_INDCPA_PUBLICKEYBYTES])+{+ mlk_polyvec_frombytes(pk, packedpk);+ mlk_memcpy(seed, packedpk + MLKEM_POLYVECBYTES, MLKEM_SYMBYTES);++ /* NOTE: If a modulus check was conducted on the PK, we know at this+ * point that the coefficients of `pk` are unsigned canonical. The+ * specifications and proofs, however, do _not_ assume this, and instead+ * work with the easily provable bound by MLKEM_UINT12_LIMIT. */+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++/**+ * Serialize the secret key.+ *+ * @spec{Implements @[FIPS203, Algorithm 13 (K-PKE.KeyGen), L20].}+ *+ * @param[out] r Output serialized secret key.+ * @param[in] sk Input vector of polynomials (secret key).+ */+#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+static void mlk_pack_sk(uint8_t r[MLKEM_INDCPA_SECRETKEYBYTES],+ const mlk_polyvec *sk)+{+ mlk_assert_bound_2d(sk->vec, MLKEM_K, MLKEM_N, 0, MLKEM_Q);+ mlk_polyvec_tobytes(r, sk);+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++/**+ * De-serialize the secret key; inverse of mlk_pack_sk.+ *+ * @spec{Implements @[FIPS203, Algorithm 15 (K-PKE.Decrypt), L5].}+ *+ * @param[out] sk Output vector of polynomials (secret key).+ * @param[in] packedsk Input serialized secret key.+ */+#if !defined(MLK_CONFIG_NO_DECAPS_API)+static void mlk_unpack_sk(mlk_polyvec *sk,+ const uint8_t packedsk[MLKEM_INDCPA_SECRETKEYBYTES])+{+ mlk_polyvec_frombytes(sk, packedsk);+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++/**+ * Serialize the ciphertext as the concatenation of the compressed and+ * serialized vector of polynomials b and the compressed and serialized+ * polynomial v.+ *+ * @spec{Implements @[FIPS203, Algorithm 14 (K-PKE.Encrypt), L22-23].}+ *+ * @param[out] r Output serialized ciphertext.+ * @param[in] b Input vector of polynomials b.+ * @param[in] v Input polynomial v.+ */+#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+static void mlk_pack_ciphertext(uint8_t r[MLKEM_INDCPA_BYTES],+ const mlk_polyvec *b, mlk_poly *v)+{+ mlk_polyvec_compress_du(r, b);+ mlk_poly_compress_dv(r + MLKEM_POLYVECCOMPRESSEDBYTES_DU, v);+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++/**+ * De-serialize and decompress ciphertext from a byte array; approximate+ * inverse of mlk_pack_ciphertext.+ *+ * @spec{Implements @[FIPS203, Algorithm 15 (K-PKE.Decrypt), L1-4].}+ *+ * @param[out] b Output vector of polynomials b.+ * @param[out] v Output polynomial v.+ * @param[in] c Input serialized ciphertext.+ */+#if !defined(MLK_CONFIG_NO_DECAPS_API)+static void mlk_unpack_ciphertext(mlk_polyvec *b, mlk_poly *v,+ const uint8_t c[MLKEM_INDCPA_BYTES])+{+ mlk_polyvec_decompress_du(b, c);+ mlk_poly_decompress_dv(v, c + MLKEM_POLYVECCOMPRESSEDBYTES_DU);+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++/* Helper function to ensure that the polynomial entries in the output+ * of gen_matrix use the standard (bitreversed) ordering of coefficients.+ * No-op unless a native backend with a custom ordering is used.+ *+ * We don't inline this into gen_matrix to avoid having to split the CBMC+ * proof for gen_matrix based on MLK_USE_NATIVE_NTT_CUSTOM_ORDER. */+static void mlk_polyvec_permute_bitrev_to_custom(mlk_polyvec *v)+__contract__(+ /* We don't specify that this should be a permutation, but only+ * that it does not change the bound established at the end of mlk_gen_matrix. */+ requires(memory_no_alias(v, sizeof(mlk_polyvec)))+ requires(forall(x, 0, MLKEM_K,+ array_bound(v->vec[x].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))+ assigns(memory_slice(v, sizeof(mlk_polyvec)))+ ensures(forall(x, 0, MLKEM_K,+ array_bound(v->vec[x].coeffs, 0, MLKEM_N, 0, MLKEM_Q))))+{+#if defined(MLK_USE_NATIVE_NTT_CUSTOM_ORDER)+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ __loop__(+ assigns(i, memory_slice(v, sizeof(mlk_polyvec)))+ invariant(i <= MLKEM_K)+ invariant(forall(x, 0, MLKEM_K,+ array_bound(v->vec[x].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))+ decreases(MLKEM_K - i))+ {+ mlk_poly_permute_bitrev_to_custom(v->vec[i].coeffs);+ }+#else /* MLK_USE_NATIVE_NTT_CUSTOM_ORDER */+ /* Nothing to do */+ (void)v;+#endif /* !MLK_USE_NATIVE_NTT_CUSTOM_ORDER */+}++static void mlk_polymat_permute_bitrev_to_custom(mlk_polymat *a)+__contract__(+ /* We don't specify that this should be a permutation, but only+ * that it does not change the bound established at the end of mlk_gen_matrix. */+ requires(memory_no_alias(a, sizeof(mlk_polymat)))+ requires(forall(x, 0, MLKEM_K, forall(y, 0, MLKEM_K,+ array_bound(a->vec[x].vec[y].coeffs, 0, MLKEM_N, 0, MLKEM_Q))))+ assigns(memory_slice(a, sizeof(mlk_polymat)))+ ensures(forall(x, 0, MLKEM_K, forall(y, 0, MLKEM_K,+ array_bound(a->vec[x].vec[y].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))))+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ __loop__(+ assigns(i, memory_slice(a, sizeof(mlk_polymat)))+ invariant(i <= MLKEM_K)+ invariant(forall(x, 0, MLKEM_K, forall(y, 0, MLKEM_K,+ array_bound(a->vec[x].vec[y].coeffs, 0, MLKEM_N, 0, MLKEM_Q))))+ decreases(MLKEM_K - i))+ {+ mlk_polyvec_permute_bitrev_to_custom(&a->vec[i]);+ }+}++/* Reference: `gen_matrix()` in the reference implementation @[REF].+ * - We use a special subroutine to generate 4 polynomials+ * at a time, to be able to leverage batched Keccak-f1600+ * implementations. The reference implementation generates+ * one matrix entry a time.+ *+ * Not static for benchmarking */+MLK_INTERNAL_API+void mlk_gen_matrix(mlk_polymat *a, const uint8_t seed[MLKEM_SYMBYTES],+ int transposed)+{+ unsigned i, j;+ MLK_ALIGN uint8_t seed_ext[4][MLK_ALIGN_UP(MLKEM_SYMBYTES + 2)];++ for (j = 0; j < 4; j++)+ {+ mlk_memcpy(seed_ext[j], seed, MLKEM_SYMBYTES);+ }++#if !defined(MLK_CONFIG_SERIAL_FIPS202_ONLY)+ /* Sample 4 matrix entries a time. */+ for (i = 0; i < (MLKEM_K * MLKEM_K / 4) * 4; i += 4)+ {+ for (j = 0; j < 4; j++)+ {+ uint8_t x, y;+ /* MLKEM_K <= 4, so the values fit in uint8_t. */+ x = (uint8_t)((i + j) / MLKEM_K);+ y = (uint8_t)((i + j) % MLKEM_K);+ if (transposed)+ {+ seed_ext[j][MLKEM_SYMBYTES + 0] = x;+ seed_ext[j][MLKEM_SYMBYTES + 1] = y;+ }+ else+ {+ seed_ext[j][MLKEM_SYMBYTES + 0] = y;+ seed_ext[j][MLKEM_SYMBYTES + 1] = x;+ }+ }++ mlk_poly_rej_uniform_x4(&a->vec[i / MLKEM_K].vec[i % MLKEM_K],+ &a->vec[(i + 1) / MLKEM_K].vec[(i + 1) % MLKEM_K],+ &a->vec[(i + 2) / MLKEM_K].vec[(i + 2) % MLKEM_K],+ &a->vec[(i + 3) / MLKEM_K].vec[(i + 3) % MLKEM_K],+ seed_ext);+ }+#else /* !MLK_CONFIG_SERIAL_FIPS202_ONLY */+ /* When using serial FIPS202, sample all entries individually. */+ i = 0;+#endif /* MLK_CONFIG_SERIAL_FIPS202_ONLY */++ /* For MLKEM_K == 3, sample the last entry individually.+ * When MLK_CONFIG_SERIAL_FIPS202_ONLY is set, sample all entries+ * individually. */+ for (; i < MLKEM_K * MLKEM_K; i++)+ {+ uint8_t x, y;+ /* MLKEM_K <= 4, so the values fit in uint8_t. */+ x = (uint8_t)(i / MLKEM_K);+ y = (uint8_t)(i % MLKEM_K);++ if (transposed)+ {+ seed_ext[0][MLKEM_SYMBYTES + 0] = x;+ seed_ext[0][MLKEM_SYMBYTES + 1] = y;+ }+ else+ {+ seed_ext[0][MLKEM_SYMBYTES + 0] = y;+ seed_ext[0][MLKEM_SYMBYTES + 1] = x;+ }++ mlk_poly_rej_uniform(&a->vec[i / MLKEM_K].vec[i % MLKEM_K], seed_ext[0]);+ }++ mlk_assert(i == MLKEM_K * MLKEM_K);++ /*+ * The public matrix is generated in NTT domain. If the native backend+ * uses a custom order in NTT domain, permute A accordingly.+ */+ mlk_polymat_permute_bitrev_to_custom(a);++ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(seed_ext, sizeof(seed_ext));+}++/**+ * Compute matrix-vector product in NTT domain, via Montgomery multiplication.+ *+ * @spec{Implements @[FIPS203, Section 2.4.7, Eq (2.12), (2.13)].}+ *+ * @param[out] out Output polynomial vector.+ * @param[in] a Input matrix. Must be in NTT domain and have coefficients+ * of absolute value < 4096.+ * @param[in] v Input polynomial vector. Must be in NTT domain.+ * @param[in] vc Mulcache for @p v, computed via+ * mlk_polyvec_mulcache_compute().+ */+static void mlk_matvec_mul(mlk_polyvec *out, const mlk_polymat *a,+ const mlk_polyvec *v, const mlk_polyvec_mulcache *vc)+__contract__(+ requires(memory_no_alias(out, sizeof(mlk_polyvec)))+ requires(memory_no_alias(a, sizeof(mlk_polymat)))+ requires(memory_no_alias(v, sizeof(mlk_polyvec)))+ requires(memory_no_alias(vc, sizeof(mlk_polyvec_mulcache)))+ requires(forall(k0, 0, MLKEM_K,+ forall(k1, 0, MLKEM_K,+ array_bound(a->vec[k0].vec[k1].coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT))))+ assigns(memory_slice(out, sizeof(mlk_polyvec))))+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ __loop__(+ assigns(i, memory_slice(out, sizeof(mlk_polyvec)))+ invariant(i <= MLKEM_K)+ decreases(MLKEM_K - i))+ {+ mlk_polyvec_basemul_acc_montgomery_cached(&out->vec[i], &a->vec[i], v, vc);+ }+}++/**+ * Compute and fill the pv and e polyvec structures needed by+ * mlk_keypair_derand(). Uses x4-batched versions of `poly_getnoise` to+ * leverage batched Keccak-f1600.+ *+ * @spec{Implements @[FIPS203, Algorithm 13 (K-PKE.KeyGen)] steps 8-15.}+ *+ * @param[out] pv Output polynomial vector.+ * @param[out] e Output polynomial vector.+ * @param[in] seed Seed bytes for sampling.+ */+#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+static void mlk_keypair_getnoise_eta1(mlk_polyvec *pv, mlk_polyvec *e,+ const uint8_t seed[MLKEM_SYMBYTES])+__contract__(+ requires(memory_no_alias(pv, sizeof(mlk_polyvec)))+ requires(memory_no_alias(e, sizeof(mlk_polyvec)))+ requires(memory_no_alias(seed, MLKEM_SYMBYTES))+ assigns(memory_slice(pv, sizeof(mlk_polyvec)))+ assigns(memory_slice(e, sizeof(mlk_polyvec)))+ ensures(forall(k0, 0, MLKEM_K, array_abs_bound(pv->vec[k0].coeffs, 0, MLKEM_N, MLKEM_ETA1 + 1)))+ ensures(forall(k1, 0, MLKEM_K, array_abs_bound(e->vec[k1].coeffs, 0, MLKEM_N, MLKEM_ETA1 + 1)))+)+{+#if MLKEM_K == 2+ mlk_poly_getnoise_eta1_4x(&pv->vec[0], &pv->vec[1], /* Fill elements of pv */+ &e->vec[0], &e->vec[1], /* and two elements of e */+ seed, 0, 1, 2, 3);+#elif MLKEM_K == 3+ /*+ * Only the first three output buffers are needed, so we pass NULL as+ * the fourth parameter, and 0xFF as its dummy nonce.+ */+ mlk_poly_getnoise_eta1_4x(&pv->vec[0], &pv->vec[1], &pv->vec[2], NULL, seed,+ 0, 1, 2, 0xFF);+ /* Same here */+ mlk_poly_getnoise_eta1_4x(&e->vec[0], &e->vec[1], &e->vec[2], NULL, seed, 3,+ 4, 5, 0xFF);+#elif MLKEM_K == 4+ mlk_poly_getnoise_eta1_4x(&pv->vec[0], &pv->vec[1], &pv->vec[2], &pv->vec[3],+ seed, 0, 1, 2, 3);+ mlk_poly_getnoise_eta1_4x(&e->vec[0], &e->vec[1], &e->vec[2], &e->vec[3],+ seed, 4, 5, 6, 7);+#endif /* MLKEM_K == 4 */+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++/**+ * Compute and fill the sp, ep, and epp polynomial structures needed by+ * mlk_indcpa_enc(). Uses x4-batched versions of `poly_getnoise` to leverage+ * batched Keccak-f1600.+ *+ * @spec{Implements @[FIPS203, Algorithm 14 (K-PKE.Encrypt)] steps 9-16.}+ *+ * @param[out] sp Output polynomial vector.+ * @param[out] ep Output polynomial vector.+ * @param[out] epp Output polynomial.+ * @param[in] coins Seed bytes for sampling.+ */+#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+static void mlk_enc_getnoise_eta1_eta2(mlk_polyvec *sp, mlk_polyvec *ep,+ mlk_poly *epp,+ const uint8_t coins[MLKEM_SYMBYTES])+__contract__(+ requires(memory_no_alias(sp, sizeof(mlk_polyvec)))+ requires(memory_no_alias(ep, sizeof(mlk_polyvec)))+ requires(memory_no_alias(epp, sizeof(mlk_poly)))+ requires(memory_no_alias(coins, MLKEM_SYMBYTES))+ assigns(memory_slice(sp, sizeof(mlk_polyvec)))+ assigns(memory_slice(ep, sizeof(mlk_polyvec)))+ assigns(memory_slice(epp, sizeof(mlk_poly)))+ ensures(forall(k0, 0, MLKEM_K, array_abs_bound(sp->vec[k0].coeffs, 0, MLKEM_N, MLKEM_ETA1 + 1)))+ ensures(forall(k1, 0, MLKEM_K, array_abs_bound(ep->vec[k1].coeffs, 0, MLKEM_N, MLKEM_ETA2 + 1)))+ ensures(array_abs_bound(epp->coeffs, 0, MLKEM_N, MLKEM_ETA2 + 1))+)+{+#if MLKEM_K == 2+ mlk_poly_getnoise_eta1122_4x(&sp->vec[0], &sp->vec[1], &ep->vec[0],+ &ep->vec[1], coins, 0, 1, 2, 3);+ mlk_poly_getnoise_eta2(epp, coins, 4);+#elif MLKEM_K == 3+ /*+ * In this call, only the first three output buffers are needed,+ * so we pass NULL as the fourth parameter, and 0xFF as its dummy nonce.+ */+ mlk_poly_getnoise_eta1_4x(&sp->vec[0], &sp->vec[1], &sp->vec[2], NULL, coins,+ 0, 1, 2, 0xFF /* irrelevant */);+ /* The fourth output buffer in this call _is_ used. */+ mlk_poly_getnoise_eta2_4x(&ep->vec[0], &ep->vec[1], &ep->vec[2], epp, coins,+ 3, 4, 5, 6);+#elif MLKEM_K == 4+ mlk_poly_getnoise_eta1_4x(&sp->vec[0], &sp->vec[1], &sp->vec[2], &sp->vec[3],+ coins, 0, 1, 2, 3);+ mlk_poly_getnoise_eta2_4x(&ep->vec[0], &ep->vec[1], &ep->vec[2], &ep->vec[3],+ coins, 4, 5, 6, 7);+ mlk_poly_getnoise_eta2(epp, coins, 8);+#endif /* MLKEM_K == 4 */+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */+++/* Reference: `indcpa_keypair_derand()` in the reference implementation @[REF].+ * - We use a different implementation of `gen_matrix()` which+ * uses x4-batched Keccak-f1600 (see `mlk_gen_matrix()` above).+ * - We use a mulcache to speed up matrix-vector multiplication.+ * - We include buffer zeroization.+ */+#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+MLK_INTERNAL_API+int mlk_indcpa_keypair_derand(uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES],+ uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES],+ const uint8_t coins[MLKEM_SYMBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ const uint8_t *publicseed;+ const uint8_t *noiseseed;+ MLK_ALLOC(buf, uint8_t, 2 * MLKEM_SYMBYTES, context);+ MLK_ALLOC(coins_with_domain_separator, uint8_t, MLKEM_SYMBYTES + 1, context);+ MLK_ALLOC(a, mlk_polymat, 1, context);+ MLK_ALLOC(e, mlk_polyvec, 1, context);+ MLK_ALLOC(pkpv, mlk_polyvec, 1, context);+ MLK_ALLOC(skpv, mlk_polyvec, 1, context);+ MLK_ALLOC(skpv_cache, mlk_polyvec_mulcache, 1, context);++ if (buf == NULL || coins_with_domain_separator == NULL || a == NULL ||+ e == NULL || pkpv == NULL || skpv == NULL || skpv_cache == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ publicseed = buf;+ noiseseed = buf + MLKEM_SYMBYTES;++ /* Concatenate coins with MLKEM_K for domain separation of security levels */+ mlk_memcpy(coins_with_domain_separator, coins, MLKEM_SYMBYTES);+ coins_with_domain_separator[MLKEM_SYMBYTES] = MLKEM_K;++ mlk_hash_g(buf, coins_with_domain_separator, MLKEM_SYMBYTES + 1);++ /*+ * Declassify the public seed.+ * Required to use it in conditional-branches in rejection sampling.+ * This is needed because all output of randombytes is marked as secret+ * (=undefined)+ */+ MLK_CT_TESTING_DECLASSIFY(publicseed, MLKEM_SYMBYTES);++ mlk_gen_matrix(a, publicseed, 0 /* no transpose */);++ mlk_keypair_getnoise_eta1(skpv, e, noiseseed);++ mlk_polyvec_ntt(skpv);+ mlk_polyvec_ntt(e);++ mlk_polyvec_mulcache_compute(skpv_cache, skpv);+ mlk_matvec_mul(pkpv, a, skpv, skpv_cache);+ mlk_polyvec_tomont(pkpv);++ mlk_polyvec_add(pkpv, e);+ mlk_polyvec_reduce(pkpv);+ mlk_polyvec_reduce(skpv);++ mlk_pack_sk(sk, skpv);+ mlk_pack_pk(pk, pkpv, publicseed);++cleanup:+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(skpv_cache, mlk_polyvec_mulcache, 1, context);+ MLK_FREE(skpv, mlk_polyvec, 1, context);+ MLK_FREE(pkpv, mlk_polyvec, 1, context);+ MLK_FREE(e, mlk_polyvec, 1, context);+ MLK_FREE(a, mlk_polymat, 1, context);+ MLK_FREE(coins_with_domain_separator, uint8_t, MLKEM_SYMBYTES + 1, context);+ MLK_FREE(buf, uint8_t, 2 * MLKEM_SYMBYTES, context);+ return ret;+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++/* Reference: `indcpa_enc()` in the reference implementation @[REF].+ * - We use x4-batched versions of `poly_getnoise` to leverage+ * batched x4-batched Keccak-f1600.+ * - We use a different implementation of `gen_matrix()` which+ * uses x4-batched Keccak-f1600 (see `mlk_gen_matrix()` above).+ * - We use a mulcache to speed up matrix-vector multiplication.+ * - We include buffer zeroization.+ */+#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_INTERNAL_API+int mlk_indcpa_enc(uint8_t c[MLKEM_INDCPA_BYTES],+ const uint8_t m[MLKEM_INDCPA_MSGBYTES],+ const uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES],+ const uint8_t coins[MLKEM_SYMBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ MLK_ALLOC(seed, uint8_t, MLKEM_SYMBYTES, context);+ MLK_ALLOC(at, mlk_polymat, 1, context);+ MLK_ALLOC(sp, mlk_polyvec, 1, context);+ MLK_ALLOC(pkpv, mlk_polyvec, 1, context);+ MLK_ALLOC(ep, mlk_polyvec, 1, context);+ MLK_ALLOC(b, mlk_polyvec, 1, context);+ MLK_ALLOC(v, mlk_poly, 1, context);+ MLK_ALLOC(k, mlk_poly, 1, context);+ MLK_ALLOC(epp, mlk_poly, 1, context);+ MLK_ALLOC(sp_cache, mlk_polyvec_mulcache, 1, context);++ if (seed == NULL || at == NULL || sp == NULL || pkpv == NULL || ep == NULL ||+ b == NULL || v == NULL || k == NULL || epp == NULL || sp_cache == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ mlk_unpack_pk(pkpv, seed, pk);+ mlk_poly_frommsg(k, m);++ /*+ * Declassify the public seed.+ * Required to use it in conditional-branches in rejection sampling.+ * This is needed because in re-encryption the publicseed originated from sk+ * which is marked undefined.+ */+ MLK_CT_TESTING_DECLASSIFY(seed, MLKEM_SYMBYTES);++ mlk_gen_matrix(at, seed, 1 /* transpose */);++ mlk_enc_getnoise_eta1_eta2(sp, ep, epp, coins);++ mlk_polyvec_ntt(sp);++ mlk_polyvec_mulcache_compute(sp_cache, sp);+ mlk_matvec_mul(b, at, sp, sp_cache);+ mlk_polyvec_basemul_acc_montgomery_cached(v, pkpv, sp, sp_cache);++ mlk_polyvec_invntt_tomont(b);+ mlk_poly_invntt_tomont(v);++ mlk_polyvec_add(b, ep);+ mlk_poly_add(v, epp);+ mlk_poly_add(v, k);++ mlk_polyvec_reduce(b);+ mlk_poly_reduce(v);++ mlk_pack_ciphertext(c, b, v);++cleanup:+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(sp_cache, mlk_polyvec_mulcache, 1, context);+ MLK_FREE(epp, mlk_poly, 1, context);+ MLK_FREE(k, mlk_poly, 1, context);+ MLK_FREE(v, mlk_poly, 1, context);+ MLK_FREE(b, mlk_polyvec, 1, context);+ MLK_FREE(ep, mlk_polyvec, 1, context);+ MLK_FREE(pkpv, mlk_polyvec, 1, context);+ MLK_FREE(sp, mlk_polyvec, 1, context);+ MLK_FREE(at, mlk_polymat, 1, context);+ MLK_FREE(seed, uint8_t, MLKEM_SYMBYTES, context);+ return ret;+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++/* Reference: `indcpa_dec()` in the reference implementation @[REF].+ * - We use a mulcache for the scalar product.+ * - We include buffer zeroization. */+#if !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_INTERNAL_API+int mlk_indcpa_dec(uint8_t m[MLKEM_INDCPA_MSGBYTES],+ const uint8_t c[MLKEM_INDCPA_BYTES],+ const uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ MLK_ALLOC(b, mlk_polyvec, 1, context);+ MLK_ALLOC(skpv, mlk_polyvec, 1, context);+ MLK_ALLOC(v, mlk_poly, 1, context);+ MLK_ALLOC(sb, mlk_poly, 1, context);+ MLK_ALLOC(b_cache, mlk_polyvec_mulcache, 1, context);++ if (b == NULL || skpv == NULL || v == NULL || sb == NULL || b_cache == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ mlk_unpack_ciphertext(b, v, c);+ mlk_unpack_sk(skpv, sk);++ mlk_polyvec_ntt(b);+ mlk_polyvec_mulcache_compute(b_cache, b);+ mlk_polyvec_basemul_acc_montgomery_cached(sb, skpv, b, b_cache);+ mlk_poly_invntt_tomont(sb);++ mlk_poly_sub(v, sb);+ mlk_poly_reduce(v);++ mlk_poly_tomsg(m, v);++cleanup:+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(b_cache, mlk_polyvec_mulcache, 1, context);+ MLK_FREE(sb, mlk_poly, 1, context);+ MLK_FREE(v, mlk_poly, 1, context);+ MLK_FREE(skpv, mlk_polyvec, 1, context);+ MLK_FREE(b, mlk_polyvec, 1, context);+ return ret;+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef mlk_pack_pk+#undef mlk_unpack_pk+#undef mlk_pack_sk+#undef mlk_unpack_sk+#undef mlk_pack_ciphertext+#undef mlk_unpack_ciphertext+#undef mlk_matvec_mul+#undef mlk_polyvec_permute_bitrev_to_custom+#undef mlk_polymat_permute_bitrev_to_custom+#undef mlk_keypair_getnoise_eta1+#undef mlk_enc_getnoise_eta1_eta2
@@ -0,0 +1,172 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#ifndef MLK_INDCPA_H+#define MLK_INDCPA_H++#include "cbmc.h"+#include "common.h"+#include "poly_k.h"++#define mlk_gen_matrix MLK_NAMESPACE_K(gen_matrix)+/**+ * Deterministically generate matrix A (or the transpose of A) from a seed.+ * Entries of the matrix are polynomials that look uniformly random.+ * Performs rejection sampling on the output of an XOF.+ *+ * @spec{Implements @[FIPS203, Algorithm 13 (K-PKE.KeyGen), L3-7] and+ * @[FIPS203, Algorithm 14 (K-PKE.Encrypt), L4-8]. The @p transposed+ * parameter only affects internal presentation.}+ *+ * @param[out] a Output matrix A.+ * @param[in] seed Input seed.+ * @param transposed Boolean deciding whether A or A^T is generated.+ */+MLK_INTERNAL_API+void mlk_gen_matrix(mlk_polymat *a, const uint8_t seed[MLKEM_SYMBYTES],+ int transposed)+__contract__(+ requires(memory_no_alias(a, sizeof(mlk_polymat)))+ requires(memory_no_alias(seed, MLKEM_SYMBYTES))+ requires(transposed == 0 || transposed == 1)+ assigns(memory_slice(a, sizeof(mlk_polymat)))+ ensures(forall(x, 0, MLKEM_K, forall(y, 0, MLKEM_K,+ array_bound(a->vec[x].vec[y].coeffs, 0, MLKEM_N, 0, MLKEM_Q))))+);++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+#define mlk_indcpa_keypair_derand \+ MLK_NAMESPACE_K(indcpa_keypair_derand) MLK_CONTEXT_PARAMETERS_3+/**+ * Generate public and private key for the CPA-secure public-key encryption+ * scheme underlying ML-KEM.+ *+ * @spec{Implements @[FIPS203, Algorithm 13 (K-PKE.KeyGen)].}+ *+ * @param[out] pk Output public key+ * (length MLKEM_INDCPA_PUBLICKEYBYTES bytes).+ * @param[out] sk Output private key+ * (length MLKEM_INDCPA_SECRETKEYBYTES bytes).+ * @param[in] coins Input randomness (length MLKEM_SYMBYTES bytes).+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+MLK_INTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_indcpa_keypair_derand(uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES],+ uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES],+ const uint8_t coins[MLKEM_SYMBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk, MLKEM_INDCPA_PUBLICKEYBYTES))+ requires(memory_no_alias(sk, MLKEM_INDCPA_SECRETKEYBYTES))+ requires(memory_no_alias(coins, MLKEM_SYMBYTES))+ assigns(memory_slice(pk, MLKEM_INDCPA_PUBLICKEYBYTES))+ assigns(memory_slice(sk, MLKEM_INDCPA_SECRETKEYBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_OUT_OF_MEMORY)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(pk, MLKEM_INDCPA_PUBLICKEYBYTES))+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sk, MLKEM_INDCPA_SECRETKEYBYTES))+);+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_indcpa_enc MLK_NAMESPACE_K(indcpa_enc) MLK_CONTEXT_PARAMETERS_4+/**+ * Encryption function of the CPA-secure public-key encryption scheme+ * underlying ML-KEM.+ *+ * @spec{Implements @[FIPS203, Algorithm 14 (K-PKE.Encrypt)].}+ *+ * @param[out] c Output ciphertext (length MLKEM_INDCPA_BYTES bytes).+ * @param[in] m Input message (length MLKEM_INDCPA_MSGBYTES bytes).+ * @param[in] pk Input public key+ * (length MLKEM_INDCPA_PUBLICKEYBYTES bytes).+ * @param[in] coins Input random coins used as seed (length MLKEM_SYMBYTES+ * bytes) to deterministically generate all randomness.+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+MLK_INTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_indcpa_enc(uint8_t c[MLKEM_INDCPA_BYTES],+ const uint8_t m[MLKEM_INDCPA_MSGBYTES],+ const uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES],+ const uint8_t coins[MLKEM_SYMBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(c, MLKEM_INDCPA_BYTES))+ requires(memory_no_alias(m, MLKEM_INDCPA_MSGBYTES))+ requires(memory_no_alias(pk, MLKEM_INDCPA_PUBLICKEYBYTES))+ requires(memory_no_alias(coins, MLKEM_SYMBYTES))+ assigns(memory_slice(c, MLKEM_INDCPA_BYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_OUT_OF_MEMORY)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(c, MLKEM_INDCPA_BYTES))+);+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_indcpa_dec MLK_NAMESPACE_K(indcpa_dec) MLK_CONTEXT_PARAMETERS_3+/**+ * Decryption function of the CPA-secure public-key encryption scheme+ * underlying ML-KEM.+ *+ * @spec{Implements @[FIPS203, Algorithm 15 (K-PKE.Decrypt)].}+ *+ * @param[out] m Output decrypted message+ * (length MLKEM_INDCPA_MSGBYTES bytes).+ * @param[in] c Input ciphertext (length MLKEM_INDCPA_BYTES bytes).+ * @param[in] sk Input secret key+ * (length MLKEM_INDCPA_SECRETKEYBYTES bytes).+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+MLK_INTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_indcpa_dec(uint8_t m[MLKEM_INDCPA_MSGBYTES],+ const uint8_t c[MLKEM_INDCPA_BYTES],+ const uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(c, MLKEM_INDCPA_BYTES))+ requires(memory_no_alias(m, MLKEM_INDCPA_MSGBYTES))+ requires(memory_no_alias(sk, MLKEM_INDCPA_SECRETKEYBYTES))+ assigns(memory_slice(m, MLKEM_INDCPA_MSGBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_OUT_OF_MEMORY)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(m, MLKEM_INDCPA_MSGBYTES))+);+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#endif /* !MLK_INDCPA_H */
@@ -0,0 +1,474 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS140_3_IG]+ * Implementation Guidance for FIPS 140-3 and the Cryptographic Module+ * Validation Program+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ *+ * - [REF]+ * CRYSTALS-Kyber C reference implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/ref+ */++#include "kem.h"++#include "indcpa.h"+#include "randombytes.h"+#include "symmetric.h"+#include "verify.h"++/* Parameter set namespacing+ * This is to facilitate building multiple instances+ * of mlkem-native (e.g. with varying security levels)+ * within a single compilation unit. */+#define mlk_check_pct MLK_ADD_PARAM_SET(mlk_check_pct) MLK_CONTEXT_PARAMETERS_2+/* End of parameter set namespacing */++#if !defined(MLK_CONFIG_NO_ENCAPS_API)+/* Reference: Not implemented in the reference implementation @[REF]. */+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_check_pk(const uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ MLK_ALLOC(p, mlk_polyvec, 1, context);+ MLK_ALLOC(p_reencoded, uint8_t, MLKEM_POLYVECBYTES, context);++ if (p == NULL || p_reencoded == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ mlk_polyvec_frombytes(p, pk);+ mlk_polyvec_reduce(p);+ mlk_polyvec_tobytes(p_reencoded, p);++ /* We use a constant-time memcmp here to avoid having to+ * declassify the PK before the PCT has succeeded. */+ ret = mlk_ct_memcmp(pk, p_reencoded, MLKEM_POLYVECBYTES) ? MLK_ERR_INVALID_PK+ : 0;++cleanup:+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(p_reencoded, uint8_t, MLKEM_POLYVECBYTES, context);+ MLK_FREE(p, mlk_polyvec, 1, context);+ return ret;+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API */+++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: Not implemented in the reference implementation @[REF]. */+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_check_sk(const uint8_t sk[MLKEM_INDCCA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ MLK_ALLOC(test, uint8_t, MLKEM_SYMBYTES, context);++ if (test == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /*+ * The parts of `sk` being hashed and compared here are public, so+ * no public information is leaked through the runtime or the return value+ * of this function.+ */++ /* Declassify the public part of the secret key */+ MLK_CT_TESTING_DECLASSIFY(sk + MLKEM_INDCPA_SECRETKEYBYTES,+ MLKEM_INDCCA_PUBLICKEYBYTES);+ MLK_CT_TESTING_DECLASSIFY(+ sk + MLKEM_INDCCA_SECRETKEYBYTES - 2 * MLKEM_SYMBYTES, MLKEM_SYMBYTES);++ mlk_hash_h(test, sk + MLKEM_INDCPA_SECRETKEYBYTES,+ MLKEM_INDCCA_PUBLICKEYBYTES);+ /* This doesn't have to be a constant-time memcmp, but it's the only place+ * in the library where a normal memcmp would be used otherwise, so for sake+ * of minimizing stdlib dependency, we use our constant-time one anyway. */+ ret = mlk_ct_memcmp(sk + MLKEM_INDCCA_SECRETKEYBYTES - 2 * MLKEM_SYMBYTES,+ test, MLKEM_SYMBYTES)+ ? MLK_ERR_INVALID_SK+ : 0;++cleanup:+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(test, uint8_t, MLKEM_SYMBYTES, context);+ return ret;+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+MLK_MUST_CHECK_RETURN_VALUE+static int mlk_check_pct(uint8_t const pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ uint8_t const sk[MLKEM_INDCCA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ requires(memory_no_alias(sk, MLKEM_INDCCA_SECRETKEYBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_OUT_OF_MEMORY ||+ return_value == MLK_ERR_RNG_FAIL ||+ return_value == MLK_ERR_PCT_FAIL)+);++#if defined(MLK_CONFIG_KEYGEN_PCT)+/* Specification:+ * Partially implements 'Pairwise Consistency Test' @[FIPS140_3_IG, p.87] and+ * @[FIPS203, Section 7.1, Pairwise Consistency]. */++/* Reference: Not implemented in the reference implementation @[REF].+ *+ * @retval 0 Success.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ * @retval MLK_ERR_RNG_FAIL Random number generation failed.+ * @retval MLK_ERR_PCT_FAIL The consistency check failed. */+MLK_MUST_CHECK_RETURN_VALUE+static int mlk_check_pct(uint8_t const pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ uint8_t const sk[MLKEM_INDCCA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ MLK_ALLOC(ct, uint8_t, MLKEM_INDCCA_CIPHERTEXTBYTES, context);+ MLK_ALLOC(ss_enc, uint8_t, MLKEM_SSBYTES, context);+ MLK_ALLOC(ss_dec, uint8_t, MLKEM_SSBYTES, context);++ if (ct == NULL || ss_enc == NULL || ss_dec == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ ret = mlk_kem_enc(ct, ss_enc, pk, context);+ if (ret != 0)+ {+ goto cleanup;+ }++ ret = mlk_kem_dec(ss_dec, ct, sk, context);+ if (ret != 0)+ {+ goto cleanup;+ }++#if defined(MLK_CONFIG_KEYGEN_PCT_BREAKAGE_TEST)+ /* Deliberately break PCT for testing purposes */+ if (mlk_break_pct())+ {+ ss_enc[0] = ~ss_enc[0];+ }+#endif /* MLK_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */++ ret = mlk_ct_memcmp(ss_enc, ss_dec, MLKEM_SSBYTES);+ /* The result of the PCT is public. */+ MLK_CT_TESTING_DECLASSIFY(&ret, sizeof(ret));++ if (ret != 0)+ {+ ret = MLK_ERR_PCT_FAIL;+ }++cleanup:++ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(ss_dec, uint8_t, MLKEM_SSBYTES, context);+ MLK_FREE(ss_enc, uint8_t, MLKEM_SSBYTES, context);+ MLK_FREE(ct, uint8_t, MLKEM_INDCCA_CIPHERTEXTBYTES, context);++ /* The key pair being tested was just generated by this library, so a key+ * check rejecting it hints at a faulty implementation rather than at bad+ * input. Report it as a PCT failure. */+ if (ret == MLK_ERR_INVALID_PK || ret == MLK_ERR_INVALID_SK)+ {+ ret = MLK_ERR_PCT_FAIL;+ }++ /* Other error codes, e.g. platform failures like out of memory or+ * randomness failure, are passed on unmodified. */++ return ret;+}+#else /* MLK_CONFIG_KEYGEN_PCT */+MLK_MUST_CHECK_RETURN_VALUE+static int mlk_check_pct(uint8_t const pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ uint8_t const sk[MLKEM_INDCCA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ /* Skip PCT */+ ((void)pk);+ ((void)sk);+ MLK_CONTEXT_UNUSED(context);+ return 0;+}+#endif /* !MLK_CONFIG_KEYGEN_PCT */++/* Reference: `crypto_kem_keypair_derand()` in the reference implementation+ * @[REF].+ * - We optionally include PCT which is not present in+ * the reference code. */+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_keypair_derand(uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ uint8_t sk[MLKEM_INDCCA_SECRETKEYBYTES],+ const uint8_t coins[2 * MLKEM_SYMBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret;++ ret = mlk_indcpa_keypair_derand(pk, sk, coins, context);+ if (ret != 0)+ {+ goto cleanup;+ }++ mlk_memcpy(sk + MLKEM_INDCPA_SECRETKEYBYTES, pk, MLKEM_INDCCA_PUBLICKEYBYTES);+ mlk_hash_h(sk + MLKEM_INDCCA_SECRETKEYBYTES - 2 * MLKEM_SYMBYTES, pk,+ MLKEM_INDCCA_PUBLICKEYBYTES);+ /* Value z for pseudo-random output on reject */+ mlk_memcpy(sk + MLKEM_INDCCA_SECRETKEYBYTES - MLKEM_SYMBYTES,+ coins + MLKEM_SYMBYTES, MLKEM_SYMBYTES);++ /* Declassify public key */+ MLK_CT_TESTING_DECLASSIFY(pk, MLKEM_INDCCA_PUBLICKEYBYTES);++ /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */+ ret = mlk_check_pct(pk, sk, context);+ if (ret != 0)+ {+ goto cleanup;+ }++cleanup:+ if (ret != 0)+ {+ mlk_zeroize(pk, MLKEM_INDCCA_PUBLICKEYBYTES);+ mlk_zeroize(sk, MLKEM_INDCCA_SECRETKEYBYTES);+ }++ return ret;+}++#if !defined(MLK_CONFIG_NO_RANDOMIZED_API)+/* Reference: `crypto_kem_keypair()` in the reference implementation @[REF]+ * - We zeroize the stack buffer */+MLK_EXTERNAL_API+int mlk_kem_keypair(uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ uint8_t sk[MLKEM_INDCCA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ MLK_ALLOC(coins, uint8_t, 2 * MLKEM_SYMBYTES, context);++ if (coins == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* Acquire necessary randomness, and mark it as secret. */+ if (mlk_randombytes(coins, 2 * MLKEM_SYMBYTES) != 0)+ {+ ret = MLK_ERR_RNG_FAIL;+ goto cleanup;+ }++ MLK_CT_TESTING_SECRET(coins, 2 * MLKEM_SYMBYTES);++ ret = mlk_kem_keypair_derand(pk, sk, coins, context);++cleanup:+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(coins, uint8_t, 2 * MLKEM_SYMBYTES, context);+ return ret;+}+#endif /* !MLK_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API)+/* Reference: `crypto_kem_enc_derand()` in the reference implementation @[REF]+ * - We include public key check+ * - We include stack buffer zeroization */+MLK_EXTERNAL_API+int mlk_kem_enc_derand(uint8_t ct[MLKEM_INDCCA_CIPHERTEXTBYTES],+ uint8_t ss[MLKEM_SSBYTES],+ const uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ const uint8_t coins[MLKEM_SYMBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ MLK_ALLOC(buf, uint8_t, 2 * MLKEM_SYMBYTES, context);+ MLK_ALLOC(kr, uint8_t, 2 * MLKEM_SYMBYTES, context);++ if (buf == NULL || kr == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* Specification: Implements @[FIPS203, Section 7.2, Modulus check] */+ ret = mlk_kem_check_pk(pk, context);+ if (ret != 0)+ {+ goto cleanup;+ }++ mlk_memcpy(buf, coins, MLKEM_SYMBYTES);++ /* Multitarget countermeasure for coins + contributory KEM */+ mlk_hash_h(buf + MLKEM_SYMBYTES, pk, MLKEM_INDCCA_PUBLICKEYBYTES);+ mlk_hash_g(kr, buf, 2 * MLKEM_SYMBYTES);++ /* coins are in kr+MLKEM_SYMBYTES */+ ret = mlk_indcpa_enc(ct, buf, pk, kr + MLKEM_SYMBYTES, context);+ if (ret != 0)+ {+ goto cleanup;+ }++ mlk_memcpy(ss, kr, MLKEM_SYMBYTES);++cleanup:+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(kr, uint8_t, 2 * MLKEM_SYMBYTES, context);+ MLK_FREE(buf, uint8_t, 2 * MLKEM_SYMBYTES, context);+ return ret;+}++#if !defined(MLK_CONFIG_NO_RANDOMIZED_API)+/* Reference: `crypto_kem_enc()` in the reference implementation @[REF]+ * - We include stack buffer zeroization */+MLK_EXTERNAL_API+int mlk_kem_enc(uint8_t ct[MLKEM_INDCCA_CIPHERTEXTBYTES],+ uint8_t ss[MLKEM_SSBYTES],+ const uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ MLK_ALLOC(coins, uint8_t, MLKEM_SYMBYTES, context);++ if (coins == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ if (mlk_randombytes(coins, MLKEM_SYMBYTES) != 0)+ {+ ret = MLK_ERR_RNG_FAIL;+ goto cleanup;+ }++ MLK_CT_TESTING_SECRET(coins, MLKEM_SYMBYTES);++ ret = mlk_kem_enc_derand(ct, ss, pk, coins, context);++cleanup:+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(coins, uint8_t, MLKEM_SYMBYTES, context);+ return ret;+}+#endif /* !MLK_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLK_CONFIG_NO_ENCAPS_API */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `crypto_kem_dec()` in the reference implementation @[REF]+ * - We include secret key check+ * - We include stack buffer zeroization */+MLK_EXTERNAL_API+int mlk_kem_dec(uint8_t ss[MLKEM_SSBYTES],+ const uint8_t ct[MLKEM_INDCCA_CIPHERTEXTBYTES],+ const uint8_t sk[MLKEM_INDCCA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+{+ int ret = 0;+ uint8_t fail;+ const uint8_t *pk = sk + MLKEM_INDCPA_SECRETKEYBYTES;+ MLK_ALLOC(buf, uint8_t, 2 * MLKEM_SYMBYTES, context);+ MLK_ALLOC(kr, uint8_t, 2 * MLKEM_SYMBYTES, context);+ MLK_ALLOC(tmp, uint8_t, MLKEM_SYMBYTES + MLKEM_INDCCA_CIPHERTEXTBYTES,+ context);++ if (buf == NULL || kr == NULL || tmp == NULL)+ {+ ret = MLK_ERR_OUT_OF_MEMORY;+ goto cleanup;+ }++ /* Specification: Implements @[FIPS203, Section 7.3, Hash check] */+ ret = mlk_kem_check_sk(sk, context);+ if (ret != 0)+ {+ goto cleanup;+ }++ ret = mlk_indcpa_dec(buf, ct, sk, context);+ if (ret != 0)+ {+ goto cleanup;+ }++ /* Multitarget countermeasure for coins + contributory KEM */+ mlk_memcpy(buf + MLKEM_SYMBYTES,+ sk + MLKEM_INDCCA_SECRETKEYBYTES - 2 * MLKEM_SYMBYTES,+ MLKEM_SYMBYTES);+ mlk_hash_g(kr, buf, 2 * MLKEM_SYMBYTES);++ /* Recompute and compare ciphertext */+ /* coins are in kr+MLKEM_SYMBYTES */+ ret = mlk_indcpa_enc(tmp, buf, pk, kr + MLKEM_SYMBYTES, context);+ if (ret != 0)+ {+ goto cleanup;+ }++ fail = mlk_ct_memcmp(ct, tmp, MLKEM_INDCCA_CIPHERTEXTBYTES);++ /* Compute rejection key */+ mlk_memcpy(tmp, sk + MLKEM_INDCCA_SECRETKEYBYTES - MLKEM_SYMBYTES,+ MLKEM_SYMBYTES);+ mlk_memcpy(tmp + MLKEM_SYMBYTES, ct, MLKEM_INDCCA_CIPHERTEXTBYTES);+ mlk_hash_j(ss, tmp, MLKEM_SYMBYTES + MLKEM_INDCCA_CIPHERTEXTBYTES);++ /* Copy true key to return buffer if fail is 0 */+ mlk_ct_cmov_zero(ss, kr, MLKEM_SYMBYTES, fail);++cleanup:+ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ MLK_FREE(tmp, uint8_t, MLKEM_SYMBYTES + MLKEM_INDCCA_CIPHERTEXTBYTES,+ context);+ MLK_FREE(kr, uint8_t, 2 * MLKEM_SYMBYTES, context);+ MLK_FREE(buf, uint8_t, 2 * MLKEM_SYMBYTES, context);++ return ret;+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef mlk_check_pct
@@ -0,0 +1,353 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ *+ * - [REF]+ * CRYSTALS-Kyber C reference implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/ref+ */++#ifndef MLK_KEM_H+#define MLK_KEM_H++#include "cbmc.h"+#include "common.h"+#include "sys.h"++#if defined(MLK_CHECK_APIS)+/* Include to ensure consistency between internal kem.h+ * and external mlkem_native.h. */+#include "mlkem_native.h"++#if MLKEM_INDCCA_SECRETKEYBYTES != \+ MLKEM_SECRETKEYBYTES(MLK_CONFIG_PARAMETER_SET)+#error Mismatch for SECRETKEYBYTES between kem.h and mlkem_native.h+#endif++#if MLKEM_INDCCA_PUBLICKEYBYTES != \+ MLKEM_PUBLICKEYBYTES(MLK_CONFIG_PARAMETER_SET)+#error Mismatch for PUBLICKEYBYTES between kem.h and mlkem_native.h+#endif++#if MLKEM_INDCCA_CIPHERTEXTBYTES != \+ MLKEM_CIPHERTEXTBYTES(MLK_CONFIG_PARAMETER_SET)+#error Mismatch for CIPHERTEXTBYTES between kem.h and mlkem_native.h+#endif++#endif /* MLK_CHECK_APIS */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+#define mlk_kem_keypair_derand \+ MLK_NAMESPACE_K(keypair_derand) MLK_CONTEXT_PARAMETERS_3+#if !defined(MLK_CONFIG_NO_RANDOMIZED_API)+#define mlk_kem_keypair MLK_NAMESPACE_K(keypair) MLK_CONTEXT_PARAMETERS_2+#endif+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */+#if !defined(MLK_CONFIG_NO_ENCAPS_API)+#define mlk_kem_enc_derand MLK_NAMESPACE_K(enc_derand) MLK_CONTEXT_PARAMETERS_4+#if !defined(MLK_CONFIG_NO_RANDOMIZED_API)+#define mlk_kem_enc MLK_NAMESPACE_K(enc) MLK_CONTEXT_PARAMETERS_3+#endif+#define mlk_kem_check_pk MLK_NAMESPACE_K(check_pk) MLK_CONTEXT_PARAMETERS_1+#endif /* !MLK_CONFIG_NO_ENCAPS_API */+#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_kem_dec MLK_NAMESPACE_K(dec) MLK_CONTEXT_PARAMETERS_3+#define mlk_kem_check_sk MLK_NAMESPACE_K(check_sk) MLK_CONTEXT_PARAMETERS_1+#endif++/**+ * Implements modulus check mandated by FIPS 203, i.e., ensures that+ * coefficients are in [0,q-1].+ *+ * @spec{Implements @[FIPS203, Section 7.2, 'modulus check'].}+ *+ * @reference{Not implemented in the reference implementation @[REF].}+ *+ * @param[in] pk Input public key (an already allocated array of+ * MLKEM_INDCCA_PUBLICKEYBYTES bytes).+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_INVALID_PK Modulus check failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+#if !defined(MLK_CONFIG_NO_ENCAPS_API)+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_check_pk(const uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_INVALID_PK ||+ return_value == MLK_ERR_OUT_OF_MEMORY)+);+#endif /* !MLK_CONFIG_NO_ENCAPS_API */+++/**+ * Implements public key hash check mandated by FIPS 203, i.e., ensures that+ * sk[768𝑘+32 ∶ 768𝑘+64] = H(pk) = H(sk[384𝑘 : 768𝑘+32]).+ *+ * @spec{Implements @[FIPS203, Section 7.3, 'hash check'].}+ *+ * @reference{Not implemented in the reference implementation @[REF].}+ *+ * @param[in] sk Input private key (an already allocated array of+ * MLKEM_INDCCA_SECRETKEYBYTES bytes).+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_INVALID_SK Public key hash check failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+#if !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_check_sk(const uint8_t sk[MLKEM_INDCCA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(sk, MLKEM_INDCCA_SECRETKEYBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_INVALID_SK ||+ return_value == MLK_ERR_OUT_OF_MEMORY)+);+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+/**+ * Generate a public/private keypair for the ML-KEM key encapsulation mechanism.+ *+ * @spec{Implements @[FIPS203, Algorithm 16, ML-KEM.KeyGen_Internal].}+ *+ * @param[out] pk Output public key (an already allocated array of+ * MLKEM_INDCCA_PUBLICKEYBYTES bytes).+ * @param[out] sk Output private key (an already allocated array of+ * MLKEM_INDCCA_SECRETKEYBYTES bytes).+ * @param[in] coins Input randomness (an already allocated array filled+ * with 2*MLKEM_SYMBYTES random bytes).+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_PCT_FAIL MLK_CONFIG_KEYGEN_PCT enabled and PCT failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ * @retval MLK_ERR_RNG_FAIL MLK_CONFIG_KEYGEN_PCT enabled and random+ * number generation failed within the PCT.+ */+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_keypair_derand(uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ uint8_t sk[MLKEM_INDCCA_SECRETKEYBYTES],+ const uint8_t coins[2 * MLKEM_SYMBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ requires(memory_no_alias(sk, MLKEM_INDCCA_SECRETKEYBYTES))+ requires(memory_no_alias(coins, 2 * MLKEM_SYMBYTES))+ assigns(memory_slice(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ assigns(memory_slice(sk, MLKEM_INDCCA_SECRETKEYBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_PCT_FAIL ||+ return_value == MLK_ERR_OUT_OF_MEMORY ||+ return_value == MLK_ERR_RNG_FAIL)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sk, MLKEM_INDCCA_SECRETKEYBYTES))+);++#if !defined(MLK_CONFIG_NO_RANDOMIZED_API)+/**+ * Generate a public/private keypair for the ML-KEM key encapsulation mechanism.+ *+ * @spec{Implements @[FIPS203, Algorithm 19, ML-KEM.KeyGen].}+ *+ * @param[out] pk Output public key (an already allocated array of+ * MLKEM_INDCCA_PUBLICKEYBYTES bytes).+ * @param[out] sk Output private key (an already allocated array of+ * MLKEM_INDCCA_SECRETKEYBYTES bytes).+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ * @retval MLK_ERR_RNG_FAIL Random number generation failed.+ * @retval MLK_ERR_PCT_FAIL MLK_CONFIG_KEYGEN_PCT enabled and PCT failed.+ */+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_keypair(uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ uint8_t sk[MLKEM_INDCCA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ requires(memory_no_alias(sk, MLKEM_INDCCA_SECRETKEYBYTES))+ assigns(memory_slice(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ assigns(memory_slice(sk, MLKEM_INDCCA_SECRETKEYBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_PCT_FAIL ||+ return_value == MLK_ERR_OUT_OF_MEMORY ||+ return_value == MLK_ERR_RNG_FAIL)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(sk, MLKEM_INDCCA_SECRETKEYBYTES))+);+#endif /* !MLK_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++/**+ * Generate ciphertext and shared secret for a given public key.+ *+ * @spec{Implements @[FIPS203, Algorithm 17, ML-KEM.Encaps_Internal].}+ *+ * @param[out] ct Output ciphertext (an already allocated array of+ * MLKEM_INDCCA_CIPHERTEXTBYTES bytes).+ * @param[out] ss Output shared secret (an already allocated array of+ * MLKEM_SSBYTES bytes).+ * @param[in] pk Input public key (an already allocated array of+ * MLKEM_INDCCA_PUBLICKEYBYTES bytes).+ * @param[in] coins Input randomness (an already allocated array filled+ * with MLKEM_SYMBYTES random bytes).+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_INVALID_PK The 'modulus check' @[FIPS203, Section 7.2]+ * for the public key failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+#if !defined(MLK_CONFIG_NO_ENCAPS_API)+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_enc_derand(uint8_t ct[MLKEM_INDCCA_CIPHERTEXTBYTES],+ uint8_t ss[MLKEM_SSBYTES],+ const uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ const uint8_t coins[MLKEM_SYMBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(ct, MLKEM_INDCCA_CIPHERTEXTBYTES))+ requires(memory_no_alias(ss, MLKEM_SSBYTES))+ requires(memory_no_alias(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ requires(memory_no_alias(coins, MLKEM_SYMBYTES))+ assigns(memory_slice(ct, MLKEM_INDCCA_CIPHERTEXTBYTES))+ assigns(memory_slice(ss, MLKEM_SSBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_INVALID_PK ||+ return_value == MLK_ERR_OUT_OF_MEMORY)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(ct, MLKEM_INDCCA_CIPHERTEXTBYTES))+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(ss, MLKEM_SSBYTES))+);++#if !defined(MLK_CONFIG_NO_RANDOMIZED_API)+/**+ * Generate ciphertext and shared secret for a given public key.+ *+ * @spec{Implements @[FIPS203, Algorithm 20, ML-KEM.Encaps].}+ *+ * @param[out] ct Output ciphertext (an already allocated array of+ * MLKEM_INDCCA_CIPHERTEXTBYTES bytes).+ * @param[out] ss Output shared secret (an already allocated array of+ * MLKEM_SSBYTES bytes).+ * @param[in] pk Input public key (an already allocated array of+ * MLKEM_INDCCA_PUBLICKEYBYTES bytes).+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ * @retval MLK_ERR_RNG_FAIL Random number generation failed.+ * @retval MLK_ERR_INVALID_PK The 'modulus check' @[FIPS203, Section 7.2]+ * for the public key failed.+ */+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_enc(uint8_t ct[MLKEM_INDCCA_CIPHERTEXTBYTES],+ uint8_t ss[MLKEM_SSBYTES],+ const uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(ct, MLKEM_INDCCA_CIPHERTEXTBYTES))+ requires(memory_no_alias(ss, MLKEM_SSBYTES))+ requires(memory_no_alias(pk, MLKEM_INDCCA_PUBLICKEYBYTES))+ assigns(memory_slice(ct, MLKEM_INDCCA_CIPHERTEXTBYTES))+ assigns(memory_slice(ss, MLKEM_SSBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_INVALID_PK ||+ return_value == MLK_ERR_OUT_OF_MEMORY ||+ return_value == MLK_ERR_RNG_FAIL)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(ct, MLKEM_INDCCA_CIPHERTEXTBYTES))+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(ss, MLKEM_SSBYTES))+);+#endif /* !MLK_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLK_CONFIG_NO_ENCAPS_API */++/**+ * Generate shared secret for a given ciphertext and private key.+ *+ * @spec{Implements @[FIPS203, Algorithm 21, ML-KEM.Decaps].}+ *+ * @param[out] ss Output shared secret (an already allocated array of+ * MLKEM_SSBYTES bytes).+ * @param[in] ct Input ciphertext (an already allocated array of+ * MLKEM_INDCCA_CIPHERTEXTBYTES bytes).+ * @param[in] sk Input private key (an already allocated array of+ * MLKEM_INDCCA_SECRETKEYBYTES bytes).+ * @param context Application context. Only present when+ * MLK_CONFIG_CONTEXT_PARAMETER is defined; type set by+ * MLK_CONFIG_CONTEXT_PARAMETER_TYPE.+ *+ * @retval 0 Success.+ * @retval MLK_ERR_INVALID_SK The 'hash check' @[FIPS203, Section 7.3]+ * for the secret key failed.+ * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and+ * MLK_CUSTOM_ALLOC returned NULL.+ */+#if !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_EXTERNAL_API+MLK_MUST_CHECK_RETURN_VALUE+int mlk_kem_dec(uint8_t ss[MLKEM_SSBYTES],+ const uint8_t ct[MLKEM_INDCCA_CIPHERTEXTBYTES],+ const uint8_t sk[MLKEM_INDCCA_SECRETKEYBYTES],+ MLK_CONFIG_CONTEXT_PARAMETER_TYPE context)+__contract__(+ requires(memory_no_alias(ss, MLKEM_SSBYTES))+ requires(memory_no_alias(ct, MLKEM_INDCCA_CIPHERTEXTBYTES))+ requires(memory_no_alias(sk, MLKEM_INDCCA_SECRETKEYBYTES))+ assigns(memory_slice(ss, MLKEM_SSBYTES))+ ensures(return_value == 0 || return_value == MLK_ERR_INVALID_SK ||+ return_value == MLK_ERR_OUT_OF_MEMORY)+ /* Output buffers on error, per API-CONVENTIONS.md */+ ensures(return_value != 0 ==>+ array_unchanged_or_zeroized_u8(ss, MLKEM_SSBYTES))+);+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#endif /* !MLK_KEM_H */
@@ -0,0 +1,16 @@+[//]: # (SPDX-License-Identifier: CC-BY-4.0)++# AArch64 backend (little endian)++This directory contains a native backend for little endian AArch64 systems. It is derived from [^NeonNTT] [^SLOTHY_Paper].++The code in this directory is auto-generated from the 'clean' assembly in [dev/aarch64_clean](../../../../dev/aarch64_clean)+in a two-step fashion: First, it is superoptimized using the [SLOTHY](https://github.com/slothy-optimizer/slothy) superoptimizer,+giving the assembly in [dev/aarch64_opt](../../../../dev/aarch64_opt). Then, it is stripped of remaining register aliases, macros+and most preprocessor directives by [`scripts/simpasm`](../../../../scripts/simpasm).++If you want to understand how the assembly works, and/or make changes to it, consult [dev/](../../../../dev).++<!--- bibliography --->+[^NeonNTT]: Becker, Hwang, Kannwischer, Yang, Yang: Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1, [https://eprint.iacr.org/2021/986](https://eprint.iacr.org/2021/986)+[^SLOTHY_Paper]: Abdulrahman, Becker, Kannwischer, Klein: Fast and Clean: Auditable high-performance assembly via constraint solving, [https://eprint.iacr.org/2022/1303](https://eprint.iacr.org/2022/1303)
@@ -0,0 +1,166 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_NATIVE_AARCH64_META_H+#define MLK_NATIVE_AARCH64_META_H++/* Set of primitives that this backend replaces */+#define MLK_USE_NATIVE_NTT+#define MLK_USE_NATIVE_INTT+#define MLK_USE_NATIVE_POLY_REDUCE+#define MLK_USE_NATIVE_POLY_TOMONT+#define MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE+#define MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED+#define MLK_USE_NATIVE_POLY_TOBYTES+#define MLK_USE_NATIVE_REJ_UNIFORM++/* Identifier for this backend so that source and assembly files+ * in the build can be appropriately guarded. */+#define MLK_ARITH_BACKEND_AARCH64+++#if !defined(__ASSEMBLER__)+#include "../api.h"+#include "src/arith_native_aarch64.h"++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_ntt_native(int16_t data[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ mlk_ntt_aarch64_asm(data, mlk_aarch64_ntt_zetas_layer12345,+ mlk_aarch64_ntt_zetas_layer67);+ return MLK_NATIVE_FUNC_SUCCESS;+}++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_intt_native(int16_t data[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ mlk_intt_aarch64_asm(data, mlk_aarch64_invntt_zetas_layer12345,+ mlk_aarch64_invntt_zetas_layer67);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_reduce_native(int16_t data[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ mlk_poly_reduce_aarch64_asm(data);+ return MLK_NATIVE_FUNC_SUCCESS;+}++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_tomont_native(int16_t data[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ mlk_poly_tomont_aarch64_asm(data);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_mulcache_compute_native(int16_t x[MLKEM_N / 2],+ const int16_t y[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ mlk_poly_mulcache_compute_aarch64_asm(+ x, y, mlk_aarch64_zetas_mulcache_native,+ mlk_aarch64_zetas_mulcache_twisted_native);+ return MLK_NATIVE_FUNC_SUCCESS;+}++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_polyvec_basemul_acc_montgomery_cached_k2_native(+ int16_t r[MLKEM_N], const int16_t a[2 * MLKEM_N],+ const int16_t b[2 * MLKEM_N], const int16_t b_cache[2 * (MLKEM_N / 2)])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ mlk_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm(r, a, b, b_cache);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 3+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_polyvec_basemul_acc_montgomery_cached_k3_native(+ int16_t r[MLKEM_N], const int16_t a[3 * MLKEM_N],+ const int16_t b[3 * MLKEM_N], const int16_t b_cache[3 * (MLKEM_N / 2)])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ mlk_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm(r, a, b, b_cache);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 3 */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_polyvec_basemul_acc_montgomery_cached_k4_native(+ int16_t r[MLKEM_N], const int16_t a[4 * MLKEM_N],+ const int16_t b[4 * MLKEM_N], const int16_t b_cache[4 * (MLKEM_N / 2)])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ mlk_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm(r, a, b, b_cache);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4 */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API) || !defined(MLK_CONFIG_NO_ENCAPS_API)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_tobytes_native(uint8_t r[MLKEM_POLYBYTES],+ const int16_t a[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ mlk_poly_tobytes_aarch64_asm(r, a);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API || !MLK_CONFIG_NO_ENCAPS_API */++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_rej_uniform_native(int16_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_AARCH64_NEON) || len != MLKEM_N ||+ buflen % 24 != 0)+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ return (int)mlk_rej_uniform_aarch64_asm(r, buf, buflen,+ mlk_rej_uniform_table);+}+#endif /* !__ASSEMBLER__ */++#endif /* !MLK_NATIVE_AARCH64_META_H */
@@ -0,0 +1,184 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_AARCH64) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#include "arith_native_aarch64.h"++/*+ * Table of zeta values used in the AArch64 forward NTT+ * See autogen for details.+ */+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const int16_t+ mlk_aarch64_ntt_zetas_layer12345[80] = {+ -1600, -15749, -749, -7373, -40, -394, -687, -6762, 630, 6201,+ -1432, -14095, 848, 8347, 0, 0, 1062, 10453, 296, 2914,+ -882, -8682, 0, 0, -1410, -13879, 1339, 13180, 1476, 14529,+ 0, 0, 193, 1900, -283, -2786, 56, 551, 0, 0,+ 797, 7845, -1089, -10719, 1333, 13121, 0, 0, -543, -5345,+ 1426, 14036, -1235, -12156, 0, 0, -69, -679, 535, 5266,+ -447, -4400, 0, 0, 569, 5601, -936, -9213, -450, -4429,+ 0, 0, -1583, -15582, -1355, -13338, 821, 8081, 0, 0,+};++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const int16_t+ mlk_aarch64_ntt_zetas_layer67[384] = {+ 289, 289, 331, 331, -76, -76, -1573, -1573, 2845,+ 2845, 3258, 3258, -748, -748, -15483, -15483, 17, 17,+ 583, 583, 1637, 1637, -1041, -1041, 167, 167, 5739,+ 5739, 16113, 16113, -10247, -10247, -568, -568, -680, -680,+ 723, 723, 1100, 1100, -5591, -5591, -6693, -6693, 7117,+ 7117, 10828, 10828, 1197, 1197, -1025, -1025, -1052, -1052,+ -1274, -1274, 11782, 11782, -10089, -10089, -10355, -10355, -12540,+ -12540, 1409, 1409, -48, -48, 756, 756, -314, -314,+ 13869, 13869, -472, -472, 7441, 7441, -3091, -3091, -667,+ -667, 233, 233, -1173, -1173, -279, -279, -6565, -6565,+ 2293, 2293, -11546, -11546, -2746, -2746, 650, 650, -1352,+ -1352, -816, -816, 632, 632, 6398, 6398, -13308, -13308,+ -8032, -8032, 6221, 6221, -1626, -1626, -540, -540, -1482,+ -1482, 1461, 1461, -16005, -16005, -5315, -5315, -14588, -14588,+ 14381, 14381, 1651, 1651, -1540, -1540, 952, 952, -642,+ -642, 16251, 16251, -15159, -15159, 9371, 9371, -6319, -6319,+ -464, -464, 33, 33, 1320, 1320, -1414, -1414, -4567,+ -4567, 325, 325, 12993, 12993, -13918, -13918, 939, 939,+ -892, -892, 733, 733, 268, 268, 9243, 9243, -8780,+ -8780, 7215, 7215, 2638, 2638, -1021, -1021, -941, -941,+ -992, -992, 641, 641, -10050, -10050, -9262, -9262, -9764,+ -9764, 6309, 6309, -1010, -1010, 1435, 1435, 807, 807,+ 452, 452, -9942, -9942, 14125, 14125, 7943, 7943, 4449,+ 4449, 1584, 1584, -1292, -1292, 375, 375, -1239, -1239,+ 15592, 15592, -12717, -12717, 3691, 3691, -12196, -12196, -1031,+ -1031, -109, -109, -780, -780, 1645, 1645, -10148, -10148,+ -1073, -1073, -7678, -7678, 16192, 16192, 1438, 1438, -461,+ -461, 1534, 1534, -927, -927, 14155, 14155, -4538, -4538,+ 15099, 15099, -9125, -9125, 1063, 1063, -556, -556, -1230,+ -1230, -863, -863, 10463, 10463, -5473, -5473, -12107, -12107,+ -8495, -8495, 319, 319, 757, 757, 561, 561, -735,+ -735, 3140, 3140, 7451, 7451, 5522, 5522, -7235, -7235,+ -682, -682, -712, -712, 1481, 1481, 648, 648, -6713,+ -6713, -7008, -7008, 14578, 14578, 6378, 6378, -525, -525,+ 403, 403, 1143, 1143, -554, -554, -5168, -5168, 3967,+ 3967, 11251, 11251, -5453, -5453, 1092, 1092, 1026, 1026,+ -1179, -1179, 886, 886, 10749, 10749, 10099, 10099, -11605,+ -11605, 8721, 8721, -855, -855, -219, -219, 1227, 1227,+ 910, 910, -8416, -8416, -2156, -2156, 12078, 12078, 8957,+ 8957, -1607, -1607, -1455, -1455, -1219, -1219, 885, 885,+ -15818, -15818, -14322, -14322, -11999, -11999, 8711, 8711, 1212,+ 1212, 1029, 1029, -394, -394, -1175, -1175, 11930, 11930,+ 10129, 10129, -3878, -3878, -11566, -11566,+};++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const int16_t+ mlk_aarch64_invntt_zetas_layer12345[80] = {+ 1583, 15582, -821, -8081, 1355, 13338, 0, 0, -569,+ -5601, 450, 4429, 936, 9213, 0, 0, 69, 679,+ 447, 4400, -535, -5266, 0, 0, 543, 5345, 1235,+ 12156, -1426, -14036, 0, 0, -797, -7845, -1333, -13121,+ 1089, 10719, 0, 0, -193, -1900, -56, -551, 283,+ 2786, 0, 0, 1410, 13879, -1476, -14529, -1339, -13180,+ 0, 0, -1062, -10453, 882, 8682, -296, -2914, 0,+ 0, 1600, 15749, 40, 394, 749, 7373, -848, -8347,+ 1432, 14095, -630, -6201, 687, 6762, 0, 0,+};++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const int16_t+ mlk_aarch64_invntt_zetas_layer67[384] = {+ -910, -910, -1227, -1227, 219, 219, 855, 855, -8957,+ -8957, -12078, -12078, 2156, 2156, 8416, 8416, 1175, 1175,+ 394, 394, -1029, -1029, -1212, -1212, 11566, 11566, 3878,+ 3878, -10129, -10129, -11930, -11930, -885, -885, 1219, 1219,+ 1455, 1455, 1607, 1607, -8711, -8711, 11999, 11999, 14322,+ 14322, 15818, 15818, -648, -648, -1481, -1481, 712, 712,+ 682, 682, -6378, -6378, -14578, -14578, 7008, 7008, 6713,+ 6713, -886, -886, 1179, 1179, -1026, -1026, -1092, -1092,+ -8721, -8721, 11605, 11605, -10099, -10099, -10749, -10749, 554,+ 554, -1143, -1143, -403, -403, 525, 525, 5453, 5453,+ -11251, -11251, -3967, -3967, 5168, 5168, 927, 927, -1534,+ -1534, 461, 461, -1438, -1438, 9125, 9125, -15099, -15099,+ 4538, 4538, -14155, -14155, 735, 735, -561, -561, -757,+ -757, -319, -319, 7235, 7235, -5522, -5522, -7451, -7451,+ -3140, -3140, 863, 863, 1230, 1230, 556, 556, -1063,+ -1063, 8495, 8495, 12107, 12107, 5473, 5473, -10463, -10463,+ -452, -452, -807, -807, -1435, -1435, 1010, 1010, -4449,+ -4449, -7943, -7943, -14125, -14125, 9942, 9942, -1645, -1645,+ 780, 780, 109, 109, 1031, 1031, -16192, -16192, 7678,+ 7678, 1073, 1073, 10148, 10148, 1239, 1239, -375, -375,+ 1292, 1292, -1584, -1584, 12196, 12196, -3691, -3691, 12717,+ 12717, -15592, -15592, 1414, 1414, -1320, -1320, -33, -33,+ 464, 464, 13918, 13918, -12993, -12993, -325, -325, 4567,+ 4567, -641, -641, 992, 992, 941, 941, 1021, 1021,+ -6309, -6309, 9764, 9764, 9262, 9262, 10050, 10050, -268,+ -268, -733, -733, 892, 892, -939, -939, -2638, -2638,+ -7215, -7215, 8780, 8780, -9243, -9243, -632, -632, 816,+ 816, 1352, 1352, -650, -650, -6221, -6221, 8032, 8032,+ 13308, 13308, -6398, -6398, 642, 642, -952, -952, 1540,+ 1540, -1651, -1651, 6319, 6319, -9371, -9371, 15159, 15159,+ -16251, -16251, -1461, -1461, 1482, 1482, 540, 540, 1626,+ 1626, -14381, -14381, 14588, 14588, 5315, 5315, 16005, 16005,+ 1274, 1274, 1052, 1052, 1025, 1025, -1197, -1197, 12540,+ 12540, 10355, 10355, 10089, 10089, -11782, -11782, 279, 279,+ 1173, 1173, -233, -233, 667, 667, 2746, 2746, 11546,+ 11546, -2293, -2293, 6565, 6565, 314, 314, -756, -756,+ 48, 48, -1409, -1409, 3091, 3091, -7441, -7441, 472,+ 472, -13869, -13869, 1573, 1573, 76, 76, -331, -331,+ -289, -289, 15483, 15483, 748, 748, -3258, -3258, -2845,+ -2845, -1100, -1100, -723, -723, 680, 680, 568, 568,+ -10828, -10828, -7117, -7117, 6693, 6693, 5591, 5591, 1041,+ 1041, -1637, -1637, -583, -583, -17, -17, 10247, 10247,+ -16113, -16113, -5739, -5739, -167, -167,+};+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const int16_t+ mlk_aarch64_zetas_mulcache_native[128] = {+ 17, -17, -568, 568, 583, -583, -680, 680, 1637, -1637,+ 723, -723, -1041, 1041, 1100, -1100, 1409, -1409, -667, 667,+ -48, 48, 233, -233, 756, -756, -1173, 1173, -314, 314,+ -279, 279, -1626, 1626, 1651, -1651, -540, 540, -1540, 1540,+ -1482, 1482, 952, -952, 1461, -1461, -642, 642, 939, -939,+ -1021, 1021, -892, 892, -941, 941, 733, -733, -992, 992,+ 268, -268, 641, -641, 1584, -1584, -1031, 1031, -1292, 1292,+ -109, 109, 375, -375, -780, 780, -1239, 1239, 1645, -1645,+ 1063, -1063, 319, -319, -556, 556, 757, -757, -1230, 1230,+ 561, -561, -863, 863, -735, 735, -525, 525, 1092, -1092,+ 403, -403, 1026, -1026, 1143, -1143, -1179, 1179, -554, 554,+ 886, -886, -1607, 1607, 1212, -1212, -1455, 1455, 1029, -1029,+ -1219, 1219, -394, 394, 885, -885, -1175, 1175,+};++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const int16_t+ mlk_aarch64_zetas_mulcache_twisted_native[128] = {+ 167, -167, -5591, 5591, 5739, -5739, -6693, 6693, 16113,+ -16113, 7117, -7117, -10247, 10247, 10828, -10828, 13869, -13869,+ -6565, 6565, -472, 472, 2293, -2293, 7441, -7441, -11546,+ 11546, -3091, 3091, -2746, 2746, -16005, 16005, 16251, -16251,+ -5315, 5315, -15159, 15159, -14588, 14588, 9371, -9371, 14381,+ -14381, -6319, 6319, 9243, -9243, -10050, 10050, -8780, 8780,+ -9262, 9262, 7215, -7215, -9764, 9764, 2638, -2638, 6309,+ -6309, 15592, -15592, -10148, 10148, -12717, 12717, -1073, 1073,+ 3691, -3691, -7678, 7678, -12196, 12196, 16192, -16192, 10463,+ -10463, 3140, -3140, -5473, 5473, 7451, -7451, -12107, 12107,+ 5522, -5522, -8495, 8495, -7235, 7235, -5168, 5168, 10749,+ -10749, 3967, -3967, 10099, -10099, 11251, -11251, -11605, 11605,+ -5453, 5453, 8721, -8721, -15818, 15818, 11930, -11930, -14322,+ 14322, 10129, -10129, -11999, 11999, -3878, 3878, 8711, -8711,+ -11566, 11566,+};++#else /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(aarch64_zetas)++#endif /* !(MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,184 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H+#define MLK_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H++#include "../../../cbmc.h"+#include "../../../common.h"++#define mlk_aarch64_ntt_zetas_layer12345 \+ MLK_NAMESPACE(aarch64_ntt_zetas_layer12345)+#define mlk_aarch64_ntt_zetas_layer67 MLK_NAMESPACE(aarch64_ntt_zetas_layer67)+#define mlk_aarch64_invntt_zetas_layer12345 \+ MLK_NAMESPACE(aarch64_invntt_zetas_layer12345)+#define mlk_aarch64_invntt_zetas_layer67 \+ MLK_NAMESPACE(aarch64_invntt_zetas_layer67)+#define mlk_aarch64_zetas_mulcache_native \+ MLK_NAMESPACE(aarch64_zetas_mulcache_native)+#define mlk_aarch64_zetas_mulcache_twisted_native \+ MLK_NAMESPACE(aarch64_zetas_mulcache_twisted_native)+#define mlk_rej_uniform_table MLK_NAMESPACE(rej_uniform_table)++MLK_INTERNAL_DATA_DECLARATION const int16_t+ mlk_aarch64_ntt_zetas_layer12345[80];+MLK_INTERNAL_DATA_DECLARATION const int16_t mlk_aarch64_ntt_zetas_layer67[384];+MLK_INTERNAL_DATA_DECLARATION const int16_t+ mlk_aarch64_invntt_zetas_layer12345[80];+MLK_INTERNAL_DATA_DECLARATION const int16_t+ mlk_aarch64_invntt_zetas_layer67[384];+MLK_INTERNAL_DATA_DECLARATION const int16_t+ mlk_aarch64_zetas_mulcache_native[128];+MLK_INTERNAL_DATA_DECLARATION const int16_t+ mlk_aarch64_zetas_mulcache_twisted_native[128];+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_rej_uniform_table[4096];++#define mlk_ntt_aarch64_asm MLK_NAMESPACE(ntt_aarch64_asm)+void mlk_ntt_aarch64_asm(int16_t p[256], const int16_t twiddles12345[80],+ const int16_t twiddles56[384])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mlkem_ntt_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(p, sizeof(int16_t) * MLKEM_N))+ requires(array_abs_bound(p, 0, MLKEM_N, 8192))+ requires(twiddles12345 == mlk_aarch64_ntt_zetas_layer12345)+ requires(twiddles56 == mlk_aarch64_ntt_zetas_layer67)+ assigns(memory_slice(p, sizeof(int16_t) * MLKEM_N))+ /* check-magic: off */+ ensures(array_abs_bound(p, 0, MLKEM_N, 23595))+ /* check-magic: on */+);++#define mlk_intt_aarch64_asm MLK_NAMESPACE(intt_aarch64_asm)+void mlk_intt_aarch64_asm(int16_t p[256], const int16_t twiddles12345[80],+ const int16_t twiddles56[384])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mlkem_intt_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(p, sizeof(int16_t) * MLKEM_N))+ requires(twiddles12345 == mlk_aarch64_invntt_zetas_layer12345)+ requires(twiddles56 == mlk_aarch64_invntt_zetas_layer67)+ assigns(memory_slice(p, sizeof(int16_t) * MLKEM_N))+ /* check-magic: off */+ ensures(array_abs_bound(p, 0, MLKEM_N, 26625))+ /* check-magic: on */+);++#define mlk_poly_reduce_aarch64_asm MLK_NAMESPACE(poly_reduce_aarch64_asm)+void mlk_poly_reduce_aarch64_asm(int16_t p[256])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mlkem_poly_reduce_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(p, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(p, sizeof(int16_t) * MLKEM_N))+ ensures(array_bound(p, 0, MLKEM_N, 0, MLKEM_Q))+);++#define mlk_poly_tomont_aarch64_asm MLK_NAMESPACE(poly_tomont_aarch64_asm)+void mlk_poly_tomont_aarch64_asm(int16_t p[256])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mlkem_poly_tomont_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(p, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(p, sizeof(int16_t) * MLKEM_N))+ ensures(array_abs_bound(p, 0, MLKEM_N, MLKEM_Q))+);++#define mlk_poly_mulcache_compute_aarch64_asm \+ MLK_NAMESPACE(poly_mulcache_compute_aarch64_asm)+void mlk_poly_mulcache_compute_aarch64_asm(int16_t cache[128],+ const int16_t mlk_poly[256],+ const int16_t zetas[128],+ const int16_t zetas_twisted[128])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mlkem_poly_mulcache_compute_aarch64_asm.ml+ */+__contract__(+ requires(memory_no_alias(cache, sizeof(int16_t) * (MLKEM_N / 2)))+ requires(memory_no_alias(mlk_poly, sizeof(int16_t) * MLKEM_N))+ requires(zetas == mlk_aarch64_zetas_mulcache_native)+ requires(zetas_twisted == mlk_aarch64_zetas_mulcache_twisted_native)+ assigns(memory_slice(cache, sizeof(int16_t) * (MLKEM_N / 2)))+ ensures(array_abs_bound(cache, 0, MLKEM_N/2, MLKEM_Q))+);++#define mlk_poly_tobytes_aarch64_asm MLK_NAMESPACE(poly_tobytes_aarch64_asm)+void mlk_poly_tobytes_aarch64_asm(uint8_t r[384], const int16_t a[256])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mlkem_poly_tobytes_aarch64_asm.ml */+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYBYTES))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT))+ assigns(memory_slice(r, MLKEM_POLYBYTES))+);++#define mlk_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm \+ MLK_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm)+void mlk_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm(+ int16_t r[256], const int16_t a[512], const int16_t b[512],+ const int16_t b_cache[256])+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/aarch64/proofs/mlkem_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, sizeof(int16_t) * 2 * MLKEM_N))+ requires(memory_no_alias(b, sizeof(int16_t) * 2 * MLKEM_N))+ requires(memory_no_alias(b_cache, sizeof(int16_t) * 2 * (MLKEM_N / 2)))+ requires(array_abs_bound(a, 0, 2 * MLKEM_N, MLKEM_UINT12_LIMIT + 1))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+);++#define mlk_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm \+ MLK_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm)+void mlk_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm(+ int16_t r[256], const int16_t a[768], const int16_t b[768],+ const int16_t b_cache[384])+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/aarch64/proofs/mlkem_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, sizeof(int16_t) * 3 * MLKEM_N))+ requires(memory_no_alias(b, sizeof(int16_t) * 3 * MLKEM_N))+ requires(memory_no_alias(b_cache, sizeof(int16_t) * 3 * (MLKEM_N / 2)))+ requires(array_abs_bound(a, 0, 3 * MLKEM_N, MLKEM_UINT12_LIMIT + 1))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+);++#define mlk_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm \+ MLK_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm)+void mlk_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm(+ int16_t r[256], const int16_t a[1024], const int16_t b[1024],+ const int16_t b_cache[512])+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/aarch64/proofs/mlkem_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, sizeof(int16_t) * 4 * MLKEM_N))+ requires(memory_no_alias(b, sizeof(int16_t) * 4 * MLKEM_N))+ requires(memory_no_alias(b_cache, sizeof(int16_t) * 4 * (MLKEM_N / 2)))+ requires(array_abs_bound(a, 0, 4 * MLKEM_N, MLKEM_UINT12_LIMIT + 1))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+);++#define mlk_rej_uniform_aarch64_asm MLK_NAMESPACE(rej_uniform_aarch64_asm)+MLK_MUST_CHECK_RETURN_VALUE+uint64_t mlk_rej_uniform_aarch64_asm(int16_t r[256], const uint8_t *buf,+ unsigned buflen, const uint8_t table[4096])+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/aarch64/proofs/mlkem_rej_uniform_aarch64_asm.ml. */+__contract__(+ requires(buflen % 24 == 0)+ requires(memory_no_alias(buf, buflen))+ requires(table == mlk_rej_uniform_table)+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(return_value <= MLKEM_N)+ ensures(array_bound(r, 0, (unsigned) return_value, 0, MLKEM_Q))+);++#endif /* !MLK_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */
@@ -0,0 +1,635 @@+/* Copyright (c) 2022 Arm Limited+ * Copyright (c) 2022 Hanno Becker+ * Copyright (c) 2023 Amin Abdulrahman, Matthias Kannwischer+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [NeonNTT]+ * Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1+ * Becker, Hwang, Kannwischer, Yang, Yang+ * https://eprint.iacr.org/2021/986+ *+ * - [SLOTHY_Paper]+ * Fast and Clean: Auditable high-performance assembly via constraint solving+ * Abdulrahman, Becker, Kannwischer, Klein+ * https://eprint.iacr.org/2022/1303+ */++/*yaml+ Name: intt_aarch64_asm+ Description: AArch64 ML-KEM inverse NTT following @[NeonNTT] and @[SLOTHY_Paper]+ Signature: void mlk_intt_aarch64_asm(int16_t p[256], const int16_t twiddles12345[80], const int16_t twiddles56[384])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t p[256]+ description: Input/output polynomial+ x1:+ type: buffer+ size_bytes: 160+ permissions: read-only+ c_parameter: const int16_t twiddles12345[80]+ description: Twiddle factors for layers 1-5+ x2:+ type: buffer+ size_bytes: 768+ permissions: read-only+ c_parameter: const int16_t twiddles56[384]+ description: Twiddle factors for layers 6-7+ Stack:+ bytes: 64+ description: saving callee-saved Neon registers+*/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API))++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_intt_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(intt_aarch64_asm)+MLK_ASM_FN_SYMBOL(intt_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ mov w5, #0xd01 // =3329+ mov v7.h[0], w5+ mov w5, #0x4ebf // =20159+ mov v7.h[1], w5+ mov w5, #0x200 // =512+ dup v29.8h, w5+ mov w5, #0x13b0 // =5040+ dup v30.8h, w5+ mov x3, x0+ mov x4, #0x8 // =8+ ldr q13, [x3, #0x20]+ ldr q8, [x3, #0x30]+ ldr q6, [x3]+ ldr q16, [x3, #0x10]+ ldr q4, [x3, #0x50]+ ldr q11, [x3, #0x40]+ ldr q3, [x3, #0x70]+ trn1 v23.4s, v13.4s, v8.4s+ ldr q0, [x3, #0x60]+ trn2 v19.4s, v6.4s, v16.4s+ trn2 v21.4s, v13.4s, v8.4s+ trn1 v6.4s, v6.4s, v16.4s+ ldr q24, [x2, #0x20]+ trn1 v10.2d, v19.2d, v21.2d+ ldr q16, [x2], #0x60+ trn1 v5.2d, v6.2d, v23.2d+ trn1 v28.4s, v0.4s, v3.4s+ trn2 v18.2d, v6.2d, v23.2d+ mul v31.8h, v10.8h, v29.8h+ trn2 v13.4s, v0.4s, v3.4s+ ldur q14, [x2, #-0x50]+ sqrdmulh v26.8h, v18.8h, v30.8h+ ldur q20, [x2, #-0x20]+ mul v17.8h, v18.8h, v29.8h+ trn2 v18.2d, v19.2d, v21.2d+ mul v9.8h, v18.8h, v29.8h+ trn1 v12.4s, v11.4s, v4.4s+ sqrdmulh v22.8h, v18.8h, v30.8h+ sqrdmulh v3.8h, v10.8h, v30.8h+ sqrdmulh v25.8h, v5.8h, v30.8h+ mls v9.8h, v22.8h, v7.h[0]+ mls v17.8h, v26.8h, v7.h[0]+ trn2 v26.4s, v11.4s, v4.4s+ mul v8.8h, v5.8h, v29.8h+ trn1 v10.2d, v26.2d, v13.2d+ ldur q11, [x2, #-0x10]+ mls v31.8h, v3.8h, v7.h[0]+ trn1 v6.2d, v12.2d, v28.2d+ trn2 v3.2d, v26.2d, v13.2d+ ldur q4, [x2, #-0x30]+ mls v8.8h, v25.8h, v7.h[0]+ sub v19.8h, v17.8h, v9.8h+ trn2 v13.2d, v12.2d, v28.2d+ sqrdmulh v1.8h, v3.8h, v30.8h+ add v9.8h, v17.8h, v9.8h+ mul v18.8h, v19.8h, v20.8h+ add v28.8h, v8.8h, v31.8h+ sqrdmulh v20.8h, v19.8h, v11.8h+ sub v12.8h, v28.8h, v9.8h+ sub v23.8h, v8.8h, v31.8h+ sqrdmulh v11.8h, v13.8h, v30.8h+ sqrdmulh v5.8h, v23.8h, v4.8h+ mul v0.8h, v23.8h, v24.8h+ mul v2.8h, v13.8h, v29.8h+ mls v0.8h, v5.8h, v7.h[0]+ add v24.8h, v28.8h, v9.8h+ mls v18.8h, v20.8h, v7.h[0]+ sqrdmulh v15.8h, v6.8h, v30.8h+ sqrdmulh v25.8h, v12.8h, v14.8h+ mul v21.8h, v12.8h, v16.8h+ sub v23.8h, v0.8h, v18.8h+ sqrdmulh v8.8h, v23.8h, v14.8h+ mul v23.8h, v23.8h, v16.8h+ mls v21.8h, v25.8h, v7.h[0]+ mls v23.8h, v8.8h, v7.h[0]+ mul v14.8h, v3.8h, v29.8h+ add v3.8h, v0.8h, v18.8h+ trn2 v4.4s, v24.4s, v3.4s+ mls v14.8h, v1.8h, v7.h[0]+ trn1 v9.4s, v24.4s, v3.4s+ trn2 v12.4s, v21.4s, v23.4s+ mls v2.8h, v11.8h, v7.h[0]+ trn1 v28.4s, v21.4s, v23.4s+ ldr q11, [x1], #0x10+ mul v31.8h, v10.8h, v29.8h+ trn1 v25.2d, v4.2d, v12.2d+ trn1 v20.2d, v9.2d, v28.2d+ ldr q23, [x2, #0x50]+ trn2 v13.2d, v4.2d, v12.2d+ sqrdmulh v21.8h, v10.8h, v30.8h+ trn2 v4.2d, v9.2d, v28.2d+ ldr q9, [x2, #0x40]+ mul v27.8h, v6.8h, v29.8h+ add v26.8h, v20.8h, v25.8h+ sub v3.8h, v2.8h, v14.8h+ sqdmulh v12.8h, v26.8h, v7.h[1]+ add v5.8h, v4.8h, v13.8h+ sub v8.8h, v4.8h, v13.8h+ add v10.8h, v2.8h, v14.8h+ sqdmulh v6.8h, v5.8h, v7.h[1]+ ldr q2, [x2, #0x10]+ mls v27.8h, v15.8h, v7.h[0]+ ldr q15, [x2, #0x20]+ srshr v12.8h, v12.8h, #0xb+ mls v31.8h, v21.8h, v7.h[0]+ srshr v6.8h, v6.8h, #0xb+ sqrdmulh v23.8h, v3.8h, v23.8h+ mls v26.8h, v12.8h, v7.h[0]+ add v21.8h, v27.8h, v31.8h+ mls v5.8h, v6.8h, v7.h[0]+ sub v6.8h, v27.8h, v31.8h+ sub v14.8h, v21.8h, v10.8h+ ldr q27, [x2], #0x60+ mul v3.8h, v3.8h, v9.8h+ mls v3.8h, v23.8h, v7.h[0]+ ldur q13, [x2, #-0x30]+ sub v12.8h, v26.8h, v5.8h+ add v5.8h, v26.8h, v5.8h+ sqrdmulh v31.8h, v8.8h, v11.h[5]+ sqrdmulh v19.8h, v12.8h, v11.h[1]+ mul v24.8h, v12.8h, v11.h[0]+ sqrdmulh v13.8h, v6.8h, v13.8h+ mls v24.8h, v19.8h, v7.h[0]+ sub x4, x4, #0x2++Lmlk_intt_layer4567_start:+ add v16.8h, v21.8h, v10.8h+ mul v18.8h, v6.8h, v15.8h+ sub v19.8h, v20.8h, v25.8h+ ldr q21, [x3, #0xa0]+ str q5, [x3], #0x40+ mls v18.8h, v13.8h, v7.h[0]+ sqrdmulh v15.8h, v14.8h, v2.8h+ ldr q10, [x3, #0x50]+ ldr q12, [x3, #0x40]+ stur q24, [x3, #-0x20]+ mul v5.8h, v8.8h, v11.h[4]+ sub v0.8h, v18.8h, v3.8h+ ldr q24, [x3, #0x70]+ mls v5.8h, v31.8h, v7.h[0]+ ldr q26, [x2, #0x50]+ trn2 v1.4s, v12.4s, v10.4s+ add v6.8h, v18.8h, v3.8h+ sqrdmulh v20.8h, v0.8h, v2.8h+ trn1 v13.4s, v12.4s, v10.4s+ trn1 v18.4s, v16.4s, v6.4s+ mul v22.8h, v0.8h, v27.8h+ trn1 v17.4s, v21.4s, v24.4s+ sqrdmulh v0.8h, v19.8h, v11.h[3]+ trn1 v25.2d, v13.2d, v17.2d+ mls v22.8h, v20.8h, v7.h[0]+ trn2 v21.4s, v21.4s, v24.4s+ mul v24.8h, v25.8h, v29.8h+ trn2 v28.2d, v13.2d, v17.2d+ sqrdmulh v4.8h, v25.8h, v30.8h+ trn2 v3.2d, v1.2d, v21.2d+ mul v17.8h, v28.8h, v29.8h+ sqrdmulh v31.8h, v28.8h, v30.8h+ ldr q2, [x2, #0x10]+ mls v24.8h, v4.8h, v7.h[0]+ mul v4.8h, v19.8h, v11.h[2]+ ldr q19, [x2, #0x40]+ mls v4.8h, v0.8h, v7.h[0]+ mul v0.8h, v14.8h, v27.8h+ mls v0.8h, v15.8h, v7.h[0]+ sub v8.8h, v4.8h, v5.8h+ mul v12.8h, v3.8h, v29.8h+ mul v23.8h, v8.8h, v11.h[0]+ trn2 v28.4s, v16.4s, v6.4s+ sqrdmulh v10.8h, v8.8h, v11.h[1]+ trn1 v9.4s, v0.4s, v22.4s+ trn2 v22.4s, v0.4s, v22.4s+ ldr q11, [x1], #0x10+ mls v17.8h, v31.8h, v7.h[0]+ trn1 v20.2d, v18.2d, v9.2d+ trn2 v14.2d, v18.2d, v9.2d+ ldr q15, [x2, #0x20]+ trn1 v6.2d, v1.2d, v21.2d+ sqrdmulh v9.8h, v3.8h, v30.8h+ trn1 v25.2d, v28.2d, v22.2d+ trn2 v16.2d, v28.2d, v22.2d+ mls v23.8h, v10.8h, v7.h[0]+ add v1.8h, v20.8h, v25.8h+ sqrdmulh v21.8h, v6.8h, v30.8h+ add v8.8h, v14.8h, v16.8h+ ldr q27, [x2], #0x60+ sqdmulh v28.8h, v8.8h, v7.h[1]+ mls v12.8h, v9.8h, v7.h[0]+ sqdmulh v31.8h, v1.8h, v7.h[1]+ mul v0.8h, v6.8h, v29.8h+ sub v10.8h, v17.8h, v12.8h+ mls v0.8h, v21.8h, v7.h[0]+ srshr v21.8h, v28.8h, #0xb+ srshr v13.8h, v31.8h, #0xb+ sqrdmulh v22.8h, v10.8h, v26.8h+ mls v8.8h, v21.8h, v7.h[0]+ mls v1.8h, v13.8h, v7.h[0]+ add v21.8h, v24.8h, v0.8h+ stur q23, [x3, #-0x10]+ sub v6.8h, v24.8h, v0.8h+ mul v3.8h, v10.8h, v19.8h+ add v0.8h, v4.8h, v5.8h+ sqdmulh v13.8h, v0.8h, v7.h[1]+ ldur q10, [x2, #-0x30]+ add v5.8h, v1.8h, v8.8h+ mls v3.8h, v22.8h, v7.h[0]+ sub v8.8h, v1.8h, v8.8h+ mul v24.8h, v8.8h, v11.h[0]+ sqrdmulh v8.8h, v8.8h, v11.h[1]+ srshr v1.8h, v13.8h, #0xb+ sqrdmulh v13.8h, v6.8h, v10.8h+ mls v0.8h, v1.8h, v7.h[0]+ add v10.8h, v17.8h, v12.8h+ mls v24.8h, v8.8h, v7.h[0]+ sub v8.8h, v14.8h, v16.8h+ sqrdmulh v31.8h, v8.8h, v11.h[5]+ sub v14.8h, v21.8h, v10.8h+ stur q0, [x3, #-0x30]+ sub x4, x4, #0x1+ cbnz x4, Lmlk_intt_layer4567_start+ mul v15.8h, v6.8h, v15.8h+ sub v22.8h, v20.8h, v25.8h+ add v4.8h, v21.8h, v10.8h+ str q24, [x3, #0x20]+ mls v15.8h, v13.8h, v7.h[0]+ str q5, [x3], #0x40+ ldr q9, [x1], #0x10+ sqrdmulh v28.8h, v14.8h, v2.8h+ mul v16.8h, v14.8h, v27.8h+ sub v18.8h, v15.8h, v3.8h+ add v15.8h, v15.8h, v3.8h+ sqrdmulh v0.8h, v18.8h, v2.8h+ trn2 v24.4s, v4.4s, v15.4s+ trn1 v2.4s, v4.4s, v15.4s+ mul v18.8h, v18.8h, v27.8h+ mls v16.8h, v28.8h, v7.h[0]+ mls v18.8h, v0.8h, v7.h[0]+ mul v23.8h, v8.8h, v11.h[4]+ sqrdmulh v12.8h, v22.8h, v11.h[3]+ trn1 v17.4s, v16.4s, v18.4s+ trn2 v4.4s, v16.4s, v18.4s+ mls v23.8h, v31.8h, v7.h[0]+ trn2 v3.2d, v2.2d, v17.2d+ trn2 v6.2d, v24.2d, v4.2d+ mul v26.8h, v22.8h, v11.h[2]+ trn1 v28.2d, v2.2d, v17.2d+ mls v26.8h, v12.8h, v7.h[0]+ add v25.8h, v3.8h, v6.8h+ sub v18.8h, v3.8h, v6.8h+ trn1 v24.2d, v24.2d, v4.2d+ sqdmulh v1.8h, v25.8h, v7.h[1]+ sub v27.8h, v28.8h, v24.8h+ sqrdmulh v2.8h, v18.8h, v9.h[5]+ add v28.8h, v28.8h, v24.8h+ mul v24.8h, v27.8h, v9.h[2]+ sqdmulh v12.8h, v28.8h, v7.h[1]+ mul v20.8h, v18.8h, v9.h[4]+ mls v20.8h, v2.8h, v7.h[0]+ srshr v1.8h, v1.8h, #0xb+ sqrdmulh v19.8h, v27.8h, v9.h[3]+ srshr v15.8h, v12.8h, #0xb+ mls v25.8h, v1.8h, v7.h[0]+ add v8.8h, v26.8h, v23.8h+ sub v4.8h, v26.8h, v23.8h+ mls v28.8h, v15.8h, v7.h[0]+ mls v24.8h, v19.8h, v7.h[0]+ mul v2.8h, v4.8h, v11.h[0]+ sub v19.8h, v28.8h, v25.8h+ sqrdmulh v15.8h, v4.8h, v11.h[1]+ add v25.8h, v28.8h, v25.8h+ sub v10.8h, v24.8h, v20.8h+ str q25, [x3], #0x40+ sqrdmulh v22.8h, v19.8h, v9.h[1]+ add v28.8h, v24.8h, v20.8h+ sqrdmulh v25.8h, v10.8h, v9.h[1]+ mul v27.8h, v19.8h, v9.h[0]+ mul v26.8h, v10.8h, v9.h[0]+ sqdmulh v20.8h, v28.8h, v7.h[1]+ sqdmulh v16.8h, v8.8h, v7.h[1]+ mls v26.8h, v25.8h, v7.h[0]+ mls v2.8h, v15.8h, v7.h[0]+ srshr v15.8h, v20.8h, #0xb+ srshr v1.8h, v16.8h, #0xb+ mls v27.8h, v22.8h, v7.h[0]+ mls v28.8h, v15.8h, v7.h[0]+ mls v8.8h, v1.8h, v7.h[0]+ stur q27, [x3, #-0x20]+ stur q2, [x3, #-0x50]+ stur q28, [x3, #-0x30]+ stur q26, [x3, #-0x10]+ stur q8, [x3, #-0x70]+ mov x4, #0x4 // =4+ ldr q0, [x1], #0x20+ ldur q1, [x1, #-0x10]+ ldr q26, [x0]+ ldr q13, [x0, #0x40]+ ldr q28, [x0, #0xc0]+ ldr q2, [x0, #0x140]+ ldr q6, [x0, #0x80]+ ldr q9, [x0, #0x100]+ ldr q29, [x0, #0x1c0]+ ldr q23, [x0, #0x180]+ sub v17.8h, v26.8h, v13.8h+ add v4.8h, v26.8h, v13.8h+ ldr q25, [x0, #0xd0]+ ldr q24, [x0, #0x50]+ add v5.8h, v6.8h, v28.8h+ mul v19.8h, v17.8h, v0.h[6]+ sub v10.8h, v6.8h, v28.8h+ ldr q30, [x0, #0x150]+ sqrdmulh v12.8h, v17.8h, v0.h[7]+ add v17.8h, v9.8h, v2.8h+ sub v28.8h, v9.8h, v2.8h+ ldr q2, [x0, #0x90]+ sub v26.8h, v23.8h, v29.8h+ sqrdmulh v31.8h, v10.8h, v1.h[1]+ add v22.8h, v23.8h, v29.8h+ ldr q3, [x0, #0x110]+ sqrdmulh v9.8h, v28.8h, v1.h[3]+ sub v20.8h, v4.8h, v5.8h+ sub v27.8h, v17.8h, v22.8h+ ldr q29, [x0, #0x10]+ add v16.8h, v4.8h, v5.8h+ sqrdmulh v4.8h, v26.8h, v1.h[5]+ add v6.8h, v17.8h, v22.8h+ ldr q22, [x0, #0x1d0]+ mul v8.8h, v28.8h, v1.h[2]+ sub v21.8h, v2.8h, v25.8h+ sub v5.8h, v16.8h, v6.8h+ mul v17.8h, v26.8h, v1.h[4]+ mul v26.8h, v10.8h, v1.h[0]+ mls v26.8h, v31.8h, v7.h[0]+ mls v17.8h, v4.8h, v7.h[0]+ mls v19.8h, v12.8h, v7.h[0]+ mls v8.8h, v9.8h, v7.h[0]+ sqrdmulh v10.8h, v27.8h, v0.h[5]+ sub v12.8h, v19.8h, v26.8h+ add v9.8h, v19.8h, v26.8h+ sqrdmulh v26.8h, v20.8h, v0.h[3]+ sub v11.8h, v8.8h, v17.8h+ add v14.8h, v8.8h, v17.8h+ sqrdmulh v13.8h, v12.8h, v0.h[3]+ add v23.8h, v9.8h, v14.8h+ sqrdmulh v28.8h, v11.8h, v0.h[5]+ sub v19.8h, v9.8h, v14.8h+ mul v17.8h, v27.8h, v0.h[4]+ str q23, [x0, #0x40]+ mul v14.8h, v20.8h, v0.h[2]+ mul v8.8h, v11.8h, v0.h[4]+ mul v4.8h, v12.8h, v0.h[2]+ mls v14.8h, v26.8h, v7.h[0]+ mls v17.8h, v10.8h, v7.h[0]+ mls v8.8h, v28.8h, v7.h[0]+ mls v4.8h, v13.8h, v7.h[0]+ sub v10.8h, v14.8h, v17.8h+ add v20.8h, v14.8h, v17.8h+ sqrdmulh v28.8h, v5.8h, v0.h[1]+ mul v18.8h, v5.8h, v0.h[0]+ str q20, [x0, #0x80]+ sub v13.8h, v4.8h, v8.8h+ mul v23.8h, v10.8h, v0.h[0]+ mul v17.8h, v19.8h, v0.h[0]+ sqrdmulh v9.8h, v13.8h, v0.h[1]+ mls v18.8h, v28.8h, v7.h[0]+ sqrdmulh v10.8h, v10.8h, v0.h[1]+ sub x4, x4, #0x2++Lmlk_intt_layer123_start:+ sub v12.8h, v3.8h, v30.8h+ mul v11.8h, v21.8h, v1.h[0]+ add v28.8h, v4.8h, v8.8h+ ldr q20, [x0, #0x190]+ add v27.8h, v16.8h, v6.8h+ sqrdmulh v8.8h, v12.8h, v1.h[3]+ add v16.8h, v29.8h, v24.8h+ str q28, [x0, #0xc0]+ mls v23.8h, v10.8h, v7.h[0]+ str q27, [x0], #0x10+ add v15.8h, v20.8h, v22.8h+ str q18, [x0, #0xf0]+ mul v14.8h, v13.8h, v0.h[0]+ add v2.8h, v2.8h, v25.8h+ sub v26.8h, v20.8h, v22.8h+ mul v4.8h, v12.8h, v1.h[2]+ sub v5.8h, v16.8h, v2.8h+ str q23, [x0, #0x170]+ add v20.8h, v3.8h, v30.8h+ sqrdmulh v27.8h, v26.8h, v1.h[5]+ add v16.8h, v16.8h, v2.8h+ mul v18.8h, v26.8h, v1.h[4]+ sub v31.8h, v20.8h, v15.8h+ mls v4.8h, v8.8h, v7.h[0]+ sub v28.8h, v29.8h, v24.8h+ mls v18.8h, v27.8h, v7.h[0]+ ldr q22, [x0, #0x1d0]+ mul v26.8h, v28.8h, v0.h[6]+ mul v2.8h, v5.8h, v0.h[2]+ sub v12.8h, v4.8h, v18.8h+ sqrdmulh v24.8h, v28.8h, v0.h[7]+ mls v14.8h, v9.8h, v7.h[0]+ sqrdmulh v10.8h, v12.8h, v0.h[5]+ mls v26.8h, v24.8h, v7.h[0]+ ldr q24, [x0, #0x50]+ mul v8.8h, v12.8h, v0.h[4]+ str q14, [x0, #0x1b0]+ add v28.8h, v4.8h, v18.8h+ sqrdmulh v5.8h, v5.8h, v0.h[3]+ add v6.8h, v20.8h, v15.8h+ sqrdmulh v3.8h, v19.8h, v0.h[1]+ sub v13.8h, v16.8h, v6.8h+ sqrdmulh v12.8h, v21.8h, v1.h[1]+ sqrdmulh v21.8h, v13.8h, v0.h[1]+ sqrdmulh v27.8h, v31.8h, v0.h[5]+ ldr q25, [x0, #0xd0]+ mls v11.8h, v12.8h, v7.h[0]+ mul v23.8h, v31.8h, v0.h[4]+ mul v18.8h, v13.8h, v0.h[0]+ add v30.8h, v26.8h, v11.8h+ sub v13.8h, v26.8h, v11.8h+ mls v23.8h, v27.8h, v7.h[0]+ add v12.8h, v30.8h, v28.8h+ sub v19.8h, v30.8h, v28.8h+ mls v2.8h, v5.8h, v7.h[0]+ str q12, [x0, #0x40]+ sqrdmulh v26.8h, v13.8h, v0.h[3]+ mls v8.8h, v10.8h, v7.h[0]+ ldr q30, [x0, #0x150]+ sub v20.8h, v2.8h, v23.8h+ mul v4.8h, v13.8h, v0.h[2]+ add v13.8h, v2.8h, v23.8h+ mls v4.8h, v26.8h, v7.h[0]+ ldr q2, [x0, #0x90]+ mul v23.8h, v20.8h, v0.h[0]+ ldr q29, [x0, #0x10]+ sqrdmulh v10.8h, v20.8h, v0.h[1]+ str q13, [x0, #0x80]+ sub v13.8h, v4.8h, v8.8h+ mls v17.8h, v3.8h, v7.h[0]+ ldr q3, [x0, #0x110]+ mls v18.8h, v21.8h, v7.h[0]+ sub v21.8h, v2.8h, v25.8h+ sqrdmulh v9.8h, v13.8h, v0.h[1]+ str q17, [x0, #0x130]+ mul v17.8h, v19.8h, v0.h[0]+ sub x4, x4, #0x1+ cbnz x4, Lmlk_intt_layer123_start+ mls v23.8h, v10.8h, v7.h[0]+ ldr q11, [x0, #0x190]+ str q18, [x0, #0x100]+ add v27.8h, v3.8h, v30.8h+ mul v13.8h, v13.8h, v0.h[0]+ sub v5.8h, v29.8h, v24.8h+ add v14.8h, v16.8h, v6.8h+ mls v13.8h, v9.8h, v7.h[0]+ add v10.8h, v11.8h, v22.8h+ str q23, [x0, #0x180]+ sub v20.8h, v11.8h, v22.8h+ sub v23.8h, v27.8h, v10.8h+ sqrdmulh v16.8h, v21.8h, v1.h[1]+ sqrdmulh v31.8h, v23.8h, v0.h[5]+ str q13, [x0, #0x1c0]+ add v13.8h, v4.8h, v8.8h+ mul v18.8h, v21.8h, v1.h[0]+ str q13, [x0, #0xc0]+ sqrdmulh v13.8h, v19.8h, v0.h[1]+ sqrdmulh v28.8h, v20.8h, v1.h[5]+ str q14, [x0], #0x10+ mul v4.8h, v20.8h, v1.h[4]+ mls v17.8h, v13.8h, v7.h[0]+ sub v13.8h, v3.8h, v30.8h+ sqrdmulh v8.8h, v13.8h, v1.h[3]+ mul v12.8h, v13.8h, v1.h[2]+ mls v4.8h, v28.8h, v7.h[0]+ mls v12.8h, v8.8h, v7.h[0]+ mls v18.8h, v16.8h, v7.h[0]+ str q17, [x0, #0x130]+ sqrdmulh v15.8h, v5.8h, v0.h[7]+ add v11.8h, v27.8h, v10.8h+ mul v16.8h, v5.8h, v0.h[6]+ sub v8.8h, v12.8h, v4.8h+ sqrdmulh v28.8h, v8.8h, v0.h[5]+ add v13.8h, v2.8h, v25.8h+ mls v16.8h, v15.8h, v7.h[0]+ add v26.8h, v12.8h, v4.8h+ mul v8.8h, v8.8h, v0.h[4]+ add v4.8h, v29.8h, v24.8h+ mls v8.8h, v28.8h, v7.h[0]+ sub v20.8h, v4.8h, v13.8h+ add v14.8h, v4.8h, v13.8h+ add v12.8h, v16.8h, v18.8h+ sqrdmulh v22.8h, v20.8h, v0.h[3]+ add v27.8h, v14.8h, v11.8h+ sub v13.8h, v16.8h, v18.8h+ mul v4.8h, v20.8h, v0.h[2]+ str q27, [x0], #0x10+ sub v24.8h, v12.8h, v26.8h+ sqrdmulh v3.8h, v13.8h, v0.h[3]+ mul v13.8h, v13.8h, v0.h[2]+ sqrdmulh v27.8h, v24.8h, v0.h[1]+ mls v13.8h, v3.8h, v7.h[0]+ mul v9.8h, v24.8h, v0.h[0]+ mls v9.8h, v27.8h, v7.h[0]+ add v30.8h, v13.8h, v8.8h+ sub v13.8h, v13.8h, v8.8h+ mls v4.8h, v22.8h, v7.h[0]+ str q30, [x0, #0xb0]+ sqrdmulh v16.8h, v13.8h, v0.h[1]+ str q9, [x0, #0x130]+ mul v9.8h, v13.8h, v0.h[0]+ add v13.8h, v12.8h, v26.8h+ str q13, [x0, #0x30]+ mul v13.8h, v23.8h, v0.h[4]+ sub v23.8h, v14.8h, v11.8h+ mls v13.8h, v31.8h, v7.h[0]+ mls v9.8h, v16.8h, v7.h[0]+ mul v30.8h, v23.8h, v0.h[0]+ sub v24.8h, v4.8h, v13.8h+ add v13.8h, v4.8h, v13.8h+ sqrdmulh v23.8h, v23.8h, v0.h[1]+ str q9, [x0, #0x1b0]+ str q13, [x0, #0x70]+ sqrdmulh v13.8h, v24.8h, v0.h[1]+ mul v21.8h, v24.8h, v0.h[0]+ mls v30.8h, v23.8h, v7.h[0]+ mls v21.8h, v13.8h, v7.h[0]+ str q30, [x0, #0xf0]+ str q21, [x0, #0x170]+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(intt_aarch64_asm)++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED && \+ (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,565 @@+/* Copyright (c) 2022 Arm Limited+ * Copyright (c) 2022 Hanno Becker+ * Copyright (c) 2023 Amin Abdulrahman, Matthias Kannwischer+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [NeonNTT]+ * Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1+ * Becker, Hwang, Kannwischer, Yang, Yang+ * https://eprint.iacr.org/2021/986+ *+ * - [SLOTHY_Paper]+ * Fast and Clean: Auditable high-performance assembly via constraint solving+ * Abdulrahman, Becker, Kannwischer, Klein+ * https://eprint.iacr.org/2022/1303+ */++/*yaml+ Name: ntt_aarch64_asm+ Description: AArch64 ML-KEM forward NTT following @[NeonNTT] and @[SLOTHY_Paper]+ Signature: void mlk_ntt_aarch64_asm(int16_t p[256], const int16_t twiddles12345[80], const int16_t twiddles56[384])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t p[256]+ description: Input/output polynomial+ x1:+ type: buffer+ size_bytes: 160+ permissions: read-only+ c_parameter: const int16_t twiddles12345[80]+ description: Twiddle factors for layers 1-5+ x2:+ type: buffer+ size_bytes: 768+ permissions: read-only+ c_parameter: const int16_t twiddles56[384]+ description: Twiddle factors for layers 6-7+ Stack:+ bytes: 64+ description: saving callee-saved Neon registers+*/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_ntt_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(ntt_aarch64_asm)+MLK_ASM_FN_SYMBOL(ntt_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ mov w5, #0xd01 // =3329+ mov v7.h[0], w5+ mov w5, #0x4ebf // =20159+ mov v7.h[1], w5+ mov x3, x0+ mov x4, #0x4 // =4+ ldr q0, [x1], #0x20+ ldur q1, [x1, #-0x10]+ ldr q21, [x0, #0x40]+ ldr q5, [x0, #0x1c0]+ ldr q30, [x0, #0x110]+ ldr q24, [x0, #0x140]+ ldr q12, [x0, #0x80]+ sqrdmulh v9.8h, v5.8h, v0.h[1]+ mul v23.8h, v5.8h, v0.h[0]+ sqrdmulh v17.8h, v24.8h, v0.h[1]+ ldr q13, [x0, #0xc0]+ mls v23.8h, v9.8h, v7.h[0]+ mul v8.8h, v24.8h, v0.h[0]+ mls v8.8h, v17.8h, v7.h[0]+ add v9.8h, v13.8h, v23.8h+ sub v10.8h, v13.8h, v23.8h+ mul v11.8h, v30.8h, v0.h[0]+ ldr q13, [x0, #0x180]+ sqrdmulh v28.8h, v9.8h, v0.h[3]+ sub v29.8h, v21.8h, v8.8h+ mul v26.8h, v9.8h, v0.h[2]+ add v8.8h, v21.8h, v8.8h+ mul v2.8h, v13.8h, v0.h[0]+ mls v26.8h, v28.8h, v7.h[0]+ mul v28.8h, v10.8h, v0.h[4]+ sqrdmulh v23.8h, v10.8h, v0.h[5]+ add v22.8h, v8.8h, v26.8h+ sqrdmulh v10.8h, v13.8h, v0.h[1]+ sqrdmulh v21.8h, v22.8h, v0.h[7]+ ldr q13, [x0, #0x100]+ mul v16.8h, v22.8h, v0.h[6]+ mls v28.8h, v23.8h, v7.h[0]+ mls v2.8h, v10.8h, v7.h[0]+ sqrdmulh v23.8h, v13.8h, v0.h[1]+ sub v10.8h, v29.8h, v28.8h+ add v17.8h, v29.8h, v28.8h+ mls v16.8h, v21.8h, v7.h[0]+ sub v18.8h, v12.8h, v2.8h+ ldr q29, [x0]+ sqrdmulh v14.8h, v17.8h, v1.h[3]+ add v22.8h, v12.8h, v2.8h+ sqrdmulh v9.8h, v18.8h, v0.h[5]+ mul v21.8h, v13.8h, v0.h[0]+ ldr q13, [x0, #0x150]+ mul v5.8h, v18.8h, v0.h[4]+ mls v5.8h, v9.8h, v7.h[0]+ mul v18.8h, v13.8h, v0.h[0]+ mls v21.8h, v23.8h, v7.h[0]+ sqrdmulh v2.8h, v13.8h, v0.h[1]+ mul v13.8h, v17.8h, v1.h[2]+ sub v4.8h, v29.8h, v21.8h+ mls v13.8h, v14.8h, v7.h[0]+ add v25.8h, v29.8h, v21.8h+ add v6.8h, v4.8h, v5.8h+ sqrdmulh v15.8h, v22.8h, v0.h[3]+ sub v21.8h, v4.8h, v5.8h+ sub v5.8h, v8.8h, v26.8h+ mul v23.8h, v22.8h, v0.h[2]+ add v28.8h, v6.8h, v13.8h+ sub v13.8h, v6.8h, v13.8h+ mul v4.8h, v5.8h, v1.h[0]+ sub x4, x4, #0x2++Lmlk_ntt_layer123_start:+ mls v23.8h, v15.8h, v7.h[0]+ ldr q6, [x0, #0x190]+ ldr q15, [x0, #0x90]+ ldr q19, [x0, #0x10]+ mul v22.8h, v10.8h, v1.h[4]+ ldr q24, [x0, #0x50]+ str q13, [x0, #0x140]+ sqrdmulh v13.8h, v6.8h, v0.h[1]+ sub v20.8h, v25.8h, v23.8h+ sqrdmulh v3.8h, v30.8h, v0.h[1]+ str q28, [x0, #0x100]+ ldr q30, [x0, #0x120]+ mul v8.8h, v6.8h, v0.h[0]+ sqrdmulh v27.8h, v10.8h, v1.h[5]+ mls v11.8h, v3.8h, v7.h[0]+ mls v18.8h, v2.8h, v7.h[0]+ ldr q31, [x0, #0x160]+ sqrdmulh v10.8h, v5.8h, v1.h[1]+ mls v8.8h, v13.8h, v7.h[0]+ ldr q13, [x0, #0x1d0]+ sub v14.8h, v24.8h, v18.8h+ add v9.8h, v24.8h, v18.8h+ sqrdmulh v2.8h, v31.8h, v0.h[1]+ mls v4.8h, v10.8h, v7.h[0]+ add v10.8h, v25.8h, v23.8h+ sub v24.8h, v19.8h, v11.8h+ add v25.8h, v19.8h, v11.8h+ sqrdmulh v28.8h, v13.8h, v0.h[1]+ mul v11.8h, v30.8h, v0.h[0]+ mul v17.8h, v13.8h, v0.h[0]+ sub v13.8h, v10.8h, v16.8h+ sub v6.8h, v15.8h, v8.8h+ mls v17.8h, v28.8h, v7.h[0]+ str q13, [x0, #0x40]+ mls v22.8h, v27.8h, v7.h[0]+ ldr q13, [x0, #0xd0]+ add v26.8h, v20.8h, v4.8h+ mul v18.8h, v31.8h, v0.h[0]+ add v27.8h, v10.8h, v16.8h+ str q26, [x0, #0x80]+ sqrdmulh v31.8h, v6.8h, v0.h[5]+ add v3.8h, v21.8h, v22.8h+ str q27, [x0], #0x10+ mul v26.8h, v6.8h, v0.h[4]+ add v6.8h, v13.8h, v17.8h+ sub v5.8h, v13.8h, v17.8h+ str q3, [x0, #0x170]+ sub v17.8h, v21.8h, v22.8h+ sqrdmulh v10.8h, v6.8h, v0.h[3]+ sub v13.8h, v20.8h, v4.8h+ add v20.8h, v15.8h, v8.8h+ sqrdmulh v12.8h, v5.8h, v0.h[5]+ str q13, [x0, #0xb0]+ mul v8.8h, v6.8h, v0.h[2]+ str q17, [x0, #0x1b0]+ mls v8.8h, v10.8h, v7.h[0]+ mul v29.8h, v5.8h, v0.h[4]+ mls v29.8h, v12.8h, v7.h[0]+ sub v5.8h, v9.8h, v8.8h+ add v3.8h, v9.8h, v8.8h+ sqrdmulh v15.8h, v20.8h, v0.h[3]+ mul v4.8h, v5.8h, v1.h[0]+ add v6.8h, v14.8h, v29.8h+ sqrdmulh v9.8h, v3.8h, v0.h[7]+ sqrdmulh v12.8h, v6.8h, v1.h[3]+ sub v10.8h, v14.8h, v29.8h+ mul v23.8h, v6.8h, v1.h[2]+ mls v26.8h, v31.8h, v7.h[0]+ mls v23.8h, v12.8h, v7.h[0]+ mul v16.8h, v3.8h, v0.h[6]+ add v13.8h, v24.8h, v26.8h+ sub v21.8h, v24.8h, v26.8h+ mls v16.8h, v9.8h, v7.h[0]+ add v28.8h, v13.8h, v23.8h+ sub v13.8h, v13.8h, v23.8h+ mul v23.8h, v20.8h, v0.h[2]+ sub x4, x4, #0x1+ cbnz x4, Lmlk_ntt_layer123_start+ sqrdmulh v3.8h, v5.8h, v1.h[1]+ mls v23.8h, v15.8h, v7.h[0]+ ldr q5, [x0, #0x190]+ mul v29.8h, v10.8h, v1.h[4]+ mls v4.8h, v3.8h, v7.h[0]+ sub v19.8h, v25.8h, v23.8h+ sqrdmulh v31.8h, v5.8h, v0.h[1]+ sqrdmulh v6.8h, v30.8h, v0.h[1]+ sub v3.8h, v19.8h, v4.8h+ mul v5.8h, v5.8h, v0.h[0]+ str q3, [x0, #0xc0]+ sqrdmulh v12.8h, v10.8h, v1.h[5]+ mls v18.8h, v2.8h, v7.h[0]+ ldr q3, [x0, #0x1d0]+ mls v5.8h, v31.8h, v7.h[0]+ sqrdmulh v10.8h, v3.8h, v0.h[1]+ mls v11.8h, v6.8h, v7.h[0]+ ldr q31, [x0, #0x90]+ mul v30.8h, v3.8h, v0.h[0]+ mls v30.8h, v10.8h, v7.h[0]+ sub v10.8h, v31.8h, v5.8h+ mls v29.8h, v12.8h, v7.h[0]+ ldr q6, [x0, #0xd0]+ sqrdmulh v15.8h, v10.8h, v0.h[5]+ mul v17.8h, v10.8h, v0.h[4]+ add v10.8h, v6.8h, v30.8h+ sub v6.8h, v6.8h, v30.8h+ sqrdmulh v12.8h, v10.8h, v0.h[3]+ sub v27.8h, v21.8h, v29.8h+ sqrdmulh v3.8h, v6.8h, v0.h[5]+ mul v10.8h, v10.8h, v0.h[2]+ ldr q20, [x0, #0x50]+ mls v10.8h, v12.8h, v7.h[0]+ mul v2.8h, v6.8h, v0.h[4]+ add v6.8h, v20.8h, v18.8h+ add v5.8h, v31.8h, v5.8h+ mls v2.8h, v3.8h, v7.h[0]+ sub v31.8h, v6.8h, v10.8h+ sqrdmulh v12.8h, v5.8h, v0.h[3]+ sub v22.8h, v20.8h, v18.8h+ add v6.8h, v6.8h, v10.8h+ mul v20.8h, v31.8h, v1.h[0]+ add v30.8h, v22.8h, v2.8h+ sqrdmulh v3.8h, v6.8h, v0.h[7]+ sqrdmulh v10.8h, v30.8h, v1.h[3]+ mul v9.8h, v30.8h, v1.h[2]+ ldr q30, [x0, #0x10]+ mls v17.8h, v15.8h, v7.h[0]+ mls v9.8h, v10.8h, v7.h[0]+ mul v15.8h, v6.8h, v0.h[6]+ add v24.8h, v30.8h, v11.8h+ sub v10.8h, v22.8h, v2.8h+ mls v15.8h, v3.8h, v7.h[0]+ add v6.8h, v19.8h, v4.8h+ add v22.8h, v25.8h, v23.8h+ sqrdmulh v3.8h, v10.8h, v1.h[5]+ str q13, [x0, #0x140]+ sub v19.8h, v30.8h, v11.8h+ add v25.8h, v22.8h, v16.8h+ mul v5.8h, v5.8h, v0.h[2]+ sub v13.8h, v22.8h, v16.8h+ str q28, [x0, #0x100]+ mls v5.8h, v12.8h, v7.h[0]+ str q13, [x0, #0x40]+ str q6, [x0, #0x80]+ add v21.8h, v21.8h, v29.8h+ sqrdmulh v13.8h, v31.8h, v1.h[1]+ str q25, [x0], #0x10+ add v12.8h, v19.8h, v17.8h+ sub v31.8h, v19.8h, v17.8h+ mul v30.8h, v10.8h, v1.h[4]+ str q21, [x0, #0x170]+ add v21.8h, v24.8h, v5.8h+ add v6.8h, v12.8h, v9.8h+ mls v30.8h, v3.8h, v7.h[0]+ str q27, [x0, #0x1b0]+ sub v10.8h, v21.8h, v15.8h+ sub v12.8h, v12.8h, v9.8h+ mls v20.8h, v13.8h, v7.h[0]+ str q6, [x0, #0x100]+ str q10, [x0, #0x40]+ sub v13.8h, v24.8h, v5.8h+ add v3.8h, v21.8h, v15.8h+ str q12, [x0, #0x140]+ sub v10.8h, v31.8h, v30.8h+ add v21.8h, v31.8h, v30.8h+ str q3, [x0], #0x10+ add v12.8h, v13.8h, v20.8h+ sub v13.8h, v13.8h, v20.8h+ str q21, [x0, #0x170]+ str q10, [x0, #0x1b0]+ str q12, [x0, #0x70]+ str q13, [x0, #0xb0]+ mov x0, x3+ mov x4, #0x8 // =8+ ldr q2, [x0, #0x20]+ ldr q13, [x1], #0x10+ ldr q30, [x0, #0x30]+ ldr q25, [x2, #0x40]+ ldr q5, [x0]+ ldr q18, [x0, #0x60]+ ldr q12, [x0, #0x70]+ sqrdmulh v17.8h, v2.8h, v13.h[1]+ ldr q4, [x1], #0x10+ ldr q23, [x0, #0x10]+ sqrdmulh v21.8h, v30.8h, v13.h[1]+ ldr q24, [x2, #0x20]+ ldr q9, [x2], #0x60+ mul v10.8h, v30.8h, v13.h[0]+ mul v11.8h, v2.8h, v13.h[0]+ mls v10.8h, v21.8h, v7.h[0]+ sqrdmulh v29.8h, v12.8h, v4.h[1]+ mul v1.8h, v12.8h, v4.h[0]+ add v21.8h, v23.8h, v10.8h+ sub v10.8h, v23.8h, v10.8h+ mul v8.8h, v18.8h, v4.h[0]+ sqrdmulh v23.8h, v21.8h, v13.h[3]+ mul v2.8h, v21.8h, v13.h[2]+ mls v1.8h, v29.8h, v7.h[0]+ mls v2.8h, v23.8h, v7.h[0]+ ldur q15, [x2, #-0x50]+ sqrdmulh v0.8h, v10.8h, v13.h[5]+ mls v11.8h, v17.8h, v7.h[0]+ ldr q29, [x0, #0x50]+ mul v23.8h, v10.8h, v13.h[4]+ mls v23.8h, v0.8h, v7.h[0]+ sub v16.8h, v29.8h, v1.8h+ add v3.8h, v5.8h, v11.8h+ sub v31.8h, v5.8h, v11.8h+ sqrdmulh v22.8h, v16.8h, v4.h[5]+ add v30.8h, v3.8h, v2.8h+ sub v0.8h, v3.8h, v2.8h+ sqrdmulh v28.8h, v18.8h, v4.h[1]+ add v21.8h, v31.8h, v23.8h+ sub v19.8h, v31.8h, v23.8h+ mul v26.8h, v16.8h, v4.h[4]+ trn2 v3.4s, v30.4s, v0.4s+ ldur q23, [x2, #-0x10]+ trn2 v18.4s, v21.4s, v19.4s+ mls v26.8h, v22.8h, v7.h[0]+ trn1 v13.4s, v30.4s, v0.4s+ mls v8.8h, v28.8h, v7.h[0]+ trn2 v31.2d, v3.2d, v18.2d+ trn1 v11.4s, v21.4s, v19.4s+ add v27.8h, v29.8h, v1.8h+ sqrdmulh v6.8h, v31.8h, v15.8h+ trn1 v2.2d, v13.2d, v11.2d+ trn2 v13.2d, v13.2d, v11.2d+ mul v1.8h, v31.8h, v9.8h+ ldr q11, [x0, #0x40]+ sqrdmulh v29.8h, v13.8h, v15.8h+ mls v1.8h, v6.8h, v7.h[0]+ trn1 v6.2d, v3.2d, v18.2d+ mul v17.8h, v13.8h, v9.8h+ sub v13.8h, v11.8h, v8.8h+ sqrdmulh v10.8h, v27.8h, v4.h[3]+ sub v12.8h, v13.8h, v26.8h+ sub v18.8h, v6.8h, v1.8h+ mls v17.8h, v29.8h, v7.h[0]+ add v30.8h, v6.8h, v1.8h+ add v6.8h, v13.8h, v26.8h+ ldur q13, [x2, #-0x30]+ sqrdmulh v16.8h, v18.8h, v23.8h+ trn1 v28.4s, v6.4s, v12.4s+ mul v23.8h, v18.8h, v25.8h+ ldr q25, [x2, #0x10]+ add v20.8h, v2.8h, v17.8h+ mul v0.8h, v30.8h, v24.8h+ sqrdmulh v29.8h, v30.8h, v13.8h+ sub v30.8h, v2.8h, v17.8h+ mls v23.8h, v16.8h, v7.h[0]+ sub x4, x4, #0x2++Lmlk_ntt_layer4567_start:+ ldr q19, [x2, #0x50]+ sub v31.8h, v30.8h, v23.8h+ mls v0.8h, v29.8h, v7.h[0]+ add v16.8h, v11.8h, v8.8h+ ldr q18, [x0, #0xa0]+ trn2 v14.4s, v6.4s, v12.4s+ mul v26.8h, v27.8h, v4.h[2]+ ldr q4, [x1], #0x10+ ldr q24, [x2, #0x40]+ ldr q21, [x0, #0xb0]+ mls v26.8h, v10.8h, v7.h[0]+ add v23.8h, v30.8h, v23.8h+ sub v15.8h, v20.8h, v0.8h+ ldr q9, [x0, #0x90]+ add v10.8h, v20.8h, v0.8h+ mul v8.8h, v18.8h, v4.h[0]+ ldr q1, [x2], #0x60+ trn1 v27.4s, v23.4s, v31.4s+ sqrdmulh v12.8h, v18.8h, v4.h[1]+ trn1 v5.4s, v10.4s, v15.4s+ sub v30.8h, v16.8h, v26.8h+ trn2 v13.2d, v5.2d, v27.2d+ sqrdmulh v2.8h, v21.8h, v4.h[1]+ add v29.8h, v16.8h, v26.8h+ mul v0.8h, v21.8h, v4.h[0]+ str q13, [x0, #0x20]+ trn1 v11.4s, v29.4s, v30.4s+ mls v8.8h, v12.8h, v7.h[0]+ trn2 v26.4s, v29.4s, v30.4s+ trn2 v6.2d, v11.2d, v28.2d+ mls v0.8h, v2.8h, v7.h[0]+ trn2 v16.2d, v26.2d, v14.2d+ trn1 v26.2d, v26.2d, v14.2d+ trn1 v20.2d, v5.2d, v27.2d+ sqrdmulh v29.8h, v6.8h, v25.8h+ trn2 v15.4s, v10.4s, v15.4s+ sqrdmulh v13.8h, v16.8h, v25.8h+ str q20, [x0], #0x40+ sub v30.8h, v9.8h, v0.8h+ add v27.8h, v9.8h, v0.8h+ mul v17.8h, v6.8h, v1.8h+ sqrdmulh v22.8h, v30.8h, v4.h[5]+ mul v18.8h, v16.8h, v1.8h+ mls v18.8h, v13.8h, v7.h[0]+ mul v2.8h, v30.8h, v4.h[4]+ mls v2.8h, v22.8h, v7.h[0]+ trn2 v22.4s, v23.4s, v31.4s+ sub v3.8h, v26.8h, v18.8h+ ldur q25, [x2, #-0x30]+ mls v17.8h, v29.8h, v7.h[0]+ trn2 v31.2d, v15.2d, v22.2d+ trn1 v20.2d, v15.2d, v22.2d+ add v16.8h, v26.8h, v18.8h+ sqrdmulh v26.8h, v3.8h, v19.8h+ trn1 v21.2d, v11.2d, v28.2d+ ldr q11, [x0, #0x40]+ sqrdmulh v29.8h, v16.8h, v25.8h+ stur q20, [x0, #-0x30]+ add v20.8h, v21.8h, v17.8h+ stur q31, [x0, #-0x10]+ mul v23.8h, v3.8h, v24.8h+ ldr q25, [x2, #0x10]+ sub v13.8h, v11.8h, v8.8h+ mls v23.8h, v26.8h, v7.h[0]+ ldur q1, [x2, #-0x40]+ sub v12.8h, v13.8h, v2.8h+ add v6.8h, v13.8h, v2.8h+ sqrdmulh v10.8h, v27.8h, v4.h[3]+ sub v30.8h, v21.8h, v17.8h+ mul v0.8h, v16.8h, v1.8h+ trn1 v28.4s, v6.4s, v12.4s+ sub x4, x4, #0x1+ cbnz x4, Lmlk_ntt_layer4567_start+ add v22.8h, v11.8h, v8.8h+ mul v27.8h, v27.8h, v4.h[2]+ trn2 v17.4s, v6.4s, v12.4s+ ldr q15, [x2], #0x60+ mls v27.8h, v10.8h, v7.h[0]+ add v4.8h, v30.8h, v23.8h+ sub v18.8h, v30.8h, v23.8h+ ldur q6, [x2, #-0x30]+ mls v0.8h, v29.8h, v7.h[0]+ ldur q12, [x2, #-0x40]+ ldur q24, [x2, #-0x20]+ ldur q2, [x2, #-0x10]+ trn1 v9.4s, v4.4s, v18.4s+ add v10.8h, v22.8h, v27.8h+ sub v13.8h, v22.8h, v27.8h+ sub v1.8h, v20.8h, v0.8h+ trn2 v21.4s, v10.4s, v13.4s+ add v27.8h, v20.8h, v0.8h+ trn2 v3.2d, v21.2d, v17.2d+ trn1 v13.4s, v10.4s, v13.4s+ trn1 v31.4s, v27.4s, v1.4s+ sqrdmulh v10.8h, v3.8h, v25.8h+ trn2 v5.2d, v13.2d, v28.2d+ trn1 v13.2d, v13.2d, v28.2d+ trn1 v21.2d, v21.2d, v17.2d+ sqrdmulh v17.8h, v5.8h, v25.8h+ trn2 v30.2d, v31.2d, v9.2d+ mul v25.8h, v3.8h, v15.8h+ str q30, [x0, #0x20]+ trn2 v30.4s, v4.4s, v18.4s+ mls v25.8h, v10.8h, v7.h[0]+ trn2 v3.4s, v27.4s, v1.4s+ mul v20.8h, v5.8h, v15.8h+ trn2 v10.2d, v3.2d, v30.2d+ mls v20.8h, v17.8h, v7.h[0]+ str q10, [x0, #0x30]+ sub v18.8h, v21.8h, v25.8h+ add v10.8h, v21.8h, v25.8h+ trn1 v3.2d, v3.2d, v30.2d+ sqrdmulh v30.8h, v18.8h, v2.8h+ mul v12.8h, v10.8h, v12.8h+ sqrdmulh v6.8h, v10.8h, v6.8h+ str q3, [x0, #0x10]+ add v21.8h, v13.8h, v20.8h+ mul v10.8h, v18.8h, v24.8h+ sub v13.8h, v13.8h, v20.8h+ mls v10.8h, v30.8h, v7.h[0]+ mls v12.8h, v6.8h, v7.h[0]+ trn1 v30.2d, v31.2d, v9.2d+ sub v3.8h, v13.8h, v10.8h+ add v6.8h, v13.8h, v10.8h+ add v10.8h, v21.8h, v12.8h+ sub v21.8h, v21.8h, v12.8h+ trn2 v13.4s, v6.4s, v3.4s+ trn1 v12.4s, v10.4s, v21.4s+ trn2 v21.4s, v10.4s, v21.4s+ trn1 v3.4s, v6.4s, v3.4s+ str q30, [x0], #0x40+ trn2 v10.2d, v21.2d, v13.2d+ trn1 v13.2d, v21.2d, v13.2d+ trn2 v21.2d, v12.2d, v3.2d+ trn1 v3.2d, v12.2d, v3.2d+ str q10, [x0, #0x30]+ str q13, [x0, #0x10]+ str q3, [x0], #0x40+ stur q21, [x0, #-0x20]+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(ntt_aarch64_asm)++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,130 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: poly_mulcache_compute_aarch64_asm+ Description: Compute multiplication cache for polynomial+ Signature: void mlk_poly_mulcache_compute_aarch64_asm(int16_t cache[128], const int16_t mlk_poly[256], const int16_t zetas[128], const int16_t zetas_twisted[128])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 256+ permissions: write-only+ c_parameter: int16_t cache[128]+ description: Output cache+ x1:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t mlk_poly[256]+ description: Input polynomial+ x2:+ type: buffer+ size_bytes: 256+ permissions: read-only+ c_parameter: const int16_t zetas[128]+ description: Zeta values+ x3:+ type: buffer+ size_bytes: 256+ permissions: read-only+ c_parameter: const int16_t zetas_twisted[128]+ description: Twisted zeta values+ Stack:+ bytes: 0+*/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_poly_mulcache_compute_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_mulcache_compute_aarch64_asm)+MLK_ASM_FN_SYMBOL(poly_mulcache_compute_aarch64_asm)++ .cfi_startproc+ mov w5, #0xd01 // =3329+ dup v6.8h, w5+ mov w5, #0x4ebf // =20159+ dup v7.8h, w5+ mov x4, #0x10 // =16+ ldr q0, [x1], #0x20+ ldur q2, [x1, #-0x10]+ ldr q19, [x1], #0x20+ ldr q29, [x3], #0x10+ ldur q16, [x1, #-0x10]+ ldr q18, [x2], #0x10+ ldr q26, [x1], #0x20+ ldr q25, [x2], #0x10+ uzp2 v5.8h, v0.8h, v2.8h+ ldr q28, [x3], #0x10+ ldur q7, [x1, #-0x10]+ ldr q2, [x1], #0x20+ uzp2 v27.8h, v19.8h, v16.8h+ sqrdmulh v16.8h, v5.8h, v29.8h+ ldr q17, [x3], #0x10+ ldr q19, [x3], #0x10+ mul v5.8h, v5.8h, v18.8h+ uzp2 v29.8h, v26.8h, v7.8h+ mul v26.8h, v27.8h, v25.8h+ sqrdmulh v4.8h, v27.8h, v28.8h+ mls v5.8h, v16.8h, v6.h[0]+ lsr x4, x4, #1+ sub x4, x4, #0x2++Lmlk_poly_mulcache_compute_loop_start:+ str q5, [x0], #0x10+ sqrdmulh v22.8h, v29.8h, v17.8h+ ldr q28, [x2], #0x10+ ldur q24, [x1, #-0x10]+ ldr q0, [x1], #0x20+ mls v26.8h, v4.8h, v6.h[0]+ ldur q16, [x1, #-0x10]+ ldr q17, [x3], #0x10+ mul v5.8h, v29.8h, v28.8h+ uzp2 v23.8h, v2.8h, v24.8h+ ldr q18, [x2], #0x10+ mls v5.8h, v22.8h, v6.h[0]+ uzp2 v29.8h, v0.8h, v16.8h+ sqrdmulh v4.8h, v23.8h, v19.8h+ ldr q2, [x1], #0x20+ ldr q19, [x3], #0x10+ str q26, [x0], #0x10+ mul v26.8h, v23.8h, v18.8h+ subs x4, x4, #0x1+ cbnz x4, Lmlk_poly_mulcache_compute_loop_start+ mls v26.8h, v4.8h, v6.h[0]+ str q5, [x0], #0x10+ ldr q5, [x2], #0x10+ ldur q4, [x1, #-0x10]+ sqrdmulh v16.8h, v29.8h, v17.8h+ ldr q0, [x2], #0x10+ mul v29.8h, v29.8h, v5.8h+ uzp2 v18.8h, v2.8h, v4.8h+ str q26, [x0], #0x10+ sqrdmulh v17.8h, v18.8h, v19.8h+ mls v29.8h, v16.8h, v6.h[0]+ mul v26.8h, v18.8h, v0.8h+ mls v26.8h, v17.8h, v6.h[0]+ str q29, [x0], #0x10+ str q26, [x0], #0x10+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_mulcache_compute_aarch64_asm)++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,153 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: poly_reduce_aarch64_asm+ Description: Barrett reduction of polynomial coefficients+ Signature: void mlk_poly_reduce_aarch64_asm(int16_t p[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t p[256]+ description: Input/output polynomial+ Stack:+ bytes: 0+*/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_poly_reduce_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_reduce_aarch64_asm)+MLK_ASM_FN_SYMBOL(poly_reduce_aarch64_asm)++ .cfi_startproc+ mov w2, #0xd01 // =3329+ dup v3.8h, w2+ mov w2, #0x4ebf // =20159+ dup v4.8h, w2+ mov x1, #0x8 // =8+ ldr q21, [x0], #0x40+ ldur q18, [x0, #-0x20]+ ldur q0, [x0, #-0x30]+ ldur q5, [x0, #-0x10]+ ldr q26, [x0], #0x40+ sqdmulh v17.8h, v21.8h, v4.h[0]+ sqdmulh v27.8h, v18.8h, v4.h[0]+ sqdmulh v22.8h, v0.8h, v4.h[0]+ srshr v17.8h, v17.8h, #0xb+ sqdmulh v23.8h, v5.8h, v4.h[0]+ srshr v29.8h, v27.8h, #0xb+ mls v21.8h, v17.8h, v3.h[0]+ srshr v17.8h, v22.8h, #0xb+ mls v18.8h, v29.8h, v3.h[0]+ srshr v22.8h, v23.8h, #0xb+ mls v0.8h, v17.8h, v3.h[0]+ sshr v2.8h, v21.8h, #0xf+ mls v5.8h, v22.8h, v3.h[0]+ sshr v29.8h, v18.8h, #0xf+ and v19.16b, v3.16b, v2.16b+ sqdmulh v2.8h, v26.8h, v4.h[0]+ sshr v31.8h, v0.8h, #0xf+ add v17.8h, v21.8h, v19.8h+ and v21.16b, v3.16b, v29.16b+ and v31.16b, v3.16b, v31.16b+ sub x1, x1, #0x2++Lmlk_poly_reduce_loop_start:+ add v21.8h, v18.8h, v21.8h+ ldur q18, [x0, #-0x20]+ add v25.8h, v0.8h, v31.8h+ ldur q0, [x0, #-0x30]+ stur q21, [x0, #-0x60]+ sshr v28.8h, v5.8h, #0xf+ stur q17, [x0, #-0x80]+ srshr v23.8h, v2.8h, #0xb+ sqdmulh v30.8h, v18.8h, v4.h[0]+ stur q25, [x0, #-0x70]+ and v22.16b, v3.16b, v28.16b+ sqdmulh v7.8h, v0.8h, v4.h[0]+ add v16.8h, v5.8h, v22.8h+ ldur q5, [x0, #-0x10]+ mls v26.8h, v23.8h, v3.h[0]+ stur q16, [x0, #-0x50]+ srshr v6.8h, v30.8h, #0xb+ srshr v1.8h, v7.8h, #0xb+ sqdmulh v19.8h, v5.8h, v4.h[0]+ mls v18.8h, v6.8h, v3.h[0]+ sshr v24.8h, v26.8h, #0xf+ mls v0.8h, v1.8h, v3.h[0]+ and v27.16b, v3.16b, v24.16b+ srshr v29.8h, v19.8h, #0xb+ add v17.8h, v26.8h, v27.8h+ ldr q26, [x0], #0x40+ sshr v1.8h, v18.8h, #0xf+ mls v5.8h, v29.8h, v3.h[0]+ sshr v20.8h, v0.8h, #0xf+ and v21.16b, v3.16b, v1.16b+ and v31.16b, v3.16b, v20.16b+ sqdmulh v2.8h, v26.8h, v4.h[0]+ subs x1, x1, #0x1+ cbnz x1, Lmlk_poly_reduce_loop_start+ add v28.8h, v0.8h, v31.8h+ ldur q29, [x0, #-0x10]+ add v21.8h, v18.8h, v21.8h+ srshr v18.8h, v2.8h, #0xb+ sshr v2.8h, v5.8h, #0xf+ ldur q16, [x0, #-0x20]+ stur q17, [x0, #-0x80]+ ldur q0, [x0, #-0x30]+ and v2.16b, v3.16b, v2.16b+ sqdmulh v24.8h, v29.8h, v4.h[0]+ stur q28, [x0, #-0x70]+ stur q21, [x0, #-0x60]+ add v31.8h, v5.8h, v2.8h+ sqdmulh v6.8h, v16.8h, v4.h[0]+ stur q31, [x0, #-0x50]+ sqdmulh v17.8h, v0.8h, v4.h[0]+ srshr v22.8h, v24.8h, #0xb+ mls v26.8h, v18.8h, v3.h[0]+ srshr v31.8h, v6.8h, #0xb+ mls v29.8h, v22.8h, v3.h[0]+ srshr v19.8h, v17.8h, #0xb+ mls v16.8h, v31.8h, v3.h[0]+ sshr v7.8h, v26.8h, #0xf+ mls v0.8h, v19.8h, v3.h[0]+ and v5.16b, v3.16b, v7.16b+ sshr v22.8h, v29.8h, #0xf+ add v27.8h, v26.8h, v5.8h+ and v26.16b, v3.16b, v22.16b+ sshr v20.8h, v16.8h, #0xf+ stur q27, [x0, #-0x40]+ and v2.16b, v3.16b, v20.16b+ sshr v23.8h, v0.8h, #0xf+ add v18.8h, v29.8h, v26.8h+ add v31.8h, v16.8h, v2.8h+ and v29.16b, v3.16b, v23.16b+ stur q18, [x0, #-0x10]+ add v25.8h, v0.8h, v29.8h+ stur q31, [x0, #-0x20]+ stur q25, [x0, #-0x30]+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_reduce_aarch64_asm)++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,124 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: poly_tobytes_aarch64_asm+ Description: Convert polynomial to byte representation+ Signature: void mlk_poly_tobytes_aarch64_asm(uint8_t r[384], const int16_t a[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 384+ permissions: write-only+ c_parameter: uint8_t r[384]+ description: Output byte array+ x1:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t a[256]+ description: Input polynomial+ Stack:+ bytes: 0+*/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (!defined(MLK_CONFIG_NO_KEYPAIR_API) || \+ !defined(MLK_CONFIG_NO_ENCAPS_API))++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_poly_tobytes_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_tobytes_aarch64_asm)+MLK_ASM_FN_SYMBOL(poly_tobytes_aarch64_asm)++ .cfi_startproc+ mov x2, #0x10 // =16+ ldr q5, [x1, #0x10]+ ldr q3, [x1], #0x20+ ldr q29, [x1], #0x20+ ldur q2, [x1, #-0x10]+ ldr q27, [x1, #0x10]+ ldr q23, [x1, #0x30]+ ldr q17, [x1], #0x20+ ldr q16, [x1], #0x20+ uzp2 v26.8h, v3.8h, v5.8h+ uzp1 v19.8h, v3.8h, v5.8h+ uzp2 v0.8h, v29.8h, v2.8h+ uzp1 v1.8h, v29.8h, v2.8h+ xtn v5.8b, v26.8h+ shrn v3.8b, v19.8h, #0x8+ shrn v4.8b, v26.8h, #0x4+ xtn v18.8b, v0.8h+ shrn v30.8b, v0.8h, #0x4+ xtn v28.8b, v1.8h+ shrn v29.8b, v1.8h, #0x8+ sli v3.8b, v5.8b, #0x4+ xtn v2.8b, v19.8h+ sli v29.8b, v18.8b, #0x4+ lsr x2, x2, #1+ sub x2, x2, #0x2++Lmlk_poly_tobytes_loop_start:+ uzp1 v25.8h, v17.8h, v27.8h+ uzp2 v31.8h, v17.8h, v27.8h+ uzp1 v24.8h, v16.8h, v23.8h+ uzp2 v6.8h, v16.8h, v23.8h+ st3 { v2.8b, v3.8b, v4.8b }, [x0], #24+ shrn v3.8b, v25.8h, #0x8+ ldr q17, [x1], #0x20+ shrn v4.8b, v31.8h, #0x4+ xtn v21.8b, v6.8h+ ldr q23, [x1, #0x10]+ st3 { v28.8b, v29.8b, v30.8b }, [x0], #24+ shrn v29.8b, v24.8h, #0x8+ ldur q27, [x1, #-0x10]+ xtn v20.8b, v31.8h+ ldr q16, [x1], #0x20+ sli v29.8b, v21.8b, #0x4+ xtn v2.8b, v25.8h+ sli v3.8b, v20.8b, #0x4+ xtn v28.8b, v24.8h+ shrn v30.8b, v6.8h, #0x4+ subs x2, x2, #0x1+ cbnz x2, Lmlk_poly_tobytes_loop_start+ uzp2 v7.8h, v17.8h, v27.8h+ uzp1 v25.8h, v17.8h, v27.8h+ uzp2 v0.8h, v16.8h, v23.8h+ st3 { v2.8b, v3.8b, v4.8b }, [x0], #24+ st3 { v28.8b, v29.8b, v30.8b }, [x0], #24+ shrn v21.8b, v25.8h, #0x8+ uzp1 v2.8h, v16.8h, v23.8h+ shrn v22.8b, v7.8h, #0x4+ shrn v4.8b, v0.8h, #0x4+ xtn v28.8b, v7.8h+ xtn v27.8b, v0.8h+ shrn v3.8b, v2.8h, #0x8+ sli v21.8b, v28.8b, #0x4+ xtn v2.8b, v2.8h+ sli v3.8b, v27.8b, #0x4+ xtn v20.8b, v25.8h+ st3 { v20.8b, v21.8b, v22.8b }, [x0], #24+ st3 { v2.8b, v3.8b, v4.8b }, [x0], #24+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_tobytes_aarch64_asm)++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED && \+ (!MLK_CONFIG_NO_KEYPAIR_API || !MLK_CONFIG_NO_ENCAPS_API) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,102 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: poly_tomont_aarch64_asm+ Description: Convert polynomial to Montgomery domain+ Signature: void mlk_poly_tomont_aarch64_asm(int16_t p[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t p[256]+ description: Input/output polynomial+ Stack:+ bytes: 0+*/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ !defined(MLK_CONFIG_NO_KEYPAIR_API)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_poly_tomont_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_tomont_aarch64_asm)+MLK_ASM_FN_SYMBOL(poly_tomont_aarch64_asm)++ .cfi_startproc+ mov w2, #0xd01 // =3329+ dup v4.8h, w2+ mov w2, #-0x414 // =-1044+ dup v2.8h, w2+ mov w2, #-0x2824 // =-10276+ dup v3.8h, w2+ mov x1, #0x8 // =8+ ldr q18, [x0, #0x20]+ ldr q0, [x0, #0x10]+ ldr q16, [x0], #0x40+ sqrdmulh v23.8h, v0.8h, v3.8h+ mul v26.8h, v0.8h, v2.8h+ sqrdmulh v19.8h, v16.8h, v3.8h+ mls v26.8h, v23.8h, v4.h[0]+ mul v29.8h, v16.8h, v2.8h+ ldur q16, [x0, #-0x10]+ mls v29.8h, v19.8h, v4.h[0]+ stur q26, [x0, #-0x30]+ sqrdmulh v26.8h, v18.8h, v3.8h+ mul v18.8h, v18.8h, v2.8h+ stur q29, [x0, #-0x40]+ sqrdmulh v29.8h, v16.8h, v3.8h+ mls v18.8h, v26.8h, v4.h[0]+ sub x1, x1, #0x1++Lmlk_poly_tomont_loop:+ ldr q19, [x0, #0x10]+ mul v26.8h, v16.8h, v2.8h+ ldr q23, [x0, #0x20]+ ldr q17, [x0], #0x40+ mls v26.8h, v29.8h, v4.h[0]+ ldur q16, [x0, #-0x10]+ sqrdmulh v28.8h, v19.8h, v3.8h+ stur q18, [x0, #-0x60]+ mul v0.8h, v19.8h, v2.8h+ stur q26, [x0, #-0x50]+ sqrdmulh v24.8h, v23.8h, v3.8h+ mul v18.8h, v23.8h, v2.8h+ sqrdmulh v22.8h, v17.8h, v3.8h+ mul v26.8h, v17.8h, v2.8h+ mls v0.8h, v28.8h, v4.h[0]+ mls v26.8h, v22.8h, v4.h[0]+ sqrdmulh v29.8h, v16.8h, v3.8h+ stur q0, [x0, #-0x30]+ mls v18.8h, v24.8h, v4.h[0]+ stur q26, [x0, #-0x40]+ sub x1, x1, #0x1+ cbnz x1, Lmlk_poly_tomont_loop+ mul v16.8h, v16.8h, v2.8h+ stur q18, [x0, #-0x20]+ mls v16.8h, v29.8h, v4.h[0]+ stur q16, [x0, #-0x10]+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_tomont_aarch64_asm)++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED && \+ !MLK_CONFIG_NO_KEYPAIR_API */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,264 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [NeonNTT]+ * Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1+ * Becker, Hwang, Kannwischer, Yang, Yang+ * https://eprint.iacr.org/2021/986+ */++/*yaml+ Name: polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm+ Description: Re-implementation of asymmetric base multiplication following @[NeonNTT] for k=2+ Signature: void mlk_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm(int16_t r[256], const int16_t a[512], const int16_t b[512], const int16_t b_cache[256])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t r[256]+ description: Output polynomial+ x1:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int16_t a[512]+ description: Input polynomial vector a+ x2:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int16_t b[512]+ description: Input polynomial vector b+ x3:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t b_cache[256]+ description: Cached values for b+ Stack:+ bytes: 64+ description: saving callee-saved Neon registers+*/++/* Re-implementation of asymmetric base multiplication following @[NeonNTT] */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm)+MLK_ASM_FN_SYMBOL(polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ mov w14, #0xd01 // =3329+ dup v0.8h, w14+ mov w14, #0xcff // =3327+ dup v2.8h, w14+ add x4, x1, #0x200+ add x5, x2, #0x200+ add x6, x3, #0x100+ mov x13, #0x10 // =16+ ldr q12, [x1], #0x20+ ldur q9, [x1, #-0x10]+ ldr q22, [x2], #0x20+ ldur q30, [x2, #-0x10]+ ldr q6, [x5], #0x20+ ldr q7, [x4, #0x10]+ ldr q8, [x4], #0x20+ ldur q23, [x5, #-0x10]+ uzp1 v16.8h, v12.8h, v9.8h+ uzp2 v14.8h, v12.8h, v9.8h+ uzp2 v13.8h, v22.8h, v30.8h+ uzp1 v18.8h, v22.8h, v30.8h+ ld1 { v27.8h }, [x3], #16+ ld1 { v17.8h }, [x6], #16+ smull2 v4.4s, v16.8h, v18.8h+ ldr q31, [x1, #0x10]+ smull v19.4s, v16.4h, v13.4h+ ldr q24, [x1], #0x20+ smlal v19.4s, v14.4h, v18.4h+ ldr q22, [x2], #0x20+ smlal2 v4.4s, v14.8h, v27.8h+ uzp2 v5.8h, v6.8h, v23.8h+ smull2 v29.4s, v16.8h, v13.8h+ uzp2 v26.8h, v8.8h, v7.8h+ smlal2 v29.4s, v14.8h, v18.8h+ uzp1 v30.8h, v24.8h, v31.8h+ uzp1 v8.8h, v8.8h, v7.8h+ smull v11.4s, v16.4h, v18.4h+ smlal v11.4s, v14.4h, v27.4h+ ldur q1, [x2, #-0x10]+ uzp1 v28.8h, v6.8h, v23.8h+ smlal2 v29.4s, v8.8h, v5.8h+ ldr q25, [x5], #0x20+ smlal v19.4s, v8.4h, v5.4h+ ldr q3, [x4, #0x10]+ smlal2 v29.4s, v26.8h, v28.8h+ uzp1 v27.8h, v22.8h, v1.8h+ smlal v19.4s, v26.4h, v28.4h+ ldr q12, [x4], #0x20+ smlal2 v4.4s, v8.8h, v28.8h+ ldur q21, [x5, #-0x10]+ smlal2 v4.4s, v26.8h, v17.8h+ smlal v11.4s, v8.4h, v28.4h+ ld1 { v15.8h }, [x6], #16+ smlal v11.4s, v26.4h, v17.4h+ ld1 { v20.8h }, [x3], #16+ uzp1 v28.8h, v19.8h, v29.8h+ smull2 v23.4s, v30.8h, v27.8h+ smull v26.4s, v30.4h, v27.4h+ uzp2 v16.8h, v22.8h, v1.8h+ mul v28.8h, v28.8h, v2.8h+ uzp1 v10.8h, v11.8h, v4.8h+ smull2 v8.4s, v30.8h, v16.8h+ mul v13.8h, v10.8h, v2.8h+ smlal v19.4s, v28.4h, v0.4h+ smlal2 v29.4s, v28.8h, v0.8h+ smull v18.4s, v30.4h, v16.4h+ uzp1 v30.8h, v25.8h, v21.8h+ smlal v11.4s, v13.4h, v0.4h+ uzp2 v6.8h, v24.8h, v31.8h+ uzp1 v16.8h, v12.8h, v3.8h+ smlal2 v4.4s, v13.8h, v0.8h+ uzp2 v17.8h, v25.8h, v21.8h+ smlal2 v8.4s, v6.8h, v27.8h+ uzp2 v12.8h, v12.8h, v3.8h+ smlal v18.4s, v6.4h, v27.4h+ uzp2 v9.8h, v19.8h, v29.8h+ smlal2 v8.4s, v16.8h, v17.8h+ smlal2 v8.4s, v12.8h, v30.8h+ uzp2 v19.8h, v11.8h, v4.8h+ sub x13, x13, #0x2++Lmlk_polyvec_basemul_acc_montgomery_cached_k2_loop_start:+ smlal v18.4s, v16.4h, v17.4h+ ldr q7, [x4], #0x20+ ldr q10, [x2, #0x10]+ smlal v18.4s, v12.4h, v30.4h+ smlal2 v23.4s, v6.8h, v20.8h+ ldr q14, [x2], #0x20+ smlal2 v23.4s, v16.8h, v30.8h+ zip1 v25.8h, v19.8h, v9.8h+ zip2 v3.8h, v19.8h, v9.8h+ smlal2 v23.4s, v12.8h, v15.8h+ smlal v26.4s, v6.4h, v20.4h+ uzp1 v5.8h, v18.8h, v8.8h+ uzp2 v21.8h, v14.8h, v10.8h+ smlal v26.4s, v16.4h, v30.4h+ str q25, [x0], #0x20+ mul v29.8h, v5.8h, v2.8h+ uzp1 v24.8h, v14.8h, v10.8h+ stur q3, [x0, #-0x10]+ smlal v26.4s, v12.4h, v15.4h+ ld1 { v15.8h }, [x6], #16+ ldr q28, [x1, #0x10]+ ldr q11, [x1], #0x20+ ldr q13, [x5], #0x20+ ldur q27, [x4, #-0x10]+ smlal2 v8.4s, v29.8h, v0.8h+ ldur q22, [x5, #-0x10]+ smlal v18.4s, v29.4h, v0.4h+ uzp1 v4.8h, v26.8h, v23.8h+ uzp1 v1.8h, v11.8h, v28.8h+ uzp2 v6.8h, v11.8h, v28.8h+ uzp1 v16.8h, v7.8h, v27.8h+ mul v31.8h, v4.8h, v2.8h+ uzp2 v17.8h, v13.8h, v22.8h+ ld1 { v20.8h }, [x3], #16+ uzp2 v9.8h, v18.8h, v8.8h+ smull2 v8.4s, v1.8h, v21.8h+ uzp1 v30.8h, v13.8h, v22.8h+ smlal2 v8.4s, v6.8h, v24.8h+ smlal2 v8.4s, v16.8h, v17.8h+ uzp2 v12.8h, v7.8h, v27.8h+ smlal v26.4s, v31.4h, v0.4h+ smlal2 v23.4s, v31.8h, v0.8h+ smull v18.4s, v1.4h, v21.4h+ smlal v18.4s, v6.4h, v24.4h+ smlal2 v8.4s, v12.8h, v30.8h+ uzp2 v19.8h, v26.8h, v23.8h+ smull2 v23.4s, v1.8h, v24.8h+ smull v26.4s, v1.4h, v24.4h+ subs x13, x13, #0x1+ cbnz x13, Lmlk_polyvec_basemul_acc_montgomery_cached_k2_loop_start+ smlal v26.4s, v6.4h, v20.4h+ smlal2 v23.4s, v6.8h, v20.8h+ smlal v26.4s, v16.4h, v30.4h+ smlal2 v23.4s, v16.8h, v30.8h+ smlal v26.4s, v12.4h, v15.4h+ smlal2 v23.4s, v12.8h, v15.8h+ smlal v18.4s, v16.4h, v17.4h+ smlal v18.4s, v12.4h, v30.4h+ zip1 v12.8h, v19.8h, v9.8h+ str q12, [x0], #0x20+ uzp1 v12.8h, v26.8h, v23.8h+ mul v6.8h, v12.8h, v2.8h+ uzp1 v12.8h, v18.8h, v8.8h+ mul v12.8h, v12.8h, v2.8h+ smlal v26.4s, v6.4h, v0.4h+ smlal2 v23.4s, v6.8h, v0.8h+ smlal2 v8.4s, v12.8h, v0.8h+ smlal v18.4s, v12.4h, v0.4h+ zip2 v12.8h, v19.8h, v9.8h+ uzp2 v6.8h, v26.8h, v23.8h+ stur q12, [x0, #-0x10]+ uzp2 v12.8h, v18.8h, v8.8h+ zip2 v1.8h, v6.8h, v12.8h+ zip1 v12.8h, v6.8h, v12.8h+ str q1, [x0, #0x10]+ str q12, [x0], #0x20+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm)+++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,317 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [NeonNTT]+ * Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1+ * Becker, Hwang, Kannwischer, Yang, Yang+ * https://eprint.iacr.org/2021/986+ */++/*yaml+ Name: polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm+ Description: Re-implementation of asymmetric base multiplication following @[NeonNTT] for k=3+ Signature: void mlk_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm(int16_t r[256], const int16_t a[768], const int16_t b[768], const int16_t b_cache[384])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t r[256]+ description: Output polynomial+ x1:+ type: buffer+ size_bytes: 1536+ permissions: read-only+ c_parameter: const int16_t a[768]+ description: Input polynomial vector a+ x2:+ type: buffer+ size_bytes: 1536+ permissions: read-only+ c_parameter: const int16_t b[768]+ description: Input polynomial vector b+ x3:+ type: buffer+ size_bytes: 768+ permissions: read-only+ c_parameter: const int16_t b_cache[384]+ description: Cached values for b+ Stack:+ bytes: 64+ description: saving callee-saved Neon registers+*/++/* Re-implementation of asymmetric base multiplication following @[NeonNTT] */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 3)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm)+MLK_ASM_FN_SYMBOL(polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ mov w14, #0xd01 // =3329+ dup v0.8h, w14+ mov w14, #0xcff // =3327+ dup v2.8h, w14+ add x4, x1, #0x200+ add x5, x2, #0x200+ add x6, x3, #0x100+ add x7, x1, #0x400+ add x8, x2, #0x400+ add x9, x3, #0x200+ mov x13, #0x10 // =16+ ldr q6, [x7], #0x20+ ldr q19, [x2, #0x10]+ ldr q23, [x1], #0x20+ ldur q14, [x1, #-0x10]+ ldr q17, [x2], #0x20+ ldr q11, [x4, #0x10]+ ldur q28, [x7, #-0x10]+ ld1 { v30.8h }, [x3], #16+ ldr q26, [x4], #0x20+ ldr q16, [x8, #0x10]+ uzp1 v8.8h, v23.8h, v14.8h+ ldr q22, [x5, #0x10]+ ldr q18, [x5], #0x20+ uzp1 v20.8h, v17.8h, v19.8h+ uzp2 v24.8h, v23.8h, v14.8h+ ldr q31, [x8], #0x20+ smull2 v4.4s, v8.8h, v20.8h+ uzp1 v25.8h, v26.8h, v11.8h+ smull v13.4s, v8.4h, v20.4h+ ld1 { v23.8h }, [x6], #16+ uzp1 v1.8h, v18.8h, v22.8h+ smlal v13.4s, v24.4h, v30.4h+ smlal2 v4.4s, v24.8h, v30.8h+ uzp2 v5.8h, v26.8h, v11.8h+ smlal2 v4.4s, v25.8h, v1.8h+ uzp1 v29.8h, v6.8h, v28.8h+ smlal2 v4.4s, v5.8h, v23.8h+ ld1 { v7.8h }, [x9], #16+ smlal v13.4s, v25.4h, v1.4h+ uzp2 v17.8h, v17.8h, v19.8h+ uzp1 v27.8h, v31.8h, v16.8h+ smlal v13.4s, v5.4h, v23.4h+ uzp2 v22.8h, v18.8h, v22.8h+ smull v18.4s, v8.4h, v17.4h+ uzp2 v28.8h, v6.8h, v28.8h+ smlal v13.4s, v29.4h, v27.4h+ smlal2 v4.4s, v29.8h, v27.8h+ uzp2 v26.8h, v31.8h, v16.8h+ smlal2 v4.4s, v28.8h, v7.8h+ ldr q3, [x7, #0x10]+ smlal v13.4s, v28.4h, v7.4h+ ldr q7, [x1], #0x20+ smlal v18.4s, v24.4h, v20.4h+ ldr q15, [x2], #0x20+ smlal v18.4s, v25.4h, v22.4h+ smull2 v8.4s, v8.8h, v17.8h+ ldur q17, [x1, #-0x10]+ uzp1 v23.8h, v13.8h, v4.8h+ smlal v18.4s, v5.4h, v1.4h+ smlal2 v8.4s, v24.8h, v20.8h+ ld1 { v16.8h }, [x3], #16+ mul v23.8h, v23.8h, v2.8h+ ldr q19, [x5, #0x10]+ ldr q14, [x4, #0x10]+ ldr q11, [x4], #0x20+ ldur q20, [x2, #-0x10]+ smlal2 v8.4s, v25.8h, v22.8h+ smlal2 v8.4s, v5.8h, v1.8h+ ldr q22, [x5], #0x20+ uzp1 v1.8h, v7.8h, v17.8h+ smlal v18.4s, v29.4h, v26.4h+ smlal v13.4s, v23.4h, v0.4h+ uzp2 v31.8h, v11.8h, v14.8h+ uzp1 v21.8h, v15.8h, v20.8h+ smlal2 v4.4s, v23.8h, v0.8h+ ld1 { v9.8h }, [x6], #16+ smlal v18.4s, v28.4h, v27.4h+ smlal2 v8.4s, v29.8h, v26.8h+ ldr q25, [x7], #0x20+ smull v26.4s, v1.4h, v21.4h+ uzp1 v24.8h, v22.8h, v19.8h+ smlal2 v8.4s, v28.8h, v27.8h+ uzp2 v28.8h, v7.8h, v17.8h+ uzp1 v29.8h, v11.8h, v14.8h+ smull2 v23.4s, v1.8h, v21.8h+ ldr q27, [x8], #0x20+ smlal2 v23.4s, v28.8h, v16.8h+ ldur q11, [x8, #-0x10]+ smlal2 v23.4s, v29.8h, v24.8h+ uzp2 v7.8h, v13.8h, v4.8h+ uzp2 v19.8h, v22.8h, v19.8h+ ld1 { v4.8h }, [x9], #16+ smlal2 v23.4s, v31.8h, v9.8h+ uzp1 v13.8h, v25.8h, v3.8h+ uzp1 v14.8h, v18.8h, v8.8h+ smlal v26.4s, v28.4h, v16.4h+ uzp2 v17.8h, v27.8h, v11.8h+ uzp2 v20.8h, v15.8h, v20.8h+ mul v14.8h, v14.8h, v2.8h+ sub x13, x13, #0x2++Lmlk_polyvec_basemul_acc_montgomery_cached_k3_loop_start:+ uzp1 v6.8h, v27.8h, v11.8h+ smlal v26.4s, v29.4h, v24.4h+ uzp2 v16.8h, v25.8h, v3.8h+ smlal v26.4s, v31.4h, v9.4h+ ldr q3, [x7, #0x10]+ smlal v26.4s, v13.4h, v6.4h+ smlal2 v8.4s, v14.8h, v0.8h+ ldr q27, [x8], #0x20+ smlal v18.4s, v14.4h, v0.4h+ ldr q25, [x7], #0x20+ smlal2 v23.4s, v13.8h, v6.8h+ ldr q11, [x1], #0x20+ smlal2 v23.4s, v16.8h, v4.8h+ smlal v26.4s, v16.4h, v4.4h+ ldur q22, [x1, #-0x10]+ uzp2 v30.8h, v18.8h, v8.8h+ smull v18.4s, v1.4h, v20.4h+ smlal v18.4s, v28.4h, v21.4h+ ldr q14, [x2], #0x20+ smlal v18.4s, v29.4h, v19.4h+ zip1 v5.8h, v7.8h, v30.8h+ uzp1 v4.8h, v26.8h, v23.8h+ smull2 v8.4s, v1.8h, v20.8h+ zip2 v10.8h, v7.8h, v30.8h+ smlal v18.4s, v31.4h, v24.4h+ mul v12.8h, v4.8h, v2.8h+ ldr q4, [x5, #0x10]+ ldr q20, [x4, #0x10]+ ldr q1, [x4], #0x20+ ldur q30, [x2, #-0x10]+ smlal2 v8.4s, v28.8h, v21.8h+ smlal2 v8.4s, v29.8h, v19.8h+ ldr q19, [x5], #0x20+ smlal2 v8.4s, v31.8h, v24.8h+ ld1 { v15.8h }, [x3], #16+ uzp2 v31.8h, v1.8h, v20.8h+ smlal v26.4s, v12.4h, v0.4h+ smlal2 v23.4s, v12.8h, v0.8h+ uzp1 v21.8h, v14.8h, v30.8h+ uzp1 v29.8h, v1.8h, v20.8h+ uzp1 v1.8h, v11.8h, v22.8h+ smlal2 v8.4s, v13.8h, v17.8h+ ld1 { v9.8h }, [x6], #16+ smlal v18.4s, v13.4h, v17.4h+ uzp1 v24.8h, v19.8h, v4.8h+ uzp2 v7.8h, v26.8h, v23.8h+ smull v26.4s, v1.4h, v21.4h+ smlal v18.4s, v16.4h, v6.4h+ uzp2 v19.8h, v19.8h, v4.8h+ smlal2 v8.4s, v16.8h, v6.8h+ uzp2 v28.8h, v11.8h, v22.8h+ smull2 v23.4s, v1.8h, v21.8h+ uzp1 v13.8h, v25.8h, v3.8h+ smlal2 v23.4s, v28.8h, v15.8h+ ldur q11, [x8, #-0x10]+ smlal2 v23.4s, v29.8h, v24.8h+ ld1 { v4.8h }, [x9], #16+ smlal2 v23.4s, v31.8h, v9.8h+ uzp1 v12.8h, v18.8h, v8.8h+ uzp2 v20.8h, v14.8h, v30.8h+ smlal v26.4s, v28.4h, v15.4h+ str q5, [x0], #0x20+ mul v14.8h, v12.8h, v2.8h+ stur q10, [x0, #-0x10]+ uzp2 v17.8h, v27.8h, v11.8h+ subs x13, x13, #0x1+ cbnz x13, Lmlk_polyvec_basemul_acc_montgomery_cached_k3_loop_start+ uzp2 v3.8h, v25.8h, v3.8h+ smull2 v16.4s, v1.8h, v20.8h+ smull v25.4s, v1.4h, v20.4h+ uzp1 v22.8h, v27.8h, v11.8h+ smlal2 v16.4s, v28.8h, v21.8h+ smlal v25.4s, v28.4h, v21.4h+ smlal2 v16.4s, v29.8h, v19.8h+ smlal v25.4s, v29.4h, v19.4h+ smlal2 v16.4s, v31.8h, v24.8h+ smlal v25.4s, v31.4h, v24.4h+ smlal v25.4s, v13.4h, v17.4h+ smlal2 v16.4s, v13.8h, v17.8h+ smlal2 v16.4s, v3.8h, v22.8h+ smlal v25.4s, v3.4h, v22.4h+ smlal2 v23.4s, v13.8h, v22.8h+ smlal v26.4s, v29.4h, v24.4h+ smlal v26.4s, v31.4h, v9.4h+ smlal v26.4s, v13.4h, v22.4h+ uzp1 v10.8h, v25.8h, v16.8h+ smlal2 v23.4s, v3.8h, v4.8h+ smlal v26.4s, v3.4h, v4.4h+ mul v13.8h, v10.8h, v2.8h+ smlal v18.4s, v14.4h, v0.4h+ smlal2 v8.4s, v14.8h, v0.8h+ uzp1 v3.8h, v26.8h, v23.8h+ mul v24.8h, v3.8h, v2.8h+ uzp2 v17.8h, v18.8h, v8.8h+ smlal v25.4s, v13.4h, v0.4h+ smlal2 v16.4s, v13.8h, v0.8h+ zip1 v21.8h, v7.8h, v17.8h+ zip2 v20.8h, v7.8h, v17.8h+ smlal2 v23.4s, v24.8h, v0.8h+ str q21, [x0], #0x20+ smlal v26.4s, v24.4h, v0.4h+ uzp2 v13.8h, v25.8h, v16.8h+ stur q20, [x0, #-0x10]+ uzp2 v23.8h, v26.8h, v23.8h+ zip1 v18.8h, v23.8h, v13.8h+ zip2 v13.8h, v23.8h, v13.8h+ str q18, [x0], #0x20+ stur q13, [x0, #-0x10]+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm)++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 3) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,371 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [NeonNTT]+ * Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1+ * Becker, Hwang, Kannwischer, Yang, Yang+ * https://eprint.iacr.org/2021/986+ */++/*yaml+ Name: polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm+ Description: Re-implementation of asymmetric base multiplication following @[NeonNTT] for k=4+ Signature: void mlk_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm(int16_t r[256], const int16_t a[1024], const int16_t b[1024], const int16_t b_cache[512])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t r[256]+ description: Output polynomial+ x1:+ type: buffer+ size_bytes: 2048+ permissions: read-only+ c_parameter: const int16_t a[1024]+ description: Input polynomial vector a+ x2:+ type: buffer+ size_bytes: 2048+ permissions: read-only+ c_parameter: const int16_t b[1024]+ description: Input polynomial vector b+ x3:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int16_t b_cache[512]+ description: Cached values for b+ Stack:+ bytes: 64+ description: saving callee-saved Neon registers+*/++/* Re-implementation of asymmetric base multiplication following @[NeonNTT] */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm)+MLK_ASM_FN_SYMBOL(polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x40+ .cfi_adjust_cfa_offset 0x40+ stp d8, d9, [sp]+ .cfi_rel_offset d8, 0x0+ .cfi_rel_offset d9, 0x8+ stp d10, d11, [sp, #0x10]+ .cfi_rel_offset d10, 0x10+ .cfi_rel_offset d11, 0x18+ stp d12, d13, [sp, #0x20]+ .cfi_rel_offset d12, 0x20+ .cfi_rel_offset d13, 0x28+ stp d14, d15, [sp, #0x30]+ .cfi_rel_offset d14, 0x30+ .cfi_rel_offset d15, 0x38+ mov w14, #0xd01 // =3329+ dup v0.8h, w14+ mov w14, #0xcff // =3327+ dup v2.8h, w14+ add x4, x1, #0x200+ add x5, x2, #0x200+ add x6, x3, #0x100+ add x7, x1, #0x400+ add x8, x2, #0x400+ add x9, x3, #0x200+ add x10, x1, #0x600+ add x11, x2, #0x600+ add x12, x3, #0x300+ mov x13, #0x10 // =16+ ldr q28, [x1], #0x20+ ldur q5, [x1, #-0x10]+ ldr q31, [x2], #0x20+ ldur q27, [x2, #-0x10]+ ldr q7, [x5], #0x20+ ldr q10, [x4], #0x20+ ldur q18, [x5, #-0x10]+ ldur q9, [x4, #-0x10]+ uzp1 v11.8h, v28.8h, v5.8h+ uzp2 v19.8h, v28.8h, v5.8h+ uzp2 v4.8h, v31.8h, v27.8h+ uzp1 v1.8h, v31.8h, v27.8h+ ldr q29, [x7], #0x20+ ldr q28, [x8, #0x10]+ uzp1 v24.8h, v10.8h, v9.8h+ uzp1 v17.8h, v7.8h, v18.8h+ uzp2 v7.8h, v7.8h, v18.8h+ ldr q21, [x8], #0x20+ uzp2 v27.8h, v10.8h, v9.8h+ ldur q6, [x7, #-0x10]+ smull v18.4s, v11.4h, v4.4h+ ld1 { v9.8h }, [x3], #16+ smull2 v8.4s, v11.8h, v4.8h+ ldr q16, [x11], #0x20+ smlal2 v8.4s, v19.8h, v1.8h+ ldur q14, [x11, #-0x10]+ smlal v18.4s, v19.4h, v1.4h+ uzp1 v10.8h, v21.8h, v28.8h+ smlal v18.4s, v24.4h, v7.4h+ ldr q4, [x10], #0x20+ smlal2 v8.4s, v24.8h, v7.8h+ ld1 { v12.8h }, [x6], #16+ smull2 v23.4s, v11.8h, v1.8h+ uzp2 v13.8h, v29.8h, v6.8h+ smull v26.4s, v11.4h, v1.4h+ uzp1 v29.8h, v29.8h, v6.8h+ smlal v26.4s, v19.4h, v9.4h+ ldur q15, [x10, #-0x10]+ smlal2 v23.4s, v19.8h, v9.8h+ uzp2 v9.8h, v21.8h, v28.8h+ smlal v18.4s, v27.4h, v17.4h+ uzp2 v6.8h, v16.8h, v14.8h+ uzp1 v21.8h, v16.8h, v14.8h+ smlal2 v8.4s, v27.8h, v17.8h+ smlal2 v8.4s, v29.8h, v9.8h+ uzp1 v30.8h, v4.8h, v15.8h+ uzp2 v16.8h, v4.8h, v15.8h+ smlal v18.4s, v29.4h, v9.4h+ smlal2 v8.4s, v13.8h, v10.8h+ ld1 { v15.8h }, [x9], #16+ smlal v18.4s, v13.4h, v10.4h+ ldr q11, [x4], #0x20+ smlal v18.4s, v30.4h, v6.4h+ ldr q7, [x2], #0x20+ smlal2 v8.4s, v30.8h, v6.8h+ ld1 { v9.8h }, [x12], #16+ smlal2 v23.4s, v24.8h, v17.8h+ ldur q4, [x2, #-0x10]+ smlal v26.4s, v24.4h, v17.4h+ ldur q25, [x4, #-0x10]+ smlal2 v8.4s, v16.8h, v21.8h+ ldr q5, [x5], #0x20+ smlal v18.4s, v16.4h, v21.4h+ ldur q22, [x5, #-0x10]+ smlal v26.4s, v27.4h, v12.4h+ ldr q19, [x1, #0x10]+ smlal v26.4s, v29.4h, v10.4h+ ld1 { v20.8h }, [x3], #16+ smlal v26.4s, v13.4h, v15.4h+ uzp1 v24.8h, v7.8h, v4.8h+ smlal2 v23.4s, v27.8h, v12.8h+ uzp1 v28.8h, v18.8h, v8.8h+ smlal v26.4s, v30.4h, v21.4h+ uzp2 v27.8h, v11.8h, v25.8h+ smlal2 v23.4s, v29.8h, v10.8h+ uzp2 v31.8h, v7.8h, v4.8h+ smlal2 v23.4s, v13.8h, v15.8h+ uzp1 v14.8h, v5.8h, v22.8h+ uzp1 v17.8h, v11.8h, v25.8h+ smlal v26.4s, v16.4h, v9.4h+ mul v29.8h, v28.8h, v2.8h+ sub x13, x13, #0x2++Lmlk_polyvec_basemul_acc_montgomery_cached_k4_loop_start:+ smlal2 v23.4s, v30.8h, v21.8h+ ldr q11, [x1], #0x20+ uzp2 v15.8h, v5.8h, v22.8h+ smlal v18.4s, v29.4h, v0.4h+ ldr q12, [x7], #0x20+ smlal2 v8.4s, v29.8h, v0.8h+ ldur q3, [x7, #-0x10]+ ldr q21, [x8], #0x20+ uzp1 v29.8h, v11.8h, v19.8h+ ldur q13, [x8, #-0x10]+ uzp2 v5.8h, v11.8h, v19.8h+ smlal2 v23.4s, v16.8h, v9.8h+ uzp2 v28.8h, v18.8h, v8.8h+ smull2 v8.4s, v29.8h, v31.8h+ smlal2 v8.4s, v5.8h, v24.8h+ uzp1 v7.8h, v12.8h, v3.8h+ smlal2 v8.4s, v17.8h, v15.8h+ uzp2 v11.8h, v21.8h, v13.8h+ uzp1 v4.8h, v26.8h, v23.8h+ smlal2 v8.4s, v27.8h, v14.8h+ smlal2 v8.4s, v7.8h, v11.8h+ mul v6.8h, v4.8h, v2.8h+ ldr q19, [x11], #0x20+ uzp2 v25.8h, v12.8h, v3.8h+ ldr q12, [x10], #0x20+ smull v18.4s, v29.4h, v31.4h+ ldur q3, [x10, #-0x10]+ smlal v18.4s, v5.4h, v24.4h+ uzp1 v4.8h, v21.8h, v13.8h+ smlal v18.4s, v17.4h, v15.4h+ ldur q13, [x11, #-0x10]+ ld1 { v1.8h }, [x6], #16+ smlal v26.4s, v6.4h, v0.4h+ smlal2 v23.4s, v6.8h, v0.8h+ ld1 { v10.8h }, [x9], #16+ smlal v18.4s, v27.4h, v14.4h+ uzp1 v30.8h, v12.8h, v3.8h+ smlal2 v8.4s, v25.8h, v4.8h+ uzp2 v31.8h, v19.8h, v13.8h+ smlal v18.4s, v7.4h, v11.4h+ ld1 { v9.8h }, [x12], #16+ smlal v18.4s, v25.4h, v4.4h+ uzp1 v21.8h, v19.8h, v13.8h+ uzp2 v16.8h, v12.8h, v3.8h+ smlal v18.4s, v30.4h, v31.4h+ smlal2 v8.4s, v30.8h, v31.8h+ uzp2 v31.8h, v26.8h, v23.8h+ smlal2 v8.4s, v16.8h, v21.8h+ smlal v18.4s, v16.4h, v21.4h+ zip1 v15.8h, v31.8h, v28.8h+ ldr q19, [x1, #0x10]+ smull2 v23.4s, v29.8h, v24.8h+ smull v26.4s, v29.4h, v24.4h+ ldr q3, [x2, #0x10]+ smlal v26.4s, v5.4h, v20.4h+ ldr q11, [x2], #0x20+ uzp1 v6.8h, v18.8h, v8.8h+ smlal v26.4s, v17.4h, v14.4h+ smlal v26.4s, v27.4h, v1.4h+ zip2 v13.8h, v31.8h, v28.8h+ smlal v26.4s, v7.4h, v4.4h+ str q15, [x0], #0x20+ smlal v26.4s, v25.4h, v10.4h+ stur q13, [x0, #-0x10]+ mul v29.8h, v6.8h, v2.8h+ uzp1 v24.8h, v11.8h, v3.8h+ uzp2 v31.8h, v11.8h, v3.8h+ ldr q11, [x4], #0x20+ smlal2 v23.4s, v5.8h, v20.8h+ ldur q28, [x4, #-0x10]+ smlal2 v23.4s, v17.8h, v14.8h+ ldr q5, [x5], #0x20+ smlal2 v23.4s, v27.8h, v1.8h+ ldur q22, [x5, #-0x10]+ smlal v26.4s, v30.4h, v21.4h+ ld1 { v20.8h }, [x3], #16+ smlal v26.4s, v16.4h, v9.4h+ uzp1 v17.8h, v11.8h, v28.8h+ smlal2 v23.4s, v7.8h, v4.8h+ uzp2 v27.8h, v11.8h, v28.8h+ smlal2 v23.4s, v25.8h, v10.8h+ uzp1 v14.8h, v5.8h, v22.8h+ subs x13, x13, #0x1+ cbnz x13, Lmlk_polyvec_basemul_acc_montgomery_cached_k4_loop_start+ smlal v18.4s, v29.4h, v0.4h+ ldr q11, [x1], #0x20+ uzp2 v28.8h, v5.8h, v22.8h+ smlal2 v23.4s, v30.8h, v21.8h+ smlal2 v8.4s, v29.8h, v0.8h+ ldr q15, [x8, #0x10]+ smlal2 v23.4s, v16.8h, v9.8h+ ldr q21, [x8], #0x20+ uzp1 v22.8h, v11.8h, v19.8h+ uzp2 v12.8h, v11.8h, v19.8h+ ldr q1, [x7, #0x10]+ ld1 { v6.8h }, [x6], #16+ uzp2 v3.8h, v18.8h, v8.8h+ smull v9.4s, v22.4h, v31.4h+ smull2 v18.4s, v22.8h, v31.8h+ ldr q16, [x7], #0x20+ smull v19.4s, v22.4h, v24.4h+ uzp1 v30.8h, v21.8h, v15.8h+ uzp2 v25.8h, v21.8h, v15.8h+ smull2 v8.4s, v22.8h, v24.8h+ smlal v19.4s, v12.4h, v20.4h+ ldr q13, [x10, #0x10]+ smlal2 v8.4s, v12.8h, v20.8h+ uzp1 v29.8h, v16.8h, v1.8h+ smlal2 v18.4s, v12.8h, v24.8h+ ldr q5, [x10], #0x20+ smlal v9.4s, v12.4h, v24.4h+ ldr q4, [x11], #0x20+ smlal v9.4s, v17.4h, v28.4h+ ldur q22, [x11, #-0x10]+ smlal2 v18.4s, v17.8h, v28.8h+ uzp2 v16.8h, v16.8h, v1.8h+ smlal v19.4s, v17.4h, v14.4h+ ld1 { v28.8h }, [x9], #16+ smlal2 v8.4s, v17.8h, v14.8h+ uzp1 v7.8h, v5.8h, v13.8h+ smlal v9.4s, v27.4h, v14.4h+ uzp1 v17.8h, v4.8h, v22.8h+ smlal2 v18.4s, v27.8h, v14.8h+ uzp2 v12.8h, v5.8h, v13.8h+ uzp2 v21.8h, v4.8h, v22.8h+ smlal v19.4s, v27.4h, v6.4h+ smlal2 v8.4s, v27.8h, v6.8h+ ld1 { v15.8h }, [x12], #16+ smlal v19.4s, v29.4h, v30.4h+ uzp1 v20.8h, v26.8h, v23.8h+ smlal v9.4s, v29.4h, v25.4h+ smlal2 v18.4s, v29.8h, v25.8h+ smlal2 v8.4s, v29.8h, v30.8h+ smlal v19.4s, v16.4h, v28.4h+ smlal2 v8.4s, v16.8h, v28.8h+ smlal2 v18.4s, v16.8h, v30.8h+ smlal v9.4s, v16.4h, v30.4h+ smlal v9.4s, v7.4h, v21.4h+ smlal2 v18.4s, v7.8h, v21.8h+ smlal2 v8.4s, v7.8h, v17.8h+ smlal v19.4s, v7.4h, v17.4h+ smlal v19.4s, v12.4h, v15.4h+ smlal2 v8.4s, v12.8h, v15.8h+ smlal2 v18.4s, v12.8h, v17.8h+ smlal v9.4s, v12.4h, v17.4h+ mul v6.8h, v20.8h, v2.8h+ uzp1 v4.8h, v19.8h, v8.8h+ mul v17.8h, v4.8h, v2.8h+ uzp1 v12.8h, v9.8h, v18.8h+ smlal v26.4s, v6.4h, v0.4h+ mul v21.8h, v12.8h, v2.8h+ smlal2 v23.4s, v6.8h, v0.8h+ smlal2 v8.4s, v17.8h, v0.8h+ smlal v19.4s, v17.4h, v0.4h+ smlal2 v18.4s, v21.8h, v0.8h+ uzp2 v23.8h, v26.8h, v23.8h+ smlal v9.4s, v21.4h, v0.4h+ zip2 v12.8h, v23.8h, v3.8h+ zip1 v22.8h, v23.8h, v3.8h+ uzp2 v14.8h, v19.8h, v8.8h+ uzp2 v18.8h, v9.8h, v18.8h+ str q12, [x0, #0x10]+ str q22, [x0], #0x20+ zip2 v24.8h, v14.8h, v18.8h+ zip1 v21.8h, v14.8h, v18.8h+ str q24, [x0, #0x10]+ str q21, [x0], #0x20+ ldp d8, d9, [sp]+ .cfi_restore d8+ .cfi_restore d9+ ldp d10, d11, [sp, #0x10]+ .cfi_restore d10+ .cfi_restore d11+ ldp d12, d13, [sp, #0x20]+ .cfi_restore d12+ .cfi_restore d13+ ldp d14, d15, [sp, #0x30]+ .cfi_restore d14+ .cfi_restore d15+ add sp, sp, #0x40+ .cfi_adjust_cfa_offset -0x40+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm)++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,226 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*yaml+ Name: rej_uniform_aarch64_asm+ Description: Run rejection sampling on uniform random bytes to generate uniform random integers mod q+ Signature: uint64_t mlk_rej_uniform_aarch64_asm(int16_t r[256], const uint8_t *buf, unsigned buflen, const uint8_t table[4096])+ ABI:+ Architecture: aarch64+ CallingConvention: AAPCS64+ Features: [NEON]+ x0:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t r[256]+ description: Output buffer+ x1:+ type: buffer+ size_bytes: x2+ permissions: read-only+ c_parameter: const uint8_t *buf+ description: Input buffer+ x2:+ type: scalar+ c_parameter: unsigned buflen+ description: Length of input buffer (must be multiple of 24)+ test_with: 504 # MLKEM_GEN_MATRIX_NBLOCKS * MLK_XOF_RATE+ x3:+ type: buffer+ size_bytes: 4096+ permissions: read-only+ c_parameter: const uint8_t table[4096]+ description: Lookup table+ Stack:+ bytes: 576+ description: register preservation and temporary storage+*/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_AARCH64) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/aarch64_opt/src/mlkem_rej_uniform_aarch64_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(rej_uniform_aarch64_asm)+MLK_ASM_FN_SYMBOL(rej_uniform_aarch64_asm)++ .cfi_startproc+ sub sp, sp, #0x240+ .cfi_adjust_cfa_offset 0x240+ mov x7, #0x1 // =1+ movk x7, #0x2, lsl #16+ movk x7, #0x4, lsl #32+ movk x7, #0x8, lsl #48+ mov v31.d[0], x7+ mov x7, #0x10 // =16+ movk x7, #0x20, lsl #16+ movk x7, #0x40, lsl #32+ movk x7, #0x80, lsl #48+ mov v31.d[1], x7+ mov w11, #0xd01 // =3329+ dup v30.8h, w11+ mov x8, sp+ mov x7, x8+ mov x11, #0x0 // =0+ eor v16.16b, v16.16b, v16.16b++Lmlk_rej_uniform_initial_zero:+ str q16, [x7], #0x40+ stur q16, [x7, #-0x30]+ stur q16, [x7, #-0x20]+ stur q16, [x7, #-0x10]+ add x11, x11, #0x20+ cmp x11, #0x100+ b.lt Lmlk_rej_uniform_initial_zero+ mov x7, x8+ mov x9, #0x0 // =0+ mov x4, #0x100 // =256+ cmp x2, #0x30+ b.lo Lmlk_rej_uniform_loop48_end++Lmlk_rej_uniform_loop48:+ cmp x9, x4+ b.hs Lmlk_rej_uniform_memory_copy+ sub x2, x2, #0x30+ ld3 { v0.16b, v1.16b, v2.16b }, [x1], #48+ zip1 v4.16b, v0.16b, v1.16b+ zip2 v5.16b, v0.16b, v1.16b+ zip1 v6.16b, v1.16b, v2.16b+ zip2 v7.16b, v1.16b, v2.16b+ bic v4.8h, #0xf0, lsl #8+ bic v5.8h, #0xf0, lsl #8+ ushr v6.8h, v6.8h, #0x4+ ushr v7.8h, v7.8h, #0x4+ zip1 v16.8h, v4.8h, v6.8h+ zip2 v17.8h, v4.8h, v6.8h+ zip1 v18.8h, v5.8h, v7.8h+ zip2 v19.8h, v5.8h, v7.8h+ cmhi v4.8h, v30.8h, v16.8h+ cmhi v5.8h, v30.8h, v17.8h+ cmhi v6.8h, v30.8h, v18.8h+ cmhi v7.8h, v30.8h, v19.8h+ and v4.16b, v4.16b, v31.16b+ and v5.16b, v5.16b, v31.16b+ and v6.16b, v6.16b, v31.16b+ and v7.16b, v7.16b, v31.16b+ uaddlv s20, v4.8h+ uaddlv s21, v5.8h+ uaddlv s22, v6.8h+ uaddlv s23, v7.8h+ fmov w12, s20+ fmov w13, s21+ fmov w14, s22+ fmov w15, s23+ ldr q24, [x3, x12, lsl #4]+ ldr q25, [x3, x13, lsl #4]+ ldr q26, [x3, x14, lsl #4]+ ldr q27, [x3, x15, lsl #4]+ cnt v4.16b, v4.16b+ cnt v5.16b, v5.16b+ cnt v6.16b, v6.16b+ cnt v7.16b, v7.16b+ uaddlv s20, v4.8h+ uaddlv s21, v5.8h+ uaddlv s22, v6.8h+ uaddlv s23, v7.8h+ fmov w12, s20+ fmov w13, s21+ fmov w14, s22+ fmov w15, s23+ tbl v16.16b, { v16.16b }, v24.16b+ tbl v17.16b, { v17.16b }, v25.16b+ tbl v18.16b, { v18.16b }, v26.16b+ tbl v19.16b, { v19.16b }, v27.16b+ st1 { v16.8h }, [x7]+ add x7, x7, x12, lsl #1+ st1 { v17.8h }, [x7]+ add x7, x7, x13, lsl #1+ st1 { v18.8h }, [x7]+ add x7, x7, x14, lsl #1+ st1 { v19.8h }, [x7]+ add x7, x7, x15, lsl #1+ add x12, x12, x13+ add x14, x14, x15+ add x9, x9, x12+ add x9, x9, x14+ cmp x2, #0x30+ b.hs Lmlk_rej_uniform_loop48++Lmlk_rej_uniform_loop48_end:+ cmp x9, x4+ b.hs Lmlk_rej_uniform_memory_copy+ cmp x2, #0x18+ b.lo Lmlk_rej_uniform_memory_copy+ ld3 { v0.8b, v1.8b, v2.8b }, [x1], #24+ zip1 v4.16b, v0.16b, v1.16b+ zip1 v5.16b, v1.16b, v2.16b+ bic v4.8h, #0xf0, lsl #8+ ushr v5.8h, v5.8h, #0x4+ zip1 v16.8h, v4.8h, v5.8h+ zip2 v17.8h, v4.8h, v5.8h+ cmhi v4.8h, v30.8h, v16.8h+ cmhi v5.8h, v30.8h, v17.8h+ and v4.16b, v4.16b, v31.16b+ and v5.16b, v5.16b, v31.16b+ uaddlv s20, v4.8h+ uaddlv s21, v5.8h+ fmov w12, s20+ fmov w13, s21+ ldr q24, [x3, x12, lsl #4]+ ldr q25, [x3, x13, lsl #4]+ cnt v4.16b, v4.16b+ cnt v5.16b, v5.16b+ uaddlv s20, v4.8h+ uaddlv s21, v5.8h+ fmov w12, s20+ fmov w13, s21+ tbl v16.16b, { v16.16b }, v24.16b+ tbl v17.16b, { v17.16b }, v25.16b+ st1 { v16.8h }, [x7]+ add x7, x7, x12, lsl #1+ st1 { v17.8h }, [x7]+ add x9, x9, x12+ add x9, x9, x13++Lmlk_rej_uniform_memory_copy:+ cmp x9, x4+ csel x9, x9, x4, lo+ mov x11, #0x0 // =0+ mov x7, x8++Lmlk_rej_uniform_final_copy:+ ldr q16, [x7], #0x40+ ldur q17, [x7, #-0x30]+ ldur q18, [x7, #-0x20]+ ldur q19, [x7, #-0x10]+ str q16, [x0], #0x40+ stur q17, [x0, #-0x30]+ stur q18, [x0, #-0x20]+ stur q19, [x0, #-0x10]+ add x11, x11, #0x20+ cmp x11, #0x100+ b.lt Lmlk_rej_uniform_final_copy+ mov x0, x9++Lmlk_rej_uniform_return:+ add sp, sp, #0x240+ .cfi_adjust_cfa_offset -0x240+ ret+ .cfi_endproc++MLK_ASM_FN_SIZE(rej_uniform_aarch64_asm)++#endif /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,543 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_AARCH64) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#include "arith_native_aarch64.h"++/*+ * Lookup table used by rejection sampling of the public matrix.+ * See autogen for details.+ */+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_rej_uniform_table[4096] = {+ 255, 255, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */,+ 0, 1, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */,+ 2, 3, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */,+ 0, 1, 2, 3, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */,+ 4, 5, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */,+ 0, 1, 4, 5, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */,+ 2, 3, 4, 5, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */,+ 0, 1, 2, 3, 4, 5, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */,+ 6, 7, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */,+ 0, 1, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */,+ 2, 3, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */,+ 0, 1, 2, 3, 6, 7, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */,+ 4, 5, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */,+ 0, 1, 4, 5, 6, 7, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */,+ 2, 3, 4, 5, 6, 7, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */,+ 8, 9, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */,+ 0, 1, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */,+ 2, 3, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */,+ 0, 1, 2, 3, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */,+ 4, 5, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */,+ 0, 1, 4, 5, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */,+ 2, 3, 4, 5, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */,+ 6, 7, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */,+ 0, 1, 6, 7, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */,+ 2, 3, 6, 7, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */,+ 4, 5, 6, 7, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */,+ 10, 11, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */,+ 0, 1, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */,+ 2, 3, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */,+ 0, 1, 2, 3, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */,+ 4, 5, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */,+ 0, 1, 4, 5, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */,+ 2, 3, 4, 5, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */,+ 6, 7, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */,+ 0, 1, 6, 7, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */,+ 2, 3, 6, 7, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */,+ 4, 5, 6, 7, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */,+ 8, 9, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */,+ 0, 1, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */,+ 2, 3, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */,+ 4, 5, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */,+ 6, 7, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */,+ 12, 13, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */,+ 0, 1, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */,+ 2, 3, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */,+ 0, 1, 2, 3, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */,+ 4, 5, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */,+ 0, 1, 4, 5, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */,+ 2, 3, 4, 5, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */,+ 0, 1, 2, 3, 4, 5, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */,+ 6, 7, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */,+ 0, 1, 6, 7, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */,+ 2, 3, 6, 7, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */,+ 0, 1, 2, 3, 6, 7, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */,+ 4, 5, 6, 7, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */,+ 0, 1, 4, 5, 6, 7, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */,+ 2, 3, 4, 5, 6, 7, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */,+ 8, 9, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */,+ 0, 1, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */,+ 2, 3, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */,+ 0, 1, 2, 3, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */,+ 4, 5, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */,+ 0, 1, 4, 5, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */,+ 2, 3, 4, 5, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */,+ 6, 7, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */,+ 0, 1, 6, 7, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */,+ 2, 3, 6, 7, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */,+ 4, 5, 6, 7, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */,+ 10, 11, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */,+ 0, 1, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */,+ 2, 3, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */,+ 0, 1, 2, 3, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */,+ 4, 5, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */,+ 0, 1, 4, 5, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */,+ 2, 3, 4, 5, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */,+ 6, 7, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */,+ 0, 1, 6, 7, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */,+ 2, 3, 6, 7, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */,+ 4, 5, 6, 7, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */,+ 8, 9, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */,+ 0, 1, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */,+ 2, 3, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */,+ 4, 5, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */,+ 6, 7, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */,+ 14, 15, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */,+ 0, 1, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */,+ 2, 3, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */,+ 0, 1, 2, 3, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */,+ 4, 5, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */,+ 0, 1, 4, 5, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */,+ 2, 3, 4, 5, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */,+ 0, 1, 2, 3, 4, 5, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */,+ 6, 7, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */,+ 0, 1, 6, 7, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */,+ 2, 3, 6, 7, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */,+ 0, 1, 2, 3, 6, 7, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */,+ 4, 5, 6, 7, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */,+ 0, 1, 4, 5, 6, 7, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */,+ 2, 3, 4, 5, 6, 7, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */,+ 8, 9, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */,+ 0, 1, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */,+ 2, 3, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */,+ 0, 1, 2, 3, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */,+ 4, 5, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */,+ 0, 1, 4, 5, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */,+ 2, 3, 4, 5, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */,+ 6, 7, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */,+ 0, 1, 6, 7, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */,+ 2, 3, 6, 7, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */,+ 4, 5, 6, 7, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */,+ 10, 11, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */,+ 0, 1, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */,+ 2, 3, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */,+ 0, 1, 2, 3, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */,+ 4, 5, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */,+ 0, 1, 4, 5, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */,+ 2, 3, 4, 5, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */,+ 6, 7, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */,+ 0, 1, 6, 7, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */,+ 2, 3, 6, 7, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */,+ 4, 5, 6, 7, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */,+ 8, 9, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */,+ 0, 1, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */,+ 2, 3, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */,+ 4, 5, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */,+ 6, 7, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */,+ 12, 13, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */,+ 0, 1, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */,+ 2, 3, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */,+ 0, 1, 2, 3, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */,+ 4, 5, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */,+ 0, 1, 4, 5, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */,+ 2, 3, 4, 5, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */,+ 0, 1, 2, 3, 4, 5, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */,+ 6, 7, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */,+ 0, 1, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */,+ 2, 3, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */,+ 0, 1, 2, 3, 6, 7, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */,+ 4, 5, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */,+ 0, 1, 4, 5, 6, 7, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */,+ 2, 3, 4, 5, 6, 7, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */,+ 8, 9, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */,+ 0, 1, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */,+ 2, 3, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */,+ 0, 1, 2, 3, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */,+ 4, 5, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */,+ 0, 1, 4, 5, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */,+ 2, 3, 4, 5, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */,+ 6, 7, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */,+ 0, 1, 6, 7, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */,+ 2, 3, 6, 7, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */,+ 4, 5, 6, 7, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */,+ 10, 11, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */,+ 0, 1, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */,+ 2, 3, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */,+ 0, 1, 2, 3, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */,+ 4, 5, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */,+ 0, 1, 4, 5, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */,+ 2, 3, 4, 5, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */,+ 6, 7, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */,+ 0, 1, 6, 7, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */,+ 2, 3, 6, 7, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */,+ 4, 5, 6, 7, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */,+ 8, 9, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */,+ 0, 1, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */,+ 2, 3, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */,+ 4, 5, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */,+ 6, 7, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */,+};++#else /* MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(aarch64_rej_uniform_table)++#endif /* !(MLK_ARITH_BACKEND_AARCH64 && !MLK_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,651 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#ifndef MLK_NATIVE_API_H+#define MLK_NATIVE_API_H+/*+ * Native arithmetic interface+ *+ * This header is primarily for documentation purposes.+ * It should not be included by backend implementations.+ *+ * To ensure consistency with backends, the header will be+ * included automatically after inclusion of the active+ * backend, to ensure consistency of function signatures,+ * and run sanity checks.+ */++#include "../cbmc.h"+#include "../common.h"++/* Backends must return MLK_NATIVE_FUNC_SUCCESS upon success. */+#define MLK_NATIVE_FUNC_SUCCESS (0)+/* Backends may return MLK_NATIVE_FUNC_FALLBACK to signal to the frontend that+ * the target/parameters are unsupported; typically, this would be because of+ * dependencies on CPU features not detected on the host CPU. In this case,+ * the frontend falls back to the default C implementation. */+#define MLK_NATIVE_FUNC_FALLBACK (-1)+++/* Absolute exclusive upper bound for the output of the inverse NTT+ *+ * NOTE: This is the same bound as in poly.h and has to be kept+ * in sync. */+#define MLK_INVNTT_BOUND (8 * MLKEM_Q)++/* Absolute exclusive upper bound for the output of the forward NTT+ *+ * NOTE: This is the same bound as in poly.h and has to be kept+ * in sync. */+#define MLK_NTT_BOUND (8 * MLKEM_Q)++/*+ * This is the C<->native interface allowing for the drop-in of+ * native code for performance critical arithmetic components of ML-KEM.+ *+ * A _backend_ is a specific implementation of (part of) this interface.+ *+ * To add a function to a backend, define MLK_USE_NATIVE_XXX and+ * implement `static inline xxx(...)` in the profile header.+ *+ * The only exception is MLK_USE_NATIVE_NTT_CUSTOM_ORDER. This option can+ * be set if there are native implementations for all of NTT, invNTT, and+ * base multiplication, and allows the native implementation to use a+ * custom order of polynomial coefficients in NTT domain -- the use of such+ * custom order is not an implementation-detail since the public matrix+ * is generated in NTT domain. In this case, a permutation function+ * mlk_poly_permute_bitrev_to_custom() needs to be provided that permutes+ * polynomials in NTT domain from bitreversed to the custom order.+ */++/*+ * Those functions are meant to be trivial wrappers around the chosen native+ * implementation. The are static inline to avoid unnecessary calls.+ * The macro before each declaration controls whether a native+ * implementation is present.+ */++#if defined(MLK_USE_NATIVE_NTT)+/**+ * Compute the negacyclic number-theoretic transform (NTT) of a polynomial+ * in place.+ *+ * The input polynomial is assumed to be in normal order. The output+ * polynomial is in bitreversed order, or of a custom order if+ * MLK_USE_NATIVE_NTT_CUSTOM_ORDER is set. See the documentation of+ * MLK_USE_NATIVE_NTT_CUSTOM_ORDER for more information.+ *+ * @param[in,out] p Input/output polynomial.+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_ntt_native(int16_t p[MLKEM_N])+__contract__(+ requires(memory_no_alias(p, sizeof(int16_t) * MLKEM_N))+ requires(array_abs_bound(p, 0, MLKEM_N, MLKEM_Q))+ assigns(memory_slice(p, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLKEM_N, MLK_NTT_BOUND))+ ensures((return_value == MLK_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLKEM_N, MLKEM_Q))+ ensures((return_value == MLK_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLKEM_N))+);+#endif /* MLK_USE_NATIVE_NTT */++#if defined(MLK_USE_NATIVE_NTT_CUSTOM_ORDER)+/*+ * This must only be set if NTT, invNTT, basemul, mulcache, and+ * to/from byte stream conversions all have native implementations+ * that are adapted to the custom order.+ */+#if !defined(MLK_USE_NATIVE_NTT) || !defined(MLK_USE_NATIVE_INTT) || \+ !defined(MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE) || \+ !defined(MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED) || \+ !defined(MLK_USE_NATIVE_POLY_TOBYTES) || \+ !defined(MLK_USE_NATIVE_POLY_FROMBYTES)+#error \+ "Invalid native profile: MLK_USE_NATIVE_NTT_CUSTOM_ORDER can only be \+set if there are native implementations for NTT, invNTT, mulcache, basemul, \+and to/from bytes conversions."+#endif /* !MLK_USE_NATIVE_NTT || !MLK_USE_NATIVE_INTT || \+ !MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE || \+ !MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED || \+ !MLK_USE_NATIVE_POLY_TOBYTES || !MLK_USE_NATIVE_POLY_FROMBYTES */++/**+ * When MLK_USE_NATIVE_NTT_CUSTOM_ORDER is defined, convert a polynomial in+ * NTT domain from bitreversed order to the custom order output by the+ * native NTT.+ *+ * This must only be defined if there is native code for all of (a) NTT,+ * (b) invNTT, (c) basemul, (d) mulcache.+ *+ * @param[in,out] p Input/output polynomial.+ */+static MLK_INLINE void mlk_poly_permute_bitrev_to_custom(int16_t p[MLKEM_N])+__contract__(+ /* We don't specify that this should be a permutation, but only+ * that it does not change the bound established at the end of mlk_gen_matrix. */+ requires(memory_no_alias(p, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(p, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(p, sizeof(int16_t) * MLKEM_N))+ ensures(array_bound(p, 0, MLKEM_N, 0, MLKEM_Q)));+#endif /* MLK_USE_NATIVE_NTT_CUSTOM_ORDER */++#if defined(MLK_USE_NATIVE_INTT) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API))+/**+ * Compute the inverse negacyclic number-theoretic transform (NTT) of a+ * polynomial in place.+ *+ * The input polynomial is in bitreversed order, or of a custom order if+ * MLK_USE_NATIVE_NTT_CUSTOM_ORDER is set. See the documentation of+ * MLK_USE_NATIVE_NTT_CUSTOM_ORDER for more information. The output+ * polynomial is assumed to be in normal order.+ *+ * @param[in,out] p Input/output polynomial.+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_intt_native(int16_t p[MLKEM_N])+__contract__(+ requires(memory_no_alias(p, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(p, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLKEM_N, MLK_INVNTT_BOUND))+ ensures((return_value == MLK_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLKEM_N))+);+#endif /* MLK_USE_NATIVE_INTT && (!MLK_CONFIG_NO_ENCAPS_API || \+ !MLK_CONFIG_NO_DECAPS_API) */++#if defined(MLK_USE_NATIVE_POLY_REDUCE)+/**+ * Apply modular reduction to all coefficients of a polynomial, mapping them+ * to unsigned canonical representatives in [0,..,MLKEM_Q-1].+ *+ * @param[in,out] p Input/output polynomial.+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_reduce_native(int16_t p[MLKEM_N])+__contract__(+ requires(memory_no_alias(p, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(p, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_bound(p, 0, MLKEM_N, 0, MLKEM_Q))+ ensures((return_value == MLK_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLKEM_N))+);+#endif /* MLK_USE_NATIVE_POLY_REDUCE */++#if defined(MLK_USE_NATIVE_POLY_TOMONT) && !defined(MLK_CONFIG_NO_KEYPAIR_API)+/**+ * In-place conversion of all coefficients of a polynomial from the normal+ * domain to the Montgomery domain.+ *+ * @param[in,out] p Input/output polynomial.+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_tomont_native(int16_t p[MLKEM_N])+__contract__(+ requires(memory_no_alias(p, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(p, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLKEM_N, MLKEM_Q))+ ensures((return_value == MLK_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLKEM_N))+);+#endif /* MLK_USE_NATIVE_POLY_TOMONT && !MLK_CONFIG_NO_KEYPAIR_API */++#if defined(MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE)+/**+ * Compute multiplication cache for a polynomial in NTT domain.+ *+ * The purpose of the multiplication cache is to cache repeated computations+ * required during a base multiplication of polynomials in NTT domain. The+ * structure of the multiplication-cache is implementation defined.+ *+ * @param[out] cache Multiplication cache.+ * @param[in] mlk_poly Input polynomial. Must be in NTT domain and in+ * bitreversed order, or of a custom order if+ * MLK_USE_NATIVE_NTT_CUSTOM_ORDER is set. See the+ * documentation of MLK_USE_NATIVE_NTT_CUSTOM_ORDER for+ * more information.+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_mulcache_compute_native(+ int16_t cache[MLKEM_N / 2], const int16_t mlk_poly[MLKEM_N])+__contract__(+ requires(memory_no_alias(cache, sizeof(int16_t) * (MLKEM_N / 2)))+ requires(memory_no_alias(mlk_poly, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(cache, sizeof(int16_t) * (MLKEM_N / 2)))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(cache, 0, MLKEM_N/2, MLKEM_Q))+);+#endif /* MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE */++#if defined(MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED)+#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2+/**+ * Compute scalar product of length-2 polynomial vectors in NTT domain.+ *+ * @param[out] r Result of the scalar product. Again in NTT domain, of+ * the same ordering as @p a and @p b.+ * @param[in] a First polynomial vector operand. Must be in NTT+ * domain and in bitreversed order, or of a custom order+ * if MLK_USE_NATIVE_NTT_CUSTOM_ORDER is set. See the+ * documentation of MLK_USE_NATIVE_NTT_CUSTOM_ORDER for+ * more information.+ * @param[in] b Second polynomial vector operand. As for @p a.+ * @param[in] b_cache Multiplication-cache for @p b.+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_polyvec_basemul_acc_montgomery_cached_k2_native(+ int16_t r[MLKEM_N], const int16_t a[2 * MLKEM_N],+ const int16_t b[2 * MLKEM_N], const int16_t b_cache[2 * (MLKEM_N / 2)])+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, sizeof(int16_t) * 2 * MLKEM_N))+ requires(memory_no_alias(b, sizeof(int16_t) * 2 * MLKEM_N))+ requires(memory_no_alias(b_cache, sizeof(int16_t) * 2 * (MLKEM_N / 2)))+ requires(array_bound(a, 0, 2 * MLKEM_N, 0, MLKEM_UINT12_LIMIT))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+);+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 3+/**+ * Compute scalar product of length-3 polynomial vectors in NTT domain.+ *+ * @param[out] r Result of the scalar product. Again in NTT domain, of+ * the same ordering as @p a and @p b.+ * @param[in] a First polynomial vector operand. Must be in NTT+ * domain and in bitreversed order, or of a custom order+ * if MLK_USE_NATIVE_NTT_CUSTOM_ORDER is set. See the+ * documentation of MLK_USE_NATIVE_NTT_CUSTOM_ORDER for+ * more information.+ * @param[in] b Second polynomial vector operand. As for @p a.+ * @param[in] b_cache Multiplication-cache for @p b.+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_polyvec_basemul_acc_montgomery_cached_k3_native(+ int16_t r[MLKEM_N], const int16_t a[3 * MLKEM_N],+ const int16_t b[3 * MLKEM_N], const int16_t b_cache[3 * (MLKEM_N / 2)])+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, sizeof(int16_t) * 3 * MLKEM_N))+ requires(memory_no_alias(b, sizeof(int16_t) * 3 * MLKEM_N))+ requires(memory_no_alias(b_cache, sizeof(int16_t) * 3 * (MLKEM_N / 2)))+ requires(array_bound(a, 0, 3 * MLKEM_N, 0, MLKEM_UINT12_LIMIT))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+);+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 3 */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4+/**+ * Compute scalar product of length-4 polynomial vectors in NTT domain.+ *+ * @param[out] r Result of the scalar product. Again in NTT domain, of+ * the same ordering as @p a and @p b.+ * @param[in] a First polynomial vector operand. Must be in NTT+ * domain and in bitreversed order, or of a custom order+ * if MLK_USE_NATIVE_NTT_CUSTOM_ORDER is set. See the+ * documentation of MLK_USE_NATIVE_NTT_CUSTOM_ORDER for+ * more information.+ * @param[in] b Second polynomial vector operand. As for @p a.+ * @param[in] b_cache Multiplication-cache for @p b.+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_polyvec_basemul_acc_montgomery_cached_k4_native(+ int16_t r[MLKEM_N], const int16_t a[4 * MLKEM_N],+ const int16_t b[4 * MLKEM_N], const int16_t b_cache[4 * (MLKEM_N / 2)])+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, sizeof(int16_t) * 4 * MLKEM_N))+ requires(memory_no_alias(b, sizeof(int16_t) * 4 * MLKEM_N))+ requires(memory_no_alias(b_cache, sizeof(int16_t) * 4 * (MLKEM_N / 2)))+ requires(array_bound(a, 0, 4 * MLKEM_N, 0, MLKEM_UINT12_LIMIT))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_FALLBACK || return_value == MLK_NATIVE_FUNC_SUCCESS)+);+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4 */+#endif /* MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED */++#if defined(MLK_USE_NATIVE_POLY_TOBYTES) && \+ (!defined(MLK_CONFIG_NO_KEYPAIR_API) || \+ !defined(MLK_CONFIG_NO_ENCAPS_API))+/**+ * Serialization of a polynomial with unsigned canonical coefficients.+ *+ * @spec{Implements ByteEncode_12 from @[FIPS203, Algorithm 5].}+ *+ * @param[out] r Output byte array (of MLKEM_POLYBYTES bytes).+ * @param[in] a Input polynomial, with each coefficient in [0,..,MLKEM_Q-1].+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_tobytes_native(uint8_t r[MLKEM_POLYBYTES],+ const int16_t a[MLKEM_N])+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYBYTES))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYBYTES))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK)+);+#endif /* MLK_USE_NATIVE_POLY_TOBYTES && (!MLK_CONFIG_NO_KEYPAIR_API || \+ !MLK_CONFIG_NO_ENCAPS_API) */++#if defined(MLK_USE_NATIVE_POLY_FROMBYTES) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API))+/**+ * Deserialization of a polynomial.+ *+ * @spec{Implements ByteDecode_12 from @[FIPS203, Algorithm 6].}+ *+ * @param[out] a Output polynomial in NTT domain.+ * @param[in] r Input byte array (of MLKEM_POLYBYTES bytes).+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_frombytes_native(+ int16_t a[MLKEM_N], const uint8_t r[MLKEM_POLYBYTES])+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYBYTES))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(a, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT))+);+#endif /* MLK_USE_NATIVE_POLY_FROMBYTES && (!MLK_CONFIG_NO_ENCAPS_API || \+ !MLK_CONFIG_NO_DECAPS_API) */++#if defined(MLK_USE_NATIVE_REJ_UNIFORM)+/**+ * Run rejection sampling on uniformly random bytes to generate uniformly random+ * integers mod MLKEM_Q, represented in [0,..,MLKEM_Q-1].+ *+ * @param[out] r Output buffer.+ * @param len Requested number of 16-bit integers (uniform mod MLKEM_Q).+ * @param[in] buf Input buffer (assumed to be uniform random bytes).+ * @param buflen Length of input buffer in bytes.+ *+ * @retval MLK_NATIVE_FUNC_FALLBACK Native implementation does not support+ * the input lengths.+ * @retval other Non-negative number of sampled 16-bit+ * integers (at most @p len).+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_rej_uniform_native(int16_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+__contract__(+ requires(len <= 4096 && buflen <= 4096 && buflen % 3 == 0)+ requires(memory_no_alias(r, sizeof(int16_t) * len))+ requires(memory_no_alias(buf, buflen))+ assigns(memory_slice(r, sizeof(int16_t) * len))+ ensures(return_value != MLK_NATIVE_FUNC_FALLBACK+ ==> (0 <= return_value && return_value <= len))+ ensures(return_value != MLK_NATIVE_FUNC_FALLBACK+ ==> array_bound(r, 0, (unsigned) return_value, 0, MLKEM_Q))+);+#endif /* MLK_USE_NATIVE_REJ_UNIFORM */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || (MLKEM_K == 2 || MLKEM_K == 3)+#if defined(MLK_USE_NATIVE_POLY_COMPRESS_D4)+/**+ * Compression (4 bits) and subsequent serialization of a polynomial.+ *+ * @spec{Compress_4 from @[FIPS203, Eq (4.7)].}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D4+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_compress_d4_native(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D4], const int16_t a[MLKEM_N])+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D4))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D4))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK));+#endif /* MLK_USE_NATIVE_POLY_COMPRESS_D4 */++#if defined(MLK_USE_NATIVE_POLY_COMPRESS_D10)+/**+ * Compression (10 bits) and subsequent serialization of a polynomial.+ *+ * @spec{Compress_10 from @[FIPS203, Eq (4.7)].}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D10+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_compress_d10_native(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D10], const int16_t a[MLKEM_N])+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D10))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D10))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK));+#endif /* MLK_USE_NATIVE_POLY_COMPRESS_D10 */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#if defined(MLK_USE_NATIVE_POLY_DECOMPRESS_D4)+/**+ * De-serialization and subsequent decompression (4 bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_d4.+ *+ * @spec{Decompress_4 from @[FIPS203, Eq (4.8)].}+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D4+ * bytes).+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_decompress_d4_native(+ int16_t r[MLKEM_N], const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D4])+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D4))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLKEM_N, 0, MLKEM_Q)));+#endif /* MLK_USE_NATIVE_POLY_DECOMPRESS_D4 */++#if defined(MLK_USE_NATIVE_POLY_DECOMPRESS_D10)+/**+ * De-serialization and subsequent decompression (10 bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_d10.+ *+ * @spec{Decompress_10 from @[FIPS203, Eq (4.8)].}+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D10+ * bytes).+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_decompress_d10_native(+ int16_t r[MLKEM_N], const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D10])+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D10))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLKEM_N, 0, MLKEM_Q)));+#endif /* MLK_USE_NATIVE_POLY_DECOMPRESS_D10 */+#endif /* !MLK_CONFIG_NO_DECAPS_API */+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 || MLKEM_K == 3 */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4+#if defined(MLK_USE_NATIVE_POLY_COMPRESS_D5)+/**+ * Compression (5 bits) and subsequent serialization of a polynomial.+ *+ * @spec{Compress_5 from @[FIPS203, Eq (4.7)].}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D5+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_compress_d5_native(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D5], const int16_t a[MLKEM_N])+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D5))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D5))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK));+#endif /* MLK_USE_NATIVE_POLY_COMPRESS_D5 */++#if defined(MLK_USE_NATIVE_POLY_COMPRESS_D11)+/**+ * Compression (11 bits) and subsequent serialization of a polynomial.+ *+ * @spec{Compress_11 from @[FIPS203, Eq (4.7)].}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D11+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_compress_d11_native(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D11], const int16_t a[MLKEM_N])+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D11))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D11))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK));+#endif /* MLK_USE_NATIVE_POLY_COMPRESS_D11 */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#if defined(MLK_USE_NATIVE_POLY_DECOMPRESS_D5)+/**+ * De-serialization and subsequent decompression (5 bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_d5.+ *+ * @spec{Decompress_5 from @[FIPS203, Eq (4.8)].}+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D5+ * bytes).+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_decompress_d5_native(+ int16_t r[MLKEM_N], const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D5])+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D5))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLKEM_N, 0, MLKEM_Q)));+#endif /* MLK_USE_NATIVE_POLY_DECOMPRESS_D5 */++#if defined(MLK_USE_NATIVE_POLY_DECOMPRESS_D11)+/**+ * De-serialization and subsequent decompression (11 bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_d11.+ *+ * @spec{Decompress_11 from @[FIPS203, Eq (4.8)].}+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_D11+ * bytes).+ *+ * @retval MLK_NATIVE_FUNC_SUCCESS Operation succeeded.+ * @retval MLK_NATIVE_FUNC_FALLBACK Backend declined; caller should fall back.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_decompress_d11_native(+ int16_t r[MLKEM_N], const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D11])+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D11))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(return_value == MLK_NATIVE_FUNC_SUCCESS || return_value == MLK_NATIVE_FUNC_FALLBACK)+ ensures((return_value == MLK_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLKEM_N, 0, MLKEM_Q)));+#endif /* MLK_USE_NATIVE_POLY_DECOMPRESS_D11 */+#endif /* !MLK_CONFIG_NO_DECAPS_API */+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4 */+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#endif /* !MLK_NATIVE_API_H */
@@ -0,0 +1,30 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_NATIVE_META_H+#define MLK_NATIVE_META_H++/*+ * Default arithmetic backend+ */+#include "../sys.h"++#ifdef MLK_SYS_AARCH64_NEON+#include "aarch64/meta.h"+#endif++/* The x86_64 backend requires toolchain support for the SysV ABI */+#if defined(MLK_SYS_X86_64_AVX2) && defined(MLK_SYSV_ABI_SUPPORTED)+#include "x86_64/meta.h"+#endif++#if defined(MLK_SYS_RISCV64_RVV)+#include "riscv64/meta.h"+#endif++#ifdef MLK_SYS_PPC64LE+#include "ppc64le/meta.h"+#endif++#endif /* !MLK_NATIVE_META_H */
@@ -0,0 +1,4 @@+[//]: # (SPDX-License-Identifier: CC-BY-4.0)++This directory contains the native x86_64 arithmetic backend for ML-KEM provided by the official [AVX2+implementation](https://github.com/pq-crystals/kyber/tree/main/avx2) of the Kyber team.
@@ -0,0 +1,324 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#ifndef MLK_NATIVE_X86_64_META_H+#define MLK_NATIVE_X86_64_META_H++/* Identifier for this backend so that source and assembly files+ * in the build can be appropriately guarded. */+#define MLK_ARITH_BACKEND_X86_64_DEFAULT++#define MLK_USE_NATIVE_NTT_CUSTOM_ORDER+#define MLK_USE_NATIVE_REJ_UNIFORM+#define MLK_USE_NATIVE_NTT+#define MLK_USE_NATIVE_INTT+#define MLK_USE_NATIVE_POLY_REDUCE+#define MLK_USE_NATIVE_POLY_TOMONT+#define MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED+#define MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE+#define MLK_USE_NATIVE_POLY_TOBYTES+#define MLK_USE_NATIVE_POLY_FROMBYTES+#define MLK_USE_NATIVE_POLY_COMPRESS_D4+#define MLK_USE_NATIVE_POLY_COMPRESS_D5+#define MLK_USE_NATIVE_POLY_COMPRESS_D10+#define MLK_USE_NATIVE_POLY_COMPRESS_D11+#define MLK_USE_NATIVE_POLY_DECOMPRESS_D4+#define MLK_USE_NATIVE_POLY_DECOMPRESS_D5+#define MLK_USE_NATIVE_POLY_DECOMPRESS_D10+#define MLK_USE_NATIVE_POLY_DECOMPRESS_D11++#if !defined(__ASSEMBLER__)+#include "../../common.h"+#include "../api.h"+#include "src/arith_native_x86_64.h"+#include "src/compress_consts.h"++static MLK_INLINE void mlk_poly_permute_bitrev_to_custom(int16_t data[MLKEM_N])+{+ if (mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ mlk_nttunpack_avx2_asm(data);+ }+}++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_rej_uniform_native(int16_t *r, unsigned len,+ const uint8_t *buf,+ unsigned buflen)+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2) || len != MLKEM_N ||+ buflen % 12 != 0)+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }+ return (int)mlk_rej_uniform_avx2_asm(r, buf, buflen, mlk_rej_uniform_table);+}++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_ntt_native(int16_t data[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_ntt_avx2_asm(data, mlk_qdata);+ return MLK_NATIVE_FUNC_SUCCESS;+}++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_intt_native(int16_t data[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_invntt_avx2_asm(data, mlk_qdata);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_reduce_native(int16_t data[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_reduce_avx2_asm(data);+ return MLK_NATIVE_FUNC_SUCCESS;+}++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_tomont_native(int16_t data[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_tomont_avx2_asm(data);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_mulcache_compute_native(int16_t x[MLKEM_N / 2],+ const int16_t y[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_poly_mulcache_compute_avx2_asm(x, y, mlk_qdata);+ return MLK_NATIVE_FUNC_SUCCESS;+}++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_polyvec_basemul_acc_montgomery_cached_k2_native(+ int16_t r[MLKEM_N], const int16_t a[2 * MLKEM_N],+ const int16_t b[2 * MLKEM_N], const int16_t b_cache[2 * (MLKEM_N / 2)])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm(r, a, b, b_cache);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 3+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_polyvec_basemul_acc_montgomery_cached_k3_native(+ int16_t r[MLKEM_N], const int16_t a[3 * MLKEM_N],+ const int16_t b[3 * MLKEM_N], const int16_t b_cache[3 * (MLKEM_N / 2)])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm(r, a, b, b_cache);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 3 */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_polyvec_basemul_acc_montgomery_cached_k4_native(+ int16_t r[MLKEM_N], const int16_t a[4 * MLKEM_N],+ const int16_t b[4 * MLKEM_N], const int16_t b_cache[4 * (MLKEM_N / 2)])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm(r, a, b, b_cache);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4 */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API) || !defined(MLK_CONFIG_NO_ENCAPS_API)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_tobytes_native(uint8_t r[MLKEM_POLYBYTES],+ const int16_t a[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_ntttobytes_avx2_asm(r, a);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API || !MLK_CONFIG_NO_ENCAPS_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_frombytes_native(+ int16_t r[MLKEM_N], const uint8_t a[MLKEM_POLYBYTES])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_nttfrombytes_avx2_asm(r, a);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2 || \+ MLKEM_K == 3)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_compress_d4_native(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D4], const int16_t a[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_poly_compress_d4_avx2_asm(r, a, mlk_compress_d4_data);+ return MLK_NATIVE_FUNC_SUCCESS;+}++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_compress_d10_native(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D10], const int16_t a[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_poly_compress_d10_avx2_asm(r, a, mlk_compress_d10_data);+ return MLK_NATIVE_FUNC_SUCCESS;+}++#if !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_decompress_d4_native(+ int16_t r[MLKEM_N], const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D4])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_poly_decompress_d4_avx2_asm(r, a, mlk_decompress_d4_data);+ return MLK_NATIVE_FUNC_SUCCESS;+}++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_decompress_d10_native(+ int16_t r[MLKEM_N], const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D10])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_poly_decompress_d10_avx2_asm(r, a, mlk_decompress_d10_data);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */+#endif /* (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 || MLKEM_K == 3) \+ */++#if (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_compress_d5_native(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D5], const int16_t a[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_poly_compress_d5_avx2_asm(r, a, mlk_compress_d5_data);+ return MLK_NATIVE_FUNC_SUCCESS;+}++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_compress_d11_native(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D11], const int16_t a[MLKEM_N])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_poly_compress_d11_avx2_asm(r, a, mlk_compress_d11_data);+ return MLK_NATIVE_FUNC_SUCCESS;+}++#if !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_decompress_d5_native(+ int16_t r[MLKEM_N], const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D5])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_poly_decompress_d5_avx2_asm(r, a, mlk_decompress_d5_data);+ return MLK_NATIVE_FUNC_SUCCESS;+}++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_poly_decompress_d11_native(+ int16_t r[MLKEM_N], const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D11])+{+ if (!mlk_sys_check_capability(MLK_SYS_CAP_X86_64_AVX2))+ {+ return MLK_NATIVE_FUNC_FALLBACK;+ }++ mlk_poly_decompress_d11_avx2_asm(r, a, mlk_decompress_d11_data);+ return MLK_NATIVE_FUNC_SUCCESS;+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */+#endif /* (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4) */++#endif /* !__ASSEMBLER__ */++#endif /* !MLK_NATIVE_X86_64_META_H */
@@ -0,0 +1,327 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H+#define MLK_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H++#include "../../../common.h"++#include <stdint.h>+#include "compress_consts.h"+#include "consts.h"++#define MLK_AVX2_REJ_UNIFORM_BUFLEN \+ (3 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */++#define mlk_rej_uniform_table MLK_NAMESPACE(rej_uniform_table)+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_rej_uniform_table[4096];++#define mlk_rej_uniform_avx2_asm MLK_NAMESPACE(rej_uniform_avx2_asm)+MLK_MUST_CHECK_RETURN_VALUE MLK_SYSV_ABI+uint64_t mlk_rej_uniform_avx2_asm(int16_t *r, const uint8_t *buf,+ unsigned buflen, const uint8_t *table)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mlkem_rej_uniform_avx2_asm.ml. */+__contract__(+ requires(buflen % 12 == 0)+ requires(memory_no_alias(buf, buflen))+ requires(table == mlk_rej_uniform_table)+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(return_value <= MLKEM_N)+ ensures(array_bound(r, 0, (unsigned) return_value, 0, MLKEM_Q))+);++#define mlk_ntt_avx2_asm MLK_NAMESPACE(ntt_avx2_asm)+MLK_SYSV_ABI+void mlk_ntt_avx2_asm(int16_t *r, const int16_t *qdata)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mlkem_ntt_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(array_abs_bound(r, 0, MLKEM_N, 8192))+ requires(qdata == mlk_qdata)+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ /* check-magic: off */+ ensures(array_abs_bound(r, 0, MLKEM_N, 23595))+ /* check-magic: on */+);++#define mlk_invntt_avx2_asm MLK_NAMESPACE(invntt_avx2_asm)+MLK_SYSV_ABI+void mlk_invntt_avx2_asm(int16_t *r, const int16_t *qdata)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mlkem_intt_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(qdata == mlk_qdata)+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ /* check-magic: off */+ ensures(array_abs_bound(r, 0, MLKEM_N, 26632))+ /* check-magic: on */+);++#define mlk_nttunpack_avx2_asm MLK_NAMESPACE(nttunpack_avx2_asm)+MLK_SYSV_ABI+void mlk_nttunpack_avx2_asm(int16_t *r)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mlkem_nttunpack_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(r, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ /* Output is a permutation of input: every output coefficient+ * is some input coefficient */+ ensures(forall(i, 0, MLKEM_N, exists(j, 0, MLKEM_N,+ r[i] == old(*(int16_t (*)[MLKEM_N])r)[j])))+);++#define mlk_reduce_avx2_asm MLK_NAMESPACE(reduce_avx2_asm)+MLK_SYSV_ABI+void mlk_reduce_avx2_asm(int16_t *r)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mlkem_reduce_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_bound(r, 0, MLKEM_N, 0, MLKEM_Q))+);++#define mlk_poly_mulcache_compute_avx2_asm \+ MLK_NAMESPACE(poly_mulcache_compute_avx2_asm)+MLK_SYSV_ABI+void mlk_poly_mulcache_compute_avx2_asm(int16_t *out, const int16_t *in,+ const int16_t *qdata)+/* This must be kept in sync with the HOL-Light specification+ * in proofs/hol_light/x86_64/proofs/mlkem_poly_mulcache_compute_avx2_asm.ml */+__contract__(+ requires(memory_no_alias(out, sizeof(int16_t) * (MLKEM_N / 2)))+ requires(memory_no_alias(in, sizeof(int16_t) * MLKEM_N))+ requires(qdata == mlk_qdata)+ assigns(memory_slice(out, sizeof(int16_t) * (MLKEM_N / 2)))+ ensures(array_abs_bound(out, 0, MLKEM_N/2, MLKEM_Q))+);++#define mlk_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm \+ MLK_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k2_avx2_asm)+MLK_SYSV_ABI+void mlk_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm(+ int16_t *r, const int16_t *a, const int16_t *b, const int16_t *b_cache)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, sizeof(int16_t) * 2 * MLKEM_N))+ requires(memory_no_alias(b, sizeof(int16_t) * 2 * MLKEM_N))+ requires(memory_no_alias(b_cache, sizeof(int16_t) * 2 * (MLKEM_N / 2)))+ requires(array_abs_bound(a, 0, 2 * MLKEM_N, MLKEM_UINT12_LIMIT + 1))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+);++#define mlk_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm \+ MLK_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k3_avx2_asm)+MLK_SYSV_ABI+void mlk_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm(+ int16_t *r, const int16_t *a, const int16_t *b, const int16_t *b_cache)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, sizeof(int16_t) * 3 * MLKEM_N))+ requires(memory_no_alias(b, sizeof(int16_t) * 3 * MLKEM_N))+ requires(memory_no_alias(b_cache, sizeof(int16_t) * 3 * (MLKEM_N / 2)))+ requires(array_abs_bound(a, 0, 3 * MLKEM_N, MLKEM_UINT12_LIMIT + 1))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+);++#define mlk_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm \+ MLK_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k4_avx2_asm)+MLK_SYSV_ABI+void mlk_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm(+ int16_t *r, const int16_t *a, const int16_t *b, const int16_t *b_cache)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, sizeof(int16_t) * 4 * MLKEM_N))+ requires(memory_no_alias(b, sizeof(int16_t) * 4 * MLKEM_N))+ requires(memory_no_alias(b_cache, sizeof(int16_t) * 4 * (MLKEM_N / 2)))+ requires(array_abs_bound(a, 0, 4 * MLKEM_N, MLKEM_UINT12_LIMIT + 1))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+);++#define mlk_ntttobytes_avx2_asm MLK_NAMESPACE(ntttobytes_avx2_asm)+MLK_SYSV_ABI+void mlk_ntttobytes_avx2_asm(uint8_t *r, const int16_t *a)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_ntttobytes_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYBYTES))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYBYTES))+);++#define mlk_nttfrombytes_avx2_asm MLK_NAMESPACE(nttfrombytes_avx2_asm)+MLK_SYSV_ABI+void mlk_nttfrombytes_avx2_asm(int16_t *r, const uint8_t *a)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_nttfrombytes_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(a, MLKEM_POLYBYTES))+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_bound(r, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT))+);++#define mlk_tomont_avx2_asm MLK_NAMESPACE(tomont_avx2_asm)+MLK_SYSV_ABI+void mlk_tomont_avx2_asm(int16_t *r)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_tomont_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_abs_bound(r, 0, MLKEM_N, MLKEM_Q))+);++#define mlk_poly_compress_d4_avx2_asm MLK_NAMESPACE(poly_compress_d4_avx2_asm)+MLK_SYSV_ABI+void mlk_poly_compress_d4_avx2_asm(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D4],+ const int16_t *MLK_RESTRICT a,+ const uint8_t *data)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_poly_compress_d4_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D4))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ requires(data == mlk_compress_d4_data)+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D4))+);++#define mlk_poly_decompress_d4_avx2_asm \+ MLK_NAMESPACE(poly_decompress_d4_avx2_asm)+MLK_SYSV_ABI+void mlk_poly_decompress_d4_avx2_asm(+ int16_t *MLK_RESTRICT r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D4],+ const uint8_t *data)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_poly_decompress_d4_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D4))+ requires(data == mlk_decompress_d4_data)+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_bound(r, 0, MLKEM_N, 0, MLKEM_Q))+);++#define mlk_poly_compress_d10_avx2_asm MLK_NAMESPACE(poly_compress_d10_avx2_asm)+MLK_SYSV_ABI+void mlk_poly_compress_d10_avx2_asm(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D10],+ const int16_t *MLK_RESTRICT a,+ const uint8_t *data)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_poly_compress_d10_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D10))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ requires(data == mlk_compress_d10_data)+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D10))+);++#define mlk_poly_decompress_d10_avx2_asm \+ MLK_NAMESPACE(poly_decompress_d10_avx2_asm)+MLK_SYSV_ABI+void mlk_poly_decompress_d10_avx2_asm(+ int16_t *MLK_RESTRICT r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D10],+ const uint8_t *data)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_poly_decompress_d10_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D10))+ requires(data == mlk_decompress_d10_data)+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_bound(r, 0, MLKEM_N, 0, MLKEM_Q))+);++#define mlk_poly_compress_d5_avx2_asm MLK_NAMESPACE(poly_compress_d5_avx2_asm)+MLK_SYSV_ABI+void mlk_poly_compress_d5_avx2_asm(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D5],+ const int16_t *MLK_RESTRICT a,+ const uint8_t *data)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_poly_compress_d5_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D5))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ requires(data == mlk_compress_d5_data)+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D5))+);++#define mlk_poly_decompress_d5_avx2_asm \+ MLK_NAMESPACE(poly_decompress_d5_avx2_asm)+MLK_SYSV_ABI+void mlk_poly_decompress_d5_avx2_asm(+ int16_t *MLK_RESTRICT r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D5],+ const uint8_t *data)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_poly_decompress_d5_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D5))+ requires(data == mlk_decompress_d5_data)+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_bound(r, 0, MLKEM_N, 0, MLKEM_Q))+);++#define mlk_poly_compress_d11_avx2_asm MLK_NAMESPACE(poly_compress_d11_avx2_asm)+MLK_SYSV_ABI+void mlk_poly_compress_d11_avx2_asm(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D11],+ const int16_t *MLK_RESTRICT a,+ const uint8_t *data)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_poly_compress_d11_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_D11))+ requires(memory_no_alias(a, sizeof(int16_t) * MLKEM_N))+ requires(array_bound(a, 0, MLKEM_N, 0, MLKEM_Q))+ requires(data == mlk_compress_d11_data)+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_D11))+);++#define mlk_poly_decompress_d11_avx2_asm \+ MLK_NAMESPACE(poly_decompress_d11_avx2_asm)+MLK_SYSV_ABI+void mlk_poly_decompress_d11_avx2_asm(+ int16_t *MLK_RESTRICT r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_D11],+ const uint8_t *data)+/* This must be kept in sync with the HOL-Light specification in+ * proofs/hol_light/x86_64/proofs/mlkem_poly_decompress_d11_avx2_asm.ml.+ */+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_D11))+ requires(data == mlk_decompress_d11_data)+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_bound(r, 0, MLKEM_N, 0, MLKEM_Q))+);++#endif /* !MLK_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */
@@ -0,0 +1,115 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API))++#include "compress_consts.h"++#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2 || \+ MLKEM_K == 3)++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_compress_d4_data[32] = {+ 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0,+ 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, /* permdidx */+};++#if !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_decompress_d4_data[32] = {+ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,+ 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, /* shufbidx */+};+#endif /* !MLK_CONFIG_NO_DECAPS_API */++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_compress_d10_data[32] = {+ 0, 1, 2, 3, 4, 8, 9, 10, 11, 12, 255,+ 255, 255, 255, 255, 255, 9, 10, 11, 12, 255, 255,+ 255, 255, 255, 255, 0, 1, 2, 3, 4, 8, /* shufbidx */+};++#if !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_decompress_d10_data[32] = {+ 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9,+ 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, /* shufbidx */+};+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#endif /* !MLK_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 || MLKEM_K == 3) \+ */++#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4)++MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_compress_d5_data[32] = {+ 0, 1, 2, 3, 4, 255, 255, 255, 255, 255, 8,+ 9, 10, 11, 12, 255, 9, 10, 11, 12, 255, 0,+ 1, 2, 3, 4, 255, 255, 255, 255, 255, 8, /* shufbidx */+};++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/* shufbidx[0:32], mask[32:64], shift[64:96] */+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_decompress_d5_data[96] = {+ 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5,+ 5, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, /* shufbidx */+ 31, 0, 224, 3, 124, 0, 128, 15, 240, 1, 62, 0, 192, 7, 248, 0, 31, 0,+ 224, 3, 124, 0, 128, 15, 240, 1, 62, 0, 192, 7, 248, 0, /* mask */+ 0, 4, 32, 0, 0, 1, 8, 0, 64, 0, 0, 2, 16, 0, 128, 0, 0, 4,+ 32, 0, 0, 1, 8, 0, 64, 0, 0, 2, 16, 0, 128, 0, /* shift */+};+#endif /* !MLK_CONFIG_NO_DECAPS_API */++/* srlvqidx[0:32], shufbidx[32:64] */+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_compress_d11_data[64] =+ {+ 10, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0,+ 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0,+ 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, /* srlvqidx */+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,+ 255, 255, 255, 255, 255, 5, 6, 7, 8, 9, 10,+ 255, 255, 255, 255, 0, 0, 1, 2, 3, 4, /* shufbidx */+};++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/* shufbidx[0:32], srlvdidx[32:64], srlvqidx[64:96], shift[96:128] */+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_decompress_d11_data[128] = {+ 0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10,+ 3, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, 10, 11, 12, 12, 13, /* shufbidx */+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* srlvdidx */+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* srlvqidx */+ 32, 0, 4, 0, 1, 0, 32, 0, 8, 0, 1, 0, 32, 0, 4, 0,+ 32, 0, 4, 0, 1, 0, 32, 0, 8, 0, 1, 0, 32, 0, 4, 0, /* shift */+};+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#endif /* !MLK_CONFIG_MULTILEVEL_NO_SHARED && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4) */++#else /* MLK_ARITH_BACKEND_X86_64_DEFAULT && (!MLK_CONFIG_NO_ENCAPS_API || \+ !MLK_CONFIG_NO_DECAPS_API) */++MLK_EMPTY_CU(avx2_compress_consts)++#endif /* !(MLK_ARITH_BACKEND_X86_64_DEFAULT && (!MLK_CONFIG_NO_ENCAPS_API || \+ !MLK_CONFIG_NO_DECAPS_API)) */
@@ -0,0 +1,53 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++#ifndef MLK_NATIVE_X86_64_SRC_COMPRESS_CONSTS_H+#define MLK_NATIVE_X86_64_SRC_COMPRESS_CONSTS_H++#include "../../../common.h"++#ifndef __ASSEMBLER__++#define mlk_compress_d4_data MLK_NAMESPACE(compress_d4_data)+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_compress_d4_data[32];++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_decompress_d4_data MLK_NAMESPACE(decompress_d4_data)+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_decompress_d4_data[32];+#endif++#define mlk_compress_d10_data MLK_NAMESPACE(compress_d10_data)+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_compress_d10_data[32];++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_decompress_d10_data MLK_NAMESPACE(decompress_d10_data)+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_decompress_d10_data[32];+#endif++#define mlk_compress_d5_data MLK_NAMESPACE(compress_d5_data)+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_compress_d5_data[32];++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_decompress_d5_data MLK_NAMESPACE(decompress_d5_data)+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_decompress_d5_data[96];+#endif++#define mlk_compress_d11_data MLK_NAMESPACE(compress_d11_data)+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_compress_d11_data[64];++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_decompress_d11_data MLK_NAMESPACE(decompress_d11_data)+MLK_INTERNAL_DATA_DECLARATION const uint8_t mlk_decompress_d11_data[128];+#endif++#endif /* !__ASSEMBLER__ */++#endif /* !MLK_NATIVE_X86_64_SRC_COMPRESS_CONSTS_H */
@@ -0,0 +1,102 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#include "consts.h"++/*+ * Table of zeta values used in the AVX2 NTTs+ * See autogen for details.+ */+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const int16_t mlk_qdata[624] = {+ 3854, 3340, 2826, 2312, 1798, 1284, 770, 256, 3854,+ 3340, 2826, 2312, 1798, 1284, 770, 256, 7, 0,+ 6, 0, 5, 0, 4, 0, 3, 0, 2,+ 0, 1, 0, 0, 0, 31498, 31498, 31498, 31498,+ -758, -758, -758, -758, 0, 0, 0, 0, 0,+ 0, 0, 0, 14745, 14745, 14745, 14745, 14745, 14745,+ 14745, 14745, 14745, 14745, 14745, 14745, 14745, 14745, 14745,+ 14745, -359, -359, -359, -359, -359, -359, -359, -359,+ -359, -359, -359, -359, -359, -359, -359, -359, 13525,+ 13525, 13525, 13525, 13525, 13525, 13525, 13525, -12402, -12402,+ -12402, -12402, -12402, -12402, -12402, -12402, 1493, 1493, 1493,+ 1493, 1493, 1493, 1493, 1493, 1422, 1422, 1422, 1422,+ 1422, 1422, 1422, 1422, -20907, -20907, -20907, -20907, 27758,+ 27758, 27758, 27758, -3799, -3799, -3799, -3799, -15690, -15690,+ -15690, -15690, -171, -171, -171, -171, 622, 622, 622,+ 622, 1577, 1577, 1577, 1577, 182, 182, 182, 182,+ -5827, -5827, 17363, 17363, -26360, -26360, -29057, -29057, 5571,+ 5571, -1102, -1102, 21438, 21438, -26242, -26242, 573, 573,+ -1325, -1325, 264, 264, 383, 383, -829, -829, 1458,+ 1458, -1602, -1602, -130, -130, -5689, -6516, 1496, 30967,+ -23565, 20179, 20710, 25080, -12796, 26616, 16064, -12442, 9134,+ -650, -25986, 27837, 1223, 652, -552, 1015, -1293, 1491,+ -282, -1544, 516, -8, -320, -666, -1618, -1162, 126,+ 1469, -335, -11477, -32227, 20494, -27738, 945, -14883, 6182,+ 32010, 10631, 29175, -28762, -18486, 17560, -14430, -5276, -1103,+ 555, -1251, 1550, 422, 177, -291, 1574, -246, 1159,+ -777, -602, -1590, -872, 418, -156, 11182, 13387, -14233,+ -21655, 13131, -4587, 23092, 5493, -32502, 30317, -18741, 12639,+ 20100, 18525, 19529, -12619, 430, 843, 871, 105, 587,+ -235, -460, 1653, 778, -147, 1483, 1119, 644, 349,+ 329, -75, 787, 787, 787, 787, 787, 787, 787,+ 787, 787, 787, 787, 787, 787, 787, 787, 787,+ -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517,+ -1517, -1517, -1517, -1517, -1517, -1517, -1517, 28191, 28191,+ 28191, 28191, 28191, 28191, 28191, 28191, -16694, -16694, -16694,+ -16694, -16694, -16694, -16694, -16694, 287, 287, 287, 287,+ 287, 287, 287, 287, 202, 202, 202, 202, 202,+ 202, 202, 202, 10690, 10690, 10690, 10690, 1358, 1358,+ 1358, 1358, -11202, -11202, -11202, -11202, 31164, 31164, 31164,+ 31164, 962, 962, 962, 962, -1202, -1202, -1202, -1202,+ -1474, -1474, -1474, -1474, 1468, 1468, 1468, 1468, -28073,+ -28073, 24313, 24313, -10532, -10532, 8800, 8800, 18426, 18426,+ 8859, 8859, 26675, 26675, -16163, -16163, -681, -681, 1017,+ 1017, 732, 732, 608, 608, -1542, -1542, 411, 411,+ -205, -205, -1571, -1571, 19883, -28250, -15887, -8898, -28309,+ 9075, -30199, 18249, 13426, 14017, -29156, -12757, 16832, 4311,+ -24155, -17915, -853, -90, -271, 830, 107, -1421, -247,+ -951, -398, 961, -1508, -725, 448, -1065, 677, -1275,+ -31183, 25435, -7382, 24391, -20927, 10946, 24214, 16989, 10335,+ -7934, -22502, 10906, 31636, 28644, 23998, -17422, 817, 603,+ 1322, -1465, -1215, 1218, -874, -1187, -1185, -1278, -1510,+ -870, -108, 996, 958, 1522, 20297, 2146, 15355, -32384,+ -6280, -14903, -11044, 14469, -21498, -20198, 23210, -17442, -23860,+ -20257, 7756, 23132, 1097, 610, -1285, 384, -136, -1335,+ 220, -1659, -1530, 794, -854, 478, -308, 991, -1460,+ 1628, -1103, 555, -1251, 1550, 422, 177, -291, 1574,+ -246, 1159, -777, -602, -1590, -872, 418, -156, 430,+ 843, 871, 105, 587, -235, -460, 1653, 778, -147,+ 1483, 1119, 644, 349, 329, -75, 817, 603, 1322,+ -1465, -1215, 1218, -874, -1187, -1185, -1278, -1510, -870,+ -108, 996, 958, 1522, 1097, 610, -1285, 384, -136,+ -1335, 220, -1659, -1530, 794, -854, 478, -308, 991,+ -1460, 1628, -335, -11477, -32227, 20494, -27738, 945, -14883,+ 6182, 32010, 10631, 29175, -28762, -18486, 17560, -14430, -5276,+ 11182, 13387, -14233, -21655, 13131, -4587, 23092, 5493, -32502,+ 30317, -18741, 12639, 20100, 18525, 19529, -12619, -31183, 25435,+ -7382, 24391, -20927, 10946, 24214, 16989, 10335, -7934, -22502,+ 10906, 31636, 28644, 23998, -17422, 20297, 2146, 15355, -32384,+ -6280, -14903, -11044, 14469, -21498, -20198, 23210, -17442, -23860,+ -20257, 7756, 23132,+};++#else /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++MLK_EMPTY_CU(avx2_consts)++#endif /* !(MLK_ARITH_BACKEND_X86_64_DEFAULT && \+ !MLK_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,25 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++#ifndef MLK_NATIVE_X86_64_SRC_CONSTS_H+#define MLK_NATIVE_X86_64_SRC_CONSTS_H+#include "../../../common.h"+#define MLK_AVX2_BACKEND_DATA_OFFSET_REVIDXB 0+#define MLK_AVX2_BACKEND_DATA_OFFSET_REVIDXD 16+#define MLK_AVX2_BACKEND_DATA_OFFSET_ZETAS_EXP 32+#define MLK_AVX2_BACKEND_DATA_OFFSET_MULCACHE_TWIDDLES 496++#ifndef __ASSEMBLER__+#define mlk_qdata MLK_NAMESPACE(qdata)+MLK_INTERNAL_DATA_DECLARATION const int16_t mlk_qdata[624];+#endif++#endif /* !MLK_NATIVE_X86_64_SRC_CONSTS_H */
@@ -0,0 +1,743 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [AVX2_NTT]+ * Faster AVX2 optimized NTT multiplication for Ring-LWE lattice cryptography.+ * Gregor Seiler+ * https://eprint.iacr.org/2018/039+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ *+ * The core ideas behind the implementation are described in @[AVX2_NTT].+ *+ * Changes:+ * - Different placement of modular reductions to simplify+ * reasoning of non-overflow+ */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API))+/*yaml+ Name: invntt_avx2_asm+ Description: x86_64 AVX2 inverse NTT+ Signature: void mlk_invntt_avx2_asm(int16_t *r, const int16_t *qdata)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t *r+ description: Input/output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 1248+ permissions: read-only+ c_parameter: const int16_t *qdata+ description: Precomputed constants (624 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_intt_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(invntt_avx2_asm)+MLK_ASM_FN_SYMBOL(invntt_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0xd8a1d8a1, %eax # imm = 0xD8A1D8A1+ vmovd %eax, %xmm2+ vpbroadcastd %xmm2, %ymm2+ movl $0x5a105a1, %eax # imm = 0x5A105A1+ vmovd %eax, %xmm3+ vpbroadcastd %xmm3, %ymm3+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x40(%rdi), %ymm6+ vmovdqa 0x20(%rdi), %ymm5+ vmovdqa 0x60(%rdi), %ymm7+ vpmullw %ymm2, %ymm4, %ymm12+ vpmulhw %ymm3, %ymm4, %ymm4+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm4, %ymm4+ vpmullw %ymm2, %ymm6, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm6, %ymm6+ vpmullw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm5, %ymm5+ vpmullw %ymm2, %ymm7, %ymm12+ vpmulhw %ymm3, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm7, %ymm7+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xc0(%rdi), %ymm10+ vmovdqa 0xa0(%rdi), %ymm9+ vmovdqa 0xe0(%rdi), %ymm11+ vpmullw %ymm2, %ymm8, %ymm12+ vpmulhw %ymm3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm8, %ymm8+ vpmullw %ymm2, %ymm10, %ymm12+ vpmulhw %ymm3, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm10, %ymm10+ vpmullw %ymm2, %ymm9, %ymm12+ vpmulhw %ymm3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm9, %ymm9+ vpmullw %ymm2, %ymm11, %ymm12+ vpmulhw %ymm3, %ymm11, %ymm11+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm11, %ymm11+ vpermq $0x4e, 0x3a0(%rsi), %ymm15 # ymm15 = mem[2,3,0,1]+ vpermq $0x4e, 0x360(%rsi), %ymm1 # ymm1 = mem[2,3,0,1]+ vpermq $0x4e, 0x3c0(%rsi), %ymm2 # ymm2 = mem[2,3,0,1]+ vpermq $0x4e, 0x380(%rsi), %ymm3 # ymm3 = mem[2,3,0,1]+ vmovdqa (%rsi), %ymm12+ vpshufb %ymm12, %ymm15, %ymm15+ vpshufb %ymm12, %ymm1, %ymm1+ vpshufb %ymm12, %ymm2, %ymm2+ vpshufb %ymm12, %ymm3, %ymm3+ vpsubw %ymm4, %ymm6, %ymm12+ vpaddw %ymm6, %ymm4, %ymm4+ vpsubw %ymm5, %ymm7, %ymm13+ vpmullw %ymm15, %ymm12, %ymm6+ vpaddw %ymm7, %ymm5, %ymm5+ vpsubw %ymm8, %ymm10, %ymm14+ vpmullw %ymm15, %ymm13, %ymm7+ vpaddw %ymm10, %ymm8, %ymm8+ vpsubw %ymm9, %ymm11, %ymm15+ vpmullw %ymm1, %ymm14, %ymm10+ vpaddw %ymm11, %ymm9, %ymm9+ vpmullw %ymm1, %ymm15, %ymm11+ vpmulhw %ymm2, %ymm12, %ymm12+ vpmulhw %ymm2, %ymm13, %ymm13+ vpmulhw %ymm3, %ymm14, %ymm14+ vpmulhw %ymm3, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm6, %ymm12, %ymm6+ vpsubw %ymm7, %ymm13, %ymm7+ vpsubw %ymm10, %ymm14, %ymm10+ vpsubw %ymm11, %ymm15, %ymm11+ vpermq $0x4e, 0x320(%rsi), %ymm2 # ymm2 = mem[2,3,0,1]+ vpermq $0x4e, 0x340(%rsi), %ymm3 # ymm3 = mem[2,3,0,1]+ vmovdqa (%rsi), %ymm1+ vpshufb %ymm1, %ymm2, %ymm2+ vpshufb %ymm1, %ymm3, %ymm3+ vpsubw %ymm4, %ymm8, %ymm12+ vpaddw %ymm8, %ymm4, %ymm4+ vpsubw %ymm5, %ymm9, %ymm13+ vpmullw %ymm2, %ymm12, %ymm8+ vpaddw %ymm9, %ymm5, %ymm5+ vpsubw %ymm6, %ymm10, %ymm14+ vpmullw %ymm2, %ymm13, %ymm9+ vpaddw %ymm10, %ymm6, %ymm6+ vpsubw %ymm7, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm10+ vpaddw %ymm11, %ymm7, %ymm7+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm3, %ymm12, %ymm12+ vpmulhw %ymm3, %ymm13, %ymm13+ vpmulhw %ymm3, %ymm14, %ymm14+ vpmulhw %ymm3, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm8, %ymm12, %ymm8+ vpsubw %ymm9, %ymm13, %ymm9+ vpsubw %ymm10, %ymm14, %ymm10+ vpsubw %ymm11, %ymm15, %ymm11+ vpslld $0x10, %ymm5, %ymm3+ vpblendw $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7],ymm4[8],ymm3[9],ymm4[10],ymm3[11],ymm4[12],ymm3[13],ymm4[14],ymm3[15]+ vpsrld $0x10, %ymm4, %ymm4+ vpblendw $0xaa, %ymm5, %ymm4, %ymm5 # ymm5 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7],ymm4[8],ymm5[9],ymm4[10],ymm5[11],ymm4[12],ymm5[13],ymm4[14],ymm5[15]+ vpslld $0x10, %ymm7, %ymm4+ vpblendw $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7],ymm6[8],ymm4[9],ymm6[10],ymm4[11],ymm6[12],ymm4[13],ymm6[14],ymm4[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7],ymm6[8],ymm7[9],ymm6[10],ymm7[11],ymm6[12],ymm7[13],ymm6[14],ymm7[15]+ vpslld $0x10, %ymm9, %ymm6+ vpblendw $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7],ymm8[8],ymm6[9],ymm8[10],ymm6[11],ymm8[12],ymm6[13],ymm8[14],ymm6[15]+ vpsrld $0x10, %ymm8, %ymm8+ vpblendw $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7],ymm8[8],ymm9[9],ymm8[10],ymm9[11],ymm8[12],ymm9[13],ymm8[14],ymm9[15]+ vpslld $0x10, %ymm11, %ymm8+ vpblendw $0xaa, %ymm8, %ymm10, %ymm8 # ymm8 = ymm10[0],ymm8[1],ymm10[2],ymm8[3],ymm10[4],ymm8[5],ymm10[6],ymm8[7],ymm10[8],ymm8[9],ymm10[10],ymm8[11],ymm10[12],ymm8[13],ymm10[14],ymm8[15]+ vpsrld $0x10, %ymm10, %ymm10+ vpblendw $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7],ymm10[8],ymm11[9],ymm10[10],ymm11[11],ymm10[12],ymm11[13],ymm10[14],ymm11[15]+ vmovdqa 0x20(%rsi), %ymm12+ vpermd 0x2e0(%rsi), %ymm12, %ymm2+ vpermd 0x300(%rsi), %ymm12, %ymm10+ vpsubw %ymm3, %ymm5, %ymm12+ vpaddw %ymm5, %ymm3, %ymm3+ vpsubw %ymm4, %ymm7, %ymm13+ vpmullw %ymm2, %ymm12, %ymm5+ vpaddw %ymm7, %ymm4, %ymm4+ vpsubw %ymm6, %ymm9, %ymm14+ vpmullw %ymm2, %ymm13, %ymm7+ vpaddw %ymm9, %ymm6, %ymm6+ vpsubw %ymm8, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm9+ vpaddw %ymm11, %ymm8, %ymm8+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm10, %ymm12, %ymm12+ vpmulhw %ymm10, %ymm13, %ymm13+ vpmulhw %ymm10, %ymm14, %ymm14+ vpmulhw %ymm10, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm5, %ymm12, %ymm5+ vpsubw %ymm7, %ymm13, %ymm7+ vpsubw %ymm9, %ymm14, %ymm9+ vpsubw %ymm11, %ymm15, %ymm11+ movl $0x4ebf4ebf, %eax # imm = 0x4EBF4EBF+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ vpmulhw %ymm1, %ymm3, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm3, %ymm3+ vmovsldup %ymm4, %ymm10 # ymm10 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm10, %ymm3, %ymm10 # ymm10 = ymm3[0],ymm10[1],ymm3[2],ymm10[3],ymm3[4],ymm10[5],ymm3[6],ymm10[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm8, %ymm3 # ymm3 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm6, %ymm3 # ymm3 = ymm6[0],ymm3[1],ymm6[2],ymm3[3],ymm6[4],ymm3[5],ymm6[6],ymm3[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm8, %ymm6, %ymm8 # ymm8 = ymm6[0],ymm8[1],ymm6[2],ymm8[3],ymm6[4],ymm8[5],ymm6[6],ymm8[7]+ vmovsldup %ymm7, %ymm6 # ymm6 = ymm7[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vmovsldup %ymm11, %ymm5 # ymm5 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm5[1],ymm9[2],ymm5[3],ymm9[4],ymm5[5],ymm9[6],ymm5[7]+ vpsrlq $0x20, %ymm9, %ymm9+ vpblendd $0xaa, %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[0],ymm11[1],ymm9[2],ymm11[3],ymm9[4],ymm11[5],ymm9[6],ymm11[7]+ vpermq $0x1b, 0x2a0(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpermq $0x1b, 0x2c0(%rsi), %ymm9 # ymm9 = mem[3,2,1,0]+ vpsubw %ymm10, %ymm4, %ymm12+ vpaddw %ymm4, %ymm10, %ymm10+ vpsubw %ymm3, %ymm8, %ymm13+ vpmullw %ymm2, %ymm12, %ymm4+ vpaddw %ymm8, %ymm3, %ymm3+ vpsubw %ymm6, %ymm7, %ymm14+ vpmullw %ymm2, %ymm13, %ymm8+ vpaddw %ymm7, %ymm6, %ymm6+ vpsubw %ymm5, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm7+ vpaddw %ymm11, %ymm5, %ymm5+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm9, %ymm12, %ymm12+ vpmulhw %ymm9, %ymm13, %ymm13+ vpmulhw %ymm9, %ymm14, %ymm14+ vpmulhw %ymm9, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm4, %ymm4+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm4, %ymm12, %ymm4+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm7, %ymm14, %ymm7+ vpsubw %ymm11, %ymm15, %ymm11+ vpmulhw %ymm1, %ymm10, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm10, %ymm10+ vpunpcklqdq %ymm3, %ymm10, %ymm9 # ymm9 = ymm10[0],ymm3[0],ymm10[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[1],ymm3[1],ymm10[3],ymm3[3]+ vpunpcklqdq %ymm5, %ymm6, %ymm10 # ymm10 = ymm6[0],ymm5[0],ymm6[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[1],ymm5[1],ymm6[3],ymm5[3]+ vpunpcklqdq %ymm8, %ymm4, %ymm6 # ymm6 = ymm4[0],ymm8[0],ymm4[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[1],ymm8[1],ymm4[3],ymm8[3]+ vpunpcklqdq %ymm11, %ymm7, %ymm4 # ymm4 = ymm7[0],ymm11[0],ymm7[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[1],ymm11[1],ymm7[3],ymm11[3]+ vpermq $0x4e, 0x260(%rsi), %ymm2 # ymm2 = mem[2,3,0,1]+ vpermq $0x4e, 0x280(%rsi), %ymm7 # ymm7 = mem[2,3,0,1]+ vpsubw %ymm9, %ymm3, %ymm12+ vpaddw %ymm3, %ymm9, %ymm9+ vpsubw %ymm10, %ymm5, %ymm13+ vpmullw %ymm2, %ymm12, %ymm3+ vpaddw %ymm5, %ymm10, %ymm10+ vpsubw %ymm6, %ymm8, %ymm14+ vpmullw %ymm2, %ymm13, %ymm5+ vpaddw %ymm8, %ymm6, %ymm6+ vpsubw %ymm4, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm8+ vpaddw %ymm11, %ymm4, %ymm4+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm7, %ymm12, %ymm12+ vpmulhw %ymm7, %ymm13, %ymm13+ vpmulhw %ymm7, %ymm14, %ymm14+ vpmulhw %ymm7, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm3, %ymm3+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm3, %ymm12, %ymm3+ vpsubw %ymm5, %ymm13, %ymm5+ vpsubw %ymm8, %ymm14, %ymm8+ vpsubw %ymm11, %ymm15, %ymm11+ vpmulhw %ymm1, %ymm9, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm9, %ymm9+ vperm2i128 $0x20, %ymm10, %ymm9, %ymm7 # ymm7 = ymm9[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm9, %ymm10 # ymm10 = ymm9[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm4, %ymm6, %ymm9 # ymm9 = ymm6[0,1],ymm4[0,1]+ vperm2i128 $0x31, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[2,3],ymm4[2,3]+ vperm2i128 $0x20, %ymm5, %ymm3, %ymm6 # ymm6 = ymm3[0,1],ymm5[0,1]+ vperm2i128 $0x31, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[2,3],ymm5[2,3]+ vperm2i128 $0x20, %ymm11, %ymm8, %ymm3 # ymm3 = ymm8[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm8, %ymm11 # ymm11 = ymm8[2,3],ymm11[2,3]+ vmovdqa 0x220(%rsi), %ymm2+ vmovdqa 0x240(%rsi), %ymm8+ vpsubw %ymm7, %ymm10, %ymm12+ vpaddw %ymm10, %ymm7, %ymm7+ vpsubw %ymm9, %ymm4, %ymm13+ vpmullw %ymm2, %ymm12, %ymm10+ vpaddw %ymm4, %ymm9, %ymm9+ vpsubw %ymm6, %ymm5, %ymm14+ vpmullw %ymm2, %ymm13, %ymm4+ vpaddw %ymm5, %ymm6, %ymm6+ vpsubw %ymm3, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm5+ vpaddw %ymm11, %ymm3, %ymm3+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm8, %ymm12, %ymm12+ vpmulhw %ymm8, %ymm13, %ymm13+ vpmulhw %ymm8, %ymm14, %ymm14+ vpmulhw %ymm8, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm4, %ymm4+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm10, %ymm12, %ymm10+ vpsubw %ymm4, %ymm13, %ymm4+ vpsubw %ymm5, %ymm14, %ymm5+ vpsubw %ymm11, %ymm15, %ymm11+ vpmulhw %ymm1, %ymm7, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm7, %ymm7+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa %ymm6, 0x40(%rdi)+ vmovdqa %ymm3, 0x60(%rdi)+ vmovdqa %ymm10, 0x80(%rdi)+ vmovdqa %ymm4, 0xa0(%rdi)+ vmovdqa %ymm5, 0xc0(%rdi)+ vmovdqa %ymm11, 0xe0(%rdi)+ movl $0xd8a1d8a1, %eax # imm = 0xD8A1D8A1+ vmovd %eax, %xmm2+ vpbroadcastd %xmm2, %ymm2+ movl $0x5a105a1, %eax # imm = 0x5A105A1+ vmovd %eax, %xmm3+ vpbroadcastd %xmm3, %ymm3+ vmovdqa 0x100(%rdi), %ymm4+ vmovdqa 0x140(%rdi), %ymm6+ vmovdqa 0x120(%rdi), %ymm5+ vmovdqa 0x160(%rdi), %ymm7+ vpmullw %ymm2, %ymm4, %ymm12+ vpmulhw %ymm3, %ymm4, %ymm4+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm4, %ymm4+ vpmullw %ymm2, %ymm6, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm6, %ymm6+ vpmullw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm5, %ymm5+ vpmullw %ymm2, %ymm7, %ymm12+ vpmulhw %ymm3, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm7, %ymm7+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1c0(%rdi), %ymm10+ vmovdqa 0x1a0(%rdi), %ymm9+ vmovdqa 0x1e0(%rdi), %ymm11+ vpmullw %ymm2, %ymm8, %ymm12+ vpmulhw %ymm3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm8, %ymm8+ vpmullw %ymm2, %ymm10, %ymm12+ vpmulhw %ymm3, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm10, %ymm10+ vpmullw %ymm2, %ymm9, %ymm12+ vpmulhw %ymm3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm9, %ymm9+ vpmullw %ymm2, %ymm11, %ymm12+ vpmulhw %ymm3, %ymm11, %ymm11+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm11, %ymm11+ vpermq $0x4e, 0x1e0(%rsi), %ymm15 # ymm15 = mem[2,3,0,1]+ vpermq $0x4e, 0x1a0(%rsi), %ymm1 # ymm1 = mem[2,3,0,1]+ vpermq $0x4e, 0x200(%rsi), %ymm2 # ymm2 = mem[2,3,0,1]+ vpermq $0x4e, 0x1c0(%rsi), %ymm3 # ymm3 = mem[2,3,0,1]+ vmovdqa (%rsi), %ymm12+ vpshufb %ymm12, %ymm15, %ymm15+ vpshufb %ymm12, %ymm1, %ymm1+ vpshufb %ymm12, %ymm2, %ymm2+ vpshufb %ymm12, %ymm3, %ymm3+ vpsubw %ymm4, %ymm6, %ymm12+ vpaddw %ymm6, %ymm4, %ymm4+ vpsubw %ymm5, %ymm7, %ymm13+ vpmullw %ymm15, %ymm12, %ymm6+ vpaddw %ymm7, %ymm5, %ymm5+ vpsubw %ymm8, %ymm10, %ymm14+ vpmullw %ymm15, %ymm13, %ymm7+ vpaddw %ymm10, %ymm8, %ymm8+ vpsubw %ymm9, %ymm11, %ymm15+ vpmullw %ymm1, %ymm14, %ymm10+ vpaddw %ymm11, %ymm9, %ymm9+ vpmullw %ymm1, %ymm15, %ymm11+ vpmulhw %ymm2, %ymm12, %ymm12+ vpmulhw %ymm2, %ymm13, %ymm13+ vpmulhw %ymm3, %ymm14, %ymm14+ vpmulhw %ymm3, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm6, %ymm12, %ymm6+ vpsubw %ymm7, %ymm13, %ymm7+ vpsubw %ymm10, %ymm14, %ymm10+ vpsubw %ymm11, %ymm15, %ymm11+ vpermq $0x4e, 0x160(%rsi), %ymm2 # ymm2 = mem[2,3,0,1]+ vpermq $0x4e, 0x180(%rsi), %ymm3 # ymm3 = mem[2,3,0,1]+ vmovdqa (%rsi), %ymm1+ vpshufb %ymm1, %ymm2, %ymm2+ vpshufb %ymm1, %ymm3, %ymm3+ vpsubw %ymm4, %ymm8, %ymm12+ vpaddw %ymm8, %ymm4, %ymm4+ vpsubw %ymm5, %ymm9, %ymm13+ vpmullw %ymm2, %ymm12, %ymm8+ vpaddw %ymm9, %ymm5, %ymm5+ vpsubw %ymm6, %ymm10, %ymm14+ vpmullw %ymm2, %ymm13, %ymm9+ vpaddw %ymm10, %ymm6, %ymm6+ vpsubw %ymm7, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm10+ vpaddw %ymm11, %ymm7, %ymm7+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm3, %ymm12, %ymm12+ vpmulhw %ymm3, %ymm13, %ymm13+ vpmulhw %ymm3, %ymm14, %ymm14+ vpmulhw %ymm3, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm8, %ymm12, %ymm8+ vpsubw %ymm9, %ymm13, %ymm9+ vpsubw %ymm10, %ymm14, %ymm10+ vpsubw %ymm11, %ymm15, %ymm11+ vpslld $0x10, %ymm5, %ymm3+ vpblendw $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7],ymm4[8],ymm3[9],ymm4[10],ymm3[11],ymm4[12],ymm3[13],ymm4[14],ymm3[15]+ vpsrld $0x10, %ymm4, %ymm4+ vpblendw $0xaa, %ymm5, %ymm4, %ymm5 # ymm5 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7],ymm4[8],ymm5[9],ymm4[10],ymm5[11],ymm4[12],ymm5[13],ymm4[14],ymm5[15]+ vpslld $0x10, %ymm7, %ymm4+ vpblendw $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7],ymm6[8],ymm4[9],ymm6[10],ymm4[11],ymm6[12],ymm4[13],ymm6[14],ymm4[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7],ymm6[8],ymm7[9],ymm6[10],ymm7[11],ymm6[12],ymm7[13],ymm6[14],ymm7[15]+ vpslld $0x10, %ymm9, %ymm6+ vpblendw $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7],ymm8[8],ymm6[9],ymm8[10],ymm6[11],ymm8[12],ymm6[13],ymm8[14],ymm6[15]+ vpsrld $0x10, %ymm8, %ymm8+ vpblendw $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7],ymm8[8],ymm9[9],ymm8[10],ymm9[11],ymm8[12],ymm9[13],ymm8[14],ymm9[15]+ vpslld $0x10, %ymm11, %ymm8+ vpblendw $0xaa, %ymm8, %ymm10, %ymm8 # ymm8 = ymm10[0],ymm8[1],ymm10[2],ymm8[3],ymm10[4],ymm8[5],ymm10[6],ymm8[7],ymm10[8],ymm8[9],ymm10[10],ymm8[11],ymm10[12],ymm8[13],ymm10[14],ymm8[15]+ vpsrld $0x10, %ymm10, %ymm10+ vpblendw $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7],ymm10[8],ymm11[9],ymm10[10],ymm11[11],ymm10[12],ymm11[13],ymm10[14],ymm11[15]+ vmovdqa 0x20(%rsi), %ymm12+ vpermd 0x120(%rsi), %ymm12, %ymm2+ vpermd 0x140(%rsi), %ymm12, %ymm10+ vpsubw %ymm3, %ymm5, %ymm12+ vpaddw %ymm5, %ymm3, %ymm3+ vpsubw %ymm4, %ymm7, %ymm13+ vpmullw %ymm2, %ymm12, %ymm5+ vpaddw %ymm7, %ymm4, %ymm4+ vpsubw %ymm6, %ymm9, %ymm14+ vpmullw %ymm2, %ymm13, %ymm7+ vpaddw %ymm9, %ymm6, %ymm6+ vpsubw %ymm8, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm9+ vpaddw %ymm11, %ymm8, %ymm8+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm10, %ymm12, %ymm12+ vpmulhw %ymm10, %ymm13, %ymm13+ vpmulhw %ymm10, %ymm14, %ymm14+ vpmulhw %ymm10, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm5, %ymm12, %ymm5+ vpsubw %ymm7, %ymm13, %ymm7+ vpsubw %ymm9, %ymm14, %ymm9+ vpsubw %ymm11, %ymm15, %ymm11+ movl $0x4ebf4ebf, %eax # imm = 0x4EBF4EBF+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ vpmulhw %ymm1, %ymm3, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm3, %ymm3+ vmovsldup %ymm4, %ymm10 # ymm10 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm10, %ymm3, %ymm10 # ymm10 = ymm3[0],ymm10[1],ymm3[2],ymm10[3],ymm3[4],ymm10[5],ymm3[6],ymm10[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm8, %ymm3 # ymm3 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm6, %ymm3 # ymm3 = ymm6[0],ymm3[1],ymm6[2],ymm3[3],ymm6[4],ymm3[5],ymm6[6],ymm3[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm8, %ymm6, %ymm8 # ymm8 = ymm6[0],ymm8[1],ymm6[2],ymm8[3],ymm6[4],ymm8[5],ymm6[6],ymm8[7]+ vmovsldup %ymm7, %ymm6 # ymm6 = ymm7[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vmovsldup %ymm11, %ymm5 # ymm5 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm5[1],ymm9[2],ymm5[3],ymm9[4],ymm5[5],ymm9[6],ymm5[7]+ vpsrlq $0x20, %ymm9, %ymm9+ vpblendd $0xaa, %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[0],ymm11[1],ymm9[2],ymm11[3],ymm9[4],ymm11[5],ymm9[6],ymm11[7]+ vpermq $0x1b, 0xe0(%rsi), %ymm2 # ymm2 = mem[3,2,1,0]+ vpermq $0x1b, 0x100(%rsi), %ymm9 # ymm9 = mem[3,2,1,0]+ vpsubw %ymm10, %ymm4, %ymm12+ vpaddw %ymm4, %ymm10, %ymm10+ vpsubw %ymm3, %ymm8, %ymm13+ vpmullw %ymm2, %ymm12, %ymm4+ vpaddw %ymm8, %ymm3, %ymm3+ vpsubw %ymm6, %ymm7, %ymm14+ vpmullw %ymm2, %ymm13, %ymm8+ vpaddw %ymm7, %ymm6, %ymm6+ vpsubw %ymm5, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm7+ vpaddw %ymm11, %ymm5, %ymm5+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm9, %ymm12, %ymm12+ vpmulhw %ymm9, %ymm13, %ymm13+ vpmulhw %ymm9, %ymm14, %ymm14+ vpmulhw %ymm9, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm4, %ymm4+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm4, %ymm12, %ymm4+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm7, %ymm14, %ymm7+ vpsubw %ymm11, %ymm15, %ymm11+ vpmulhw %ymm1, %ymm10, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm10, %ymm10+ vpunpcklqdq %ymm3, %ymm10, %ymm9 # ymm9 = ymm10[0],ymm3[0],ymm10[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[1],ymm3[1],ymm10[3],ymm3[3]+ vpunpcklqdq %ymm5, %ymm6, %ymm10 # ymm10 = ymm6[0],ymm5[0],ymm6[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[1],ymm5[1],ymm6[3],ymm5[3]+ vpunpcklqdq %ymm8, %ymm4, %ymm6 # ymm6 = ymm4[0],ymm8[0],ymm4[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[1],ymm8[1],ymm4[3],ymm8[3]+ vpunpcklqdq %ymm11, %ymm7, %ymm4 # ymm4 = ymm7[0],ymm11[0],ymm7[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[1],ymm11[1],ymm7[3],ymm11[3]+ vpermq $0x4e, 0xa0(%rsi), %ymm2 # ymm2 = mem[2,3,0,1]+ vpermq $0x4e, 0xc0(%rsi), %ymm7 # ymm7 = mem[2,3,0,1]+ vpsubw %ymm9, %ymm3, %ymm12+ vpaddw %ymm3, %ymm9, %ymm9+ vpsubw %ymm10, %ymm5, %ymm13+ vpmullw %ymm2, %ymm12, %ymm3+ vpaddw %ymm5, %ymm10, %ymm10+ vpsubw %ymm6, %ymm8, %ymm14+ vpmullw %ymm2, %ymm13, %ymm5+ vpaddw %ymm8, %ymm6, %ymm6+ vpsubw %ymm4, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm8+ vpaddw %ymm11, %ymm4, %ymm4+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm7, %ymm12, %ymm12+ vpmulhw %ymm7, %ymm13, %ymm13+ vpmulhw %ymm7, %ymm14, %ymm14+ vpmulhw %ymm7, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm3, %ymm3+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm3, %ymm12, %ymm3+ vpsubw %ymm5, %ymm13, %ymm5+ vpsubw %ymm8, %ymm14, %ymm8+ vpsubw %ymm11, %ymm15, %ymm11+ vpmulhw %ymm1, %ymm9, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm9, %ymm9+ vperm2i128 $0x20, %ymm10, %ymm9, %ymm7 # ymm7 = ymm9[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm9, %ymm10 # ymm10 = ymm9[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm4, %ymm6, %ymm9 # ymm9 = ymm6[0,1],ymm4[0,1]+ vperm2i128 $0x31, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[2,3],ymm4[2,3]+ vperm2i128 $0x20, %ymm5, %ymm3, %ymm6 # ymm6 = ymm3[0,1],ymm5[0,1]+ vperm2i128 $0x31, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[2,3],ymm5[2,3]+ vperm2i128 $0x20, %ymm11, %ymm8, %ymm3 # ymm3 = ymm8[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm8, %ymm11 # ymm11 = ymm8[2,3],ymm11[2,3]+ vmovdqa 0x60(%rsi), %ymm2+ vmovdqa 0x80(%rsi), %ymm8+ vpsubw %ymm7, %ymm10, %ymm12+ vpaddw %ymm10, %ymm7, %ymm7+ vpsubw %ymm9, %ymm4, %ymm13+ vpmullw %ymm2, %ymm12, %ymm10+ vpaddw %ymm4, %ymm9, %ymm9+ vpsubw %ymm6, %ymm5, %ymm14+ vpmullw %ymm2, %ymm13, %ymm4+ vpaddw %ymm5, %ymm6, %ymm6+ vpsubw %ymm3, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm5+ vpaddw %ymm11, %ymm3, %ymm3+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm8, %ymm12, %ymm12+ vpmulhw %ymm8, %ymm13, %ymm13+ vpmulhw %ymm8, %ymm14, %ymm14+ vpmulhw %ymm8, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm4, %ymm4+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm10, %ymm12, %ymm10+ vpsubw %ymm4, %ymm13, %ymm4+ vpsubw %ymm5, %ymm14, %ymm5+ vpsubw %ymm11, %ymm15, %ymm11+ vpmulhw %ymm1, %ymm7, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm7, %ymm7+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa %ymm6, 0x140(%rdi)+ vmovdqa %ymm3, 0x160(%rdi)+ vmovdqa %ymm10, 0x180(%rdi)+ vmovdqa %ymm4, 0x1a0(%rdi)+ vmovdqa %ymm5, 0x1c0(%rdi)+ vmovdqa %ymm11, 0x1e0(%rdi)+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x100(%rdi), %ymm8+ vmovdqa 0x20(%rdi), %ymm5+ vmovdqa 0x120(%rdi), %ymm9+ vpbroadcastq 0x40(%rsi), %ymm2+ vmovdqa 0x40(%rdi), %ymm6+ vmovdqa 0x140(%rdi), %ymm10+ vmovdqa 0x60(%rdi), %ymm7+ vmovdqa 0x160(%rdi), %ymm11+ vpbroadcastq 0x48(%rsi), %ymm3+ vpsubw %ymm4, %ymm8, %ymm12+ vpaddw %ymm8, %ymm4, %ymm4+ vpsubw %ymm5, %ymm9, %ymm13+ vpmullw %ymm2, %ymm12, %ymm8+ vpaddw %ymm9, %ymm5, %ymm5+ vpsubw %ymm6, %ymm10, %ymm14+ vpmullw %ymm2, %ymm13, %ymm9+ vpaddw %ymm10, %ymm6, %ymm6+ vpsubw %ymm7, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm10+ vpaddw %ymm11, %ymm7, %ymm7+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm3, %ymm12, %ymm12+ vpmulhw %ymm3, %ymm13, %ymm13+ vpmulhw %ymm3, %ymm14, %ymm14+ vpmulhw %ymm3, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm8, %ymm12, %ymm8+ vpsubw %ymm9, %ymm13, %ymm9+ vpsubw %ymm10, %ymm14, %ymm10+ vpsubw %ymm11, %ymm15, %ymm11+ vmovdqa %ymm4, (%rdi)+ vmovdqa %ymm5, 0x20(%rdi)+ vmovdqa %ymm6, 0x40(%rdi)+ vmovdqa %ymm7, 0x60(%rdi)+ vmovdqa %ymm8, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa %ymm10, 0x140(%rdi)+ vmovdqa %ymm11, 0x160(%rdi)+ vmovdqa 0x80(%rdi), %ymm4+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm5+ vmovdqa 0x1a0(%rdi), %ymm9+ vpbroadcastq 0x40(%rsi), %ymm2+ vmovdqa 0xc0(%rdi), %ymm6+ vmovdqa 0x1c0(%rdi), %ymm10+ vmovdqa 0xe0(%rdi), %ymm7+ vmovdqa 0x1e0(%rdi), %ymm11+ vpbroadcastq 0x48(%rsi), %ymm3+ vpsubw %ymm4, %ymm8, %ymm12+ vpaddw %ymm8, %ymm4, %ymm4+ vpsubw %ymm5, %ymm9, %ymm13+ vpmullw %ymm2, %ymm12, %ymm8+ vpaddw %ymm9, %ymm5, %ymm5+ vpsubw %ymm6, %ymm10, %ymm14+ vpmullw %ymm2, %ymm13, %ymm9+ vpaddw %ymm10, %ymm6, %ymm6+ vpsubw %ymm7, %ymm11, %ymm15+ vpmullw %ymm2, %ymm14, %ymm10+ vpaddw %ymm11, %ymm7, %ymm7+ vpmullw %ymm2, %ymm15, %ymm11+ vpmulhw %ymm3, %ymm12, %ymm12+ vpmulhw %ymm3, %ymm13, %ymm13+ vpmulhw %ymm3, %ymm14, %ymm14+ vpmulhw %ymm3, %ymm15, %ymm15+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm8, %ymm12, %ymm8+ vpsubw %ymm9, %ymm13, %ymm9+ vpsubw %ymm10, %ymm14, %ymm10+ vpsubw %ymm11, %ymm15, %ymm11+ vmovdqa %ymm4, 0x80(%rdi)+ vmovdqa %ymm5, 0xa0(%rdi)+ vmovdqa %ymm6, 0xc0(%rdi)+ vmovdqa %ymm7, 0xe0(%rdi)+ vmovdqa %ymm8, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa %ymm10, 0x1c0(%rdi)+ vmovdqa %ymm11, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(invntt_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,661 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [AVX2_NTT]+ * Faster AVX2 optimized NTT multiplication for Ring-LWE lattice cryptography.+ * Gregor Seiler+ * https://eprint.iacr.org/2018/039+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ *+ * The core ideas behind the implementation are described in @[AVX2_NTT].+ */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+/*yaml+ Name: ntt_avx2_asm+ Description: x86_64 AVX2 forward NTT+ Signature: void mlk_ntt_avx2_asm(int16_t *r, const int16_t *qdata)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t *r+ description: Input/output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 1248+ permissions: read-only+ c_parameter: const int16_t *qdata+ description: Precomputed constants (624 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_ntt_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(ntt_avx2_asm)+MLK_ASM_FN_SYMBOL(ntt_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ vpbroadcastq 0x40(%rsi), %ymm15+ vmovdqa 0x100(%rdi), %ymm8+ vmovdqa 0x120(%rdi), %ymm9+ vmovdqa 0x140(%rdi), %ymm10+ vmovdqa 0x160(%rdi), %ymm11+ vpbroadcastq 0x48(%rsi), %ymm2+ vpmullw %ymm15, %ymm8, %ymm12+ vpmullw %ymm15, %ymm9, %ymm13+ vpmullw %ymm15, %ymm10, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm2, %ymm11, %ymm11+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x20(%rdi), %ymm5+ vmovdqa 0x40(%rdi), %ymm6+ vmovdqa 0x60(%rdi), %ymm7+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm8, %ymm4, %ymm3+ vpsubw %ymm8, %ymm4, %ymm8+ vpaddw %ymm9, %ymm5, %ymm4+ vpsubw %ymm9, %ymm5, %ymm9+ vpaddw %ymm10, %ymm6, %ymm5+ vpsubw %ymm10, %ymm6, %ymm10+ vpaddw %ymm11, %ymm7, %ymm6+ vpsubw %ymm11, %ymm7, %ymm11+ vpsubw %ymm12, %ymm3, %ymm3+ vpaddw %ymm12, %ymm8, %ymm8+ vpsubw %ymm13, %ymm4, %ymm4+ vpaddw %ymm13, %ymm9, %ymm9+ vpsubw %ymm14, %ymm5, %ymm5+ vpaddw %ymm14, %ymm10, %ymm10+ vpsubw %ymm15, %ymm6, %ymm6+ vpaddw %ymm15, %ymm11, %ymm11+ vmovdqa %ymm3, (%rdi)+ vmovdqa %ymm4, 0x20(%rdi)+ vmovdqa %ymm5, 0x40(%rdi)+ vmovdqa %ymm6, 0x60(%rdi)+ vmovdqa %ymm8, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa %ymm10, 0x140(%rdi)+ vmovdqa %ymm11, 0x160(%rdi)+ vpbroadcastq 0x40(%rsi), %ymm15+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm9+ vmovdqa 0x1c0(%rdi), %ymm10+ vmovdqa 0x1e0(%rdi), %ymm11+ vpbroadcastq 0x48(%rsi), %ymm2+ vpmullw %ymm15, %ymm8, %ymm12+ vpmullw %ymm15, %ymm9, %ymm13+ vpmullw %ymm15, %ymm10, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm2, %ymm11, %ymm11+ vmovdqa 0x80(%rdi), %ymm4+ vmovdqa 0xa0(%rdi), %ymm5+ vmovdqa 0xc0(%rdi), %ymm6+ vmovdqa 0xe0(%rdi), %ymm7+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm8, %ymm4, %ymm3+ vpsubw %ymm8, %ymm4, %ymm8+ vpaddw %ymm9, %ymm5, %ymm4+ vpsubw %ymm9, %ymm5, %ymm9+ vpaddw %ymm10, %ymm6, %ymm5+ vpsubw %ymm10, %ymm6, %ymm10+ vpaddw %ymm11, %ymm7, %ymm6+ vpsubw %ymm11, %ymm7, %ymm11+ vpsubw %ymm12, %ymm3, %ymm3+ vpaddw %ymm12, %ymm8, %ymm8+ vpsubw %ymm13, %ymm4, %ymm4+ vpaddw %ymm13, %ymm9, %ymm9+ vpsubw %ymm14, %ymm5, %ymm5+ vpaddw %ymm14, %ymm10, %ymm10+ vpsubw %ymm15, %ymm6, %ymm6+ vpaddw %ymm15, %ymm11, %ymm11+ vmovdqa %ymm3, 0x80(%rdi)+ vmovdqa %ymm4, 0xa0(%rdi)+ vmovdqa %ymm5, 0xc0(%rdi)+ vmovdqa %ymm6, 0xe0(%rdi)+ vmovdqa %ymm8, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa %ymm10, 0x1c0(%rdi)+ vmovdqa %ymm11, 0x1e0(%rdi)+ vmovdqa 0x60(%rsi), %ymm15+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm9+ vmovdqa 0xc0(%rdi), %ymm10+ vmovdqa 0xe0(%rdi), %ymm11+ vmovdqa 0x80(%rsi), %ymm2+ vpmullw %ymm15, %ymm8, %ymm12+ vpmullw %ymm15, %ymm9, %ymm13+ vpmullw %ymm15, %ymm10, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm2, %ymm11, %ymm11+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x20(%rdi), %ymm5+ vmovdqa 0x40(%rdi), %ymm6+ vmovdqa 0x60(%rdi), %ymm7+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm8, %ymm4, %ymm3+ vpsubw %ymm8, %ymm4, %ymm8+ vpaddw %ymm9, %ymm5, %ymm4+ vpsubw %ymm9, %ymm5, %ymm9+ vpaddw %ymm10, %ymm6, %ymm5+ vpsubw %ymm10, %ymm6, %ymm10+ vpaddw %ymm11, %ymm7, %ymm6+ vpsubw %ymm11, %ymm7, %ymm11+ vpsubw %ymm12, %ymm3, %ymm3+ vpaddw %ymm12, %ymm8, %ymm8+ vpsubw %ymm13, %ymm4, %ymm4+ vpaddw %ymm13, %ymm9, %ymm9+ vpsubw %ymm14, %ymm5, %ymm5+ vpaddw %ymm14, %ymm10, %ymm10+ vpsubw %ymm15, %ymm6, %ymm6+ vpaddw %ymm15, %ymm11, %ymm11+ vperm2i128 $0x20, %ymm10, %ymm5, %ymm7 # ymm7 = ymm5[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm5, %ymm10 # ymm10 = ymm5[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm6, %ymm11 # ymm11 = ymm6[2,3],ymm11[2,3]+ vmovdqa 0xa0(%rsi), %ymm15+ vmovdqa 0xc0(%rsi), %ymm2+ vpmullw %ymm15, %ymm7, %ymm12+ vpmullw %ymm15, %ymm10, %ymm13+ vpmullw %ymm15, %ymm5, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm7, %ymm7+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm2, %ymm5, %ymm5+ vpmulhw %ymm2, %ymm11, %ymm11+ vperm2i128 $0x20, %ymm8, %ymm3, %ymm6 # ymm6 = ymm3[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm3, %ymm8 # ymm8 = ymm3[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm4, %ymm9 # ymm9 = ymm4[2,3],ymm9[2,3]+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm7, %ymm6, %ymm4+ vpsubw %ymm7, %ymm6, %ymm7+ vpaddw %ymm10, %ymm8, %ymm6+ vpsubw %ymm10, %ymm8, %ymm10+ vpaddw %ymm5, %ymm3, %ymm8+ vpsubw %ymm5, %ymm3, %ymm5+ vpaddw %ymm11, %ymm9, %ymm3+ vpsubw %ymm11, %ymm9, %ymm11+ vpsubw %ymm12, %ymm4, %ymm4+ vpaddw %ymm12, %ymm7, %ymm7+ vpsubw %ymm13, %ymm6, %ymm6+ vpaddw %ymm13, %ymm10, %ymm10+ vpsubw %ymm14, %ymm8, %ymm8+ vpaddw %ymm14, %ymm5, %ymm5+ vpsubw %ymm15, %ymm3, %ymm3+ vpaddw %ymm15, %ymm11, %ymm11+ vpunpcklqdq %ymm5, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm5[0],ymm8[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm8, %ymm5 # ymm5 = ymm8[1],ymm5[1],ymm8[3],ymm5[3]+ vpunpcklqdq %ymm11, %ymm3, %ymm8 # ymm8 = ymm3[0],ymm11[0],ymm3[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm3, %ymm11 # ymm11 = ymm3[1],ymm11[1],ymm3[3],ymm11[3]+ vmovdqa 0xe0(%rsi), %ymm15+ vmovdqa 0x100(%rsi), %ymm2+ vpmullw %ymm15, %ymm9, %ymm12+ vpmullw %ymm15, %ymm5, %ymm13+ vpmullw %ymm15, %ymm8, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm5, %ymm5+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm2, %ymm11, %ymm11+ vpunpcklqdq %ymm7, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm7[0],ymm4[2],ymm7[2]+ vpunpckhqdq %ymm7, %ymm4, %ymm7 # ymm7 = ymm4[1],ymm7[1],ymm4[3],ymm7[3]+ vpunpcklqdq %ymm10, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm10[0],ymm6[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[1],ymm10[1],ymm6[3],ymm10[3]+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm9, %ymm3, %ymm6+ vpsubw %ymm9, %ymm3, %ymm9+ vpaddw %ymm5, %ymm7, %ymm3+ vpsubw %ymm5, %ymm7, %ymm5+ vpaddw %ymm8, %ymm4, %ymm7+ vpsubw %ymm8, %ymm4, %ymm8+ vpaddw %ymm11, %ymm10, %ymm4+ vpsubw %ymm11, %ymm10, %ymm11+ vpsubw %ymm12, %ymm6, %ymm6+ vpaddw %ymm12, %ymm9, %ymm9+ vpsubw %ymm13, %ymm3, %ymm3+ vpaddw %ymm13, %ymm5, %ymm5+ vpsubw %ymm14, %ymm7, %ymm7+ vpaddw %ymm14, %ymm8, %ymm8+ vpsubw %ymm15, %ymm4, %ymm4+ vpaddw %ymm15, %ymm11, %ymm11+ vmovsldup %ymm8, %ymm10 # ymm10 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm10, %ymm7, %ymm10 # ymm10 = ymm7[0],ymm10[1],ymm7[2],ymm10[3],ymm7[4],ymm10[5],ymm7[6],ymm10[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm11, %ymm7 # ymm7 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm4, %ymm7 # ymm7 = ymm4[0],ymm7[1],ymm4[2],ymm7[3],ymm4[4],ymm7[5],ymm4[6],ymm7[7]+ vpsrlq $0x20, %ymm4, %ymm4+ vpblendd $0xaa, %ymm11, %ymm4, %ymm11 # ymm11 = ymm4[0],ymm11[1],ymm4[2],ymm11[3],ymm4[4],ymm11[5],ymm4[6],ymm11[7]+ vmovdqa 0x120(%rsi), %ymm15+ vmovdqa 0x140(%rsi), %ymm2+ vpmullw %ymm15, %ymm10, %ymm12+ vpmullw %ymm15, %ymm8, %ymm13+ vpmullw %ymm15, %ymm7, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm2, %ymm7, %ymm7+ vpmulhw %ymm2, %ymm11, %ymm11+ vmovsldup %ymm9, %ymm4 # ymm4 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm9, %ymm6, %ymm9 # ymm9 = ymm6[0],ymm9[1],ymm6[2],ymm9[3],ymm6[4],ymm9[5],ymm6[6],ymm9[7]+ vmovsldup %ymm5, %ymm6 # ymm6 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm3, %ymm6 # ymm6 = ymm3[0],ymm6[1],ymm3[2],ymm6[3],ymm3[4],ymm6[5],ymm3[6],ymm6[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm10, %ymm4, %ymm3+ vpsubw %ymm10, %ymm4, %ymm10+ vpaddw %ymm8, %ymm9, %ymm4+ vpsubw %ymm8, %ymm9, %ymm8+ vpaddw %ymm7, %ymm6, %ymm9+ vpsubw %ymm7, %ymm6, %ymm7+ vpaddw %ymm11, %ymm5, %ymm6+ vpsubw %ymm11, %ymm5, %ymm11+ vpsubw %ymm12, %ymm3, %ymm3+ vpaddw %ymm12, %ymm10, %ymm10+ vpsubw %ymm13, %ymm4, %ymm4+ vpaddw %ymm13, %ymm8, %ymm8+ vpsubw %ymm14, %ymm9, %ymm9+ vpaddw %ymm14, %ymm7, %ymm7+ vpsubw %ymm15, %ymm6, %ymm6+ vpaddw %ymm15, %ymm11, %ymm11+ vpslld $0x10, %ymm7, %ymm5+ vpblendw $0xaa, %ymm5, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm5[1],ymm9[2],ymm5[3],ymm9[4],ymm5[5],ymm9[6],ymm5[7],ymm9[8],ymm5[9],ymm9[10],ymm5[11],ymm9[12],ymm5[13],ymm9[14],ymm5[15]+ vpsrld $0x10, %ymm9, %ymm9+ vpblendw $0xaa, %ymm7, %ymm9, %ymm7 # ymm7 = ymm9[0],ymm7[1],ymm9[2],ymm7[3],ymm9[4],ymm7[5],ymm9[6],ymm7[7],ymm9[8],ymm7[9],ymm9[10],ymm7[11],ymm9[12],ymm7[13],ymm9[14],ymm7[15]+ vpslld $0x10, %ymm11, %ymm9+ vpblendw $0xaa, %ymm9, %ymm6, %ymm9 # ymm9 = ymm6[0],ymm9[1],ymm6[2],ymm9[3],ymm6[4],ymm9[5],ymm6[6],ymm9[7],ymm6[8],ymm9[9],ymm6[10],ymm9[11],ymm6[12],ymm9[13],ymm6[14],ymm9[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm11, %ymm6, %ymm11 # ymm11 = ymm6[0],ymm11[1],ymm6[2],ymm11[3],ymm6[4],ymm11[5],ymm6[6],ymm11[7],ymm6[8],ymm11[9],ymm6[10],ymm11[11],ymm6[12],ymm11[13],ymm6[14],ymm11[15]+ vmovdqa 0x160(%rsi), %ymm15+ vmovdqa 0x180(%rsi), %ymm2+ vpmullw %ymm15, %ymm5, %ymm12+ vpmullw %ymm15, %ymm7, %ymm13+ vpmullw %ymm15, %ymm9, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm5, %ymm5+ vpmulhw %ymm2, %ymm7, %ymm7+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm11, %ymm11+ vpslld $0x10, %ymm10, %ymm6+ vpblendw $0xaa, %ymm6, %ymm3, %ymm6 # ymm6 = ymm3[0],ymm6[1],ymm3[2],ymm6[3],ymm3[4],ymm6[5],ymm3[6],ymm6[7],ymm3[8],ymm6[9],ymm3[10],ymm6[11],ymm3[12],ymm6[13],ymm3[14],ymm6[15]+ vpsrld $0x10, %ymm3, %ymm3+ vpblendw $0xaa, %ymm10, %ymm3, %ymm10 # ymm10 = ymm3[0],ymm10[1],ymm3[2],ymm10[3],ymm3[4],ymm10[5],ymm3[6],ymm10[7],ymm3[8],ymm10[9],ymm3[10],ymm10[11],ymm3[12],ymm10[13],ymm3[14],ymm10[15]+ vpslld $0x10, %ymm8, %ymm3+ vpblendw $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7],ymm4[8],ymm3[9],ymm4[10],ymm3[11],ymm4[12],ymm3[13],ymm4[14],ymm3[15]+ vpsrld $0x10, %ymm4, %ymm4+ vpblendw $0xaa, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm8[1],ymm4[2],ymm8[3],ymm4[4],ymm8[5],ymm4[6],ymm8[7],ymm4[8],ymm8[9],ymm4[10],ymm8[11],ymm4[12],ymm8[13],ymm4[14],ymm8[15]+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm5, %ymm6, %ymm4+ vpsubw %ymm5, %ymm6, %ymm5+ vpaddw %ymm7, %ymm10, %ymm6+ vpsubw %ymm7, %ymm10, %ymm7+ vpaddw %ymm9, %ymm3, %ymm10+ vpsubw %ymm9, %ymm3, %ymm9+ vpaddw %ymm11, %ymm8, %ymm3+ vpsubw %ymm11, %ymm8, %ymm11+ vpsubw %ymm12, %ymm4, %ymm4+ vpaddw %ymm12, %ymm5, %ymm5+ vpsubw %ymm13, %ymm6, %ymm6+ vpaddw %ymm13, %ymm7, %ymm7+ vpsubw %ymm14, %ymm10, %ymm10+ vpaddw %ymm14, %ymm9, %ymm9+ vpsubw %ymm15, %ymm3, %ymm3+ vpaddw %ymm15, %ymm11, %ymm11+ vmovdqa 0x1a0(%rsi), %ymm14+ vmovdqa 0x1e0(%rsi), %ymm15+ vmovdqa 0x1c0(%rsi), %ymm8+ vmovdqa 0x200(%rsi), %ymm2+ vpmullw %ymm14, %ymm10, %ymm12+ vpmullw %ymm14, %ymm3, %ymm13+ vpmullw %ymm15, %ymm9, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm8, %ymm10, %ymm10+ vpmulhw %ymm8, %ymm3, %ymm3+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm11, %ymm11+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm10, %ymm4, %ymm8+ vpsubw %ymm10, %ymm4, %ymm10+ vpaddw %ymm3, %ymm6, %ymm4+ vpsubw %ymm3, %ymm6, %ymm3+ vpaddw %ymm9, %ymm5, %ymm6+ vpsubw %ymm9, %ymm5, %ymm9+ vpaddw %ymm11, %ymm7, %ymm5+ vpsubw %ymm11, %ymm7, %ymm11+ vpsubw %ymm12, %ymm8, %ymm8+ vpaddw %ymm12, %ymm10, %ymm10+ vpsubw %ymm13, %ymm4, %ymm4+ vpaddw %ymm13, %ymm3, %ymm3+ vpsubw %ymm14, %ymm6, %ymm6+ vpaddw %ymm14, %ymm9, %ymm9+ vpsubw %ymm15, %ymm5, %ymm5+ vpaddw %ymm15, %ymm11, %ymm11+ vmovdqa %ymm8, (%rdi)+ vmovdqa %ymm4, 0x20(%rdi)+ vmovdqa %ymm10, 0x40(%rdi)+ vmovdqa %ymm3, 0x60(%rdi)+ vmovdqa %ymm6, 0x80(%rdi)+ vmovdqa %ymm5, 0xa0(%rdi)+ vmovdqa %ymm9, 0xc0(%rdi)+ vmovdqa %ymm11, 0xe0(%rdi)+ vmovdqa 0x220(%rsi), %ymm15+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm9+ vmovdqa 0x1c0(%rdi), %ymm10+ vmovdqa 0x1e0(%rdi), %ymm11+ vmovdqa 0x240(%rsi), %ymm2+ vpmullw %ymm15, %ymm8, %ymm12+ vpmullw %ymm15, %ymm9, %ymm13+ vpmullw %ymm15, %ymm10, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm2, %ymm11, %ymm11+ vmovdqa 0x100(%rdi), %ymm4+ vmovdqa 0x120(%rdi), %ymm5+ vmovdqa 0x140(%rdi), %ymm6+ vmovdqa 0x160(%rdi), %ymm7+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm8, %ymm4, %ymm3+ vpsubw %ymm8, %ymm4, %ymm8+ vpaddw %ymm9, %ymm5, %ymm4+ vpsubw %ymm9, %ymm5, %ymm9+ vpaddw %ymm10, %ymm6, %ymm5+ vpsubw %ymm10, %ymm6, %ymm10+ vpaddw %ymm11, %ymm7, %ymm6+ vpsubw %ymm11, %ymm7, %ymm11+ vpsubw %ymm12, %ymm3, %ymm3+ vpaddw %ymm12, %ymm8, %ymm8+ vpsubw %ymm13, %ymm4, %ymm4+ vpaddw %ymm13, %ymm9, %ymm9+ vpsubw %ymm14, %ymm5, %ymm5+ vpaddw %ymm14, %ymm10, %ymm10+ vpsubw %ymm15, %ymm6, %ymm6+ vpaddw %ymm15, %ymm11, %ymm11+ vperm2i128 $0x20, %ymm10, %ymm5, %ymm7 # ymm7 = ymm5[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm5, %ymm10 # ymm10 = ymm5[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm6, %ymm11 # ymm11 = ymm6[2,3],ymm11[2,3]+ vmovdqa 0x260(%rsi), %ymm15+ vmovdqa 0x280(%rsi), %ymm2+ vpmullw %ymm15, %ymm7, %ymm12+ vpmullw %ymm15, %ymm10, %ymm13+ vpmullw %ymm15, %ymm5, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm7, %ymm7+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm2, %ymm5, %ymm5+ vpmulhw %ymm2, %ymm11, %ymm11+ vperm2i128 $0x20, %ymm8, %ymm3, %ymm6 # ymm6 = ymm3[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm3, %ymm8 # ymm8 = ymm3[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm4, %ymm9 # ymm9 = ymm4[2,3],ymm9[2,3]+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm7, %ymm6, %ymm4+ vpsubw %ymm7, %ymm6, %ymm7+ vpaddw %ymm10, %ymm8, %ymm6+ vpsubw %ymm10, %ymm8, %ymm10+ vpaddw %ymm5, %ymm3, %ymm8+ vpsubw %ymm5, %ymm3, %ymm5+ vpaddw %ymm11, %ymm9, %ymm3+ vpsubw %ymm11, %ymm9, %ymm11+ vpsubw %ymm12, %ymm4, %ymm4+ vpaddw %ymm12, %ymm7, %ymm7+ vpsubw %ymm13, %ymm6, %ymm6+ vpaddw %ymm13, %ymm10, %ymm10+ vpsubw %ymm14, %ymm8, %ymm8+ vpaddw %ymm14, %ymm5, %ymm5+ vpsubw %ymm15, %ymm3, %ymm3+ vpaddw %ymm15, %ymm11, %ymm11+ vpunpcklqdq %ymm5, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm5[0],ymm8[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm8, %ymm5 # ymm5 = ymm8[1],ymm5[1],ymm8[3],ymm5[3]+ vpunpcklqdq %ymm11, %ymm3, %ymm8 # ymm8 = ymm3[0],ymm11[0],ymm3[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm3, %ymm11 # ymm11 = ymm3[1],ymm11[1],ymm3[3],ymm11[3]+ vmovdqa 0x2a0(%rsi), %ymm15+ vmovdqa 0x2c0(%rsi), %ymm2+ vpmullw %ymm15, %ymm9, %ymm12+ vpmullw %ymm15, %ymm5, %ymm13+ vpmullw %ymm15, %ymm8, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm5, %ymm5+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm2, %ymm11, %ymm11+ vpunpcklqdq %ymm7, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm7[0],ymm4[2],ymm7[2]+ vpunpckhqdq %ymm7, %ymm4, %ymm7 # ymm7 = ymm4[1],ymm7[1],ymm4[3],ymm7[3]+ vpunpcklqdq %ymm10, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm10[0],ymm6[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[1],ymm10[1],ymm6[3],ymm10[3]+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm9, %ymm3, %ymm6+ vpsubw %ymm9, %ymm3, %ymm9+ vpaddw %ymm5, %ymm7, %ymm3+ vpsubw %ymm5, %ymm7, %ymm5+ vpaddw %ymm8, %ymm4, %ymm7+ vpsubw %ymm8, %ymm4, %ymm8+ vpaddw %ymm11, %ymm10, %ymm4+ vpsubw %ymm11, %ymm10, %ymm11+ vpsubw %ymm12, %ymm6, %ymm6+ vpaddw %ymm12, %ymm9, %ymm9+ vpsubw %ymm13, %ymm3, %ymm3+ vpaddw %ymm13, %ymm5, %ymm5+ vpsubw %ymm14, %ymm7, %ymm7+ vpaddw %ymm14, %ymm8, %ymm8+ vpsubw %ymm15, %ymm4, %ymm4+ vpaddw %ymm15, %ymm11, %ymm11+ vmovsldup %ymm8, %ymm10 # ymm10 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm10, %ymm7, %ymm10 # ymm10 = ymm7[0],ymm10[1],ymm7[2],ymm10[3],ymm7[4],ymm10[5],ymm7[6],ymm10[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm11, %ymm7 # ymm7 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm4, %ymm7 # ymm7 = ymm4[0],ymm7[1],ymm4[2],ymm7[3],ymm4[4],ymm7[5],ymm4[6],ymm7[7]+ vpsrlq $0x20, %ymm4, %ymm4+ vpblendd $0xaa, %ymm11, %ymm4, %ymm11 # ymm11 = ymm4[0],ymm11[1],ymm4[2],ymm11[3],ymm4[4],ymm11[5],ymm4[6],ymm11[7]+ vmovdqa 0x2e0(%rsi), %ymm15+ vmovdqa 0x300(%rsi), %ymm2+ vpmullw %ymm15, %ymm10, %ymm12+ vpmullw %ymm15, %ymm8, %ymm13+ vpmullw %ymm15, %ymm7, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm2, %ymm7, %ymm7+ vpmulhw %ymm2, %ymm11, %ymm11+ vmovsldup %ymm9, %ymm4 # ymm4 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm9, %ymm6, %ymm9 # ymm9 = ymm6[0],ymm9[1],ymm6[2],ymm9[3],ymm6[4],ymm9[5],ymm6[6],ymm9[7]+ vmovsldup %ymm5, %ymm6 # ymm6 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm3, %ymm6 # ymm6 = ymm3[0],ymm6[1],ymm3[2],ymm6[3],ymm3[4],ymm6[5],ymm3[6],ymm6[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm10, %ymm4, %ymm3+ vpsubw %ymm10, %ymm4, %ymm10+ vpaddw %ymm8, %ymm9, %ymm4+ vpsubw %ymm8, %ymm9, %ymm8+ vpaddw %ymm7, %ymm6, %ymm9+ vpsubw %ymm7, %ymm6, %ymm7+ vpaddw %ymm11, %ymm5, %ymm6+ vpsubw %ymm11, %ymm5, %ymm11+ vpsubw %ymm12, %ymm3, %ymm3+ vpaddw %ymm12, %ymm10, %ymm10+ vpsubw %ymm13, %ymm4, %ymm4+ vpaddw %ymm13, %ymm8, %ymm8+ vpsubw %ymm14, %ymm9, %ymm9+ vpaddw %ymm14, %ymm7, %ymm7+ vpsubw %ymm15, %ymm6, %ymm6+ vpaddw %ymm15, %ymm11, %ymm11+ vpslld $0x10, %ymm7, %ymm5+ vpblendw $0xaa, %ymm5, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm5[1],ymm9[2],ymm5[3],ymm9[4],ymm5[5],ymm9[6],ymm5[7],ymm9[8],ymm5[9],ymm9[10],ymm5[11],ymm9[12],ymm5[13],ymm9[14],ymm5[15]+ vpsrld $0x10, %ymm9, %ymm9+ vpblendw $0xaa, %ymm7, %ymm9, %ymm7 # ymm7 = ymm9[0],ymm7[1],ymm9[2],ymm7[3],ymm9[4],ymm7[5],ymm9[6],ymm7[7],ymm9[8],ymm7[9],ymm9[10],ymm7[11],ymm9[12],ymm7[13],ymm9[14],ymm7[15]+ vpslld $0x10, %ymm11, %ymm9+ vpblendw $0xaa, %ymm9, %ymm6, %ymm9 # ymm9 = ymm6[0],ymm9[1],ymm6[2],ymm9[3],ymm6[4],ymm9[5],ymm6[6],ymm9[7],ymm6[8],ymm9[9],ymm6[10],ymm9[11],ymm6[12],ymm9[13],ymm6[14],ymm9[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm11, %ymm6, %ymm11 # ymm11 = ymm6[0],ymm11[1],ymm6[2],ymm11[3],ymm6[4],ymm11[5],ymm6[6],ymm11[7],ymm6[8],ymm11[9],ymm6[10],ymm11[11],ymm6[12],ymm11[13],ymm6[14],ymm11[15]+ vmovdqa 0x320(%rsi), %ymm15+ vmovdqa 0x340(%rsi), %ymm2+ vpmullw %ymm15, %ymm5, %ymm12+ vpmullw %ymm15, %ymm7, %ymm13+ vpmullw %ymm15, %ymm9, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm2, %ymm5, %ymm5+ vpmulhw %ymm2, %ymm7, %ymm7+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm11, %ymm11+ vpslld $0x10, %ymm10, %ymm6+ vpblendw $0xaa, %ymm6, %ymm3, %ymm6 # ymm6 = ymm3[0],ymm6[1],ymm3[2],ymm6[3],ymm3[4],ymm6[5],ymm3[6],ymm6[7],ymm3[8],ymm6[9],ymm3[10],ymm6[11],ymm3[12],ymm6[13],ymm3[14],ymm6[15]+ vpsrld $0x10, %ymm3, %ymm3+ vpblendw $0xaa, %ymm10, %ymm3, %ymm10 # ymm10 = ymm3[0],ymm10[1],ymm3[2],ymm10[3],ymm3[4],ymm10[5],ymm3[6],ymm10[7],ymm3[8],ymm10[9],ymm3[10],ymm10[11],ymm3[12],ymm10[13],ymm3[14],ymm10[15]+ vpslld $0x10, %ymm8, %ymm3+ vpblendw $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7],ymm4[8],ymm3[9],ymm4[10],ymm3[11],ymm4[12],ymm3[13],ymm4[14],ymm3[15]+ vpsrld $0x10, %ymm4, %ymm4+ vpblendw $0xaa, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm8[1],ymm4[2],ymm8[3],ymm4[4],ymm8[5],ymm4[6],ymm8[7],ymm4[8],ymm8[9],ymm4[10],ymm8[11],ymm4[12],ymm8[13],ymm4[14],ymm8[15]+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm5, %ymm6, %ymm4+ vpsubw %ymm5, %ymm6, %ymm5+ vpaddw %ymm7, %ymm10, %ymm6+ vpsubw %ymm7, %ymm10, %ymm7+ vpaddw %ymm9, %ymm3, %ymm10+ vpsubw %ymm9, %ymm3, %ymm9+ vpaddw %ymm11, %ymm8, %ymm3+ vpsubw %ymm11, %ymm8, %ymm11+ vpsubw %ymm12, %ymm4, %ymm4+ vpaddw %ymm12, %ymm5, %ymm5+ vpsubw %ymm13, %ymm6, %ymm6+ vpaddw %ymm13, %ymm7, %ymm7+ vpsubw %ymm14, %ymm10, %ymm10+ vpaddw %ymm14, %ymm9, %ymm9+ vpsubw %ymm15, %ymm3, %ymm3+ vpaddw %ymm15, %ymm11, %ymm11+ vmovdqa 0x360(%rsi), %ymm14+ vmovdqa 0x3a0(%rsi), %ymm15+ vmovdqa 0x380(%rsi), %ymm8+ vmovdqa 0x3c0(%rsi), %ymm2+ vpmullw %ymm14, %ymm10, %ymm12+ vpmullw %ymm14, %ymm3, %ymm13+ vpmullw %ymm15, %ymm9, %ymm14+ vpmullw %ymm15, %ymm11, %ymm15+ vpmulhw %ymm8, %ymm10, %ymm10+ vpmulhw %ymm8, %ymm3, %ymm3+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm2, %ymm11, %ymm11+ vpmulhw %ymm0, %ymm12, %ymm12+ vpmulhw %ymm0, %ymm13, %ymm13+ vpmulhw %ymm0, %ymm14, %ymm14+ vpmulhw %ymm0, %ymm15, %ymm15+ vpaddw %ymm10, %ymm4, %ymm8+ vpsubw %ymm10, %ymm4, %ymm10+ vpaddw %ymm3, %ymm6, %ymm4+ vpsubw %ymm3, %ymm6, %ymm3+ vpaddw %ymm9, %ymm5, %ymm6+ vpsubw %ymm9, %ymm5, %ymm9+ vpaddw %ymm11, %ymm7, %ymm5+ vpsubw %ymm11, %ymm7, %ymm11+ vpsubw %ymm12, %ymm8, %ymm8+ vpaddw %ymm12, %ymm10, %ymm10+ vpsubw %ymm13, %ymm4, %ymm4+ vpaddw %ymm13, %ymm3, %ymm3+ vpsubw %ymm14, %ymm6, %ymm6+ vpaddw %ymm14, %ymm9, %ymm9+ vpsubw %ymm15, %ymm5, %ymm5+ vpaddw %ymm15, %ymm11, %ymm11+ vmovdqa %ymm8, 0x100(%rdi)+ vmovdqa %ymm4, 0x120(%rdi)+ vmovdqa %ymm10, 0x140(%rdi)+ vmovdqa %ymm3, 0x160(%rdi)+ vmovdqa %ymm6, 0x180(%rdi)+ vmovdqa %ymm5, 0x1a0(%rdi)+ vmovdqa %ymm9, 0x1c0(%rdi)+ vmovdqa %ymm11, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(ntt_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,217 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API))+/*yaml+ Name: nttfrombytes_avx2_asm+ Description: x86_64 AVX2 polynomial deserialization in NTT domain+ Signature: void mlk_nttfrombytes_avx2_asm(int16_t *r, const uint8_t *a)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t *r+ description: Output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 384+ permissions: read-only+ c_parameter: const uint8_t *a+ description: Input byte array (MLKEM_POLYBYTES = 384)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_nttfrombytes_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(nttfrombytes_avx2_asm)+MLK_ASM_FN_SYMBOL(nttfrombytes_avx2_asm)++ .cfi_startproc+ movl $0xfff0fff, %eax # imm = 0xFFF0FFF+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ vmovdqu (%rsi), %ymm4+ vmovdqu 0x20(%rsi), %ymm5+ vmovdqu 0x40(%rsi), %ymm6+ vmovdqu 0x60(%rsi), %ymm7+ vmovdqu 0x80(%rsi), %ymm8+ vmovdqu 0xa0(%rsi), %ymm9+ vperm2i128 $0x20, %ymm7, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm7[0,1]+ vperm2i128 $0x31, %ymm7, %ymm4, %ymm7 # ymm7 = ymm4[2,3],ymm7[2,3]+ vperm2i128 $0x20, %ymm8, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm5, %ymm8 # ymm8 = ymm5[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm6, %ymm9 # ymm9 = ymm6[2,3],ymm9[2,3]+ vpunpcklqdq %ymm8, %ymm3, %ymm6 # ymm6 = ymm3[0],ymm8[0],ymm3[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm3, %ymm8 # ymm8 = ymm3[1],ymm8[1],ymm3[3],ymm8[3]+ vpunpcklqdq %ymm5, %ymm7, %ymm3 # ymm3 = ymm7[0],ymm5[0],ymm7[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm7, %ymm5 # ymm5 = ymm7[1],ymm5[1],ymm7[3],ymm5[3]+ vpunpcklqdq %ymm9, %ymm4, %ymm7 # ymm7 = ymm4[0],ymm9[0],ymm4[2],ymm9[2]+ vpunpckhqdq %ymm9, %ymm4, %ymm9 # ymm9 = ymm4[1],ymm9[1],ymm4[3],ymm9[3]+ vmovsldup %ymm5, %ymm4 # ymm4 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[0],ymm5[1],ymm6[2],ymm5[3],ymm6[4],ymm5[5],ymm6[6],ymm5[7]+ vmovsldup %ymm7, %ymm6 # ymm6 = ymm7[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7]+ vpsrlq $0x20, %ymm8, %ymm8+ vpblendd $0xaa, %ymm7, %ymm8, %ymm7 # ymm7 = ymm8[0],ymm7[1],ymm8[2],ymm7[3],ymm8[4],ymm7[5],ymm8[6],ymm7[7]+ vmovsldup %ymm9, %ymm8 # ymm8 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm8, %ymm3, %ymm8 # ymm8 = ymm3[0],ymm8[1],ymm3[2],ymm8[3],ymm3[4],ymm8[5],ymm3[6],ymm8[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm9, %ymm3, %ymm9 # ymm9 = ymm3[0],ymm9[1],ymm3[2],ymm9[3],ymm3[4],ymm9[5],ymm3[6],ymm9[7]+ vpslld $0x10, %ymm7, %ymm10+ vpblendw $0xaa, %ymm10, %ymm4, %ymm10 # ymm10 = ymm4[0],ymm10[1],ymm4[2],ymm10[3],ymm4[4],ymm10[5],ymm4[6],ymm10[7],ymm4[8],ymm10[9],ymm4[10],ymm10[11],ymm4[12],ymm10[13],ymm4[14],ymm10[15]+ vpsrld $0x10, %ymm4, %ymm4+ vpblendw $0xaa, %ymm7, %ymm4, %ymm7 # ymm7 = ymm4[0],ymm7[1],ymm4[2],ymm7[3],ymm4[4],ymm7[5],ymm4[6],ymm7[7],ymm4[8],ymm7[9],ymm4[10],ymm7[11],ymm4[12],ymm7[13],ymm4[14],ymm7[15]+ vpslld $0x10, %ymm8, %ymm4+ vpblendw $0xaa, %ymm4, %ymm5, %ymm4 # ymm4 = ymm5[0],ymm4[1],ymm5[2],ymm4[3],ymm5[4],ymm4[5],ymm5[6],ymm4[7],ymm5[8],ymm4[9],ymm5[10],ymm4[11],ymm5[12],ymm4[13],ymm5[14],ymm4[15]+ vpsrld $0x10, %ymm5, %ymm5+ vpblendw $0xaa, %ymm8, %ymm5, %ymm8 # ymm8 = ymm5[0],ymm8[1],ymm5[2],ymm8[3],ymm5[4],ymm8[5],ymm5[6],ymm8[7],ymm5[8],ymm8[9],ymm5[10],ymm8[11],ymm5[12],ymm8[13],ymm5[14],ymm8[15]+ vpslld $0x10, %ymm9, %ymm5+ vpblendw $0xaa, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[0],ymm5[1],ymm6[2],ymm5[3],ymm6[4],ymm5[5],ymm6[6],ymm5[7],ymm6[8],ymm5[9],ymm6[10],ymm5[11],ymm6[12],ymm5[13],ymm6[14],ymm5[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm9, %ymm6, %ymm9 # ymm9 = ymm6[0],ymm9[1],ymm6[2],ymm9[3],ymm6[4],ymm9[5],ymm6[6],ymm9[7],ymm6[8],ymm9[9],ymm6[10],ymm9[11],ymm6[12],ymm9[13],ymm6[14],ymm9[15]+ vpsrlw $0xc, %ymm10, %ymm11+ vpsllw $0x4, %ymm7, %ymm12+ vpor %ymm11, %ymm12, %ymm11+ vpand %ymm0, %ymm10, %ymm10+ vpand %ymm0, %ymm11, %ymm11+ vpsrlw $0x8, %ymm7, %ymm12+ vpsllw $0x8, %ymm4, %ymm13+ vpor %ymm12, %ymm13, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpsrlw $0x4, %ymm4, %ymm13+ vpand %ymm0, %ymm13, %ymm13+ vpsrlw $0xc, %ymm8, %ymm14+ vpsllw $0x4, %ymm5, %ymm15+ vpor %ymm14, %ymm15, %ymm14+ vpand %ymm0, %ymm8, %ymm8+ vpand %ymm0, %ymm14, %ymm14+ vpsrlw $0x8, %ymm5, %ymm15+ vpsllw $0x8, %ymm9, %ymm1+ vpor %ymm15, %ymm1, %ymm15+ vpand %ymm0, %ymm15, %ymm15+ vpsrlw $0x4, %ymm9, %ymm1+ vpand %ymm0, %ymm1, %ymm1+ vmovdqa %ymm10, (%rdi)+ vmovdqa %ymm11, 0x20(%rdi)+ vmovdqa %ymm12, 0x40(%rdi)+ vmovdqa %ymm13, 0x60(%rdi)+ vmovdqa %ymm8, 0x80(%rdi)+ vmovdqa %ymm14, 0xa0(%rdi)+ vmovdqa %ymm15, 0xc0(%rdi)+ vmovdqa %ymm1, 0xe0(%rdi)+ vmovdqu 0xc0(%rsi), %ymm4+ vmovdqu 0xe0(%rsi), %ymm5+ vmovdqu 0x100(%rsi), %ymm6+ vmovdqu 0x120(%rsi), %ymm7+ vmovdqu 0x140(%rsi), %ymm8+ vmovdqu 0x160(%rsi), %ymm9+ vperm2i128 $0x20, %ymm7, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm7[0,1]+ vperm2i128 $0x31, %ymm7, %ymm4, %ymm7 # ymm7 = ymm4[2,3],ymm7[2,3]+ vperm2i128 $0x20, %ymm8, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm5, %ymm8 # ymm8 = ymm5[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm6, %ymm9 # ymm9 = ymm6[2,3],ymm9[2,3]+ vpunpcklqdq %ymm8, %ymm3, %ymm6 # ymm6 = ymm3[0],ymm8[0],ymm3[2],ymm8[2]+ vpunpckhqdq %ymm8, %ymm3, %ymm8 # ymm8 = ymm3[1],ymm8[1],ymm3[3],ymm8[3]+ vpunpcklqdq %ymm5, %ymm7, %ymm3 # ymm3 = ymm7[0],ymm5[0],ymm7[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm7, %ymm5 # ymm5 = ymm7[1],ymm5[1],ymm7[3],ymm5[3]+ vpunpcklqdq %ymm9, %ymm4, %ymm7 # ymm7 = ymm4[0],ymm9[0],ymm4[2],ymm9[2]+ vpunpckhqdq %ymm9, %ymm4, %ymm9 # ymm9 = ymm4[1],ymm9[1],ymm4[3],ymm9[3]+ vmovsldup %ymm5, %ymm4 # ymm4 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[0],ymm5[1],ymm6[2],ymm5[3],ymm6[4],ymm5[5],ymm6[6],ymm5[7]+ vmovsldup %ymm7, %ymm6 # ymm6 = ymm7[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7]+ vpsrlq $0x20, %ymm8, %ymm8+ vpblendd $0xaa, %ymm7, %ymm8, %ymm7 # ymm7 = ymm8[0],ymm7[1],ymm8[2],ymm7[3],ymm8[4],ymm7[5],ymm8[6],ymm7[7]+ vmovsldup %ymm9, %ymm8 # ymm8 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm8, %ymm3, %ymm8 # ymm8 = ymm3[0],ymm8[1],ymm3[2],ymm8[3],ymm3[4],ymm8[5],ymm3[6],ymm8[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm9, %ymm3, %ymm9 # ymm9 = ymm3[0],ymm9[1],ymm3[2],ymm9[3],ymm3[4],ymm9[5],ymm3[6],ymm9[7]+ vpslld $0x10, %ymm7, %ymm10+ vpblendw $0xaa, %ymm10, %ymm4, %ymm10 # ymm10 = ymm4[0],ymm10[1],ymm4[2],ymm10[3],ymm4[4],ymm10[5],ymm4[6],ymm10[7],ymm4[8],ymm10[9],ymm4[10],ymm10[11],ymm4[12],ymm10[13],ymm4[14],ymm10[15]+ vpsrld $0x10, %ymm4, %ymm4+ vpblendw $0xaa, %ymm7, %ymm4, %ymm7 # ymm7 = ymm4[0],ymm7[1],ymm4[2],ymm7[3],ymm4[4],ymm7[5],ymm4[6],ymm7[7],ymm4[8],ymm7[9],ymm4[10],ymm7[11],ymm4[12],ymm7[13],ymm4[14],ymm7[15]+ vpslld $0x10, %ymm8, %ymm4+ vpblendw $0xaa, %ymm4, %ymm5, %ymm4 # ymm4 = ymm5[0],ymm4[1],ymm5[2],ymm4[3],ymm5[4],ymm4[5],ymm5[6],ymm4[7],ymm5[8],ymm4[9],ymm5[10],ymm4[11],ymm5[12],ymm4[13],ymm5[14],ymm4[15]+ vpsrld $0x10, %ymm5, %ymm5+ vpblendw $0xaa, %ymm8, %ymm5, %ymm8 # ymm8 = ymm5[0],ymm8[1],ymm5[2],ymm8[3],ymm5[4],ymm8[5],ymm5[6],ymm8[7],ymm5[8],ymm8[9],ymm5[10],ymm8[11],ymm5[12],ymm8[13],ymm5[14],ymm8[15]+ vpslld $0x10, %ymm9, %ymm5+ vpblendw $0xaa, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[0],ymm5[1],ymm6[2],ymm5[3],ymm6[4],ymm5[5],ymm6[6],ymm5[7],ymm6[8],ymm5[9],ymm6[10],ymm5[11],ymm6[12],ymm5[13],ymm6[14],ymm5[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm9, %ymm6, %ymm9 # ymm9 = ymm6[0],ymm9[1],ymm6[2],ymm9[3],ymm6[4],ymm9[5],ymm6[6],ymm9[7],ymm6[8],ymm9[9],ymm6[10],ymm9[11],ymm6[12],ymm9[13],ymm6[14],ymm9[15]+ vpsrlw $0xc, %ymm10, %ymm11+ vpsllw $0x4, %ymm7, %ymm12+ vpor %ymm11, %ymm12, %ymm11+ vpand %ymm0, %ymm10, %ymm10+ vpand %ymm0, %ymm11, %ymm11+ vpsrlw $0x8, %ymm7, %ymm12+ vpsllw $0x8, %ymm4, %ymm13+ vpor %ymm12, %ymm13, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpsrlw $0x4, %ymm4, %ymm13+ vpand %ymm0, %ymm13, %ymm13+ vpsrlw $0xc, %ymm8, %ymm14+ vpsllw $0x4, %ymm5, %ymm15+ vpor %ymm14, %ymm15, %ymm14+ vpand %ymm0, %ymm8, %ymm8+ vpand %ymm0, %ymm14, %ymm14+ vpsrlw $0x8, %ymm5, %ymm15+ vpsllw $0x8, %ymm9, %ymm1+ vpor %ymm15, %ymm1, %ymm15+ vpand %ymm0, %ymm15, %ymm15+ vpsrlw $0x4, %ymm9, %ymm1+ vpand %ymm0, %ymm1, %ymm1+ vmovdqa %ymm10, 0x100(%rdi)+ vmovdqa %ymm11, 0x120(%rdi)+ vmovdqa %ymm12, 0x140(%rdi)+ vmovdqa %ymm13, 0x160(%rdi)+ vmovdqa %ymm8, 0x180(%rdi)+ vmovdqa %ymm14, 0x1a0(%rdi)+ vmovdqa %ymm15, 0x1c0(%rdi)+ vmovdqa %ymm1, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(nttfrombytes_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,205 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (!defined(MLK_CONFIG_NO_KEYPAIR_API) || \+ !defined(MLK_CONFIG_NO_ENCAPS_API))+/*yaml+ Name: ntttobytes_avx2_asm+ Description: x86_64 AVX2 polynomial serialization in NTT domain+ Signature: void mlk_ntttobytes_avx2_asm(uint8_t *r, const int16_t *a)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 384+ permissions: write-only+ c_parameter: uint8_t *r+ description: Output byte array (MLKEM_POLYBYTES = 384)+ rsi:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t *a+ description: Input polynomial (256 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_ntttobytes_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(ntttobytes_avx2_asm)+MLK_ASM_FN_SYMBOL(ntttobytes_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ vmovdqa (%rsi), %ymm5+ vmovdqa 0x20(%rsi), %ymm6+ vmovdqa 0x40(%rsi), %ymm7+ vmovdqa 0x60(%rsi), %ymm8+ vmovdqa 0x80(%rsi), %ymm9+ vmovdqa 0xa0(%rsi), %ymm10+ vmovdqa 0xc0(%rsi), %ymm11+ vmovdqa 0xe0(%rsi), %ymm12+ vpsllw $0xc, %ymm6, %ymm4+ vpor %ymm4, %ymm5, %ymm4+ vpsrlw $0x4, %ymm6, %ymm5+ vpsllw $0x8, %ymm7, %ymm6+ vpor %ymm5, %ymm6, %ymm5+ vpsrlw $0x8, %ymm7, %ymm6+ vpsllw $0x4, %ymm8, %ymm7+ vpor %ymm6, %ymm7, %ymm6+ vpsllw $0xc, %ymm10, %ymm7+ vpor %ymm7, %ymm9, %ymm7+ vpsrlw $0x4, %ymm10, %ymm8+ vpsllw $0x8, %ymm11, %ymm9+ vpor %ymm8, %ymm9, %ymm8+ vpsrlw $0x8, %ymm11, %ymm9+ vpsllw $0x4, %ymm12, %ymm10+ vpor %ymm9, %ymm10, %ymm9+ vpslld $0x10, %ymm5, %ymm3+ vpblendw $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7],ymm4[8],ymm3[9],ymm4[10],ymm3[11],ymm4[12],ymm3[13],ymm4[14],ymm3[15]+ vpsrld $0x10, %ymm4, %ymm4+ vpblendw $0xaa, %ymm5, %ymm4, %ymm5 # ymm5 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7],ymm4[8],ymm5[9],ymm4[10],ymm5[11],ymm4[12],ymm5[13],ymm4[14],ymm5[15]+ vpslld $0x10, %ymm7, %ymm4+ vpblendw $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7],ymm6[8],ymm4[9],ymm6[10],ymm4[11],ymm6[12],ymm4[13],ymm6[14],ymm4[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7],ymm6[8],ymm7[9],ymm6[10],ymm7[11],ymm6[12],ymm7[13],ymm6[14],ymm7[15]+ vpslld $0x10, %ymm9, %ymm6+ vpblendw $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7],ymm8[8],ymm6[9],ymm8[10],ymm6[11],ymm8[12],ymm6[13],ymm8[14],ymm6[15]+ vpsrld $0x10, %ymm8, %ymm8+ vpblendw $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7],ymm8[8],ymm9[9],ymm8[10],ymm9[11],ymm8[12],ymm9[13],ymm8[14],ymm9[15]+ vmovsldup %ymm4, %ymm8 # ymm8 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm8, %ymm3, %ymm8 # ymm8 = ymm3[0],ymm8[1],ymm3[2],ymm8[3],ymm3[4],ymm8[5],ymm3[6],ymm8[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm5, %ymm3 # ymm3 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm6, %ymm3 # ymm3 = ymm6[0],ymm3[1],ymm6[2],ymm3[3],ymm6[4],ymm3[5],ymm6[6],ymm3[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[0],ymm5[1],ymm6[2],ymm5[3],ymm6[4],ymm5[5],ymm6[6],ymm5[7]+ vmovsldup %ymm9, %ymm6 # ymm6 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm7, %ymm6 # ymm6 = ymm7[0],ymm6[1],ymm7[2],ymm6[3],ymm7[4],ymm6[5],ymm7[6],ymm6[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpunpcklqdq %ymm3, %ymm8, %ymm7 # ymm7 = ymm8[0],ymm3[0],ymm8[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm8, %ymm3 # ymm3 = ymm8[1],ymm3[1],ymm8[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm6, %ymm8 # ymm8 = ymm6[0],ymm4[0],ymm6[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[1],ymm4[1],ymm6[3],ymm4[3]+ vpunpcklqdq %ymm9, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm9[0],ymm5[2],ymm9[2]+ vpunpckhqdq %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[1],ymm9[1],ymm5[3],ymm9[3]+ vperm2i128 $0x20, %ymm8, %ymm7, %ymm5 # ymm5 = ymm7[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm3, %ymm6, %ymm7 # ymm7 = ymm6[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm6, %ymm3 # ymm3 = ymm6[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm9, %ymm4, %ymm6 # ymm6 = ymm4[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm4, %ymm9 # ymm9 = ymm4[2,3],ymm9[2,3]+ vmovdqu %ymm5, (%rdi)+ vmovdqu %ymm7, 0x20(%rdi)+ vmovdqu %ymm6, 0x40(%rdi)+ vmovdqu %ymm8, 0x60(%rdi)+ vmovdqu %ymm3, 0x80(%rdi)+ vmovdqu %ymm9, 0xa0(%rdi)+ vmovdqa 0x100(%rsi), %ymm5+ vmovdqa 0x120(%rsi), %ymm6+ vmovdqa 0x140(%rsi), %ymm7+ vmovdqa 0x160(%rsi), %ymm8+ vmovdqa 0x180(%rsi), %ymm9+ vmovdqa 0x1a0(%rsi), %ymm10+ vmovdqa 0x1c0(%rsi), %ymm11+ vmovdqa 0x1e0(%rsi), %ymm12+ vpsllw $0xc, %ymm6, %ymm4+ vpor %ymm4, %ymm5, %ymm4+ vpsrlw $0x4, %ymm6, %ymm5+ vpsllw $0x8, %ymm7, %ymm6+ vpor %ymm5, %ymm6, %ymm5+ vpsrlw $0x8, %ymm7, %ymm6+ vpsllw $0x4, %ymm8, %ymm7+ vpor %ymm6, %ymm7, %ymm6+ vpsllw $0xc, %ymm10, %ymm7+ vpor %ymm7, %ymm9, %ymm7+ vpsrlw $0x4, %ymm10, %ymm8+ vpsllw $0x8, %ymm11, %ymm9+ vpor %ymm8, %ymm9, %ymm8+ vpsrlw $0x8, %ymm11, %ymm9+ vpsllw $0x4, %ymm12, %ymm10+ vpor %ymm9, %ymm10, %ymm9+ vpslld $0x10, %ymm5, %ymm3+ vpblendw $0xaa, %ymm3, %ymm4, %ymm3 # ymm3 = ymm4[0],ymm3[1],ymm4[2],ymm3[3],ymm4[4],ymm3[5],ymm4[6],ymm3[7],ymm4[8],ymm3[9],ymm4[10],ymm3[11],ymm4[12],ymm3[13],ymm4[14],ymm3[15]+ vpsrld $0x10, %ymm4, %ymm4+ vpblendw $0xaa, %ymm5, %ymm4, %ymm5 # ymm5 = ymm4[0],ymm5[1],ymm4[2],ymm5[3],ymm4[4],ymm5[5],ymm4[6],ymm5[7],ymm4[8],ymm5[9],ymm4[10],ymm5[11],ymm4[12],ymm5[13],ymm4[14],ymm5[15]+ vpslld $0x10, %ymm7, %ymm4+ vpblendw $0xaa, %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[0],ymm4[1],ymm6[2],ymm4[3],ymm6[4],ymm4[5],ymm6[6],ymm4[7],ymm6[8],ymm4[9],ymm6[10],ymm4[11],ymm6[12],ymm4[13],ymm6[14],ymm4[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7],ymm6[8],ymm7[9],ymm6[10],ymm7[11],ymm6[12],ymm7[13],ymm6[14],ymm7[15]+ vpslld $0x10, %ymm9, %ymm6+ vpblendw $0xaa, %ymm6, %ymm8, %ymm6 # ymm6 = ymm8[0],ymm6[1],ymm8[2],ymm6[3],ymm8[4],ymm6[5],ymm8[6],ymm6[7],ymm8[8],ymm6[9],ymm8[10],ymm6[11],ymm8[12],ymm6[13],ymm8[14],ymm6[15]+ vpsrld $0x10, %ymm8, %ymm8+ vpblendw $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7],ymm8[8],ymm9[9],ymm8[10],ymm9[11],ymm8[12],ymm9[13],ymm8[14],ymm9[15]+ vmovsldup %ymm4, %ymm8 # ymm8 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm8, %ymm3, %ymm8 # ymm8 = ymm3[0],ymm8[1],ymm3[2],ymm8[3],ymm3[4],ymm8[5],ymm3[6],ymm8[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm5, %ymm3 # ymm3 = ymm5[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm6, %ymm3 # ymm3 = ymm6[0],ymm3[1],ymm6[2],ymm3[3],ymm6[4],ymm3[5],ymm6[6],ymm3[7]+ vpsrlq $0x20, %ymm6, %ymm6+ vpblendd $0xaa, %ymm5, %ymm6, %ymm5 # ymm5 = ymm6[0],ymm5[1],ymm6[2],ymm5[3],ymm6[4],ymm5[5],ymm6[6],ymm5[7]+ vmovsldup %ymm9, %ymm6 # ymm6 = ymm9[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm6, %ymm7, %ymm6 # ymm6 = ymm7[0],ymm6[1],ymm7[2],ymm6[3],ymm7[4],ymm6[5],ymm7[6],ymm6[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpunpcklqdq %ymm3, %ymm8, %ymm7 # ymm7 = ymm8[0],ymm3[0],ymm8[2],ymm3[2]+ vpunpckhqdq %ymm3, %ymm8, %ymm3 # ymm3 = ymm8[1],ymm3[1],ymm8[3],ymm3[3]+ vpunpcklqdq %ymm4, %ymm6, %ymm8 # ymm8 = ymm6[0],ymm4[0],ymm6[2],ymm4[2]+ vpunpckhqdq %ymm4, %ymm6, %ymm4 # ymm4 = ymm6[1],ymm4[1],ymm6[3],ymm4[3]+ vpunpcklqdq %ymm9, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm9[0],ymm5[2],ymm9[2]+ vpunpckhqdq %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[1],ymm9[1],ymm5[3],ymm9[3]+ vperm2i128 $0x20, %ymm8, %ymm7, %ymm5 # ymm5 = ymm7[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm3, %ymm6, %ymm7 # ymm7 = ymm6[0,1],ymm3[0,1]+ vperm2i128 $0x31, %ymm3, %ymm6, %ymm3 # ymm3 = ymm6[2,3],ymm3[2,3]+ vperm2i128 $0x20, %ymm9, %ymm4, %ymm6 # ymm6 = ymm4[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm4, %ymm9 # ymm9 = ymm4[2,3],ymm9[2,3]+ vmovdqu %ymm5, 0xc0(%rdi)+ vmovdqu %ymm7, 0xe0(%rdi)+ vmovdqu %ymm6, 0x100(%rdi)+ vmovdqu %ymm8, 0x120(%rdi)+ vmovdqu %ymm3, 0x140(%rdi)+ vmovdqu %ymm9, 0x160(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(ntttobytes_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (!MLK_CONFIG_NO_KEYPAIR_API || !MLK_CONFIG_NO_ENCAPS_API) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,190 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+/*yaml+ Name: nttunpack_avx2_asm+ Description: x86_64 AVX2 NTT unpack from custom to bitreversed order+ Signature: void mlk_nttunpack_avx2_asm(int16_t *r)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t *r+ description: Input/output polynomial (256 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_nttunpack_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(nttunpack_avx2_asm)+MLK_ASM_FN_SYMBOL(nttunpack_avx2_asm)++ .cfi_startproc+ vmovdqa (%rdi), %ymm4+ vmovdqa 0x20(%rdi), %ymm5+ vmovdqa 0x40(%rdi), %ymm6+ vmovdqa 0x60(%rdi), %ymm7+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm9+ vmovdqa 0xc0(%rdi), %ymm10+ vmovdqa 0xe0(%rdi), %ymm11+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vpslld $0x10, %ymm5, %ymm10+ vpblendw $0xaa, %ymm10, %ymm9, %ymm10 # ymm10 = ymm9[0],ymm10[1],ymm9[2],ymm10[3],ymm9[4],ymm10[5],ymm9[6],ymm10[7],ymm9[8],ymm10[9],ymm9[10],ymm10[11],ymm9[12],ymm10[13],ymm9[14],ymm10[15]+ vpsrld $0x10, %ymm9, %ymm9+ vpblendw $0xaa, %ymm5, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm5[1],ymm9[2],ymm5[3],ymm9[4],ymm5[5],ymm9[6],ymm5[7],ymm9[8],ymm5[9],ymm9[10],ymm5[11],ymm9[12],ymm5[13],ymm9[14],ymm5[15]+ vpslld $0x10, %ymm4, %ymm9+ vpblendw $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7],ymm8[8],ymm9[9],ymm8[10],ymm9[11],ymm8[12],ymm9[13],ymm8[14],ymm9[15]+ vpsrld $0x10, %ymm8, %ymm8+ vpblendw $0xaa, %ymm4, %ymm8, %ymm4 # ymm4 = ymm8[0],ymm4[1],ymm8[2],ymm4[3],ymm8[4],ymm4[5],ymm8[6],ymm4[7],ymm8[8],ymm4[9],ymm8[10],ymm4[11],ymm8[12],ymm4[13],ymm8[14],ymm4[15]+ vpslld $0x10, %ymm3, %ymm8+ vpblendw $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7],ymm7[8],ymm8[9],ymm7[10],ymm8[11],ymm7[12],ymm8[13],ymm7[14],ymm8[15]+ vpsrld $0x10, %ymm7, %ymm7+ vpblendw $0xaa, %ymm3, %ymm7, %ymm3 # ymm3 = ymm7[0],ymm3[1],ymm7[2],ymm3[3],ymm7[4],ymm3[5],ymm7[6],ymm3[7],ymm7[8],ymm3[9],ymm7[10],ymm3[11],ymm7[12],ymm3[13],ymm7[14],ymm3[15]+ vpslld $0x10, %ymm11, %ymm7+ vpblendw $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7],ymm6[8],ymm7[9],ymm6[10],ymm7[11],ymm6[12],ymm7[13],ymm6[14],ymm7[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm11, %ymm6, %ymm11 # ymm11 = ymm6[0],ymm11[1],ymm6[2],ymm11[3],ymm6[4],ymm11[5],ymm6[6],ymm11[7],ymm6[8],ymm11[9],ymm6[10],ymm11[11],ymm6[12],ymm11[13],ymm6[14],ymm11[15]+ vmovdqa %ymm10, (%rdi)+ vmovdqa %ymm5, 0x20(%rdi)+ vmovdqa %ymm9, 0x40(%rdi)+ vmovdqa %ymm4, 0x60(%rdi)+ vmovdqa %ymm8, 0x80(%rdi)+ vmovdqa %ymm3, 0xa0(%rdi)+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm11, 0xe0(%rdi)+ vmovdqa 0x100(%rdi), %ymm4+ vmovdqa 0x120(%rdi), %ymm5+ vmovdqa 0x140(%rdi), %ymm6+ vmovdqa 0x160(%rdi), %ymm7+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm9+ vmovdqa 0x1c0(%rdi), %ymm10+ vmovdqa 0x1e0(%rdi), %ymm11+ vperm2i128 $0x20, %ymm8, %ymm4, %ymm3 # ymm3 = ymm4[0,1],ymm8[0,1]+ vperm2i128 $0x31, %ymm8, %ymm4, %ymm8 # ymm8 = ymm4[2,3],ymm8[2,3]+ vperm2i128 $0x20, %ymm9, %ymm5, %ymm4 # ymm4 = ymm5[0,1],ymm9[0,1]+ vperm2i128 $0x31, %ymm9, %ymm5, %ymm9 # ymm9 = ymm5[2,3],ymm9[2,3]+ vperm2i128 $0x20, %ymm10, %ymm6, %ymm5 # ymm5 = ymm6[0,1],ymm10[0,1]+ vperm2i128 $0x31, %ymm10, %ymm6, %ymm10 # ymm10 = ymm6[2,3],ymm10[2,3]+ vperm2i128 $0x20, %ymm11, %ymm7, %ymm6 # ymm6 = ymm7[0,1],ymm11[0,1]+ vperm2i128 $0x31, %ymm11, %ymm7, %ymm11 # ymm11 = ymm7[2,3],ymm11[2,3]+ vpunpcklqdq %ymm5, %ymm3, %ymm7 # ymm7 = ymm3[0],ymm5[0],ymm3[2],ymm5[2]+ vpunpckhqdq %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[1],ymm5[1],ymm3[3],ymm5[3]+ vpunpcklqdq %ymm10, %ymm8, %ymm3 # ymm3 = ymm8[0],ymm10[0],ymm8[2],ymm10[2]+ vpunpckhqdq %ymm10, %ymm8, %ymm10 # ymm10 = ymm8[1],ymm10[1],ymm8[3],ymm10[3]+ vpunpcklqdq %ymm6, %ymm4, %ymm8 # ymm8 = ymm4[0],ymm6[0],ymm4[2],ymm6[2]+ vpunpckhqdq %ymm6, %ymm4, %ymm6 # ymm6 = ymm4[1],ymm6[1],ymm4[3],ymm6[3]+ vpunpcklqdq %ymm11, %ymm9, %ymm4 # ymm4 = ymm9[0],ymm11[0],ymm9[2],ymm11[2]+ vpunpckhqdq %ymm11, %ymm9, %ymm11 # ymm11 = ymm9[1],ymm11[1],ymm9[3],ymm11[3]+ vmovsldup %ymm8, %ymm9 # ymm9 = ymm8[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm9, %ymm7, %ymm9 # ymm9 = ymm7[0],ymm9[1],ymm7[2],ymm9[3],ymm7[4],ymm9[5],ymm7[6],ymm9[7]+ vpsrlq $0x20, %ymm7, %ymm7+ vpblendd $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7]+ vmovsldup %ymm6, %ymm7 # ymm7 = ymm6[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm7, %ymm5, %ymm7 # ymm7 = ymm5[0],ymm7[1],ymm5[2],ymm7[3],ymm5[4],ymm7[5],ymm5[6],ymm7[7]+ vpsrlq $0x20, %ymm5, %ymm5+ vpblendd $0xaa, %ymm6, %ymm5, %ymm6 # ymm6 = ymm5[0],ymm6[1],ymm5[2],ymm6[3],ymm5[4],ymm6[5],ymm5[6],ymm6[7]+ vmovsldup %ymm4, %ymm5 # ymm5 = ymm4[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm5, %ymm3, %ymm5 # ymm5 = ymm3[0],ymm5[1],ymm3[2],ymm5[3],ymm3[4],ymm5[5],ymm3[6],ymm5[7]+ vpsrlq $0x20, %ymm3, %ymm3+ vpblendd $0xaa, %ymm4, %ymm3, %ymm4 # ymm4 = ymm3[0],ymm4[1],ymm3[2],ymm4[3],ymm3[4],ymm4[5],ymm3[6],ymm4[7]+ vmovsldup %ymm11, %ymm3 # ymm3 = ymm11[0,0,2,2,4,4,6,6]+ vpblendd $0xaa, %ymm3, %ymm10, %ymm3 # ymm3 = ymm10[0],ymm3[1],ymm10[2],ymm3[3],ymm10[4],ymm3[5],ymm10[6],ymm3[7]+ vpsrlq $0x20, %ymm10, %ymm10+ vpblendd $0xaa, %ymm11, %ymm10, %ymm11 # ymm11 = ymm10[0],ymm11[1],ymm10[2],ymm11[3],ymm10[4],ymm11[5],ymm10[6],ymm11[7]+ vpslld $0x10, %ymm5, %ymm10+ vpblendw $0xaa, %ymm10, %ymm9, %ymm10 # ymm10 = ymm9[0],ymm10[1],ymm9[2],ymm10[3],ymm9[4],ymm10[5],ymm9[6],ymm10[7],ymm9[8],ymm10[9],ymm9[10],ymm10[11],ymm9[12],ymm10[13],ymm9[14],ymm10[15]+ vpsrld $0x10, %ymm9, %ymm9+ vpblendw $0xaa, %ymm5, %ymm9, %ymm5 # ymm5 = ymm9[0],ymm5[1],ymm9[2],ymm5[3],ymm9[4],ymm5[5],ymm9[6],ymm5[7],ymm9[8],ymm5[9],ymm9[10],ymm5[11],ymm9[12],ymm5[13],ymm9[14],ymm5[15]+ vpslld $0x10, %ymm4, %ymm9+ vpblendw $0xaa, %ymm9, %ymm8, %ymm9 # ymm9 = ymm8[0],ymm9[1],ymm8[2],ymm9[3],ymm8[4],ymm9[5],ymm8[6],ymm9[7],ymm8[8],ymm9[9],ymm8[10],ymm9[11],ymm8[12],ymm9[13],ymm8[14],ymm9[15]+ vpsrld $0x10, %ymm8, %ymm8+ vpblendw $0xaa, %ymm4, %ymm8, %ymm4 # ymm4 = ymm8[0],ymm4[1],ymm8[2],ymm4[3],ymm8[4],ymm4[5],ymm8[6],ymm4[7],ymm8[8],ymm4[9],ymm8[10],ymm4[11],ymm8[12],ymm4[13],ymm8[14],ymm4[15]+ vpslld $0x10, %ymm3, %ymm8+ vpblendw $0xaa, %ymm8, %ymm7, %ymm8 # ymm8 = ymm7[0],ymm8[1],ymm7[2],ymm8[3],ymm7[4],ymm8[5],ymm7[6],ymm8[7],ymm7[8],ymm8[9],ymm7[10],ymm8[11],ymm7[12],ymm8[13],ymm7[14],ymm8[15]+ vpsrld $0x10, %ymm7, %ymm7+ vpblendw $0xaa, %ymm3, %ymm7, %ymm3 # ymm3 = ymm7[0],ymm3[1],ymm7[2],ymm3[3],ymm7[4],ymm3[5],ymm7[6],ymm3[7],ymm7[8],ymm3[9],ymm7[10],ymm3[11],ymm7[12],ymm3[13],ymm7[14],ymm3[15]+ vpslld $0x10, %ymm11, %ymm7+ vpblendw $0xaa, %ymm7, %ymm6, %ymm7 # ymm7 = ymm6[0],ymm7[1],ymm6[2],ymm7[3],ymm6[4],ymm7[5],ymm6[6],ymm7[7],ymm6[8],ymm7[9],ymm6[10],ymm7[11],ymm6[12],ymm7[13],ymm6[14],ymm7[15]+ vpsrld $0x10, %ymm6, %ymm6+ vpblendw $0xaa, %ymm11, %ymm6, %ymm11 # ymm11 = ymm6[0],ymm11[1],ymm6[2],ymm11[3],ymm6[4],ymm11[5],ymm6[6],ymm11[7],ymm6[8],ymm11[9],ymm6[10],ymm11[11],ymm6[12],ymm11[13],ymm6[14],ymm11[15]+ vmovdqa %ymm10, 0x100(%rdi)+ vmovdqa %ymm5, 0x120(%rdi)+ vmovdqa %ymm9, 0x140(%rdi)+ vmovdqa %ymm4, 0x160(%rdi)+ vmovdqa %ymm8, 0x180(%rdi)+ vmovdqa %ymm3, 0x1a0(%rdi)+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm11, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(nttunpack_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,413 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++/*************************************************+ * Name: mlk_poly_compress_d10_avx2_asm+ *+ * Description: Compression of a polynomial to 10 bits per coefficient.+ *+ * Arguments: - uint8_t *r: pointer to output byte array+ * (of length MLKEM_POLYCOMPRESSEDBYTES_D10)+ * - const int16_t *a: pointer to input polynomial+ * - const uint8_t *data: pointer to shufbidx constant+ **************************************************/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2 || MLKEM_K == 3)+/*yaml+ Name: poly_compress_d10_avx2_asm+ Description: x86_64 AVX2 polynomial compression (d=10)+ Signature: void mlk_poly_compress_d10_avx2_asm(uint8_t *r, const int16_t *a, const uint8_t *data)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 320+ permissions: write-only+ c_parameter: uint8_t *r+ description: Output compressed polynomial+ rsi:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t *a+ description: Input polynomial (256 x int16_t)+ rdx:+ type: buffer+ size_bytes: 32+ permissions: read-only+ c_parameter: const uint8_t *data+ description: Precomputed compression constants+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_poly_compress_d10_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_compress_d10_avx2_asm)+MLK_ASM_FN_SYMBOL(poly_compress_d10_avx2_asm)++ .cfi_startproc+ movl $0x4ebf4ebf, %eax # imm = 0x4EBF4EBF+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ vpsllw $0x3, %ymm0, %ymm1+ movl $0xf000f, %eax # imm = 0xF000F+ vmovd %eax, %xmm2+ vpbroadcastd %xmm2, %ymm2+ movl $0x10001000, %eax # imm = 0x10001000+ vmovd %eax, %xmm3+ vpbroadcastd %xmm3, %ymm3+ movl $0x3ff03ff, %eax # imm = 0x3FF03FF+ vmovd %eax, %xmm4+ vpbroadcastd %xmm4, %ymm4+ movabsq $0x400000104000001, %rax # imm = 0x400000104000001+ vmovq %rax, %xmm5+ vpbroadcastq %xmm5, %ymm5+ movl $0xc, %eax+ vmovq %rax, %xmm6+ vpbroadcastq %xmm6, %ymm6+ vmovdqa (%rdx), %ymm7+ vmovdqa (%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, (%rdi)+ vmovd %xmm9, 0x10(%rdi)+ vmovdqa 0x20(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x14(%rdi)+ vmovd %xmm9, 0x24(%rdi)+ vmovdqa 0x40(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x28(%rdi)+ vmovd %xmm9, 0x38(%rdi)+ vmovdqa 0x60(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x3c(%rdi)+ vmovd %xmm9, 0x4c(%rdi)+ vmovdqa 0x80(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x50(%rdi)+ vmovd %xmm9, 0x60(%rdi)+ vmovdqa 0xa0(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x64(%rdi)+ vmovd %xmm9, 0x74(%rdi)+ vmovdqa 0xc0(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x78(%rdi)+ vmovd %xmm9, 0x88(%rdi)+ vmovdqa 0xe0(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x8c(%rdi)+ vmovd %xmm9, 0x9c(%rdi)+ vmovdqa 0x100(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0xa0(%rdi)+ vmovd %xmm9, 0xb0(%rdi)+ vmovdqa 0x120(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0xb4(%rdi)+ vmovd %xmm9, 0xc4(%rdi)+ vmovdqa 0x140(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0xc8(%rdi)+ vmovd %xmm9, 0xd8(%rdi)+ vmovdqa 0x160(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0xdc(%rdi)+ vmovd %xmm9, 0xec(%rdi)+ vmovdqa 0x180(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0xf0(%rdi)+ vmovd %xmm9, 0x100(%rdi)+ vmovdqa 0x1a0(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x104(%rdi)+ vmovd %xmm9, 0x114(%rdi)+ vmovdqa 0x1c0(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x118(%rdi)+ vmovd %xmm9, 0x128(%rdi)+ vmovdqa 0x1e0(%rsi), %ymm8+ vpmullw %ymm1, %ymm8, %ymm9+ vpaddw %ymm2, %ymm8, %ymm10+ vpsllw $0x3, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm8, %ymm8+ vpsubw %ymm10, %ymm9, %ymm10+ vpandn %ymm10, %ymm9, %ymm9+ vpsrlw $0xf, %ymm9, %ymm9+ vpsubw %ymm9, %ymm8, %ymm8+ vpmulhrsw %ymm3, %ymm8, %ymm8+ vpand %ymm4, %ymm8, %ymm8+ vpmaddwd %ymm5, %ymm8, %ymm8+ vpsllvd %ymm6, %ymm8, %ymm8+ vpsrlq $0xc, %ymm8, %ymm8+ vpshufb %ymm7, %ymm8, %ymm8+ vextracti128 $0x1, %ymm8, %xmm9+ vpblendw $0xe0, %xmm9, %xmm8, %xmm8 # xmm8 = xmm8[0,1,2,3,4],xmm9[5,6,7]+ vmovdqu %xmm8, 0x12c(%rdi)+ vmovd %xmm9, 0x13c(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_compress_d10_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 || MLKEM_K == 3) \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,479 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++/*************************************************+ * Name: mlk_poly_compress_d11_avx2_asm+ *+ * Description: Compression of a polynomial to 11 bits per coefficient.+ *+ * Arguments: - uint8_t *r: pointer to output byte array+ * (of length MLKEM_POLYCOMPRESSEDBYTES_D11)+ * - const int16_t *a: pointer to input polynomial+ * - const uint8_t *data: pointer to constants+ * (srlvqidx[0:32], shufbidx[32:64])+ **************************************************/++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4)+/*yaml+ Name: poly_compress_d11_avx2_asm+ Description: x86_64 AVX2 polynomial compression (d=11)+ Signature: void mlk_poly_compress_d11_avx2_asm(uint8_t *r, const int16_t *a, const uint8_t *data)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 352+ permissions: write-only+ c_parameter: uint8_t *r+ description: Output compressed polynomial+ rsi:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t *a+ description: Input polynomial (256 x int16_t)+ rdx:+ type: buffer+ size_bytes: 64+ permissions: read-only+ c_parameter: const uint8_t *data+ description: Precomputed compression constants+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_poly_compress_d11_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_compress_d11_avx2_asm)+MLK_ASM_FN_SYMBOL(poly_compress_d11_avx2_asm)++ .cfi_startproc+ movl $0x4ebf4ebf, %eax # imm = 0x4EBF4EBF+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ vpsllw $0x3, %ymm0, %ymm1+ movl $0x240024, %eax # imm = 0x240024+ vmovd %eax, %xmm2+ vpbroadcastd %xmm2, %ymm2+ movl $0x20002000, %eax # imm = 0x20002000+ vmovd %eax, %xmm3+ vpbroadcastd %xmm3, %ymm3+ movl $0x7ff07ff, %eax # imm = 0x7FF07FF+ vmovd %eax, %xmm4+ vpbroadcastd %xmm4, %ymm4+ movabsq $0x800000108000001, %rax # imm = 0x800000108000001+ vmovq %rax, %xmm5+ vpbroadcastq %xmm5, %ymm5+ movl $0xa, %eax+ vmovq %rax, %xmm6+ vpbroadcastq %xmm6, %ymm6+ vmovdqa (%rdx), %ymm7+ vmovdqa 0x20(%rdx), %ymm8+ vmovdqa (%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, (%rdi)+ vmovd %xmm10, 0x10(%rdi)+ vpextrw $0x2, %xmm10, 0x14(%rdi)+ vmovdqa 0x20(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x16(%rdi)+ vmovd %xmm10, 0x26(%rdi)+ vpextrw $0x2, %xmm10, 0x2a(%rdi)+ vmovdqa 0x40(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x2c(%rdi)+ vmovd %xmm10, 0x3c(%rdi)+ vpextrw $0x2, %xmm10, 0x40(%rdi)+ vmovdqa 0x60(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x42(%rdi)+ vmovd %xmm10, 0x52(%rdi)+ vpextrw $0x2, %xmm10, 0x56(%rdi)+ vmovdqa 0x80(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x58(%rdi)+ vmovd %xmm10, 0x68(%rdi)+ vpextrw $0x2, %xmm10, 0x6c(%rdi)+ vmovdqa 0xa0(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x6e(%rdi)+ vmovd %xmm10, 0x7e(%rdi)+ vpextrw $0x2, %xmm10, 0x82(%rdi)+ vmovdqa 0xc0(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x84(%rdi)+ vmovd %xmm10, 0x94(%rdi)+ vpextrw $0x2, %xmm10, 0x98(%rdi)+ vmovdqa 0xe0(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x9a(%rdi)+ vmovd %xmm10, 0xaa(%rdi)+ vpextrw $0x2, %xmm10, 0xae(%rdi)+ vmovdqa 0x100(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0xb0(%rdi)+ vmovd %xmm10, 0xc0(%rdi)+ vpextrw $0x2, %xmm10, 0xc4(%rdi)+ vmovdqa 0x120(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0xc6(%rdi)+ vmovd %xmm10, 0xd6(%rdi)+ vpextrw $0x2, %xmm10, 0xda(%rdi)+ vmovdqa 0x140(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0xdc(%rdi)+ vmovd %xmm10, 0xec(%rdi)+ vpextrw $0x2, %xmm10, 0xf0(%rdi)+ vmovdqa 0x160(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0xf2(%rdi)+ vmovd %xmm10, 0x102(%rdi)+ vpextrw $0x2, %xmm10, 0x106(%rdi)+ vmovdqa 0x180(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x108(%rdi)+ vmovd %xmm10, 0x118(%rdi)+ vpextrw $0x2, %xmm10, 0x11c(%rdi)+ vmovdqa 0x1a0(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x11e(%rdi)+ vmovd %xmm10, 0x12e(%rdi)+ vpextrw $0x2, %xmm10, 0x132(%rdi)+ vmovdqa 0x1c0(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x134(%rdi)+ vmovd %xmm10, 0x144(%rdi)+ vpextrw $0x2, %xmm10, 0x148(%rdi)+ vmovdqa 0x1e0(%rsi), %ymm9+ vpmullw %ymm1, %ymm9, %ymm10+ vpaddw %ymm2, %ymm9, %ymm11+ vpsllw $0x3, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm9, %ymm9+ vpsubw %ymm11, %ymm10, %ymm11+ vpandn %ymm11, %ymm10, %ymm10+ vpsrlw $0xf, %ymm10, %ymm10+ vpsubw %ymm10, %ymm9, %ymm9+ vpmulhrsw %ymm3, %ymm9, %ymm9+ vpand %ymm4, %ymm9, %ymm9+ vpmaddwd %ymm5, %ymm9, %ymm9+ vpsllvd %ymm6, %ymm9, %ymm9+ vpsrldq $0x8, %ymm9, %ymm10 # ymm10 = ymm9[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero,ymm9[24,25,26,27,28,29,30,31],zero,zero,zero,zero,zero,zero,zero,zero+ vpsrlvq %ymm7, %ymm9, %ymm9+ vpsllq $0x22, %ymm10, %ymm10+ vpaddq %ymm10, %ymm9, %ymm9+ vpshufb %ymm8, %ymm9, %ymm9+ vextracti128 $0x1, %ymm9, %xmm10+ vpblendvb %xmm8, %xmm10, %xmm9, %xmm9+ vmovdqu %xmm9, 0x14a(%rdi)+ vmovd %xmm10, 0x15a(%rdi)+ vpextrw $0x2, %xmm10, 0x15e(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_compress_d11_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,194 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++/*************************************************+ * Name: mlk_poly_compress_d4_avx2_asm+ *+ * Description: Compression of a polynomial to 4 bits per coefficient.+ *+ * Arguments: - uint8_t *r: pointer to output byte array+ * (of length MLKEM_POLYCOMPRESSEDBYTES_D4)+ * - const int16_t *a: pointer to input polynomial+ * - const uint8_t *data: pointer to permdidx constant+ **************************************************/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2 || MLKEM_K == 3)+/*yaml+ Name: poly_compress_d4_avx2_asm+ Description: x86_64 AVX2 polynomial compression (d=4)+ Signature: void mlk_poly_compress_d4_avx2_asm(uint8_t *r, const int16_t *a, const uint8_t *data)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 128+ permissions: write-only+ c_parameter: uint8_t *r+ description: Output compressed polynomial+ rsi:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t *a+ description: Input polynomial (256 x int16_t)+ rdx:+ type: buffer+ size_bytes: 32+ permissions: read-only+ c_parameter: const uint8_t *data+ description: Precomputed compression constants+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_poly_compress_d4_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_compress_d4_avx2_asm)+MLK_ASM_FN_SYMBOL(poly_compress_d4_avx2_asm)++ .cfi_startproc+ movl $0x4ebf4ebf, %eax # imm = 0x4EBF4EBF+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0x2000200, %eax # imm = 0x2000200+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ movl $0xf000f, %eax # imm = 0xF000F+ vmovd %eax, %xmm2+ vpbroadcastd %xmm2, %ymm2+ movl $0x10011001, %eax # imm = 0x10011001+ vmovd %eax, %xmm3+ vpbroadcastd %xmm3, %ymm3+ vmovdqa (%rdx), %ymm4+ vmovdqa (%rsi), %ymm5+ vmovdqa 0x20(%rsi), %ymm6+ vmovdqa 0x40(%rsi), %ymm7+ vmovdqa 0x60(%rsi), %ymm8+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm5, %ymm5+ vpmulhrsw %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm5, %ymm5+ vpand %ymm2, %ymm6, %ymm6+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm6, %ymm5, %ymm5+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm5, %ymm5+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpackuswb %ymm7, %ymm5, %ymm5+ vpermd %ymm5, %ymm4, %ymm5+ vmovdqu %ymm5, (%rdi)+ vmovdqa 0x80(%rsi), %ymm5+ vmovdqa 0xa0(%rsi), %ymm6+ vmovdqa 0xc0(%rsi), %ymm7+ vmovdqa 0xe0(%rsi), %ymm8+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm5, %ymm5+ vpmulhrsw %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm5, %ymm5+ vpand %ymm2, %ymm6, %ymm6+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm6, %ymm5, %ymm5+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm5, %ymm5+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpackuswb %ymm7, %ymm5, %ymm5+ vpermd %ymm5, %ymm4, %ymm5+ vmovdqu %ymm5, 0x20(%rdi)+ vmovdqa 0x100(%rsi), %ymm5+ vmovdqa 0x120(%rsi), %ymm6+ vmovdqa 0x140(%rsi), %ymm7+ vmovdqa 0x160(%rsi), %ymm8+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm5, %ymm5+ vpmulhrsw %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm5, %ymm5+ vpand %ymm2, %ymm6, %ymm6+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm6, %ymm5, %ymm5+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm5, %ymm5+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpackuswb %ymm7, %ymm5, %ymm5+ vpermd %ymm5, %ymm4, %ymm5+ vmovdqu %ymm5, 0x40(%rdi)+ vmovdqa 0x180(%rsi), %ymm5+ vmovdqa 0x1a0(%rsi), %ymm6+ vmovdqa 0x1c0(%rsi), %ymm7+ vmovdqa 0x1e0(%rsi), %ymm8+ vpmulhw %ymm0, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm5, %ymm5+ vpmulhrsw %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm5, %ymm5+ vpand %ymm2, %ymm6, %ymm6+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm6, %ymm5, %ymm5+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm5, %ymm5+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpackuswb %ymm7, %ymm5, %ymm5+ vpermd %ymm5, %ymm4, %ymm5+ vmovdqu %ymm5, 0x60(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_compress_d4_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2 || MLKEM_K == 3) \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,251 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++/*************************************************+ * Name: mlk_poly_compress_d5_avx2_asm+ *+ * Description: Compression of a polynomial to 5 bits per coefficient.+ *+ * Arguments: - uint8_t *r: pointer to output byte array+ * (of length MLKEM_POLYCOMPRESSEDBYTES_D5)+ * - const int16_t *a: pointer to input polynomial+ * - const uint8_t *data: pointer to shufbidx constant+ **************************************************/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4)+/*yaml+ Name: poly_compress_d5_avx2_asm+ Description: x86_64 AVX2 polynomial compression (d=5)+ Signature: void mlk_poly_compress_d5_avx2_asm(uint8_t *r, const int16_t *a, const uint8_t *data)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 160+ permissions: write-only+ c_parameter: uint8_t *r+ description: Output compressed polynomial+ rsi:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t *a+ description: Input polynomial (256 x int16_t)+ rdx:+ type: buffer+ size_bytes: 32+ permissions: read-only+ c_parameter: const uint8_t *data+ description: Precomputed compression constants+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_poly_compress_d5_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_compress_d5_avx2_asm)+MLK_ASM_FN_SYMBOL(poly_compress_d5_avx2_asm)++ .cfi_startproc+ movl $0x4ebf4ebf, %eax # imm = 0x4EBF4EBF+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0x4000400, %eax # imm = 0x4000400+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ movl $0x1f001f, %eax # imm = 0x1F001F+ vmovd %eax, %xmm2+ vpbroadcastd %xmm2, %ymm2+ movl $0x20012001, %eax # imm = 0x20012001+ vmovd %eax, %xmm3+ vpbroadcastd %xmm3, %ymm3+ movl $0x4000001, %eax # imm = 0x4000001+ vmovd %eax, %xmm4+ vpbroadcastd %xmm4, %ymm4+ movl $0xc, %eax+ vmovq %rax, %xmm5+ vpbroadcastq %xmm5, %ymm5+ vmovdqa (%rdx), %ymm6+ vmovdqa (%rsi), %ymm7+ vmovdqa 0x20(%rsi), %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpmaddwd %ymm4, %ymm7, %ymm7+ vpsllvd %ymm5, %ymm7, %ymm7+ vpsrlvq %ymm5, %ymm7, %ymm7+ vpshufb %ymm6, %ymm7, %ymm7+ vextracti128 $0x1, %ymm7, %xmm8+ vpblendvb %xmm6, %xmm8, %xmm7, %xmm7+ vmovdqu %xmm7, (%rdi)+ vmovd %xmm8, 0x10(%rdi)+ vmovdqa 0x40(%rsi), %ymm7+ vmovdqa 0x60(%rsi), %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpmaddwd %ymm4, %ymm7, %ymm7+ vpsllvd %ymm5, %ymm7, %ymm7+ vpsrlvq %ymm5, %ymm7, %ymm7+ vpshufb %ymm6, %ymm7, %ymm7+ vextracti128 $0x1, %ymm7, %xmm8+ vpblendvb %xmm6, %xmm8, %xmm7, %xmm7+ vmovdqu %xmm7, 0x14(%rdi)+ vmovd %xmm8, 0x24(%rdi)+ vmovdqa 0x80(%rsi), %ymm7+ vmovdqa 0xa0(%rsi), %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpmaddwd %ymm4, %ymm7, %ymm7+ vpsllvd %ymm5, %ymm7, %ymm7+ vpsrlvq %ymm5, %ymm7, %ymm7+ vpshufb %ymm6, %ymm7, %ymm7+ vextracti128 $0x1, %ymm7, %xmm8+ vpblendvb %xmm6, %xmm8, %xmm7, %xmm7+ vmovdqu %xmm7, 0x28(%rdi)+ vmovd %xmm8, 0x38(%rdi)+ vmovdqa 0xc0(%rsi), %ymm7+ vmovdqa 0xe0(%rsi), %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpmaddwd %ymm4, %ymm7, %ymm7+ vpsllvd %ymm5, %ymm7, %ymm7+ vpsrlvq %ymm5, %ymm7, %ymm7+ vpshufb %ymm6, %ymm7, %ymm7+ vextracti128 $0x1, %ymm7, %xmm8+ vpblendvb %xmm6, %xmm8, %xmm7, %xmm7+ vmovdqu %xmm7, 0x3c(%rdi)+ vmovd %xmm8, 0x4c(%rdi)+ vmovdqa 0x100(%rsi), %ymm7+ vmovdqa 0x120(%rsi), %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpmaddwd %ymm4, %ymm7, %ymm7+ vpsllvd %ymm5, %ymm7, %ymm7+ vpsrlvq %ymm5, %ymm7, %ymm7+ vpshufb %ymm6, %ymm7, %ymm7+ vextracti128 $0x1, %ymm7, %xmm8+ vpblendvb %xmm6, %xmm8, %xmm7, %xmm7+ vmovdqu %xmm7, 0x50(%rdi)+ vmovd %xmm8, 0x60(%rdi)+ vmovdqa 0x140(%rsi), %ymm7+ vmovdqa 0x160(%rsi), %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpmaddwd %ymm4, %ymm7, %ymm7+ vpsllvd %ymm5, %ymm7, %ymm7+ vpsrlvq %ymm5, %ymm7, %ymm7+ vpshufb %ymm6, %ymm7, %ymm7+ vextracti128 $0x1, %ymm7, %xmm8+ vpblendvb %xmm6, %xmm8, %xmm7, %xmm7+ vmovdqu %xmm7, 0x64(%rdi)+ vmovd %xmm8, 0x74(%rdi)+ vmovdqa 0x180(%rsi), %ymm7+ vmovdqa 0x1a0(%rsi), %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpmaddwd %ymm4, %ymm7, %ymm7+ vpsllvd %ymm5, %ymm7, %ymm7+ vpsrlvq %ymm5, %ymm7, %ymm7+ vpshufb %ymm6, %ymm7, %ymm7+ vextracti128 $0x1, %ymm7, %xmm8+ vpblendvb %xmm6, %xmm8, %xmm7, %xmm7+ vmovdqu %xmm7, 0x78(%rdi)+ vmovd %xmm8, 0x88(%rdi)+ vmovdqa 0x1c0(%rsi), %ymm7+ vmovdqa 0x1e0(%rsi), %ymm8+ vpmulhw %ymm0, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm8, %ymm8+ vpmulhrsw %ymm1, %ymm7, %ymm7+ vpmulhrsw %ymm1, %ymm8, %ymm8+ vpand %ymm2, %ymm7, %ymm7+ vpand %ymm2, %ymm8, %ymm8+ vpackuswb %ymm8, %ymm7, %ymm7+ vpmaddubsw %ymm3, %ymm7, %ymm7+ vpmaddwd %ymm4, %ymm7, %ymm7+ vpsllvd %ymm5, %ymm7, %ymm7+ vpsrlvq %ymm5, %ymm7, %ymm7+ vpshufb %ymm6, %ymm7, %ymm7+ vextracti128 $0x1, %ymm7, %xmm8+ vpblendvb %xmm6, %xmm8, %xmm7, %xmm7+ vmovdqu %xmm7, 0x8c(%rdi)+ vmovd %xmm8, 0x9c(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_compress_d5_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API) && \+ (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,257 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++/*************************************************+ * Name: mlk_poly_decompress_d10_avx2_asm+ *+ * Description: Decompression of a polynomial from 10 bits per coefficient.+ *+ * Arguments: - int16_t *r: pointer to output polynomial+ * - const uint8_t *a: pointer to input byte array+ * (of length MLKEM_POLYCOMPRESSEDBYTES_D10)+ * - const uint8_t *data: pointer to shufbidx constant+ **************************************************/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ !defined(MLK_CONFIG_NO_DECAPS_API) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2 || MLKEM_K == 3)+/*yaml+ Name: poly_decompress_d10_avx2_asm+ Description: x86_64 AVX2 polynomial decompression (d=10)+ Signature: void mlk_poly_decompress_d10_avx2_asm(int16_t *r, const uint8_t *a, const uint8_t *data)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t *r+ description: Output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 320+ permissions: read-only+ c_parameter: const uint8_t *a+ description: Input compressed polynomial+ rdx:+ type: buffer+ size_bytes: 32+ permissions: read-only+ c_parameter: const uint8_t *data+ description: Precomputed decompression constants+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_poly_decompress_d10_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_decompress_d10_avx2_asm)+MLK_ASM_FN_SYMBOL(poly_decompress_d10_avx2_asm)++ .cfi_startproc+ movl $0xd013404, %eax # imm = 0xD013404+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0x4, %eax+ vmovq %rax, %xmm1+ vpbroadcastq %xmm1, %ymm1+ movl $0x7fe01ff8, %eax # imm = 0x7FE01FF8+ vmovd %eax, %xmm2+ vpbroadcastd %xmm2, %ymm2+ vmovdqa (%rdx), %ymm3+ vmovdqu (%rsi), %xmm4+ vmovd 0x10(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, (%rdi)+ vmovdqu 0x14(%rsi), %xmm4+ vmovd 0x24(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x20(%rdi)+ vmovdqu 0x28(%rsi), %xmm4+ vmovd 0x38(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x40(%rdi)+ vmovdqu 0x3c(%rsi), %xmm4+ vmovd 0x4c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x60(%rdi)+ vmovdqu 0x50(%rsi), %xmm4+ vmovd 0x60(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x80(%rdi)+ vmovdqu 0x64(%rsi), %xmm4+ vmovd 0x74(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0xa0(%rdi)+ vmovdqu 0x78(%rsi), %xmm4+ vmovd 0x88(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0xc0(%rdi)+ vmovdqu 0x8c(%rsi), %xmm4+ vmovd 0x9c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0xe0(%rdi)+ vmovdqu 0xa0(%rsi), %xmm4+ vmovd 0xb0(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x100(%rdi)+ vmovdqu 0xb4(%rsi), %xmm4+ vmovd 0xc4(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x120(%rdi)+ vmovdqu 0xc8(%rsi), %xmm4+ vmovd 0xd8(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x140(%rdi)+ vmovdqu 0xdc(%rsi), %xmm4+ vmovd 0xec(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x160(%rdi)+ vmovdqu 0xf0(%rsi), %xmm4+ vmovd 0x100(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x180(%rdi)+ vmovdqu 0x104(%rsi), %xmm4+ vmovd 0x114(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x1a0(%rdi)+ vmovdqu 0x118(%rsi), %xmm4+ vmovd 0x128(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x1c0(%rdi)+ vmovdqu 0x12c(%rsi), %xmm4+ vmovd 0x13c(%rsi), %xmm5+ vinserti128 $0x1, %xmm5, %ymm4, %ymm4+ vpermq $0x94, %ymm4, %ymm4 # ymm4 = ymm4[0,1,1,2]+ vpshufb %ymm3, %ymm4, %ymm4+ vpsllvd %ymm1, %ymm4, %ymm4+ vpsrlw $0x1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_decompress_d10_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && !MLK_CONFIG_NO_DECAPS_API && (MLK_CONFIG_MULTILEVEL_WITH_SHARED || \+ MLKEM_K == 2 || MLKEM_K == 3) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,307 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++/*************************************************+ * Name: mlk_poly_decompress_d11_avx2_asm+ *+ * Description: Decompression of a polynomial from 11 bits per coefficient.+ *+ * Arguments: - int16_t *r: pointer to output polynomial+ * - const uint8_t *a: pointer to input byte array+ * (of length MLKEM_POLYCOMPRESSEDBYTES_D11)+ * - const uint8_t *data: pointer to constants+ * (shufbidx[0:32], srlvdidx[32:64],+ * srlvqidx[64:96], shift[96:128])+ **************************************************/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ !defined(MLK_CONFIG_NO_DECAPS_API) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4)+/*yaml+ Name: poly_decompress_d11_avx2_asm+ Description: x86_64 AVX2 polynomial decompression (d=11)+ Signature: void mlk_poly_decompress_d11_avx2_asm(int16_t *r, const uint8_t *a, const uint8_t *data)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t *r+ description: Output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 352+ permissions: read-only+ c_parameter: const uint8_t *a+ description: Input compressed polynomial+ rdx:+ type: buffer+ size_bytes: 128+ permissions: read-only+ c_parameter: const uint8_t *data+ description: Precomputed decompression constants+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_poly_decompress_d11_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_decompress_d11_avx2_asm)+MLK_ASM_FN_SYMBOL(poly_decompress_d11_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0x7ff07ff0, %eax # imm = 0x7FF07FF0+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ vmovdqa (%rdx), %ymm2+ vmovdqa 0x20(%rdx), %ymm3+ vmovdqa 0x40(%rdx), %ymm4+ vmovdqa 0x60(%rdx), %ymm5+ vmovdqu (%rsi), %xmm6+ vmovd 0x10(%rsi), %xmm7+ vpinsrw $0x2, 0x14(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, (%rdi)+ vmovdqu 0x16(%rsi), %xmm6+ vmovd 0x26(%rsi), %xmm7+ vpinsrw $0x2, 0x2a(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x20(%rdi)+ vmovdqu 0x2c(%rsi), %xmm6+ vmovd 0x3c(%rsi), %xmm7+ vpinsrw $0x2, 0x40(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x40(%rdi)+ vmovdqu 0x42(%rsi), %xmm6+ vmovd 0x52(%rsi), %xmm7+ vpinsrw $0x2, 0x56(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x60(%rdi)+ vmovdqu 0x58(%rsi), %xmm6+ vmovd 0x68(%rsi), %xmm7+ vpinsrw $0x2, 0x6c(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x80(%rdi)+ vmovdqu 0x6e(%rsi), %xmm6+ vmovd 0x7e(%rsi), %xmm7+ vpinsrw $0x2, 0x82(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0xa0(%rdi)+ vmovdqu 0x84(%rsi), %xmm6+ vmovd 0x94(%rsi), %xmm7+ vpinsrw $0x2, 0x98(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0xc0(%rdi)+ vmovdqu 0x9a(%rsi), %xmm6+ vmovd 0xaa(%rsi), %xmm7+ vpinsrw $0x2, 0xae(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0xe0(%rdi)+ vmovdqu 0xb0(%rsi), %xmm6+ vmovd 0xc0(%rsi), %xmm7+ vpinsrw $0x2, 0xc4(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x100(%rdi)+ vmovdqu 0xc6(%rsi), %xmm6+ vmovd 0xd6(%rsi), %xmm7+ vpinsrw $0x2, 0xda(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x120(%rdi)+ vmovdqu 0xdc(%rsi), %xmm6+ vmovd 0xec(%rsi), %xmm7+ vpinsrw $0x2, 0xf0(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x140(%rdi)+ vmovdqu 0xf2(%rsi), %xmm6+ vmovd 0x102(%rsi), %xmm7+ vpinsrw $0x2, 0x106(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x160(%rdi)+ vmovdqu 0x108(%rsi), %xmm6+ vmovd 0x118(%rsi), %xmm7+ vpinsrw $0x2, 0x11c(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x180(%rdi)+ vmovdqu 0x11e(%rsi), %xmm6+ vmovd 0x12e(%rsi), %xmm7+ vpinsrw $0x2, 0x132(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x1a0(%rdi)+ vmovdqu 0x134(%rsi), %xmm6+ vmovd 0x144(%rsi), %xmm7+ vpinsrw $0x2, 0x148(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x1c0(%rdi)+ vmovdqu 0x14a(%rsi), %xmm6+ vmovd 0x15a(%rsi), %xmm7+ vpinsrw $0x2, 0x15e(%rsi), %xmm7, %xmm7+ vinserti128 $0x1, %xmm7, %ymm6, %ymm6+ vpermq $0x94, %ymm6, %ymm6 # ymm6 = ymm6[0,1,1,2]+ vpshufb %ymm2, %ymm6, %ymm6+ vpsrlvd %ymm3, %ymm6, %ymm6+ vpsrlvq %ymm4, %ymm6, %ymm6+ vpmullw %ymm5, %ymm6, %ymm6+ vpsrlw $0x1, %ymm6, %ymm6+ vpand %ymm1, %ymm6, %ymm6+ vpmulhrsw %ymm0, %ymm6, %ymm6+ vmovdqu %ymm6, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_decompress_d11_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && !MLK_CONFIG_NO_DECAPS_API && (MLK_CONFIG_MULTILEVEL_WITH_SHARED || \+ MLKEM_K == 4) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,209 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++/*************************************************+ * Name: mlk_poly_decompress_d4_avx2_asm+ *+ * Description: Decompression of a polynomial from 4 bits per coefficient.+ *+ * Arguments: - int16_t *r: pointer to output polynomial+ * - const uint8_t *a: pointer to input byte array+ * (of length MLKEM_POLYCOMPRESSEDBYTES_D4)+ * - const int8_t *data: pointer to shufbidx constant+ **************************************************/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ !defined(MLK_CONFIG_NO_DECAPS_API) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2 || MLKEM_K == 3)+/*yaml+ Name: poly_decompress_d4_avx2_asm+ Description: x86_64 AVX2 polynomial decompression (d=4)+ Signature: void mlk_poly_decompress_d4_avx2_asm(int16_t *r, const uint8_t *a, const uint8_t *data)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t *r+ description: Output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 128+ permissions: read-only+ c_parameter: const uint8_t *a+ description: Input compressed polynomial+ rdx:+ type: buffer+ size_bytes: 32+ permissions: read-only+ c_parameter: const uint8_t *data+ description: Precomputed decompression constants+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_poly_decompress_d4_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_decompress_d4_avx2_asm)+MLK_ASM_FN_SYMBOL(poly_decompress_d4_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0xf0000f, %eax # imm = 0xF0000F+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ movl $0x800800, %eax # imm = 0x800800+ vmovd %eax, %xmm2+ vpbroadcastd %xmm2, %ymm2+ vmovdqa (%rdx), %ymm3+ vmovq (%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, (%rdi)+ vmovq 0x8(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x20(%rdi)+ vmovq 0x10(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x40(%rdi)+ vmovq 0x18(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x60(%rdi)+ vmovq 0x20(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x80(%rdi)+ vmovq 0x28(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0xa0(%rdi)+ vmovq 0x30(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0xc0(%rdi)+ vmovq 0x38(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0xe0(%rdi)+ vmovq 0x40(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x100(%rdi)+ vmovq 0x48(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x120(%rdi)+ vmovq 0x50(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x140(%rdi)+ vmovq 0x58(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x160(%rdi)+ vmovq 0x60(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x180(%rdi)+ vmovq 0x68(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x1a0(%rdi)+ vmovq 0x70(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x1c0(%rdi)+ vmovq 0x78(%rsi), %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm3, %ymm4, %ymm4+ vpand %ymm1, %ymm4, %ymm4+ vpmullw %ymm2, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_decompress_d4_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && !MLK_CONFIG_NO_DECAPS_API && (MLK_CONFIG_MULTILEVEL_WITH_SHARED || \+ MLKEM_K == 2 || MLKEM_K == 3) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,222 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ */++/*************************************************+ * Name: mlk_poly_decompress_d5_avx2_asm+ *+ * Description: Decompression of a polynomial from 5 bits per coefficient.+ *+ * Arguments: - int16_t *r: pointer to output polynomial+ * - const uint8_t *a: pointer to input byte array+ * (of length MLKEM_POLYCOMPRESSEDBYTES_D5)+ * - const uint8_t *data: pointer to constants+ * (shufbidx[0:32], mask[32:64], shift[64:96])+ **************************************************/++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ !defined(MLK_CONFIG_NO_DECAPS_API) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4)+/*yaml+ Name: poly_decompress_d5_avx2_asm+ Description: x86_64 AVX2 polynomial decompression (d=5)+ Signature: void mlk_poly_decompress_d5_avx2_asm(int16_t *r, const uint8_t *a, const uint8_t *data)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t *r+ description: Output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 160+ permissions: read-only+ c_parameter: const uint8_t *a+ description: Input compressed polynomial+ rdx:+ type: buffer+ size_bytes: 96+ permissions: read-only+ c_parameter: const uint8_t *data+ description: Precomputed decompression constants+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_poly_decompress_d5_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_decompress_d5_avx2_asm)+MLK_ASM_FN_SYMBOL(poly_decompress_d5_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ vmovdqa (%rdx), %ymm1+ vmovdqa 0x20(%rdx), %ymm2+ vmovdqa 0x40(%rdx), %ymm3+ vmovq (%rsi), %xmm4+ vpinsrw $0x4, 0x8(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, (%rdi)+ vmovq 0xa(%rsi), %xmm4+ vpinsrw $0x4, 0x12(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x20(%rdi)+ vmovq 0x14(%rsi), %xmm4+ vpinsrw $0x4, 0x1c(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x40(%rdi)+ vmovq 0x1e(%rsi), %xmm4+ vpinsrw $0x4, 0x26(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x60(%rdi)+ vmovq 0x28(%rsi), %xmm4+ vpinsrw $0x4, 0x30(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x80(%rdi)+ vmovq 0x32(%rsi), %xmm4+ vpinsrw $0x4, 0x3a(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0xa0(%rdi)+ vmovq 0x3c(%rsi), %xmm4+ vpinsrw $0x4, 0x44(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0xc0(%rdi)+ vmovq 0x46(%rsi), %xmm4+ vpinsrw $0x4, 0x4e(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0xe0(%rdi)+ vmovq 0x50(%rsi), %xmm4+ vpinsrw $0x4, 0x58(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x100(%rdi)+ vmovq 0x5a(%rsi), %xmm4+ vpinsrw $0x4, 0x62(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x120(%rdi)+ vmovq 0x64(%rsi), %xmm4+ vpinsrw $0x4, 0x6c(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x140(%rdi)+ vmovq 0x6e(%rsi), %xmm4+ vpinsrw $0x4, 0x76(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x160(%rdi)+ vmovq 0x78(%rsi), %xmm4+ vpinsrw $0x4, 0x80(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x180(%rdi)+ vmovq 0x82(%rsi), %xmm4+ vpinsrw $0x4, 0x8a(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x1a0(%rdi)+ vmovq 0x8c(%rsi), %xmm4+ vpinsrw $0x4, 0x94(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x1c0(%rdi)+ vmovq 0x96(%rsi), %xmm4+ vpinsrw $0x4, 0x9e(%rsi), %xmm4, %xmm4+ vinserti128 $0x1, %xmm4, %ymm4, %ymm4+ vpshufb %ymm1, %ymm4, %ymm4+ vpand %ymm2, %ymm4, %ymm4+ vpmullw %ymm3, %ymm4, %ymm4+ vpmulhrsw %ymm0, %ymm4, %ymm4+ vmovdqu %ymm4, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_decompress_d5_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && !MLK_CONFIG_NO_DECAPS_API && (MLK_CONFIG_MULTILEVEL_WITH_SHARED || \+ MLKEM_K == 4) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,118 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+/*yaml+ Name: poly_mulcache_compute_avx2_asm+ Description: x86_64 AVX2 mulcache computation+ Signature: void mlk_poly_mulcache_compute_avx2_asm(int16_t *out, const int16_t *in, const int16_t *qdata)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 256+ permissions: write-only+ c_parameter: int16_t *out+ description: Output mulcache (128 x int16_t)+ rsi:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t *in+ description: Input polynomial (256 x int16_t)+ rdx:+ type: buffer+ size_bytes: 1248+ permissions: read-only+ c_parameter: const int16_t *qdata+ description: Precomputed constants (624 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_poly_mulcache_compute_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(poly_mulcache_compute_avx2_asm)+MLK_ASM_FN_SYMBOL(poly_mulcache_compute_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ vmovdqa 0x20(%rsi), %ymm2+ vmovdqa 0x60(%rsi), %ymm3+ vmovdqa 0x3e0(%rdx), %ymm4+ vmovdqa 0x460(%rdx), %ymm1+ vpmullw %ymm2, %ymm1, %ymm5+ vpmullw %ymm3, %ymm1, %ymm6+ vpmulhw %ymm2, %ymm4, %ymm7+ vpmulhw %ymm3, %ymm4, %ymm8+ vpmulhw %ymm5, %ymm0, %ymm9+ vpmulhw %ymm6, %ymm0, %ymm10+ vpsubw %ymm9, %ymm7, %ymm7+ vpsubw %ymm10, %ymm8, %ymm8+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm8, 0x20(%rdi)+ vmovdqa 0xa0(%rsi), %ymm2+ vmovdqa 0xe0(%rsi), %ymm3+ vmovdqa 0x400(%rdx), %ymm4+ vmovdqa 0x480(%rdx), %ymm1+ vpmullw %ymm2, %ymm1, %ymm5+ vpmullw %ymm3, %ymm1, %ymm6+ vpmulhw %ymm2, %ymm4, %ymm7+ vpmulhw %ymm3, %ymm4, %ymm8+ vpmulhw %ymm5, %ymm0, %ymm9+ vpmulhw %ymm6, %ymm0, %ymm10+ vpsubw %ymm9, %ymm7, %ymm7+ vpsubw %ymm10, %ymm8, %ymm8+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm8, 0x60(%rdi)+ vmovdqa 0x120(%rsi), %ymm2+ vmovdqa 0x160(%rsi), %ymm3+ vmovdqa 0x420(%rdx), %ymm4+ vmovdqa 0x4a0(%rdx), %ymm1+ vpmullw %ymm2, %ymm1, %ymm5+ vpmullw %ymm3, %ymm1, %ymm6+ vpmulhw %ymm2, %ymm4, %ymm7+ vpmulhw %ymm3, %ymm4, %ymm8+ vpmulhw %ymm5, %ymm0, %ymm9+ vpmulhw %ymm6, %ymm0, %ymm10+ vpsubw %ymm9, %ymm7, %ymm7+ vpsubw %ymm10, %ymm8, %ymm8+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm8, 0xa0(%rdi)+ vmovdqa 0x1a0(%rsi), %ymm2+ vmovdqa 0x1e0(%rsi), %ymm3+ vmovdqa 0x440(%rdx), %ymm4+ vmovdqa 0x4c0(%rdx), %ymm1+ vpmullw %ymm2, %ymm1, %ymm5+ vpmullw %ymm3, %ymm1, %ymm6+ vpmulhw %ymm2, %ymm4, %ymm7+ vpmulhw %ymm3, %ymm4, %ymm8+ vpmulhw %ymm5, %ymm0, %ymm9+ vpmulhw %ymm6, %ymm0, %ymm10+ vpsubw %ymm9, %ymm7, %ymm7+ vpsubw %ymm10, %ymm8, %ymm8+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm8, 0xe0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(poly_mulcache_compute_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,536 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 2)+/*yaml+ Name: polyvec_basemul_acc_montgomery_cached_k2_avx2_asm+ Description: x86_64 AVX2 base multiplication with accumulation (k=2)+ Signature: void mlk_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm(int16_t *r, const int16_t *a, const int16_t *b, const int16_t *b_cache)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t *r+ description: Output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int16_t *a+ description: Input polyvec a (2 x 256 x int16_t)+ rdx:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int16_t *b+ description: Input polyvec b (2 x 256 x int16_t)+ rcx:+ type: buffer+ size_bytes: 512+ permissions: read-only+ c_parameter: const int16_t *b_cache+ description: Mulcache for b (2 x 128 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k2_avx2_asm)+MLK_ASM_FN_SYMBOL(polyvec_basemul_acc_montgomery_cached_k2_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0xf301f301, %eax # imm = 0xF301F301+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ vmovdqa (%rsi), %ymm2+ vmovdqa 0x20(%rsi), %ymm3+ vmovdqa (%rdx), %ymm4+ vmovdqa 0x20(%rdx), %ymm5+ vmovdqa (%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa 0x40(%rsi), %ymm2+ vmovdqa 0x60(%rsi), %ymm3+ vmovdqa 0x40(%rdx), %ymm4+ vmovdqa 0x60(%rdx), %ymm5+ vmovdqa 0x20(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm9, 0x60(%rdi)+ vmovdqa 0x80(%rsi), %ymm2+ vmovdqa 0xa0(%rsi), %ymm3+ vmovdqa 0x80(%rdx), %ymm4+ vmovdqa 0xa0(%rdx), %ymm5+ vmovdqa 0x40(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm9, 0xa0(%rdi)+ vmovdqa 0xc0(%rsi), %ymm2+ vmovdqa 0xe0(%rsi), %ymm3+ vmovdqa 0xc0(%rdx), %ymm4+ vmovdqa 0xe0(%rdx), %ymm5+ vmovdqa 0x60(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x100(%rsi), %ymm2+ vmovdqa 0x120(%rsi), %ymm3+ vmovdqa 0x100(%rdx), %ymm4+ vmovdqa 0x120(%rdx), %ymm5+ vmovdqa 0x80(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa 0x140(%rsi), %ymm2+ vmovdqa 0x160(%rsi), %ymm3+ vmovdqa 0x140(%rdx), %ymm4+ vmovdqa 0x160(%rdx), %ymm5+ vmovdqa 0xa0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm9, 0x160(%rdi)+ vmovdqa 0x180(%rsi), %ymm2+ vmovdqa 0x1a0(%rsi), %ymm3+ vmovdqa 0x180(%rdx), %ymm4+ vmovdqa 0x1a0(%rdx), %ymm5+ vmovdqa 0xc0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa 0x1c0(%rsi), %ymm2+ vmovdqa 0x1e0(%rsi), %ymm3+ vmovdqa 0x1c0(%rdx), %ymm4+ vmovdqa 0x1e0(%rdx), %ymm5+ vmovdqa 0xe0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ vmovdqa 0x200(%rsi), %ymm2+ vmovdqa 0x220(%rsi), %ymm3+ vmovdqa 0x200(%rdx), %ymm4+ vmovdqa 0x220(%rdx), %ymm5+ vmovdqa 0x100(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa (%rdi), %ymm8+ vmovdqa 0x20(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa 0x240(%rsi), %ymm2+ vmovdqa 0x260(%rsi), %ymm3+ vmovdqa 0x240(%rdx), %ymm4+ vmovdqa 0x260(%rdx), %ymm5+ vmovdqa 0x120(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x40(%rdi), %ymm8+ vmovdqa 0x60(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm9, 0x60(%rdi)+ vmovdqa 0x280(%rsi), %ymm2+ vmovdqa 0x2a0(%rsi), %ymm3+ vmovdqa 0x280(%rdx), %ymm4+ vmovdqa 0x2a0(%rdx), %ymm5+ vmovdqa 0x140(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm9, 0xa0(%rdi)+ vmovdqa 0x2c0(%rsi), %ymm2+ vmovdqa 0x2e0(%rsi), %ymm3+ vmovdqa 0x2c0(%rdx), %ymm4+ vmovdqa 0x2e0(%rdx), %ymm5+ vmovdqa 0x160(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0xc0(%rdi), %ymm8+ vmovdqa 0xe0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x300(%rsi), %ymm2+ vmovdqa 0x320(%rsi), %ymm3+ vmovdqa 0x300(%rdx), %ymm4+ vmovdqa 0x320(%rdx), %ymm5+ vmovdqa 0x180(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x100(%rdi), %ymm8+ vmovdqa 0x120(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa 0x340(%rsi), %ymm2+ vmovdqa 0x360(%rsi), %ymm3+ vmovdqa 0x340(%rdx), %ymm4+ vmovdqa 0x360(%rdx), %ymm5+ vmovdqa 0x1a0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x140(%rdi), %ymm8+ vmovdqa 0x160(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm9, 0x160(%rdi)+ vmovdqa 0x380(%rsi), %ymm2+ vmovdqa 0x3a0(%rsi), %ymm3+ vmovdqa 0x380(%rdx), %ymm4+ vmovdqa 0x3a0(%rdx), %ymm5+ vmovdqa 0x1c0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa 0x3c0(%rsi), %ymm2+ vmovdqa 0x3e0(%rsi), %ymm3+ vmovdqa 0x3c0(%rdx), %ymm4+ vmovdqa 0x3e0(%rdx), %ymm5+ vmovdqa 0x1e0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x1c0(%rdi), %ymm8+ vmovdqa 0x1e0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(polyvec_basemul_acc_montgomery_cached_k2_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 2) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,784 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 3)+/*yaml+ Name: polyvec_basemul_acc_montgomery_cached_k3_avx2_asm+ Description: x86_64 AVX2 base multiplication with accumulation (k=3)+ Signature: void mlk_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm(int16_t *r, const int16_t *a, const int16_t *b, const int16_t *b_cache)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t *r+ description: Output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 1536+ permissions: read-only+ c_parameter: const int16_t *a+ description: Input polyvec a (3 x 256 x int16_t)+ rdx:+ type: buffer+ size_bytes: 1536+ permissions: read-only+ c_parameter: const int16_t *b+ description: Input polyvec b (3 x 256 x int16_t)+ rcx:+ type: buffer+ size_bytes: 768+ permissions: read-only+ c_parameter: const int16_t *b_cache+ description: Mulcache for b (3 x 128 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k3_avx2_asm)+MLK_ASM_FN_SYMBOL(polyvec_basemul_acc_montgomery_cached_k3_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0xf301f301, %eax # imm = 0xF301F301+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ vmovdqa (%rsi), %ymm2+ vmovdqa 0x20(%rsi), %ymm3+ vmovdqa (%rdx), %ymm4+ vmovdqa 0x20(%rdx), %ymm5+ vmovdqa (%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa 0x40(%rsi), %ymm2+ vmovdqa 0x60(%rsi), %ymm3+ vmovdqa 0x40(%rdx), %ymm4+ vmovdqa 0x60(%rdx), %ymm5+ vmovdqa 0x20(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm9, 0x60(%rdi)+ vmovdqa 0x80(%rsi), %ymm2+ vmovdqa 0xa0(%rsi), %ymm3+ vmovdqa 0x80(%rdx), %ymm4+ vmovdqa 0xa0(%rdx), %ymm5+ vmovdqa 0x40(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm9, 0xa0(%rdi)+ vmovdqa 0xc0(%rsi), %ymm2+ vmovdqa 0xe0(%rsi), %ymm3+ vmovdqa 0xc0(%rdx), %ymm4+ vmovdqa 0xe0(%rdx), %ymm5+ vmovdqa 0x60(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x100(%rsi), %ymm2+ vmovdqa 0x120(%rsi), %ymm3+ vmovdqa 0x100(%rdx), %ymm4+ vmovdqa 0x120(%rdx), %ymm5+ vmovdqa 0x80(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa 0x140(%rsi), %ymm2+ vmovdqa 0x160(%rsi), %ymm3+ vmovdqa 0x140(%rdx), %ymm4+ vmovdqa 0x160(%rdx), %ymm5+ vmovdqa 0xa0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm9, 0x160(%rdi)+ vmovdqa 0x180(%rsi), %ymm2+ vmovdqa 0x1a0(%rsi), %ymm3+ vmovdqa 0x180(%rdx), %ymm4+ vmovdqa 0x1a0(%rdx), %ymm5+ vmovdqa 0xc0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa 0x1c0(%rsi), %ymm2+ vmovdqa 0x1e0(%rsi), %ymm3+ vmovdqa 0x1c0(%rdx), %ymm4+ vmovdqa 0x1e0(%rdx), %ymm5+ vmovdqa 0xe0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ vmovdqa 0x200(%rsi), %ymm2+ vmovdqa 0x220(%rsi), %ymm3+ vmovdqa 0x200(%rdx), %ymm4+ vmovdqa 0x220(%rdx), %ymm5+ vmovdqa 0x100(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa (%rdi), %ymm8+ vmovdqa 0x20(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa 0x240(%rsi), %ymm2+ vmovdqa 0x260(%rsi), %ymm3+ vmovdqa 0x240(%rdx), %ymm4+ vmovdqa 0x260(%rdx), %ymm5+ vmovdqa 0x120(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x40(%rdi), %ymm8+ vmovdqa 0x60(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm9, 0x60(%rdi)+ vmovdqa 0x280(%rsi), %ymm2+ vmovdqa 0x2a0(%rsi), %ymm3+ vmovdqa 0x280(%rdx), %ymm4+ vmovdqa 0x2a0(%rdx), %ymm5+ vmovdqa 0x140(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm9, 0xa0(%rdi)+ vmovdqa 0x2c0(%rsi), %ymm2+ vmovdqa 0x2e0(%rsi), %ymm3+ vmovdqa 0x2c0(%rdx), %ymm4+ vmovdqa 0x2e0(%rdx), %ymm5+ vmovdqa 0x160(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0xc0(%rdi), %ymm8+ vmovdqa 0xe0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x300(%rsi), %ymm2+ vmovdqa 0x320(%rsi), %ymm3+ vmovdqa 0x300(%rdx), %ymm4+ vmovdqa 0x320(%rdx), %ymm5+ vmovdqa 0x180(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x100(%rdi), %ymm8+ vmovdqa 0x120(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa 0x340(%rsi), %ymm2+ vmovdqa 0x360(%rsi), %ymm3+ vmovdqa 0x340(%rdx), %ymm4+ vmovdqa 0x360(%rdx), %ymm5+ vmovdqa 0x1a0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x140(%rdi), %ymm8+ vmovdqa 0x160(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm9, 0x160(%rdi)+ vmovdqa 0x380(%rsi), %ymm2+ vmovdqa 0x3a0(%rsi), %ymm3+ vmovdqa 0x380(%rdx), %ymm4+ vmovdqa 0x3a0(%rdx), %ymm5+ vmovdqa 0x1c0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa 0x3c0(%rsi), %ymm2+ vmovdqa 0x3e0(%rsi), %ymm3+ vmovdqa 0x3c0(%rdx), %ymm4+ vmovdqa 0x3e0(%rdx), %ymm5+ vmovdqa 0x1e0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x1c0(%rdi), %ymm8+ vmovdqa 0x1e0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ vmovdqa 0x400(%rsi), %ymm2+ vmovdqa 0x420(%rsi), %ymm3+ vmovdqa 0x400(%rdx), %ymm4+ vmovdqa 0x420(%rdx), %ymm5+ vmovdqa 0x200(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa (%rdi), %ymm8+ vmovdqa 0x20(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa 0x440(%rsi), %ymm2+ vmovdqa 0x460(%rsi), %ymm3+ vmovdqa 0x440(%rdx), %ymm4+ vmovdqa 0x460(%rdx), %ymm5+ vmovdqa 0x220(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x40(%rdi), %ymm8+ vmovdqa 0x60(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm9, 0x60(%rdi)+ vmovdqa 0x480(%rsi), %ymm2+ vmovdqa 0x4a0(%rsi), %ymm3+ vmovdqa 0x480(%rdx), %ymm4+ vmovdqa 0x4a0(%rdx), %ymm5+ vmovdqa 0x240(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm9, 0xa0(%rdi)+ vmovdqa 0x4c0(%rsi), %ymm2+ vmovdqa 0x4e0(%rsi), %ymm3+ vmovdqa 0x4c0(%rdx), %ymm4+ vmovdqa 0x4e0(%rdx), %ymm5+ vmovdqa 0x260(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0xc0(%rdi), %ymm8+ vmovdqa 0xe0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x500(%rsi), %ymm2+ vmovdqa 0x520(%rsi), %ymm3+ vmovdqa 0x500(%rdx), %ymm4+ vmovdqa 0x520(%rdx), %ymm5+ vmovdqa 0x280(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x100(%rdi), %ymm8+ vmovdqa 0x120(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa 0x540(%rsi), %ymm2+ vmovdqa 0x560(%rsi), %ymm3+ vmovdqa 0x540(%rdx), %ymm4+ vmovdqa 0x560(%rdx), %ymm5+ vmovdqa 0x2a0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x140(%rdi), %ymm8+ vmovdqa 0x160(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm9, 0x160(%rdi)+ vmovdqa 0x580(%rsi), %ymm2+ vmovdqa 0x5a0(%rsi), %ymm3+ vmovdqa 0x580(%rdx), %ymm4+ vmovdqa 0x5a0(%rdx), %ymm5+ vmovdqa 0x2c0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa 0x5c0(%rsi), %ymm2+ vmovdqa 0x5e0(%rsi), %ymm3+ vmovdqa 0x5c0(%rdx), %ymm4+ vmovdqa 0x5e0(%rdx), %ymm5+ vmovdqa 0x2e0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x1c0(%rdi), %ymm8+ vmovdqa 0x1e0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(polyvec_basemul_acc_montgomery_cached_k3_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 3) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,1032 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ (defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_K == 4)+/*yaml+ Name: polyvec_basemul_acc_montgomery_cached_k4_avx2_asm+ Description: x86_64 AVX2 base multiplication with accumulation (k=4)+ Signature: void mlk_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm(int16_t *r, const int16_t *a, const int16_t *b, const int16_t *b_cache)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t *r+ description: Output polynomial (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: 2048+ permissions: read-only+ c_parameter: const int16_t *a+ description: Input polyvec a (4 x 256 x int16_t)+ rdx:+ type: buffer+ size_bytes: 2048+ permissions: read-only+ c_parameter: const int16_t *b+ description: Input polyvec b (4 x 256 x int16_t)+ rcx:+ type: buffer+ size_bytes: 1024+ permissions: read-only+ c_parameter: const int16_t *b_cache+ description: Mulcache for b (4 x 128 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(polyvec_basemul_acc_montgomery_cached_k4_avx2_asm)+MLK_ASM_FN_SYMBOL(polyvec_basemul_acc_montgomery_cached_k4_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0xf301f301, %eax # imm = 0xF301F301+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ vmovdqa (%rsi), %ymm2+ vmovdqa 0x20(%rsi), %ymm3+ vmovdqa (%rdx), %ymm4+ vmovdqa 0x20(%rdx), %ymm5+ vmovdqa (%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa 0x40(%rsi), %ymm2+ vmovdqa 0x60(%rsi), %ymm3+ vmovdqa 0x40(%rdx), %ymm4+ vmovdqa 0x60(%rdx), %ymm5+ vmovdqa 0x20(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm9, 0x60(%rdi)+ vmovdqa 0x80(%rsi), %ymm2+ vmovdqa 0xa0(%rsi), %ymm3+ vmovdqa 0x80(%rdx), %ymm4+ vmovdqa 0xa0(%rdx), %ymm5+ vmovdqa 0x40(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm9, 0xa0(%rdi)+ vmovdqa 0xc0(%rsi), %ymm2+ vmovdqa 0xe0(%rsi), %ymm3+ vmovdqa 0xc0(%rdx), %ymm4+ vmovdqa 0xe0(%rdx), %ymm5+ vmovdqa 0x60(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x100(%rsi), %ymm2+ vmovdqa 0x120(%rsi), %ymm3+ vmovdqa 0x100(%rdx), %ymm4+ vmovdqa 0x120(%rdx), %ymm5+ vmovdqa 0x80(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa 0x140(%rsi), %ymm2+ vmovdqa 0x160(%rsi), %ymm3+ vmovdqa 0x140(%rdx), %ymm4+ vmovdqa 0x160(%rdx), %ymm5+ vmovdqa 0xa0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm9, 0x160(%rdi)+ vmovdqa 0x180(%rsi), %ymm2+ vmovdqa 0x1a0(%rsi), %ymm3+ vmovdqa 0x180(%rdx), %ymm4+ vmovdqa 0x1a0(%rdx), %ymm5+ vmovdqa 0xc0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa 0x1c0(%rsi), %ymm2+ vmovdqa 0x1e0(%rsi), %ymm3+ vmovdqa 0x1c0(%rdx), %ymm4+ vmovdqa 0x1e0(%rdx), %ymm5+ vmovdqa 0xe0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ vmovdqa 0x200(%rsi), %ymm2+ vmovdqa 0x220(%rsi), %ymm3+ vmovdqa 0x200(%rdx), %ymm4+ vmovdqa 0x220(%rdx), %ymm5+ vmovdqa 0x100(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa (%rdi), %ymm8+ vmovdqa 0x20(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa 0x240(%rsi), %ymm2+ vmovdqa 0x260(%rsi), %ymm3+ vmovdqa 0x240(%rdx), %ymm4+ vmovdqa 0x260(%rdx), %ymm5+ vmovdqa 0x120(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x40(%rdi), %ymm8+ vmovdqa 0x60(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm9, 0x60(%rdi)+ vmovdqa 0x280(%rsi), %ymm2+ vmovdqa 0x2a0(%rsi), %ymm3+ vmovdqa 0x280(%rdx), %ymm4+ vmovdqa 0x2a0(%rdx), %ymm5+ vmovdqa 0x140(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm9, 0xa0(%rdi)+ vmovdqa 0x2c0(%rsi), %ymm2+ vmovdqa 0x2e0(%rsi), %ymm3+ vmovdqa 0x2c0(%rdx), %ymm4+ vmovdqa 0x2e0(%rdx), %ymm5+ vmovdqa 0x160(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0xc0(%rdi), %ymm8+ vmovdqa 0xe0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x300(%rsi), %ymm2+ vmovdqa 0x320(%rsi), %ymm3+ vmovdqa 0x300(%rdx), %ymm4+ vmovdqa 0x320(%rdx), %ymm5+ vmovdqa 0x180(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x100(%rdi), %ymm8+ vmovdqa 0x120(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa 0x340(%rsi), %ymm2+ vmovdqa 0x360(%rsi), %ymm3+ vmovdqa 0x340(%rdx), %ymm4+ vmovdqa 0x360(%rdx), %ymm5+ vmovdqa 0x1a0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x140(%rdi), %ymm8+ vmovdqa 0x160(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm9, 0x160(%rdi)+ vmovdqa 0x380(%rsi), %ymm2+ vmovdqa 0x3a0(%rsi), %ymm3+ vmovdqa 0x380(%rdx), %ymm4+ vmovdqa 0x3a0(%rdx), %ymm5+ vmovdqa 0x1c0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa 0x3c0(%rsi), %ymm2+ vmovdqa 0x3e0(%rsi), %ymm3+ vmovdqa 0x3c0(%rdx), %ymm4+ vmovdqa 0x3e0(%rdx), %ymm5+ vmovdqa 0x1e0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x1c0(%rdi), %ymm8+ vmovdqa 0x1e0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ vmovdqa 0x400(%rsi), %ymm2+ vmovdqa 0x420(%rsi), %ymm3+ vmovdqa 0x400(%rdx), %ymm4+ vmovdqa 0x420(%rdx), %ymm5+ vmovdqa 0x200(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa (%rdi), %ymm8+ vmovdqa 0x20(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa 0x440(%rsi), %ymm2+ vmovdqa 0x460(%rsi), %ymm3+ vmovdqa 0x440(%rdx), %ymm4+ vmovdqa 0x460(%rdx), %ymm5+ vmovdqa 0x220(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x40(%rdi), %ymm8+ vmovdqa 0x60(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm9, 0x60(%rdi)+ vmovdqa 0x480(%rsi), %ymm2+ vmovdqa 0x4a0(%rsi), %ymm3+ vmovdqa 0x480(%rdx), %ymm4+ vmovdqa 0x4a0(%rdx), %ymm5+ vmovdqa 0x240(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm9, 0xa0(%rdi)+ vmovdqa 0x4c0(%rsi), %ymm2+ vmovdqa 0x4e0(%rsi), %ymm3+ vmovdqa 0x4c0(%rdx), %ymm4+ vmovdqa 0x4e0(%rdx), %ymm5+ vmovdqa 0x260(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0xc0(%rdi), %ymm8+ vmovdqa 0xe0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x500(%rsi), %ymm2+ vmovdqa 0x520(%rsi), %ymm3+ vmovdqa 0x500(%rdx), %ymm4+ vmovdqa 0x520(%rdx), %ymm5+ vmovdqa 0x280(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x100(%rdi), %ymm8+ vmovdqa 0x120(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa 0x540(%rsi), %ymm2+ vmovdqa 0x560(%rsi), %ymm3+ vmovdqa 0x540(%rdx), %ymm4+ vmovdqa 0x560(%rdx), %ymm5+ vmovdqa 0x2a0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x140(%rdi), %ymm8+ vmovdqa 0x160(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm9, 0x160(%rdi)+ vmovdqa 0x580(%rsi), %ymm2+ vmovdqa 0x5a0(%rsi), %ymm3+ vmovdqa 0x580(%rdx), %ymm4+ vmovdqa 0x5a0(%rdx), %ymm5+ vmovdqa 0x2c0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa 0x5c0(%rsi), %ymm2+ vmovdqa 0x5e0(%rsi), %ymm3+ vmovdqa 0x5c0(%rdx), %ymm4+ vmovdqa 0x5e0(%rdx), %ymm5+ vmovdqa 0x2e0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x1c0(%rdi), %ymm8+ vmovdqa 0x1e0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ vmovdqa 0x600(%rsi), %ymm2+ vmovdqa 0x620(%rsi), %ymm3+ vmovdqa 0x600(%rdx), %ymm4+ vmovdqa 0x620(%rdx), %ymm5+ vmovdqa 0x300(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa (%rdi), %ymm8+ vmovdqa 0x20(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, (%rdi)+ vmovdqa %ymm9, 0x20(%rdi)+ vmovdqa 0x640(%rsi), %ymm2+ vmovdqa 0x660(%rsi), %ymm3+ vmovdqa 0x640(%rdx), %ymm4+ vmovdqa 0x660(%rdx), %ymm5+ vmovdqa 0x320(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x40(%rdi), %ymm8+ vmovdqa 0x60(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x40(%rdi)+ vmovdqa %ymm9, 0x60(%rdi)+ vmovdqa 0x680(%rsi), %ymm2+ vmovdqa 0x6a0(%rsi), %ymm3+ vmovdqa 0x680(%rdx), %ymm4+ vmovdqa 0x6a0(%rdx), %ymm5+ vmovdqa 0x340(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x80(%rdi), %ymm8+ vmovdqa 0xa0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm9, 0xa0(%rdi)+ vmovdqa 0x6c0(%rsi), %ymm2+ vmovdqa 0x6e0(%rsi), %ymm3+ vmovdqa 0x6c0(%rdx), %ymm4+ vmovdqa 0x6e0(%rdx), %ymm5+ vmovdqa 0x360(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0xc0(%rdi), %ymm8+ vmovdqa 0xe0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x700(%rsi), %ymm2+ vmovdqa 0x720(%rsi), %ymm3+ vmovdqa 0x700(%rdx), %ymm4+ vmovdqa 0x720(%rdx), %ymm5+ vmovdqa 0x380(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x100(%rdi), %ymm8+ vmovdqa 0x120(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x100(%rdi)+ vmovdqa %ymm9, 0x120(%rdi)+ vmovdqa 0x740(%rsi), %ymm2+ vmovdqa 0x760(%rsi), %ymm3+ vmovdqa 0x740(%rdx), %ymm4+ vmovdqa 0x760(%rdx), %ymm5+ vmovdqa 0x3a0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x140(%rdi), %ymm8+ vmovdqa 0x160(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x140(%rdi)+ vmovdqa %ymm9, 0x160(%rdi)+ vmovdqa 0x780(%rsi), %ymm2+ vmovdqa 0x7a0(%rsi), %ymm3+ vmovdqa 0x780(%rdx), %ymm4+ vmovdqa 0x7a0(%rdx), %ymm5+ vmovdqa 0x3c0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm8, %ymm13, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x180(%rdi), %ymm8+ vmovdqa 0x1a0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm9, 0x1a0(%rdi)+ vmovdqa 0x7c0(%rsi), %ymm2+ vmovdqa 0x7e0(%rsi), %ymm3+ vmovdqa 0x7c0(%rdx), %ymm4+ vmovdqa 0x7e0(%rdx), %ymm5+ vmovdqa 0x3e0(%rcx), %ymm6+ vpmullw %ymm2, %ymm1, %ymm13+ vpmullw %ymm3, %ymm1, %ymm14+ vpmullw %ymm13, %ymm4, %ymm7+ vpmullw %ymm13, %ymm5, %ymm9+ vpmullw %ymm14, %ymm6, %ymm8+ vpmullw %ymm14, %ymm4, %ymm10+ vpmulhw %ymm7, %ymm0, %ymm7+ vpmulhw %ymm9, %ymm0, %ymm9+ vpmulhw %ymm8, %ymm0, %ymm8+ vpmulhw %ymm10, %ymm0, %ymm10+ vpmulhw %ymm2, %ymm4, %ymm11+ vpmulhw %ymm2, %ymm5, %ymm12+ vpmulhw %ymm3, %ymm6, %ymm13+ vpmulhw %ymm3, %ymm4, %ymm14+ vpsubw %ymm7, %ymm11, %ymm7+ vpsubw %ymm9, %ymm12, %ymm9+ vpsubw %ymm13, %ymm8, %ymm8+ vpsubw %ymm10, %ymm14, %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa 0x1c0(%rdi), %ymm8+ vmovdqa 0x1e0(%rdi), %ymm10+ vpaddw %ymm7, %ymm8, %ymm7+ vpaddw %ymm9, %ymm10, %ymm9+ vmovdqa %ymm7, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(polyvec_basemul_acc_montgomery_cached_k4_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && (MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_K == 4) */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,234 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * This file is derived from the public domain+ * AVX2 Kyber implementation @[REF_AVX2].+ *+ * Changes:+ * - Add call to csub in reduce128_avx to produce outputs+ * in [0,1,...,q-1] rather than [0,1,...,q], matching the+ * semantics of mlk_poly_reduce(),+ * - Use a macro instead of a local function call.+ */++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+/*yaml+ Name: reduce_avx2_asm+ Description: x86_64 AVX2 modular reduction+ Signature: void mlk_reduce_avx2_asm(int16_t *r)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t *r+ description: Input/output polynomial (256 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_reduce_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(reduce_avx2_asm)+MLK_ASM_FN_SYMBOL(reduce_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0x4ebf4ebf, %eax # imm = 0x4EBF4EBF+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ vmovdqa (%rdi), %ymm2+ vmovdqa 0x20(%rdi), %ymm3+ vmovdqa 0x40(%rdi), %ymm4+ vmovdqa 0x60(%rdi), %ymm5+ vmovdqa 0x80(%rdi), %ymm6+ vmovdqa 0xa0(%rdi), %ymm7+ vmovdqa 0xc0(%rdi), %ymm8+ vmovdqa 0xe0(%rdi), %ymm9+ vpmulhw %ymm1, %ymm2, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm2, %ymm2+ vpmulhw %ymm1, %ymm3, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm3, %ymm3+ vpmulhw %ymm1, %ymm4, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm4, %ymm4+ vpmulhw %ymm1, %ymm5, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm5, %ymm5+ vpmulhw %ymm1, %ymm6, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm6, %ymm6+ vpmulhw %ymm1, %ymm7, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm7, %ymm7+ vpmulhw %ymm1, %ymm8, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm8, %ymm8+ vpmulhw %ymm1, %ymm9, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm9, %ymm9+ vpsubw %ymm0, %ymm2, %ymm2+ vpsraw $0xf, %ymm2, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm2, %ymm2+ vpsubw %ymm0, %ymm3, %ymm3+ vpsraw $0xf, %ymm3, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm3, %ymm3+ vpsubw %ymm0, %ymm4, %ymm4+ vpsraw $0xf, %ymm4, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm4, %ymm4+ vpsubw %ymm0, %ymm5, %ymm5+ vpsraw $0xf, %ymm5, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm5, %ymm5+ vpsubw %ymm0, %ymm6, %ymm6+ vpsraw $0xf, %ymm6, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm6, %ymm6+ vpsubw %ymm0, %ymm7, %ymm7+ vpsraw $0xf, %ymm7, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm7, %ymm7+ vpsubw %ymm0, %ymm8, %ymm8+ vpsraw $0xf, %ymm8, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm8, %ymm8+ vpsubw %ymm0, %ymm9, %ymm9+ vpsraw $0xf, %ymm9, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm9, %ymm9+ vmovdqa %ymm2, (%rdi)+ vmovdqa %ymm3, 0x20(%rdi)+ vmovdqa %ymm4, 0x40(%rdi)+ vmovdqa %ymm5, 0x60(%rdi)+ vmovdqa %ymm6, 0x80(%rdi)+ vmovdqa %ymm7, 0xa0(%rdi)+ vmovdqa %ymm8, 0xc0(%rdi)+ vmovdqa %ymm9, 0xe0(%rdi)+ vmovdqa 0x100(%rdi), %ymm2+ vmovdqa 0x120(%rdi), %ymm3+ vmovdqa 0x140(%rdi), %ymm4+ vmovdqa 0x160(%rdi), %ymm5+ vmovdqa 0x180(%rdi), %ymm6+ vmovdqa 0x1a0(%rdi), %ymm7+ vmovdqa 0x1c0(%rdi), %ymm8+ vmovdqa 0x1e0(%rdi), %ymm9+ vpmulhw %ymm1, %ymm2, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm2, %ymm2+ vpmulhw %ymm1, %ymm3, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm3, %ymm3+ vpmulhw %ymm1, %ymm4, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm4, %ymm4+ vpmulhw %ymm1, %ymm5, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm5, %ymm5+ vpmulhw %ymm1, %ymm6, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm6, %ymm6+ vpmulhw %ymm1, %ymm7, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm7, %ymm7+ vpmulhw %ymm1, %ymm8, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm8, %ymm8+ vpmulhw %ymm1, %ymm9, %ymm12+ vpsraw $0xa, %ymm12, %ymm12+ vpmullw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm9, %ymm9+ vpsubw %ymm0, %ymm2, %ymm2+ vpsraw $0xf, %ymm2, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm2, %ymm2+ vpsubw %ymm0, %ymm3, %ymm3+ vpsraw $0xf, %ymm3, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm3, %ymm3+ vpsubw %ymm0, %ymm4, %ymm4+ vpsraw $0xf, %ymm4, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm4, %ymm4+ vpsubw %ymm0, %ymm5, %ymm5+ vpsraw $0xf, %ymm5, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm5, %ymm5+ vpsubw %ymm0, %ymm6, %ymm6+ vpsraw $0xf, %ymm6, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm6, %ymm6+ vpsubw %ymm0, %ymm7, %ymm7+ vpsraw $0xf, %ymm7, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm7, %ymm7+ vpsubw %ymm0, %ymm8, %ymm8+ vpsraw $0xf, %ymm8, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm8, %ymm8+ vpsubw %ymm0, %ymm9, %ymm9+ vpsraw $0xf, %ymm9, %ymm12+ vpand %ymm0, %ymm12, %ymm12+ vpaddw %ymm12, %ymm9, %ymm9+ vmovdqa %ymm2, 0x100(%rdi)+ vmovdqa %ymm3, 0x120(%rdi)+ vmovdqa %ymm4, 0x140(%rdi)+ vmovdqa %ymm5, 0x160(%rdi)+ vmovdqa %ymm6, 0x180(%rdi)+ vmovdqa %ymm7, 0x1a0(%rdi)+ vmovdqa %ymm8, 0x1c0(%rdi)+ vmovdqa %ymm9, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(reduce_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,136 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*************************************************+ * Name: mlk_rej_uniform_avx2_asm+ *+ * Description: Run rejection sampling on uniform random bytes to generate+ * uniform random integers mod q+ *+ * Arguments: - int16_t *r: pointer to output buffer of MLKEM_N+ * 16-bit coefficients.+ * - const uint8_t *buf: pointer to input buffer+ * (assumed to be uniform random bytes)+ * - unsigned buflen: length of input buffer in bytes.+ * Must be a multiple of 12.+ *+ * Returns number of sampled 16-bit integers (at most MLKEM_N).+ **************************************************/+#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+/*yaml+ Name: rej_uniform_avx2_asm+ Description: x86_64 AVX2 rejection sampling+ Signature: uint64_t mlk_rej_uniform_avx2_asm(int16_t *r, const uint8_t *buf, unsigned buflen, const uint8_t *table)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: write-only+ c_parameter: int16_t *r+ description: Output buffer (256 x int16_t)+ rsi:+ type: buffer+ size_bytes: rdx+ permissions: read-only+ c_parameter: const uint8_t *buf+ description: Input buffer+ rdx:+ type: scalar+ c_parameter: unsigned buflen+ description: Length of input buffer (must be multiple of 12)+ test_with: 504 # MLKEM_GEN_MATRIX_NBLOCKS * MLK_XOF_RATE+ rcx:+ type: buffer+ size_bytes: 4096+ permissions: read-only+ c_parameter: const uint8_t *table+ description: Lookup table+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_rej_uniform_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(rej_uniform_avx2_asm)+MLK_ASM_FN_SYMBOL(rej_uniform_avx2_asm)++ .cfi_startproc+ subq $0x210, %rsp # imm = 0x210+ .cfi_adjust_cfa_offset 0x210+ xorl %eax, %eax+ testq %rdx, %rdx+ je Lmlk_rej_uniform_asm_end+ movabsq $0xd010d010d010d01, %rax # imm = 0xD010D010D010D01+ movq %rax, %xmm0+ pinsrq $0x1, %rax, %xmm0+ movabsq $0xfff0fff0fff0fff, %rax # imm = 0xFFF0FFF0FFF0FFF+ movq %rax, %xmm5+ pinsrq $0x1, %rax, %xmm5+ movabsq $0x504040302010100, %rax # imm = 0x504040302010100+ movq %rax, %xmm4+ movabsq $0xb0a0a0908070706, %rax # imm = 0xB0A0A0908070706+ pinsrq $0x1, %rax, %xmm4+ movq $0x0, %rax+ movq $0x0, %r8+ movq $0x5555, %r9 # imm = 0x5555++Lmlk_rej_uniform_asm_loop_start:+ movq (%rsi,%r8), %xmm2+ pinsrd $0x2, 0x8(%rsi,%r8), %xmm2+ pshufb %xmm4, %xmm2+ movdqa %xmm2, %xmm3+ psrlw $0x4, %xmm3+ pblendw $0xaa, %xmm3, %xmm2 # xmm2 = xmm2[0],xmm3[1],xmm2[2],xmm3[3],xmm2[4],xmm3[5],xmm2[6],xmm3[7]+ pand %xmm5, %xmm2+ movdqa %xmm0, %xmm1+ pcmpgtw %xmm2, %xmm1+ pmovmskb %xmm1, %r11d+ pextq %r9, %r11, %r11+ movq %r11, %r10+ shlq $0x4, %r10+ movdqu (%rcx,%r10), %xmm3+ pshufb %xmm3, %xmm2+ movdqu %xmm2, (%rsp,%rax,2)+ popcntq %r11, %r11+ addq %r11, %rax+ cmpq $0x100, %rax # imm = 0x100+ jae Lmlk_rej_uniform_asm_final_copy+ addq $0xc, %r8+ cmpq %r8, %rdx+ ja Lmlk_rej_uniform_asm_loop_start++Lmlk_rej_uniform_asm_final_copy:+ movq $0x100, %rcx # imm = 0x100+ cmpq $0x100, %rax # imm = 0x100+ cmovaq %rcx, %rax+ movq %rsp, %rsi+ movq %rax, %rcx+ shlq %rcx+ rep movsb (%rsi), %es:(%rdi)++Lmlk_rej_uniform_asm_end:+ addq $0x210, %rsp # imm = 0x210+ .cfi_adjust_cfa_offset -0x210+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(rej_uniform_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,172 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [REF_AVX2]+ * CRYSTALS-Kyber optimized AVX2 implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/avx2+ */++/*+ * Implementation from Kyber reference repository @[REF_AVX2]+ *+ * Changes:+ * - Add call to csub in reduce128_avx to produce outputs+ * in [0,1,...,q-1] rather than [0,1,...,q], matching the+ * semantics of mlk_poly_reduce(),+ * - Use a macro instead of a local function call.+ */++#include "../../../common.h"+#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED) && \+ !defined(MLK_CONFIG_NO_KEYPAIR_API)+/*yaml+ Name: tomont_avx2_asm+ Description: x86_64 AVX2 Montgomery conversion+ Signature: void mlk_tomont_avx2_asm(int16_t *r)+ ABI:+ Architecture: x86_64+ CallingConvention: SysV+ Features: [AVX2]+ rdi:+ type: buffer+ size_bytes: 512+ permissions: read/write+ c_parameter: int16_t *r+ description: Input/output polynomial (256 x int16_t)+*/+++/*+ * WARNING: This file is auto-derived from the mlkem-native source file+ * dev/x86_64/src/mlkem_tomont_avx2_asm.S using scripts/simpasm. Do not modify it directly.+ */++.text+.balign 4+.global MLK_ASM_NAMESPACE(tomont_avx2_asm)+MLK_ASM_FN_SYMBOL(tomont_avx2_asm)++ .cfi_startproc+ movl $0xd010d01, %eax # imm = 0xD010D01+ vmovd %eax, %xmm0+ vpbroadcastd %xmm0, %ymm0+ movl $0x50495049, %eax # imm = 0x50495049+ vmovd %eax, %xmm1+ vpbroadcastd %xmm1, %ymm1+ movl $0x5490549, %eax # imm = 0x5490549+ vmovd %eax, %xmm2+ vpbroadcastd %xmm2, %ymm2+ vmovdqa (%rdi), %ymm3+ vmovdqa 0x20(%rdi), %ymm4+ vmovdqa 0x40(%rdi), %ymm5+ vmovdqa 0x60(%rdi), %ymm6+ vmovdqa 0x80(%rdi), %ymm7+ vmovdqa 0xa0(%rdi), %ymm8+ vmovdqa 0xc0(%rdi), %ymm9+ vmovdqa 0xe0(%rdi), %ymm10+ vpmullw %ymm1, %ymm3, %ymm11+ vpmulhw %ymm2, %ymm3, %ymm3+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm11, %ymm3, %ymm3+ vpmullw %ymm1, %ymm4, %ymm12+ vpmulhw %ymm2, %ymm4, %ymm4+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm4, %ymm4+ vpmullw %ymm1, %ymm5, %ymm13+ vpmulhw %ymm2, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm13, %ymm13+ vpsubw %ymm13, %ymm5, %ymm5+ vpmullw %ymm1, %ymm6, %ymm14+ vpmulhw %ymm2, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm14, %ymm14+ vpsubw %ymm14, %ymm6, %ymm6+ vpmullw %ymm1, %ymm7, %ymm15+ vpmulhw %ymm2, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm15, %ymm15+ vpsubw %ymm15, %ymm7, %ymm7+ vpmullw %ymm1, %ymm8, %ymm11+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm11, %ymm8, %ymm8+ vpmullw %ymm1, %ymm9, %ymm12+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm9, %ymm9+ vpmullw %ymm1, %ymm10, %ymm13+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm13, %ymm13+ vpsubw %ymm13, %ymm10, %ymm10+ vmovdqa %ymm3, (%rdi)+ vmovdqa %ymm4, 0x20(%rdi)+ vmovdqa %ymm5, 0x40(%rdi)+ vmovdqa %ymm6, 0x60(%rdi)+ vmovdqa %ymm7, 0x80(%rdi)+ vmovdqa %ymm8, 0xa0(%rdi)+ vmovdqa %ymm9, 0xc0(%rdi)+ vmovdqa %ymm10, 0xe0(%rdi)+ vmovdqa 0x100(%rdi), %ymm3+ vmovdqa 0x120(%rdi), %ymm4+ vmovdqa 0x140(%rdi), %ymm5+ vmovdqa 0x160(%rdi), %ymm6+ vmovdqa 0x180(%rdi), %ymm7+ vmovdqa 0x1a0(%rdi), %ymm8+ vmovdqa 0x1c0(%rdi), %ymm9+ vmovdqa 0x1e0(%rdi), %ymm10+ vpmullw %ymm1, %ymm3, %ymm11+ vpmulhw %ymm2, %ymm3, %ymm3+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm11, %ymm3, %ymm3+ vpmullw %ymm1, %ymm4, %ymm12+ vpmulhw %ymm2, %ymm4, %ymm4+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm4, %ymm4+ vpmullw %ymm1, %ymm5, %ymm13+ vpmulhw %ymm2, %ymm5, %ymm5+ vpmulhw %ymm0, %ymm13, %ymm13+ vpsubw %ymm13, %ymm5, %ymm5+ vpmullw %ymm1, %ymm6, %ymm14+ vpmulhw %ymm2, %ymm6, %ymm6+ vpmulhw %ymm0, %ymm14, %ymm14+ vpsubw %ymm14, %ymm6, %ymm6+ vpmullw %ymm1, %ymm7, %ymm15+ vpmulhw %ymm2, %ymm7, %ymm7+ vpmulhw %ymm0, %ymm15, %ymm15+ vpsubw %ymm15, %ymm7, %ymm7+ vpmullw %ymm1, %ymm8, %ymm11+ vpmulhw %ymm2, %ymm8, %ymm8+ vpmulhw %ymm0, %ymm11, %ymm11+ vpsubw %ymm11, %ymm8, %ymm8+ vpmullw %ymm1, %ymm9, %ymm12+ vpmulhw %ymm2, %ymm9, %ymm9+ vpmulhw %ymm0, %ymm12, %ymm12+ vpsubw %ymm12, %ymm9, %ymm9+ vpmullw %ymm1, %ymm10, %ymm13+ vpmulhw %ymm2, %ymm10, %ymm10+ vpmulhw %ymm0, %ymm13, %ymm13+ vpsubw %ymm13, %ymm10, %ymm10+ vmovdqa %ymm3, 0x100(%rdi)+ vmovdqa %ymm4, 0x120(%rdi)+ vmovdqa %ymm5, 0x140(%rdi)+ vmovdqa %ymm6, 0x160(%rdi)+ vmovdqa %ymm7, 0x180(%rdi)+ vmovdqa %ymm8, 0x1a0(%rdi)+ vmovdqa %ymm9, 0x1c0(%rdi)+ vmovdqa %ymm10, 0x1e0(%rdi)+ retq+ .cfi_endproc++MLK_ASM_FN_SIZE(tomont_avx2_asm)++#endif /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ && !MLK_CONFIG_NO_KEYPAIR_API */++#if defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,545 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */++#include "../../../common.h"++#if defined(MLK_ARITH_BACKEND_X86_64_DEFAULT) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#include "arith_native_x86_64.h"++/*+ * Lookup table used by rejection sampling of the public matrix.+ * See autogen for details.+ */+MLK_ALIGN MLK_INTERNAL_DATA_DEFINITION const uint8_t+ mlk_rej_uniform_table[4096] = {+ 255, 255, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */,+ 0, 1, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */,+ 2, 3, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */,+ 0, 1, 2, 3, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */,+ 4, 5, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */,+ 0, 1, 4, 5, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */,+ 2, 3, 4, 5, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */,+ 0, 1, 2, 3, 4, 5, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */,+ 6, 7, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */,+ 0, 1, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */,+ 2, 3, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */,+ 0, 1, 2, 3, 6, 7, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */,+ 4, 5, 6, 7, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */,+ 0, 1, 4, 5, 6, 7, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */,+ 2, 3, 4, 5, 6, 7, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */,+ 8, 9, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */,+ 0, 1, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */,+ 2, 3, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */,+ 0, 1, 2, 3, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */,+ 4, 5, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */,+ 0, 1, 4, 5, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */,+ 2, 3, 4, 5, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */,+ 6, 7, 8, 9, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */,+ 0, 1, 6, 7, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */,+ 2, 3, 6, 7, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */,+ 4, 5, 6, 7, 8, 9, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */,+ 10, 11, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */,+ 0, 1, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */,+ 2, 3, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */,+ 0, 1, 2, 3, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */,+ 4, 5, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */,+ 0, 1, 4, 5, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */,+ 2, 3, 4, 5, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */,+ 6, 7, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */,+ 0, 1, 6, 7, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */,+ 2, 3, 6, 7, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */,+ 4, 5, 6, 7, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */,+ 8, 9, 10, 11, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */,+ 0, 1, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */,+ 2, 3, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */,+ 4, 5, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */,+ 6, 7, 8, 9, 10, 11, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */,+ 12, 13, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */,+ 0, 1, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */,+ 2, 3, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */,+ 0, 1, 2, 3, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */,+ 4, 5, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */,+ 0, 1, 4, 5, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */,+ 2, 3, 4, 5, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */,+ 0, 1, 2, 3, 4, 5, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */,+ 6, 7, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */,+ 0, 1, 6, 7, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */,+ 2, 3, 6, 7, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */,+ 0, 1, 2, 3, 6, 7, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */,+ 4, 5, 6, 7, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */,+ 0, 1, 4, 5, 6, 7, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */,+ 2, 3, 4, 5, 6, 7, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */,+ 8, 9, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */,+ 0, 1, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */,+ 2, 3, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */,+ 0, 1, 2, 3, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */,+ 4, 5, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */,+ 0, 1, 4, 5, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */,+ 2, 3, 4, 5, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */,+ 6, 7, 8, 9, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */,+ 0, 1, 6, 7, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */,+ 2, 3, 6, 7, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */,+ 4, 5, 6, 7, 8, 9, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */,+ 10, 11, 12, 13, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */,+ 0, 1, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */,+ 2, 3, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */,+ 0, 1, 2, 3, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */,+ 4, 5, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */,+ 0, 1, 4, 5, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */,+ 2, 3, 4, 5, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */,+ 6, 7, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */,+ 0, 1, 6, 7, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */,+ 2, 3, 6, 7, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */,+ 4, 5, 6, 7, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */,+ 8, 9, 10, 11, 12, 13, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */,+ 0, 1, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */,+ 2, 3, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */,+ 4, 5, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */,+ 6, 7, 8, 9, 10, 11, 12, 13,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */,+ 14, 15, 255, 255, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */,+ 0, 1, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */,+ 2, 3, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */,+ 0, 1, 2, 3, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */,+ 4, 5, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */,+ 0, 1, 4, 5, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */,+ 2, 3, 4, 5, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */,+ 0, 1, 2, 3, 4, 5, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */,+ 6, 7, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */,+ 0, 1, 6, 7, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */,+ 2, 3, 6, 7, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */,+ 0, 1, 2, 3, 6, 7, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */,+ 4, 5, 6, 7, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */,+ 0, 1, 4, 5, 6, 7, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */,+ 2, 3, 4, 5, 6, 7, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */,+ 8, 9, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */,+ 0, 1, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */,+ 2, 3, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */,+ 0, 1, 2, 3, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */,+ 4, 5, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */,+ 0, 1, 4, 5, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */,+ 2, 3, 4, 5, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */,+ 6, 7, 8, 9, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */,+ 0, 1, 6, 7, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */,+ 2, 3, 6, 7, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */,+ 4, 5, 6, 7, 8, 9, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */,+ 10, 11, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */,+ 0, 1, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */,+ 2, 3, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */,+ 0, 1, 2, 3, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */,+ 4, 5, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */,+ 0, 1, 4, 5, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */,+ 2, 3, 4, 5, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */,+ 6, 7, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */,+ 0, 1, 6, 7, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */,+ 2, 3, 6, 7, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */,+ 4, 5, 6, 7, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */,+ 8, 9, 10, 11, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */,+ 0, 1, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */,+ 2, 3, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */,+ 4, 5, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */,+ 6, 7, 8, 9, 10, 11, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */,+ 12, 13, 14, 15, 255, 255, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */,+ 0, 1, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */,+ 2, 3, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */,+ 0, 1, 2, 3, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */,+ 4, 5, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */,+ 0, 1, 4, 5, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */,+ 2, 3, 4, 5, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */,+ 0, 1, 2, 3, 4, 5, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */,+ 6, 7, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */,+ 0, 1, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */,+ 2, 3, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */,+ 0, 1, 2, 3, 6, 7, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */,+ 4, 5, 6, 7, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */,+ 0, 1, 4, 5, 6, 7, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */,+ 2, 3, 4, 5, 6, 7, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */,+ 8, 9, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */,+ 0, 1, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */,+ 2, 3, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */,+ 0, 1, 2, 3, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */,+ 4, 5, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */,+ 0, 1, 4, 5, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */,+ 2, 3, 4, 5, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */,+ 6, 7, 8, 9, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */,+ 0, 1, 6, 7, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */,+ 2, 3, 6, 7, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */,+ 4, 5, 6, 7, 8, 9, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */,+ 10, 11, 12, 13, 14, 15, 255, 255,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */,+ 0, 1, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */,+ 2, 3, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */,+ 0, 1, 2, 3, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */,+ 4, 5, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */,+ 0, 1, 4, 5, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */,+ 2, 3, 4, 5, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */,+ 0, 1, 2, 3, 4, 5, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */,+ 6, 7, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */,+ 0, 1, 6, 7, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */,+ 2, 3, 6, 7, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */,+ 0, 1, 2, 3, 6, 7, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */,+ 4, 5, 6, 7, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */,+ 0, 1, 4, 5, 6, 7, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */,+ 2, 3, 4, 5, 6, 7, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */,+ 8, 9, 10, 11, 12, 13, 14, 15,+ 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */,+ 0, 1, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */,+ 2, 3, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */,+ 0, 1, 2, 3, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */,+ 4, 5, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */,+ 0, 1, 4, 5, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */,+ 2, 3, 4, 5, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */,+ 0, 1, 2, 3, 4, 5, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */,+ 6, 7, 8, 9, 10, 11, 12, 13,+ 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */,+ 0, 1, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */,+ 2, 3, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */,+ 0, 1, 2, 3, 6, 7, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */,+ 4, 5, 6, 7, 8, 9, 10, 11,+ 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */,+ 0, 1, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */,+ 2, 3, 4, 5, 6, 7, 8, 9,+ 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */,+ 0, 1, 2, 3, 4, 5, 6, 7,+ 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */,+};++#else /* MLK_ARITH_BACKEND_X86_64_DEFAULT && !MLK_CONFIG_MULTILEVEL_NO_SHARED \+ */++MLK_EMPTY_CU(avx2_rej_uniform_table)++#endif /* !(MLK_ARITH_BACKEND_X86_64_DEFAULT && \+ !MLK_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,76 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_PARAMS_H+#define MLK_PARAMS_H++#if !defined(MLK_CONFIG_PARAMETER_SET)+#error MLK_CONFIG_PARAMETER_SET is not defined+#endif++#if MLK_CONFIG_PARAMETER_SET == 512+#define MLKEM_K 2+#elif MLK_CONFIG_PARAMETER_SET == 768+#define MLKEM_K 3+#elif MLK_CONFIG_PARAMETER_SET == 1024+#define MLKEM_K 4+#else+#error Invalid value for MLK_CONFIG_PARAMETER_SET. Must be 512, 768, or 1024.+#endif++#define MLKEM_N 256+#define MLKEM_Q 3329+#define MLKEM_Q_HALF ((MLKEM_Q + 1) / 2) /* 1665 */+#define MLKEM_UINT12_LIMIT 4096++#define MLKEM_SYMBYTES 32 /* size in bytes of hashes, and seeds */+#define MLKEM_SSBYTES 32 /* size in bytes of shared key */++#define MLKEM_POLYBYTES 384+#define MLKEM_POLYVECBYTES (MLKEM_K * MLKEM_POLYBYTES)++#define MLKEM_POLYCOMPRESSEDBYTES_D4 128+#define MLKEM_POLYCOMPRESSEDBYTES_D5 160+#define MLKEM_POLYCOMPRESSEDBYTES_D10 320+#define MLKEM_POLYCOMPRESSEDBYTES_D11 352++#if MLKEM_K == 2+#define MLKEM_ETA1 3+#define MLKEM_DU 10+#define MLKEM_DV 4+#define MLKEM_POLYCOMPRESSEDBYTES_DV MLKEM_POLYCOMPRESSEDBYTES_D4+#define MLKEM_POLYCOMPRESSEDBYTES_DU MLKEM_POLYCOMPRESSEDBYTES_D10+#define MLKEM_POLYVECCOMPRESSEDBYTES_DU (MLKEM_K * MLKEM_POLYCOMPRESSEDBYTES_DU)+#elif MLKEM_K == 3+#define MLKEM_ETA1 2+#define MLKEM_DU 10+#define MLKEM_DV 4+#define MLKEM_POLYCOMPRESSEDBYTES_DV MLKEM_POLYCOMPRESSEDBYTES_D4+#define MLKEM_POLYCOMPRESSEDBYTES_DU MLKEM_POLYCOMPRESSEDBYTES_D10+#define MLKEM_POLYVECCOMPRESSEDBYTES_DU (MLKEM_K * MLKEM_POLYCOMPRESSEDBYTES_DU)+#elif MLKEM_K == 4+#define MLKEM_ETA1 2+#define MLKEM_DU 11+#define MLKEM_DV 5+#define MLKEM_POLYCOMPRESSEDBYTES_DV MLKEM_POLYCOMPRESSEDBYTES_D5+#define MLKEM_POLYCOMPRESSEDBYTES_DU MLKEM_POLYCOMPRESSEDBYTES_D11+#define MLKEM_POLYVECCOMPRESSEDBYTES_DU (MLKEM_K * MLKEM_POLYCOMPRESSEDBYTES_DU)+#endif /* MLKEM_K == 4 */++#define MLKEM_ETA2 2++#define MLKEM_INDCPA_MSGBYTES (MLKEM_SYMBYTES)+#define MLKEM_INDCPA_PUBLICKEYBYTES (MLKEM_POLYVECBYTES + MLKEM_SYMBYTES)+#define MLKEM_INDCPA_SECRETKEYBYTES (MLKEM_POLYVECBYTES)+#define MLKEM_INDCPA_BYTES \+ (MLKEM_POLYVECCOMPRESSEDBYTES_DU + MLKEM_POLYCOMPRESSEDBYTES_DV)++#define MLKEM_INDCCA_PUBLICKEYBYTES (MLKEM_INDCPA_PUBLICKEYBYTES)+/* 32 bytes of additional space to save H(pk) */+#define MLKEM_INDCCA_SECRETKEYBYTES \+ (MLKEM_INDCPA_SECRETKEYBYTES + MLKEM_INDCPA_PUBLICKEYBYTES + \+ 2 * MLKEM_SYMBYTES)+#define MLKEM_INDCCA_CIPHERTEXTBYTES (MLKEM_INDCPA_BYTES)++#endif /* !MLK_PARAMS_H */
@@ -0,0 +1,581 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [NeonNTT]+ * Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1+ * Becker, Hwang, Kannwischer, Yang, Yang+ * https://eprint.iacr.org/2021/986+ *+ * - [REF]+ * CRYSTALS-Kyber C reference implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/ref+ */++#include "common.h"+#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+++#include "cbmc.h"+#include "debug.h"+#include "poly.h"+#include "sampling.h"+#include "symmetric.h"+#include "verify.h"++/**+ * Montgomery multiplication modulo MLKEM_Q.+ *+ * @reference{`fqmul()` in the reference implementation @[REF].}+ *+ * @param a First factor. Can be any int16_t.+ * @param b Second factor. Must be signed canonical+ * (abs value < (MLKEM_Q+1)/2).+ *+ * @return 16-bit integer congruent to a*b*R^{-1} mod MLKEM_Q, and+ * smaller than MLKEM_Q in absolute value.+ */+static MLK_INLINE int16_t mlk_fqmul(int16_t a, int16_t b)+__contract__(+ requires(b > -MLKEM_Q_HALF && b < MLKEM_Q_HALF)+ ensures(return_value > -MLKEM_Q && return_value < MLKEM_Q)+)+{+ int16_t res;+ mlk_assert_abs_bound(&b, 1, MLKEM_Q_HALF);++ res = mlk_montgomery_reduce((int32_t)a * (int32_t)b);+ /* Bounds:+ * |res| <= ceil(|a| * |b| / 2^16) + (MLKEM_Q + 1) / 2+ * <= ceil(2^15 * ((MLKEM_Q - 1)/2) / 2^16) + (MLKEM_Q + 1) / 2+ * <= ceil((MLKEM_Q - 1) / 4) + (MLKEM_Q + 1) / 2+ * < MLKEM_Q+ */++ mlk_assert_abs_bound(&res, 1, MLKEM_Q);+ return res;+}++/**+ * Barrett reduction; given a 16-bit integer a, computes the centered+ * representative congruent to a mod MLKEM_Q in [-(MLKEM_Q-1)/2, (MLKEM_Q-1)/2].+ *+ * @reference{`barrett_reduce()` in the reference implementation @[REF].}+ *+ * @param a Input integer to be reduced.+ *+ * @return Integer in [-(MLKEM_Q-1)/2, (MLKEM_Q-1)/2] congruent to @p a modulo+ * MLKEM_Q.+ */+static MLK_INLINE int16_t mlk_barrett_reduce(int16_t a)+__contract__(+ ensures(return_value > -MLKEM_Q_HALF && return_value < MLKEM_Q_HALF)+)+{+ /* Barrett reduction approximates+ * ```+ * round(a/MLKEM_Q)+ * = round(a*(2^N/MLKEM_Q))/2^N)+ * ~= round(a*round(2^N/MLKEM_Q)/2^N)+ * ```+ * Here, we pick N=26.+ */+ const int32_t magic = 20159; /* check-magic: 20159 == round(2^26 / MLKEM_Q) */++ /*+ * PORTABILITY: Right-shift on a signed integer is+ * implementation-defined for negative left argument.+ * Here, we assume it's sign-preserving "arithmetic" shift right.+ * See (C99 6.5.7 (5))+ */+ const int32_t t = (magic * a + ((int32_t)1 << 25)) >> 26;++ /*+ * t is in -10 .. +10, so we need 32-bit math to+ * evaluate t * MLKEM_Q and the subsequent subtraction+ */+ int16_t res = (int16_t)(a - t * MLKEM_Q);++ mlk_assert_abs_bound(&res, 1, MLKEM_Q_HALF);+ return res;+}++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+/* Reference: `poly_tomont()` in the reference implementation @[REF]. */+MLK_STATIC_TESTABLE void mlk_poly_tomont_c(mlk_poly *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_abs_bound(r->coeffs, 0, MLKEM_N, MLKEM_Q))+)+{+ unsigned i;+ const int16_t f = 1353; /* check-magic: 1353 == signed_mod(2^32, MLKEM_Q) */+ for (i = 0; i < MLKEM_N; i++)+ __loop__(+ invariant(i <= MLKEM_N)+ invariant(array_abs_bound(r->coeffs, 0, i, MLKEM_Q))+ decreases(MLKEM_N - i))+ {+ r->coeffs[i] = mlk_fqmul(r->coeffs[i], f);+ }++ mlk_assert_abs_bound(r, MLKEM_N, MLKEM_Q);+}++MLK_INTERNAL_API+void mlk_poly_tomont(mlk_poly *r)+{+#if defined(MLK_USE_NATIVE_POLY_TOMONT)+ int ret;+ ret = mlk_poly_tomont_native(r->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ mlk_assert_abs_bound(r, MLKEM_N, MLKEM_Q);+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_TOMONT */++ mlk_poly_tomont_c(r);+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++/**+ * Constant-time conversion of signed representatives modulo MLKEM_Q within+ * range [-(MLKEM_Q-1), MLKEM_Q-1] into unsigned representatives within+ * range [0, MLKEM_Q-1].+ *+ * @reference{Not present in the reference implementation @[REF]. Used here+ * to implement different semantics of `poly_reduce()`; see below. In the+ * reference implementation @[REF] this logic is part of all compression+ * functions (see `compress.c`).}+ *+ * @param c Signed coefficient to be converted.+ *+ * @return Unsigned representative in [0, MLKEM_Q).+ */+static MLK_INLINE int16_t mlk_scalar_signed_to_unsigned_q(int16_t c)+__contract__(+ requires(c > -MLKEM_Q && c < MLKEM_Q)+ ensures(return_value >= 0 && return_value < MLKEM_Q)+ ensures(return_value == (int32_t)c + (((int32_t)c < 0) * MLKEM_Q)))+{+ mlk_assert_abs_bound(&c, 1, MLKEM_Q);++ /* Add MLKEM_Q if c is negative, but in constant time.+ *+ * Note that c + MLKEM_Q does not overflow in int16_t,+ * so the cast to uint16_t is safe. */+ c = mlk_ct_sel_int16((int16_t)(c + MLKEM_Q), c, mlk_ct_cmask_neg_i16(c));++ mlk_assert_bound(&c, 1, 0, MLKEM_Q);+ return c;+}++/* Reference: `poly_reduce()` in the reference implementation @[REF]+ * - We use _unsigned_ canonical outputs, while the reference+ * implementation uses _signed_ canonical outputs.+ * Accordingly, we need a conditional addition of MLKEM_Q+ * here to go from signed to unsigned representatives.+ * This conditional addition is then dropped from all+ * polynomial compression functions instead (see `compress.c`). */+MLK_STATIC_TESTABLE void mlk_poly_reduce_c(mlk_poly *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+)+{+ unsigned i;++ for (i = 0; i < MLKEM_N; i++)+ __loop__(+ invariant(i <= MLKEM_N)+ invariant(array_bound(r->coeffs, 0, i, 0, MLKEM_Q))+ decreases(MLKEM_N - i))+ {+ /* Barrett reduction, giving signed canonical representative */+ int16_t t = mlk_barrett_reduce(r->coeffs[i]);+ /* Conditional addition to get unsigned canonical representative */+ r->coeffs[i] = mlk_scalar_signed_to_unsigned_q(t);+ }++ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+}++MLK_INTERNAL_API+void mlk_poly_reduce(mlk_poly *r)+{+#if defined(MLK_USE_NATIVE_POLY_REDUCE)+ int ret;+ ret = mlk_poly_reduce_native(r->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ mlk_assert_bound(r, MLKEM_N, 0, MLKEM_Q);+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_REDUCE */++ mlk_poly_reduce_c(r);+}++/* Reference: `poly_add()` in the reference implementation @[REF].+ * - We use destructive version (output=first input) to avoid+ * reasoning about aliasing in the CBMC specification */+MLK_INTERNAL_API+void mlk_poly_add(mlk_poly *r, const mlk_poly *b)+{+ unsigned i;+ for (i = 0; i < MLKEM_N; i++)+ __loop__(+ invariant(i <= MLKEM_N)+ invariant(forall(k0, i, MLKEM_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0]))+ invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1]))+ decreases(MLKEM_N - i))+ {+ /* The preconditions imply that the addition stays within int16_t. */+ r->coeffs[i] = (int16_t)(r->coeffs[i] + b->coeffs[i]);+ }+}++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `poly_sub()` in the reference implementation @[REF].+ * - We use destructive version (output=first input) to avoid+ * reasoning about aliasing in the CBMC specification */+MLK_INTERNAL_API+void mlk_poly_sub(mlk_poly *r, const mlk_poly *b)+{+ unsigned i;+ for (i = 0; i < MLKEM_N; i++)+ __loop__(+ invariant(i <= MLKEM_N)+ invariant(forall(k0, i, MLKEM_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0]))+ invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] - b->coeffs[k1]))+ decreases(MLKEM_N - i))+ {+ /* The preconditions imply that the subtraction stays within int16_t. */+ r->coeffs[i] = (int16_t)(r->coeffs[i] - b->coeffs[i]);+ }+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#include "zetas.inc"++/* Reference: Does not exist in the reference implementation @[REF].+ * - The reference implementation does not use a+ * multiplication cache ('mulcache'). This idea originates+ * from @[NeonNTT] and is used at the C level here. */+MLK_STATIC_TESTABLE void mlk_poly_mulcache_compute_c(mlk_poly_mulcache *x,+ const mlk_poly *a)+__contract__(+ requires(memory_no_alias(x, sizeof(mlk_poly_mulcache)))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ assigns(memory_slice(x, sizeof(mlk_poly_mulcache)))+)+{+ unsigned i;+ for (i = 0; i < MLKEM_N / 4; i++)+ __loop__(+ invariant(i <= MLKEM_N / 4)+ invariant(array_abs_bound(x->coeffs, 0, 2 * i, MLKEM_Q))+ decreases(MLKEM_N / 4 - i))+ {+ x->coeffs[2 * i + 0] = mlk_fqmul(a->coeffs[4 * i + 1], mlk_zetas[64 + i]);+ /* The values in zeta table are <= MLKEM_Q in absolute value,+ * so the negation in int16_t is safe. */+ x->coeffs[2 * i + 1] =+ mlk_fqmul(a->coeffs[4 * i + 3], (int16_t)(-mlk_zetas[64 + i]));+ }++ /*+ * This bound is true for the C implementation, but not needed+ * in the higher level bounds reasoning. It is thus omitted+ * from the spec to not unnecessarily constrain native+ * implementations, but checked here nonetheless.+ */+ mlk_assert_abs_bound(x, MLKEM_N / 2, MLKEM_Q);+}++MLK_INTERNAL_API+void mlk_poly_mulcache_compute(mlk_poly_mulcache *x, const mlk_poly *a)+{+#if defined(MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE)+ int ret;+ ret = mlk_poly_mulcache_compute_native(x->coeffs, a->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+#endif /* MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE */++ mlk_poly_mulcache_compute_c(x, a);+}++/*+ * Computes a block CT butterflies with a fixed twiddle factor,+ * using Montgomery multiplication.+ * Parameters:+ * - r: Pointer to base of polynomial (_not_ the base of butterfly block)+ * - root: Twiddle factor to use for the butterfly. This must be in+ * Montgomery form and signed canonical.+ * - start: Offset to the beginning of the butterfly block+ * - len: Index difference between coefficients subject to a butterfly+ * - bound: Ghost variable describing coefficient bound: Prior to `start`,+ * coefficients must be bound by `bound + MLKEM_Q`. Post `start`,+ * they must be bound by `bound`.+ * When this function returns, output coefficients in the index range+ * [start, start+2*len) have bound bumped to `bound + MLKEM_Q`.+ * Example:+ * - start=8, len=4+ * This would compute the following four butterflies+ * 8 -- 12+ * 9 -- 13+ * 10 -- 14+ * 11 -- 15+ * - start=4, len=2+ * This would compute the following two butterflies+ * 4 -- 6+ * 5 -- 7+ */++/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */+static void mlk_ntt_butterfly_block(int16_t r[MLKEM_N], int16_t zeta,+ unsigned start, unsigned len,+ unsigned bound)+__contract__(+ requires(start < MLKEM_N)+ requires(1 <= len && len <= MLKEM_N / 2 && start + 2 * len <= MLKEM_N)+ requires(0 <= bound && bound < INT16_MAX - MLKEM_Q)+ requires(-MLKEM_Q_HALF < zeta && zeta < MLKEM_Q_HALF)+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(array_abs_bound(r, 0, start, bound + MLKEM_Q))+ requires(array_abs_bound(r, start, MLKEM_N, bound))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_abs_bound(r, 0, start + 2*len, bound + MLKEM_Q))+ ensures(array_abs_bound(r, start + 2 * len, MLKEM_N, bound)))+{+ /* `bound` is a ghost variable only needed in the CBMC specification */+ unsigned j;+ ((void)bound);+ for (j = start; j < start + len; j++)+ __loop__(+ invariant(start <= j && j <= start + len)+ /*+ * Coefficients are updated in strided pairs, so the bounds for the+ * intermediate states alternate twice between the old and new bound+ */+ invariant(array_abs_bound(r, 0, j, bound + MLKEM_Q))+ invariant(array_abs_bound(r, j, start + len, bound))+ invariant(array_abs_bound(r, start + len, j + len, bound + MLKEM_Q))+ invariant(array_abs_bound(r, j + len, MLKEM_N, bound))+ decreases(start + len - j))+ {+ int16_t t;+ t = mlk_fqmul(r[j + len], zeta);+ /* The precondition implies that the arithmetic does not overflow. */+ r[j + len] = (int16_t)(r[j] - t);+ r[j] = (int16_t)(r[j] + t);+ }+}++/*+ * Compute one layer of forward NTT+ * Parameters:+ * - r: Pointer to base of polynomial+ * - layer: Variable indicating which layer is being applied.+ */++/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */+static void mlk_ntt_layer(int16_t r[MLKEM_N], unsigned layer)+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(1 <= layer && layer <= 7)+ requires(array_abs_bound(r, 0, MLKEM_N, layer * MLKEM_Q))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_abs_bound(r, 0, MLKEM_N, (layer + 1) * MLKEM_Q)))+{+ unsigned start, k, len;+ /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */+ k = 1u << (layer - 1);+ len = (unsigned)MLKEM_N >> layer;+ for (start = 0; start < MLKEM_N; start += 2 * len)+ __loop__(+ invariant(start < MLKEM_N + 2 * len)+ invariant(k <= MLKEM_N / 2 && 2 * len * k == start + MLKEM_N)+ invariant(array_abs_bound(r, 0, start, layer * MLKEM_Q + MLKEM_Q))+ invariant(array_abs_bound(r, start, MLKEM_N, layer * MLKEM_Q))+ decreases(MLKEM_N - start))+ {+ int16_t zeta = mlk_zetas[k++];+ mlk_ntt_butterfly_block(r, zeta, start, len, layer * MLKEM_Q);+ }+}++/*+ * Compute full forward NTT+ * NOTE: This particular implementation satisfies a much tighter+ * bound on the output coefficients (5*q) than the contractual one (8*q),+ * but this is not needed in the calling code. Should we change the+ * base multiplication strategy to require smaller NTT output bounds,+ * the proof may need strengthening.+ */++/* Reference: `ntt()` in the reference implementation @[REF].+ * - Iterate over `layer` instead of `len` in the outer loop+ * to simplify computation of zeta index. */+MLK_STATIC_TESTABLE void mlk_poly_ntt_c(mlk_poly *p)+__contract__(+ requires(memory_no_alias(p, sizeof(mlk_poly)))+ requires(array_abs_bound(p->coeffs, 0, MLKEM_N, MLKEM_Q))+ assigns(memory_slice(p, sizeof(mlk_poly)))+ ensures(array_abs_bound(p->coeffs, 0, MLKEM_N, MLK_NTT_BOUND))+)+{+ unsigned layer;+ int16_t *r;++ mlk_assert_abs_bound(p, MLKEM_N, MLKEM_Q);++ r = p->coeffs;++ for (layer = 1; layer <= 7; layer++)+ __loop__(+ invariant(1 <= layer && layer <= 8)+ invariant(array_abs_bound(r, 0, MLKEM_N, layer * MLKEM_Q))+ decreases(8 - layer))+ {+ mlk_ntt_layer(r, layer);+ }++ /* Check the stronger bound */+ mlk_assert_abs_bound(p, MLKEM_N, MLK_NTT_BOUND);+}++MLK_INTERNAL_API+void mlk_poly_ntt(mlk_poly *r)+{+#if defined(MLK_USE_NATIVE_NTT)+ int ret;+ mlk_assert_abs_bound(r, MLKEM_N, MLKEM_Q);+ ret = mlk_ntt_native(r->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ mlk_assert_abs_bound(r, MLKEM_N, MLK_NTT_BOUND);+ return;+ }+#endif /* MLK_USE_NATIVE_NTT */++ mlk_poly_ntt_c(r);+}+++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+/* Compute one layer of inverse NTT */++/* Reference: Embedded into `invntt()` in the reference implementation @[REF] */+static void mlk_invntt_layer(int16_t *r, unsigned layer)+__contract__(+ requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N))+ requires(1 <= layer && layer <= 7)+ requires(array_abs_bound(r, 0, MLKEM_N, MLKEM_Q))+ assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N))+ ensures(array_abs_bound(r, 0, MLKEM_N, MLKEM_Q)))+{+ unsigned start, k, len;+ len = (unsigned)MLKEM_N >> layer;+ k = (1u << layer) - 1;+ for (start = 0; start < MLKEM_N; start += 2 * len)+ __loop__(+ invariant(array_abs_bound(r, 0, MLKEM_N, MLKEM_Q))+ invariant(start <= MLKEM_N && k <= 127)+ /* Normalised form of k == MLKEM_N / len - 1 - start / (2 * len) */+ invariant(2 * len * k + start == 2 * MLKEM_N - 2 * len)+ decreases(MLKEM_N - start))+ {+ unsigned j;+ int16_t zeta = mlk_zetas[k--];+ for (j = start; j < start + len; j++)+ __loop__(+ invariant(start <= j && j <= start + len)+ invariant(start <= MLKEM_N && k <= 127)+ invariant(array_abs_bound(r, 0, MLKEM_N, MLKEM_Q))+ decreases(start + len - j))+ {+ int16_t t = r[j];+ /* The preconditions imply that the arithmetic does not overflow. */+ r[j] = mlk_barrett_reduce((int16_t)(t + r[j + len]));+ r[j + len] = (int16_t)(r[j + len] - t);+ r[j + len] = mlk_fqmul(r[j + len], zeta);+ }+ }+}++/* Reference: `invntt()` in the reference implementation @[REF]+ * - We normalize at the beginning of the inverse NTT,+ * while the reference implementation normalizes at+ * the end. This allows us to drop a call to `poly_reduce()`+ * from the base multiplication. */+MLK_STATIC_TESTABLE void mlk_poly_invntt_tomont_c(mlk_poly *p)+__contract__(+ requires(memory_no_alias(p, sizeof(mlk_poly)))+ assigns(memory_slice(p, sizeof(mlk_poly)))+ ensures(array_abs_bound(p->coeffs, 0, MLKEM_N, MLK_INVNTT_BOUND))+)+{+ unsigned j, layer;+ const int16_t f = 1441; /* check-magic: 1441 == pow(2,32 - 7,MLKEM_Q) */+ int16_t *r = p->coeffs;++ /*+ * Scale input polynomial to account for Montgomery factor+ * and NTT twist. This also brings coefficients down to+ * absolute value < MLKEM_Q.+ */+ for (j = 0; j < MLKEM_N; j++)+ __loop__(+ invariant(j <= MLKEM_N)+ invariant(array_abs_bound(r, 0, j, MLKEM_Q))+ decreases(MLKEM_N - j))+ {+ r[j] = mlk_fqmul(r[j], f);+ }++ /* Run the invNTT layers */+ for (layer = 7; layer > 0; layer--)+ __loop__(+ invariant(0 <= layer && layer < 8)+ invariant(array_abs_bound(r, 0, MLKEM_N, MLKEM_Q))+ decreases(layer))+ {+ mlk_invntt_layer(r, layer);+ }++ mlk_assert_abs_bound(p, MLKEM_N, MLK_INVNTT_BOUND);+}++MLK_INTERNAL_API+void mlk_poly_invntt_tomont(mlk_poly *r)+{+#if defined(MLK_USE_NATIVE_INTT)+ int ret;+ ret = mlk_intt_native(r->coeffs);+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ mlk_assert_abs_bound(r, MLKEM_N, MLK_INVNTT_BOUND);+ return;+ }+#endif /* MLK_USE_NATIVE_INTT */++ mlk_poly_invntt_tomont_c(r);+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */+#else /* !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(mlk_poly)++#endif /* MLK_CONFIG_MULTILEVEL_NO_SHARED */
@@ -0,0 +1,296 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#ifndef MLK_POLY_H+#define MLK_POLY_H+++#include "cbmc.h"+#include "common.h"+#include "debug.h"+#include "verify.h"++/* Absolute exclusive upper bound for the output of the inverse NTT */+#define MLK_INVNTT_BOUND (8 * MLKEM_Q)++/* Absolute exclusive upper bound for the output of the forward NTT */+#define MLK_NTT_BOUND (8 * MLKEM_Q)++/**+ * Element of R_q = Z_q[X]/(X^n + 1). Represents polynomial+ * coeffs[0] + X*coeffs[1] + X^2*coeffs[2] + ... + X^{n-1}*coeffs[n-1].+ */+typedef struct+{+ int16_t coeffs[MLKEM_N]; /**< Polynomial coefficients. */+} MLK_ALIGN mlk_poly;++/**+ * INTERNAL representation of precomputed data speeding up+ * the base multiplication of two polynomials in NTT domain.+ */+typedef struct+{+ int16_t coeffs[MLKEM_N >> 1]; /**< Cached coefficients. */+} MLK_ALIGN mlk_poly_mulcache;++/**+ * Generic Montgomery reduction; given a 32-bit integer a, computes a 16-bit+ * integer congruent to a * R^-1 mod MLKEM_Q, where R=2^16.+ *+ * @param a Input integer to be reduced, of absolute value smaller or equal+ * to INT32_MAX - 2^15 * MLKEM_Q.+ *+ * @return Integer congruent to a * R^-1 modulo MLKEM_Q, with absolute value+ * <= ceil(|a| / 2^16) + (MLKEM_Q + 1)/2.+ */+static MLK_ALWAYS_INLINE int16_t mlk_montgomery_reduce(int32_t a)+__contract__(+ requires(a < +(INT32_MAX - (((int32_t)1 << 15) * MLKEM_Q)) &&+ a > -(INT32_MAX - (((int32_t)1 << 15) * MLKEM_Q)))+ /* We don't attempt to express an input-dependent output bound+ * as the post-condition here. There are two call-sites for this+ * function:+ * - The base multiplication: Here, we need no output bound.+ * - mlk_fqmul: Here, we inline this function and prove another spec+ * for mlk_fqmul which does have a post-condition bound. */+)+{+ /* check-magic: 62209 == unsigned_mod(pow(MLKEM_Q, -1, 2^16), 2^16) */+ const uint32_t QINV = 62209;++ /* Compute a*q^{-1} mod 2^16 in unsigned representatives. */+ const uint16_t a_reduced = mlk_cast_int32_to_uint16(a);+ const uint16_t a_inverted = (a_reduced * QINV) & UINT16_MAX;++ /* Lift to signed canonical representative mod 2^16. */+ const int16_t t = mlk_cast_uint16_to_int16(a_inverted);++ int32_t r;++ mlk_assert(a < +(INT32_MAX - (((int32_t)1 << 15) * MLKEM_Q)) &&+ a > -(INT32_MAX - (((int32_t)1 << 15) * MLKEM_Q)));++ r = a - ((int32_t)t * MLKEM_Q);++ /*+ * PORTABILITY: Right-shift on a signed integer is, strictly-speaking,+ * implementation-defined for negative left argument. Here,+ * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5))+ */+ r = r >> 16;+ /* Bounds: |r >> 16| <= ceil(|r| / 2^16)+ * <= ceil(|a| / 2^16 + MLKEM_Q / 2)+ * <= ceil(|a| / 2^16) + (MLKEM_Q + 1) / 2+ *+ * (Note that |a >> n| = ceil(|a| / 2^16) for negative a)+ */+ return (int16_t)r;+}++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+#define mlk_poly_tomont MLK_NAMESPACE(poly_tomont)+/**+ * In-place conversion of all coefficients of a polynomial from the normal+ * domain to the Montgomery domain.+ *+ * Bounds: output < MLKEM_Q in absolute value.+ *+ * @spec{Internal normalization required in `mlk_indcpa_keypair_derand` as+ * part of matrix-vector multiplication @[FIPS203, Algorithm 13, K-PKE.KeyGen,+ * L18].}+ *+ * @param[in,out] r Input/output polynomial.+ */+MLK_INTERNAL_API+void mlk_poly_tomont(mlk_poly *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_abs_bound(r->coeffs, 0, MLKEM_N, MLKEM_Q))+);+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++#define mlk_poly_mulcache_compute MLK_NAMESPACE(poly_mulcache_compute)+/**+ * Compute the mulcache for a polynomial in NTT domain.+ *+ * The mulcache of a degree-2 polynomial b := b0 + b1*X in Fq[X]/(X^2-zeta)+ * is the value b1*zeta, needed when computing products of b in+ * Fq[X]/(X^2-zeta).+ *+ * The mulcache of a polynomial in NTT domain -- which is a 128-tuple of+ * degree-2 polynomials in Fq[X]/(X^2-zeta), for varying zeta, is the+ * 128-tuple of mulcaches of those polynomials.+ *+ * @spec{Caches `b_1 * \gamma` in @[FIPS203, Algorithm 12, BaseCaseMultiply,+ * L1].}+ *+ * @param[out] x Mulcache to be populated.+ * @param[in] a Input polynomial.+ */+/*+ * NOTE: The default C implementation of this function populates+ * the mulcache with values in (-q,q), but this is not needed for the+ * higher level safety proofs, and thus not part of the spec.+ */+MLK_INTERNAL_API+void mlk_poly_mulcache_compute(mlk_poly_mulcache *x, const mlk_poly *a)+__contract__(+ requires(memory_no_alias(x, sizeof(mlk_poly_mulcache)))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ assigns(memory_slice(x, sizeof(mlk_poly_mulcache)))+);++#define mlk_poly_reduce MLK_NAMESPACE(poly_reduce)+/**+ * Convert a polynomial to unsigned canonical representatives.+ *+ * The input coefficients can be arbitrary integers in int16_t. The output+ * coefficients are in [0,1,..,MLKEM_Q-1].+ *+ * @spec{Normalizes on unsigned canonical representatives ahead of calling+ * @[FIPS203, Compress_d, Eq (4.7)]. This is not made explicit in FIPS 203.}+ *+ * @param[in,out] r Input/output polynomial.+ */+/*+ * NOTE: The semantics of mlk_poly_reduce() is different in+ * the reference implementation, which requires+ * signed canonical output data. Unsigned canonical+ * outputs are better suited to the only remaining+ * use of mlk_poly_reduce() in the context of (de)serialization.+ */+MLK_INTERNAL_API+void mlk_poly_reduce(mlk_poly *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+);++#define mlk_poly_add MLK_NAMESPACE(poly_add)+/**+ * Add two polynomials in place.+ *+ * The coefficients of @p r and @p b must be such that the addition does not+ * overflow. Otherwise, the behaviour of this function is undefined.+ *+ * @spec{@[FIPS203, 2.4.5, Arithmetic With Polynomials and NTT+ * Representations]. Used in @[FIPS203, Algorithm 14 (K-PKE.Encrypt), L21].}+ *+ * @param[in,out] r Input-output polynomial to be added to.+ * @param[in] b Input polynomial that should be added to @p r. Must be+ * disjoint from @p r.+ */+/*+ * NOTE: The reference implementation uses a 3-argument mlk_poly_add.+ * We specialize to the accumulator form to avoid reasoning about aliasing.+ */+MLK_INTERNAL_API+void mlk_poly_add(mlk_poly *r, const mlk_poly *b)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(b, sizeof(mlk_poly)))+ requires(forall(k0, 0, MLKEM_N, (int32_t) r->coeffs[k0] + b->coeffs[k0] <= INT16_MAX))+ requires(forall(k1, 0, MLKEM_N, (int32_t) r->coeffs[k1] + b->coeffs[k1] >= INT16_MIN))+ ensures(forall(k, 0, MLKEM_N, r->coeffs[k] == old(*r).coeffs[k] + b->coeffs[k]))+ assigns(memory_slice(r, sizeof(mlk_poly)))+);++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_sub MLK_NAMESPACE(poly_sub)+/**+ * Subtract two polynomials; no modular reduction is performed.+ *+ * @spec{@[FIPS203, 2.4.5, Arithmetic With Polynomials and NTT+ * Representations]. Used in @[FIPS203, Algorithm 15, K-PKE.Decrypt, L6].}+ *+ * @param[in,out] r Input-output polynomial to be subtracted from.+ * @param[in] b Second input polynomial.+ */+/*+ * NOTE: The reference implementation uses a 3-argument mlk_poly_sub.+ * We specialize to the accumulator form to avoid reasoning about aliasing.+ */+MLK_INTERNAL_API+void mlk_poly_sub(mlk_poly *r, const mlk_poly *b)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(b, sizeof(mlk_poly)))+ requires(forall(k0, 0, MLKEM_N, (int32_t) r->coeffs[k0] - b->coeffs[k0] <= INT16_MAX))+ requires(forall(k1, 0, MLKEM_N, (int32_t) r->coeffs[k1] - b->coeffs[k1] >= INT16_MIN))+ ensures(forall(k, 0, MLKEM_N, r->coeffs[k] == old(*r).coeffs[k] - b->coeffs[k]))+ assigns(memory_slice(r, sizeof(mlk_poly)))+);+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#define mlk_poly_ntt MLK_NAMESPACE(poly_ntt)+/**+ * Compute the negacyclic number-theoretic transform (NTT) of a polynomial+ * in place.+ *+ * The input is assumed to be in normal order and coefficient-wise bound by+ * MLKEM_Q in absolute value.+ *+ * The output polynomial is in bitreversed order, or of a custom order if+ * MLK_USE_NATIVE_NTT_CUSTOM_ORDER is set, and coefficient-wise bound+ * by MLK_NTT_BOUND in absolute value.+ *+ * (NOTE: Sometimes the input to the NTT is actually smaller, which gives+ * better bounds.)+ *+ * @spec{Implements @[FIPS203, Algorithm 9, NTT].}+ *+ * @param[in,out] r Input/output polynomial.+ */+MLK_INTERNAL_API+void mlk_poly_ntt(mlk_poly *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(array_abs_bound(r->coeffs, 0, MLKEM_N, MLKEM_Q))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_abs_bound(r->coeffs, 0, MLKEM_N, MLK_NTT_BOUND))+);++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_invntt_tomont MLK_NAMESPACE(poly_invntt_tomont)+/**+ * Compute the inverse negacyclic number-theoretic transform (NTT) of a+ * polynomial in place; input assumed to be in bitreversed order, output in+ * normal order.+ *+ * The input is assumed to be in bitreversed order, or of a custom order if+ * MLK_USE_NATIVE_NTT_CUSTOM_ORDER is set, and can have arbitrary+ * coefficients in int16_t.+ *+ * The output polynomial is in normal order, and coefficient-wise bound by+ * MLK_INVNTT_BOUND in absolute value.+ *+ * @spec{Implements composition of @[FIPS203, Algorithm 10, NTT^{-1}] and+ * elementwise modular multiplication with a suitable Montgomery factor+ * introduced during the base multiplication.}+ *+ * @param[in,out] r Input/output polynomial.+ */+MLK_INTERNAL_API+void mlk_poly_invntt_tomont(mlk_poly *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_abs_bound(r->coeffs, 0, MLKEM_N, MLK_INVNTT_BOUND))+);+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#endif /* !MLK_POLY_H */
@@ -0,0 +1,522 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ *+ * - [NeonNTT]+ * Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1+ * Becker, Hwang, Kannwischer, Yang, Yang+ * https://eprint.iacr.org/2021/986+ *+ * - [REF]+ * CRYSTALS-Kyber C reference implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/ref+ */++#include "poly_k.h"++#include "debug.h"+#include "sampling.h"+#include "symmetric.h"+#include "verify.h"++/* Parameter set namespacing+ * This is to facilitate building multiple instances+ * of mlkem-native (e.g. with varying parameter sets)+ * within a single compilation unit. */+#define mlk_poly_cbd_eta1 MLK_ADD_PARAM_SET(mlk_poly_cbd_eta1)+#define mlk_poly_cbd_eta2 MLK_ADD_PARAM_SET(mlk_poly_cbd_eta2)+#define mlk_polyvec_basemul_acc_montgomery_cached_c \+ MLK_ADD_PARAM_SET(mlk_polyvec_basemul_acc_montgomery_cached_c)+/* End of parameter set namespacing */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `polyvec_compress()` in the reference implementation @[REF]+ * - In contrast to the reference implementation, we assume+ * unsigned canonical coefficients here.+ * The reference implementation works with coefficients+ * in the range [-(MLKEM_Q-1), MLKEM_Q-1]. */+MLK_INTERNAL_API+void mlk_polyvec_compress_du(uint8_t r[MLKEM_POLYVECCOMPRESSEDBYTES_DU],+ const mlk_polyvec *a)+{+ unsigned i;+ mlk_assert_bound_2d(a->vec, MLKEM_K, MLKEM_N, 0, MLKEM_Q);++ for (i = 0; i < MLKEM_K; i++)+ {+ mlk_poly_compress_du(r + i * MLKEM_POLYCOMPRESSEDBYTES_DU, &a->vec[i]);+ }+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `polyvec_decompress()` in the reference implementation @[REF]. */+MLK_INTERNAL_API+void mlk_polyvec_decompress_du(mlk_polyvec *r,+ const uint8_t a[MLKEM_POLYVECCOMPRESSEDBYTES_DU])+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ {+ mlk_poly_decompress_du(&r->vec[i], a + i * MLKEM_POLYCOMPRESSEDBYTES_DU);+ }++ mlk_assert_bound_2d(r->vec, MLKEM_K, MLKEM_N, 0, MLKEM_Q);+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API) || !defined(MLK_CONFIG_NO_ENCAPS_API)+/* Reference: `polyvec_tobytes()` in the reference implementation @[REF].+ * - In contrast to the reference implementation, we assume+ * unsigned canonical coefficients here.+ * The reference implementation works with coefficients+ * in the range [-(MLKEM_Q-1), MLKEM_Q-1]. */+MLK_INTERNAL_API+void mlk_polyvec_tobytes(uint8_t r[MLKEM_POLYVECBYTES], const mlk_polyvec *a)+{+ unsigned i;+ mlk_assert_bound_2d(a->vec, MLKEM_K, MLKEM_N, 0, MLKEM_Q);++ for (i = 0; i < MLKEM_K; i++)+ __loop__(+ assigns(i, memory_slice(r, MLKEM_POLYVECBYTES))+ invariant(i <= MLKEM_K)+ decreases(MLKEM_K - i)+ )+ {+ mlk_poly_tobytes(&r[i * MLKEM_POLYBYTES], &a->vec[i]);+ }+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API || !MLK_CONFIG_NO_ENCAPS_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+/* Reference: `polyvec_frombytes()` in the reference implementation @[REF]. */+MLK_INTERNAL_API+void mlk_polyvec_frombytes(mlk_polyvec *r, const uint8_t a[MLKEM_POLYVECBYTES])+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ {+ mlk_poly_frombytes(&r->vec[i], a + i * MLKEM_POLYBYTES);+ }++ mlk_assert_bound_2d(r->vec, MLKEM_K, MLKEM_N, 0, MLKEM_UINT12_LIMIT);+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++/* Reference: `polyvec_ntt()` in the reference implementation @[REF]. */+MLK_INTERNAL_API+void mlk_polyvec_ntt(mlk_polyvec *r)+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ {+ mlk_poly_ntt(&r->vec[i]);+ }++ mlk_assert_abs_bound_2d(r->vec, MLKEM_K, MLKEM_N, MLK_NTT_BOUND);+}++/* Reference: `polyvec_invntt_tomont()` in the reference implementation @[REF].+ * - We normalize at the beginning of the inverse NTT,+ * while the reference implementation normalizes at+ * the end. This allows us to drop a call to `poly_reduce()`+ * from the base multiplication. */+#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+MLK_INTERNAL_API+void mlk_polyvec_invntt_tomont(mlk_polyvec *r)+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ {+ mlk_poly_invntt_tomont(&r->vec[i]);+ }++ mlk_assert_abs_bound_2d(r->vec, MLKEM_K, MLKEM_N, MLK_INVNTT_BOUND);+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++/* Reference: `polyvec_basemul_acc_montgomery()` in the+ * reference implementation @[REF].+ * - We use a multiplication cache ('mulcache') here+ * which is not present in the reference implementation @[REF].+ * This idea originates from @[NeonNTT] and is used+ * at the C level here.+ * - We compute the coefficients of the scalar product in 32-bit+ * coefficients and perform only a single modular reduction+ * at the end. The reference implementation uses 2 * MLKEM_K+ * more modular reductions since it reduces after every modular+ * multiplication. */+MLK_STATIC_TESTABLE void mlk_polyvec_basemul_acc_montgomery_cached_c(+ mlk_poly *r, const mlk_polyvec *a, const mlk_polyvec *b,+ const mlk_polyvec_mulcache *b_cache)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, sizeof(mlk_polyvec)))+ requires(memory_no_alias(b, sizeof(mlk_polyvec)))+ requires(memory_no_alias(b_cache, sizeof(mlk_polyvec_mulcache)))+ requires(forall(k1, 0, MLKEM_K,+ array_bound(a->vec[k1].coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+)+{+ unsigned i;+ mlk_assert_bound_2d(a->vec, MLKEM_K, MLKEM_N, 0, MLKEM_UINT12_LIMIT);++ for (i = 0; i < MLKEM_N / 2; i++)+ __loop__(invariant(i <= MLKEM_N / 2)+ decreases(MLKEM_N / 2 - i))+ {+ unsigned k;+ int32_t t[2] = {0};+ for (k = 0; k < MLKEM_K; k++)+ __loop__(+ invariant(k <= MLKEM_K &&+ t[0] <= (int32_t) k * 2 * MLKEM_UINT12_LIMIT * 32768 &&+ t[0] >= - ((int32_t) k * 2 * MLKEM_UINT12_LIMIT * 32768) &&+ t[1] <= ((int32_t) k * 2 * MLKEM_UINT12_LIMIT * 32768) &&+ t[1] >= - ((int32_t) k * 2 * MLKEM_UINT12_LIMIT * 32768))+ decreases(MLKEM_K - k))+ {+ t[0] += (int32_t)a->vec[k].coeffs[2 * i + 1] * b_cache->vec[k].coeffs[i];+ t[0] += (int32_t)a->vec[k].coeffs[2 * i] * b->vec[k].coeffs[2 * i];+ t[1] += (int32_t)a->vec[k].coeffs[2 * i] * b->vec[k].coeffs[2 * i + 1];+ t[1] += (int32_t)a->vec[k].coeffs[2 * i + 1] * b->vec[k].coeffs[2 * i];+ }+ r->coeffs[2 * i + 0] = mlk_montgomery_reduce(t[0]);+ r->coeffs[2 * i + 1] = mlk_montgomery_reduce(t[1]);+ }+}++MLK_INTERNAL_API+void mlk_polyvec_basemul_acc_montgomery_cached(+ mlk_poly *r, const mlk_polyvec *a, const mlk_polyvec *b,+ const mlk_polyvec_mulcache *b_cache)+{+#if defined(MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED)+ {+ int ret;+ mlk_assert_bound_2d(a->vec, MLKEM_K, MLKEM_N, 0, MLKEM_UINT12_LIMIT);+#if MLKEM_K == 2+ ret = mlk_polyvec_basemul_acc_montgomery_cached_k2_native(+ r->coeffs, (const int16_t *)a, (const int16_t *)b,+ (const int16_t *)b_cache);+#elif MLKEM_K == 3+ ret = mlk_polyvec_basemul_acc_montgomery_cached_k3_native(+ r->coeffs, (const int16_t *)a, (const int16_t *)b,+ (const int16_t *)b_cache);+#elif MLKEM_K == 4+ ret = mlk_polyvec_basemul_acc_montgomery_cached_k4_native(+ r->coeffs, (const int16_t *)a, (const int16_t *)b,+ (const int16_t *)b_cache);+#endif+ if (ret == MLK_NATIVE_FUNC_SUCCESS)+ {+ return;+ }+ }+#endif /* MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED */++ mlk_polyvec_basemul_acc_montgomery_cached_c(r, a, b, b_cache);+}++/* Reference: Does not exist in the reference implementation @[REF].+ * - The reference implementation does not use a+ * multiplication cache ('mulcache'). This idea originates+ * from @[NeonNTT] and is used at the C level here. */+MLK_INTERNAL_API+void mlk_polyvec_mulcache_compute(mlk_polyvec_mulcache *x, const mlk_polyvec *a)+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ {+ mlk_poly_mulcache_compute(&x->vec[i], &a->vec[i]);+ }+}++/* Reference: `polyvec_reduce()` in the reference implementation @[REF].+ * - We use _unsigned_ canonical outputs, while the reference+ * implementation uses _signed_ canonical outputs.+ * Accordingly, we need a conditional addition of MLKEM_Q+ * here to go from signed to unsigned representatives.+ * This conditional addition is then dropped from all+ * polynomial compression functions instead (see `compress.c`). */+MLK_INTERNAL_API+void mlk_polyvec_reduce(mlk_polyvec *r)+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ {+ mlk_poly_reduce(&r->vec[i]);+ }++ mlk_assert_bound_2d(r->vec, MLKEM_K, MLKEM_N, 0, MLKEM_Q);+}++/* Reference: `polyvec_add()` in the reference implementation @[REF].+ * - We use destructive version (output=first input) to avoid+ * reasoning about aliasing in the CBMC specification */+MLK_INTERNAL_API+void mlk_polyvec_add(mlk_polyvec *r, const mlk_polyvec *b)+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ __loop__(+ assigns(i, memory_slice(r, sizeof(mlk_polyvec)))+ invariant(i <= MLKEM_K)+ invariant(forall(j0, i, MLKEM_K,+ forall(k0, 0, MLKEM_N,+ ((int32_t)r->vec[j0].coeffs[k0] + b->vec[j0].coeffs[k0] <= INT16_MAX) &&+ ((int32_t)r->vec[j0].coeffs[k0] + b->vec[j0].coeffs[k0] >= INT16_MIN))))+ invariant(forall(j2, 0, i,+ forall(k2, 0, MLKEM_N,+ (r->vec[j2].coeffs[k2] <= INT16_MAX) &&+ (r->vec[j2].coeffs[k2] >= INT16_MIN))))+ decreases(MLKEM_K - i)+ )+ {+ mlk_poly_add(&r->vec[i], &b->vec[i]);+ }+}++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+/* Reference: `polyvec_tomont()` in the reference implementation @[REF]. */+MLK_INTERNAL_API+void mlk_polyvec_tomont(mlk_polyvec *r)+{+ unsigned i;+ for (i = 0; i < MLKEM_K; i++)+ {+ mlk_poly_tomont(&r->vec[i]);+ }++ mlk_assert_abs_bound_2d(r->vec, MLKEM_K, MLKEM_N, MLKEM_Q);+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */+++/**+ * Given an array of uniformly random bytes, compute a polynomial with+ * coefficients distributed according to a centered binomial distribution+ * with parameter MLKEM_ETA1.+ *+ * @spec{Implements @[FIPS203, Algorithm 8, SamplePolyCBD_eta1], where eta1+ * is specified per parameter set in @[FIPS203, Table 2] and represented as+ * MLKEM_ETA1 here.}+ *+ * @reference{`poly_cbd_eta1` in the reference implementation @[REF].}+ *+ * @param[out] r Output polynomial.+ * @param[in] buf Input byte array.+ */+static MLK_INLINE void mlk_poly_cbd_eta1(+ mlk_poly *r, const uint8_t buf[MLKEM_ETA1 * MLKEM_N / 4])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(buf, MLKEM_ETA1 * MLKEM_N / 4))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_abs_bound(r->coeffs, 0, MLKEM_N, MLKEM_ETA1 + 1))+)+{+#if MLKEM_ETA1 == 2+ mlk_poly_cbd2(r, buf);+#elif MLKEM_ETA1 == 3+ mlk_poly_cbd3(r, buf);+#else+#error "Invalid value of MLKEM_ETA1"+#endif+}++#if !defined(MLK_CONFIG_NO_KEYPAIR_API) || \+ (MLKEM_ETA1 == MLKEM_ETA2 && (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)))+/* Reference: Does not exist in the reference implementation @[REF].+ * - This implements a x4-batched version of `poly_getnoise_eta1()`+ * from the reference implementation, to leverage+ * batched Keccak-f1600.*/+MLK_INTERNAL_API+void mlk_poly_getnoise_eta1_4x(mlk_poly *r0, mlk_poly *r1, mlk_poly *r2,+ mlk_poly *r3, const uint8_t seed[MLKEM_SYMBYTES],+ uint8_t nonce0, uint8_t nonce1, uint8_t nonce2,+ uint8_t nonce3)+{+ MLK_ALIGN uint8_t buf[4][MLK_ALIGN_UP(MLKEM_ETA1 * MLKEM_N / 4)];+ MLK_ALIGN uint8_t extkey[4][MLK_ALIGN_UP(MLKEM_SYMBYTES + 1)];+ mlk_memcpy(extkey[0], seed, MLKEM_SYMBYTES);+ mlk_memcpy(extkey[1], seed, MLKEM_SYMBYTES);+ mlk_memcpy(extkey[2], seed, MLKEM_SYMBYTES);+ mlk_memcpy(extkey[3], seed, MLKEM_SYMBYTES);+ extkey[0][MLKEM_SYMBYTES] = nonce0;+ extkey[1][MLKEM_SYMBYTES] = nonce1;+ extkey[2][MLKEM_SYMBYTES] = nonce2;+ extkey[3][MLKEM_SYMBYTES] = nonce3;++#if !defined(FIPS202_X4_DEFAULT_IMPLEMENTATION) && \+ !defined(MLK_CONFIG_SERIAL_FIPS202_ONLY)+ mlk_prf_eta1_x4(buf, extkey);+#else+ mlk_prf_eta1(buf[0], extkey[0]);+ mlk_prf_eta1(buf[1], extkey[1]);+ mlk_prf_eta1(buf[2], extkey[2]);+ if (r3 != NULL)+ {+ mlk_prf_eta1(buf[3], extkey[3]);+ }+#endif /* !(!FIPS202_X4_DEFAULT_IMPLEMENTATION && \+ !MLK_CONFIG_SERIAL_FIPS202_ONLY) */++ mlk_poly_cbd_eta1(r0, buf[0]);+ mlk_poly_cbd_eta1(r1, buf[1]);+ mlk_poly_cbd_eta1(r2, buf[2]);+ if (r3 != NULL)+ {+ mlk_poly_cbd_eta1(r3, buf[3]);+ mlk_assert_abs_bound(r3, MLKEM_N, MLKEM_ETA1 + 1);+ }++ mlk_assert_abs_bound(r0, MLKEM_N, MLKEM_ETA1 + 1);+ mlk_assert_abs_bound(r1, MLKEM_N, MLKEM_ETA1 + 1);+ mlk_assert_abs_bound(r2, MLKEM_N, MLKEM_ETA1 + 1);++ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(buf, sizeof(buf));+ mlk_zeroize(extkey, sizeof(extkey));+}+#endif /* !MLK_CONFIG_NO_KEYPAIR_API || (MLKEM_ETA1 == MLKEM_ETA2 && \+ (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API)) */++#if (MLKEM_K == 2 || MLKEM_K == 4) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API))+/**+ * Given an array of uniformly random bytes, compute a polynomial with+ * coefficients distributed according to a centered binomial distribution+ * with parameter MLKEM_ETA2.+ *+ * @spec{Implements @[FIPS203, Algorithm 8, SamplePolyCBD_eta2], where eta2+ * is specified per parameter set in @[FIPS203, Table 2] and represented as+ * MLKEM_ETA2 here.}+ *+ * @reference{`poly_cbd_eta2` in the reference implementation @[REF].}+ *+ * @param[out] r Output polynomial.+ * @param[in] buf Input byte array.+ */+static MLK_INLINE void mlk_poly_cbd_eta2(+ mlk_poly *r, const uint8_t buf[MLKEM_ETA2 * MLKEM_N / 4])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(buf, MLKEM_ETA2 * MLKEM_N / 4))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_abs_bound(r->coeffs, 0, MLKEM_N, MLKEM_ETA2 + 1)))+{+#if MLKEM_ETA2 == 2+ mlk_poly_cbd2(r, buf);+#else+#error "Invalid value of MLKEM_ETA2"+#endif+}++/* Reference: `poly_getnoise_eta2()` in the reference implementation @[REF].+ * - We include buffer zeroization. */+MLK_INTERNAL_API+void mlk_poly_getnoise_eta2(mlk_poly *r, const uint8_t seed[MLKEM_SYMBYTES],+ uint8_t nonce)+{+ MLK_ALIGN uint8_t buf[MLKEM_ETA2 * MLKEM_N / 4];+ MLK_ALIGN uint8_t extkey[MLKEM_SYMBYTES + 1];++ mlk_memcpy(extkey, seed, MLKEM_SYMBYTES);+ extkey[MLKEM_SYMBYTES] = nonce;+ mlk_prf_eta2(buf, extkey);++ mlk_poly_cbd_eta2(r, buf);++ mlk_assert_abs_bound(r, MLKEM_N, MLKEM_ETA2 + 1);++ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(buf, sizeof(buf));+ mlk_zeroize(extkey, sizeof(extkey));+}+#endif /* (MLKEM_K == 2 || MLKEM_K == 4) && (!MLK_CONFIG_NO_ENCAPS_API || \+ !MLK_CONFIG_NO_DECAPS_API) */++#if MLKEM_K == 2 && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API))+/* Reference: Does not exist in the reference implementation @[REF].+ * - This implements a x4-batched version of `poly_getnoise_eta1()`+ * and `poly_getnoise_eta2()` from the reference implementation,+ * leveraging batched Keccak-f1600.+ * - If a x4-batched Keccak-f1600 is available, we squeeze+ * more random data than needed for the eta2 calls, to be+ * be able to use a x4-batched Keccak-f1600. */+MLK_INTERNAL_API+void mlk_poly_getnoise_eta1122_4x(mlk_poly *r0, mlk_poly *r1, mlk_poly *r2,+ mlk_poly *r3,+ const uint8_t seed[MLKEM_SYMBYTES],+ uint8_t nonce0, uint8_t nonce1,+ uint8_t nonce2, uint8_t nonce3)+{+#if MLKEM_ETA2 >= MLKEM_ETA1+#error mlk_poly_getnoise_eta1122_4x assumes MLKEM_ETA1 > MLKEM_ETA2+#endif+ MLK_ALIGN uint8_t buf[4][MLK_ALIGN_UP(MLKEM_ETA1 * MLKEM_N / 4)];+ MLK_ALIGN uint8_t extkey[4][MLK_ALIGN_UP(MLKEM_SYMBYTES + 1)];++ mlk_memcpy(extkey[0], seed, MLKEM_SYMBYTES);+ mlk_memcpy(extkey[1], seed, MLKEM_SYMBYTES);+ mlk_memcpy(extkey[2], seed, MLKEM_SYMBYTES);+ mlk_memcpy(extkey[3], seed, MLKEM_SYMBYTES);+ extkey[0][MLKEM_SYMBYTES] = nonce0;+ extkey[1][MLKEM_SYMBYTES] = nonce1;+ extkey[2][MLKEM_SYMBYTES] = nonce2;+ extkey[3][MLKEM_SYMBYTES] = nonce3;++ /* On systems with fast batched Keccak, we use 4-fold batched PRF,+ * even though that means generating more random data in buf[2] and buf[3]+ * than necessary. */+#if !defined(FIPS202_X4_DEFAULT_IMPLEMENTATION) && \+ !defined(MLK_CONFIG_SERIAL_FIPS202_ONLY)+ mlk_prf_eta1_x4(buf, extkey);+#else+ mlk_prf_eta1(buf[0], extkey[0]);+ mlk_prf_eta1(buf[1], extkey[1]);+ mlk_prf_eta2(buf[2], extkey[2]);+ mlk_prf_eta2(buf[3], extkey[3]);+#endif /* !(!FIPS202_X4_DEFAULT_IMPLEMENTATION && \+ !MLK_CONFIG_SERIAL_FIPS202_ONLY) */++ mlk_poly_cbd_eta1(r0, buf[0]);+ mlk_poly_cbd_eta1(r1, buf[1]);+ mlk_poly_cbd_eta2(r2, buf[2]);+ mlk_poly_cbd_eta2(r3, buf[3]);++ mlk_assert_abs_bound(r0, MLKEM_N, MLKEM_ETA1 + 1);+ mlk_assert_abs_bound(r1, MLKEM_N, MLKEM_ETA1 + 1);+ mlk_assert_abs_bound(r2, MLKEM_N, MLKEM_ETA2 + 1);+ mlk_assert_abs_bound(r3, MLKEM_N, MLKEM_ETA2 + 1);++ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(buf, sizeof(buf));+ mlk_zeroize(extkey, sizeof(extkey));+}+#endif /* MLKEM_K == 2 && (!MLK_CONFIG_NO_ENCAPS_API || \+ !MLK_CONFIG_NO_DECAPS_API) */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef mlk_poly_cbd_eta1+#undef mlk_poly_cbd_eta2+#undef mlk_polyvec_basemul_acc_montgomery_cached_c
@@ -0,0 +1,622 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#ifndef MLK_POLY_K_H+#define MLK_POLY_K_H++#include "common.h"+#include "compress.h"+#include "poly.h"++/* Parameter set namespacing+ * This is to facilitate building multiple instances+ * of mlkem-native (e.g. with varying parameter sets)+ * within a single compilation unit. */+#define mlk_polyvec MLK_ADD_PARAM_SET(mlk_polyvec)+#define mlk_polymat MLK_ADD_PARAM_SET(mlk_polymat)+#define mlk_polyvec_mulcache MLK_ADD_PARAM_SET(mlk_polyvec_mulcache)+/* End of parameter set namespacing */++/** Vector of MLKEM_K polynomials. */+typedef struct+{+ mlk_poly vec[MLKEM_K]; /**< Component polynomials. */+} MLK_ALIGN mlk_polyvec;++/** MLKEM_K x MLKEM_K matrix of polynomials. */+typedef struct+{+ mlk_polyvec vec[MLKEM_K]; /**< Rows of the matrix. */+} MLK_ALIGN mlk_polymat;++/** Vector of MLKEM_K mlk_poly_mulcache entries. */+typedef struct+{+ mlk_poly_mulcache vec[MLKEM_K]; /**< Per-component caches. */+} MLK_ALIGN mlk_polyvec_mulcache;++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_compress_du MLK_NAMESPACE_K(poly_compress_du)+/**+ * Compression (du bits) and subsequent serialization of a polynomial.+ *+ * @spec{Implements `ByteEncode_{d_u} (Compress_{d_u} (u))` in @[FIPS203,+ * Algorithm 14 (K-PKE.Encrypt), L22], with level-specific d_u defined in+ * @[FIPS203, Table 2], and given by MLKEM_DU here.}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_DU+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ */+static MLK_INLINE void mlk_poly_compress_du(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DU], const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_DU))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_DU)))+{+#if MLKEM_DU == 10+ mlk_poly_compress_d10(r, a);+#elif MLKEM_DU == 11+ mlk_poly_compress_d11(r, a);+#else+#error "Invalid value of MLKEM_DU"+#endif+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_decompress_du MLK_NAMESPACE_K(poly_decompress_du)+/**+ * De-serialization and subsequent decompression (du bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_du.+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @spec{Implements `Decompress_{d_u} (ByteDecode_{d_u} (u))` in @[FIPS203,+ * Algorithm 15 (K-PKE.Decrypt), L3], with level-specific d_u defined in+ * @[FIPS203, Table 2], and given by MLKEM_DU here.}+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_DU+ * bytes).+ */+static MLK_INLINE void mlk_poly_decompress_du(+ mlk_poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DU])+__contract__(+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_DU))+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q)))+{+#if MLKEM_DU == 10+ mlk_poly_decompress_d10(r, a);+#elif MLKEM_DU == 11+ mlk_poly_decompress_d11(r, a);+#else+#error "Invalid value of MLKEM_DU"+#endif+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_compress_dv MLK_NAMESPACE_K(poly_compress_dv)+/**+ * Compression (dv bits) and subsequent serialization of a polynomial.+ *+ * @spec{Implements `ByteEncode_{d_v} (Compress_{d_v} (v))` in @[FIPS203,+ * Algorithm 14 (K-PKE.Encrypt), L23], with level-specific d_v defined in+ * @[FIPS203, Table 2], and given by MLKEM_DV here.}+ *+ * @param[out] r Output byte array (of length MLKEM_POLYCOMPRESSEDBYTES_DV+ * bytes).+ * @param[in] a Input polynomial. Coefficients must be unsigned canonical,+ * i.e. in [0,1,..,MLKEM_Q-1].+ */+static MLK_INLINE void mlk_poly_compress_dv(+ uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DV], const mlk_poly *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_DV))+ requires(memory_no_alias(a, sizeof(mlk_poly)))+ requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_DV)))+{+#if MLKEM_DV == 4+ mlk_poly_compress_d4(r, a);+#elif MLKEM_DV == 5+ mlk_poly_compress_d5(r, a);+#else+#error "Invalid value of MLKEM_DV"+#endif+}+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */+++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_decompress_dv MLK_NAMESPACE_K(poly_decompress_dv)+/**+ * De-serialization and subsequent decompression (dv bits) of a polynomial;+ * approximate inverse of mlk_poly_compress_dv.+ *+ * Upon return, the coefficients of the output polynomial are+ * unsigned-canonical (non-negative and smaller than MLKEM_Q).+ *+ * @spec{Implements `Decompress_{d_v} (ByteDecode_{d_v} (v))` in @[FIPS203,+ * Algorithm 15 (K-PKE.Decrypt), L4], with level-specific d_v defined in+ * @[FIPS203, Table 2], and given by MLKEM_DV here.}+ *+ * @param[out] r Output polynomial.+ * @param[in] a Input byte array (of length MLKEM_POLYCOMPRESSEDBYTES_DV+ * bytes).+ */+static MLK_INLINE void mlk_poly_decompress_dv(+ mlk_poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DV])+__contract__(+ requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_DV))+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q)))+{+#if MLKEM_DV == 4+ mlk_poly_decompress_d4(r, a);+#elif MLKEM_DV == 5+ mlk_poly_decompress_d5(r, a);+#else+#error "Invalid value of MLKEM_DV"+#endif+}+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_polyvec_compress_du MLK_NAMESPACE_K(polyvec_compress_du)+/**+ * Compress and serialize a vector of polynomials.+ *+ * @spec{Implements `ByteEncode_{d_u} (Compress_{d_u} (u))` in @[FIPS203,+ * Algorithm 14 (K-PKE.Encrypt), L22], with level-specific d_u defined in+ * @[FIPS203, Table 2], and given by MLKEM_DU here.}+ *+ * @param[out] r Output byte array (needs space for+ * MLKEM_POLYVECCOMPRESSEDBYTES_DU bytes).+ * @param[in] a Input vector of polynomials. Coefficients must be unsigned+ * canonical, i.e. in [0,1,..,MLKEM_Q-1].+ */+MLK_INTERNAL_API+void mlk_polyvec_compress_du(uint8_t r[MLKEM_POLYVECCOMPRESSEDBYTES_DU],+ const mlk_polyvec *a)+__contract__(+ requires(memory_no_alias(r, MLKEM_POLYVECCOMPRESSEDBYTES_DU))+ requires(memory_no_alias(a, sizeof(mlk_polyvec)))+ requires(forall(k0, 0, MLKEM_K,+ array_bound(a->vec[k0].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))+ assigns(memory_slice(r, MLKEM_POLYVECCOMPRESSEDBYTES_DU))+);+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_polyvec_decompress_du MLK_NAMESPACE_K(polyvec_decompress_du)+/**+ * De-serialize and decompress a vector of polynomials; approximate inverse+ * of mlk_polyvec_compress_du.+ *+ * @spec{Implements `Decompress_{d_u} (ByteDecode_{d_u} (u))` in @[FIPS203,+ * Algorithm 15 (K-PKE.Decrypt), L3], with level-specific d_u defined in+ * @[FIPS203, Table 2], and given by MLKEM_DU here.}+ *+ * @param[out] r Output vector of polynomials. Coefficients are normalized+ * to [0,1,..,MLKEM_Q-1].+ * @param[in] a Input byte array (of length MLKEM_POLYVECCOMPRESSEDBYTES_DU+ * bytes).+ */+MLK_INTERNAL_API+void mlk_polyvec_decompress_du(mlk_polyvec *r,+ const uint8_t a[MLKEM_POLYVECCOMPRESSEDBYTES_DU])+__contract__(+ requires(memory_no_alias(a, MLKEM_POLYVECCOMPRESSEDBYTES_DU))+ requires(memory_no_alias(r, sizeof(mlk_polyvec)))+ assigns(memory_slice(r, sizeof(mlk_polyvec)))+ ensures(forall(k0, 0, MLKEM_K,+ array_bound(r->vec[k0].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))+);+#endif /* !MLK_CONFIG_NO_DECAPS_API */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API) || !defined(MLK_CONFIG_NO_ENCAPS_API)+#define mlk_polyvec_tobytes MLK_NAMESPACE_K(polyvec_tobytes)+/**+ * Serialize a vector of polynomials.+ *+ * @spec{Implements ByteEncode_12 @[FIPS203, Algorithm 5]. Extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays] and+ * @[FIPS203, 2.4.6, Matrices and Vectors].}+ *+ * @param[out] r Output byte array (needs space for MLKEM_POLYVECBYTES bytes).+ * @param[in] a Input vector of polynomials. Each polynomial must have+ * coefficients in [0,1,..,MLKEM_Q-1].+ */+MLK_INTERNAL_API+void mlk_polyvec_tobytes(uint8_t r[MLKEM_POLYVECBYTES], const mlk_polyvec *a)+__contract__(+ requires(memory_no_alias(a, sizeof(mlk_polyvec)))+ requires(memory_no_alias(r, MLKEM_POLYVECBYTES))+ requires(forall(k0, 0, MLKEM_K,+ array_bound(a->vec[k0].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))+ assigns(memory_slice(r, MLKEM_POLYVECBYTES))+);+#endif /* !MLK_CONFIG_NO_KEYPAIR_API || !MLK_CONFIG_NO_ENCAPS_API */++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_polyvec_frombytes MLK_NAMESPACE_K(polyvec_frombytes)+/**+ * De-serialize a vector of polynomials; inverse of mlk_polyvec_tobytes.+ *+ * @spec{Implements ByteDecode_12 @[FIPS203, Algorithm 6]. Extended to+ * vectors as per @[FIPS203, 2.4.8 Applying Algorithms to Arrays] and+ * @[FIPS203, 2.4.6, Matrices and Vectors].}+ *+ * @param[out] r Output vector of polynomials. Coefficients will be+ * normalized in [0,1,..,4095].+ * @param[in] a Input byte array (of length MLKEM_POLYVECBYTES bytes).+ */+MLK_INTERNAL_API+void mlk_polyvec_frombytes(mlk_polyvec *r, const uint8_t a[MLKEM_POLYVECBYTES])+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_polyvec)))+ requires(memory_no_alias(a, MLKEM_POLYVECBYTES))+ assigns(memory_slice(r, sizeof(mlk_polyvec)))+ ensures(forall(k0, 0, MLKEM_K,+ array_bound(r->vec[k0].coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT)))+);+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#define mlk_polyvec_ntt MLK_NAMESPACE_K(polyvec_ntt)+/**+ * Apply forward NTT to all elements of a vector of polynomials.+ *+ * The input is assumed to be in normal order and coefficient-wise bound by+ * MLKEM_Q in absolute value.+ *+ * The output polynomial is in bitreversed order, and coefficient-wise bound+ * by MLK_NTT_BOUND in absolute value.+ *+ * @spec{Implements @[FIPS203, Algorithm 9, NTT]. Extended to vectors as per+ * @[FIPS203, 2.4.6, Matrices and Vectors].}+ *+ * @param[in,out] r Input/output vector of polynomials.+ */+MLK_INTERNAL_API+void mlk_polyvec_ntt(mlk_polyvec *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_polyvec)))+ requires(forall(j, 0, MLKEM_K,+ array_abs_bound(r->vec[j].coeffs, 0, MLKEM_N, MLKEM_Q)))+ assigns(memory_slice(r, sizeof(mlk_polyvec)))+ ensures(forall(j, 0, MLKEM_K,+ array_abs_bound(r->vec[j].coeffs, 0, MLKEM_N, MLK_NTT_BOUND)))+);++#if !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_polyvec_invntt_tomont MLK_NAMESPACE_K(polyvec_invntt_tomont)+/**+ * Apply inverse NTT to all elements of a vector of polynomials and multiply+ * by Montgomery factor 2^16.+ *+ * The input is assumed to be in bitreversed order, and can have arbitrary+ * coefficients in int16_t.+ *+ * The output polynomial is in normal order, and coefficient-wise bound by+ * MLK_INVNTT_BOUND in absolute value.+ *+ * @spec{Implements @[FIPS203, Algorithm 10, NTT^{-1}]. Extended to vectors+ * as per @[FIPS203, 2.4.6, Matrices and Vectors].}+ *+ * @param[in,out] r Input/output vector of polynomials.+ */+MLK_INTERNAL_API+void mlk_polyvec_invntt_tomont(mlk_polyvec *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_polyvec)))+ assigns(memory_slice(r, sizeof(mlk_polyvec)))+ ensures(forall(j, 0, MLKEM_K,+ array_abs_bound(r->vec[j].coeffs, 0, MLKEM_N, MLK_INVNTT_BOUND)))+);+#endif /* !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#define mlk_polyvec_basemul_acc_montgomery_cached \+ MLK_NAMESPACE_K(polyvec_basemul_acc_montgomery_cached)+/**+ * Scalar product of two vectors of polynomials in NTT domain, using+ * mulcache for the second operand.+ *+ * Bounds: every coefficient of @p a is assumed to be in [0,1,..,4095]. No+ * bounds guarantees for the coefficients in the result.+ *+ * @spec{Implements @[FIPS203, Section 2.4.7, Eq (2.14)], @[FIPS203,+ * Algorithm 11, MultiplyNTTs], and @[FIPS203, Algorithm 12,+ * BaseCaseMultiply].}+ *+ * @param[out] r Output polynomial.+ * @param[in] a First input polynomial vector.+ * @param[in] b Second input polynomial vector.+ * @param[in] b_cache Mulcache for the second input polynomial vector. Can+ * be computed via mlk_polyvec_mulcache_compute().+ */+MLK_INTERNAL_API+void mlk_polyvec_basemul_acc_montgomery_cached(+ mlk_poly *r, const mlk_polyvec *a, const mlk_polyvec *b,+ const mlk_polyvec_mulcache *b_cache)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(a, sizeof(mlk_polyvec)))+ requires(memory_no_alias(b, sizeof(mlk_polyvec)))+ requires(memory_no_alias(b_cache, sizeof(mlk_polyvec_mulcache)))+ requires(forall(k1, 0, MLKEM_K,+ array_bound(a->vec[k1].coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT)))+ assigns(memory_slice(r, sizeof(mlk_poly)))+);++#define mlk_polyvec_mulcache_compute MLK_NAMESPACE_K(polyvec_mulcache_compute)+/**+ * Compute the mulcache for a vector of polynomials in NTT domain.+ *+ * The mulcache of a degree-2 polynomial b := b0 + b1*X in Fq[X]/(X^2-zeta)+ * is the value b1*zeta, needed when computing products of b in+ * Fq[X]/(X^2-zeta).+ *+ * The mulcache of a polynomial in NTT domain -- which is a 128-tuple of+ * degree-2 polynomials in Fq[X]/(X^2-zeta), for varying zeta, is the+ * 128-tuple of mulcaches of those polynomials.+ *+ * The mulcache of a vector of polynomials is the vector of mulcaches of+ * its entries.+ *+ * @spec{Caches `b_1 * \gamma` in @[FIPS203, Algorithm 12, BaseCaseMultiply,+ * L1].}+ *+ * @param[out] x Mulcache to be populated.+ * @param[in] a Input polynomial vector.+ */+/*+ * NOTE: The default C implementation of this function populates+ * the mulcache with values in (-q,q), but this is not needed for the+ * higher level safety proofs, and thus not part of the spec.+ */+MLK_INTERNAL_API+void mlk_polyvec_mulcache_compute(mlk_polyvec_mulcache *x, const mlk_polyvec *a)+__contract__(+ requires(memory_no_alias(x, sizeof(mlk_polyvec_mulcache)))+ requires(memory_no_alias(a, sizeof(mlk_polyvec)))+ assigns(memory_slice(x, sizeof(mlk_polyvec_mulcache)))+);++#define mlk_polyvec_reduce MLK_NAMESPACE_K(polyvec_reduce)+/**+ * Apply Barrett reduction to each coefficient of each element of a vector+ * of polynomials. For details of the Barrett reduction see comments in+ * poly.c.+ *+ * @spec{Normalizes on unsigned canonical representatives ahead of calling+ * @[FIPS203, Compress_d, Eq (4.7)]. This is not made explicit in FIPS 203.}+ *+ * @param[in,out] r Input/output polynomial vector.+ */+/*+ * NOTE: The semantics of mlk_polyvec_reduce() is different in+ * the reference implementation, which requires+ * signed canonical output data. Unsigned canonical+ * outputs are better suited to the only remaining+ * use of mlk_poly_reduce() in the context of (de)serialization.+ */+MLK_INTERNAL_API+void mlk_polyvec_reduce(mlk_polyvec *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_polyvec)))+ assigns(memory_slice(r, sizeof(mlk_polyvec)))+ ensures(forall(k0, 0, MLKEM_K,+ array_bound(r->vec[k0].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))+);++#define mlk_polyvec_add MLK_NAMESPACE_K(polyvec_add)+/**+ * Add vectors of polynomials.+ *+ * The coefficients of @p r and @p b must be such that the addition does+ * not overflow. Otherwise, the behaviour of this function is undefined.+ *+ * The coefficients returned in @p *r are in int16_t which is sufficient to+ * prove type-safety of calling units. Therefore, no stronger ensures clause+ * is required on this function.+ *+ * @spec{@[FIPS203, 2.4.5, Arithmetic With Polynomials and NTT+ * Representations]. Used in @[FIPS203, Algorithm 14 (K-PKE.Encrypt), L19].}+ *+ * @param[in,out] r Input-output vector of polynomials to be added to.+ * @param[in] b Second input vector of polynomials.+ */+MLK_INTERNAL_API+void mlk_polyvec_add(mlk_polyvec *r, const mlk_polyvec *b)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_polyvec)))+ requires(memory_no_alias(b, sizeof(mlk_polyvec)))+ requires(forall(j0, 0, MLKEM_K,+ forall(k0, 0, MLKEM_N,+ (int32_t)r->vec[j0].coeffs[k0] + b->vec[j0].coeffs[k0] <= INT16_MAX)))+ requires(forall(j1, 0, MLKEM_K,+ forall(k1, 0, MLKEM_N,+ (int32_t)r->vec[j1].coeffs[k1] + b->vec[j1].coeffs[k1] >= INT16_MIN)))+ assigns(memory_slice(r, sizeof(mlk_polyvec)))+);++#if !defined(MLK_CONFIG_NO_KEYPAIR_API)+#define mlk_polyvec_tomont MLK_NAMESPACE_K(polyvec_tomont)+/**+ * In-place conversion of all coefficients of a polynomial vector from the+ * normal domain to the Montgomery domain.+ *+ * Bounds: output < MLKEM_Q in absolute value.+ *+ * @spec{Internal normalization required in `mlk_indcpa_keypair_derand` as+ * part of matrix-vector multiplication @[FIPS203, Algorithm 13, K-PKE.KeyGen,+ * L18].}+ *+ * @param[in,out] r Input/output polynomial vector.+ */+MLK_INTERNAL_API+void mlk_polyvec_tomont(mlk_polyvec *r)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_polyvec)))+ assigns(memory_slice(r, sizeof(mlk_polyvec)))+ ensures(forall(j, 0, MLKEM_K,+ array_abs_bound(r->vec[j].coeffs, 0, MLKEM_N, MLKEM_Q)))+);+#endif /* !MLK_CONFIG_NO_KEYPAIR_API */++#if !defined(MLK_CONFIG_NO_KEYPAIR_API) || \+ (MLKEM_ETA1 == MLKEM_ETA2 && (!defined(MLK_CONFIG_NO_ENCAPS_API) || \+ !defined(MLK_CONFIG_NO_DECAPS_API)))+#define mlk_poly_getnoise_eta1_4x MLK_NAMESPACE_K(poly_getnoise_eta1_4x)+/**+ * Batch sample four polynomials deterministically from a seed and nonces,+ * with output polynomials close to centered binomial distribution with+ * parameter MLKEM_ETA1.+ *+ * @spec{Implements 4x `SamplePolyCBD_{eta1} (PRF_{eta1} (sigma, N))`:+ * @[FIPS203, Algorithm 8, SamplePolyCBD_eta] and @[FIPS203, Eq (4.3),+ * PRF_eta]. `SamplePolyCBD_{eta1} (PRF_{eta1} (sigma, N))` appears in+ * @[FIPS203, Algorithm 13, K-PKE.KeyGen, L{9, 13}] and @[FIPS203,+ * Algorithm 14, K-PKE.Encrypt, L10].}+ *+ * @param[out] r0 Output polynomial.+ * @param[out] r1 Output polynomial.+ * @param[out] r2 Output polynomial.+ * @param[out] r3 Output polynomial. May be NULL.+ * @param[in] seed Input seed (of length MLKEM_SYMBYTES bytes).+ * @param nonce0 One-byte input nonce.+ * @param nonce1 One-byte input nonce.+ * @param nonce2 One-byte input nonce.+ * @param nonce3 One-byte input nonce.+ */+MLK_INTERNAL_API+void mlk_poly_getnoise_eta1_4x(mlk_poly *r0, mlk_poly *r1, mlk_poly *r2,+ mlk_poly *r3, const uint8_t seed[MLKEM_SYMBYTES],+ uint8_t nonce0, uint8_t nonce1, uint8_t nonce2,+ uint8_t nonce3)+__contract__(+ requires(memory_no_alias(seed, MLKEM_SYMBYTES))+ requires(memory_no_alias(r0, sizeof(mlk_poly)))+ requires(memory_no_alias(r1, sizeof(mlk_poly)))+ requires(memory_no_alias(r2, sizeof(mlk_poly)))+ requires(r3 == NULL || memory_no_alias(r3, sizeof(mlk_poly)))+ assigns(memory_slice(r0, sizeof(mlk_poly)))+ assigns(memory_slice(r1, sizeof(mlk_poly)))+ assigns(memory_slice(r2, sizeof(mlk_poly)))+ assigns(r3 != NULL: memory_slice(r3, sizeof(mlk_poly)))+ ensures(array_abs_bound(r0->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1))+ ensures(array_abs_bound(r1->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1))+ ensures(array_abs_bound(r2->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1))+ ensures(r3 != NULL ==> array_abs_bound(r3->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1))+);++#if MLKEM_ETA1 == MLKEM_ETA2+/*+ * We only require mlk_poly_getnoise_eta2_4x for ml-kem-768 and ml-kem-1024+ * where MLKEM_ETA2 = MLKEM_ETA1 = 2.+ * For ml-kem-512, mlk_poly_getnoise_eta1122_4x is used instead.+ */+#define mlk_poly_getnoise_eta2_4x mlk_poly_getnoise_eta1_4x+#endif /* MLKEM_ETA1 == MLKEM_ETA2 */+#endif /* !MLK_CONFIG_NO_KEYPAIR_API || (MLKEM_ETA1 == MLKEM_ETA2 && \+ (!MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API)) */++#if (MLKEM_K == 2 || MLKEM_K == 4) && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API))+#define mlk_poly_getnoise_eta2 MLK_NAMESPACE_K(poly_getnoise_eta2)+/**+ * Sample a polynomial deterministically from a seed and a nonce, with+ * output polynomial close to centered binomial distribution with parameter+ * MLKEM_ETA2.+ *+ * @spec{Implements `SamplePolyCBD_{eta2} (PRF_{eta2} (sigma, N))`:+ * @[FIPS203, Algorithm 8, SamplePolyCBD_eta] and @[FIPS203, Eq (4.3),+ * PRF_eta]. `SamplePolyCBD_{eta2} (PRF_{eta2} (sigma, N))` appears in+ * @[FIPS203, Algorithm 14, K-PKE.Encrypt, L14].}+ *+ * @param[out] r Output polynomial.+ * @param[in] seed Input seed (of length MLKEM_SYMBYTES bytes).+ * @param nonce One-byte input nonce.+ */+MLK_INTERNAL_API+void mlk_poly_getnoise_eta2(mlk_poly *r, const uint8_t seed[MLKEM_SYMBYTES],+ uint8_t nonce)+__contract__(+ requires(memory_no_alias(r, sizeof(mlk_poly)))+ requires(memory_no_alias(seed, MLKEM_SYMBYTES))+ assigns(memory_slice(r, sizeof(mlk_poly)))+ ensures(array_abs_bound(r->coeffs, 0, MLKEM_N, MLKEM_ETA2 + 1))+);+#endif /* (MLKEM_K == 2 || MLKEM_K == 4) && (!MLK_CONFIG_NO_ENCAPS_API || \+ !MLK_CONFIG_NO_DECAPS_API) */++#if MLKEM_K == 2 && \+ (!defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API))+#define mlk_poly_getnoise_eta1122_4x MLK_NAMESPACE_K(poly_getnoise_eta1122_4x)+/**+ * Batch sample four polynomials deterministically from a seed and nonces,+ * with output polynomials close to centered binomial distribution with+ * parameter MLKEM_ETA1 and MLKEM_ETA2.+ *+ * @spec{Implements two instances each of+ * `SamplePolyCBD_{eta1} (PRF_{eta1} (sigma, N))` and+ * `SamplePolyCBD_{eta2} (PRF_{eta2} (sigma, N))`:+ * @[FIPS203, Algorithm 8, SamplePolyCBD_eta] and @[FIPS203, Eq (4.3),+ * PRF_eta]. `SamplePolyCBD_{eta2} (PRF_{eta2} (sigma, N))` appears in+ * @[FIPS203, Algorithm 14, K-PKE.Encrypt, L14].}+ *+ * @param[out] r0 Output polynomial.+ * @param[out] r1 Output polynomial.+ * @param[out] r2 Output polynomial.+ * @param[out] r3 Output polynomial.+ * @param[in] seed Input seed (of length MLKEM_SYMBYTES bytes).+ * @param nonce0 One-byte input nonce.+ * @param nonce1 One-byte input nonce.+ * @param nonce2 One-byte input nonce.+ * @param nonce3 One-byte input nonce.+ */+MLK_INTERNAL_API+void mlk_poly_getnoise_eta1122_4x(mlk_poly *r0, mlk_poly *r1, mlk_poly *r2,+ mlk_poly *r3,+ const uint8_t seed[MLKEM_SYMBYTES],+ uint8_t nonce0, uint8_t nonce1,+ uint8_t nonce2, uint8_t nonce3)+__contract__(+ requires(memory_no_alias(r0, sizeof(mlk_poly)))+ requires(memory_no_alias(r1, sizeof(mlk_poly)))+ requires(memory_no_alias(r2, sizeof(mlk_poly)))+ requires(memory_no_alias(r3, sizeof(mlk_poly)))+ requires(memory_no_alias(seed, MLKEM_SYMBYTES))+ assigns(memory_slice(r0, sizeof(mlk_poly)))+ assigns(memory_slice(r1, sizeof(mlk_poly)))+ assigns(memory_slice(r2, sizeof(mlk_poly)))+ assigns(memory_slice(r3, sizeof(mlk_poly)))+ ensures(array_abs_bound(r0->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1)+ && array_abs_bound(r1->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1)+ && array_abs_bound(r2->coeffs,0, MLKEM_N, MLKEM_ETA2 + 1)+ && array_abs_bound(r3->coeffs,0, MLKEM_N, MLKEM_ETA2 + 1))+);+#endif /* MLKEM_K == 2 && (!MLK_CONFIG_NO_ENCAPS_API || \+ !MLK_CONFIG_NO_DECAPS_API) */++#endif /* !MLK_POLY_K_H */
@@ -0,0 +1,52 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_RANDOMBYTES_H+#define MLK_RANDOMBYTES_H+++#include "cbmc.h"+#include "common.h"++#if !defined(MLK_CONFIG_NO_RANDOMIZED_API)+#if !defined(MLK_CONFIG_CUSTOM_RANDOMBYTES)+/**+ * Fill a buffer with cryptographically secure random bytes.+ *+ * mlkem-native does not provide an implementation of this function.+ * It must be provided by the consumer.+ *+ * To use a custom random byte source with a different name or signature,+ * set MLK_CONFIG_CUSTOM_RANDOMBYTES and define mlk_randombytes directly.+ *+ * @param[out] out Output buffer.+ * @param outlen Number of random bytes to write.+ *+ * @retval 0 Success.+ * @retval other Failure; top-level APIs propagate this as MLK_ERR_RNG_FAIL.+ */+int randombytes(uint8_t *out, size_t outlen);++/**+ * Internal wrapper around randombytes().+ *+ * Fills a buffer with cryptographically secure random bytes.+ *+ * This function can be replaced by setting MLK_CONFIG_CUSTOM_RANDOMBYTES+ * and defining mlk_randombytes directly.+ *+ * @param[out] out Output buffer.+ * @param outlen Number of random bytes to write.+ *+ * @retval 0 Success.+ * @retval other Failure; top-level APIs propagate this as MLK_ERR_RNG_FAIL.+ */+MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_randombytes(uint8_t *out, size_t outlen)+__contract__(+ requires(memory_no_alias(out, outlen))+ assigns(memory_slice(out, outlen))) { return randombytes(out, outlen); }+#endif /* !MLK_CONFIG_CUSTOM_RANDOMBYTES */+#endif /* !MLK_CONFIG_NO_RANDOMIZED_API */+#endif /* !MLK_RANDOMBYTES_H */
@@ -0,0 +1,371 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ *+ * - [REF]+ * CRYSTALS-Kyber C reference implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/ref+ */++#include "common.h"+#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)++#include "debug.h"+#include "sampling.h"+#include "symmetric.h"+#include "verify.h"++/* Reference: `rej_uniform()` in the reference implementation @[REF].+ * - Our signature differs from the reference implementation+ * in that it adds the offset and always expects the base of the+ * target buffer. This avoids shifting the buffer base in the+ * caller, which appears tricky to reason about. */+MLK_STATIC_TESTABLE unsigned mlk_rej_uniform_c(int16_t *r, unsigned target,+ unsigned offset,+ const uint8_t *buf,+ unsigned buflen)+__contract__(+ requires(offset <= target && target <= 4096 && buflen <= 4096 && buflen % 3 == 0)+ requires(memory_no_alias(r, sizeof(int16_t) * target))+ requires(memory_no_alias(buf, buflen))+ requires(array_bound(r, 0, offset, 0, MLKEM_Q))+ assigns(memory_slice(r, sizeof(int16_t) * target))+ ensures(offset <= return_value && return_value <= target)+ ensures(array_bound(r, 0, return_value, 0, MLKEM_Q)))+{+ unsigned ctr, pos;+ int16_t val0, val1;++ mlk_assert_bound(r, offset, 0, MLKEM_Q);++ ctr = offset;+ pos = 0;+ /* pos + 3 cannot overflow due to the assumption buflen <= 4096 */+ while (ctr < target && pos + 3 <= buflen)+ __loop__(+ invariant(offset <= ctr && ctr <= target && pos <= buflen)+ invariant(array_bound(r, 0, ctr, 0, MLKEM_Q))+ decreases(buflen - pos))+ {+ /* Safety:+ * - The explicit cast to uint16_t ensures that << 8 does+ * not signed-overflow even on a 16-bit system.+ * - The conversion to int16_t is safe due to the explicit 0xFFF+ * truncation.+ */+ val0 = (int16_t)(((buf[pos + 0] >> 0) | ((uint16_t)buf[pos + 1] << 8)) &+ 0xFFF);+ val1 = (int16_t)(((buf[pos + 1] >> 4) | (buf[pos + 2] << 4)) & 0xFFF);+ pos += 3;++ if (val0 < MLKEM_Q)+ {+ r[ctr++] = val0;+ }+ if (ctr < target && val1 < MLKEM_Q)+ {+ r[ctr++] = val1;+ }+ }++ mlk_assert_bound(r, ctr, 0, MLKEM_Q);+ return ctr;+}++/**+ * Run rejection sampling on uniform random bytes to generate uniform random+ * integers mod MLKEM_Q.+ *+ * @reference{`rej_uniform()` in the reference implementation @[REF]. Our+ * signature differs from the reference in that it adds the offset and always+ * expects the base of the target buffer; this avoids shifting the buffer+ * base in the caller, which is tricky to reason about. Has an optional+ * fallback to a native implementation.}+ *+ * @param[out] r Output buffer.+ * @param target Requested number of 16-bit integers (uniform mod MLKEM_Q).+ * Must be <= 4096.+ * @param offset Number of 16-bit integers that have already been+ * sampled. Must be <= @p target.+ * @param[in] buf Input buffer (assumed to be uniform random bytes).+ * @param buflen Length of input buffer in bytes. Must be <= 4096 and a+ * multiple of 3.+ *+ * @note Strictly speaking, only a few values of @p buflen near UINT_MAX need+ * excluding. The limit of 4096 is somewhat arbitrary but sufficient+ * for all uses of this function. Similarly, the actual limit for+ * @p target is UINT_MAX/2.+ *+ * @return New offset of sampled 16-bit integers, at most @p target and at+ * least the initial @p offset. If the new offset is strictly less+ * than @p target, the entire input buffer is guaranteed to have been+ * consumed; otherwise no information is provided on how many bytes+ * of the input buffer have been consumed.+ */+static unsigned mlk_rej_uniform(int16_t *r, unsigned target, unsigned offset,+ const uint8_t *buf, unsigned buflen)+__contract__(+ requires(offset <= target && target <= 4096 && buflen <= 4096 && buflen % 3 == 0)+ requires(memory_no_alias(r, sizeof(int16_t) * target))+ requires(memory_no_alias(buf, buflen))+ requires(array_bound(r, 0, offset, 0, MLKEM_Q))+ assigns(memory_slice(r, sizeof(int16_t) * target))+ ensures(offset <= return_value && return_value <= target)+ ensures(array_bound(r, 0, return_value, 0, MLKEM_Q))+)+{+#if defined(MLK_USE_NATIVE_REJ_UNIFORM)+ if (offset == 0)+ {+ int ret;+ ret = mlk_rej_uniform_native(r, target, buf, buflen);+ if (ret != MLK_NATIVE_FUNC_FALLBACK)+ {+ unsigned res = (unsigned)ret;+ mlk_assert_bound(r, res, 0, MLKEM_Q);+ return res;+ }+ }+#endif /* MLK_USE_NATIVE_REJ_UNIFORM */++ return mlk_rej_uniform_c(r, target, offset, buf, buflen);+}++#ifndef MLKEM_GEN_MATRIX_NBLOCKS+#define MLKEM_GEN_MATRIX_NBLOCKS \+ ((12 * MLKEM_N / 8 * ((uint32_t)1 << 12) / MLKEM_Q + MLK_XOF_RATE) / \+ MLK_XOF_RATE)+#endif++#if !defined(MLK_CONFIG_SERIAL_FIPS202_ONLY)+/* Reference: Does not exist in the reference implementation @[REF].+ * - x4-batched version of `rej_uniform()` from the+ * reference implementation, leveraging x4-batched Keccak-f1600. */+MLK_INTERNAL_API+void mlk_poly_rej_uniform_x4(mlk_poly *vec0, mlk_poly *vec1, mlk_poly *vec2,+ mlk_poly *vec3,+ uint8_t seed[4][MLK_ALIGN_UP(MLKEM_SYMBYTES + 2)])+{+ /* Temporary buffers for XOF output before rejection sampling */+ MLK_ALIGN uint8_t+ buf[4][MLK_ALIGN_UP(MLKEM_GEN_MATRIX_NBLOCKS * MLK_XOF_RATE)];++ /* Tracks the number of coefficients we have already sampled */+ unsigned ctr[4];+ mlk_xof_x4_ctx statex;+ unsigned buflen;++ mlk_xof_x4_init(&statex);+ mlk_xof_x4_absorb(&statex, seed, MLKEM_SYMBYTES + 2);++ /*+ * Initially, squeeze heuristic number of MLKEM_GEN_MATRIX_NBLOCKS.+ * This should generate the matrix entries with high probability.+ */+ mlk_xof_x4_squeezeblocks(buf, MLKEM_GEN_MATRIX_NBLOCKS, &statex);+ buflen = MLKEM_GEN_MATRIX_NBLOCKS * MLK_XOF_RATE;+ ctr[0] = mlk_rej_uniform(vec0->coeffs, MLKEM_N, 0, buf[0], buflen);+ ctr[1] = mlk_rej_uniform(vec1->coeffs, MLKEM_N, 0, buf[1], buflen);+ ctr[2] = mlk_rej_uniform(vec2->coeffs, MLKEM_N, 0, buf[2], buflen);+ ctr[3] = mlk_rej_uniform(vec3->coeffs, MLKEM_N, 0, buf[3], buflen);++ /*+ * So long as not all matrix entries have been generated, squeeze+ * one more block a time until we're done.+ */+ buflen = MLK_XOF_RATE;+ while (ctr[0] < MLKEM_N || ctr[1] < MLKEM_N || ctr[2] < MLKEM_N ||+ ctr[3] < MLKEM_N)+ __loop__(+ assigns(ctr, statex,+ memory_slice(vec0, sizeof(mlk_poly)),+ memory_slice(vec1, sizeof(mlk_poly)),+ memory_slice(vec2, sizeof(mlk_poly)),+ memory_slice(vec3, sizeof(mlk_poly)),+ object_whole(buf))+ invariant(ctr[0] <= MLKEM_N && ctr[1] <= MLKEM_N)+ invariant(ctr[2] <= MLKEM_N && ctr[3] <= MLKEM_N)+ invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLKEM_Q))+ invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLKEM_Q))+ invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLKEM_Q))+ invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLKEM_Q)))+ {+ mlk_xof_x4_squeezeblocks(buf, 1, &statex);+ ctr[0] = mlk_rej_uniform(vec0->coeffs, MLKEM_N, ctr[0], buf[0], buflen);+ ctr[1] = mlk_rej_uniform(vec1->coeffs, MLKEM_N, ctr[1], buf[1], buflen);+ ctr[2] = mlk_rej_uniform(vec2->coeffs, MLKEM_N, ctr[2], buf[2], buflen);+ ctr[3] = mlk_rej_uniform(vec3->coeffs, MLKEM_N, ctr[3], buf[3], buflen);+ }++ mlk_xof_x4_release(&statex);++ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(buf, sizeof(buf));+}+#endif /* !MLK_CONFIG_SERIAL_FIPS202_ONLY */++MLK_INTERNAL_API+void mlk_poly_rej_uniform(mlk_poly *entry, uint8_t seed[MLKEM_SYMBYTES + 2])+{+ mlk_xof_ctx state;+ MLK_ALIGN uint8_t buf[MLKEM_GEN_MATRIX_NBLOCKS * MLK_XOF_RATE];+ unsigned ctr, buflen;++ mlk_xof_init(&state);+ mlk_xof_absorb(&state, seed, MLKEM_SYMBYTES + 2);++ /* Initially, squeeze + sample heuristic number of MLKEM_GEN_MATRIX_NBLOCKS.+ */+ /* This should generate the matrix entry with high probability. */+ mlk_xof_squeezeblocks(buf, MLKEM_GEN_MATRIX_NBLOCKS, &state);+ buflen = MLKEM_GEN_MATRIX_NBLOCKS * MLK_XOF_RATE;+ ctr = mlk_rej_uniform(entry->coeffs, MLKEM_N, 0, buf, buflen);++ /* Squeeze + sample one more block a time until we're done */+ buflen = MLK_XOF_RATE;+ while (ctr < MLKEM_N)+ __loop__(+ assigns(ctr, state, memory_slice(entry, sizeof(mlk_poly)), object_whole(buf))+ invariant(ctr <= MLKEM_N)+ invariant(array_bound(entry->coeffs, 0, ctr, 0, MLKEM_Q)))+ {+ mlk_xof_squeezeblocks(buf, 1, &state);+ ctr = mlk_rej_uniform(entry->coeffs, MLKEM_N, ctr, buf, buflen);+ }++ mlk_xof_release(&state);++ /* Specification: Partially implements+ * @[FIPS203, Section 3.3, Destruction of intermediate values] */+ mlk_zeroize(buf, sizeof(buf));+}++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_ETA1 == 2 || \+ !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+/**+ * Load 4 bytes into a 32-bit integer in little-endian order.+ *+ * @reference{`load32_littleendian()` in the reference implementation @[REF].}+ *+ * @param[in] x Input byte array.+ *+ * @return 32-bit unsigned integer loaded from @p x.+ */+static uint32_t mlk_load32_littleendian(const uint8_t x[4])+{+ uint32_t r;+ r = (uint32_t)x[0];+ r |= (uint32_t)x[1] << 8;+ r |= (uint32_t)x[2] << 16;+ r |= (uint32_t)x[3] << 24;+ return r;+}++/* Reference: `cbd2()` in the reference implementation @[REF]. */+MLK_INTERNAL_API+void mlk_poly_cbd2(mlk_poly *r, const uint8_t buf[2 * MLKEM_N / 4])+{+ unsigned i;+ for (i = 0; i < MLKEM_N / 8; i++)+ __loop__(+ invariant(i <= MLKEM_N / 8)+ invariant(array_abs_bound(r->coeffs, 0, 8 * i, 3))+ decreases(MLKEM_N / 8 - i))+ {+ unsigned j;+ uint32_t t = mlk_load32_littleendian(buf + 4 * i);+ uint32_t d = t & 0x55555555;+ d += (t >> 1) & 0x55555555;++ for (j = 0; j < 8; j++)+ __loop__(+ invariant(i <= MLKEM_N / 8 && j <= 8)+ invariant(array_abs_bound(r->coeffs, 0, 8 * i + j, 3))+ decreases(8 - j))+ {+ /* Safety: The & 0x3 masks each value to 2 bits (range [0, 3]), so the+ * truncation and subsequent subtraction in int16_t is lossless. */+ const int16_t a = (int16_t)((d >> (4 * j + 0)) & 0x3);+ const int16_t b = (int16_t)((d >> (4 * j + 2)) & 0x3);+ r->coeffs[8 * i + j] = (int16_t)(a - b);+ }+ }+}+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_ETA1 == 2 || \+ !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_ETA1 == 3+/**+ * Load 3 bytes into a 32-bit integer in little-endian order.+ *+ * This function is only needed for ML-KEM-512.+ *+ * @reference{`load24_littleendian()` in the reference implementation @[REF].}+ *+ * @param[in] x Input byte array.+ *+ * @return 32-bit unsigned integer loaded from @p x (most significant byte+ * is zero).+ */+static uint32_t mlk_load24_littleendian(const uint8_t x[3])+{+ uint32_t r;+ r = (uint32_t)x[0];+ r |= (uint32_t)x[1] << 8;+ r |= (uint32_t)x[2] << 16;+ return r;+}++/* Reference: `cbd3()` in the reference implementation @[REF]. */+MLK_INTERNAL_API+void mlk_poly_cbd3(mlk_poly *r, const uint8_t buf[3 * MLKEM_N / 4])+{+ unsigned i;+ for (i = 0; i < MLKEM_N / 4; i++)+ __loop__(+ invariant(i <= MLKEM_N / 4)+ invariant(array_abs_bound(r->coeffs, 0, 4 * i, 4))+ decreases(MLKEM_N / 4 - i))+ {+ unsigned j;+ const uint32_t t = mlk_load24_littleendian(buf + 3 * i);+ uint32_t d = t & 0x00249249;+ d += (t >> 1) & 0x00249249;+ d += (t >> 2) & 0x00249249;++ for (j = 0; j < 4; j++)+ __loop__(+ invariant(i <= MLKEM_N / 4 && j <= 4)+ invariant(array_abs_bound(r->coeffs, 0, 4 * i + j, 4))+ decreases(4 - j))+ {+ /* Safety: The & 0x7 masks each value to 3 bits (range [0, 7]), so the+ * truncation and subsequent subtraction in int16_t is lossless. */+ const int16_t a = (int16_t)((d >> (6 * j + 0)) & 0x7);+ const int16_t b = (int16_t)((d >> (6 * j + 3)) & 0x7);+ r->coeffs[4 * i + j] = (int16_t)(a - b);+ }+ }+}+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_ETA1 == 3 */++#else /* !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(sampling)++#endif /* MLK_CONFIG_MULTILEVEL_NO_SHARED */++/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.+ * Don't modify by hand -- this is auto-generated by scripts/autogen. */+#undef MLKEM_GEN_MATRIX_NBLOCKS
@@ -0,0 +1,111 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#ifndef MLK_SAMPLING_H+#define MLK_SAMPLING_H++#include "cbmc.h"+#include "common.h"+#include "poly.h"++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_ETA1 == 2 || \+ !defined(MLK_CONFIG_NO_ENCAPS_API) || !defined(MLK_CONFIG_NO_DECAPS_API)+#define mlk_poly_cbd2 MLK_NAMESPACE(poly_cbd2)+/**+ * Given an array of uniformly random bytes, compute a polynomial with+ * coefficients distributed according to a centered binomial distribution+ * with parameter eta=2.+ *+ * @spec{Implements @[FIPS203, Algorithm 8, SamplePolyCBD_2].}+ *+ * @param[out] r Output polynomial.+ * @param[in] buf Input byte array.+ */+MLK_INTERNAL_API+void mlk_poly_cbd2(mlk_poly *r, const uint8_t buf[2 * MLKEM_N / 4]);+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_ETA1 == 2 || \+ !MLK_CONFIG_NO_ENCAPS_API || !MLK_CONFIG_NO_DECAPS_API */++#if defined(MLK_CONFIG_MULTILEVEL_WITH_SHARED) || MLKEM_ETA1 == 3+#define mlk_poly_cbd3 MLK_NAMESPACE(poly_cbd3)+/**+ * Given an array of uniformly random bytes, compute a polynomial with+ * coefficients distributed according to a centered binomial distribution+ * with parameter eta=3.+ *+ * This function is only needed for ML-KEM-512.+ *+ * @spec{Implements @[FIPS203, Algorithm 8, SamplePolyCBD_3].}+ *+ * @param[out] r Output polynomial.+ * @param[in] buf Input byte array.+ */+MLK_INTERNAL_API+void mlk_poly_cbd3(mlk_poly *r, const uint8_t buf[3 * MLKEM_N / 4]);+#endif /* MLK_CONFIG_MULTILEVEL_WITH_SHARED || MLKEM_ETA1 == 3 */++#if !defined(MLK_CONFIG_SERIAL_FIPS202_ONLY)+#define mlk_poly_rej_uniform_x4 MLK_NAMESPACE(poly_rej_uniform_x4)+/**+ * Generate four polynomials using rejection sampling on (pseudo-)uniformly+ * random bytes sampled from a seed.+ *+ * @spec{Implements @[FIPS203, Algorithm 7, SampleNTT].}+ *+ * @param[out] vec0 Polynomial to be sampled.+ * @param[out] vec1 Polynomial to be sampled.+ * @param[out] vec2 Polynomial to be sampled.+ * @param[out] vec3 Polynomial to be sampled.+ * @param[in] seed Consecutive array of 4 seed buffers of size+ * MLKEM_SYMBYTES + 2 each, plus padding for alignment.+ */+MLK_INTERNAL_API+void mlk_poly_rej_uniform_x4(mlk_poly *vec0, mlk_poly *vec1, mlk_poly *vec2,+ mlk_poly *vec3,+ uint8_t seed[4][MLK_ALIGN_UP(MLKEM_SYMBYTES + 2)])+__contract__(+ requires(memory_no_alias(vec0, sizeof(mlk_poly)))+ requires(memory_no_alias(vec1, sizeof(mlk_poly)))+ requires(memory_no_alias(vec2, sizeof(mlk_poly)))+ requires(memory_no_alias(vec3, sizeof(mlk_poly)))+ requires(memory_no_alias(seed, 4 * MLK_ALIGN_UP(MLKEM_SYMBYTES + 2)))+ assigns(memory_slice(vec0, sizeof(mlk_poly)))+ assigns(memory_slice(vec1, sizeof(mlk_poly)))+ assigns(memory_slice(vec2, sizeof(mlk_poly)))+ assigns(memory_slice(vec3, sizeof(mlk_poly)))+ ensures(array_bound(vec0->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ ensures(array_bound(vec1->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ ensures(array_bound(vec2->coeffs, 0, MLKEM_N, 0, MLKEM_Q))+ ensures(array_bound(vec3->coeffs, 0, MLKEM_N, 0, MLKEM_Q)));+#endif /* !MLK_CONFIG_SERIAL_FIPS202_ONLY */++#define mlk_poly_rej_uniform MLK_NAMESPACE(poly_rej_uniform)+/**+ * Generate a polynomial using rejection sampling on (pseudo-)uniformly+ * random bytes sampled from a seed.+ *+ * @spec{Implements @[FIPS203, Algorithm 7, SampleNTT].}+ *+ * @param[out] entry Polynomial to be sampled.+ * @param[in] seed Seed buffer of size MLKEM_SYMBYTES + 2.+ */+MLK_INTERNAL_API+void mlk_poly_rej_uniform(mlk_poly *entry, uint8_t seed[MLKEM_SYMBYTES + 2])+__contract__(+ requires(memory_no_alias(entry, sizeof(mlk_poly)))+ requires(memory_no_alias(seed, MLKEM_SYMBYTES + 2))+ assigns(memory_slice(entry, sizeof(mlk_poly)))+ ensures(array_bound(entry->coeffs, 0, MLKEM_N, 0, MLKEM_Q)));++#endif /* !MLK_SAMPLING_H */
@@ -0,0 +1,70 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ */++#ifndef MLK_SYMMETRIC_H+#define MLK_SYMMETRIC_H+++#include "cbmc.h"+#include "common.h"+#include MLK_FIPS202_HEADER_FILE+#if !defined(MLK_CONFIG_SERIAL_FIPS202_ONLY)+#include MLK_FIPS202X4_HEADER_FILE+#endif++/* Macros denoting FIPS 203 specific Hash functions */++/* Hash function H, @[FIPS203, Section 4.1, Eq (4.4)] */+#define mlk_hash_h(OUT, IN, INBYTES) mlk_sha3_256(OUT, IN, INBYTES)++/* Hash function G, @[FIPS203, Section 4.1, Eq (4.5)] */+#define mlk_hash_g(OUT, IN, INBYTES) mlk_sha3_512(OUT, IN, INBYTES)++/* Hash function J, @[FIPS203, Section 4.1, Eq (4.4)] */+#define mlk_hash_j(OUT, IN, INBYTES) \+ mlk_shake256(OUT, MLKEM_SYMBYTES, IN, INBYTES)++/* PRF function, @[FIPS203, Section 4.1, Eq (4.3)]+ * Referring to (eq 4.3), `OUT` is assumed to contain `s || b`. */+#define mlk_prf_eta(ETA, OUT, IN) \+ mlk_shake256(OUT, (ETA) * MLKEM_N / 4, IN, MLKEM_SYMBYTES + 1)+#define mlk_prf_eta1(OUT, IN) mlk_prf_eta(MLKEM_ETA1, OUT, IN)+#define mlk_prf_eta2(OUT, IN) mlk_prf_eta(MLKEM_ETA2, OUT, IN)+#define mlk_prf_eta1_x4(OUT, IN) \+ mlk_shake256x4((OUT)[0], (OUT)[1], (OUT)[2], (OUT)[3], \+ (MLKEM_ETA1 * MLKEM_N / 4), (IN)[0], (IN)[1], (IN)[2], \+ (IN)[3], MLKEM_SYMBYTES + 1)++/* XOF function, FIPS 203 4.1 */+#define mlk_xof_ctx mlk_shake128ctx+#define mlk_xof_x4_ctx mlk_shake128x4ctx+#define mlk_xof_init(CTX) mlk_shake128_init((CTX))+#define mlk_xof_absorb(CTX, IN, INBYTES) \+ mlk_shake128_absorb_once((CTX), (IN), (INBYTES))+#define mlk_xof_squeezeblocks(BUF, NBLOCKS, CTX) \+ mlk_shake128_squeezeblocks((BUF), (NBLOCKS), (CTX))+#define mlk_xof_release(CTX) mlk_shake128_release((CTX))++#define mlk_xof_x4_init(CTX) mlk_shake128x4_init((CTX))+#define mlk_xof_x4_absorb(CTX, IN, INBYTES) \+ mlk_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \+ (INBYTES))+#define mlk_xof_x4_squeezeblocks(BUF, NBLOCKS, CTX) \+ mlk_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \+ (NBLOCKS), (CTX))+#define mlk_xof_x4_release(CTX) mlk_shake128x4_release((CTX))++#define MLK_XOF_RATE SHAKE128_RATE++#endif /* !MLK_SYMMETRIC_H */
@@ -0,0 +1,320 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#ifndef MLK_SYS_H+#define MLK_SYS_H++#if !defined(MLK_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__))+#define MLK_HAVE_INLINE_ASM+#endif++/* Try to find endianness, if not forced through CFLAGS already */+#if !defined(MLK_SYS_LITTLE_ENDIAN) && !defined(MLK_SYS_BIG_ENDIAN)+#if defined(__BYTE_ORDER__)+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__+#define MLK_SYS_LITTLE_ENDIAN+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__+#define MLK_SYS_BIG_ENDIAN+#else+#error "__BYTE_ORDER__ defined, but don't recognize value."+#endif+#endif /* __BYTE_ORDER__ */++/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports+ * little endian x86, x86_64, and AArch64. It is, hence, safe to assume+ * little endian. */+#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \+ defined(_M_IX86) || defined(_M_ARM64))+#define MLK_SYS_LITTLE_ENDIAN+#endif++#endif /* !MLK_SYS_LITTLE_ENDIAN && !MLK_SYS_BIG_ENDIAN */++/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by+ * MSVC. */+#if defined(__AARCH64EL__) || defined(_M_ARM64)+#define MLK_SYS_AARCH64+#endif++/* Check if the AArch64 compilation target supports NEON (Advanced SIMD).+ *+ * Some compilers also define __ARM_NEON__, but __ARM_NEON is the most reliable+ * signal. Specifically, clang on Apple appears to keep __ARM_NEON__ set even if+ * -march=armv8-a+nosimd is set.+ *+ * gcc 4.8 -- the first gcc version introducing Neon support -- sets neither+ * __ARM_NEON nor __ARM_NEON__; in fact, there is no preprocessor signal that+ * Neon is enabled. If you use gcc 4.8, you should set __ARM_NEON manually.+ * gcc 4.9 onwards do set __ARM_NEON.+ */+#if defined(MLK_SYS_AARCH64) && defined(__ARM_NEON)+#define MLK_SYS_AARCH64_NEON+#endif++/* Check if we're running on an AArch64 big endian system. */+#if defined(__AARCH64EB__)+#define MLK_SYS_AARCH64_EB+#endif++/* Check if we're running on an Armv8.1-M system with MVE */+#if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_FEATURE_MVE)+#define MLK_SYS_ARMV81M_MVE+#endif++/* Check if we're running on an x86_64 system. */+#if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64)+#define MLK_SYS_X86_64+#if defined(__AVX2__)+#define MLK_SYS_X86_64_AVX2+#endif+#endif /* __x86_64__ || _M_X64 || _M_AMD64 */++#if defined(MLK_SYS_LITTLE_ENDIAN) && defined(__powerpc64__)+#define MLK_SYS_PPC64LE+#endif++#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64+#define MLK_SYS_RISCV64+#endif++#if defined(MLK_SYS_RISCV64) && defined(__riscv_vector) && \+ defined(__riscv_v_intrinsic)+#define MLK_SYS_RISCV64_RVV+#endif++#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32+#define MLK_SYS_RISCV32+#endif++#if defined(_WIN32)+#define MLK_SYS_WINDOWS+#endif++#if defined(__linux__)+#define MLK_SYS_LINUX+#endif++#if defined(__APPLE__)+#define MLK_SYS_APPLE+#endif++#if defined(MLK_FORCE_AARCH64) && !defined(MLK_SYS_AARCH64)+#error "MLK_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system."+#endif++#if defined(MLK_FORCE_AARCH64_EB) && !defined(MLK_SYS_AARCH64_EB)+#error \+ "MLK_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system."+#endif++#if defined(MLK_FORCE_X86_64) && !defined(MLK_SYS_X86_64)+#error "MLK_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system."+#endif++#if defined(MLK_FORCE_PPC64LE) && !defined(MLK_SYS_PPC64LE)+#error "MLK_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system."+#endif++#if defined(MLK_FORCE_RISCV64) && !defined(MLK_SYS_RISCV64)+#error "MLK_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system."+#endif++#if defined(MLK_FORCE_RISCV32) && !defined(MLK_SYS_RISCV32)+#error "MLK_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system."+#endif++/*+ * MLK_INLINE: Hint for inlining.+ * - MSVC: __inline+ * - C99+: inline+ * - GCC/Clang C90: __attribute__((unused)) to silence warnings+ * - Other C90: empty+ */+#if !defined(MLK_INLINE)+#if defined(_MSC_VER)+#define MLK_INLINE __inline+#elif defined(inline) || \+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)+#define MLK_INLINE inline+#elif defined(__GNUC__) || defined(__clang__)+#define MLK_INLINE __attribute__((unused))+#else+#define MLK_INLINE+#endif+#endif /* !MLK_INLINE */++/*+ * MLK_ALWAYS_INLINE: Force inlining.+ * - MSVC: __forceinline+ * - GCC/Clang C99+: MLK_INLINE __attribute__((always_inline))+ * - Other: MLK_INLINE (no forced inlining)+ */+#if !defined(MLK_ALWAYS_INLINE)+#if defined(_MSC_VER)+#define MLK_ALWAYS_INLINE __forceinline+#elif (defined(__GNUC__) || defined(__clang__)) && \+ (defined(inline) || \+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L))+#define MLK_ALWAYS_INLINE MLK_INLINE __attribute__((always_inline))+#else+#define MLK_ALWAYS_INLINE MLK_INLINE+#endif+#endif /* !MLK_ALWAYS_INLINE */++/*+ * MLK_NOINLINE: Prevent inlining.+ * - MSVC: __declspec(noinline)+ * - GCC/Clang: __attribute__((noinline))+ * - Other: empty+ */+#if !defined(MLK_NOINLINE)+#if defined(_MSC_VER)+#define MLK_NOINLINE __declspec(noinline)+#elif defined(__GNUC__) || defined(__clang__)+#define MLK_NOINLINE __attribute__((noinline))+#else+#define MLK_NOINLINE+#endif+#endif /* !MLK_NOINLINE */++#ifndef MLK_STATIC_TESTABLE+#define MLK_STATIC_TESTABLE static+#endif++/*+ * C90 does not have the restrict compiler directive yet.+ * We don't use it in C90 builds.+ */+#if !defined(restrict)+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L+#define MLK_RESTRICT restrict+#else+#define MLK_RESTRICT+#endif++#else /* !restrict */++#define MLK_RESTRICT restrict+#endif /* restrict */++#define MLK_DEFAULT_ALIGN 32+#define MLK_ALIGN_UP(N) \+ ((((N) + (MLK_DEFAULT_ALIGN - 1)) / MLK_DEFAULT_ALIGN) * MLK_DEFAULT_ALIGN)+#if defined(__GNUC__)+#define MLK_ALIGN __attribute__((aligned(MLK_DEFAULT_ALIGN)))+#elif defined(_MSC_VER)+#define MLK_ALIGN __declspec(align(MLK_DEFAULT_ALIGN))+#else+#define MLK_ALIGN /* No known support for alignment constraints */+#endif+++/* New X86_64 CPUs support control-flow protection using the CET instructions.+ * When enabled (through -fcf-protection=), all compilation units (including+ * empty ones) need to support CET for this to work.+ * For assembly, this means that source files need to signal support for+ * CET by setting the appropriate note.gnu.property section.+ * This can be achieved by including the <cet.h> header in all assembly file.+ * This file also provides the _CET_ENDBR macro which needs to be placed at+ * every potential target of an indirect branch.+ * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise+ * it is empty.+ * In case the compiler does not support CET (e.g., <gcc8, <clang11),+ * the __CET__ macro is not set and we default to nothing.+ * Note that we only issue _CET_ENDBR instructions through the MLK_ASM_FN_SYMBOL+ * macro as the global symbols are the only possible targets of indirect+ * branches in our code.+ */+#if defined(MLK_SYS_X86_64)+#if defined(__CET__)+#include <cet.h>+#define MLK_CET_ENDBR _CET_ENDBR+#else+#define MLK_CET_ENDBR+#endif+#endif /* MLK_SYS_X86_64 */++#if defined(MLK_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__)+#include <valgrind/memcheck.h>+#define MLK_CT_TESTING_SECRET(ptr, len) \+ VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len))+#define MLK_CT_TESTING_DECLASSIFY(ptr, len) \+ VALGRIND_MAKE_MEM_DEFINED((ptr), (len))+#else /* MLK_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */+#define MLK_CT_TESTING_SECRET(ptr, len) \+ do \+ { \+ } while (0)+#define MLK_CT_TESTING_DECLASSIFY(ptr, len) \+ do \+ { \+ } while (0)+#endif /* !(MLK_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */++#if defined(__GNUC__) || defined(__clang__)+#define MLK_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result))+#else+#define MLK_MUST_CHECK_RETURN_VALUE+#endif++/* The x86_64 assembly backend uses the SysV calling convention. On Windows,+ * where the Microsoft x64 calling convention is the default, it can still be+ * used with compilers that allow choosing the calling convention per+ * function: GCC and Clang support __attribute__((sysv_abi)), which makes+ * calls to the annotated function follow the SysV calling convention.+ *+ * MLK_SYSV_ABI_SUPPORTED signals that the toolchain can call SysV assembly+ * routines; the x86_64 assembly backend is only enabled if it is defined.+ * MLK_SYSV_ABI is the attribute carried by declarations of x86_64 assembly+ * routines. Both macros can be set externally for toolchains offering an+ * equivalent mechanism that is not recognized here. */+#if defined(MLK_SYS_X86_64) && !defined(MLK_SYSV_ABI_SUPPORTED)+#if !defined(MLK_SYS_WINDOWS) || defined(__GNUC__) || defined(__clang__)+#define MLK_SYSV_ABI_SUPPORTED+#endif+#endif++#if !defined(MLK_SYSV_ABI)+#if defined(MLK_SYS_WINDOWS) && defined(MLK_SYSV_ABI_SUPPORTED)+#define MLK_SYSV_ABI __attribute__((sysv_abi))+#else+#define MLK_SYSV_ABI+#endif+#endif /* !MLK_SYSV_ABI */++#if !defined(__ASSEMBLER__)+/* System capability enumeration */+typedef enum+{+ /* x86_64 */+ MLK_SYS_CAP_X86_64_AVX2,+ /* AArch64 */+ MLK_SYS_CAP_AARCH64_NEON,+ MLK_SYS_CAP_AARCH64_SHA3,+ /* Armv8.1-M */+ MLK_SYS_CAP_ARMV81M_MVE+} mlk_sys_cap;++#if !defined(MLK_CONFIG_CUSTOM_CAPABILITY_FUNC)+#include "cbmc.h"++MLK_MUST_CHECK_RETURN_VALUE+static MLK_INLINE int mlk_sys_check_capability(mlk_sys_cap cap)+__contract__(+ ensures(return_value == 0 || return_value == 1)+)+{+ /* By default, we rely on compile-time feature detection/specification:+ * If a feature is enabled at compile-time, we assume it is supported by+ * the host that the resulting library/binary will be built on.+ * If this assumption is not true, you MUST overwrite this function.+ * See the documentation of MLK_CONFIG_CUSTOM_CAPABILITY_FUNC in+ * mlkem_native_config.h for more information. */+ (void)cap;+ return 1;+}+#endif /* !MLK_CONFIG_CUSTOM_CAPABILITY_FUNC */+#endif /* !__ASSEMBLER__ */++#endif /* !MLK_SYS_H */
@@ -0,0 +1,20 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */+#include "verify.h"++#if !defined(MLK_USE_ASM_VALUE_BARRIER) && \+ !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)+/*+ * Masking value used in constant-time functions from+ * verify.h to block the compiler's range analysis and+ * thereby reduce the risk of compiler-introduced branches.+ */+volatile uint64_t mlk_ct_opt_blocker_u64 = 0;++#else /* !MLK_USE_ASM_VALUE_BARRIER && !MLK_CONFIG_MULTILEVEL_NO_SHARED */++MLK_EMPTY_CU(verify)++#endif /* !(!MLK_USE_ASM_VALUE_BARRIER && !MLK_CONFIG_MULTILEVEL_NO_SHARED) */
@@ -0,0 +1,447 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/* References+ * ==========+ *+ * - [FIPS203]+ * FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard+ * National Institute of Standards and Technology+ * https://csrc.nist.gov/pubs/fips/203/final+ *+ * - [REF]+ * CRYSTALS-Kyber C reference implementation+ * Bos, Ducas, Kiltz, Lepoint, Lyubashevsky, Schanck, Schwabe, Seiler, Stehlé+ * https://github.com/pq-crystals/kyber/tree/main/ref+ *+ * - [libmceliece]+ * libmceliece implementation of Classic McEliece+ * Bernstein, Chou+ * https://lib.mceliece.org/+ *+ * - [optblocker]+ * PQC forum post on opt-blockers using volatile globals+ * Daniel J. Bernstein+ * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ+ */++#ifndef MLK_VERIFY_H+#define MLK_VERIFY_H+++#include "cbmc.h"+#include "common.h"++/* Constant-time comparisons and conditional operations++ We reduce the risk for compilation into variable-time code+ through the use of 'value barriers'.++ Functionally, a value barrier is a no-op. To the compiler, however,+ it constitutes an arbitrary modification of its input, and therefore+ harden's value propagation and range analysis.++ We consider two approaches to implement a value barrier:+ - An empty inline asm block which marks the target value as clobbered.+ - XOR'ing with the value of a volatile global that's set to 0;+ see @[optblocker] for a discussion of this idea, and+ @[libmceliece, inttypes/crypto_intN.h] for an implementation.++ The first approach is cheap because it only prevents the compiler+ from reasoning about the value of the variable past the barrier,+ but does not directly generate additional instructions.++ The second approach generates redundant loads and XOR operations+ and therefore comes at a higher runtime cost. However, it appears+ more robust towards optimization, as compilers should never drop+ a volatile load.++ We use the empty-ASM value barrier for GCC and clang, and fall+ back to the global volatile barrier otherwise.++ The global value barrier can be forced by setting+ MLK_CONFIG_NO_ASM_VALUE_BARRIER.++*/++#if defined(MLK_HAVE_INLINE_ASM) && !defined(MLK_CONFIG_NO_ASM_VALUE_BARRIER)+#define MLK_USE_ASM_VALUE_BARRIER+#endif++#if !defined(MLK_USE_ASM_VALUE_BARRIER)++/*+ * Declaration of global volatile that the global value barrier+ * is loading from and masking with.+ */+#define mlk_ct_opt_blocker_u64 MLK_NAMESPACE(ct_opt_blocker_u64)+extern volatile uint64_t mlk_ct_opt_blocker_u64;++/* Helper functions for obtaining global masks of various sizes */++/* This contract is not proved but treated as an axiom.+ *+ * Its validity relies on the assumption that the global opt-blocker+ * constant mlk_ct_opt_blocker_u64 is not modified.+ */+static MLK_INLINE uint64_t mlk_ct_get_optblocker_u64(void)+__contract__(ensures(return_value == 0)) { return mlk_ct_opt_blocker_u64; }++static MLK_INLINE uint8_t mlk_ct_get_optblocker_u8(void)+__contract__(ensures(return_value == 0)) { return (uint8_t)mlk_ct_get_optblocker_u64(); }++static MLK_INLINE uint32_t mlk_ct_get_optblocker_u32(void)+__contract__(ensures(return_value == 0)) { return (uint32_t)mlk_ct_get_optblocker_u64(); }++static MLK_INLINE int32_t mlk_ct_get_optblocker_i32(void)+__contract__(ensures(return_value == 0)) { return (int32_t)mlk_ct_get_optblocker_u64(); }++/* Opt-blocker based implementation of value barriers */+static MLK_INLINE uint32_t mlk_value_barrier_u32(uint32_t b)+__contract__(ensures(return_value == b)) { return (b ^ mlk_ct_get_optblocker_u32()); }++static MLK_INLINE int32_t mlk_value_barrier_i32(int32_t b)+__contract__(ensures(return_value == b)) { return (b ^ mlk_ct_get_optblocker_i32()); }++static MLK_INLINE uint8_t mlk_value_barrier_u8(uint8_t b)+__contract__(ensures(return_value == b)) { return (b ^ mlk_ct_get_optblocker_u8()); }++#else /* !MLK_USE_ASM_VALUE_BARRIER */++static MLK_INLINE uint32_t mlk_value_barrier_u32(uint32_t b)+__contract__(ensures(return_value == b))+{+ __asm__ volatile("" : "+r"(b));+ return b;+}++static MLK_INLINE int32_t mlk_value_barrier_i32(int32_t b)+__contract__(ensures(return_value == b))+{+ __asm__ volatile("" : "+r"(b));+ return b;+}++static MLK_INLINE uint8_t mlk_value_barrier_u8(uint8_t b)+__contract__(ensures(return_value == b))+{+ __asm__ volatile("" : "+r"(b));+ return b;+}++#endif /* MLK_USE_ASM_VALUE_BARRIER */++#ifdef CBMC+#pragma CPROVER check push+#pragma CPROVER check disable "conversion"+#endif+/**+ * Cast uint16 value to int16.+ *+ * @param x Input value.+ *+ * @return For uint16_t x, the unique y in int16_t so that x == y mod 2^16.+ * Concretely:+ * - x < 32768: returns x+ * - x >= 32768: returns x - 65536+ */+static MLK_ALWAYS_INLINE int16_t mlk_cast_uint16_to_int16(uint16_t x)+{+ /*+ * PORTABILITY: This relies on uint16_t -> int16_t+ * being implemented as the inverse of int16_t -> uint16_t,+ * which is implementation-defined (C99 6.3.1.3 (3))+ * CBMC (correctly) fails to prove this conversion is OK,+ * so we have to suppress that check here+ */+ return (int16_t)x;+}+#ifdef CBMC+#pragma CPROVER check pop+#endif++/**+ * Cast int32 value to uint16 as per C standard.+ *+ * @param x Input value.+ *+ * @return For int32_t x, the unique y in uint16_t so that x == y mod 2^16.+ */+static MLK_ALWAYS_INLINE uint16_t mlk_cast_int32_to_uint16(int32_t x)+{+ return (uint16_t)(x & (int32_t)UINT16_MAX);+}++/**+ * Cast int16 value to uint16 as per C standard.+ *+ * @param x Input value.+ *+ * @return For int16_t x, the unique y in uint16_t so that x == y mod 2^16.+ */+static MLK_ALWAYS_INLINE uint16_t mlk_cast_int16_to_uint16(int32_t x)+{+ return mlk_cast_int32_to_uint16(x);+}++/**+ * Return 0 if input is non-negative, and -1 otherwise.+ *+ * @reference{Embedded in the polynomial compression function in the+ * reference implementation @[REF]. Used as part of signed->unsigned+ * conversion for modular representatives to detect whether the input is+ * negative. This happens in `mlk_poly_reduce()` here, and as part of+ * polynomial compression functions in the reference implementation. See+ * `mlk_poly_reduce()`. We use value barriers to reduce the risk of+ * compiler-introduced branches.}+ *+ * @param x Value to be converted into a mask.+ *+ * @return Mask value (0 or 0xFFFF).+ */+static MLK_INLINE uint16_t mlk_ct_cmask_neg_i16(int16_t x)+__contract__(ensures(return_value == ((x < 0) ? 0xFFFF : 0)))+{+ int32_t tmp = mlk_value_barrier_i32((int32_t)x);+ /*+ * PORTABILITY: Right-shift on a signed integer is+ * implementation-defined for negative left argument.+ * Here, we assume it's sign-preserving "arithmetic" shift right.+ * See (C99 6.5.7 (5))+ */+ tmp >>= 16;+ return mlk_cast_int32_to_uint16(tmp);+}++/**+ * Return 0 if input is zero, and -1 otherwise.+ *+ * @reference{Embedded in `cmov_int16()` in the reference implementation+ * @[REF]. Uses a value barrier and shift instead of `b = -b` to convert+ * condition into mask.}+ *+ * @param x Value to be converted into a mask.+ *+ * @return Mask value (0 or 0xFFFF).+ */+static MLK_INLINE uint16_t mlk_ct_cmask_nonzero_u16(uint16_t x)+__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFF)))+{+ int32_t tmp = mlk_value_barrier_i32(-((int32_t)x));+ /*+ * PORTABILITY: Right-shift on a signed integer is+ * implementation-defined for negative left argument.+ * Here, we assume it's sign-preserving "arithmetic" shift right.+ * See (C99 6.5.7 (5))+ */+ tmp >>= 16;+ return mlk_cast_int32_to_uint16(tmp);+}++/**+ * Return 0 if input is zero, and -1 otherwise.+ *+ * @reference{Embedded in `verify()` and `cmov()` in the reference+ * implementation @[REF]. We include a value barrier not present in the+ * reference implementation, to prevent the compiler from realizing that+ * this function returns a mask.}+ *+ * @param x Value to be converted into a mask.+ *+ * @return Mask value (0 or 0xFF).+ */+static MLK_INLINE uint8_t mlk_ct_cmask_nonzero_u8(uint8_t x)+__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF)))+{+ uint16_t mask = mlk_ct_cmask_nonzero_u16((uint16_t)x);+ return (uint8_t)(mask & 0xFF);+}++/**+ * Functionally equivalent to cond ? a : b, but implemented with guards+ * against compiler-introduced branches.+ *+ * @spec{With `a = MLKEM_Q_HALF` and `b=0`, this essentially implements+ * `Decompress_1` @[FIPS203, Eq (4.8)] in `mlk_poly_frommsg()`. With+ * `a = x + MLKEM_Q`, `b = x`, and `cond` indicating whether `x` is negative,+ * implements signed->unsigned conversion of modular representatives.+ * Questions of representation are not considered in the specification+ * @[FIPS203, Section 2.4.1, "The pseudocode is agnostic regarding how an+ * integer modulo 𝑚 is represented in actual implementations"].}+ *+ * @reference{Embedded in the polynomial compression function in the+ * reference implementation @[REF]. Used as part of signed->unsigned+ * conversion for modular representatives. This happens in `mlk_poly_reduce()`+ * here, and as part of polynomial compression functions in @[REF]. See+ * `mlk_poly_reduce()`. Barrier to reduce the risk of compiler-introduced+ * branches. For `a = MLKEM_Q_HALF` and `b=0`, also embedded in+ * `poly_frommsg()` from the reference implementation, which uses+ * `cmov_int16()` instead.}+ *+ * @param a First alternative.+ * @param b Second alternative.+ * @param cond Condition variable.+ *+ * @return @p a if @p cond != 0, else @p b.+ */+static MLK_INLINE int16_t mlk_ct_sel_int16(int16_t a, int16_t b, uint16_t cond)+__contract__(ensures(return_value == (cond ? a : b)))+{+ uint16_t au = mlk_cast_int16_to_uint16(a);+ uint16_t bu = mlk_cast_int16_to_uint16(b);+ uint16_t res = bu ^ (mlk_ct_cmask_nonzero_u16(cond) & (au ^ bu));+ return mlk_cast_uint16_to_int16(res);+}++/**+ * Functionally equivalent to cond ? a : b, but implemented with guards+ * against compiler-introduced branches.+ *+ * @reference{Embedded into `cmov()` in the reference implementation @[REF].+ * Uses a value barrier to get mask from condition value.}+ *+ * @param a First alternative.+ * @param b Second alternative.+ * @param cond Condition variable.+ *+ * @return @p a if @p cond != 0, else @p b.+ */+static MLK_INLINE uint8_t mlk_ct_sel_uint8(uint8_t a, uint8_t b, uint8_t cond)+__contract__(ensures(return_value == (cond ? a : b)))+{+ return b ^ (mlk_ct_cmask_nonzero_u8(cond) & (a ^ b));+}++/**+ * Compare two arrays for equality in constant time.+ *+ * @spec{Used to securely compute conditional move in @[FIPS203, Algorithm+ * 18 (ML-KEM.Decaps_Internal, L9-11].}+ *+ * @reference{`cmov()` in the reference implementation @[REF]. We return+ * `uint8_t`, not `int`. We use an additional XOR-accumulator in the+ * comparison loop which prevents early abort if the OR-accumulator is 0xFF.+ * We use a value barrier to convert the OR-accumulator into a mask; the+ * reference implementation uses a shift which the compiler can argue to+ * result in either 0 or 0xFF..FF.}+ *+ * @param[in] a First byte array.+ * @param[in] b Second byte array.+ * @param len Length of the byte arrays, upper-bounded to UINT16_MAX to+ * control proof complexity only.+ *+ * @retval 0 The byte arrays are equal.+ * @retval 0xFF The byte arrays are not equal.+ */+static MLK_INLINE uint8_t mlk_ct_memcmp(const uint8_t *a, const uint8_t *b,+ const size_t len)+__contract__(+ requires(len <= UINT16_MAX)+ requires(memory_no_alias(a, len))+ requires(memory_no_alias(b, len))+ ensures((return_value == 0) || (return_value == 0xFF))+ ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i]))))+{+ uint8_t r = 0, s = 0;+ unsigned i;++ for (i = 0; i < len; i++)+ __loop__(+ invariant(i <= len)+ invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))+ decreases(len - i))+ {+ r |= a[i] ^ b[i];+ /* s is useless, but prevents the loop from being aborted once r=0xff. */+ s ^= a[i] ^ b[i];+ }++ /*+ * - Convert r into a mask; this may not be necessary, but is an additional+ * safeguard+ * towards leaking information about a and b.+ * - XOR twice with s, separated by a value barrier, to prevent the compile+ * from dropping the s computation in the loop.+ */+ return (mlk_value_barrier_u8(mlk_ct_cmask_nonzero_u8(r) ^ s) ^ s);+}++/**+ * Copy len bytes from x to r if b is zero; don't modify x if b is non-zero.+ * Assumes two's complement representation of negative integers. Runs in+ * constant time.+ *+ * @spec{Used to securely compute conditional move in @[FIPS203, Algorithm+ * 18 (ML-KEM.Decaps_Internal, L9-11].}+ *+ * @reference{`cmov()` in the reference implementation @[REF]. We move if+ * condition value is `0`, not `1`. We use `mlk_ct_sel_uint8` for+ * constant-time selection.}+ *+ * @param[out] r Output byte array.+ * @param[in] x Input byte array.+ * @param len Number of bytes to be copied.+ * @param b Condition value.+ */+static MLK_INLINE void mlk_ct_cmov_zero(uint8_t *r, const uint8_t *x,+ size_t len, uint8_t b)+__contract__(+ requires(len <= UINT32_MAX)+ requires(memory_no_alias(r, len))+ requires(memory_no_alias(x, len))+ assigns(memory_slice(r, len))+ ensures(forall(i, 0, len, (r[i] == (b == 0 ? x[i] : old(r)[i])))))+{+ size_t i;+ for (i = 0; i < len; i++)+ __loop__(+ invariant(i <= len)+ invariant(forall(k, 0, i, r[k] == (b == 0 ? x[k] : loop_entry(r)[k])))+ decreases(len - i))+ {+ r[i] = mlk_ct_sel_uint8(r[i], x[i], b);+ }+}++/**+ * Force-zeroize a buffer.+ *+ * @spec{Used to implement @[FIPS203, Section 3.3, Destruction of+ * intermediate values].}+ *+ * @reference{Not present in the reference implementation @[REF].}+ *+ * @param[out] ptr Buffer to be zeroed.+ * @param len Number of bytes to be zeroed.+ */+#if !defined(MLK_CONFIG_CUSTOM_ZEROIZE)+#if defined(MLK_SYS_WINDOWS)+#include <windows.h>+#elif !defined(MLK_HAVE_INLINE_ASM)+#error No plausibly-secure implementation of mlk_zeroize available. Please provide your own using MLK_CONFIG_CUSTOM_ZEROIZE.+#endif++static MLK_INLINE void mlk_zeroize(void *ptr, size_t len)+__contract__(+ requires(len <= UINT32_MAX)+ requires(memory_no_alias(ptr, len))+ assigns(memory_slice(ptr, len))+ ensures(array_zeroized_u8((uint8_t *)ptr, len)))+{+#if defined(MLK_SYS_WINDOWS)+ SecureZeroMemory(ptr, len);+#else+ mlk_memset(ptr, 0, len);+ /* This follows OpenSSL and seems sufficient to prevent the compiler+ * from optimizing away the memset.+ *+ * If there was a reliable way to detect availability of memset_s(),+ * that would be preferred. */+ __asm__ volatile("" : : "r"(ptr) : "memory");+#endif /* !MLK_SYS_WINDOWS */+}+#endif /* !MLK_CONFIG_CUSTOM_ZEROIZE */++#endif /* !MLK_VERIFY_H */
@@ -0,0 +1,30 @@+/*+ * Copyright (c) The mlkem-native project authors+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT+ */++/*+ * WARNING: This file is auto-generated from scripts/autogen+ * in the mlkem-native repository.+ * Do not modify it directly.+ */+++/*+ * Table of zeta values used in the reference NTT and inverse NTT.+ * See autogen for details.+ */+static MLK_ALIGN const int16_t mlk_zetas[128] = {+ -1044, -758, -359, -1517, 1493, 1422, 287, 202, -171, 622, 1577,+ 182, 962, -1202, -1474, 1468, 573, -1325, 264, 383, -829, 1458,+ -1602, -130, -681, 1017, 732, 608, -1542, 411, -205, -1571, 1223,+ 652, -552, 1015, -1293, 1491, -282, -1544, 516, -8, -320, -666,+ -1618, -1162, 126, 1469, -853, -90, -271, 830, 107, -1421, -247,+ -951, -398, 961, -1508, -725, 448, -1065, 677, -1275, -1103, 430,+ 555, 843, -1251, 871, 1550, 105, 422, 587, 177, -235, -291,+ -460, 1574, 1653, -246, 778, 1159, -147, -777, 1483, -602, 1119,+ -1590, 644, -872, 349, 418, 329, -156, -75, 817, 1097, 603,+ 610, 1322, -1285, -1465, 384, -1215, -136, 1218, -1335, -874, 220,+ -1187, -1659, -1185, -1530, -1278, 794, -1510, -854, -870, 478, -108,+ -308, 996, 991, 958, -1460, 1522, 1628,+};
@@ -0,0 +1,126 @@+#!/usr/bin/env python3+"""Build the two tables of multiples of the base point that crypton reads.++ ./gen_base_table.py 5 p256_base_table.c # for p256_scalarmulbase+ ./gen_base_table.py odd 7 p256_wnaf_table.c # for p256_verify.c++Its own words for the layout: for each i, j with blocksize*i <= 256 and+1 <= j <= B, where B = 2^(blocksize-1), the multiple 2^(blocksize*i) * j * P+goes at tab + 64*(B*i + (j-1)), as a Montgomery-affine pair, four+little-endian 64-bit words each.++Five is the blocksize crypton ships: on an Apple M4 it is 6.40 microseconds+against 7.15 for four and 6.10 for six, and the table is 52 KiB against 33+and 88. Nothing outside this file knows the number -- it is written into+the generated file and read from there.++The curve constants come from `openssl ecparam`, not from memory, and the+generated table is checked against crypton's own base-point multiplication+by the test suite, so a mistake here does not pass quietly.+"""+import subprocess, re, sys++def curve():+ out = subprocess.run(["openssl","ecparam","-name","prime256v1",+ "-param_enc","explicit","-text","-noout"],+ capture_output=True, text=True).stdout+ f, cur = {}, None+ for line in out.splitlines():+ m = re.match(r'^(Prime|A|B|Generator \(uncompressed\)|Order):?\s*$', line.strip())+ if m:+ cur = m.group(1); f[cur] = ""; continue+ if cur and re.match(r'^\s+[0-9a-f]{2}[:0-9a-f]*:?\s*$', line):+ f[cur] += line.strip()+ elif cur and line and not line.startswith(' '):+ cur = None+ def num(s):+ return int.from_bytes(bytes(int(v,16) for v in s.strip(':').split(':') if v), 'big')+ g = bytes(int(v,16) for v in f['Generator (uncompressed)'].strip(':').split(':') if v)+ assert g[0] == 4 and len(g) == 65+ return (num(f['Prime']), num(f['A']), num(f['B']),+ int.from_bytes(g[1:33],'big'), int.from_bytes(g[33:],'big'), num(f['Order']))++P, A, B, GX, GY, N = curve()+assert (GY*GY - GX**3 - A*GX - B) % P == 0, "the generator is not on the curve"++def add(p, q):+ if p is None: return q+ if q is None: return p+ (x1,y1),(x2,y2) = p,q+ if x1 == x2:+ if (y1 + y2) % P == 0: return None+ l = (3*x1*x1 + A) * pow(2*y1, -1, P) % P+ else:+ l = (y2-y1) * pow(x2-x1, -1, P) % P+ x3 = (l*l - x1 - x2) % P+ return (x3, (l*(x1-x3) - y1) % P)++R = 1 << 256+def mont(v): return v * R % P+def words(v): return [(v >> (64*k)) & 0xFFFFFFFFFFFFFFFF for k in range(4)]++def table(blocksize):+ Bn = 1 << (blocksize - 1)+ blocks = 256 // blocksize + 1+ out = []+ base = (GX, GY) # 2^(blocksize*i) * P+ for i in range(blocks):+ acc = None+ for j in range(1, Bn + 1):+ acc = add(acc, base) # j * base+ out.append(acc)+ for _ in range(blocksize):+ base = add(base, base)+ return blocks, Bn, out++def odd_table(width):+ """The odd multiples 1P, 3P, ..., (2^(width-1)-1)P, which is what the+ windowed form in cbits/p256/p256_verify.c reads for the base point."""+ n = 1 << (width - 2)+ twice = add((GX, GY), (GX, GY))+ out, acc = [], (GX, GY)+ for _ in range(n):+ out.append(acc)+ acc = add(acc, twice)+ return out++def emit_odd(width, path):+ pts = odd_table(width)+ with open(path, 'w') as fh:+ fh.write("/* Generated by cbits/p256/gen_base_table.py; do not hand-edit.\n"+ " * The odd multiples of the base point, in Montgomery-affine\n"+ " * form, which cbits/p256/p256_verify.c reads. A verification\n"+ " * is public, so this table is walked in variable time. */\n")+ fh.write("#include <stdint.h>\n\n")+ fh.write(f"const uint64_t crypton_p256_wnaf_width = {width};\n\n")+ fh.write(f"const uint64_t crypton_p256_wnaf_table[{len(pts)*8}] = {{\n")+ for (x, y) in pts:+ ws = words(mont(x)) + words(mont(y))+ fh.write("\t" + ",".join(f"0x{w:016x}ULL" for w in ws) + ",\n")+ fh.write("};\n")+ return len(pts), len(pts) * 64++def emit(blocksize, path):+ blocks, Bn, pts = table(blocksize)+ with open(path, 'w') as fh:+ fh.write("/* Generated by cbits/p256/gen_base_table.py; do not hand-edit.\n"+ " * The multiples of the base point that s2n-bignum's\n"+ " * p256_scalarmulbase reads, in Montgomery-affine form. */\n")+ fh.write("#include <stdint.h>\n\n")+ fh.write(f"const uint64_t crypton_p256_s2n_base_blocksize = {blocksize};\n\n")+ fh.write(f"const uint64_t crypton_p256_s2n_base_table[{len(pts)*8}] = {{\n")+ for (x, y) in pts:+ ws = words(mont(x)) + words(mont(y))+ fh.write("\t" + ",".join(f"0x{w:016x}ULL" for w in ws) + ",\n")+ fh.write("};\n")+ return blocks, Bn, len(pts)*64++if __name__ == "__main__":+ if sys.argv[1] == "odd":+ w = int(sys.argv[2]); path = sys.argv[3]+ n, size = emit_odd(w, path)+ print(f"width {w}: {n} odd multiples = {size} bytes")+ else:+ b = int(sys.argv[1]); path = sys.argv[2]+ blocks, Bn, size = emit(b, path)+ print(f"blocksize {b}: {blocks} blocks x {Bn} = {size} bytes")
@@ -39,6 +39,15 @@ #include "p256/p256.h" +#ifdef CRYPTON_S2N_BIGNUM+extern void bignum_modinv(uint64_t k, uint64_t *z, const uint64_t *a,+ const uint64_t *b, uint64_t *t);+/* the digits are handed over as they lie */+#if P256_BITSPERDIGIT != 64 || P256_NDIGITS != 4+#error "CRYPTON_S2N_BIGNUM wants the 64-bit crypton_p256_int"+#endif+#endif+ const crypton_p256_int crypton_SECP256r1_n = // curve order {{P256_LITERAL(0xfc632551, 0xf3b9cac2), P256_LITERAL(0xa7179e84, 0xbce6faad), P256_LITERAL(-1, -1), P256_LITERAL(0, -1)}};@@ -214,7 +223,11 @@ n %= P256_BITSPERDIGIT; for (i = P256_NDIGITS - 1; i > 0; --i) { crypton_p256_digit accu = (P256_DIGIT(a, i) << n);- accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));+ /* n is zero as often as it is anything else, and a digit shifted by its+ * own width is undefined: x86 takes the count modulo the width and hands+ * back the whole digit, ARM hands back nothing. Two shifts that are each+ * inside the width say the intended nothing on both. */+ accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - 1 - n) >> 1); P256_DIGIT(b, i) = accu; } P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);@@ -230,7 +243,8 @@ n %= P256_BITSPERDIGIT; for (i = 0; i < P256_NDIGITS - 1; ++i) { crypton_p256_digit accu = (P256_DIGIT(a, i) >> n);- accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));+ /* the same full-width shift as in crypton_p256_shl above */+ accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1 - n) << 1); P256_DIGIT(b, i) = accu; } P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);@@ -244,8 +258,11 @@ accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1)); P256_DIGIT(b, i) = accu; }+ /* The shift is unsigned: highbit is a carry, zero or one, and one shifted+ * into the sign bit of the signed digit is an overflow the standard leaves+ * undefined. The value put into b is the same either way. */ P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |- (((crypton_p256_sdigit) highbit) << (P256_BITSPERDIGIT - 1));+ (((crypton_p256_digit) highbit) << (P256_BITSPERDIGIT - 1)); } // Return -1, 0, 1 for a < b, a == b or a > b respectively.@@ -312,6 +329,22 @@ crypton_p256_int U = *MOD; crypton_p256_int V = *a; + /* Zero has no inverse, and the loop below never finds that out: V stays+ even forever, so it is halved forever, and the only break is in the+ branch both U and V have to be odd to reach. The other input without an+ inverse is MOD itself -- 2*MOD does not fit in 256 bits, so there is no+ third -- and that one already leaves here as zero, which is also what+ Crypto.PubKey.ECC.P256's scalarInvSafe answers for both. Answer the+ same for zero rather than not answering.++ Reachable: Crypto.PubKey.ECC.P256 exports scalarInv, and scalarFromBinary+ accepts any 256 bits. A hang inside a foreign call cannot be interrupted+ by System.Timeout either. */+ if (crypton_p256_is_zero(a)) {+ crypton_p256_clear(b);+ return;+ }+ for (;;) { if (crypton_p256_is_even(&U)) { crypton_p256_shr1(&U, 0, &U);@@ -480,6 +513,16 @@ // b = 1/a mod n, using Fermat's little theorem. void crypton_p256e_scalar_invert(const crypton_p256_int* a, crypton_p256_int* b) {+#ifdef CRYPTON_S2N_BIGNUM+ /* The assembly, which takes a fixed number of division steps instead: 0.80+ * microseconds against 6.02 on an Apple M4. It answers zero where a has no+ * inverse, which is what the chain below does as well, and the caller reads+ * a zero as "no inverse". */+ uint64_t t[12];++ bignum_modinv(4, P256_DIGITS(b), P256_DIGITS(a),+ P256_DIGITS(&crypton_SECP256r1_n), t);+#else crypton_p256_int _1, _10, _11, _101, _111, _1010, _1111; crypton_p256_int _10101, _101010, _101111, x6, x8, x16, x32; int i;@@ -534,4 +577,5 @@ // Demontgomerize crypton_p256e_montmul(b, &crypton_SECP256r1_one, b);+#endif }
@@ -0,0 +1,841 @@+/* Generated by cbits/p256/gen_base_table.py; do not hand-edit.+ * The multiples of the base point that s2n-bignum's+ * p256_scalarmulbase reads, in Montgomery-affine form. */+#include <stdint.h>++const uint64_t crypton_p256_s2n_base_blocksize = 5;++const uint64_t crypton_p256_s2n_base_table[6656] = {+ 0x79e730d418a9143cULL,0x75ba95fc5fedb601ULL,0x79fb732b77622510ULL,0x18905f76a53755c6ULL,0xddf25357ce95560aULL,0x8b4ab8e4ba19e45cULL,0xd2e88688dd21f325ULL,0x8571ff1825885d85ULL,+ 0x850046d410ddd64dULL,0xaa6ae3c1a433827dULL,0x732205038d1490d9ULL,0xf6bb32e43dcf3a3bULL,0x2f3648d361bee1a5ULL,0x152cd7cbeb236ff8ULL,0x19a8fb0e92042dbeULL,0x78c577510a5b8a3bULL,+ 0xffac3f904eebc127ULL,0xb027f84a087d81fbULL,0x66ad77dd87cbbc98ULL,0x26936a3fb6ff747eULL,0xb04c5c1fc983a7ebULL,0x583e47ad0861fe1aULL,0x788208311a2ee98eULL,0xd5f06a29e587cc07ULL,+ 0x74b0b50d46918dccULL,0x4650a6edc623c173ULL,0x0cdaacace8100af2ULL,0x577362f541b0176bULL,0x2d96f24ce4cbaba6ULL,0x17628471fad6f447ULL,0x6b6c36dee5ddd22eULL,0x84b14c394c5ab863ULL,+ 0xbe1b8aaec45c61f5ULL,0x90ec649a94b9537dULL,0x941cb5aad076c20cULL,0xc9079605890523c8ULL,0xeb309b4ae7ba4f10ULL,0x73c568efe5eb882bULL,0x3540a9877e7a1f68ULL,0x73a076bb2dd1e916ULL,+ 0x403947373e77664aULL,0x55ae744f346cee3eULL,0xd50a961a5b17a3adULL,0x13074b5954213673ULL,0x93d36220d377e44bULL,0x299c2b53adff14b5ULL,0xf424d44cef639f11ULL,0xa4c9916d4a07f75fULL,+ 0x0746354ea0173b4fULL,0x2bd20213d23c00f7ULL,0xf43eaab50c23bb08ULL,0x13ba5119c3123e03ULL,0x2847d0303f5b9d4dULL,0x6742f2f25da67bddULL,0xef933bdc77c94195ULL,0xeaedd9156e240867ULL,+ 0x27f14cd19499a78fULL,0x462ab5c56f9b3455ULL,0x8f90f02af02cfc6bULL,0xb763891eb265230dULL,0xf59da3a9532d4977ULL,0x21e3327dcf9eba15ULL,0x123c7b84be60bbf0ULL,0x56ec12f27706df76ULL,+ 0x75c96e8f264e20e8ULL,0xabe6bfed59a7a841ULL,0x2cc09c0444c8eb00ULL,0xe05b3080f0c4e16bULL,0x1eb7777aa45f3314ULL,0x56af7bedce5d45e3ULL,0x2b6e019a88b12f1aULL,0x086659cdfd835f9bULL,+ 0x2c18dbd19dc21ec8ULL,0x98f9868a0fcf8139ULL,0x737d2cd648250b49ULL,0xcc61c94724b3428fULL,0x0c2b407880dd9e76ULL,0xc43a8991383fbe08ULL,0x5f7d2d65779be5d2ULL,0x78719a54eb3b4ab5ULL,+ 0xea7d260a6245e404ULL,0x9de407956e7fdfe0ULL,0x1ff3a4158dac1ab5ULL,0x3e7090f1649c9073ULL,0x1a7685612b944e88ULL,0x250f939ee57f61c8ULL,0x0c0daa891ead643dULL,0x68930023e125b88eULL,+ 0x04b71aa7d2697768ULL,0xabdedef5ca345a33ULL,0x2409d29dee37385eULL,0x4ee1df77cb83e156ULL,0x0cac12d91cbb5b43ULL,0x170ed2f6ca895637ULL,0x28228cfa8ade6d66ULL,0x7ff57c9553238acaULL,+ 0xccc425634b2ed709ULL,0x0e356769856fd30dULL,0xbcbcd43f559e9811ULL,0x738477ac5395b759ULL,0x35752b90c00ee17fULL,0x68748390742ed2e3ULL,0x7cd06422bd1f5bc1ULL,0xfbc08769c9e7b797ULL,+ 0xa242a35bb0cf664aULL,0x126e48f77f9707e3ULL,0x1717bf54c6832660ULL,0xfaae7332fd12c72eULL,0x27b52db7995d586bULL,0xbe29569e832237c2ULL,0xe8e4193e2a65e7dbULL,0x152706dc2eaa1bbbULL,+ 0x72bcd8b7bc60055bULL,0x03cc23ee56e27e4bULL,0xee337424e4819370ULL,0xe2aa0e430ad3da09ULL,0x40b8524f6383c45dULL,0xd766355442a41b25ULL,0x64efa6de778a4797ULL,0x2042170a7079adf4ULL,+ 0x808b0b650bc6fb80ULL,0x5882e0753ffe2e6bULL,0xd5ef2f7c2c83f549ULL,0x54d63c809103b723ULL,0xf2f11bd652a23f9bULL,0x3670c3194b0b6587ULL,0x55c4623bb1580e9eULL,0x64edf7b201efe220ULL,+ 0xd8c5fccfc5e3a3d8ULL,0xbefd904c4079dfbfULL,0xbc6d6a58fead0197ULL,0x39227077695532a4ULL,0x09e23e6ddbef42f5ULL,0x7e449b64480a9908ULL,0x7b969c1aad9a2e40ULL,0x6231d7929591c2a4ULL,+ 0xdb6d96f305968b80ULL,0x380a0913089f73b9ULL,0x7da70b83c2c61e01ULL,0x95fb8394569b38c7ULL,0x9a3c651280edfe2fULL,0x8f726bb98faeaf82ULL,0x8010a4a078424bf8ULL,0x296720440e844970ULL,+ 0x802b8d2333e12b70ULL,0x6d490a4b19dd329bULL,0x14f356cc6abc354dULL,0x11eddf7fd0a0da0dULL,0x1e208328d87fd1d8ULL,0xfd2f4f8cfd025813ULL,0x03b48cc47c29bca2ULL,0x3f2a78b3241a2b71ULL,+ 0x63c5cb817a2ad62aULL,0x7ef2b6b9ac62ff54ULL,0x3749bba4b3ad9db5ULL,0xad311f2c46d5a617ULL,0xb77a8087c2ff3b6dULL,0xb46feaf3367834ffULL,0xf8aa266d75d6b138ULL,0xfa38d320ec008188ULL,+ 0xc04afa1ae3451a09ULL,0x7cc69103bc117423ULL,0x876be3aa51cf56eeULL,0xe7577d57ad844a25ULL,0x266fed8cdb77f341ULL,0xcfa258dc23ae4a2aULL,0x53a7a98cda782760ULL,0x04b48868ceaf7d4aULL,+ 0xc0f2affc4e6916c6ULL,0x6fb94957811842daULL,0x6034bcb624b4d157ULL,0xde2efdc7992efb90ULL,0xd66f7eceac793c87ULL,0x02f026267dc6fdcdULL,0x90d3235c9aa1c501ULL,0xf6e494962b4666f0ULL,+ 0x082736d19c0859c3ULL,0x89ea5516b269386aULL,0xf25071871aa87b33ULL,0xe9d82f5f704e8236ULL,0x7834612442e855f5ULL,0x209f50fe395e00d8ULL,0xcd9e03aae6e7e62bULL,0xb4b4959e5e5be37bULL,+ 0x486d8ffa696946fcULL,0x50fbc6d8b9cba56dULL,0x7e3d423e90f35a15ULL,0x7c3da195c0dd962cULL,0xe673fdb03cfd5d8bULL,0x0704b7c2889dfca5ULL,0xf6ce581ff52305aaULL,0x399d49eb914d5e53ULL,+ 0x7966afbb10e6d950ULL,0x37e4a4c4e2bf970aULL,0x23d0c8559d54ca2aULL,0x13d62865fee39a10ULL,0x15f53c38d3bd15e9ULL,0x014b8bed84a80bccULL,0x10674c77bfd8f608ULL,0x4dfab986c93fbfefULL,+ 0x24c97c367b92d453ULL,0xd2c271a2249a26c0ULL,0x60eb4b2b89d14a39ULL,0x1198de20432e8005ULL,0x9eabea75799b80d9ULL,0xab6e0c2b8f826ae5ULL,0xca004eedd10061ecULL,0x31a9f439e99c4fd8ULL,+ 0x734c8b75b5498a7cULL,0xaeccad8a29f64c2dULL,0x95dd54fa295b1677ULL,0x383902a0b4c54968ULL,0x78cb276feb9d33a9ULL,0x00aedca1af552869ULL,0xa01d14594c5c1630ULL,0xfeba17067cf7d50dULL,+ 0x380a496d6ec293cdULL,0x733dbda78e7051f5ULL,0x037e388db849140aULL,0xee4b32b05946dbf6ULL,0xb1c4fda9cae368d1ULL,0x5001a7b0fdb0b2f3ULL,0x6df593742e3ac46eULL,0x4af675f239b3e656ULL,+ 0x1a1fffdcc01b0a46ULL,0x07ad675f83f843c2ULL,0xbcec2d076738e81aULL,0x910aec75aa8b7da8ULL,0x13b4d740a4509ba7ULL,0x057010734c7b8216ULL,0x3d75c8f71591f1e5ULL,0x134c1b6f0dfe1d90ULL,+ 0xb20e7c44d67826ebULL,0x1212d3cfac379637ULL,0x614f67877de03a5dULL,0x7538a2fc802baa26ULL,0x133c37a19d252415ULL,0x7db390506eb4b587ULL,0x5d40d7574c49d1d9ULL,0xf1126b99a801c4baULL,+ 0x39a7aeb9c56729fcULL,0x21a59448e7a8bd85ULL,0xd7c6da5d049d10c6ULL,0x93a4c4a8c5197afbULL,0xd185539c25933861ULL,0x4994bcba27494d9dULL,0xef033de14ce7bfa9ULL,0x22e9b000321f9236ULL,+ 0x44e3811039949296ULL,0x5b63827b361db1b5ULL,0x3e5323ed206eaff5ULL,0x942370d2c21f4290ULL,0xf2caaf2ee0d985a1ULL,0x192cc64b7239846dULL,0x7c0b8f47ae6312f8ULL,0x7dc61f9196620108ULL,+ 0x4f7081e144cc3addULL,0xd5ffa1d687be82cfULL,0x89890b6c0edd6472ULL,0xada26e1a3ed17863ULL,0x276f271563483caaULL,0xe6924cd92f6077fdULL,0x05a7fe980a466e3cULL,0xf1c794b0b1902d1fULL,+ 0x3d2b24b9eb7926b8ULL,0xbff88cb3cdbe5509ULL,0xd0f399afe4dd640bULL,0x3c5fe1302f76ed45ULL,0x6f3562f43764fb3dULL,0x7b5af3183151b62dULL,0xd5bd0bc7d79ce5f3ULL,0xfdaf6b20ec66890fULL,+ 0x32027fe891e5d7d3ULL,0xf14b7d1773a07678ULL,0xf88497b3c0dfdd61ULL,0xf7c2eec02a8c4f48ULL,0xaa5573f43756e621ULL,0xc013a2401825b948ULL,0x1c03b34563878572ULL,0xa0472bea653a4184ULL,+ 0x6772b0e5ab4b35a2ULL,0x1d8b6001f5eeaacfULL,0x728f7ce4795b9580ULL,0x4a20ed2a41fb81daULL,0x9f685cd44fec01e6ULL,0x3ed7ddcca7ff50adULL,0x460fd2640c2d97fdULL,0x3a241426eb82f4f9ULL,+ 0x29ae2cf983dfedc9ULL,0xf84371348d87631aULL,0xaf5717117429c8d2ULL,0x18d15867146d9272ULL,0x83053ecf69769bb7ULL,0xc55eb856c479ab82ULL,0x5ef7791c21b0f4b2ULL,0xaa5956ba3d491525ULL,+ 0x84cfbfa1c5c5ea50ULL,0xd3baf14c67960681ULL,0x263984030dd50942ULL,0xe4b7839c4716a663ULL,0xd5f1f794e7de6dc0ULL,0x5cd0f4d4622aa7ceULL,0x5295f3f159acfeecULL,0x8d933552953e0607ULL,+ 0xe652533b3cef0d7dULL,0xd94f7b182bbb4381ULL,0x838752be0e80f500ULL,0x8e6e24889e9c9bfbULL,0xc975169716caca6aULL,0x866c49d838531ad9ULL,0xc917e2397151ade1ULL,0x2d016ec16037c407ULL,+ 0x80009862d5d721d5ULL,0x0c3357a35bd3a182ULL,0x27f3a83b7aa2cda4ULL,0xb58ae74ef6f83085ULL,0x2a911a812e6dad6bULL,0xde286051f43d6c5bULL,0x4bdccc41f996c4d8ULL,0xe7312ec00ae1e24eULL,+ 0x903f6e3960e913afULL,0xb2b58bee98bf140dULL,0x9deff025354890b8ULL,0x155810068d2e924eULL,0xb5755db493c95e5bULL,0x3fac42f0dae20eb8ULL,0x9377c8c109b6d8e0ULL,0xa43e2b46ab47ceffULL,+ 0x5f57b2fbfacfa459ULL,0x874b1498c1b5aa6bULL,0xb9e89acac4db2092ULL,0x1362bf8ddf4381daULL,0x25d76830b76328a0ULL,0x38188b7098572ae4ULL,0xb43e941429132f7dULL,0x7895a29f22dd42c9ULL,+ 0xcbde78dd5e22cbb2ULL,0xf449c85b76bb4391ULL,0x4289f357b6a4273bULL,0x9fce23fd48e84a19ULL,0xcfc32730939eb3b4ULL,0x8b3d982c16c32280ULL,0x5ac234bad5f1346cULL,0x781954b470769fc9ULL,+ 0x6faf68feaae6ee70ULL,0x78f4cc155602b0c9ULL,0x7e3321a86e94052aULL,0x2fb3a0d6734d5d80ULL,0xf3b98f3bb25a43baULL,0x30bf803119ee2951ULL,0x7ffee43321b0612aULL,0x12f775e42eb821d0ULL,+ 0x4fdff805f57209b5ULL,0x9bd65ac3f952ac8dULL,0x02a3abd3c7969a6fULL,0x1359927ef523775fULL,0xe09b463f88d2e861ULL,0x661d2199623287c3ULL,0x821e64495a70eb7aULL,0x0afbbb1dd67dc684ULL,+ 0x7418e3d3acff89f9ULL,0x227f16aed852251fULL,0xdd5bc6e4eb84658bULL,0xf066b9c8f90a9f7eULL,0xc2369071800a7f87ULL,0x383ddc0d5a72862aULL,0x5b48465d8a776da5ULL,0x3d82f64f5e2d8318ULL,+ 0x5852104b87453b28ULL,0x073e8128b387344dULL,0x300e78e4817cfc08ULL,0x3a82ed4799362088ULL,0xe222304c88de46a4ULL,0x666c94fd57fadf4aULL,0x40b2d08ea0c8e108ULL,0x4b2955b909e050faULL,+ 0xf8d112e76e6485b3ULL,0x4d3e24db771c52f8ULL,0x48e3ee41684a2f6dULL,0x7161957d21d95551ULL,0x19631283cdb12a6cULL,0xbf3fa8822e50e164ULL,0xf6254b633166cc73ULL,0x3aefa7aeaee8cc38ULL,+ 0x79b0fe623b36f9fdULL,0x26543b23fde19fc0ULL,0x136e64a0958482efULL,0x23f637719b095825ULL,0x14cfd596b6a1142eULL,0x5ea6aac6335aac0bULL,0x86a0e8bdf3081dd5ULL,0x5fb89d79003dc12aULL,+ 0x0f0165fce3779ee3ULL,0xe00e7f9dbd495d9eULL,0x1fa4efa220284e7aULL,0x4564bade47ac6219ULL,0x90e6312ac4708e8eULL,0x4f5725fba71e9adfULL,0xe95f55ae3d684b9fULL,0x47f7ccb11e94b415ULL,+ 0xda3a77e5522e6b69ULL,0x69c908c3bbcd6c18ULL,0x1f1b9e48d924fd56ULL,0x37c64e36aa4bb3f7ULL,0x5a4fdbdfee478d7dULL,0xba75c8bc0193f7a0ULL,0x84bc1e8456cd16dfULL,0x1fb08f0846fad151ULL,+ 0x3617890361a341c1ULL,0x3604dc600cfd6142ULL,0x022295eb8533316cULL,0x3dbde4ac44af2922ULL,0x898afc5d1c7eef69ULL,0x58896805d14f4fa1ULL,0x05002160203c21caULL,0x6f0d1f3040ef730bULL,+ 0x48201b4b12cfe297ULL,0x3eee129c292f74e5ULL,0xe1fe114ec9e874e8ULL,0x899b055c92c5fc41ULL,0x4e477a643a39c8cfULL,0x82f09efe78963cc9ULL,0x6fd3fd8fd333f863ULL,0x85132b2adc949c63ULL,+ 0xbd9b8b1dbe7a2af3ULL,0xec51caa94fb74a72ULL,0xb9937a4b63879697ULL,0x7c9a9d20ec2687d5ULL,0x1773e44f6ef5f014ULL,0x8abcf412e90c6900ULL,0x387bd0228142161eULL,0x50393755fcb6ff2aULL,+ 0x766e072232398baaULL,0x205fee425cfca031ULL,0xa49f53417a029cf2ULL,0xa88c68b84023890dULL,0xbc2750417337aaa8ULL,0x9ed364ad0eb384f4ULL,0xe0816f8529aba92fULL,0x2e9e194104e38a88ULL,+ 0xfabf770977f7195aULL,0x8ec86167adeb838fULL,0xea1285a8bb4f012dULL,0xd68835039a3eab3fULL,0xee5d24f8309004c2ULL,0xa96e4b7613ffe95eULL,0x0cdffe12bd223ea4ULL,0x8f5c2ee5b6739a53ULL,+ 0xecace1dda1887395ULL,0x40960f36932a65deULL,0x9611ff5c3aa95529ULL,0xc58215b07c1e5a36ULL,0xd48c9b58f0e1a524ULL,0xb406856bf590dfb8ULL,0xc7605e049cd95662ULL,0x0dd036eea33ecf82ULL,+ 0x3d61333959145a65ULL,0xcd9bc368fa406337ULL,0x82d11be32d8a52a0ULL,0xf6877b2797a1c590ULL,0x837a819bf5cbdb25ULL,0x2a4fd1d8de090249ULL,0x622a7de774990e5fULL,0x840fa5a07945511bULL,+ 0xfe2893277946d3f9ULL,0xe132bd2407472273ULL,0xeeeb510c1eb6ae86ULL,0x777708c5f0595067ULL,0x18e2c8cd1297029eULL,0x2c61095cbbf9305eULL,0xe466c2586b85d6d9ULL,0x8ac06c36da1ea530ULL,+ 0xe58e90b36b0cf82eULL,0x6438d2462615b5e7ULL,0x07b1f8fc669c145aULL,0xb0d8b2da36f1e1cbULL,0x54d5dadbd9184c4dULL,0x3dbb18d5f93d9976ULL,0x0a3e0f56d1147d47ULL,0x2afa8c8da0a48609ULL,+ 0x871239ad653ae326ULL,0x14bcf72aa74cbb43ULL,0x8737650e20d4c083ULL,0x3df86536110ed4afULL,0xd2d86fe7b53ca555ULL,0x688cb00dabd5d538ULL,0xcf81bda31ad38468ULL,0x7ccfe3ccf01167b6ULL,+ 0x26e08c07e3533d77ULL,0xd7222e6a2e341c99ULL,0x9d60ec3d8d2dc4edULL,0xbdfe0d8f7c476cf8ULL,0x1fe59ab61d056605ULL,0xa9ea9df686a8551fULL,0x8489941e47fb8d8cULL,0xfeb874eb4a7f1b10ULL,+ 0x61fc181060a71676ULL,0xe852d1a8f66a8ad1ULL,0x172bbd656417231eULL,0x0d6de7bd3babb11fULL,0x6fde6f88c8e347f8ULL,0x1c5875479bd99cc3ULL,0x78e54ed034076950ULL,0x97f0f334796e83baULL,+ 0xed406aa9bd763802ULL,0xc21486a065303da1ULL,0x61ae291ec7e62ec4ULL,0x622a0492df99333eULL,0x7fd80c9dbb7a8ee0ULL,0xdc2ed3bc6c01aedbULL,0x35c35a1208be74ecULL,0xd540cb1a469f671fULL,+ 0xa7a8746a584c5e20ULL,0x267e4ea1b9dc7035ULL,0x593a15cfb9548c9bULL,0x5e6e21354bd012f3ULL,0xdf31cc6a8c8f936eULL,0x8af84d04b5c241dcULL,0x63990a6f345efb86ULL,0x6fef4e61b9b962cbULL,+ 0xf6368f0925722608ULL,0x131260db131cf5c6ULL,0x40eb353bfab4f7acULL,0x85c7888037eee829ULL,0x4c1581ffc3bdf24eULL,0x5bff75cbf5c3c5a8ULL,0x35e8c83fa14e6f40ULL,0xb81d1c0f0295e0caULL,+ 0xf2efe23d442a8ad1ULL,0xc3816a7d06b9c164ULL,0xa9df2d8bdc0aa5e5ULL,0x191ae46f120a8e65ULL,0x83667f8700611c5bULL,0x83171ed7ff109948ULL,0x33a2ecf8ca695952ULL,0xfa4a73eef48d1a13ULL,+ 0xfcde7cc8f43a730fULL,0xe89b6f3c33ab590eULL,0xc823f529ad03240bULL,0x82b79afe98bea5dbULL,0x568f2856962fe5deULL,0x0c590adb60c591f3ULL,0x1fc74a144a28a858ULL,0x3b662498b3203f4cULL,+ 0x48fc4ed082dd1b6aULL,0x5783a13867b703afULL,0x2463cb9a005d6aaaULL,0xd31ec55c706ecd43ULL,0x9f8ed33f8e9a7641ULL,0x625453ed098d9e7aULL,0xa3beade4ec887493ULL,0x442b80505a795566ULL,+ 0x91e3cf0d6c39765aULL,0xa2db3acdac3cca0bULL,0x288f2f08cb953b50ULL,0x2414582ccf43cf1aULL,0x8dec8bbc60eee9a8ULL,0x54c79f02729aa042ULL,0xd81cd5ec6532f5d5ULL,0xa672303acf82e15fULL,+ 0x46df582d3bfab839ULL,0x92474e042f8adadeULL,0x36a7766a147a1bc3ULL,0xb6940f540dc0f979ULL,0x44738ef2f2759f25ULL,0x9dd95789a719f4c6ULL,0x2859b7f40750c345ULL,0x5e788bf2b22180d5ULL,+ 0x376aafa8719c0563ULL,0xcd8ad2dcbc5fc79fULL,0x303fdb9fcb750cd3ULL,0x14ff052f4418b08eULL,0xf75084cf3e2d6520ULL,0x7ebdf0f8144ed509ULL,0xf43bf0f2d3f25b98ULL,0x86ad71cfa354d837ULL,+ 0xa839c9fdfd67ca25ULL,0x023e626860f2015cULL,0x2414a7930e7b2a65ULL,0x92dbe372b13edcbbULL,0xf64981ee64c2200fULL,0x94fb9cdf8446f2f3ULL,0x01411a6a3f1367bbULL,0x7985c1915a1e8331ULL,+ 0xb827fe9226f43572ULL,0xdfd3ab5b5d824758ULL,0x315dd23a539094c1ULL,0x85c0e37a66623d68ULL,0x575c79727be19ae0ULL,0x616a3396df0d36b5ULL,0xa1ebb3c826b1ff7eULL,0x635b9485140ad453ULL,+ 0xc8123c6037e2efeaULL,0x8d49b502034a96f6ULL,0x466a346b973e4a95ULL,0xf176b5bab7de00ffULL,0x1c58fa3b82dfa945ULL,0x2eb27a9609e429aeULL,0x57c67a67a12b187cULL,0xb155ba82e2298bbaULL,+ 0x92bf3cdada430c0bULL,0x4702850e3a96dac6ULL,0xc91cf0a515ac326aULL,0x95de4f49ab8c25e4ULL,0xb01bad09e265c17cULL,0x24e45464087b3881ULL,0xd43e583ce1fac5caULL,0xe17cb3186ead97a6ULL,+ 0xf1a542073d99bcfaULL,0x59db703ce8becf6dULL,0x2e455142d2459569ULL,0xb0ee5143a901b910ULL,0xfc05d451e26d994fULL,0x7a6062b41360caafULL,0xdf1ded5f4fa639b1ULL,0xaf930348d335b8b0ULL,+ 0x6cc3924374dcec46ULL,0x33cfc02d54c2b73fULL,0x82917844f26cd99cULL,0x8819dd95d1773f89ULL,0x09572aa60871f427ULL,0x8e0cf365f6f01c34ULL,0x7fa52988bff1f5afULL,0x4eb357eae75e8e50ULL,+ 0x3d8f248a21fd0861ULL,0xade3bd649bd5a4b6ULL,0xcb56c953c2e2a6bfULL,0x699cd2b5287d6c5fULL,0xdebce1be47d05e8fULL,0x1a4fbb13a8f53732ULL,0x97163beaa5852b08ULL,0x92c49e6ceec6987aULL,+ 0xd9d0c8c4868af75dULL,0xd7325cff45c8c7eaULL,0xab471996cc81ecb0ULL,0xff5d55f3611824edULL,0xbe3145411977a0eeULL,0x5085c4c5722038c6ULL,0x2d5335bff94bb495ULL,0x894ad8a6c8e2a082ULL,+ 0x540234b22c11bb37ULL,0x2d0366dded4c74a3ULL,0xf9a968daeec5f25dULL,0x3660106867b63142ULL,0x07cd6d2c68d7b6d4ULL,0xa8f74f090c842942ULL,0xe27514047768b1eeULL,0x4b5f7e89fe62aee4ULL,+ 0xf2369f0b879fbbedULL,0x0ff0ae86da9d1869ULL,0x5251d75956766f45ULL,0x4984d8c02be8d0fcULL,0x7ecc95a6d21008f0ULL,0x29bd54a03a1a1c49ULL,0xab9828c5d26c50f3ULL,0x32c0087c51d0d251ULL,+ 0x47feeb6662b5f3afULL,0xcefab5610abb3734ULL,0x449de60e19f35cb1ULL,0x39f8db14157f0eb9ULL,0xffaecc5b3c61bfd6ULL,0xa5a4d41d41216703ULL,0x7f8fabed224e1cc2ULL,0x0d5a8186871ad953ULL,+ 0x190d8ea601799a52ULL,0xa20cec41b86d2952ULL,0x3062ffb27fff2a7cULL,0x741b32e579f19d37ULL,0xf80d81814eb57d47ULL,0x7a2d0ed416aef06bULL,0x09735fb01cecb588ULL,0x1641caaac6061f5bULL,+ 0xae2ad171656e8c3aULL,0xc0e2a4631acd0705ULL,0x006f6a8aa0b6055cULL,0xaf4513d72b65a26eULL,0x3f549e14d616d5bcULL,0x64ee395571253b1fULL,0xe8b10bc1b8ce243aULL,0xbcbeace5913a4e77ULL,+ 0x68d32256f779d6a7ULL,0x20423b4d19e7284eULL,0xde19aa1b38f3b153ULL,0x73d0b6c28444f703ULL,0x666161489c64e6a3ULL,0x99587c3737256224ULL,0x6f5277fe61331563ULL,0x7174ad4aa656502eULL,+ 0xec1ffc920133918dULL,0x15d9bf5eb2c9ef97ULL,0x7885b542fc6cbb9aULL,0x8abe64535720cf5dULL,0x4e715dced4ec68abULL,0x57a67614279c24a3ULL,0x788ed52a31bb61cfULL,0xaba82444f437a003ULL,+ 0x7f99824f20151427ULL,0x206828b692430206ULL,0xaa9097d7e1112357ULL,0xacf9a2f209e414ecULL,0xdbdac9da27915356ULL,0x7e0734b7001efee3ULL,0x54fab5bbd2b288e2ULL,0x4c630fc4f62dd09cULL,+ 0x6d883e66bd70a5e1ULL,0x9bd884c1d05de713ULL,0x48d9d445d4d8487dULL,0x8440cd8b0eeae405ULL,0xa3cd0f293d26f83eULL,0x3fd9453022a3c5e4ULL,0x63a078663ffa2ca7ULL,0xbfeadd2900d4a097ULL,+ 0x13aea559d68432baULL,0x940043fbd33915dbULL,0x476c7c94e2e8da08ULL,0x6b1630c4443065bbULL,0xd6d8546d19f06c75ULL,0x7e1e98c22eb35abdULL,0x751c9310f0157d8eULL,0xdef84327f6fa6075ULL,+ 0x765b993c3a7a4e0eULL,0xfb8f4aef9d79d314ULL,0x5ea2c50e2a19eb24ULL,0x925016e5b891bc8cULL,0x8f70afdc3ad1ece7ULL,0x0abba84cf08fabe2ULL,0x0a9922c815f6132bULL,0x6c0213735d076d77ULL,+ 0x00af2615a4453961ULL,0x1705494b993d112cULL,0x0032e12aa1cdd652ULL,0x0ebfa612046d9cb3ULL,0x9f03a9f31b63728cULL,0x8f3618a2de022b05ULL,0xd5b24d903e77c5c9ULL,0x837838a372acb77cULL,+ 0xfe65cbd98fceb047ULL,0xde872ef53f8b11a1ULL,0x9aba0d3d8fec802fULL,0x139f1d329a9f381dULL,0x0721aed9c587958dULL,0x066a015cb9f6a7daULL,0x059ec4e3ed5d9d06ULL,0x144285716cbaca1fULL,+ 0x66fe0fffe298cdf5ULL,0x3f61bea47b2e51b6ULL,0x7d372117bad3afa4ULL,0x6521a09cef656e2fULL,0xb3b8c966e8a58fe7ULL,0x25203a115a47ebc7ULL,0xfe81588d5c4be573ULL,0x6132e2f31f49a03cULL,+ 0xec1ab0130f8c2c99ULL,0x60e8968ff17725c2ULL,0xe1a4a593940a980bULL,0x15ed15b020e9ccb1ULL,0x77d754cc64a00becULL,0x90d09c3341687382ULL,0x294fe02dc31fb651ULL,0x8372cd1a1c94ae53ULL,+ 0x8537107a1ac2703bULL,0xb49258d86bc857b5ULL,0x57df14debcdaccd1ULL,0x24ab68d7c4ae8529ULL,0x7ed8b5d4734e59d0ULL,0x5f8740c8c495cc80ULL,0x84aedd5a291db9b3ULL,0x80b360f84fb995beULL,+ 0x55d5c68da61a76faULL,0x598b441dca1554dcULL,0xd39923b9773b279cULL,0x33331d3c36bf9efcULL,0x2d4c848e298de399ULL,0xcfdb8e77a1a27f56ULL,0x94c855ea57b8ab70ULL,0xdcdb9dae6f7879baULL,+ 0x4c4f07367f636a38ULL,0x9f943fb70e76d5cbULL,0xb03510baa8b68b8bULL,0xc246780a9ed07a1fULL,0x3c0514156d549fc2ULL,0xc2953f31607781caULL,0x955e2c69d8d95413ULL,0xb300fadc7bd282e3ULL,+ 0xa14b1163c27901b4ULL,0xfd9236e0899b8bf3ULL,0x42b091eccbc6da0aULL,0xbb1dac6f5ad1d297ULL,0x80e61d53a91cf76eULL,0x4110a412d31f1ee7ULL,0x2d87c3ba13efcf77ULL,0x1f374bb4df450d76ULL,+ 0x202886024147519aULL,0xd0981eac26b372f0ULL,0xa9d4a7caa785ebc8ULL,0xd953c50ddbdf58e9ULL,0x9d6361ccfd590f8fULL,0x72e9626b44e6c917ULL,0x7fd9611022eb64cfULL,0x863ebb7e9eb288f3ULL,+ 0x15e10a0a097e4403ULL,0xcb3d0a8619854665ULL,0x88d8e211d67d4826ULL,0xb39af66e0b9d2839ULL,0xa5f94588bd475ca8ULL,0xe06b7966c077b80bULL,0xfedb1485da27c26cULL,0xd290d33afe0fd5e0ULL,+ 0x686202f31306583dULL,0x05b10da0437c622eULL,0xbf9aaa0f076a7bc8ULL,0x25e94efb8f8f4e43ULL,0x8a35c9b7fa3dc26dULL,0xe0e5fb9396ff03c5ULL,0xa77e3843ebc394ceULL,0xcede65958361de60ULL,+ 0xbf9075090c22b540ULL,0x2cde42aab7c267d4ULL,0xba18f9ed5ab0d693ULL,0x3ba62aa66e4660d9ULL,0xb24bf97bab9ea96aULL,0x5d039642e3b60e32ULL,0x4e6a45067c4d9bd5ULL,0x666c5b9e7ed4a6a4ULL,+ 0x877b7cf5678a31b0ULL,0xd50301ae3998b620ULL,0x734257c5c00fb396ULL,0xf9fb18a004e672a6ULL,0xff8bd8ebe8758851ULL,0x1e64e4c65d99ba44ULL,0x4b8eaedf7dfd93b7ULL,0xba2f2a9804e76b8cULL,+ 0xae02a2f09b56ddbdULL,0x1339b5ac8a2f1cf3ULL,0xf2b569c7839dff0dULL,0xb0b9e864fee9a43dULL,0x4ff8ca4177bb064eULL,0x145a2812fd249f63ULL,0x3ab7beacf86f689aULL,0x9bafec2701d35f5eULL,+ 0xbba23fddae57c7b7ULL,0x345342f21b932522ULL,0xfd9c80fe556d4aa3ULL,0xa03907ba6525bb61ULL,0x38b010e1ff218933ULL,0xc066b654aa52117bULL,0x8e14192094f2e6eaULL,0x66a27dca0d32f2b2ULL,+ 0xb2e6b121fbabbe92ULL,0x281850fbe1330076ULL,0x093581ec97890015ULL,0x69b1dded75ff77f5ULL,0x7cf0b18fab105105ULL,0x953ced31a89ccfefULL,0x3151f85feb914009ULL,0x3c9f1b8788ed48adULL,+ 0xa18f07e0e90fb21eULL,0x00fd2b80bba7fca1ULL,0x20387f2795cd67b5ULL,0x5b89a4e7d39707f7ULL,0x8f83ad3f894407ceULL,0xa0025b946c226132ULL,0xc79563c7f906c13bULL,0x5f548f314e7bb025ULL,+ 0xff7589494fde0c1fULL,0xbf8a1abee5b6ec20ULL,0x702278fb87e1db6cULL,0xc447ad7a35ed658fULL,0x48d4aa3803d0ccf2ULL,0x80acb338819a7c03ULL,0x9bc7c89e6e17ceccULL,0x46736b8b03be1d82ULL,+ 0x2126f742d43b5eaaULL,0x054a0766dfa59b85ULL,0x9d0d5e36126bfd45ULL,0xa1f8fbd7384f8a8fULL,0x317680f5d563fcccULL,0x48ca5055f280a928ULL,0xe00b81b227b578cfULL,0x10aad9182994a514ULL,+ 0xe63f301f358bcdc0ULL,0x07689e990a9d47f8ULL,0x1f689e2f4f43d43aULL,0x4d542a1690920904ULL,0xaea293d59ca0a707ULL,0xd061fe458ac68065ULL,0x1033bf1b0090008cULL,0x29749558c08a6db6ULL,+ 0x0ee6d3a7c35d8794ULL,0x042e65580356bae5ULL,0x9f59698d643322fdULL,0x9379ae1550a61967ULL,0x64b9ae62fcc9981eULL,0xaed3d6316d2934c6ULL,0x2454b3025e4e65ebULL,0xab09f647f9950428ULL,+ 0xb2083a1222248accULL,0x1f6ec0ef3264e366ULL,0x5659b7045afdee28ULL,0x7a823a40e6430bb5ULL,0x24592a04e1900a79ULL,0xcde09d4ac9ee6576ULL,0x52b6463f4b5ea54aULL,0x1efe9ed3d3ca65a7ULL,+ 0xe27a6dbe305406ddULL,0x8eb7dc7fdd5d1957ULL,0xf54a6876387d4d8fULL,0x9c479409c7762de4ULL,0xbe4d5b5d99b30778ULL,0x25380c566e793682ULL,0x602d37f3dac740e3ULL,0x140deabe1566e4aeULL,+ 0x4481d067afd32acfULL,0xd8f0fccae1f71ccfULL,0xd208dd0cb596f2daULL,0xd049d7309aad93f9ULL,0xc79f263d42ab580eULL,0x09411bb123f707b4ULL,0x8cfde1ff835e0edaULL,0x7270749090f03402ULL,+ 0xeaee6126c49a861eULL,0x024f3b65e14f0d06ULL,0x51a3f1e8c69bfc17ULL,0xc3c3a8e9a7686381ULL,0x3400752cb103d4c8ULL,0x02bc46139218b36bULL,0xc67f75eb7651504aULL,0xd6848b56d02aebfaULL,+ 0xbd9802e6c30fa92bULL,0x5a70d96d9a552784ULL,0x9085c4ea3f83169bULL,0xfa9423bb06908228ULL,0x2ffebe12fe97a5b9ULL,0x85da604971b99118ULL,0x9cbc2f7f63178846ULL,0xfd96bc709153218eULL,+ 0x958381db1782269bULL,0xae34bf792597e550ULL,0xbb5c60645f385153ULL,0x6f0e96afe3088048ULL,0xbf6a021577884456ULL,0xb3b5688c69310ea7ULL,0x17c9429504fad2deULL,0xe020f0e517896d4dULL,+ 0x730ba0ab0976505fULL,0x567f6813095e2ec5ULL,0x470620106331ab71ULL,0x72cfa97741d22b9fULL,0x33e55ead8a2373daULL,0xa8d0d5f47ba45a68ULL,0xba1d8f9c03029d15ULL,0x8f34f1ccfc55b9f3ULL,+ 0xcca4428dbbe5a1a9ULL,0x8187fd5f3126bd67ULL,0x0036973a48105826ULL,0xa39b6663b8bd61a0ULL,0x6d42deef2d65a808ULL,0x4969044f94636b19ULL,0xf611ee47dd5d564cULL,0x7b2f3a49d2873077ULL,+ 0x94157d45300eb294ULL,0x2b2a656e169c1494ULL,0xc000dd76d3a47aa9ULL,0xa2864e4fa6243ea4ULL,0x82716c47db89842eULL,0x12dfd7d761479fb7ULL,0x3b9a2c56e0b2f6dcULL,0x46be862ad7f85d67ULL,+ 0x03b0d8dd0f82b214ULL,0x460c34f9f103cbc6ULL,0xf32e5c0318d79e19ULL,0x8b8888baa84117f8ULL,0x8f3c37dcc0722677ULL,0x10d21be91c1c0f27ULL,0xd47c8468e0f7a0c6ULL,0x9bf02213adecc0e0ULL,+ 0x0baa7d1242b48b99ULL,0x1bcb665d48424096ULL,0x8b847cd6ebfb5cfbULL,0x87c2ae569ad4d10dULL,0xf1cbb1220de36726ULL,0xe7043c683fdfbd21ULL,0x4bd0826a4e79d460ULL,0x11f5e5984bd1a2cbULL,+ 0x97554160b7fe7b6eULL,0x7d16189a400a3fb2ULL,0xd73e9beae328ca1eULL,0x0dd04b97e793d8ccULL,0xa9c83c9b506db8ccULL,0x5cd47aaecf38814cULL,0x26fc430db64b45e6ULL,0x079b5499d818ea84ULL,+ 0xebb01102c1c24a3bULL,0xca24e5681c161c1aULL,0x103eea6936f00a4aULL,0x9ad76ee876176c7bULL,0x97451fc2538e0ff7ULL,0x94f898096604b3b0ULL,0x6311436e3249cfd7ULL,0x27b4a7bd41224f69ULL,+ 0x03b5d21ae0ac2941ULL,0x279b0254c2d31937ULL,0x3307c052cac992d0ULL,0x6aa7cb92efa8b1f3ULL,0x5a1825800d37c7a5ULL,0x13380c37342d5422ULL,0x92ac2d66d5d2ef92ULL,0x035a70c9030c63c6ULL,+ 0xc16025dd4ce4f152ULL,0x1f419a71f9df7c06ULL,0x6d5b221491e4bb14ULL,0xfc43c6cc839fb4ceULL,0x49f06591925d6b2dULL,0x4b37d9d362186598ULL,0x8c54a971d01b1629ULL,0xe1a9c29f51d50e05ULL,+ 0x5109b78571ba1861ULL,0x48b22d5cd0c8f93dULL,0xe8fa84a78633bb93ULL,0x53fba6ba5aebbd08ULL,0x7ff27df3e5eea7d8ULL,0x521c879668ca7158ULL,0xb9d5133bce6f1a05ULL,0x2d50cd53fd0ebee4ULL,+ 0x889f6d65533ef217ULL,0x7158c7e4c3ca2e87ULL,0xfb670dfbdc2b4167ULL,0x75910a01844c257fULL,0xf336bf07cf88577dULL,0x22245250e45e2aceULL,0x2ed92e8d7ca23d85ULL,0x29f8be4c2b812f58ULL,+ 0xfbb9b2452133ffd9ULL,0x39a8b2f1830f1a20ULL,0x484bc97dd5a1f52aULL,0xd6aebf56a40eddf8ULL,0x32257acb76ccdac6ULL,0xaf4d36ec1586ff27ULL,0x8eaa8863f8de7dd1ULL,0x0045d5cf88647c16ULL,+ 0xc51e414351facc61ULL,0xbaf2647de68a25bcULL,0x8f5271a00ff872edULL,0x8f32ef993d2d9659ULL,0xca12488c7593cbd4ULL,0xed266c5d02b82fabULL,0x0a2f78ad14eb3f16ULL,0xc34049484d47afe3ULL,+ 0xa6f3d574c005979dULL,0xc2072b426a40e350ULL,0xfca5c1568de2ecf9ULL,0xa8c8bf5ba515344eULL,0x97aee555114df14aULL,0xd4374a4dfdc5ec6bULL,0x754cc28f2ca85418ULL,0x71cb9e27d3c41f78ULL,+ 0x09c1670209470496ULL,0xa489a5edebd23815ULL,0xc4dde4648edd4398ULL,0x3ca7b94a80111696ULL,0x3c385d682ad636a4ULL,0x6702702508dc5f1eULL,0x0c1965deafa21943ULL,0x18666e16610be69eULL,+ 0x6792fd350369c8e1ULL,0x9271aa62b9dc843bULL,0x8711a4b14d02e2abULL,0x02b2a3e27ee1a383ULL,0xb226e35f0e2b379bULL,0x3d3de39cd652ab25ULL,0xaca6d4c93b560106ULL,0xeced0cf4c95bd877ULL,+ 0x45beb4ca2a604b3bULL,0x56f651843a616762ULL,0xf52f5a70978b806eULL,0x7aa3978711dc4480ULL,0xe13fac2a0e01fabcULL,0x7c6ee8a5237d99f9ULL,0x251384ee05211ffeULL,0x4ff6976d1bc9d3ebULL,+ 0x8910507903605c39ULL,0xf0843d9ea142c96cULL,0xf374493416923684ULL,0x732caa2ffa0a2893ULL,0xb2e8c27061160170ULL,0xc32788cc437fbaa3ULL,0x39cd818ea6eda3acULL,0xe2e942399e2b2e07ULL,+ 0xdde0492316e043a2ULL,0x98a452611dd3d209ULL,0xeaf9f61bd431ebe8ULL,0x00919f4dbaf56abdULL,0xe42417db6d8774b1ULL,0x5fc5279c58e0e309ULL,0x64aa40613adf81eaULL,0xef419edabc627c7fULL,+ 0x3919759239ef620fULL,0x9d47284074fa29c4ULL,0x4e428fa39d416d83ULL,0xd1a7c25129f30269ULL,0x46076e1cd746218fULL,0xf3ad6ee8110d967eULL,0xfbb5f434a00ae61fULL,0x3cd2c01980d4c929ULL,+ 0xfa24d0537a4af00fULL,0x3f938926ca294614ULL,0x0d700c183982182eULL,0x801334434cc59947ULL,0xf0397106ec87c925ULL,0x62bd59fc0ed6665cULL,0xe8414348c7cca8b5ULL,0x574c76209f9f0a30ULL,+ 0x6967d39b0260e52aULL,0xd42585cc90653325ULL,0x0d9bd60521ca7954ULL,0x4fa2087781ed57b3ULL,0x60c1eff8e34a0bbeULL,0x56b0040c84f6ef64ULL,0x28be2b24b1af8483ULL,0xb2278163f5531614ULL,+ 0x95be42e2bb8b6a07ULL,0x64be74eeca23f86aULL,0xa73d74fd154ce470ULL,0x1c2d2857d8dc076aULL,0xb1fa1c575a887868ULL,0x38df8e0b3de64818ULL,0xd88e52f9c34e8967ULL,0x274b4f018b4cc76cULL,+ 0x59c81ec2c11c208bULL,0x240207da4e3a7234ULL,0x4957eb80f4a089d8ULL,0xc86960bc2137a072ULL,0xde1154fd7f1a932cULL,0xb517fe74d3f2fa17ULL,0x2d5d94557111c0ebULL,0x2aa3378980929d36ULL,+ 0x3f5c05b4f8b7559dULL,0x0be4c7acfae29200ULL,0xdd6d3ef756532accULL,0xf6c3ed87eea7a285ULL,0xe463b0a8f46ec59bULL,0x531d9b14ecea6c83ULL,0x3d6bdbafc2dc836bULL,0x3ee501e92ab27f0bULL,+ 0x8df275455922ac1cULL,0xa7b3ef5ca52b3f63ULL,0x8e77b21471de57c4ULL,0x31682c10834c008bULL,0xc76824f04bd55d31ULL,0xb6d1c08617b61c71ULL,0x31db0903c2a5089dULL,0x9c092172184e5d3fULL,+ 0x5ace5035ea6c3997ULL,0x54259aaac2610befULL,0xef18bb3f3c80dd39ULL,0x6910b95b5fc3fa39ULL,0xfce2f51043e09aeeULL,0xced56c9fa7675665ULL,0x10e265acd872db61ULL,0x6982812eae9fce69ULL,+ 0xb8fa3d931341ed7aULL,0x4223272ca7b59d49ULL,0x3dcb194783b8c4a4ULL,0x4e413c01ed1302e4ULL,0x6d999127e17e44ceULL,0xee86bf7533b3adfbULL,0xf6902fe625aa96caULL,0xb73540e4e5aae47dULL,+ 0xcc50ef6c872b4a60ULL,0xab2a34a44613521bULL,0x39c5c190983e15d1ULL,0x61dde5df59905512ULL,0xe417f6219f2275f3ULL,0x0750c8b6451d894bULL,0x75b04ab978b0bdaaULL,0x3bfd9fd4458589bdULL,+ 0xaafcbfabaf95894cULL,0x7b9bdc07276b2241ULL,0xeaf983625bdda48bULL,0x5977faf2a3fcb4dfULL,0xbed042ef052c4b5bULL,0x9fe87f71067591f0ULL,0xc89c73ca22f24ec7ULL,0x7d37fa9ee64a9f1bULL,+ 0xbd78148045ee2f40ULL,0x75e354af416b60cfULL,0xde0b58a18d49a8c4ULL,0xe40e94e2fa359536ULL,0xbd4fa59f62accd76ULL,0x05cf466a8c762837ULL,0xb5abda99448c277bULL,0x5a9e01bf48b13740ULL,+ 0xb51e55e6f2606a82ULL,0xe25f706190f2fb57ULL,0xacef6c2ab1a4e37cULL,0x864e359d5dcf2706ULL,0x479e6b187ce57316ULL,0x2cab25003a96b23dULL,0xed4898628ef16df7ULL,0x2056538cef3758b5ULL,+ 0xef69a0c3d41d3bd3ULL,0xb533b8c907a26bdeULL,0xe2801d97db2edf9fULL,0xdc4a8269e1877af0ULL,0x6c1c58513d590dbeULL,0x84632f6bee4e9357ULL,0xd36d36b779b33374ULL,0xb46833e39bbca2e6ULL,+ 0xcc7a64880a750c0fULL,0x39bacfe34e548e83ULL,0x3d418c760c110f05ULL,0x3e4daa4cb1f11588ULL,0x2733e7b55ffc69ffULL,0x46f147bc92053127ULL,0x885b2434d722df94ULL,0x6a444f65e6fc6b7cULL,+ 0x008be4bb346ac9cbULL,0x2e6cb02429811bb2ULL,0xa6ccc747f41540c1ULL,0xf119334efbf6de47ULL,0x4e6bffe9cc97fe6eULL,0x7f4b578bf3d82883ULL,0x459db722753dd1c7ULL,0x05843cd82066b495ULL,+ 0x7cb88cd5dbf2af33ULL,0xded9566eaf6b0eabULL,0xd1caf5488e40d844ULL,0x3ae59bd67ce1f67fULL,0xacf4ad33dd82429eULL,0xcc7ebd2bbc4467c7ULL,0xf4f6e95de783d011ULL,0x5197e39116e92db7ULL,+ 0xd4f2031885e7a4afULL,0x291bf9a0f7a6878dULL,0xadd8b6eebd051913ULL,0x174f5124f36be034ULL,0x2ac3364527f60189ULL,0xd8902eed8b37ec73ULL,0x546166a11cfdb42eULL,0x31c4e3b807076421ULL,+ 0x7de29dfdbc6ebdfbULL,0xa1ee450589de549bULL,0xfd7181aa3ef26a64ULL,0x003179eedf2f3980ULL,0x1bce4d30fd71bc78ULL,0xeb842b14be86a583ULL,0xe00125dc5eb85711ULL,0x9f586983ff11f405ULL,+ 0x5b5a089eb833eccbULL,0xc1b3077a7bc51c79ULL,0xe581157f9fbe0e93ULL,0xab487d695b29b172ULL,0xc72551082222f24bULL,0x338cd22cf6dd35dfULL,0x92010e6f5fc24afeULL,0xf8298f15681d46edULL,+ 0x2ce7f723042389edULL,0xdf7de0d5a54b1972ULL,0xb8ea2e142c251d75ULL,0xd22a4d37f4e8e8c8ULL,0xe99958566c29c8bcULL,0x9fefdbfe1d1e201eULL,0xb97d946edac885c9ULL,0xf6ea9767d38eac70ULL,+ 0x9aaca8e974e75a2eULL,0xcda6fc1eadac968fULL,0x3f6651bf46306befULL,0xc7445e4ecb2ed7f9ULL,0x584a12d8d1571ac1ULL,0x684846c4daf3a679ULL,0xcfc622a9863fbc43ULL,0x2f9e101dea6814f2ULL,+ 0x7a1a465ac3f16ea8ULL,0x115a461db2f1d11cULL,0x4767dd956c68a172ULL,0x3392f2ebd13a4698ULL,0xc7a99ccde526cdc7ULL,0x8e537fdc22292b81ULL,0x76d8cf69a6d39198ULL,0xffc5ff432446852dULL,+ 0x97b14f7ea90567e6ULL,0x513257b7b6ae5cb7ULL,0x85454a3c9f10903dULL,0xd8d2c9ad69bc3724ULL,0x38da93246b29cb44ULL,0xb540a21d77c8cbacULL,0x9bbfe43501918e42ULL,0xfffa707a56c3614eULL,+ 0x56c2e05b1cb76219ULL,0x0ec0bf9171567e7eULL,0xe7076f8661c4c910ULL,0xd67b085bbabc04d9ULL,0x9fb904595e93a96aULL,0x7526c1eafbdc249aULL,0x0d44d367ecdd0bb7ULL,0x953999179dc0d695ULL,+ 0x2ccbc583a4c506ecULL,0x957ed188d1acfe97ULL,0x8baed83312f1aea2ULL,0xef2a6cb48325362dULL,0x130dde428e195c43ULL,0xc842025a0e6050c6ULL,0x2da972a708686a5dULL,0xb52999a1e508b4a8ULL,+ 0x83f49167ceca9754ULL,0x426d2cf64b7939a0ULL,0x2555e355723fd0bfULL,0xa96e6d06c4f144e2ULL,0x4768a8dd87880e61ULL,0x15543815e508e4d5ULL,0x09d7e772b1b65e15ULL,0x63439dd6ac302fa0ULL,+ 0xb11df8e1698e04ccULL,0x877be203169005c8ULL,0x32749e8c4f3c6179ULL,0x2dbc9d0a7853fc05ULL,0x187d4f939454d937ULL,0xe682ce9db4800e1bULL,0xa9129ad8165e68e8ULL,0x0fe29735be7f785bULL,+ 0x31019ccf3a4434b4ULL,0xa34581111a7954dcULL,0xa9dac80de34972a7ULL,0xb043d05474f6b8ddULL,0x021c319e11137b1aULL,0x00a754ceed5cc03fULL,0x0aa2c794cbea5ad4ULL,0x093e67f470c015b6ULL,+ 0x20ac0351d598d710ULL,0x272c4166cb3a4da4ULL,0xdb82fe1aca71de1fULL,0x746e79f2d8f54b0fULL,0x6e7fc7364b573e9bULL,0x75d03f46fd4b5040ULL,0x5c1cc36d0b98d87bULL,0x513ba3f11f472da1ULL,+ 0x859d3145983c38b5ULL,0xb14f176c637abc8bULL,0x2793fb9dcaff7be6ULL,0xebe5a55f35a66a5aULL,0x7cec1dcd9f87dc59ULL,0x7c595cd3fbdbf560ULL,0x5b543b2226eb3257ULL,0x69080646c4c935fdULL,+ 0xdca3b70678a6513bULL,0x92ea4a2a9edb1943ULL,0x02642216db6e2dd8ULL,0x9b45d0b49fd57894ULL,0x114e70dbc69d11aeULL,0x1477dd194c57595fULL,0xbc2208b4ec77c272ULL,0x95c5b4d7db68f59cULL,+ 0xfe541fa47ea67c77ULL,0x952bd2afe3ea810cULL,0x791fef568d01d374ULL,0xa3a1c6210f11336eULL,0x5ad0d5a9c7ec6d79ULL,0xff7038af3225c342ULL,0x003c6689bc69601bULL,0x25059bc745e8747dULL,+ 0x9a75c80676cb2566ULL,0x8f76acb1b24892d9ULL,0x7ae7b9cc1f08fe45ULL,0x19ef73296a4907d8ULL,0x2db4ab715f228bf0ULL,0xf3cdea39817032d7ULL,0x0b1f482edcabe3c0ULL,0x3baf76b4bb86325cULL,+ 0x6aac688eadd70482ULL,0x708de92a7b4a4e8aULL,0x75b6dd73758a6eefULL,0xea4bf352725b3c43ULL,0x10041f2c87912868ULL,0xb1b1be95ef09297aULL,0x19ae23c5a9f3860aULL,0xc4f0f839515dcf4bULL,+ 0xc71e27bf8538a5c6ULL,0x195c63dd89abff17ULL,0xfd3152851b71e3daULL,0x9cbdfda7fa680fa0ULL,0x9db876ca849d7eabULL,0xebe2764b3c273271ULL,0x663357e3f208dceaULL,0x8c5bd833565b1b70ULL,+ 0x75900d7c2fa4f126ULL,0x08a3b8655c99a232ULL,0x2478b6bfdb25e0c3ULL,0x482cc2c271db2edfULL,0x37df7e645f321bb8ULL,0x8a93821b9a8005b4ULL,0x3fa2f10ccc8c1958ULL,0x0d3322182c269d0aULL,+ 0xba5514df3fd165e8ULL,0x499fd6a9061f8811ULL,0x72cd1fe0bfef9f00ULL,0x120a4bb979ad7e8aULL,0xf2ffd0955f4a5ac5ULL,0xcfd174f195a7a2f0ULL,0xd42301ba9d17baf1ULL,0xd2fa487a77f22089ULL,+ 0xb93452381d531696ULL,0x57201c0088cdde69ULL,0xdde922519a86afc7ULL,0xe3043895bd35cea8ULL,0x7608c1e18555970dULL,0x8267dfa92535935eULL,0xd4c60a57322ea38bULL,0xe0bf7977804ef8b5ULL,+ 0x6233ea68c094dbb5ULL,0xb77d062ed968d410ULL,0x3e719bbc58b3002dULL,0x68e7dd3d3dc49d58ULL,0x8d825740013a5e58ULL,0x213117473c9e3c1bULL,0x0cb0a2a77c99b6abULL,0x5c48a3b3c2f888f2ULL,+ 0xc7913e91991724f3ULL,0x5eda799c39cbd686ULL,0xddb595c763d4fc1eULL,0x6b63b80bac4fed54ULL,0x6ea0fc697e5fb516ULL,0x737708bad0f1c964ULL,0x9628745f11a92ca5ULL,0x61f379589a86967aULL,+ 0x5320fd610979e6b3ULL,0x1d0bd3e593d40723ULL,0x0ac006fcaa80baccULL,0xb1d9c60ed2002515ULL,0x610e7ed0af780b92ULL,0xf5bf446e80a9ce31ULL,0x441c011d3c20b54bULL,0x77f76da1191596c3ULL,+ 0x9af39b2caa665072ULL,0x78322fa4efd324efULL,0x3d153394c327bd31ULL,0x81d5f2713129dab0ULL,0xc72e0c42f48027f5ULL,0xaa40cdbc8536e717ULL,0xf45a657a2d369d0fULL,0xb03bbfc4ea7f74e6ULL,+ 0x7a04d5429b6a42eaULL,0xfa597e853daf41b9ULL,0x4c58ec27726b0b89ULL,0xed8eb16a030d43deULL,0x65e1e5e1ec9dcf57ULL,0xb7a770c1697cff81ULL,0x1e6d918f9f6e2b22ULL,0x7c277a9ac64e82b7ULL,+ 0x46a8c4180d738dedULL,0x6f1a5bb0e0de5729ULL,0xf10230b98ba81675ULL,0x32c6f30c112b33d4ULL,0x7559129dd8fffb62ULL,0x6a281b47b459bf05ULL,0x77c1bd3afa3b6776ULL,0x0709b3807829973aULL,+ 0x0875e0c1da36cb47ULL,0xfdf5b7cb1e0210f0ULL,0x7e0c7e4d3a3787c8ULL,0xf043f5262b1c741fULL,0x76df1b006d74d72dULL,0x0514df7338b45ba9ULL,0xaecf7c3e0a6b797aULL,0x5e30b285ddeaac39ULL,+ 0x8c26b232a3326505ULL,0x38d69272ee1d41bfULL,0x0459453effe32afaULL,0xce8143ad7cb3ea87ULL,0x932ec1fa7e6ab666ULL,0x6cd2d23022286264ULL,0x459a46fe6736f8edULL,0x50bf0d009eca85bbULL,+ 0x15c78f7d605238a5ULL,0xe9d87842448496abULL,0xcfcf75d0d210acc1ULL,0x2948f2295c8c14e2ULL,0xe81fd76de8daf0cbULL,0xd02d11e4a03be800ULL,0x0c4df3518778d30cULL,0x3482bc96965139cbULL,+ 0x0b825852877a21ecULL,0x300414a70f537a94ULL,0x3f1cba4021a9a6a2ULL,0x50824eee76943c00ULL,0xa0dbfcecf83cba5dULL,0xf953814893b4f3c0ULL,0x6174416248f24dd7ULL,0x5322d64de4fb09ddULL,+ 0x56b6cf278a448bbcULL,0x0ca898dfc85251daULL,0x9082cad836e79b24ULL,0x2e7b9ed31a8e51a7ULL,0xdc7d318a43e1c802ULL,0x4750e523cbf8689dULL,0x9887a072f0071b1aULL,0x52090f87814bfdc1ULL,+ 0x574473843d9325f3ULL,0xa9bef2d0f371cb84ULL,0x77d2188ba61e36c5ULL,0xbbd6a7d7c602df72ULL,0xba3aa9028f61bc0bULL,0xf49085ed6ed0b6a1ULL,0x8bc625d6ae6e8298ULL,0x832b0b1da2e9c01dULL,+ 0x5bebf2196196bc6eULL,0x0e66736bef097efdULL,0x1128f3b8ea87293aULL,0x2998e4056addfcdeULL,0x55cc31b85d16c961ULL,0x87a434e12418f056ULL,0x2e94aaccdc9fe819ULL,0x94a486c1a56490c6ULL,+ 0xa337c447f1f0ced1ULL,0x800cc7939492dd2bULL,0x4b93151dbea08efaULL,0x820cf3f8de0a741eULL,0xff1982dc1c0f7d13ULL,0xef92196084dde6caULL,0x1ad7d97245f96ee3ULL,0x319c8dbe29dea0c7ULL,+ 0x1ff2385bde259ec8ULL,0xf6b0836a30f67b0dULL,0x04cc65b006661cffULL,0x467e6358d4230f5cULL,0xce468c802dbed3d3ULL,0x7b984262f1920da6ULL,0x34d257421537479fULL,0x5c8aa88c87bb8de1ULL,+ 0xd3ea38717b82b99bULL,0x75922d4d470eb624ULL,0x8f66ec543b95d466ULL,0x66e673ccbee1e346ULL,0x6afe67c4b5f2b89aULL,0x3de9c1e6290e5cd3ULL,0x8c278bb6310a2adaULL,0x420fa3840bdb323bULL,+ 0x646f96796424c49bULL,0xf888dfe867c241c9ULL,0xe12d4b9324f68b49ULL,0x9a6b62d8a571df20ULL,0x81b4b26d179483cbULL,0x666f96329511fae2ULL,0xd281b3e4d53aa51fULL,0x7f96a7657f3dbd16ULL,+ 0x8553d37c051af62bULL,0xe9a998eb0bf94496ULL,0xe0844f9fb0d59aa1ULL,0x983fd558e6afb813ULL,0x9670c0ca65d69804ULL,0x732b22de6ea5ff2dULL,0xd7640ba95fd8623bULL,0x9f619163a6351782ULL,+ 0xf167b4e0bdefdd4fULL,0x69958465f366e401ULL,0x5aa368aba73bbec0ULL,0x121487097b240c21ULL,0x378c323318969006ULL,0xcb4d73cee1fe53d1ULL,0x5f50a80e130c4361ULL,0xd67f59517ef5212bULL,+ 0x332f81088cad38c0ULL,0x471b7e906bd68ae2ULL,0x56ac3fb20d8e27a3ULL,0xb54660db136b4b0dULL,0x123a1e11a6fd8de4ULL,0x44dbffeaa37799efULL,0x4540b977ce6ac17cULL,0x495173a8af60acefULL,+ 0xeb4437434573eab0ULL,0x11570dfbd1ac6031ULL,0xf7d9b45b44dd9afdULL,0xb8066add22067231ULL,0x15f92ad8f8a3f0b4ULL,0x9e0e4899e0ace2a2ULL,0xbdcd0aadfab38b80ULL,0x46506ae917020052ULL,+ 0x429a69f78fca399dULL,0xfe9e27d20207bb63ULL,0xec655ed68788f582ULL,0xa426d748adb75f6eULL,0x18695c02ca81c66dULL,0x84fb8d27a531d425ULL,0x3a3a8956deff48baULL,0xaf1d0d56766d2247ULL,+ 0x5a059565352c4b5cULL,0x49261531590bc3e2ULL,0x809f7521f66f9f5fULL,0x2baef6bfc70a4a9bULL,0xe7e6fa6509ed3561ULL,0x11370233984b230cULL,0x2151659bd04cdc69ULL,0xbdb83c63f007d416ULL,+ 0x9ebb284d391c2a82ULL,0xbcdd4863158308e8ULL,0x006f16ec83f1edcaULL,0xa13e2c37695dc6c8ULL,0x2ab756f04a057a87ULL,0xa8765500a6b48f98ULL,0x4252face68651c44ULL,0xa52b540be1765e02ULL,+ 0xcb35a1a85ca37ff0ULL,0xe1a04f1ccd2f1c8fULL,0x238816ce15a26112ULL,0xe206a111095b177eULL,0x3c10b6048a424149ULL,0xc6a3f56774752cfbULL,0xbf16a37a47f1dbb8ULL,0x7c372f9ad31a3dfbULL,+ 0x122d05b5c20b4d2aULL,0xff659cf50c662a67ULL,0xed57c128e8ffc9e9ULL,0x0fbb15859e987683ULL,0xadd70df247319a2bULL,0x4b98baba374be470ULL,0xf03d747356a7b307ULL,0x342e696e3efebf30ULL,+ 0xf84b48f7864ac537ULL,0x04713409a6940d3dULL,0x014db22d6174c7aeULL,0xc73a1c438c213034ULL,0x18ac4ea5ffdd93ecULL,0x724fc7576102783eULL,0x9fe13fcc91c3e83fULL,0x92a8c2c8f08f0bf5ULL,+ 0x7f2e22fd8f67f6deULL,0xab018833d8693177ULL,0x266d1db6863eca95ULL,0x6bb7732b31b5ef2bULL,0x4fa927c6915f80ceULL,0x6fa1d6d25f90efd8ULL,0x7bd75de8456b48adULL,0xd2cb507a845b6429ULL,+ 0xa72cf82ae255d7ecULL,0x52025c23a460e204ULL,0x10ae542d7d5b0a44ULL,0xa85143109305aedaULL,0x958315f5a14bbfe8ULL,0x3f361826385365feULL,0xc2b3a36b66d95040ULL,0x12c7b3347cf4eda2ULL,+ 0xa545b4d1e744119dULL,0x4c93b169829a71e7ULL,0x2dbb908c6117fcbfULL,0x4dc97320b35a3d85ULL,0x94c04f856bf88105ULL,0x452e1bce1b51bc1fULL,0x0c41ff50b3013af3ULL,0xf07af445224d7e24ULL,+ 0xbdb9e57ca3d24f6aULL,0x8a8246d7f345a763ULL,0x73bd2a6d98cfbb5fULL,0x1dd8e85e86ed04dbULL,0x76f2da42c01f420bULL,0x7ef0547364407bc7ULL,0x7e98ba7faff548f5ULL,0x6b7afbeefd30b64aULL,+ 0x4f922fc516a0d2bbULL,0x0d5cc16c1a623499ULL,0x9241cf3a57c62c8bULL,0x2f5e6961fd1b667fULL,0x5c15c70bf5a01797ULL,0x3d20b44d60956192ULL,0x04911b37071fdb52ULL,0xf648f9168d6f0f7bULL,+ 0x027cc8b8fac61d9aULL,0x7d25e062e3c6fe8aULL,0xe08805bfe5bff503ULL,0x13271e6c6ff632f7ULL,0x55dca6c0232f76a5ULL,0x8957c32d701ef426ULL,0xee728bcba10a5178ULL,0x5ea60411b62c5173ULL,+ 0x9ad5462bb4d8bc50ULL,0x181c0b16a9195770ULL,0xebd4fe1c78412a68ULL,0xae0341bcc0dff48cULL,0xb6bc45cf7003e866ULL,0xf11a6dea8a24a41bULL,0x5407151ad04c24c2ULL,0x62c9d27dda5b7b68ULL,+ 0x32865719a8afd30bULL,0x867983288a826dceULL,0xdf04e891c4a8fbe0ULL,0xbb6b6e1bebf56ad3ULL,0x0a695b11471f1ff0ULL,0xd76c3389be15baf0ULL,0x018edb95be96c43eULL,0xf2beaaf490794158ULL,+ 0x0a50b12e523b8bf6ULL,0x8009eb5b8f910c1bULL,0xf535af824a167588ULL,0x0f835f9cfb2a2abdULL,0xf59b29312afceb62ULL,0xc797df2a169d383fULL,0xeb3f5fb066ac02b0ULL,0x029d4c6fdaa2d0caULL,+ 0x87a7ebd1e0a1b12aULL,0x1e4ef88d770ba95fULL,0x8c33345cdc2ae9cbULL,0xcecf127601cc8403ULL,0x687c012e1b39b80fULL,0xfd90d0ad35c33ba4ULL,0xa3ef5a675c9661c2ULL,0x368fc88ee017429eULL,+ 0xb82226052b7ce542ULL,0xe6d4ce997472bde1ULL,0x53e16ebe09d2f4daULL,0x180ff42e53b92b2eULL,0xc59bcc022c34a1c6ULL,0x3803d6f9422c46c2ULL,0x18aff74f5c14a8a2ULL,0x55aebf8010a08b28ULL,+ 0xb956970e2fdd23ccULL,0xb80288bc5682e971ULL,0xe6e6d91e9ae86ebcULL,0x0564c83f8c9f1939ULL,0x551932a239560368ULL,0xe893752b049c28e2ULL,0x0b03cee5a6a158c3ULL,0xe12d656b04964263ULL,+ 0x58af2010f5b343bcULL,0x0f2e400af2f142feULL,0x3483bfdea85f4bdfULL,0xf0b1d09303bfeaa9ULL,0x2ea01b95c7081603ULL,0xe943e4c93dba1097ULL,0x47be92adb438f3a6ULL,0x00bb7742e5bf6636ULL,+ 0x4ed714576be5f7deULL,0xd93006f8c2263c9eULL,0xe073694ccacacb36ULL,0x2ff7a5b43ae118abULL,0x3cce53f1cd871236ULL,0xf156a39dc2aa6d52ULL,0x9cc5f271b198d76dULL,0xbc615b6f81383d39ULL,+ 0x137a4fb486df2a61ULL,0xa1ed9c07ecf7b4a2ULL,0xb2e460e27bd042ffULL,0xb7f5e2fa5f62f5ecULL,0x7aa6ec6bcc2423b7ULL,0x75ce0a7fba63eea7ULL,0x67a45fb1f250a6e1ULL,0x93bc919ce53cdc9fULL,+ 0x67930af231f63950ULL,0xa77797c114caa2c9ULL,0x526e80ee27ac7e62ULL,0xe1e6e62658b28aecULL,0x636178b0b3c9fef0ULL,0xaf7752e06d5f90beULL,0x94ecaf18eece51cfULL,0x2864d0edca806e1fULL,+ 0xec2fccaaddce3345ULL,0x2a6811b7012a4350ULL,0x96760ff1ac598bdcULL,0x054d652ad1bf4128ULL,0x0a1151d492a21005ULL,0xad7f397133110fdfULL,0x8c95928c1960100fULL,0x6c91c8257bf03362ULL,+ 0x17785b7799eb6df0ULL,0x26c3cc517386b779ULL,0x345ed9886417a48eULL,0xe990b4e407d6ef31ULL,0x0f456b7e2586abbaULL,0x239ca6a559c96e9aULL,0xe327459ce2eb4206ULL,0x3a4c3313a002b90aULL,+ 0x19e6125dec3f1decULL,0x07b1f040911178daULL,0xd93ededa904a6738ULL,0x55187a5a0bebedcdULL,0xf7d04722eb329d41ULL,0xf449099ef170b391ULL,0xfd317a69ca99f828ULL,0x50c3db2b34a4976dULL,+ 0x3806b69b92222f1fULL,0x5a2459ca6cf7ae70ULL,0x6789f69ca85217eeULL,0x5f232b5ee3dc85acULL,0x660e3ec548e9e516ULL,0x124b4e473197eb31ULL,0x10a0cb13aafcca23ULL,0x7bd63ba48213224fULL,+ 0xb674481b7bfe7178ULL,0x4e1debae65405868ULL,0x061b2821c48c867dULL,0x69c15b35513b30eaULL,0x3b4a166636871088ULL,0xe5e29f5d1220b1ffULL,0x4b82bb35233d9f4dULL,0x4e07633318cdc675ULL,+ 0x0d53f5c7a3e6fcedULL,0xe8cbbdd5f45fbdebULL,0xf85c01df13339a70ULL,0x0ff71880142ceb81ULL,0x4c4e8774bd70437aULL,0x5fb32891ba0bda6aULL,0x1cdbebd2f18bd26eULL,0x2f9526f103a9d522ULL,+ 0x40ce305192c4d684ULL,0x8b04d7257612efcdULL,0xb9dcda366f9cae20ULL,0x0edc4d24f058856cULL,0x64f2e6bf85427900ULL,0x3de81295dc09dfeaULL,0xd41b4487379bf26cULL,0x50b62c6d6df135a9ULL,+ 0xd4f8e3b4c72dfe67ULL,0xc416b0f690e19fdfULL,0x18b9098d4c13bd35ULL,0xac11118a15b8cb9eULL,0xf598a318f0062841ULL,0xbfe0602f89f356f4ULL,0x7ae3637e30177a0cULL,0x3409774761136537ULL,+ 0x0db2fb5ed005832aULL,0x5f5efd3b91042e4fULL,0x8c4ffdc6ed70f8caULL,0xe4645d0bb52da9ccULL,0x9596f58bc9001d1fULL,0x52c8f0bc4e117205ULL,0xfd4aa0d2e398a084ULL,0x815bfe3a104f49deULL,+ 0x97e5443f23885e5fULL,0xf72f8f99e8433aabULL,0xbd00b154e4d4e604ULL,0xd0b35e6ae5e173ffULL,0x57b2a0489164722dULL,0x3e3c665b88761ec8ULL,0x6bdd13973da83832ULL,0x3c8b1a1e73dafe3bULL,+ 0x4497ace654317cacULL,0xbe600ab9521771b3ULL,0xb42e409eb0dfe8b8ULL,0x386a67d73942310fULL,0x25548d8d4431cc28ULL,0xa7cff142985dc524ULL,0x4d60f5a193c4be32ULL,0x83ebd5c8d071c6e1ULL,+ 0xba3a80a7b1fd2b0bULL,0x9b3ad3965bec33e8ULL,0xb3868d6179743fb3ULL,0xcfd169fcfdb462faULL,0xd3b499d79ce0a6afULL,0x55dc1cf1e42d3ff8ULL,0x04fb9e6cc6c3e1b2ULL,0x47e6961d6f69a474ULL,+ 0x54eb3acce548b37bULL,0xb38e754284d40549ULL,0x8c3daa517b341b4fULL,0x2f6928ec690bf7faULL,0x0496b32386ce6c41ULL,0x01be1c5510adadcdULL,0xc04e67e74bb5faf9ULL,0x3cbaf678e15c9985ULL,+ 0x8cd1214550ca4247ULL,0xba1aa47ae7dd30aaULL,0x2f81ddf1e58fee24ULL,0x03452936eec9b0e8ULL,0x8bdc3b81243aea96ULL,0x9a2919af15c3d0e5ULL,0x9ea640ec10948361ULL,0x5ac86d5b6e0bcccfULL,+ 0xf892d918c36cf440ULL,0xaed3e837c939719cULL,0xb07b08d2c0218b64ULL,0x6f1bcbbace9790ddULL,0x4a84d6ed60919b8eULL,0xd89007918ac1f9ebULL,0xf84941aa0dd5daefULL,0xb22fe40a67fd62c5ULL,+ 0x97e15ba2157f2db3ULL,0xbda2fc8f8e28ca9cULL,0x5d050da437b9f454ULL,0x3d57eb572379d72eULL,0xe9b5eba2fb5ee997ULL,0x01648ca2e11538caULL,0x32bb76f6f6327974ULL,0x338f14b8ff3f4bb7ULL,+ 0x524d226ad7ab9a2dULL,0x9c00090d7dfae958ULL,0x0ba5f5398751d8c2ULL,0x8afcbcdd3ab8262dULL,0x57392729e99d043bULL,0xef51263baebc943aULL,0x9feace9320862935ULL,0x639efc03b06c817bULL,+ 0x1fe054b366b4be7aULL,0x3f25a9de84a37a1eULL,0xf39ef1ad78d75cd9ULL,0xd7b58f495062c1b5ULL,0x6f74f9a9ff563436ULL,0xf718ff29e8af51e7ULL,0x5234d31315e97fecULL,0xb6a8e2b1292f1c0aULL,+ 0xa7f53aa8327720c1ULL,0x956ca322ba092cc8ULL,0x8f03d64a28746c4dULL,0x51fe178266d0d392ULL,0xd19b34db3c832c80ULL,0x60dccc5c6da2e3b4ULL,0x245dd62e0a104cccULL,0xa7ab1de1620b21fdULL,+ 0xb293ae0b3893d123ULL,0xf7b75783b15ee71cULL,0x5aa3c61442a9468bULL,0xd686123cdb15d744ULL,0x8c616891a7ab4116ULL,0x6fcd72c8a4e6a459ULL,0xac21911077e5fad7ULL,0xfb6a20e7704fa46bULL,+ 0xe839be7d341d81dcULL,0xcddb688932148379ULL,0xda6211a1f7026eadULL,0xf3b2575ff4d1cc5eULL,0x40cfc8f6a7a73ae6ULL,0x83879a5e61d5b483ULL,0xc5acb1ed41a50ebcULL,0x59a60cc83c07d8faULL,+ 0x439530b665c7322dULL,0xcf12cc01b3c1b3fbULL,0xc70b01860172f685ULL,0xb915ee221b58391dULL,0x9afdf03ba317db24ULL,0x87dec65917b8ffc4ULL,0x7f46597be4d3d050ULL,0x80a1c1ed006500e7ULL,+ 0x3e22a7b397acf4ecULL,0x0426c4005ea8b640ULL,0x5e3295a64e969285ULL,0x22aabc59a6a45670ULL,0xb929714c5f5942bcULL,0x9a6168bdfa3182edULL,0x2216a665104152baULL,0x46908d03b6926368ULL,+ 0x52cb8ac6c2babcc1ULL,0x4748d448fe81ae8dULL,0x5844f03f80f1a711ULL,0x3db784b2f8df4ac4ULL,0xad918f122df1fe36ULL,0xe40f25b9f33cc7c0ULL,0x4700d0e73b5e5555ULL,0x5c28fa08b03326f9ULL,+ 0xa9f5d8745a1251fbULL,0x967747a8c72725c7ULL,0x195c33e531ffe89eULL,0x609d210fe964935eULL,0xcafd6ca82fe12227ULL,0xaf9b5b960426469dULL,0x2e9ee04c5693183cULL,0x1084a333c8146fefULL,+ 0x56dab1c8321a518cULL,0xfd4439a68bce226fULL,0xe0b30d194facb9faULL,0xb5052f307583571bULL,0x1442641012afd476ULL,0xd02e417203fe624aULL,0xfc394f65531c92e6ULL,0x16d4bf5ad4bc0b52ULL,+ 0xce06b88210395755ULL,0x117ce6345ec1df80ULL,0xfefae513eff55e96ULL,0xcf36cba6fd7fed1eULL,0x7340eca9a40ebf88ULL,0xe6ec1bcfb3d37e12ULL,0xca51b64e86bbf9ffULL,0x4e0dbb588b40e05eULL,+ 0x120ad0bf5f8b8a84ULL,0xbfa00f36866f3edeULL,0xa8c6064ec30ebc2cULL,0xc39e40b823001e3bULL,0x9614f7cde7b1cbabULL,0xcd4420c704a56284ULL,0x8446a8f316857a19ULL,0x519b93b1e6f706cbULL,+ 0x96649933aed1d1f7ULL,0x566eaff350563090ULL,0x345057f0ad2e39cfULL,0x148ff65b1f832124ULL,0x042e89d4cf94cf0dULL,0x319bec84520c58b3ULL,0x2a2676265361aa0dULL,0xc86fa3028fbc87adULL,+ 0x3805e5b80863b664ULL,0x8be7ac6b3cabdb53ULL,0x9f7d70505dfeff91ULL,0x7dea8bd095896206ULL,0x28005a3b410e3c4eULL,0x24a4f0e9bc603ebfULL,0xcc4fd5ae4aec15d2ULL,0x4dc253f80f96641dULL,+ 0x359d7b9c7ea2ee34ULL,0x3fd0d94c09cc3a71ULL,0xbb53c31c3a1ea37aULL,0x533425facf818c87ULL,0x7cd199c3810156e0ULL,0x0ea020e430c16448ULL,0xe557ba094a642542ULL,0xe657e7e79465f5eaULL,+ 0xea723ad1fbc82439ULL,0xc726868bf896e9fdULL,0xd97c913c511c33ffULL,0x8a3fa8e2e2114231ULL,0x2a6c0e5608445b3eULL,0x2c4cd884f8d098d3ULL,0x7bf51faf2fea77d4ULL,0x709f208a7b1c4f71ULL,+ 0xfc83d2ab5c8b06d5ULL,0xb1a785a2fe4eac46ULL,0xb99315bc846f7779ULL,0xcf31d816ef9ea505ULL,0x2391fe6a15d7dc85ULL,0x2f132b04b4016b33ULL,0x29547fe3181cb4c7ULL,0xdb66d8a6650155a1ULL,+ 0x5b9e4843f45aac50ULL,0xc31e042e91eaaad0ULL,0x6e8c0b345a54eea0ULL,0xf0437b94962c7a57ULL,0xe4531ce8fe1d348bULL,0xe1489378e3786432ULL,0xd5e19c4a3f510d38ULL,0x4df3f016ce348b00ULL,+ 0x59cd0e8b593d070fULL,0x437575165255625dULL,0x551fdda75b7a0399ULL,0x7bb6e6b02dec1eebULL,0x729bb662334c0922ULL,0x3df631df0cf41b79ULL,0x01abf3c578f32402ULL,0xfcb4666c9cd33c88ULL,+ 0xb805b445735e843cULL,0x2a8e890d97379134ULL,0xebc7c10c52ab9f87ULL,0xcbb5e1ecb80a92b6ULL,0xd6ada2d9dc2c4efeULL,0xfccf504eae8cc7bdULL,0x650115acb2418a74ULL,0x8dd90e06c52bd80cULL,+ 0x6b66d7e1adc1696fULL,0x98ebe5930acd72d0ULL,0x65f24550cc1b7435ULL,0xce231393b4b9a5ecULL,0x234a22d4db067df9ULL,0x98dda095caff9b00ULL,0x1bbc75a06100c9c1ULL,0x1560a9c8939cf695ULL,+ 0xe4050f1cf1c367caULL,0x9bc85a9bc90fbc7dULL,0xa373c4a2e1a11032ULL,0xb64232b7ad0393a9ULL,0xf5577eb0167dad29ULL,0x1604f30194b78ab2ULL,0x0baa94afe829348bULL,0x77fbd8dd41654342ULL,+ 0x31f14802fcf0a7fdULL,0x42fd07895488b01eULL,0x71d78d6d9952b498ULL,0x8eb572d907ac5201ULL,0xe0a2a44c4d194a88ULL,0xd2b63fd9ba017e66ULL,0x78efc6c8f888aefcULL,0xb76f6bda4a881a11ULL,+ 0xa2f7932c68af43eeULL,0x5502468e703d00bdULL,0xe5dc978f2fb061f5ULL,0xc9a1904a28c815adULL,0xd3af538d470c56a4ULL,0x159abc5f193d8cedULL,0x2a37245f20108ef3ULL,0xfa17081e223f7178ULL,+ 0x1fe2a9b2b4b4b67cULL,0xc1d10df0e8020604ULL,0x9d64abfcbc8058d8ULL,0x8943b9b2712a0fbbULL,0x90eed9143b3def04ULL,0x85ab3aa24ce775ffULL,0x605fd4ca7bbc9040ULL,0x8b34a564e2c75dfbULL,+ 0x5c18acf88e2f7d90ULL,0xfdbf33d777be32cdULL,0x0a085cd7d2eb5ee9ULL,0x2d702cfbb3201115ULL,0xb6e0ebdb85c88ce8ULL,0x23a3ce3c1e01d617ULL,0x3041618e567333acULL,0x9dd0fd8f157edb6bULL,+ 0xb2b2610798fa7aaaULL,0x41209ee4f073aa4eULL,0xf1570359f2d6b19bULL,0xcbe6868cfc577cafULL,0x186c4bdc32c04dd3ULL,0xa6c35faecfeee397ULL,0xb4a1b312f086c0cfULL,0xe0a5ccc6d9461fe2ULL,+ 0x516ff3a36fa6110cULL,0x74fb1eb1fb93561fULL,0x6c0c90478457522bULL,0xcfd321046bb8bdc6ULL,0x2d6884a2cc80ad57ULL,0x7c27fc3586a9b637ULL,0x3461baedadf4e8cdULL,0x1d56251a617242f0ULL,+ 0xb84011a9431dd80eULL,0xeb7c7cca73306cd9ULL,0x20fadd29d1b3b730ULL,0x83858b5bfe37b3d3ULL,0xbf4cd193b6251d5cULL,0x1cca1fd31352d952ULL,0xc66157a490fbc051ULL,0x7990a63889b98636ULL,+ 0x892c81a321175ec1ULL,0x9159a505ee018109ULL,0xc70130532d8be316ULL,0x76060c21426fa2e5ULL,0x074d2dfc6b6f0f22ULL,0x9725fc64ca01a671ULL,0x3f6679b92770bd8eULL,0x8fe6604fd7c9b3feULL,+ 0xce711154b6e00a84ULL,0xd9fe7e4224890e60ULL,0xd10bc6c34560988fULL,0xbdc2ef526859b004ULL,0xdcf0d868d5c890eeULL,0x893115e6119c47dcULL,0xe97966fbee714567ULL,0x117813355c85aa53ULL,+ 0x71d530cc73204349ULL,0xc9df473d94a0679cULL,0xc572f0014261e031ULL,0x9786b71f22f135feULL,0xed6505fa6b64e56fULL,0xe2fb48e905219c46ULL,0x0dbec45bedf53d71ULL,0xd7d782f2c589f406ULL,+ 0x350fb66b73ed0966ULL,0x968e4b082886032bULL,0x5a16ed6e88390493ULL,0x0a83ce84a121edbeULL,0x7c86fc10a3d9cda0ULL,0x5a40a6d595ce67fbULL,0x6cb8cda7f937dbf6ULL,0x95b44768651f6283ULL,+ 0x06513c8a446cd7f4ULL,0x158c423b906d52a6ULL,0x71503261c423866cULL,0x4b96f57093c148eeULL,0x5daf9cc7239a8523ULL,0x611b597695ac4b8bULL,0xde3981db724bf7f6ULL,0x7e7d0f7867afc443ULL,+ 0x984f101ed6fc3837ULL,0x340bf99f5e1b3a09ULL,0xbb96036f06942626ULL,0x7bc878ab0c7da618ULL,0xb37416441c6fb035ULL,0xc65bd5aea182fe9fULL,0x1b9c2fb86cc7a67aULL,0x8d1b19af5ce68d7dULL,+ 0x3d1ab80c8ce59954ULL,0x742c5a9478222ac0ULL,0x3ddacbf894f878ddULL,0xfc085117e7d54a99ULL,0xfb0f1dfa21e38ec2ULL,0x1c7b59cb16f4ff7fULL,0x988752397ea888feULL,0x705d270cb10dc889ULL,+ 0xe5aa692a87dec0e1ULL,0x010ded8df7b39d00ULL,0x7b1b80c854cfa0b5ULL,0x66beb876a0f8ea28ULL,0x50d7f5313476cd0eULL,0xa63d0e65b08d3949ULL,0x1a09eea953479fc6ULL,0x82ae9891f499e742ULL,+ 0xab58b9105ca7d866ULL,0x582967e23adb3b34ULL,0x89ae4447cceac0bcULL,0x919c667c7bf56af5ULL,0x9aec17b160f5dcd7ULL,0xec697b9fddcaadbcULL,0x0b98f341463467f5ULL,0xb187f1f7a967132fULL,+ 0xeb5ddcb6ec7fae9fULL,0x995f2714efb66e5aULL,0xdee95d8e69445d52ULL,0x1b6c2d4609e27620ULL,0x32621c318129d716ULL,0xb03909f10958c1aaULL,0x8c468ef91af4af63ULL,0x162c429ffba5cdf6ULL,+ 0xe8cb5eef9c053df7ULL,0x8de25b37b300ea6fULL,0xdb03fa92c849cffbULL,0x242e43a7e84169bbULL,0xe4fa51f4dd6f958eULL,0x6925a77ff4445a8dULL,0xe6e72a50e90d8949ULL,0xc66648e32b1f6390ULL,+ 0x6c3b96f31711ebecULL,0x2da40f1fce98fdc4ULL,0xb99774d357b4411fULL,0x87c8bdf415b65bb6ULL,0xda3a89e3c2eef12dULL,0xde95bb9b3c7471f3ULL,0x600f225bd812c594ULL,0x54907c5d2b75a56bULL,+ 0x699e4d2945c1dd53ULL,0xcadc5898231debb5ULL,0xdf49fcc7a77f00e0ULL,0x93057bbfa73e5a0eULL,0x2f8b7ecd027a4cd1ULL,0x114734b3c614011aULL,0xe7a01db767677c68ULL,0x89d9be5e7e273f4fULL,+ 0xe0deee5931fba239ULL,0xf47424d398bd91d1ULL,0x0f8886f4071a3c1dULL,0x3f7d41e8a819233bULL,0x708623c2cf6eb998ULL,0x86bb49af609a287fULL,0x942bb24963c90762ULL,0x0ef6eea555a9654bULL,+ 0x4add4a2e649d4e57ULL,0xcd53a2b01917526eULL,0xc526233020b44ac4ULL,0x4028746abaa2c31dULL,0x5131839064291d4cULL,0xbf48f151ee5ad909ULL,0xcce57f597b185681ULL,0x7c3ac1b04854d442ULL,+ 0xa80d1db6f79588c0ULL,0xfa52fc69b55768ccULL,0x0b4df1ae7f54438aULL,0x0cadd1a7f9b46a4fULL,0xb40ea6b31803dd6fULL,0x488e4fa555eaae35ULL,0x9f047d55382e4e16ULL,0xc9b5b7e02f6e0c98ULL,+ 0xc19972d0b611c24bULL,0x1d468e6560a8f351ULL,0xeb7580697bcf6421ULL,0xec9dd0ee88fbc491ULL,0x5b59d2bf956c2e32ULL,0x73dc6864dcddf94eULL,0xfd5e2321bcee7665ULL,0xa7b4f8ef5e9a06c4ULL,+ 0x03cc8f17cf41c6e8ULL,0xf1f03c2a037b925cULL,0xc39c19cc66d2427cULL,0x823d24ba7b6c18e4ULL,0x32ef9013901f0b4fULL,0x684360f1f8941c2eULL,0x0ebaff522c28092eULL,0x7891e4e3256c932fULL,+ 0x174e8f82d8d38a9bULL,0x2e97c600e7de1391ULL,0xc5709850a1c175ddULL,0x969041a032ae5035ULL,0xcbfd533b76a2086bULL,0xd6bba71bd7c2e8feULL,0xb2d58ee6099dfb67ULL,0x3a8b342d064a85d9ULL,+ 0xf83cbf0502f40d9aULL,0x4681c4682c318a4dULL,0x985756180e9c2674ULL,0xbe79d0461847092eULL,0xaf1e480a78bd01e0ULL,0x6dd359e472a51db9ULL,0x62ce3821e3afbab6ULL,0xc5cee5b617733199ULL,+ 0x671ed8fc3b922bf8ULL,0xe4d8c0a04c29b133ULL,0x87eb12393b6e99c4ULL,0xaff3974c8793bebaULL,0x037494052c18df9bULL,0xc5c3a29391007139ULL,0x6a77234fe37a0b95ULL,0x02c29a21b661c96bULL,+ 0x5a52fe2e34d74e31ULL,0xa352c3103bf79ab6ULL,0x97ff6c5aabfeeb8fULL,0xbfbe8feff5c97305ULL,0xd6081ce6a7904608ULL,0x1f812f3ac4fca249ULL,0x9b24bc9ab9e5e200ULL,0x91022c6738012ee8ULL,+ 0x184de7d7cc5f4394ULL,0xb5551b5c4536e142ULL,0x2e89b212d34aa60aULL,0x14a96feaf50051d5ULL,0x4e21ef740d12bb0bULL,0xc522f02060b9677eULL,0x8b12e4672df7731dULL,0x39f803827b326d31ULL,+ 0xc12738b67c4a658aULL,0xb3c4763940e72182ULL,0x3b77be468798e44fULL,0xdc047df217a7f85fULL,0x2439d4c55e59d92dULL,0xcedca475e8e64d8dULL,0xa724cd0d87ca9b16ULL,0x35e4fd59a5540dfeULL,+ 0x9894344f3a29467aULL,0xde81e949c51eba6dULL,0xdaea066ba5e5c2f2ULL,0x3fc8a61408c8c7b3ULL,0x7adff88f06d0de9fULL,0xbbc11cf53b75ce0aULL,0x9fbb7accfbbc87d5ULL,0xa1458e267badfde2ULL,+ 0x1cb43668e039c256ULL,0x5f26fb8b7c17fd5dULL,0xeee426af79aa062bULL,0x072002d0d78fbf04ULL,0x4c9ca237e84fb7e3ULL,0xb401d8a10c82133dULL,0xaaa525926d7e4181ULL,0xe943083373dbb152ULL,+ 0x2f5fad1e6ee7c983ULL,0xeb0f9d7cb41328f5ULL,0x9ba68b441d78d5f7ULL,0xa06b3b9e35bc726fULL,0xa2550255593e1ff1ULL,0x552dd43ddfbec115ULL,0x2c48a7abbba8f046ULL,0xd4fc56a3ad0bf133ULL,+ 0xf92dda31be24319aULL,0x03f7d28be095a8e7ULL,0xa52fe84098782185ULL,0x276ddafe29c24dbcULL,0x80cd54961d7a64ebULL,0xe43608897f1dbe42ULL,0x2f81a8778438d2d5ULL,0x7e4d52a885169036ULL,+ 0x62f21cefba04b5d1ULL,0x9a442707224c7352ULL,0xbf07966c33c6171fULL,0xdb7ba8911e0816b0ULL,0x306fea59033745a9ULL,0x2aacf7e0c0a78f67ULL,0xb5aa3883ad251bf9ULL,0x345aede926bd7086ULL,+ 0x19e3d5b11d59715dULL,0xc7eaa762d788983eULL,0xe5a730b0abf1f248ULL,0xfbab8084fae3fd83ULL,0x65e50d2153765b2fULL,0xbdd4e083fa127f3dULL,0x9cf3c074397b1b10ULL,0x59f8090cb1b59fd3ULL,+ 0xdc1de17d98119f10ULL,0x74353c5d488c36a6ULL,0x14aaf33a3d8e23dfULL,0x31e075c078baf593ULL,0x0f7ca03a46d1ca3cULL,0x99c5e3ac47b660c7ULL,0x70d0241388fe2e59ULL,0x2e9a6be12a7ec005ULL,+ 0x7b15fd9d615faa8fULL,0x8fa1eb40968554edULL,0x7bb4447e7aa44882ULL,0x2bb2d0d1029fff32ULL,0x075e2a646caa6d2fULL,0x8eb879de22e7351bULL,0xbcd5624e9a506c62ULL,0x218eaef0a87e24dcULL,+ 0xac449695241fbd6fULL,0x67c9b170081c1223ULL,0x16868f21b56aac6fULL,0x34bd8fa3f8bcb721ULL,0x06b6bd33b6691c76ULL,0x6c924766381a7973ULL,0x6a12444ca54078dbULL,0xd02e91a96d1051ccULL,+ 0x37e5684744ddfa35ULL,0x9ccfc5c5dab3f747ULL,0x9ac1df3f1ee96cf4ULL,0x0c0571a13b480b8fULL,0x2fbeb3d54b3a7b3cULL,0x35c036695dcdbb99ULL,0x52a0f5dcb2415b3aULL,0xd57759b44413ed9aULL,+ 0x077379c00b33d3f8ULL,0x421883c67064e409ULL,0x2d0873d76c29c8f6ULL,0xbfa433a3d274c0c8ULL,0x56dc778f23a5891eULL,0xd663bf6535e2de04ULL,0x488fdb485db517ceULL,0x00bba55e19b226c2ULL,+ 0x1fe647d83d30a2c5ULL,0x0857f77ef78a81dcULL,0x11d5a334131a4a9bULL,0xc0a94af929d393f5ULL,0xbc3a5c0bdaa6ec1aULL,0xba9fe49388d2d7edULL,0xbb4335b4bb614797ULL,0x991c4d6872f83533ULL,+ 0xedbbeee78a058fb6ULL,0xb9d19ddcfb09121aULL,0xa41bb45bd34dddceULL,0x2dbc80b900964bc4ULL,0x4ed9137d1d6cb654ULL,0x1b9016db483d01c5ULL,0x5fc501bc6528e22eULL,0xb2d2f8816cad646bULL,+ 0x53258c28d2f01cb3ULL,0x93d6eaa3d75db0b1ULL,0x419a2b0de87d0db4ULL,0xa1e48f03d8fe8493ULL,0xf747faf6c508b23aULL,0xf137571a35d53549ULL,0x9f5e58e2fcf9b838ULL,0xc7186ceea7fd3cf5ULL,+ 0x5e76fb2f286bad39ULL,0xbad9efe39dcad1e2ULL,0x60e75190edc7e904ULL,0x6a6f063e0fecb5a5ULL,0x5150ed85aed8acc3ULL,0xb56ccfbc6d20af6cULL,0x7e0d1e982c69dbfaULL,0xabf5628a7c7e10a9ULL,+ 0x77b868cee978a1d3ULL,0xe3a68b337ab92d04ULL,0x5102979487a5b862ULL,0x5f0606c33a61d41dULL,0x2814be276f9326f1ULL,0x2f521c14c6fe3c2eULL,0x17464d7dacdf7351ULL,0x10f5f9d3777f7e44ULL,+ 0xb06b1244c5f95cd8ULL,0xda8c8af0f4ab95f4ULL,0x1bae59c2b9e5836dULL,0x07d51e7e3acffffcULL,0x01e15e6ac2ccbcdaULL,0x3bc1923f8528c3e0ULL,0x43324577a49fead4ULL,0x61a1b8842aa7a711ULL,+ 0x4fe7ee31b0e63d34ULL,0xf4600572a9e54fabULL,0xc0493334d5e7b5a4ULL,0x8589fb9206d54831ULL,0xaa70f5cc6583553aULL,0x0879094ae25649e5ULL,0xcc90450710044652ULL,0xebb0696d02541c4fULL,+ 0x172a5247d95ea168ULL,0x1758fada2970764aULL,0xac803a511d978169ULL,0x299cfe2ede77e01bULL,0x652a1e17b0a98927ULL,0x2e26e1d120014495ULL,0x7ae0af9f7175b56aULL,0xc2e22a80d64b9f95ULL,+ 0x758c1a3ea2dee7a6ULL,0xdcde2f3c734b2284ULL,0xaba445d24eaba6adULL,0x35aaf66876cee0a7ULL,0x7e0b04a9e5aa049aULL,0xe74083ad91103e84ULL,0xbeb183ce40afecc3ULL,0x6b89de9fea043f7aULL,+ 0xafbfb1eda4f7e665ULL,0x403cce6aa23df8e7ULL,0xb49cc83f1312c2f4ULL,0xe1cc2366771a9c34ULL,0x7ab6a6c0db92faacULL,0xacd15e0dec3befe1ULL,0x7f8ed988583a0f36ULL,0x1821de7705f9be09ULL,+ 0xb99f0e0399375235ULL,0x7614c847b9917970ULL,0xfec93ce9524ec067ULL,0xe40e7bf89b122520ULL,0xb5670631ee4c4774ULL,0x6f03847a3b04914cULL,0xc96e9429dc9dd226ULL,0x43489b6c8c57c1f8ULL,+ 0x7b9722a5c5f26464ULL,0xca4c3dfba442809aULL,0x7d10986723644810ULL,0x9e4951723c924f82ULL,0xef4a6968a2c5bc14ULL,0x750eac4f68de6b7aULL,0x4e01884d52a2cbb5ULL,0xac40830af4a5f446ULL,+ 0x0e299d23fe67ba66ULL,0x9145076093cf2f34ULL,0xf45b5ea997fcf913ULL,0x5be008438bd7dddaULL,0x358c3e05d53ff04dULL,0xbf7ccdc35de91ef7ULL,0xad684dbfb69ec1a0ULL,0x367e7cf2801fd997ULL,+ 0x8c54f1076103adf8ULL,0x2d813d6cbe8e9810ULL,0xb1466fa85fbd3c9bULL,0x68c65d2240e1ca76ULL,0xb81baa40255f9164ULL,0x5b34c3eed1a864b2ULL,0x3602209b122ca141ULL,0xe7d7248e885badebULL,+ 0x46ffd227cc2338fbULL,0x89ff6fa990e26153ULL,0xbe570779331a0076ULL,0x43d241c506e1f3afULL,0xfdcdb97dde9b62a3ULL,0x6a06e984a0ae30eaULL,0xc9bf16804fbddf7dULL,0x170471a2d36163c4ULL,+ 0xfd23e207a6469d43ULL,0xcb9f5f112f753a85ULL,0xde2625d4fbb5ca72ULL,0x82e4e54ab7b1c78bULL,0x2cd0ca5378b9e814ULL,0xfcd44051125b817aULL,0xb68f719f30cfd965ULL,0x31644719d848a974ULL,+ 0xff5ba8ae3113655eULL,0xfa2c6e2b57b83180ULL,0x1c48271977e0eabeULL,0xf9f3c555337fea97ULL,0x340f7022a42581cbULL,0xe1de0bc218f710e3ULL,0xee640adef62e5aa8ULL,0x16b2389149428940ULL,+ 0x5045738f25f653f5ULL,0xe42b8cb83764f635ULL,0xb4f89406dc11ffc3ULL,0x99593144b6b3e4aaULL,0x81c849f3c9740052ULL,0x2c9cf4c155ffc48bULL,0x6299e52177f67a49ULL,0x5869f6e3c00c6c62ULL,+ 0x361619e455950cc3ULL,0xc71d665c56b66bb8ULL,0xea034b34afac6d84ULL,0xa987f832e5e4c7e3ULL,0xa07427727a79a6a7ULL,0x56e5d017e26d6c23ULL,0x7e50b97638167e10ULL,0xaa6c81efe88aa84eULL,+ 0xb84186f75fe01576ULL,0x446e276cdea51395ULL,0xf3c5ef8105f3f8d4ULL,0x3d7f7df674f7f142ULL,0x7c69b565f9ef1656ULL,0x87efa4247c414ef6ULL,0xeb7e620d3d292060ULL,0x50b1de346eec21aeULL,+ 0x0ca1f3b7b0dc8595ULL,0x27de46089f1d9f2eULL,0x1af3bf39badd82a7ULL,0x79356a7965862448ULL,0xc0602345f5f9a052ULL,0x1a8b0f89139a42f9ULL,0xb53eee42844d40fcULL,0x93b0bfe54e5b6368ULL,+ 0x0f893a5dc8de610bULL,0xe8c515fb67e223ceULL,0x7774bfa64ead6dc5ULL,0x89d20f95925c728fULL,0x7a1e0966098583ceULL,0xa2eedb9493f2a7d7ULL,0x1b2820974c304d4aULL,0x0842e3dac077282dULL,+ 0xa1010e9d74cd06ffULL,0x9c17c7dfaca3eeacULL,0x74c86cd38063aa2bULL,0x8595c4b3734614ffULL,0xa3de00ca990f62ccULL,0xd9bed213ca0c3be5ULL,0x7886078adf8ce9f5ULL,0xddb27ce35cd44444ULL,+ 0x5a3097befc15aa1eULL,0x40d12548b54b0745ULL,0x5bad4706519a5f12ULL,0xed03f717a439dee6ULL,0x0794bb6c4a02c499ULL,0xf725083dcffe71d2ULL,0x2cad75190f3adcafULL,0x7f68ea1c43729310ULL,+ 0x9c7c581d26ee8382ULL,0xcf17dcc5359d638eULL,0xee8273abb728ae3dULL,0x1d112926f821f047ULL,0x1149847750491a74ULL,0x687fa761fde0dfb9ULL,0x2c2580227ea435abULL,0x6b8bdb9491ce7e3fULL,+ 0x9c806d8af7f91d0fULL,0x3b61b0f1a82a5728ULL,0x4640032d94d76754ULL,0x273eb5de47d834c6ULL,0x2988abf77b4e4d53ULL,0xb7ce66bfde401777ULL,0x9fba6b32715071b3ULL,0x82413c24ad3a1a98ULL,+ 0x75537b7e3cc8ac85ULL,0x8d725f57dd02753bULL,0xfd05ff64b737df2fULL,0x55fe8712f6d2531dULL,0x57ce04a96ab6b01cULL,0x69a02a897cd93724ULL,0x4f82ac35cf86699bULL,0x8242d3ad9cb4b232ULL,+ 0x69c435269be47be0ULL,0x323b7dd8cb28fea1ULL,0xfa5538ba3a6c67e5ULL,0xef921d701d378e46ULL,0xf92961fc3c4b880eULL,0x3f6f914e98940a67ULL,0xa990eb0afef0ff39ULL,0xa6c2920ff0eeff9cULL,+ 0xb23a03a553fb2b56ULL,0x6ce141e74e057f78ULL,0x796525c389e490d9ULL,0x0bc95725a31a7e75ULL,0x1ec567911220fd06ULL,0x716e3a3c408b0bd6ULL,0x31cd6bf7e8ebeba9ULL,0xa7326ca6bee6b670ULL,+ 0x70b63d32343bf1a9ULL,0x8fd3bd2837d1a6b1ULL,0x0454879c316865b4ULL,0xee959ff6c458efa2ULL,0x0461dcf89706dc3fULL,0x737db0e2164e4b2eULL,0x092626802f8843c8ULL,0x54498bbc7745e6f6ULL,+ 0x5341352b5acf6e10ULL,0xc50343fdafe652c3ULL,0x4af3792d18577a7fULL,0xe1a4c617af16823dULL,0x9b26d0cd33425d0aULL,0x306399ed9b7bc47fULL,0x2a792f33706bb20bULL,0x3121961498111055ULL,+ 0x4c1f428cd5f30851ULL,0x94dfed272a4f6630ULL,0x4df53772fc5d48a4ULL,0xdd2d5a2f933260ceULL,0x574115bdd44cc7a5ULL,0x4ba6b20dbd12533aULL,0x30e93cb8243057c9ULL,0x794c486a14de320eULL,+ 0x6095355699f241d7ULL,0xee4adbd7001a349dULL,0x0b35bf6aaa89e491ULL,0x7f0076f4136f7546ULL,0xd19a18ba9264da3dULL,0x6eb2d2cd62a7a28bULL,0xcdba941f8761c971ULL,0x1550518ba3be4a5dULL,+ 0xc232d97302f1cd1eULL,0xce87eacb1dd212a4ULL,0x6e4c8c73e69802f7ULL,0x12ef02901fffddbdULL,0x941ec74e1bcea6e2ULL,0xd0b540243cb92cbbULL,0x809fb9d47e8f9d05ULL,0x3bf16159f2992aaeULL,+ 0xb2497007eafbb1e1ULL,0xd75c9ce6e75b7a93ULL,0x3558352defb68d78ULL,0xa2f26699223f6396ULL,0xeb911ecfe469b17aULL,0x62545779e72d3ec2ULL,0x8ea47de782cb113fULL,0xebe4b0864e1fa98dULL,+ 0xbdb8e675b055cb40ULL,0x898f8e7b977b5167ULL,0xecc65651b82fb863ULL,0x565448146d88f01fULL,0xb0928e95263a75a9ULL,0xcfb6836f1a22fcdaULL,0x651d14db3f3bd37cULL,0x1d3837fbb6ad4664ULL,+ 0x20d3c982cf7d62d2ULL,0x1f36e29d23ba8150ULL,0x48ae0bf092763f9eULL,0x7a527e6b1d3a7007ULL,0xb4a89097581a85e3ULL,0x1f1a520fdc158be5ULL,0xf98db37d167d726eULL,0x8802786e1113e862ULL,+ 0xefb2149e36f09ab0ULL,0x03f163ca4a10bb5bULL,0xd029704506e20998ULL,0x56f0af001b5a3babULL,0x7af4cfec70880e0dULL,0x7332a66fbe3d913fULL,0x32e6c84a7eceb4bdULL,0xedc4a79a9c228f55ULL,+ 0xc37c7dd0c55c4496ULL,0xa6a9635725bbabd2ULL,0x5b7e63f2add7f363ULL,0x9dce37822e73f1dfULL,0xe1e5a16ab2b91f71ULL,0xe44898235ba0163cULL,0xf2759c32f6e515adULL,0xa5e2f1f88615eecfULL,+ 0x74519be7abded551ULL,0x03d358b8c8b74410ULL,0x4d00b10b0e10d9a9ULL,0x6392b0b128da52b7ULL,0x6744a2980b75c904ULL,0xc305b0aea8f7f96cULL,0x042e421d182cf932ULL,0xf6fc5d509e4636caULL,+ 0x795847c9d64cc78cULL,0x6c50621b9b6cb27bULL,0x07099bf8df8022abULL,0x48f862ebc04eda1dULL,0xd12732ede1603c16ULL,0x19a80e0f5c9a9450ULL,0xe2257f54b429b4fcULL,0x66d3b2c645460515ULL,+ 0x6ca4f87e822e37beULL,0x73f237b4253bda4eULL,0xf747f3a241190aebULL,0xf06fa36f804cf284ULL,0x0a6bbb6efc621c12ULL,0x5d624b6440b80ec6ULL,0x4b0724257ba556f3ULL,0x7fa0c3543e2d20a8ULL,+ 0xe921fa31e3229d41ULL,0xa929c65294531bd4ULL,0x84156027a6d38209ULL,0xf3d69f736bdb97bdULL,0x8906d19a16833631ULL,0x68a34c2e03d51be3ULL,0xcb59583b0e511cd8ULL,0x99ce6bfdfdc132a8ULL,+ 0x3facdaaaffcdb463ULL,0x658bbc1a34a38b08ULL,0x12a801f8f1a9078dULL,0x1567bcf96ab855deULL,0xe08498e03572359bULL,0xcf0353e58659e68bULL,0xbb86e9c87d23807cULL,0xbc08728d2198e8a2ULL,+ 0x8de2b7bc453cadd6ULL,0x203900a7bc0bc1f8ULL,0xbcd86e47a6abd3afULL,0x911cac128502effbULL,0x2d550242ec965469ULL,0x0e9f769229e0017eULL,0x633f078f65979885ULL,0xfb87d4494cf751efULL,+ 0xe1790e4bfc25419aULL,0x364672034bff3cfdULL,0xc8db638625b6e83fULL,0x6cc69f236cad6fd2ULL,0x0219e45a6bc68bb9ULL,0xe43d79b6297f7334ULL,0x7d445368465dc97cULL,0x4b9eea322a0b949aULL,+ 0x1b96c6ba6102d021ULL,0xeaafac782f4461eaULL,0xd4b85c41c49f19a8ULL,0x275c28e4cf538875ULL,0x35451a9ddd2e54e0ULL,0x6991adb50605618bULL,0x5b8b4bcd7b36cd24ULL,0x372a4f8c56f37216ULL,+ 0xc890bd73a6a5da60ULL,0x6f083da0dc4c9ff0ULL,0xf4e14d94f0536e57ULL,0xf9ee1edaaaec8243ULL,0x571241ec8bdcf8e7ULL,0xa5db82710b041e26ULL,0x9a0b9a99e3fff040ULL,0xcaaf21dd7c271202ULL,+ 0xb4e2b2e14f0dd2e8ULL,0xe77e7c4f0a377ac7ULL,0x69202c3f0d7a2198ULL,0xf759b7ff28200eb8ULL,0xc87526eddcfe314eULL,0xeb84c52453d5cf99ULL,0xb1b52ace515138b6ULL,0x5aa7ff8c23fca3f4ULL,+ 0xff0b13c3b9791a26ULL,0x960022dacdd58b16ULL,0xdbd55c9257aad2deULL,0x3baaaaa3f30fe619ULL,0x9a4b23460d881efdULL,0x506416c046325e2aULL,0x91381e76035c18d4ULL,0xb3bb68bef27817b0ULL,+ 0x15bfb8bf5116f937ULL,0x7c64a586c1268943ULL,0x71e25cc38419a2c8ULL,0x9fd6b0c48335f463ULL,0x4bf0ba3ce8ee0e0eULL,0x6f6fba60298c21faULL,0x57d57b39ae66bee0ULL,0x292d513022672544ULL,+ 0xf451105dbab093b3ULL,0x012f59b902839986ULL,0x8a9158023474a89cULL,0x048c919c2de03e97ULL,0xc476a2b591071cd5ULL,0x791ed89a034970a5ULL,0x89bd9042e1b7994bULL,0x8eaf5179a1057ffdULL,+ 0x6066e2a2d551ee10ULL,0x87a8f1d8727e09a6ULL,0x00d08bab2c01148dULL,0x6da8e4f1424f33feULL,0x466d17f0cf9a4e71ULL,0xff5020103bf5cb19ULL,0xdccf97d8d062ecc0ULL,0x80c0d9af81d80ac4ULL,+ 0x98857ceb1bf4581cULL,0xe635e186aca7b166ULL,0x278ddd22659722acULL,0xa0903c4c1db68007ULL,0x366e458948f21402ULL,0x31b49c14b96abda2ULL,0x329c4b09e0403190ULL,0x97197ca3d29f43feULL,+ 0x03e2de1cf3480d4aULL,0xf0d8edc7bc8acf1aULL,0xf23e330368295a9cULL,0xfadd5f68c546a97dULL,0x895597ad96f8acb1ULL,0xbddd49d5671bdae2ULL,0x16fcd52821dd43f4ULL,0xa5a454126619141aULL,+ 0xfa32c79f439f29cfULL,0x7bf321c04dd82a3bULL,0xff127f54eaa2c1b1ULL,0xa8365f2df35e9618ULL,0x852d29024d0ef8ddULL,0x395ce2c159228c4aULL,0xb69f44e8215afed3ULL,0x16c1f898b27458e3ULL,+ 0x8ce9b6bfc360e25aULL,0xe6425195075a1a78ULL,0x9dc756a8481732f4ULL,0x83c0440f5432b57aULL,0xc670b3f1d720281fULL,0x2205910ed135e051ULL,0xded14b0edb052be7ULL,0x697b3d27c568ea39ULL,+ 0xdef29005dc453233ULL,0xc208c47a2fac4bcfULL,0x6057a3feac3d55acULL,0x1723725d902c1207ULL,0x9c31c62733eb0fecULL,0x4913ccdbbb3c63bbULL,0x113e542b07305838ULL,0x9d48e72a310c2d97ULL,+ 0x54424ec4d9bbeb3dULL,0x34ceafe3d7b2921cULL,0x5e68022e296d37c5ULL,0xa28e0a2b359f16b0ULL,0xfdd82dd9bc3f9d73ULL,0x6939a8f9baf3e1ffULL,0x55cff45c31736dc4ULL,0x910f56427892e8e7ULL,+ 0xde09b349dfe39260ULL,0x984612f773549093ULL,0x7cede28167853b02ULL,0x7d809bb429d17703ULL,0x450b6bfb2756c4f0ULL,0xc59ff9ba93f02b80ULL,0x3e69545720ad9561ULL,0x0c7cf0be3331e2c7ULL,+ 0x2e599b9afb3ff9edULL,0x28c2e0ab17f6515cULL,0x1cbee4fd474da449ULL,0x071279a44f364452ULL,0x97abff6601fbe855ULL,0x3ee394e85fda51c4ULL,0x190385f667597c0bULL,0x6e9fccc6a27ee34bULL,+ 0xced2d419362fb228ULL,0x894637c206aa0be4ULL,0x7a4fc55eb294b197ULL,0xd9cbac1cfd4ca1e8ULL,0x068b74800ccdb6ceULL,0xca4c556580dfaa49ULL,0xe835382176033b78ULL,0x35db7525c5ce98a7ULL,+ 0x8cf5927274fd1997ULL,0x987d2031ffadeb58ULL,0x5647c6c3d4db260cULL,0xf08bb13b985543beULL,0x566eeb1056fad695ULL,0x39e17dde68334cc7ULL,0x8a97b3bb7ddd1db2ULL,0xf91199d8c1c5a300ULL,+ 0x402fa437bdc47fe4ULL,0x35bd25234f3751f0ULL,0x8c2281b7cf57d485ULL,0x50083ea58f607cb6ULL,0x6f41e480df6d730dULL,0x1164e47e91bb06a2ULL,0xd9040c22391fb48aULL,0xe12df251da23dda7ULL,+ 0x0b89de9314092ebbULL,0xf17256bd428e240cULL,0xcf89a7f393d2f064ULL,0x4f57841ee1ed3b14ULL,0x4ee14405e708d855ULL,0x856aae7203f1c3d0ULL,0xc8e5424fbdd7eed5ULL,0x3333e4ef73ab4270ULL,+ 0xf9cf2b5148f835b1ULL,0x4a70faf32adaaba8ULL,0xa0d2e24fed7beadeULL,0x2b1e4e6715f04032ULL,0xeadbc0b91fb3ceeeULL,0xb817b0863a54b0b4ULL,0x14a787257fd4a188ULL,0xff13304623482e60ULL,+ 0x312012ec4efe42dcULL,0x7251b2c2c664b2bcULL,0x996c2e6b798f9cb9ULL,0x3543376a3b8f3465ULL,0x337ae8416fbfb6a9ULL,0xe0893a840cb91a03ULL,0x53744e9d7b02d855ULL,0x7e673186206d473fULL,+ 0x9509996f3ef143dbULL,0x9cf1e82e399378bcULL,0xb59cd09b0b8ccc89ULL,0x64b4a2fc52cda6beULL,0xd3bda8b31bcd55dfULL,0xfec4e87d2507cb37ULL,0x3d48a85eb610e49bULL,0x02fbe1bd1f9cc445ULL,+ 0x3bc77adedda492f8ULL,0xc11a3aea78297205ULL,0x5e89a3e734931b4cULL,0x17512e2e9f5694bbULL,0x5dc349f3177bf8b6ULL,0x232ea4ba08c7ff3eULL,0x9c4f9d16f511145dULL,0xccf109a333b379c3ULL,+ 0x60e2857080eb24a9ULL,0x7bedfb4d488e0cfdULL,0x721ebbd7c259cdb8ULL,0x0b0da855bc6390a9ULL,0x2b4d04dbde314c70ULL,0xcdbf1fbc6c32e846ULL,0x33833eabb162fc9eULL,0x9939b48bb0dd3ab7ULL,+ 0x96892c1f711b0eb9ULL,0xb905f2c8780ab954ULL,0xace26309a20792dbULL,0xec8ac9b30684e126ULL,0x486ad8b6b40a2447ULL,0x60121fc19fe3fb24ULL,0x5626fccf1a8e3b3fULL,0x4e5686226ad1f394ULL,+ 0x5cfbbb22236f4a98ULL,0x0b0c59e9066800bbULL,0x4ac69a8f5a9a7774ULL,0x2b33f804d6bec948ULL,0xb372929532e6c466ULL,0x68956d0f4e599c73ULL,0xa47a249f155c31ccULL,0x24d80f0de1ce284eULL,+ 0x5a4b46c64a8a3d62ULL,0x8469c4d0247743d2ULL,0x2bb3a13d88f7e433ULL,0x62b23a1001be5849ULL,0xe83596b4a63d1a4cULL,0x454e7fea7d183f3eULL,0x643fce6117afb01cULL,0x4e65e5e61c4c3638ULL,+ 0xb7e830e3dc09508bULL,0xfaf6d2cf74317655ULL,0x72606cebdf690355ULL,0x48bb92b3d0c3ded6ULL,0x65b754845c7cf892ULL,0xf6cd7ac9d5d5f01fULL,0xc2c30a5996401d69ULL,0x91268650ed921878ULL,+ 0xe5db77176add8545ULL,0x1b71cb6672c49b66ULL,0xd856073968421d77ULL,0x03840fe883e3afeaULL,0xb391dad51ec69977ULL,0xae243fb9307f6726ULL,0xc88ac87be8ca160cULL,0x5174cced4ce355f4ULL,+ 0x752067f8ff81578eULL,0x786221509045447dULL,0xc0c22fcf0505aa6fULL,0x1030f0a66bed1c77ULL,0x31f29f151f0bd739ULL,0x2d7989c7e6debe85ULL,0x5c070e728e677e98ULL,0x0a817bd306e81fd5ULL,+ 0xc1e17eb6cbc613e5ULL,0x33131d55497ea61cULL,0x2f69d39eaf7eded5ULL,0x73c2f434de6af11bULL,0x4ca52493a4a375faULL,0x5f06787cb833c5c2ULL,0x814e091f3e6e71cfULL,0x76451f578b746666ULL,+ 0x01c7e082e1539388ULL,0xfd286f30759a9c6bULL,0x94581041176bacfbULL,0xe580f07c3bc3de53ULL,0xdcdb6f75884d772fULL,0xd75c3bb840bb9d4fULL,0xdc6c2e4edb083011ULL,0xe18789a2cd9c298dULL,+ 0x5ee6ab8495fe1347ULL,0xab0f6c396f24503cULL,0x807e3ffb4486dd6bULL,0xf00b6c748002fef5ULL,0x48bff9a6a7862999ULL,0x85e5a06cbed89e26ULL,0x86d311af3d8419ebULL,0x24f3ad7834733f16ULL,+ 0x5e20551311820d44ULL,0x0c651bcc86c4473aULL,0x1d230c2b9bd80eefULL,0x042c4a1207515be5ULL,0x42517ca0bfe9e284ULL,0xe8f605782369827aULL,0x184f04f01638699dULL,0x174618edf2bc6d05ULL,+ 0x5e3e03fc6c68d687ULL,0x3e732c3d1ff052c7ULL,0xf2d0efa66ed16e7aULL,0x63d92b26b65bb746ULL,0xffcd82badd44867cULL,0xa71b4a9ef8c081b8ULL,0x6c1676a7736c8785ULL,0xbe2c06169d8932d0ULL,+ 0x7bfa1a4b9eca1c9fULL,0x960bc1dc8ce5e535ULL,0xe267d9f317eec30aULL,0x06fb89ef6c257d38ULL,0x2328999ad364a26dULL,0x69b794cb26eaab58ULL,0xad28ab1fb85ba596ULL,0x05dcbff356d0aa94ULL,+ 0x53376d282bcffbc4ULL,0x708817a706eadb7aULL,0x6ff50e05cd35ae69ULL,0x63b5fb7574bc7fdeULL,0x71c9e953e7fe08c4ULL,0xb4d8bfd4f583ca18ULL,0xde8d788245e81c5cULL,0xa5f5e93ce0474138ULL,+ 0x426c160f293c9f31ULL,0x8eb56333e864d7a7ULL,0xbe1164023ebbba30ULL,0x64c2bae32fd5a302ULL,0x800601e1265aff7bULL,0x52d8a88066fd4b14ULL,0x5aba20e746075a9cULL,0xdaa32bf87e1234c6ULL,+ 0x80f9bdef694db7e0ULL,0xedca8787b9fcddc6ULL,0x51981c3403b8dce1ULL,0x4274dcf170e10ba1ULL,0xf72743b86def6d1aULL,0xd25b1670ebdb1866ULL,0xc4491e8c050c6f58ULL,0x2be2b2ab87fbd7f5ULL,+ 0x3e0e5c9dd111f8ecULL,0xbcc33f8db7c4e760ULL,0x702f9a91bd392a51ULL,0x7da4a795c132e92dULL,0x1a0b0ae30bb1151bULL,0x54febac802e32251ULL,0xea3a5082694e9e78ULL,0xe58ffec1e4fe40b8ULL,+ 0xfbb8349d29c4120bULL,0x9f94391fc0d0d915ULL,0xc4074fa75410ba51ULL,0xa66adbf6150a5911ULL,0xc164543c34bfca38ULL,0xe0f27560b9e1ccfcULL,0x99da0f53e820219cULL,0xe8234498c6b4997aULL,+ 0x7b23c513516e19e4ULL,0x56e2e847c5c4d593ULL,0x9f727d735ce71ef6ULL,0x5b6304a6f79a44c5ULL,0x6638a7363ab7e433ULL,0x1adea470fe742f83ULL,0xe054b8545b7fc19fULL,0xf935381aba1d0698ULL,+ 0xb5504f9d918e4936ULL,0x65035ef6b2513982ULL,0x0553a0c26f4d9cb9ULL,0x6cb10d56bea85509ULL,0x48d957b7a242da11ULL,0x16a4d3dd672b7268ULL,0x3d7e637c8502a96bULL,0x27c7032b730d463bULL,+ 0x55366b7d5846426fULL,0xe7d09e89247d441dULL,0x510b404d736fbf48ULL,0x7fa003d0e784bd7dULL,0x25f7614f17fd9596ULL,0x49e0e0a135cb98dbULL,0x2c65957b2e83a76aULL,0x5d40da8dcddbe0f8ULL,+ 0x37f68bb4a595939dULL,0x0355647928740217ULL,0x8e740e7c84ad7612ULL,0xd89bc8439044695fULL,0xf7f3da5d85a9184dULL,0x562563bb9fc0b074ULL,0x06d2e6aaf88a888eULL,0x612d8643161fbe7cULL,+ 0x9fb3bba354530bb2ULL,0xbde3ef77cb0869eaULL,0x89bc90460b431163ULL,0x4d03d7d2e4819a35ULL,0x33ae4f9e43b6a782ULL,0x216db3079c88a686ULL,0x91dd88e000ffedd9ULL,0xb280da9f12bd4840ULL,+ 0x458f86913e538cd7ULL,0xa7001f6c8e08ad53ULL,0x52b8c6e6bf5d15ffULL,0x548234a4011215ddULL,0xff5a9d2d3d5b4045ULL,0xb0ffeeb64a904190ULL,0x55a3aca448607f8bULL,0x8cbd665c30a0672aULL,+ 0xa37f3573f37f5937ULL,0xeb0f6c7dd1e4fca5ULL,0x2965a554ac8ab0fcULL,0x17fbf56c274676acULL,0x2e2f6bd9acf7d720ULL,0x41fc8f8810224766ULL,0x517a14b385d53befULL,0xdae327a57d76a7d1ULL,+ 0x515d5c891f5f82dcULL,0x9a7f67d76361079eULL,0xa8da81e311a35330ULL,0xe44990c44b18be1bULL,0xc7d5ed95af103e59ULL,0xece8aba78dac9261ULL,0xbe82b0999394b8d3ULL,0x6830f09a16adfe83ULL,+ 0x43c41ac194d7d9b1ULL,0x5bafdd82c82e7f17ULL,0xdf0614c15fda0fcaULL,0x74b043a7a8ae37adULL,0x3ba6afa19e71734cULL,0x15d5437e9c450f2eULL,0x4a5883fe67e242b1ULL,0x5143bdc22c1953c2ULL,+ 0xa2a9ce7c6b53f5f9ULL,0x642465951b176d99ULL,0xb1298d36b95c081bULL,0x53505bb81d9a9ee6ULL,0x3f6f9e61f2ba70b0ULL,0xd07e16c98afad453ULL,0x9f1694bbe7eb4a6aULL,0xdfebced93cb0bc8eULL,+ 0xc676d7f2b1f3390bULL,0x9f7a1b8ca5b61272ULL,0x4ebebfc9c2e127a9ULL,0x4602500c5dd997bfULL,0x7f09771c4711230fULL,0x058eb37c020f09c1ULL,0xab693d4bfee5e38bULL,0x9289eb1f4653cbc0ULL,+ 0xa44d2b391770f5a7ULL,0xe4d4d7910e44eb82ULL,0x42e69d1e3f69712aULL,0xbf11c4d6ac6a820eULL,0xb5e7f3e542c4224cULL,0xd6b4e81c449d941cULL,0x5d72bd165450e878ULL,0x6a61e28aee25ac54ULL,+ 0x54da9dc7ab952578ULL,0xb5423df226e84d0bULL,0xa8b64eeb9b872042ULL,0xac2057825990f6dfULL,0x4ff696eb21f4c77aULL,0x1a79c3e4aab273afULL,0x29bc922e9436b3f1ULL,0xff807ef8d6d9a27aULL,+ 0xc7f3a8f833f6746cULL,0x21e46f65fea990caULL,0x915fd5c5caddb0a9ULL,0xbd41f01678614555ULL,0x346f4434426ffb58ULL,0x8055943614dbc204ULL,0xf3dd20fe5a969b7fULL,0x9d59e956e899a39aULL,+ 0x3c2f0ba9b733aa5fULL,0xdece47cbf05af235ULL,0xf8e3f715a2ac82a5ULL,0xc97ba6412203f18aULL,0xc3af550409c11060ULL,0x56ea2c0546af512dULL,0xfac28daff3f28146ULL,0x87fab43a959ef494ULL,+ 0x09891641d4c5105fULL,0x1ae80f8e6d7fbd65ULL,0x9d67225fbee6bdb0ULL,0x3b433b597fc4d860ULL,0x44e66db693e85638ULL,0xf7b59252e3e9862fULL,0xdb785157665c32ecULL,0x702fefd7ae362f50ULL,+ 0xfe756a5c97290293ULL,0xbf04a19cd388acbfULL,0xfbbbb9cf5e916bdaULL,0xf489527391f93becULL,0xdee07ec32a5923d7ULL,0xc7bc949bfde0c370ULL,0xbd5121750419d8fcULL,0x54f5d4763fdcc93fULL,+ 0x3754475d0fefb0c3ULL,0xd48fb56b46d7c35dULL,0xa070b633363798a4ULL,0xae89f3d28fdb98e6ULL,0x970b89c86363d14cULL,0x8981752167abd27dULL,0x9bf7d47444d5a021ULL,0xb3083bafcac72aeeULL,+ 0x0acda2ffcc5e62e9ULL,0x3b8b7d755edb02a4ULL,0xa700741c66120c76ULL,0xf77e847f7d974064ULL,0x0d310678a5e3d464ULL,0xde68b1f346bf35a3ULL,0xcae83028d32f9043ULL,0x724e4717517cb0cbULL,+ 0x389741debe949a44ULL,0x638e9388546a4fa5ULL,0x3fe6419ca0047bdcULL,0x7047f648aaea57caULL,0x54e48a9041fbab17ULL,0xda8e0b28576bdba2ULL,0xe807eebcc72afddcULL,0x07d3336df42577bfULL,+ 0xfae8563b4f3011dbULL,0xda33776536610c03ULL,0xad4f6f2a6381af0bULL,0xc277984cd95378ecULL,0x5ab0a10c5751d2b2ULL,0x70a18bb97a4bf3f4ULL,0x38d07ad4eae3caf3ULL,0xe8ef552fec430361ULL,+ 0x62a8c244bfe20925ULL,0x91c19ac38fdce867ULL,0x5a96a5d5dd387063ULL,0x61d587d421d324f6ULL,0xe87673a2a37173eaULL,0x2384800853778b65ULL,0x10f8441e05bab43eULL,0xfa11fe124621efbeULL,+ 0xedd0389a8391d54bULL,0xdac74c08c8afe546ULL,0x8525a4ad5be60bbdULL,0x2419ac9690ad7b87ULL,0x078a3a0277eee51bULL,0xe86ecf367239768dULL,0xcb0a259d8fd48035ULL,0x94db43cb9d29ca5bULL,+ 0x047b772e81685d7bULL,0x23f27d81bf34a976ULL,0xc27608e2915f48efULL,0x3b0b43faa521d5c3ULL,0x7613fb2663ca7284ULL,0x7f5729b41d4db837ULL,0x87b14898583b526bULL,0x00b732a6bbadd3d1ULL,+ 0x4fffa25b90f8550aULL,0x254db3d31c8dae9dULL,0x58cef963c1fbb232ULL,0xad1cb481a4bfdf0fULL,0x84d26ea1958773c2ULL,0x58622664010114f1ULL,0xeadb3a87f051e67eULL,0xf3185722b69e45c6ULL,+ 0x8e02f4262048e396ULL,0x436b50b6383d9de4ULL,0xf78d3481471e85adULL,0x8b01ea6ad005c8d6ULL,0xd3c7afee97015c07ULL,0x46cdf1a94e3ba2aeULL,0x7a42e50183d3a1d2ULL,0xd54b5268b541dff4ULL,+ 0xe120c4f948a48e22ULL,0xf24977eed0335a96ULL,0x9af3442336151c7bULL,0xe2815a7fd36648d8ULL,0xb4d2deba66e0a6b2ULL,0x783a84cf817515e8ULL,0x78424c0bff3ff24aULL,0x12dd1bb638e1c5d9ULL,+ 0x3f24cf304e23e9bcULL,0x4387f816126e3624ULL,0x26a46a033b0b6d61ULL,0xaf1bc8458b2d777cULL,0x25c401ba527de79cULL,0x0e1346d44261bbb6ULL,0x4b96c44b287b4bc7ULL,0x658493c75254562fULL,+ 0xfcb0e9d8fdd41d98ULL,0x8be980c1bcc7c7fbULL,0xa72e86506f8fa4d9ULL,0x356b14ad748cb88dULL,0xfd9fccefea6178f2ULL,0xc84a620d78bb0e35ULL,0xbc75367c62f391a9ULL,0x6a83a5c623100c05ULL,+ 0x23f949feb8a24a20ULL,0x17ebfed1f52ca53fULL,0x9b691bbebcfb4853ULL,0x5617ff6b6278a05dULL,0x241b34c5e3c99ebdULL,0xfc64242e1784156aULL,0x4206482f695d67dfULL,0xb967ce0eee27c011ULL,+ 0xb4480f0441c23fa3ULL,0xb4712eb0c1989a2eULL,0x3ccbba0f93a29ca7ULL,0x6e205c14d619428cULL,0x90db7957b3641686ULL,0x0432691d45ac8b4eULL,0x07a759acf64e0350ULL,0x0514d89c9c972517ULL,+ 0xe3b22c6bc4fe3c39ULL,0xba4a81536c7bebdfULL,0xf23ab6b725693459ULL,0x53bc377014922b11ULL,0x4645c8ab5afc60dbULL,0xaa02235520b9f2a3ULL,0x52a2954cce0fc507ULL,0x8c2731bb7ce1c2e7ULL,+ 0x5066efb6d9790ed6ULL,0xa77a0cbca6aa793bULL,0x1a915f3c223e042eULL,0x1c5def0469c5874bULL,0x0e83007873b6c1daULL,0x55cf85d2fcd8557aULL,0x0f7c7c760460f3b1ULL,0x87052acb46e58063ULL,+ 0x6a7091c2e48fb889ULL,0x26882c137b8a9d06ULL,0xa24986631b82a0e2ULL,0x844ed7363518152dULL,0x282f476fd86e27c7ULL,0xa04edaca04afefdcULL,0x8b256ebc6119e34dULL,0x56a413e90787d78bULL,+ 0x16eab6a20d645fd6ULL,0x632cbd8df61d3148ULL,0xcc1bf7cf62079ae9ULL,0x257ee5c7f33eccbbULL,0xbf6b34a81680ac73ULL,0xaa084e8872c77aa0ULL,0x7b5a864e05a0a1d1ULL,0x0641f6db359a1b16ULL,+ 0xf01d095dc8385050ULL,0x0d54a5d5df4b441cULL,0x2a37ccb40927706aULL,0xdf008f5445d7eb7eULL,0x74eb34f35bf716c7ULL,0x57a65b58641bd6caULL,0xef345e4835e6fa02ULL,0x191f913b88342a09ULL,+ 0x1554d46da670ff1dULL,0x24833d88cb97a1ccULL,0x8fa6ab3cded97493ULL,0x215e037189926498ULL,0x549bd592e56d74ffULL,0x58a8caf543b5e1ecULL,0x3c6087a323e93cb9ULL,0x8b0549875648b83cULL,+ 0x82ee061d5a74be50ULL,0xe41781c4dea16ff5ULL,0xe0b0c81e99bfc8a2ULL,0x624f4d690b547e2dULL,0x3a83545dbdcc9ae4ULL,0x2573dbb6409b1e8eULL,0x482960c4a6c93539ULL,0xf01059ad5ae18798ULL,+ 0xc431a238013ff83bULL,0x7c0018b2fad69d08ULL,0x99aeb52a4c9589eaULL,0x121f41ab9b1cf19fULL,0x0cfbbcbaef0f5958ULL,0x8deb3aeb7be8fbdcULL,0x12b954081f15aa31ULL,0x5acc09b34c0c06fdULL,+ 0x775cbfa86d518ffbULL,0xdecee1f6930f124bULL,0x9a402804f5e81d0fULL,0x0e8225c52a0eeb2fULL,0x884a5d39fee9e867ULL,0x9540428ffb505454ULL,0xb2bf2e20107a70d1ULL,0xd9917c3ba010b2aaULL,+ 0xa98f42fa3d843d53ULL,0x33777cc613ef927aULL,0xc440cdbecb84ca74ULL,0x8c22f9631dc7c5ddULL,0x4bc82b70c8d94708ULL,0x7e0b43fcc814364fULL,0x286d4e2486f59b7eULL,0x1abc895e4d6bf4c4ULL,+ 0x38151e274d559d96ULL,0x4f18c0d3b8db6c01ULL,0x49a3aa836f9921afULL,0xdbeab27b8c046029ULL,0x242b9eaa7040bf3bULL,0x39c479e51614b091ULL,0x338ede2b0e4baf5dULL,0x5bb192b7f0a53945ULL,+ 0x896d572337e440d7ULL,0x685c5fd9ade23f68ULL,0xb5b1a26dc2c64918ULL,0xb9390e30dad6580cULL,0x87911c4e7dee5b9bULL,0xb90c5053deb04f6eULL,0x37b942a18f065aa6ULL,0x34acdf2a1ca0928dULL,+ 0x733b64d39de40ca3ULL,0x1d4b6d6fd2f3857eULL,0xbe2be8e9b2ed92f7ULL,0x64ca7047b77da248ULL,0xc65dae9b8da99315ULL,0x9c1451750fc698a4ULL,0x8a296b94ff958c27ULL,0x38684e0843950097ULL,+ 0x7872e34b3390ff23ULL,0x968ce4abde7d18efULL,0x9b4a745e627fe7b1ULL,0x9607b0a0caff3e2aULL,0x1b05818eeb40e3a5ULL,0x6ac62204c0fa8d7aULL,0xb5b9058571ed4809ULL,0xb2432ef0f7cb65f2ULL,+ 0x715c9f973112795fULL,0xe8244437984e6ee1ULL,0x55cb4858ecb66bcdULL,0x7c136735abaffbeeULL,0x546615955dbec38eULL,0x51c0782c388ad153ULL,0x9ba4c53ac6e0952fULL,0x27e6782a1b21dfa8ULL,+ 0xfeb09740e2c2bf15ULL,0x627a2205a9e99704ULL,0xec8d73d0c2fbc565ULL,0x223eed8fc20c8de8ULL,0x1ee32583a8363b49ULL,0x1a0b6cb9c9c2b0a6ULL,0x49f7c3d290dbc85cULL,0xa8dfbb971ef4c1acULL,+ 0xc16c236e846e364fULL,0x7f33527cdea50ca0ULL,0xc48107750926b86dULL,0x6c2a36090598e70cULL,0xa6755e52f024e924ULL,0xe0fa07a49db4afcaULL,0x15c3ce7d66831790ULL,0x5b4ef350a6cbb0d6ULL,+ 0x42806b2da6dc1d29ULL,0xd3030009f871e144ULL,0xa1feb333aaf49276ULL,0xb5583b9ec70bc04bULL,0x1db0be7895695f20ULL,0xfc84181189d012b5ULL,0x6409f27205f61643ULL,0x40d34174d5883128ULL,+ 0x05214c050f15dde9ULL,0xa47a76a80d5f2b82ULL,0xbb254d3062e82b62ULL,0x11a05fe03ec955eeULL,0x7eaff46e9d529b36ULL,0x55ab13018f9e3df6ULL,0xc463e37199317698ULL,0xfd251438ccda47adULL,+ 0x8c3c669c72ba075bULL,0x89f78b55ba469015ULL,0x5706aade3e9f8ba8ULL,0x6d8bd565b32d7ed7ULL,0x25f4e63b805f08d6ULL,0x7f48200dc3bcc1b5ULL,0x4e801968b025d847ULL,0x74afac0487cbe0a8ULL,+ 0xe2a37598a9d82abfULL,0x5f188ccbe6c170f5ULL,0x816822005066b087ULL,0xda22c212c7155adaULL,0x151e5d3afbddb479ULL,0x4b606b846d715b99ULL,0x4a73b54bf997cb2eULL,0x9a1bfe433ecd8b66ULL,+ 0x79732522cccc18adULL,0xaadf3f8df1a6e027ULL,0xf7382c9317c2354dULL,0x5ce1680cd818b689ULL,0x359ebbfcd9ecbee9ULL,0x4330689c1cae62acULL,0xb55ce5b4c51ac38aULL,0x7921dfeafe238ee8ULL,+ 0xe13122f3dbfb894eULL,0xbe9b79f6ce274b18ULL,0x85a49de5ca58aadfULL,0x2495775811487351ULL,0x111def61bb939099ULL,0x1d6a974a26d13694ULL,0x4474b4ced3fc253bULL,0x3a1485e64c5db15eULL,+ 0x65994ddb0f5f27caULL,0xe85461fba80d59ffULL,0xff05481a66601023ULL,0xc665427afc9ebbfbULL,0xb0571a697587fd52ULL,0x935289f88d49efceULL,0x61becc60ea420688ULL,0xb22639d913a786afULL,+ 0x5afddab61430c9abULL,0x0bdd41d32238e997ULL,0xf0947430418042aeULL,0x71f9addacdddc4cbULL,0x7090c016c52dd907ULL,0xd9bdf44d29e2047fULL,0xe6f1fe801b1011a6ULL,0xb63accbcd9acdc78ULL,+ 0x264c76680448087cULL,0xac30903f71432daeULL,0x3851b26600f9bf47ULL,0x400ed3116cdd6d03ULL,0x045e79fef8fd2424ULL,0xfdfd974afa6da98bULL,0x45c9f6410c1e673aULL,0x76f2e7335b2c5168ULL,+ 0x7817acab4baef62eULL,0x9f5a2202a85b91e8ULL,0x9666ebe66ce57610ULL,0x32ad31f3f73bfe03ULL,0x628330a425bcf4d6ULL,0xea950593515056e6ULL,0x59811c89e1332156ULL,0xc89cf1fe8c11b2d7ULL,+ 0x889e5acbc46d7ce1ULL,0x9a515bb78b085877ULL,0xfac1a03d0b7a5050ULL,0x7d3e738af2926035ULL,0x861cc2ce2a6cb0ebULL,0x6f2e29558f7adc79ULL,0x61c4d45133016376ULL,0xd9fd2c805ad59090ULL,+ 0x0ad7337ac0b7eff3ULL,0x8552225ec5e48b3cULL,0xe6f78b0c73f13a5fULL,0x5e70062e82349cbeULL,0x6b8d5048e7073969ULL,0x392d2a29c33cb3d2ULL,0xee4f727c4ecaa20fULL,0xa068c99e2ccde707ULL,+ 0x1888d65861a023efULL,0x1d72aab4b9e5246eULL,0xa9a26348e5563ec0ULL,0xa0971963c3439a43ULL,0x567dd54badb9b5b7ULL,0x73fac1a1c45a524bULL,0x8fe97ef7fe38e608ULL,0x608748d23f384f48ULL,+ 0xebde86ec1ed66f18ULL,0x225d906bd61fce43ULL,0x5cab07d6e8bed74dULL,0x16e4617f27855ab7ULL,0x6568aaddb2fbc3ddULL,0xedb5484f8aeddf5bULL,0x878f20e86dcf2fadULL,0x3516497c615f5699ULL,+ 0xef0a3fecfa181e69ULL,0x9ea02f8130d69a98ULL,0xb2e9cf8e66eab95dULL,0x520f2beb24720021ULL,0x621c540a1df84361ULL,0x1203772171fa6d5dULL,0x6e3c7b510ff5f6ffULL,0x817a069babb2bef3ULL,+ 0x83572fb6b294cda6ULL,0x6ce9bf75b9039f34ULL,0x20e012f0095cbb21ULL,0xa0aecc1bd063f0daULL,0x57c21c3af02909e5ULL,0xc7d59ecf48ce9cdcULL,0x2732b8448ae336f8ULL,0x056e37233f4f85f4ULL,+ 0x8a10b53189e800caULL,0x50fe0c17145208fdULL,0x9e43c0d3b714ba37ULL,0x427d200e34189accULL,0x05dee24fe616e2c0ULL,0x9c25f4c8ee1854c1ULL,0x4d3222a58f342a73ULL,0x0807804fa027c952ULL,+ 0xc222653a4f0d56f3ULL,0x961e4047ca28b805ULL,0x2c03f8b04a73434bULL,0x4c966787ab712a19ULL,0xcc196c42864fee42ULL,0xc1be93da5b0ece5cULL,0xa87d9f22c131c159ULL,0x2bb6d593dce45655ULL,+ 0x22c49ec9b809b7ceULL,0x8a41486be2c72c2cULL,0x813b9420fea0bf36ULL,0xb3d36ee9a66dac69ULL,0x6fddc08a328cc987ULL,0x0a3bcd2c3a326461ULL,0x7103c49dd810dbbaULL,0xf9d81a284b78a4c4ULL,+ 0x3de865ade4d55941ULL,0xdedafa5e30384087ULL,0x6f414abb4ef18b9bULL,0x9ee9ea42faee5268ULL,0x260faa1637a55a4aULL,0xeb19a514015f93b9ULL,0x51d7ebd29e9c3598ULL,0x523fc56d1932178eULL,+ 0x501d070cb98fe684ULL,0xd60fbe9a124a1458ULL,0xa45761c892bc6b3fULL,0xf5384858fe6f27cbULL,0x4b0271f7b59e763bULL,0x3d4606a95b5a8e5eULL,0x1eda5d9b05a48292ULL,0xda7731d0e6fec446ULL,+ 0xa3e3369390d45871ULL,0xe976404006166d8dULL,0xb5c3368289a90403ULL,0x4bd1798372f1d637ULL,0xa616679ed5d2c53aULL,0x5ec4bcd8fdcf3b87ULL,0xae6d7613b66a694eULL,0x7460fc76e3fc27e5ULL,+ 0x70469b8295caabeeULL,0xde024ca5889501e3ULL,0x6bdadc06076ed265ULL,0x0cb1236b5a0ef8b2ULL,0x4065ddbf0972ebf9ULL,0xf1dd387522aca432ULL,0xa88b97cf744aff76ULL,0xd1359afdfe8e3d24ULL,+ 0x52a3ba2b91502cf3ULL,0x2c3832a8084db75dULL,0x04a12dddde30b1c9ULL,0x7802eabce31fd60cULL,0x33707327a37fddabULL,0x65d6f2abfaafa973ULL,0x3525c5b811e6f91aULL,0x76aeb0c95f46530bULL,+ 0xe8815ff62f93a675ULL,0xa6ec968405f48679ULL,0x6dcbb556358ae884ULL,0x0af61472e19e3873ULL,0x72334372a5f696beULL,0xc65e57ea6f22fb70ULL,0x268da30c946cea90ULL,0x136a8a8765681b2aULL,+ 0xad5e81dc0f9f44d4ULL,0xf09a69602c46585aULL,0xd1649164c447d1b1ULL,0x3b4b36c8879dc8b1ULL,0x20d4177b3b6b234cULL,0x096a25051730d9d0ULL,0x0611b9b8ef80531dULL,0xba904b3b64bb495dULL,+ 0x1192d9d493a3147aULL,0x9f30a5dc9a565545ULL,0x90b1f9cb6ef07212ULL,0x299585460d87fc13ULL,0xd3323effc17db9baULL,0xcb18548ccb1644a8ULL,0x18a306d44f49ffbcULL,0x28d658f14c2e8684ULL,+ 0x44ba60cda99f8c71ULL,0x67b7abdb4bf742ffULL,0x66310f9c914b3f99ULL,0xae430a32f412c161ULL,0x1e6776d388ace52fULL,0x4bc0fa2452d7067dULL,0x03c286aa8f07cd1bULL,0x4cb8f38ca985b2c1ULL,+ 0x83ccbe808c3bff36ULL,0x005a0bd25263e575ULL,0x460d7dda259bdcd1ULL,0x4a1c5642fa5cab6bULL,0x2b7bdbb99fe4fc88ULL,0x09418e28cc97bbb5ULL,0xd8274fb4a12321aeULL,0xb137007d5c87b64eULL,+ 0x80531fe1c63c4962ULL,0x50541e89981fdb25ULL,0xdc1291a1fd4c2b6bULL,0xc0693a17a6df4fcaULL,0xb2c4604e0117f203ULL,0x245f19630a99b8d0ULL,0xaedc20aac6212c44ULL,0xb1ed4e56520f52a8ULL,+ 0xb5560fb6700a1acdULL,0xe823fd73fd999681ULL,0xda915d1f6cb4e1baULL,0x0d0301186ebe00a3ULL,0x744fb0c989fca8cdULL,0x970d01dbf9da0e0bULL,0x0ad8c5647931d76fULL,0xb15737bff659b96aULL,+ 0xa12b384ece53c2d0ULL,0x779d897d5e4606daULL,0xa53e47b073ec12b0ULL,0x462dbbba5756f1adULL,0x69fe09f2cafe37b6ULL,0x273d1ebfecce2e17ULL,0x8ac1d5383cf607fdULL,0x8035f7ff12e10c25ULL,+ 0xca442d5a2093c22aULL,0xebd0bd31d5703aedULL,0x308f2afd653287b6ULL,0x9bb88bac0d1bc8baULL,0xfbaf853875c1e3b2ULL,0xbd2ac950ca11447cULL,0x286d816cea5c4c8dULL,0xdc3aa80028dc3208ULL,+ 0x854d34c77e6c5520ULL,0xc27df9efdcb9ea58ULL,0x405f2369d686666dULL,0x29d1febf0417aa85ULL,0x9846819e93470afeULL,0x3e6a9669e2a27f9eULL,0x24d008a2e31e6504ULL,0xdba7cecf9cb7680aULL,+ 0x26a43e41d07fa53dULL,0x3154a78a74e35bc5ULL,0x7b768924e0da2f8cULL,0xba964a2b23613f9aULL,0x5a548d35ba1d16c4ULL,0x2e1bfed1fb54d057ULL,0xff992136bc640205ULL,0xf39cb9148156df29ULL,+ 0xc913e64699b444adULL,0xddfce99dc40504c5ULL,0x58482a99d42e53dbULL,0x9aaf2c25d1aff537ULL,0xee90f7962664cf67ULL,0x74ab5c99f1393e2bULL,0xfad0faeae6225bb0ULL,0xc355648c2d63dd6cULL,+ 0xe4e31d271d91cf9dULL,0xcb35d4fdb377b20aULL,0x74de1e45055e1327ULL,0x3298e31b28703e75ULL,0x55087237de013339ULL,0x32cbf30123d101c6ULL,0xc70dba22e8aab0dcULL,0x4a52623d3d155bb9ULL,+ 0xecaff541338d6e43ULL,0x56f7dd734541d5ccULL,0xb5d426de96bc88caULL,0x48d94f6b9ed3a2c3ULL,0x6354a3bb2ef8279cULL,0xd575465b0b1867f2ULL,0xef99b0ff95225151ULL,0xf3e19d88f94500d8ULL,+ 0xdbf435acc85dcf57ULL,0x61745658c88f5415ULL,0x26367e9a17c55807ULL,0x22d077a5ca90c56fULL,0xfbf72258a2e04e76ULL,0xba965d3e6e06e405ULL,0x5724d06fe3e6f954ULL,0x3e47d47581251a74ULL,+ 0xb8ba0151e0fb82f7ULL,0x0d160726d5668ac2ULL,0x622ba25814d711b0ULL,0x6addf5577f3fe2f2ULL,0x2b831e1c6b9c9435ULL,0xce3a060ab73826bdULL,0x93fa11c11c240f89ULL,0x4f9cc8d8956e303aULL,+ 0x4b9331f6641f82c9ULL,0xd97c7c54dffec756ULL,0xf5ee6d1f1a9158abULL,0x054493a385c3da7fULL,0xa57a05f5eb7d96dfULL,0xa3afd447e4473a39ULL,0x42a4d9c488e16d55ULL,0x83e144f5f5f876aeULL,+ 0x92a83268e32dd620ULL,0x913ec99f627849a2ULL,0xedd8fdfa2c378882ULL,0xaf96f33eee6f8cfeULL,0xc06737e5dc3fa8a5ULL,0x236bb531b0b03a1dULL,0x33e59f2989f037b0ULL,0x13f9b5a7d9a12a53ULL,+ 0x50d8ae9559029aa6ULL,0xd74e292c5a4db2edULL,0x0b9c3355848f373dULL,0xec018db6ac45ab38ULL,0x1f44690269cc53a8ULL,0x8c4b628d1a879864ULL,0x1c743d284b13475eULL,0xbf4a933873de19f6ULL,+ 0x4a8a4f47f0cefa69ULL,0xdc8e4cbaa4546866ULL,0x359ba69b23f603c1ULL,0xdab4d601187b7ac5ULL,0xa6ca4337c1ebc8d9ULL,0x9fa6585452b4074bULL,0x1a4b4f81902fb733ULL,0xd2bb5d7aa525deaaULL,+ 0xeb2e92d5f81f9567ULL,0x54cb95ea4d698470ULL,0x5f2acb28e04c81ebULL,0x1c1ebfc4f8ceec64ULL,0x8f799fac06e07423ULL,0x72225f9937fa0c85ULL,0xb0cd861634f4db44ULL,0x5ec36159752c9091ULL,+ 0x0d0df6ce51efb310ULL,0xcb5b2eb4958df5beULL,0xd6459e2936158e59ULL,0x82aae2b91466e336ULL,0xfb658a39411aa636ULL,0x7152ecc5d4c0a933ULL,0xf10c758a49f026b7ULL,0xf4837f97cb09311fULL,+ 0x994f523a626332d5ULL,0x7bc388335561bb44ULL,0x005ed4b03d845ea2ULL,0xd39d3ee1c2a1f08aULL,0x6561fdd3e7676b0dULL,0x620e35fffb706017ULL,0x36ce424ff264f9a8ULL,0xc4c3419fda2681f7ULL,+ 0x00f831769bb81648ULL,0xd69eb485653120d0ULL,0xd17d75f44ccabc62ULL,0x34a07f82b749fcb1ULL,0x2c3af787bbfb5554ULL,0xb06ed4d062e283f8ULL,0x5722889fa19213a0ULL,0x162b085edcf3c7b4ULL,+ 0x36d90ddaeb300f7aULL,0x9dcf7dfcedb5e801ULL,0x645cb26874d5244cULL,0xa127ee79348e3aa2ULL,0x488acc53575f1dbbULL,0x95037e8580e6161eULL,0x57e59283292650d0ULL,0xabe67d9914938216ULL,+ 0x32670d2f7189e71fULL,0xc64387485ecf91e7ULL,0x15758e57db757a21ULL,0x427d09f8290a9ce5ULL,0x846a308f38384a7aULL,0xaac3acb4b0732b99ULL,0x9e94100917845819ULL,0x95cba111a7ce5e03ULL,+ 0xeb81aa377378058eULL,0x41c746a104411154ULL,0xa10c73bcfb828ac7ULL,0x6439be919d972b29ULL,0x4bf3b4b043a2fbadULL,0x39e6dadf82b5e840ULL,0x4f7164086397bd4cULL,0x0f7de5687f1eeccbULL,+ 0xdb332a73f37ec3c3ULL,0xc65259bddd59eba0ULL,0x2291709cdb4d3257ULL,0x9a793b25bd389390ULL,0xf39fe34be43756f0ULL,0x2f76bdce9afb56c9ULL,0x9f37867a61208b27ULL,0xea1d4307089972c3ULL,+ 0xd0a744878a429f4fULL,0x0649712bdb516609ULL,0xb826ba57e769b5dfULL,0x82335df21fc7aaf2ULL,0x2389f0675c93d995ULL,0x59ac367a68677be6ULL,0xa77985ff21d9951bULL,0x038956fb85011cceULL,+ 0x97b7851aaaca5e9bULL,0x518aa52156713b97ULL,0x3357e8c7150a61f6ULL,0x7842e7e2ec2c2b69ULL,0x8dffaf656868a548ULL,0xd963bd82e068fc81ULL,0x64da5c8b65917733ULL,0x927090ff7b247328ULL,+ 0xd6ffdb942f6d0d97ULL,0x05c3ee41443b9373ULL,0xb2e541ebffd36db6ULL,0xb7415a96ce1dcc3eULL,0xe383682e163aa2f6ULL,0x46febdd42f3af218ULL,0x90a0507ebafdbadbULL,0x4ca8ab4dce52e21aULL,+ 0xa3f0832e1b7cfb73ULL,0x7a8afe523ec354c9ULL,0xae91c97e378eadcaULL,0x7449c599ac3b32bbULL,0xa619c3710b1c4655ULL,0x692e4c6af79da87eULL,0xff3f5d86de38d96aULL,0xc5320f421c08c0ecULL,+ 0x92a6f2bc8fec5decULL,0xa71383ff84d6786cULL,0x87588c06dbffa084ULL,0x0d85f5ca6857e715ULL,0xe87311b3b6c774d4ULL,0x672357c84c3521a8ULL,0xe5fe74615b29fe0fULL,0x02bc51105b7158cdULL,+ 0x37a01e48a105fc8eULL,0x769d754a289ba48cULL,0xc08c6fe1d51c2180ULL,0xb032dd33b7bd1387ULL,0x953826db020b0aa6ULL,0x05137e800664c73cULL,0xc66302c4660cf95dULL,0x99004e11b2cef28aULL,+ 0x824f5b284f973536ULL,0xb43e299ed35b04eaULL,0xc72c88f74da03089ULL,0x8269d57a45a2e42cULL,0x7c1e63fc6607b38eULL,0xe89e2aaf29390b0cULL,0xc7c740da1bee2869ULL,0x8556f6fcaf3fb974ULL,+ 0x1a0a3995a4b6bed1ULL,0x2dab579597095c54ULL,0x06c6a1ff2aa73ce9ULL,0xadd0a54b4de438a7ULL,0x160b6b1afca906cdULL,0x25fc601629de10ddULL,0x348e9c99d3633da3ULL,0x1fe3f746158a4d5aULL,+ 0xc253edc88be85c1dULL,0xdd3d0e483ca09cb6ULL,0xb997f6879ae3055aULL,0x0c929ad007431dbfULL,0xcef1621584d2db42ULL,0xb50df3ef078828cdULL,0x4589da9d6dbd4b66ULL,0xbc4fd2e3d99c2b04ULL,+ 0x214bc9a7d298c241ULL,0xe3b697ba56807cfdULL,0xef1c78024564eadbULL,0xdde8cdcfb48149c5ULL,0x946bf0a75a4d2604ULL,0x27154d7f6c1538afULL,0x95cc9230de5b1fccULL,0xd88519e966864f82ULL,+ 0xb828dd1a7cb1282cULL,0xa08d7626be46973aULL,0x6baf8d40e708d6b2ULL,0x72571fa14daeb3f3ULL,0x85b1732ff22dfd98ULL,0x87ab01a70087108dULL,0xaaaafea85988207aULL,0xccc832f869f00755ULL,+ 0x488f1185ca8d9d1aULL,0xadf2c77dd987ded2ULL,0x5f3039f060c46124ULL,0xe5d70b7571e095f4ULL,0x82d586506260e70fULL,0x39d75ea7f750d105ULL,0x8cf3d0b175bac364ULL,0xf3a7564d21d01329ULL,+ 0x94ab4700ec3128c2ULL,0x6c76d8628e383f49ULL,0xdc36b150c03024ebULL,0xfb43947753daac69ULL,0xfc68764a8dc79623ULL,0x5b86995db440fbb2ULL,0xd66879bfccc5ee0dULL,0x0522894295aa8bd3ULL,+ 0xb24aa43e3fcd3efcULL,0xdd26c034b8088e9aULL,0xa5ef4dc9bd3d46eaULL,0xa2f99d588a4c6a6fULL,0xddabd3552f1da46cULL,0x72c3f8ce1afacdd1ULL,0xd90c4eee92d40578ULL,0xd28bb41fca623b94ULL,+ 0x5e7c3becee8314f3ULL,0x1c068aeddbea298fULL,0x08d381f17c80acecULL,0x03b56be8e330495bULL,0xaeffb8f29222882dULL,0x95ff38f6c4af8bf7ULL,0x50e32d351fc57d8cULL,0x6635be5217b444f0ULL,+ 0x242792d2e7417ce1ULL,0xff42bc71970ee7f5ULL,0x1ff4dc6d5c67a41eULL,0x77709b7b20882a58ULL,0x3554731dbe217f2cULL,0x2af2a8cd5bb72177ULL,0x58eee769591dd059ULL,0xbb2930c94bba6477ULL,+ 0x174a9126cecdaa7aULL,0xfc8c7e0e0b13247bULL,0x29c110d23484c1c4ULL,0xf8eb8757831dfc3bULL,0x022f0212c0067452ULL,0x3f6f69ee7b9b926cULL,0x09032da0ef42daf4ULL,0x79f00ade83f80de4ULL,+ 0x1e6adddaf176f2c0ULL,0x01ca4604e2572658ULL,0x0a404ded85342ffbULL,0x8cf60f96441838d6ULL,0x9bbc691cc9071c4aULL,0xfd58874434442803ULL,0x97101c85809c0d81ULL,0xa7fb754c8c456f7fULL,+ 0xf8559ff4c1e99d81ULL,0x08e1a7d6a3c617c0ULL,0xb398fd43248c6ba7ULL,0x6ffedd91d1283794ULL,0x8a6a59d2d629d208ULL,0xa9d141d53490530eULL,0x42f6fc1838505989ULL,0x09bf250d479d94eeULL,+ 0x6af7a1d5af71013fULL,0xe68216e50bedc946ULL,0xf4cba30bd27370a0ULL,0x7981afbf870421ccULL,0x02496a679449f0e1ULL,0x86cfc4be0a47edaeULL,0x3073c936b1feca22ULL,0xf569461203f8f8fbULL,+ 0xec14f9e12cb7191eULL,0x78ea1bd8e5b08ea6ULL,0x3c65aa9b46332bb9ULL,0x84cc22b3bf80ce25ULL,0x0098e9e9d49d5bf1ULL,0xcd4ec1c619087da4ULL,0x3c9d07c5aef6e357ULL,0x839a02689f8f64b8ULL,+ 0xbcadd6715bde48f8ULL,0xc97038732189bc7dULL,0x5d45299ec709ee8aULL,0xd1287ee2845aaff8ULL,0x7d1f8874db1dbf1fULL,0xea46588b990c88d6ULL,0x60ba649a84368313ULL,0xd5fdcbce60d543aeULL,+ 0xf795643037577dd8ULL,0x83b82af429c5fe88ULL,0x9c1bea26cdbdc132ULL,0x589fa0869c04339eULL,0x033e9538b13799dfULL,0x85fa8b21d295d034ULL,0xdf17f73fbd9ddccaULL,0xf32bd122ddb66334ULL,+ 0xcf3de9959890272dULL,0x75f3432a3e713a10ULL,0x5e13479fe28227b8ULL,0xb8561ea9fefacdc8ULL,0xa6a297a08332aafdULL,0x9b0d8bb573809b62ULL,0xd2fa1cfd0c63036fULL,0x7a16eb55bd64bda8ULL,+ 0x4cc34ec13cf48283ULL,0xb09daa259c8a705eULL,0xd1e9d0d05b7d4f84ULL,0x4df6ef64db38929dULL,0xe16b0763aa21ba46ULL,0xc6b1d178a293f8fbULL,0x0ff5b602d520aabfULL,0x94d671bdc339397aULL,+ 0xf7e48e8a2ac13e27ULL,0x4494f6df4eb1a9f5ULL,0xedbf84eb981f0a62ULL,0x49badc32536438f0ULL,0x50bea541004f7571ULL,0xbac67d10df1c94eeULL,0x253d73a1b727bc31ULL,0xb3d01cf230686e28ULL,+ 0xd433e50f6d3549cfULL,0x6f33696ffacd665eULL,0x695bfdacce11fcb4ULL,0x810ee252af7c9860ULL,0x65450fe17159bb2cULL,0xf7dfbebe758b357bULL,0x2b057e74d69fea72ULL,0xd485717a92731745ULL,+ 0x896c42e8ee36860cULL,0xdaf04dfd4113c22dULL,0x1adbb7b744104213ULL,0xe5fd5fa11fd394eaULL,0x68235d941a4e0551ULL,0x6772cfbe18d10151ULL,0x276071e309984523ULL,0xe4e879de5a56ba98ULL,+ 0x6c8d0aa9b898fd52ULL,0x2fb38a57be9af1a7ULL,0xe1f2b9a93b4f03f8ULL,0x2b1aad44c3f0cc6fULL,0x58b5332e7cf2c084ULL,0x1c57d96f0367d26dULL,0x2297eabdfa6e4a8dULL,0x65a947ee4a0e2b6aULL,+ 0xaaafafb0285b9491ULL,0x01a0be881e4c705eULL,0xff1d4f5d2ad9caabULL,0x6e349a4ac37a233fULL,0xcf1c12464a1c6a16ULL,0xd99e6b6629383260ULL,0xea3d43665f6d5471ULL,0x36974d04ff8cc89bULL,+ 0xf535b616fdd5b854ULL,0x592549c85728719fULL,0xe231468606921cadULL,0x98c8ce34311b1ef8ULL,0x28b937e7e9090b36ULL,0x67fc3ab90bf7bbb7ULL,0x12337097a9d87974ULL,0x3e5adca1f970e3feULL,+ 0xc26c49a1cfe89d80ULL,0xb42c026dda9c8371ULL,0xca6c013adad066d2ULL,0xfb8f722856a4f3eeULL,0x08b579ecd850935bULL,0x34c1a74cd631e1b3ULL,0xcb5fe596ac198534ULL,0x39ff21f6e1f24f25ULL,+ 0xcdcc68a7b3f85ff0ULL,0xacd21cdd1a888044ULL,0xb6719b2e05dbe894ULL,0xfae1d3d88b8260d4ULL,0xedfedece8a1c5d92ULL,0xbca01a94dc52077eULL,0xc085549c16dd13edULL,0xdc5c3bae495ebaadULL,+ 0x27f29e148f929057ULL,0x7a64ae06c0c853dfULL,0x256cd18358e9c5ceULL,0x9d9cce82ded092a5ULL,0xcc6e59796e93b7c7ULL,0xe1e4709231bb9e27ULL,0xb70b3083aa9e29a0ULL,0xbf181a753785e644ULL,+ 0xcc17063fbe7b643aULL,0x7872e1c846085760ULL,0x86b0fffbb4214c9eULL,0xb18bbc0e72bf3638ULL,0x8b17de0c722591c9ULL,0x1edeab1948c29e0cULL,0x9fbfd98ef4304f20ULL,0x2d1dbb6b9c77ffb6ULL,+ 0xf53f2c658ead09f7ULL,0x1335e1d59780d14dULL,0x69cc20e0cd1b66bcULL,0x9b670a37bbe0bfc8ULL,0xce53dc8128efbeedULL,0x0c74e77c8326a6e5ULL,0x3604e0d2b88e9a63ULL,0xbab38fca13dc2248ULL,+ 0x255616d3c7141771ULL,0xa86691ab2f226b66ULL,0xda19fea4b3ca63a9ULL,0xfc05dc42ae672f2bULL,0xa9c6e786718ba28fULL,0x07b7995b9c66b984ULL,0x0f434f551b3702f2ULL,0xd6f6212fda84eeffULL,+ 0x8ed6e8c85c0a3f1eULL,0xbcad24927c87c37fULL,0xfdfb62bb9ee3b78dULL,0xeba8e477cbceba46ULL,0x37d38cb0eeaede4bULL,0x0bc498e87976deb6ULL,0xb2944c046b6147fbULL,0x8b123f35f71f9609ULL,+ 0x4b0e7987b5b41d78ULL,0xea7df9074bf0c4f8ULL,0xb4d03560fab80ecdULL,0x6cf306f6fb1db7e5ULL,0x0d59fb5689fd4773ULL,0xab254f4000f9be33ULL,0x18a09a9277352da4ULL,0xf81862f5641ea3efULL,+ 0xa155dcc7de79dc24ULL,0xf1168a32558f69cdULL,0xbac215950d1850dfULL,0x15c8295bb204c848ULL,0xf661aa367d8184ffULL,0xc396228e30447bdbULL,0x11cd5143bde4a59eULL,0xe3a26e3b6beab5e6ULL,+ 0xb59b01579f759d01ULL,0xa2923d2f7eae4fdeULL,0x18327757690ba8c0ULL,0x4bf7e38b44f51443ULL,0xb6812563b413fc26ULL,0xedb7d36379e53b36ULL,0x4fa585c4c389f66dULL,0x8e1adc3154bd3416ULL,+ 0xd3b3a13f1402b9d0ULL,0x573441c32c7bc863ULL,0x4b301ec4578c3e6eULL,0xc26fc9c40adaf57eULL,0x96e71bfd7493cea3ULL,0xd05d4b3f1af81456ULL,0xdaca2a8a6a8c608fULL,0x53ef07f60725b276ULL,+ 0xa6b5c9d646ac49d2ULL,0x42c77c0b83137aa9ULL,0x24d000fc68225a38ULL,0x0f63cfc82fe1e907ULL,0x22d1b01bc6441f95ULL,0x7d38f719ec8e448fULL,0x9b33fa5f787fb1baULL,0x94dcfda1190158dfULL,+ 0x211cde10296c36efULL,0x7ee8967282c4da77ULL,0xb617d270a57836daULL,0xf0cd9c319cb7560bULL,0x01fdcbf7e455fe90ULL,0x3fb53cbb7e7334f3ULL,0x781e2ea44e7de4ecULL,0x8adab3ad0b384fd0ULL,+ 0x01778a2b599ff0f9ULL,0x68a923d78104fc6bULL,0x5bfa44dfda694ff3ULL,0x4f7199dbf7667f12ULL,0xc06d8ff6e46f2a79ULL,0x08b5deade9f8131dULL,0x02519a59abb4ce7cULL,0xc4f710bcb42aec3eULL,+ 0x3014368b4ed80940ULL,0x67e6d0567a6fceddULL,0x7c208c49ca97579fULL,0xfe3d7a81a23597f6ULL,0x5e2032027e096ae2ULL,0xb1f3e1e724b39366ULL,0x26da26f32fdcdffcULL,0x79422f1d6097be83ULL,+ 0x50549c748c878145ULL,0x67f14edf39c63565ULL,0x22ddf78c9bcf2d5eULL,0xffaa842f68201d10ULL,0x47d94a9dd1b2de28ULL,0xc09c4be8054be414ULL,0xac80e178ca82755bULL,0xe3251d105697c3bdULL,+ 0x2bbe09d35001417bULL,0x795e84ee5962ed5eULL,0x5b79d1ca279f46c3ULL,0x1f7f8a3b83836a2eULL,0x692200b14a64dc32ULL,0xc84243350f84f739ULL,0xf110da07cc9155c0ULL,0xee8fbe61594b0507ULL,+ 0x2f6a5391035703ccULL,0x9899bf6a40c7e24dULL,0xc3f7f248bbfcbb9aULL,0xf65027ded555875bULL,0xa7a16b69ffff3b37ULL,0x67b6eb54145b4431ULL,0x19d7e1d249afd679ULL,0xbd819bab110fccdfULL,+ 0x263a2cfb9db3b381ULL,0x9c3a2deed4df0a4bULL,0x728d06e97d04e61fULL,0x8b1adfbc42449325ULL,0x6ec1d9397e053a1bULL,0xee2be5c766daf707ULL,0x80ba1e14810ac7abULL,0xdd2ae778f530f174ULL,+ 0x3e708e703b9f0426ULL,0xe5b02fb60c84f17cULL,0x2f4ff35be3b70a0bULL,0x781b3c5f9b15565dULL,0xe76c636a6e124c3aULL,0xbde81eba8b496784ULL,0xa412f8e2443f0370ULL,0x15d42362999be45dULL,+ 0x0f503ae2a4af76c1ULL,0x550e66dc08276fe7ULL,0x11e0c1fcbf3a33c6ULL,0x42be231006629f85ULL,0xedf7743e516ace49ULL,0xce436668436a2262ULL,0xe1ac7036446ca192ULL,0x73631cb5476fe13eULL,+ 0xd47f82d4a160bcfaULL,0x258fb075b8ceb1f2ULL,0x4f818e8fdf5a8d25ULL,0x6685475e6fd31c9dULL,0xcef6385ae1e9b13fULL,0xe0a42594f0508bdbULL,0x5ad7ae16aef1f90dULL,0x45a155ef63f8a81eULL,+ 0x8ca407c28034b95eULL,0xc93eb97617bdc560ULL,0x4ec24e8d339807e8ULL,0x91b734d6dd64a4ebULL,0xd0fece398f668b26ULL,0x4822cc4b141823d5ULL,0xb953bc32f09e4e00ULL,0xca0a7c6006d861aeULL,+ 0x4c74d4470f33e712ULL,0x3cec1e0625a87cb0ULL,0x5cec0610e5962db4ULL,0xd971af1571a256aaULL,0xa044c983a2ef4ac9ULL,0xcaa1da63d74e9d00ULL,0xfb972d834673d881ULL,0x50747c5a03a26c8bULL,+ 0x04349982a3e25566ULL,0xeef9075e18e1b896ULL,0x4c7bead092b2d24bULL,0xd99f72fb0a21ba55ULL,0xb93e09315005e541ULL,0x2a7a98389ece3205ULL,0xeb388ed11462f2f6ULL,0xb488b15a2e3460a6ULL,+ 0x43f6cd67969d56afULL,0x9e0d872cdfc58a8bULL,0x401c1509a4e70377ULL,0x103d1a1308ad646cULL,0x078ee37e9d062427ULL,0x4e69c5acb9bef78cULL,0x521ec00136e66142ULL,0x8de1ecb2a634cd82ULL,+ 0x0435d97a205b9d8bULL,0x6eb8f064056756d4ULL,0xd5e88a8bb6f8210eULL,0x070ef12dec9fd9eaULL,0x4d8495053bcc876aULL,0x12a75338a7404ce3ULL,0xd22b49e1b8a1db5eULL,0xec1f205114bfa5adULL,+ 0x43ed81b5c4e83d33ULL,0xd9f358795efd488bULL,0x164a620f9deb4d0fULL,0xc6927bdbac6a7394ULL,0x45c28df79f9e0f03ULL,0x2868661efcd7e1a9ULL,0x7cf4e8d0ffa348f1ULL,0x6bd4c284398538e0ULL,+ 0x56036e8c06d75fc1ULL,0x2dcf7bb73249a89fULL,0x81dd1d3de245e7ddULL,0xf578dc4bebd6e2a7ULL,0x4c028903df2ce7a0ULL,0xaee362889c39afacULL,0xdc847c31146404abULL,0x6304c0d8a4e97818ULL,+ 0xfb6836c327d02dccULL,0x5ad009827a68bcc2ULL,0x1b24b44c005e912dULL,0xcc83d20f811fdcfeULL,0x36527ec1666fba0cULL,0x6994819714754635ULL,0xfcdcb1a8556da9c2ULL,0xa593426781a732b2ULL,+ 0xe4ac8b33070d3aabULL,0x2643672b9a2cd5e5ULL,0x52eff79b1cfc9173ULL,0x665ca49b90a7c13fULL,0x5a8dda59b3efb998ULL,0x8a5b922d052f1341ULL,0xae9ebbab3cf9a530ULL,0x35986e7bf56da4d7ULL,+ 0x63ee4cbd8088b454ULL,0xdb7f32f79a9e0c8aULL,0xb377d4186b2447cbULL,0xe3e982aad370219bULL,0x06ccc1e4c2a2a593ULL,0x72c368650773f24fULL,0xa13b4da795859423ULL,0x8bbf1d3375040c8fULL,+ 0x03c187d0ad886aacULL,0x5c16878ab771b645ULL,0xb07dfc6fc74045abULL,0x2c6360bf7800caedULL,0x24295bb5b9c972a3ULL,0xc9e6f88e7c9a6dbaULL,0x90ffbf2492a79aa6ULL,0xde29d50a41c26ac2ULL,+ 0xb1f0fb68d84d835dULL,0xc90caf39861dc1e6ULL,0x12e5b0467594f8d7ULL,0x26897ae265012b92ULL,0xbcf68a08a4d6755dULL,0x403ee41c0991fbdaULL,0x733e343e3bbf17e8ULL,0xd2c7980d679b3d65ULL,+ 0x534acf4fda79e5acULL,0x68b83b3a8630215fULL,0x5c748b2ed085756eULL,0xb0317258e5d37cb2ULL,0x6735841ac5ccc2c4ULL,0x7d7dc96b3d9d5069ULL,0xa147e410fd1754bdULL,0x65296e94d399ddd5ULL,+ 0x1e71c9a1deb8568bULL,0xa35daea080fb3d32ULL,0xe8b6f2662cf8fb81ULL,0x6d51afe89490696aULL,0x81beac6e51803a19ULL,0xe3d24b7f86219080ULL,0x727cfd9ddf6f463cULL,0x8c6865ca72284ee8ULL,+ 0xe00df169d23233f3ULL,0x3e32279677cb637fULL,0x1f897c0e1da0cf6cULL,0xa651f5d831d6bbddULL,0xdd61af191a230c76ULL,0xbd527272cdaa5e4aULL,0xca753636d0abcd7eULL,0x78bdd37c370bd8dcULL,+ 0xcddb27c17078c432ULL,0xe1961b9cb77fedb7ULL,0x1edc2f5cc2290570ULL,0x2c3fefca19cbd886ULL,0xcf880a36c2af389aULL,0x96c610fdbda71ceaULL,0xf03977a932aa8463ULL,0x8eb7763f8586d90aULL,+ 0x831ab3edf0290a8fULL,0xcae81966cb47c387ULL,0xaad7dece184efb4fULL,0xdcfc53b34749110eULL,0x6698f23c4cb632f9ULL,0xc42a1ad6b91f8067ULL,0xb116a81d6284180aULL,0xebedf5f8e901326fULL,+ 0x91633f0ab2cf8940ULL,0x72b0b1786f948f51ULL,0x2d28dc30782653c8ULL,0x88829849db903a05ULL,0xb8095d0c6a19d2bbULL,0x4b9e7f0c86f782cbULL,0x7af739882d907064ULL,0xd12be0fe8b32643cULL,+ 0x9561f28b638a7e81ULL,0x54155cdf5980ddc3ULL,0xb2db4a96d26f247aULL,0x9d774e4e4787d100ULL,0x1a9e6e2e078637d2ULL,0x1c363e2d5e0ae06aULL,0x7493483ee9cfa354ULL,0x76843cb37f74b98dULL,+ 0x0491f1bc789a283bULL,0x72d3ac3d880836f4ULL,0xaa1c5ea388e5402dULL,0x1b192421d5cc473dULL,0x5c0b99989dc84cacULL,0xb0a8482d9c6e75b8ULL,0x639961d03a191ce2ULL,0xda3bc8656d837930ULL,+ 0xd7e0c4cdb30cfb3aULL,0x6d09b8c16c9db4c8ULL,0x40ba1a4207c8d9dfULL,0x6fd495f71c52c66dULL,0xfb0e169f275264daULL,0x80c2b746e57d8362ULL,0xedd987f749ad7222ULL,0xfdc229af4398ec7bULL,+ 0xb0d1ed8452666a58ULL,0x4bcb6e00e6a9c3c2ULL,0x3c57411c26906408ULL,0xcfc2075513556400ULL,0xa08b1c505294dba3ULL,0xa30ba2868b7dd31eULL,0xd70ba90e991eca74ULL,0x094e142ce762c2b9ULL,+ 0xb81d783e979f3925ULL,0x1efd130aaf4c89a7ULL,0x525c2144fd1bf7faULL,0x4b2969041b265a9eULL,0xed8e9634b9db65b6ULL,0x35c82e3203599d8aULL,0xdaa7a54f403563f3ULL,0x9df088ad022c38abULL,+ 0xe5cfb066bb3fd30aULL,0x429169daeff0354eULL,0x809cf8523524e36cULL,0x136f4fb30155be1dULL,0x4826af011fbba712ULL,0x6ef0f0b4506ba1a1ULL,0xd9928b3177aea73eULL,0xe2bf6af25eaa244eULL,+ 0x8d084f124237b64bULL,0x688ebe99e3ecfd07ULL,0x57b8a70cf6845dd8ULL,0x808fc59c5da4a325ULL,0xa9032b2ba3585862ULL,0xb66825d5edf29386ULL,0xb5a5a8db431ec29bULL,0xbb143a983a1e8dc8ULL,+ 0x35ee94ce12ae381bULL,0x3a7f176c86ccda90ULL,0xc63a657e4606eacaULL,0x9ae5a38043cd04dfULL,0x9bec8d15ed251b46ULL,0x1f5d6d30caca5e64ULL,0x347b3b359ff20f07ULL,0x4d65f034f7e4b286ULL,+ 0x9e93ba24f111661eULL,0xedced484b105eb04ULL,0x96dc9ba1f424b578ULL,0xbf8f66b7e83e9069ULL,0x872d4df4d7ed8216ULL,0xbf07f3778e2cbecfULL,0x4281d89998e73754ULL,0xfec85fbb8aab8708ULL,+ 0x9a3c0deea5ba5b0bULL,0xe6a116ce42d05299ULL,0xae9775fee9b02d42ULL,0x72b05200a1545cb6ULL,0xbc506f7d31a3b4eaULL,0xe58930788bbd9b32ULL,0xc8bc5f37e4b12a97ULL,0x6b000c064a73b671ULL,+ 0x13b5bf22765fa7d0ULL,0x59805bf01d6a5370ULL,0x67a5e29d4280db98ULL,0x4f53916f776b1ce3ULL,0x714ff61f33ddf626ULL,0x4206238ea085d103ULL,0x1c50d4b7e5809ee3ULL,0x999f450d85f8eb1dULL,+ 0x658a6051e4c79e9bULL,0x1394cb73c66a9feaULL,0x27f31ed5c6be7b23ULL,0xf4c88f365aa6f8feULL,0x0fb0721f4aaa499eULL,0x68b3a7d5e3fb2a6bULL,0xa788097d3a92851dULL,0x060e7f8ae96f4913ULL,+ 0x82eebe731a3a93bcULL,0x42bbf465a21adc1aULL,0xc10b6fa4ef030efdULL,0x247aa4c787b097bbULL,0x8b8dc632f60c77daULL,0x6ffbc26ac223523eULL,0xa4f6ff11344579cfULL,0x5825653c980250f6ULL,+ 0xb2dd097ebc1aa2b9ULL,0x0788939337a0333aULL,0x1cf55e7137a0db38ULL,0x2648487f792c1613ULL,0xdad013363fcef261ULL,0x6239c81d0eabf129ULL,0x8ee761de9d276be2ULL,0x406a7a341eda6ad3ULL,+ 0x4bf367ba4a493b31ULL,0x54f20a529bf7f026ULL,0xb696e0629795914bULL,0xcddab96d8bf236acULL,0x4ff2c70aed25ea13ULL,0xfa1d09eb81cbbbe7ULL,0x88fc8c87468544c5ULL,0x847a670d696b3317ULL,+ 0xf133421e64bcb626ULL,0xaea638c826dee0b5ULL,0xd6e7680bb310346cULL,0xe06f4097d5d4ced3ULL,0x099614527512a30bULL,0xf3d867fde589a59aULL,0x2e73254f52d0c180ULL,0x9063d8a3333c74acULL,+ 0xeda6c595d314e7bcULL,0x2ee7464b467899edULL,0x1cef423c0a1ed5d3ULL,0x217e76ea69cc7613ULL,0x27ccce1fe7cda917ULL,0x12d8016b8a893f16ULL,0xbcd6de849fc74f6bULL,0xfa5817e2f3144e61ULL,+ 0x1f3541640821ee4cULL,0x1583eab40bc61992ULL,0x7490caf61d72879fULL,0x998ad9f3f76ae7b2ULL,0x1e181950a41157f7ULL,0xa9d7e1e6e8da3a7eULL,0x963784eb8426b95fULL,0x0ee4ed6e542e2a10ULL,+ 0xb79d4cc5ac751e7bULL,0x93f96472fd4211bdULL,0x8c72d3d2c8de4fc6ULL,0x7b69cbf5df44f064ULL,0x3da90ca2f4bf94e1ULL,0x1a5325f8f12894e2ULL,0x0a437f6c7917d60bULL,0x9be7048696c9cb5dULL,+ 0x949c9976e1337c26ULL,0x6faadebdd73d68e5ULL,0x9e158614f1b768d9ULL,0x22dfa5579cc4f069ULL,0xccd6da17be93c6d6ULL,0x24866c61a504f5b9ULL,0x2121353c8d694da1ULL,0x1c6ca5800140b8c6ULL,+ 0xf1604a7dd4b79bb8ULL,0xaee806fb52c878c8ULL,0x34144f118d47b8e8ULL,0x72edf52b949f9054ULL,0xebfca84e2127015aULL,0x9051d0c09cb7cef3ULL,0x86e8fe58296deec8ULL,0x33b2818841010d74ULL,+ 0xbd5660ed9aed9f40ULL,0x70ca6ad1532a8c99ULL,0xc4978bfb95c371eaULL,0xe5464d0d7003109dULL,0x1af32fdfd9e535efULL,0xabf57ea798c9185bULL,0xed7a741712b42488ULL,0x8e0296a7e97286faULL,+ 0x01079383171b445fULL,0x9bcf21e38131ad4cULL,0x8cdfe205c93987e8ULL,0xe63f4152c92e8c8fULL,0x729462a930add43dULL,0x62ebb143c980f05aULL,0x4f3954e53b06e968ULL,0xfe1d75ad242cf6b1ULL,+ 0x8b57416e1f017d5eULL,0x375333967674e99bULL,0x6e6d94c0e8f488a0ULL,0xb93a787adc16f95eULL,0xc3ac51a2dcc99cccULL,0xc134b4139aa47c1dULL,0xf28fcdafafdfd8d5ULL,0x0d57bd8e10b831edULL,+ 0x9276fbccf0bcfc46ULL,0x3a822aceb5cffee6ULL,0x328ed2fec75d915bULL,0xa145c113c359476cULL,0xf61a81538be17bcdULL,0x01e867c3aa6c3d8fULL,0x5634e15d6516c82fULL,0xc1437bd26948b9b0ULL,+ 0xd2fcd2006c19d4c7ULL,0xa0f3c437e1b1e976ULL,0xf0545ff694f237e8ULL,0xdd10ec3fc0bf8bb1ULL,0x4f89696cac7cd3e1ULL,0xed3714ec5f24bfe6ULL,0x363eb1d85faf7706ULL,0xfcbd604dc027cc32ULL,+ 0x5f95c6c7af8685c8ULL,0xd4c1c8ce2f8f01aaULL,0xc44bbe322574692aULL,0xb8003478d4a4a068ULL,0x7c8fc6e52eca3cdbULL,0xea1db16bec04d399ULL,0xb05bc82e8f2bc5cfULL,0x763d517ff44793d2ULL,+ 0x16ce8eddc355363bULL,0x4af2f70ff8820d6eULL,0xcb7ed4d27661a508ULL,0x41d3444edd195472ULL,0x17fea2b438da9649ULL,0x9bf69356aeb4a200ULL,0xa13b5f916ab19c3dULL,0xc0519c14dc9360a6ULL,+ 0xc2571ae92e42e171ULL,0xcb31ab63ed41ccf9ULL,0x37f3c576b5c8854fULL,0x66e5191bc62392a1ULL,0x71565a1c6cd5683bULL,0x484b0283606fe689ULL,0xf3a25d6767e2fda6ULL,0x87ba21de8a65c0a4ULL,+ 0xde74e49ca70684d1ULL,0x3ae8766133e80c3dULL,0x5984a2a916a5c34dULL,0x09a83eccb8298c35ULL,0x9a19867caa4ca4c0ULL,0x02085610b375b8ffULL,0xf296328bf70396dcULL,0x9c9ddc4cde6fae63ULL,+ 0x4451c1b808bd98d0ULL,0x644b1cd46575f240ULL,0x6907eb337375d270ULL,0x56c8bebdfa2286bdULL,0xc713d2acc4632b46ULL,0x17da427aafd60242ULL,0x313065b7c95c7546ULL,0xf8239898bf17a3deULL,+ 0x94683d260b083b6eULL,0x0a3752eb06f6a54dULL,0x48bedc23752074ddULL,0x637622fc3e822593ULL,0xea0005136be55d3bULL,0x9f5e12f4324d006dULL,0x529486a964fc0270ULL,0x09ba0d0c923399e6ULL,+ 0x363858473a977080ULL,0x4cf8e1b80c6a6ab6ULL,0x919a5c6c0482261eULL,0x517a9ad0e5ce4806ULL,0x2792d40c056aa7aaULL,0x4c7c6adae56c61b0ULL,0xf19cb178a4b19e0cULL,0x046d5c4fe4ba267fULL,+ 0xd3e926ab121550b3ULL,0xe4975e4ac147ce84ULL,0x7a8be0f95eff722aULL,0x71e4702c6fd4f2a0ULL,0x13b92acf3cb7b280ULL,0xc588716d28272d73ULL,0x862c7bf3daa9fe5cULL,0x78c008f2e2a79e42ULL,+ 0xf3b7963f4c830320ULL,0x842c7aa0903203e3ULL,0xaf22ca0ae7327afbULL,0x38e13092967609b6ULL,0x73b8fb62757558f1ULL,0x3cc3e831f7eca8c1ULL,0xe4174474f6331627ULL,0xa77989cac3c40234ULL,+ 0xae8317f4b0166f7aULL,0xfbd3e3f7ceec74e6ULL,0xfdb516ace0874bfdULL,0x3d846019c681f3a3ULL,0x0b12ee5c7c1620b0ULL,0xba68b4dd2b63c501ULL,0xac03cd326668c51eULL,0x2a6279f74e0bcb5bULL,+ 0xfd8e139f8f5fcda8ULL,0xf3e558c4bdee5bfdULL,0xd76cbaf4e33f9f77ULL,0x3a4c97a471771969ULL,0xda27e84bf6dce6a7ULL,0xff373d9613e6c2d1ULL,0xf115193cd759a6e9ULL,0x3f9b702563d2262cULL,+ 0x12536fea87baa627ULL,0x58c1fec1f72aa680ULL,0x6c29b637601e5dc9ULL,0x9e3c3c1cde9e01b9ULL,0xefc8127b2bcfe0b0ULL,0x351071022a12f50dULL,0x6ccd6cb14879b397ULL,0xf792f804f8a82f21ULL,+ 0x8c3184911a335cc8ULL,0x563459ba6a5913e4ULL,0x1b920d61c7b32919ULL,0x805ab8b6a02425adULL,0x2ac512da8d006086ULL,0x6ca4846abcf5c0fdULL,0xafea51d8ac2138d7ULL,0xcb647545344cd443ULL,+ 0xa3f4f521e447f2c4ULL,0x81b8da7a604291f0ULL,0xd680bc467d5926deULL,0x84f21fd534a1202fULL,0x1d1e31814e9df3d8ULL,0x1ca4861a39ab8d34ULL,0x809ddeec5b19aa4aULL,0x59f72f7e4d329366ULL,+ 0x9f1b2466cdedca85ULL,0x140bb7101a09538cULL,0xac8ae8515e11115dULL,0x0d63ff676f03f59eULL,0x755e55517d234afbULL,0x61c2db4e7e208fc1ULL,0xaa9859cef28a4b5dULL,0xbdd6d4fc34af030fULL,+ 0x3f39e67f906151e5ULL,0xcea27f5f55e10649ULL,0xdca1d4e1c17cf7b7ULL,0x0c326d122fe2362dULL,0x05f7ac337dd35df3ULL,0x0c3b7639c396dbdfULL,0x0912f5ac03b7db1cULL,0x9dea4b705c9ed4a9ULL,+ 0x511053e453544774ULL,0x834d0ecc3adba2bcULL,0x4215d7f7bae371f5ULL,0xfcfd57bf6c8663bcULL,0xded2383dd6901b1dULL,0x3b49fbb4b5587dc3ULL,0xfd44a08d07625f62ULL,0x3ee4d65b9de9b762ULL,+ 0x3e56fe5bdf53aad0ULL,0x51314de5e4604a67ULL,0x386ad98607a261a0ULL,0x8b7e021217afcc91ULL,0xcbf411273b72aec5ULL,0x13c85d05c4f9f509ULL,0xeda56845b6484b57ULL,0x13cb1642b3d0995bULL,+ 0x5a994b6e717815deULL,0xd995c7a0a7e131d1ULL,0xc8b46df226c023aaULL,0x8cfd094d702afcedULL,0x7bc743cdced6a886ULL,0xb7d70ec41fcabe75ULL,0x2a6c9e47ddac9390ULL,0x720694259310aa90ULL,+ 0xa607b3263e8f793cULL,0xa541166ecde3b289ULL,0xf44ff2924a915b21ULL,0x68bea906b58ecda6ULL,0xd85b37b440292897ULL,0xd2a508ae4b768423ULL,0xd10bb79da413bbbeULL,0x0262f481061491f4ULL,+ 0xd17e80f55464d0ebULL,0x89d3e1a767a613a7ULL,0x77791260c8c97dadULL,0xec2ff21fe4f0cbe7ULL,0xed984ac2e9e6bc10ULL,0xe3c53de877cba305ULL,0x9bbaf9b283624fdcULL,0x5e9451cd1485c0ecULL,+ 0xfdfc9f63b7abad11ULL,0xc7ec3a9263a46189ULL,0x49ebee42f67037b7ULL,0x8247f504cdac1710ULL,0xfc518f8d397583e5ULL,0xe7d24de70c3f8c2eULL,0x354832669c5edcb1ULL,0x94bba483f8c2cefcULL,+ 0x1f13756db1761ec8ULL,0xe53c8b98a4b97e55ULL,0xb2aee3f84096cc28ULL,0x48c361a0920f1a8dULL,0xa98b672d8c31190aULL,0x7bc1e7d1001855d4ULL,0x242cfb07bf3f4b2aULL,0x9bf44a3f32a28bc4ULL,+ 0xeba8976299da550cULL,0xb2c1781a16baa042ULL,0x3068b082788c2f9dULL,0xc0fa414594869a9eULL,0x73bd9e39d50b693fULL,0xb79e2a9c988e2c5eULL,0xf1cb8de40f8f9f62ULL,0x415b04ee1ea50c7bULL,+ 0x64e5137d0d63d1faULL,0x658fc05202a9d89fULL,0x4889487450436309ULL,0xe9ae30f8d598da61ULL,0x2ed710d1818baf91ULL,0xe27e9e068b6a0c20ULL,0x1e28dcfb1c1a6b44ULL,0x883acb64d6ac57dcULL,+ 0x8735728dc2c6ff70ULL,0x79d6122fc5dc2235ULL,0x23f5d00319e277f9ULL,0x7ee84e25dded8cc7ULL,0x91a8afb063cd880aULL,0x3f3ea7c63574af60ULL,0x0cfcdc8402de7f42ULL,0x62d0792fb31aa152ULL,+ 0xb02c83f9dec31a21ULL,0x988c8b236ad9d573ULL,0x53e983aea57be365ULL,0xe968734d646f834eULL,0x9137ea8f5da6309bULL,0x10f3a624c1f1ce16ULL,0x782a9ea2ca440921ULL,0xdf94739e5b46f1b5ULL,+ 0x1df165a434a35ea8ULL,0x3418e0f74d4412f6ULL,0x5af1f8af518836c3ULL,0x42ceef4d130e1965ULL,0x5560ca0b543a1957ULL,0xc33761e5886cb123ULL,0x66624b1ffe98ed30ULL,0xf772f4bf1090997dULL,+ 0x56f8410ef4f8b16aULL,0x97241afec47b266aULL,0x0a406b8e6d9c87c1ULL,0x803f3e02cd42ab1bULL,0x7f0309a804dbec69ULL,0xa83b85f73bbad05fULL,0xc6097273ad8e197fULL,0xc097440e5067adc1ULL,+ 0xc507b6dd418e7dddULL,0x39888d93472f19d6ULL,0x7eae26be0c27eb4dULL,0x17b53ed3fbabb884ULL,0xfc27021b2b01ae4fULL,0x88462e87cf488682ULL,0xbee096ec215e2d87ULL,0xeb2fea9ad242e29bULL,+ 0xbbcc00c756b95bceULL,0x5ec03906616da680ULL,0x79162ee672214252ULL,0x43132b6386a892d2ULL,0x4bdd3ff22f3263bfULL,0xd5b3733c9cd0a142ULL,0x592eaa8244415ccbULL,0x663e89248d5474eaULL,+ 0x0d38ab35ce7c42d4ULL,0x9fd493ef82feab10ULL,0x46056b6d82111b45ULL,0xda11dae173efc5c3ULL,0xdc7402785545a7fbULL,0xbdb2601c40d507e6ULL,0x121dfeeb7066fa58ULL,0x214369a839ae8c2aULL,+ 0x3f747fa0b311898cULL,0xe2a272e4cd0eac65ULL,0x4bba5851f914d0bcULL,0x7a1a9660c4a43ee3ULL,0xe5a367cea1c8cde9ULL,0x9d958ba97271abe3ULL,0xf3ff7eb63d1615cdULL,0xa2280dcef5ae20b0ULL,+ 0x8c0ed566d4312483ULL,0x5179a95d643e216fULL,0xcc185fec17044493ULL,0xb306333954991a21ULL,0xd801ecdb0081a726ULL,0x0149b0c64fa89bbbULL,0xafe9065a4391b6b9ULL,0xedc92786d633f3a3ULL,+ 0xd6d9d9e37a6a308bULL,0x623758304c2767d3ULL,0x874a8bc6f38cbeb6ULL,0xd94d3f1accb6fd9eULL,0x92a9735bba21f248ULL,0x272ad0e56cd1efb0ULL,0x7437b69c05b03284ULL,0xe7f047026948c225ULL,+ 0x9ae868a9e9adfe1cULL,0x3984403d314e39bbULL,0xb5875720f2fe378fULL,0x33f901e0ba44a628ULL,0xea1125fe3652438cULL,0xae9ec4e69dd1f20bULL,0x1e740d9ebebf7fbdULL,0x6dbd3ddc42dbe79cULL,+ 0x266344a43794f8dcULL,0xdcca923a483c5c36ULL,0x2d6b6bbf3f9d10a0ULL,0xb320c5ca81d9bdf3ULL,0x620e28ff47b50a95ULL,0x933e3b01cef03371ULL,0xf081bf8599100153ULL,0x183be9a0c3a8c8d6ULL,+ 0x8a9443d77613aa81ULL,0x8010080085fe6584ULL,0x70fc4dbc7fb10288ULL,0xf58280d3e86beee8ULL,0x14fdd82f7c978c38ULL,0xdf1204c10de44d7bULL,0xa08a1c844160252fULL,0x591554cac17646a5ULL,+ 0x7ddc81ea77b46a08ULL,0xcf5a6477c7480699ULL,0x43a8cb346633f683ULL,0x1b867e6b92363c60ULL,0x439211141f60558eULL,0xcdbcdd632f41450eULL,0x7fc04601cc630e8bULL,0xea7c66d597038b43ULL,+ 0x34fc8820fbeee3f9ULL,0x93e5349049091afdULL,0x764b9be59a31f35cULL,0x71f3786457e3d924ULL,0x02fb34e0943aa75eULL,0xa18c9c58ab8ff6e4ULL,0x080f31b133cf0d19ULL,0x5c9682db083518a7ULL,+ 0xb6c185c341dca566ULL,0x7de7fedad8622aa3ULL,0x99e84d92901b6dfbULL,0x30a02b0e7c4ad288ULL,0xc7c81daa2fd3cf36ULL,0xd1319547df89e59fULL,0xb2be8184cd496733ULL,0xd5f449eb93d3412bULL,+ 0xc492ec644cd8f64cULL,0x58a2d790279d7b51ULL,0x0ced1fc51fc75256ULL,0x3e658aed8f433017ULL,0x0b61942e05da59ebULL,0xba3d60a30ddc3722ULL,0x7c311cd1742e7f87ULL,0x6473ffeef6b01b6eULL,+ 0x8303604f692ac542ULL,0xf079ffe1227b91d3ULL,0x19f63e6315aaf9bdULL,0xf99ee565f1f344fbULL,0x8a1d661fd6219199ULL,0x8c883bc6d48ce41cULL,0x1065118f3c74d904ULL,0x713889ee0faf8b1bULL,+ 0xc035f697960eb8c7ULL,0xf1599f2ce2de04d3ULL,0x892450f8d2ad9228ULL,0x7d48129bb829c1abULL,0x24d785e13a50afc9ULL,0x2745ba2763a96ee0ULL,0x956534013bfb6d7bULL,0x536202671bad2a42ULL,+ 0x972b3f8f81a1b3beULL,0x4f3ce145ce2764a0ULL,0xe2d0f1cc28c4f5f7ULL,0xdeee0c0dc7f3985bULL,0x7df4adc0d39e25c3ULL,0x40619820c467a080ULL,0x440ebc9361cf5a58ULL,0x527729a6422ad600ULL,+ 0xa691398a4a9eb3f0ULL,0x56c1dbff3b99a48fULL,0x9a87e1b91b4b5b32ULL,0xad6396145378b5feULL,0x437a243ec26b5302ULL,0x0275878c3ccb4c10ULL,0x0e81e4a21de07015ULL,0x0c6265c9850df3c0ULL,+ 0xca6c0937b1b76ba6ULL,0x1a2eab854d2026dcULL,0xb1715e1519d9ae0aULL,0xf1ad9199bac4a026ULL,0x35b3dfb807ea7b0eULL,0xedf5496f3ed9eb89ULL,0x8932e5ff2d6d08abULL,0xf314874e25bd2731ULL,+ 0xc8327149a8c25ff6ULL,0x29bf2556782e6569ULL,0x9012f5c6cd68fc38ULL,0x3e67e8bd3b982ad5ULL,0x5e3a75386ecdca88ULL,0xf297eaa6c1753a04ULL,0x10121e5405db3256ULL,0xab9697d4f0851055ULL,+ 0xefb26a753f73f449ULL,0x1d1c94f88d44fc79ULL,0x49f0fbc53bc0dc4dULL,0xb747ea0b3698a0d0ULL,0x5218c3fe228d291eULL,0x35b804b543c129d6ULL,0xfac859b8d1acc516ULL,0x6c10697d95d6e668ULL,+ 0xe5d27171f6bdf1bfULL,0x0b77b876facb0d8fULL,0xda95471d8496a31bULL,0x46a50dbb3f16b103ULL,0x2a4f3f977b865bffULL,0x848195e66b1c198cULL,0x491ad08821702ea6ULL,0x3f20b43749035228ULL,+ 0xc38e438f0876fd4eULL,0x45f0c30783d2f383ULL,0x203cc2ecb10934cbULL,0x6a8f24392c9d46eeULL,0xf16b431b65ccde7bULL,0x41e2cd1827e76a6fULL,0xb9c8cf8f4e3484d7ULL,0x64426efd8315244aULL,+ 0xe6ec98093a69fc01ULL,0x7e20fecbfaa9dfc2ULL,0x5cfdbb07f56f2a55ULL,0xb1cd68680bbdbfdfULL,0x247b4995986eb9edULL,0x74785bf53dd0955eULL,0x88f74f61c0c7a201ULL,0x8861a15b5d01a80dULL,+ 0x1c0a8e44fc94dea3ULL,0x34c8cdbfdad6a0b0ULL,0x919c384004113cefULL,0xfd32fba415490ffaULL,0x58d190f6795dcfb7ULL,0xfef01b0383588bafULL,0x9e6d1d63ca1fc1c0ULL,0x53173f96f0a41ac9ULL,+ 0x54637e4182997cc1ULL,0x08c5a96ce3720c9cULL,0x78bce01c11de5d45ULL,0x49d623e50dfdd75aULL,0x8c72a4680fb2a3acULL,0xcc53bbff319c25afULL,0x198eba7978a92421ULL,0xcd61f28ba3bdecf3ULL,+ 0x2b1d402aba16f73bULL,0x2fb310148cf9b9fcULL,0x2d51e60e446ef7bfULL,0xc731021bb91e1745ULL,0x9d3b47244fee99d4ULL,0x4bca48b6fac5c1eaULL,0x70f5f514bbea9af7ULL,0x751f55a5974c283aULL,+ 0x23899fe8662595c2ULL,0x495d672711a80773ULL,0x86c971d2b0d1d43bULL,0xb518637c93b7a65fULL,0x30e453bad98c99ceULL,0xba6e0d4a14d39f5bULL,0xf7db02a6431ce415ULL,0xcd909c7cf6e1d823ULL,+ 0x6e30251acb452fdbULL,0x31ee696550f30650ULL,0xb0b3e508933548d9ULL,0xb8949a4ff4b0ef5bULL,0x208b83263c88f3bdULL,0xab147c30db1d9989ULL,0xed6515fd44d4df03ULL,0x17a12f75e72eb0c5ULL,+ 0x25914f7881fdad90ULL,0xcf638f560d2cf6abULL,0xb90bc03fcc054de5ULL,0x932811a718b06350ULL,0x2f00b3309bbd11ffULL,0x76108a6fb4044974ULL,0x801bb9e0a851d266ULL,0x0dd099bebf8990c1ULL,+ 0x14c6dd8a58d6cd46ULL,0x9cb633b58e6634d2ULL,0xc1305047f81bc328ULL,0x12ede0e226a177e5ULL,0x332cca62065a6f4fULL,0xc3a47ecd67be487bULL,0x741eb1870f47ed1cULL,0x99e66e58e7598b14ULL,+ 0xebd6a6777b0ac93dULL,0xa6e37b0d78f5e0d7ULL,0x2516c09676f5492bULL,0x1e4bf8889ac05f3aULL,0xcdb42ce04df0ba2bULL,0x935d5cfd5062341bULL,0x8a30333382acac20ULL,0x429438c45198b00eULL,+ 0xfb2838be67e573e0ULL,0x05891db94084c44bULL,0x9131137396c1c2c5ULL,0x6aebfa3fd958444bULL,0xac9cdce9e56e55c1ULL,0x7148ced32caa46d0ULL,0x2e10c7efb61fe8ebULL,0x9fd835daff97cf4dULL,+ 0x6c626f56c1770616ULL,0x5351909e09da9a2dULL,0xe58e6825a3730e45ULL,0x9d8c8bc003ef0a79ULL,0x543f78b6056becfdULL,0x33f13253a090b36dULL,0x82ad4997794432f9ULL,0x1386493c4721f502ULL,+ 0x3794eefa5abea82aULL,0x8dc611b993fe62d4ULL,0x69f1af37281ef606ULL,0x6af546c839839e69ULL,0x625578c7c977ec23ULL,0xa8de294cbd5c0576ULL,0xe2ddaf0f7cd1a4c0ULL,0x8243fc704f95f4d4ULL,+ 0xe566f400b008733aULL,0xcba0697d512e1f57ULL,0x9537c2b240509cd0ULL,0x5f989c6957353d8cULL,0x7dbec9724c3c2b2fULL,0x90e02fa8ff031fa8ULL,0xf4d15c53cfd5d11fULL,0xb3404fae48314dfcULL,+ 0xa36da109081e9387ULL,0xfb9780d78c935828ULL,0xd5940332e540b015ULL,0xc9d7b51be0f466faULL,0xfaadcd41d6d9f671ULL,0xba6c1e28b1a2ac17ULL,0x066a7833ed201e5fULL,0x19d99719f90f462bULL,+ 0xf02cc3a9f327a07fULL,0xefb27a9b4490937dULL,0x81451e96b1b3afa5ULL,0x67e24de891883be4ULL,0x1ad65d4770869e54ULL,0xd36291a464a3856aULL,0x070a1abf7132e880ULL,0x9511d0a30e28dfdfULL,+ 0xfdeed650f8d1cac4ULL,0xeb99194b6d16bda5ULL,0xb53b19f71cabbe46ULL,0x5f45af5039b9276cULL,0xd0784c6126ee9d77ULL,0xf7a1558b0c02ca5dULL,0xb61d6c59f032e720ULL,0xae3ffb95470cf3f7ULL,+ 0x9b185facc72a4be5ULL,0xf66de2364d848089ULL,0xba14d07c717afea9ULL,0x25bfbfc02d551c1cULL,0x2cef0ecd4cdf3d88ULL,0x8cee2aa3647f73c4ULL,0xc10a7d3d722d67f7ULL,0x090037a294564a21ULL,+ 0xe6567987fa9ced27ULL,0x36b2d8842a9e5dbcULL,0xf4bdeec6380d8e8cULL,0xb5e6a6b0dbc300d0ULL,0x7ba7e9b9592bef36ULL,0x2b373c4fee81b749ULL,0x484b5e01f0ce596bULL,0x7cc51c62c0bf54ccULL,+ 0x6ac07bb84f3815c4ULL,0xddb9f6241aa9017eULL,0x31e30228ca85720aULL,0xe59d63f57cb75838ULL,0x69e18e777baad2d0ULL,0x2cfdb784d42f5d73ULL,0x025dd53df5774983ULL,0x2f80e7cee042cd52ULL,+ 0x4bf56bafec695bb0ULL,0x22da1ca8f13c78adULL,0x0f9c4b131182abb0ULL,0x02ea555aae7d249eULL,0x868583f25e05d9e3ULL,0xe09cdcdf70382afaULL,0xdf072ec787080408ULL,0x0a317847cbf75658ULL,+ 0x43f18d7f4d6ee4abULL,0xd3ac8cde9570c3dcULL,0x527e49070b8c9b2aULL,0x716709a7c5a4c0f1ULL,0x930852b0916a26b1ULL,0x3cc17fcf4e071177ULL,0x34f5e3d459694868ULL,0xee0341aba28f655dULL,+ 0xf431f462060b5f61ULL,0xa56f46b47bd057c2ULL,0x348dca6c47e1bf65ULL,0x9a38783e41bcf1ffULL,0x7a5d33a9da710718ULL,0x5a7799872e0aeaf6ULL,0xca87314d2d29d187ULL,0xfa0edc3ec687d733ULL,+ 0x1c894849cb198ac7ULL,0xa884a93d0f264665ULL,0x2da964ef9b200678ULL,0x3c351b87009834e6ULL,0xafb2ef9fe2c4b44bULL,0x580f6c473326790cULL,0xb84805210b02264aULL,0x8ba6f9e242a194e2ULL,+ 0x39d934abd3c095f1ULL,0x04b261bee4b76d71ULL,0x1d2e6970e73e6984ULL,0x879fb23b5e5fcb11ULL,0x11506c72dfd75490ULL,0x3a97d08561bcf1c1ULL,0x43201d82bf5e7007ULL,0x7f0ac52f798232a7ULL,+ 0xb25101fb319d7682ULL,0xb02931290a982feeULL,0x51c1c9b90261b344ULL,0x0e008c5bbfd371faULL,0xd866dd1c0278ca33ULL,0x666f76a6e5aa53b1ULL,0xe5cfb7796013a2cfULL,0x1d3a1aada3521836ULL,+ 0x76b4131a567193ecULL,0xaf3c305ae5f6e70bULL,0x9587bd39031eebddULL,0x5709def871bbe831ULL,0x570599830eb2b669ULL,0x4d80ce1b875b7029ULL,0x838a7da80364ac16ULL,0x2f431d23be1c83abULL,+ 0xe781276638235d4eULL,0x1c62bd67496e3298ULL,0x8378660c3f175bc8ULL,0x4d04e18917afdd4dULL,0x32a8160185a8068cULL,0xdb58e4e192b29a85ULL,0xe8a65b86c70d8a3bULL,0x5f0e6f4e98a0403bULL,+ 0x2c2492b73f894ae0ULL,0xf59df3e5b75f18ceULL,0x7cb740d28f53cad0ULL,0x3eb585fbc4f01294ULL,0x17da0c8632c7f717ULL,0xeb8c795baf943f4cULL,0x4ee23fb5f67c51d2ULL,0xef18757568889949ULL,+ 0x3ea011a4e822f0d0ULL,0xbc647ad15a8704f8ULL,0xbb315b3550c6820fULL,0x863dec3db7e76becULL,0x01ff5d3af017bfc7ULL,0x20054439976b8229ULL,0x067fca370bbd0d3bULL,0xf63dde647f5e3d0fULL,+ 0x75d9bc15adf7cccfULL,0x81a3e5d6dfa1e1b0ULL,0x8c39e444249bc17eULL,0xf37dccb28ea7fd43ULL,0xda654873907fba12ULL,0x35daa6da4a372904ULL,0x0564cfc66283a6c5ULL,0xd09fa4f64a9395bfULL,+ 0xb510b3b56aa39dffULL,0x59b43da29f8e4d8cULL,0xa8ce31fd9e4c4b9fULL,0x0e20be26c1303c01ULL,0x18187182e8ee47c9ULL,0xd9687cdb7db98101ULL,0x7a520e4da1e14ff6ULL,0x429808ba8836d572ULL,+ 0x174d46996d16768eULL,0x9fc4ff6a628bf217ULL,0x77705a94154e490dULL,0x9d96dd288d2d997aULL,0x77e2d9d8ce5d72c4ULL,0x9d06c5a4c11c714fULL,0x02aa513679e4a03eULL,0x1386b3c2030ff28bULL,+ 0x26a42d69ea40dc3aULL,0xdc84ad22aecc018fULL,0x25c36c7b3270f04aULL,0x46ba6d4750fa72edULL,0x6c37d1c593e58a8eULL,0xa2394731120c088cULL,0xc3be4263cb6e86daULL,0x2c417d367126d038ULL,+ 0xcca523bb440e2229ULL,0x324673a273ef4d04ULL,0xaf3adf343e11ec39ULL,0x6136d7f1dc5968d3ULL,0x7a7b2899b053a927ULL,0x3eaa2661ae067ecdULL,0x8549b9c802779cd9ULL,0x061d7940c53385eaULL,+ 0xe07141fcaaa2902bULL,0x539ad799e4f69ad3ULL,0xa6453f94813f9ffdULL,0xc58d3c48375bc2f7ULL,0xb3326fad5dc64e96ULL,0x3aafcaa9b240e354ULL,0x1d1b0903aca1e7a9ULL,0x4ceb97671211b8a0ULL,+ 0x1eb4de4687032d58ULL,0xc54f3d835e2c79e0ULL,0x07818df45d04ef23ULL,0x55faa9c8673d41b4ULL,0xced64f6f89b95355ULL,0x4860d2eab7415c84ULL,0x5fdb9bd2050ebad3ULL,0xdb53e0cc6685a5bfULL,+ 0x919fca5fabfae1caULL,0x937afaac1a21459bULL,0x9e0ca91c1f66a4d2ULL,0x194cc7f323ec1331ULL,0xad25143a8aa11690ULL,0xbe40ad8d09b59e08ULL,0x37d60d9be750860aULL,0x6c53b008c6bf434cULL,+ 0x832d7080eb6b242dULL,0xd30bd0233b71e246ULL,0x7027991bbe31139dULL,0x68797e91462e4e53ULL,0x423fe20a6b4e185aULL,0x82f2c67e42d9b707ULL,0x25c817684cf7811bULL,0xbd53005e045bb95dULL,+ 0xe5f649be9d8e68fdULL,0xdb0f05331b044320ULL,0xf6fde9b3e0c33398ULL,0x92f4209b66c8cfaeULL,0xe9d1afcc1a739d4bULL,0x09aea75fa28ab8deULL,0x14375fb5eac6f1d0ULL,0x6420b560708f7aa5ULL,+ 0x9eae499c6254dc41ULL,0x7e2939247a837e7eULL,0x74aec08c090524a7ULL,0xf82b92198d6f55f2ULL,0x493c962e1402cec5ULL,0x9f17ca17fa2f30e7ULL,0xbcd783e8e9b879cbULL,0xea3d8c145a6f145fULL,+ 0xdede15e75e0dee6eULL,0x74f24872dc628aa2ULL,0xd3e9c4fe7861bb93ULL,0x56d4822a6187b2e0ULL,0xb66417cfc59826f9ULL,0xca2609692408169eULL,0xedf69d06c79ef885ULL,0x00031f8adc7d138fULL,+ 0x103c46e60ebcf726ULL,0x4482b8316231470eULL,0x6f6dfaca487c2109ULL,0x2e0ace9762e666efULL,0x3246a9d31f8d1f42ULL,0x1b1e83f1574944d2ULL,0x13dfa63aa57f334bULL,0x0cf8daed9f025d81ULL,+ 0x30d78ea800ee11c1ULL,0xeb053cd4b5e3dd75ULL,0x9b65b13ed58c43c5ULL,0xc3ad49bdbd151663ULL,0x99fd8e41b6427990ULL,0x12cf15bd707eae1eULL,0x29ad4f1b1aabb71eULL,0x5143e74d07545d0eULL,+ 0x30266336c88bdee1ULL,0x25f293065876767cULL,0x9c078571c6731996ULL,0xc88690b2ed552951ULL,0x274f2c2d852705b4ULL,0xb0bf8d444e09552dULL,0x7628beeb986575d1ULL,0x407be2387f864651ULL,+ 0x0e5e3049a639fc6bULL,0xe75c35d986003625ULL,0x0cf35bd85dcc1646ULL,0x8bcaced26c26273aULL,0xe22ecf1db5536742ULL,0x013dd8971a9e068bULL,0x17f411cb8a7909c5ULL,0x5757ac98861dd506ULL,+ 0x85de1f0d1e935abbULL,0xdefd10b4154de37aULL,0xb8d9e392369cebb5ULL,0x54d5ef9b761324beULL,0x4d6341ba74f17e26ULL,0xc0a0e3c878c1dde4ULL,0xa6d7758187d918fdULL,0x6687601502ca3a13ULL,+ 0xc7313e9cf36658f0ULL,0xc433ef1c71f8057eULL,0x853262461b6a835aULL,0xc8f053987c86394cULL,0xff398cdfe983c4a1ULL,0xbf5e816203b7b931ULL,0x93193c46b7b9045bULL,0x1e4ebf5da4a6e46bULL,+ 0xf9942a6043a24fe7ULL,0x29c1191effb3492bULL,0x9f662449902fde05ULL,0xc792a7ac6713c32dULL,0x2fd88ad8b737982cULL,0x7e3a0319a21e60e3ULL,0x09b0de447383591aULL,0x6df141ee8310a456ULL,+ 0xaec1a039e6d6f471ULL,0x14b2ba0f1198d12eULL,0xebc1a1603aeee5acULL,0x401f4836e0b964ceULL,0x2ee437964fd03f66ULL,0x3fdb4e49dd8f3f12ULL,0x6ef267f629380f18ULL,0x3e8e96708da64d16ULL,+ 0xbc19180c207674f1ULL,0x112e09a733ae8fdbULL,0x996675546aaeb71eULL,0x79432af1e101b1c7ULL,0xd5eb558fde2ddec6ULL,0x81392d1f5357753fULL,0xa7a76b973ae1158aULL,0x416fbbff4a899991ULL,+ 0x9e65fdfd0d4a9dcfULL,0x7bc29e48944ddf12ULL,0xbc1a92d93c856866ULL,0x273c69056e98dfe2ULL,0x69fce418cdfaa6b8ULL,0x606bd8235061c69fULL,0x42d495a06af75e27ULL,0x8ed3d5056d873a1fULL,+ 0xaf5528416ab25b6aULL,0xc6c0ffc72b1a4523ULL,0xab18827b21c99e03ULL,0x060e86489034691bULL,0x5207f90f93c7f398ULL,0x9f4a96cb82f8d10bULL,0xdd71cd793ad0f9e3ULL,0x84f435d2fc3a54f5ULL,+ 0x4b03c55b8e33787fULL,0xef42f975a6384673ULL,0xff7304f75051b9f0ULL,0x18aca1dc741c87c2ULL,0x56f120a72d4bfe80ULL,0xfd823b3d053e732cULL,0x11bccfe47537ca16ULL,0xdf6c9c741b5a996bULL,+ 0xee7332c7904fc3faULL,0x14a23f45c7e3636aULL,0xc38659c3f091d9aaULL,0x4a995e5db12d8540ULL,0x20a53becf3a5598aULL,0x56534b17b1eaa995ULL,0x9ed3dca4bf04e03cULL,0x716c563ad8d56268ULL,+ 0x5043dea7e0f222c2ULL,0x309d42ac72e65142ULL,0x94fe9ddd9216cd30ULL,0xd6539c7d0f87feecULL,0x03c5a57c432ac7d7ULL,0x72692cf0327fda10ULL,0xec28c85f280698deULL,0x2331fb467ec283b1ULL,+ 0xa0158eeae457a477ULL,0xd19857dbee6ddc05ULL,0xb326522418c41671ULL,0x3ffdfc7e3c2c0d58ULL,0x3a3a525426ee7cdaULL,0x341b0869df02c3a8ULL,0xa023bf42723bbfc8ULL,0x3d15002a14452691ULL,+ 0xc961b2f687500b96ULL,0x795510e72dcd9425ULL,0x0308172978615433ULL,0xe5d0145465445029ULL,0x5bd13302bf690cbeULL,0x44e48831731eca67ULL,0x73306bc72b8038a4ULL,0x351d151ebf57bf02ULL,+ 0x5ef7324c85edfa30ULL,0x2597655487d4f3daULL,0x352f5bc0dcb50c86ULL,0x8f6927b04832a96cULL,0xd08ee1ba55f2f94cULL,0x6a996f99344b45faULL,0xe133cb8da8aa455dULL,0x5d0721ec758dc1f7ULL,+ 0xf3d44e1f9a876441ULL,0x82bc0c14147a818dULL,0x33ddc1170603eddeULL,0x77163f2e0a25f260ULL,0xb54c02caa3bfaa53ULL,0xbd1b2502e2256982ULL,0xc4e1728c1a6f37dcULL,0xfe36c213814c94a5ULL,+ 0xf3cae7e9262a3539ULL,0x78a49d1d6670d59eULL,0x37de0f63c1c5e1b9ULL,0x3072c30c69cb7c1cULL,0x1d278a5277c850e6ULL,0x84f15f8f1f6a3de6ULL,0x46a8bb45592ca7adULL,0x1912e3eee4d424b8ULL,+ 0xc1ffe2d490e31734ULL,0x91b1f1267fca007cULL,0x5459b1d0ae3f77e8ULL,0x262b051d46425c88ULL,0xcf5c8f765c51e274ULL,0x997481e2304e6146ULL,0x6fc1198bd84046b5ULL,0x1cb0a6bbe7f7a6bdULL,+ 0x6ba7a92079e5fb67ULL,0xe1331feb70aa725eULL,0x5080ccf57df5d837ULL,0xe4cae01d7ff72e21ULL,0xd9243ee60412a77dULL,0x06ff7cacdf449025ULL,0xbe75f7cd23ef5a31ULL,0xbc9578220ddef7a8ULL,+ 0xc4737ad11b7f30b0ULL,0x525ab2c63629dcf9ULL,0x963f4cc1186ae160ULL,0x8507671373e6b6e0ULL,0xd9be3180f6998bcfULL,0x93d91da3b1c8d8d8ULL,0xf902ce661b8c0054ULL,0x47e7924d74a8a768ULL,+ 0xdc988086365e668bULL,0xada8dcdaaabda5fbULL,0xbc146b4c255f1fbeULL,0x9cfcde29cf34cfc3ULL,0xacbb453e7e85d1e4ULL,0x9ca09679f92358b5ULL,0x15fc2d96240823ffULL,0x8d65adf70c11d11eULL,+ 0x323cfd177e19a46fULL,0x0948a7a786161156ULL,0x50d06b977e7d3363ULL,0x41c47ec1a702579dULL,0x9455998e59e9260bULL,0xc865e44446c24260ULL,0x393021ec13bc3744ULL,0x4981994ecd92a14aULL,+ 0x8cf7230cb0ce1c55ULL,0x5b534d050bbfb607ULL,0xee1ef1130e16363bULL,0x27e0aa7ab4999e82ULL,0xce1dac2d79362c41ULL,0x67920c9091bb6cb0ULL,0x1e648d632223df24ULL,0x0f7d9eefe32e8f28ULL,+ 0x9766f264d66f51c0ULL,0x644317ab5d9ccea5ULL,0xa39b37bcd721e232ULL,0x98bdde0bb9daf737ULL,0xc2ecc758165166bdULL,0x0951a285a2802108ULL,0xe39fbf24997aa66fULL,0x1a2f6862db62da27ULL,+ 0x775557f10296f4fdULL,0x1dca76a3ea51b436ULL,0xf3e98f60fb950805ULL,0x31ff32ea831cf7f1ULL,0x643e7bf18d2c714bULL,0x64b5c3392e9d2acaULL,0xa9fd9ccc6adc2d23ULL,0xfc2397eccc721b9bULL,+ 0xab651fc764465367ULL,0xe43870152b098f57ULL,0x0a91d519d382376fULL,0xb5afdb0a53cad929ULL,0x457e1875138d5523ULL,0xa92becae1aecacfbULL,0x0762f6e811484f49ULL,0x114b5c86dda16c2bULL,+ 0x6943f39afa833834ULL,0x22951722a6328562ULL,0x81d63dd54170fc10ULL,0x9f5fa58faecc2e6dULL,0xb66c8725e77d9a3bULL,0x11235cea6384ebe0ULL,0x06a8c1185845e24aULL,0x0137b286ebd093b1ULL,+ 0xdb567d6ac42bd6d2ULL,0x6df86468bb1f96aeULL,0x0efe5b1a4843b28eULL,0x961bbb056379b240ULL,0xb6caf5f070a6a26bULL,0x70686c0d328e6e39ULL,0x80da06cf895fc8d3ULL,0x804d8810b363fdc9ULL,+ 0x63b99ce74462007dULL,0xb8ab48a54cb5f5b7ULL,0x9ec673d2f55edde7ULL,0xd1567f748cfaefdaULL,0x46381b6b0887bcecULL,0x694497cee178f3c2ULL,0x5e6525e31e6266cbULL,0x5931de26697d6413ULL,+ 0x14e49da11f17a34cULL,0x5420ab39235a1456ULL,0xb76372412f50363bULL,0x7b15d623c3fabb6eULL,0xa0ef40b1e274e49cULL,0x5cf5074496b1860aULL,0xd6583fbf66afe5a4ULL,0x44240510f47e3e9aULL,+ 0x142b55021a93507aULL,0xb4cd11878d3c06cfULL,0xdf70e76a91ec3f40ULL,0x484e81ad4e7553c2ULL,0x830f87b5272e9d6eULL,0xea1c93e5c6ff514aULL,0x67cc2adcc4192a8eULL,0xc77e27e242f4535aULL,+ 0xb5358b1e48ac2840ULL,0x18311294ecba9477ULL,0xda58f990a6946b43ULL,0x3098baf99ab41819ULL,0x66c4c1584198da52ULL,0xab4fc17c146bfd1bULL,0x2f0a4c3cbf36a908ULL,0x2ae9e34b58cf7838ULL,+ 0x45eb40ec0ccced58ULL,0x25cd4b9c0da44f98ULL,0x43e06458871812c6ULL,0x99f80d5516cef651ULL,0x571340c9ce6dc153ULL,0x138d5117d8665521ULL,0xacdb45bc4e07014dULL,0x2f34bb3884b60b91ULL,+ 0x417499e84a34f239ULL,0x15fdb83cb90402d5ULL,0xb75f46bf433aa832ULL,0xb61e15af63215db1ULL,0xaabe59d4a127f89aULL,0x5d541e0c07e816daULL,0xaaba0659a618b692ULL,0x5532773317266026ULL,+ 0x8cda9cf2d0c05199ULL,0x502fbc22fae78454ULL,0xc0bda9dff572a182ULL,0x5f9b71b86158b372ULL,0xe0f33a592b82dd07ULL,0x763027359523032eULL,0x7fe1a721c4505a32ULL,0x7b6e3e82f796409fULL,+ 0x023c155d3f6effc7ULL,0x1fbd69ff9c90f0c7ULL,0xe5d7da8abeec2c5dULL,0x8813872bd7e86273ULL,0x9f3bc2c655f5e228ULL,0x11482869b0923b41ULL,0x65d75c741aa307caULL,0xda92c2577f24eee5ULL,+ 0x26357732edc665d1ULL,0x9fb5b731a939ef1bULL,0x7db720fb94968089ULL,0x36f75f2c33138c52ULL,0xf8b793ec48d3cb97ULL,0x8dff1d456d261726ULL,0xfb65791b885c4ffbULL,0xf7c79e2df1a3a870ULL,+ 0x08dd1028754c92e1ULL,0xca90b57acf0fef34ULL,0x1a9b84ac8af55919ULL,0xaa95e0e1ed93686bULL,0x46737315167021a4ULL,0x6cb6a0da20d5ff98ULL,0xecc4801a1092e706ULL,0xedcab23a3c5e61a6ULL,+ 0xb4c66356ea37ba9eULL,0x1adc84150afff55dULL,0xf0080ef9596cc862ULL,0x756c85b86d647ab6ULL,0xc9db94aa1db9c215ULL,0x2dd36db12013b1a5ULL,0xde6ac61c4286c903ULL,0x3fd32f88c76cf884ULL,+ 0x7f1290fca06d107eULL,0x697261fdb7661137ULL,0x1bb5be4e947b4b38ULL,0xb49826b63bb79130ULL,0x019ddfe85ba8bffbULL,0xb1af79007e3fa8e4ULL,0x72e1bdf201bcfe7fULL,0x2ed3ca8fd1169aeaULL,+ 0x3befda8cd745fff1ULL,0x70b9e9b669b9924eULL,0xa5df48cfd1511381ULL,0x84f93fe2d06bc535ULL,0xaa42c5a9b279a6c3ULL,0x651da6c4d8f96132ULL,0xb0368c8b01b6aea5ULL,0x64e44c47ac7862a2ULL,+ 0xe17a9947d9de99a8ULL,0xc2e61b2dc93477bdULL,0x57f684d41d19e287ULL,0x843c2122fe358135ULL,0xe2d3e2e904f7e8abULL,0xbf93ffe9b5f27aeeULL,0x29830d1d7b1858c4ULL,0xa8f449648106adbfULL,+ 0xe3417bc035d0b34aULL,0x440b386b8327c0a7ULL,0x8fb7262dac0362d1ULL,0x2c41114ce0cdf943ULL,0x2ba5cef1ad95a0b1ULL,0xc09b37a867d54362ULL,0x26d6cdd201e486c9ULL,0x20477abf42ff9297ULL,+ 0xa004dcb3292a9287ULL,0xddc15cf677b092c7ULL,0x083a8464806c0605ULL,0x4a68df703db997b0ULL,0x9c134e4505bf7dd0ULL,0xa4e63d398ccf7f8cULL,0xa6e6517f41b5f8afULL,0xaa8b9342ad7bc1ccULL,+ 0xc41764717af715d2ULL,0xe2f7f594d0134a96ULL,0x2c1873efa41ec956ULL,0xe4e7b4f677821304ULL,0xe5c8ff9788d5374aULL,0x2b915e6380823d5bULL,0xea6bc755b2ee8fe2ULL,0x6657624ce7112651ULL,+ 0xd6f800e07442f1d5ULL,0x475607d166e0e3abULL,0x82807f16b7c64047ULL,0x8858e1e3a749883dULL,0x5859120b8231ee10ULL,0x1b80e7eb638a1eceULL,0xcb72525ac6aa73a4ULL,0xa7cdea3d844423acULL,+ 0x57477b11e51732d2ULL,0xdfd6eb282538fc0eULL,0x5c43b0cc3b39eec5ULL,0x6af12778cb36cc57ULL,0x70b0852d06c425aeULL,0x6df92f8c5c221b9bULL,0x6c8d4f9ece826d9cULL,0xf59aba7bb49359c3ULL,+ 0xd2eb2cf152bfda05ULL,0xe0e4c4e96197b98cULL,0x1d35076cf8a1726fULL,0x6c06085b2db11e3dULL,0x15c0c4d74463ba14ULL,0x9d292f830030238cULL,0x1311ee8b3727536dULL,0xfeea86efbeaedc1eULL,+ 0xa7f96054afa05dd8ULL,0x26dfcf21fcaf119eULL,0xe20ef2e30564bb59ULL,0xef4dca5061cb02b8ULL,0xcda7838a65d30672ULL,0x8b08d534fd657e86ULL,0x4c5b439546d595c8ULL,0x39b58725425cb836ULL,+ 0xfda853931a62cc26ULL,0x23c69b9650c0e052ULL,0xa227df15bfc633f3ULL,0x2ac788481bae7d48ULL,0x487878f9187d073dULL,0x6c2be919967f807dULL,0x765861d8336e6d8fULL,0x88b8974cce528a43ULL,+ 0xc37e2c2e421d3aa4ULL,0xf926407ce84fa840ULL,0x18abc03d1454e41cULL,0x26605ecd3f7af644ULL,0x242341a6d6a5eabfULL,0x1edb84f4216b668eULL,0xd836edb804010102ULL,0x5b337ce7945e1d8cULL,+ 0x666ba2dccc78cf66ULL,0xb30181746fdbff77ULL,0x8d4dd0db168d4668ULL,0x259455d01dab3a2aULL,0xf58564c5cde3acecULL,0x7714192513adb276ULL,0x527d725d8a303f65ULL,0x55deb6c9e6f38f7bULL,+ 0x864d05d73272d838ULL,0xe22924f9fa6295c5ULL,0x8189593f6c2fda32ULL,0x330d7189b184b544ULL,0x79efa62cbde1f714ULL,0x35771c94e5cb1a63ULL,0x2f4826b8641c8332ULL,0x00a894fbc8cee854ULL,+ 0xdcdacd0a1058a318ULL,0x369cf3f578053a9aULL,0xc6c3de5031c68de2ULL,0x4653a5763c4b6d9fULL,0x1688dd5aaa4e5c97ULL,0x5be80aa1b7ab3c74ULL,0x70cefe7cbc65c283ULL,0x57f95f1306867091ULL,+ 0xc240b6de34eaacdaULL,0xd9e116e82ba0f1deULL,0xcbe45ec779438e55ULL,0x91787c9d96f752d7ULL,0x897f532bf129ac2fULL,0xd307b7c85a36e22cULL,0x91940675749fb8f3ULL,0xd14f95d0157fdb28ULL,+ 0x1625360416df4285ULL,0xb0c9babbd0c56ae2ULL,0x73032b19cfc5cfc3ULL,0xe497e5c309752056ULL,0x12096bb4164bda96ULL,0x1ee42419a0b74da1ULL,0x8fc36243403826baULL,0x0c8f0069dc09e660ULL,+ 0xc44b74a15b0ec6f5ULL,0x47989fe45289b2b8ULL,0x745f848458d6fc73ULL,0xec362a6ff61c70abULL,0x070c98a7b3a8ad41ULL,0x73a20fc07b63db51ULL,0xed2c2173f44c35f4ULL,0x8a56149d9acc9dcaULL,+ 0xa395c36f35d33ae7ULL,0x200ea12350bb5a94ULL,0x20c789bd0bafe84bULL,0x243ef52d0919276aULL,0x3934c577e23ae233ULL,0xb93807afa460d1ecULL,0xb72a53b1f8fa76a4ULL,0xd8914cb0c3ca4491ULL,+ 0x4c076b86d23ddc82ULL,0x03fd344c7e0143f0ULL,0xa95362ff317af2c5ULL,0x0add3db7e18b7a4fULL,0x9c673e3f8260e01bULL,0xfbeb49e554a1cc91ULL,0x91351bf292f2e433ULL,0xc755e7ec851141ebULL,+ 0x2bf5db47f23206d5ULL,0x2f6d34201d260152ULL,0x17b876533f8ff89aULL,0x5157c30c378fa458ULL,0x7517c5c52d4fb936ULL,0xef22f7ace6518cdcULL,0xdeb483e6bf847a64ULL,0xf508455892e0fa89ULL,+ 0xab9659d8df7304d4ULL,0xb71bcf1bff210e8eULL,0xa9a2438bd73fbd60ULL,0x4595cd1f5d11b4deULL,0x9c0d329a4835859dULL,0x4a0f0d2d7dbb6e56ULL,0xc6038e5edf928a4eULL,0xc94296218f5ad154ULL,+ 0x08a33840a70c6ec4ULL,0x9e8819f7e0311195ULL,0xed209d96708ab202ULL,0x10d7c4e7ce943a27ULL,0x372fb317a29b49a1ULL,0x57a67fb346627d1fULL,0xf912561e7cdf39ecULL,0xfa3ce6f26f7c8f17ULL,+ 0x91213462f23f2d92ULL,0x6cab71bd60b94078ULL,0x6bdd0a63176cde20ULL,0x54c9b20cee4d54bcULL,0x3cd2d8aa9f2ac02fULL,0x03f8e617206eedb0ULL,0xc7f68e1693086434ULL,0x831469c592dd3db9ULL,+ 0xfe7d7465653f3c5fULL,0x283dd45ef040feb1ULL,0x91fe599bf3b7edfeULL,0x5ff039ad80379311ULL,0xbf76995b4e96fa49ULL,0x2640b6b2a3e25094ULL,0x8b096341c1c83f74ULL,0xd2bec884fa560ac3ULL,+ 0x8521df248f981354ULL,0x587e23ec3588a259ULL,0xcbedf281d7a0992cULL,0x06930a5538961407ULL,0x09320debbe5bbe21ULL,0xa7ffa5b52491817fULL,0xe6c8b4d909065160ULL,0xac4f3992fff6d2a9ULL,+ 0x2e4eb2a3cc53da66ULL,0x04708a71f17a9b4eULL,0xdbfdc7b20de05b2cULL,0x4cdc9aee4907a201ULL,0xe5cc8dfc6c475566ULL,0x2b83cbfb47be1691ULL,0x695833a74c05c3fdULL,0xee938a7243b0deb0ULL,+ 0x7aa7a1583ae9c1bdULL,0xe0af6d98e37ce240ULL,0xe54342d928ab38b4ULL,0xe8b750070a1c98caULL,0xefce86afe02358f2ULL,0x31b8b856ea921228ULL,0x052a19120a1c67fcULL,0xb4069ea4e3aead59ULL,+ 0x3b826205c6ffcfe6ULL,0x2eb31256aa39418aULL,0xc4b4a9e1c18521fbULL,0x48614dd8db610615ULL,0x04c362bbeea7475fULL,0x916ab969a8ead162ULL,0x6a7975bc0310a876ULL,0xea4e7d11ecc77ec4ULL,+ 0x3232d6e27fa03cb3ULL,0xdb938e5b0fdd7d88ULL,0x04c1d2cd2ccbfc5dULL,0xd2f45c12af3a580fULL,0x592620b57883e614ULL,0x5fd27e68be7c5f26ULL,0x139e45a91567e1e3ULL,0x2cc71d2d44d8aaafULL,+ 0x6ef493c706ba8e6fULL,0x05c07bf8123deffdULL,0xcebf9b4d9c2b5a4fULL,0xf958147e2d038e9cULL,0x5af5cee03e5561c4ULL,0x8d0b5a7a794a6afcULL,0x9de22df13772168bULL,0xe5d249c5d84097fdULL,+ 0x4a9090cde36d0757ULL,0xf722d7b1d9a29382ULL,0xfb7fb04c04b48ddfULL,0x628ad2a7ebe16f43ULL,0xcd3fbfb520226040ULL,0x6c34ecb15104b6c4ULL,0x30c0754ec903c188ULL,0xec336b082d23cab0ULL,+ 0x74c70b4295c69248ULL,0x8813259dfed90303ULL,0xa3e330684b8cc87aULL,0xe689371c111a7a95ULL,0x52bfbbf7fbbbc20bULL,0x73a8543d65f9a6e2ULL,0x67bb2fdd7e413e6dULL,0xa066b3efc5cf2032ULL,+ 0x473d62a21e206ee5ULL,0xf1e274808c49a633ULL,0x87ab956ce9f6b2c3ULL,0x61830b4862b606eaULL,0x67cd6846e78e815fULL,0xfe40139f4c02082aULL,0x52bbbfcb952ec365ULL,0x74c116426b9836abULL,+ 0xcf61b89c44f48971ULL,0xe2d700f76d660683ULL,0x72ef285cd1d431bdULL,0x0593b24e9bdebf4aULL,0x4084bc5b0561f8a1ULL,0x84ce74d0aa16f256ULL,0x9cbc79d309f6d277ULL,0xa94fe2fe4139bdfeULL,+ 0x9f51439e558df019ULL,0x230da4baac712b27ULL,0x518919e355185a24ULL,0x4dcefcdd84b78f50ULL,0xa7d90fb2a47d4c5aULL,0x55ac9abfb30e009eULL,0xfd2fc35974eed273ULL,0xb72d824cdbea8fafULL,+ 0x549db2b5ef7d9289ULL,0x2480d4a8197f015aULL,0x61d5590bc40493b6ULL,0x3a55b52e6f780331ULL,0x40eb8115309eadb0ULL,0xdea7de5a92e5c625ULL,0x64d631f0cc6a3d5aULL,0x9d5e9d7c93e8dd61ULL,+ 0x196860411e84e0e5ULL,0xa5db84d3aea34c93ULL,0xf9d5bb197073a732ULL,0xb8d2fe566bcfd7c0ULL,0x45775f36f3eb82faULL,0x8cb20cccfdff8b58ULL,0x1659b65f8374c110ULL,0xb8b4a422330c789aULL,+ 0xc925ff87aedbae9fULL,0x7daf0eb936880a54ULL,0x9284ddf59c4d0e71ULL,0x1581cf93316f8cf5ULL,0x3eeca8873ac1f452ULL,0xb417fce9fb6aeffeULL,0xa5918046eefb8dc3ULL,0x73d318ac02209400ULL,+ 0xc4f4cda3af2ebc2fULL,0xa0af843dcb4efe24ULL,0x53b857c19ccd10b1ULL,0xddc9d1eb914d3e04ULL,0x7bdec8bb62771debULL,0x829277aa91c5aa81ULL,0x7af18dd6832391aeULL,0x1740f316c71a84caULL,+ 0xdd4a12d8e12b31f8ULL,0x577e29bc177736e6ULL,0x2353722ba88935e8ULL,0xca1d3729015f286dULL,0x86c7b6a239a3e035ULL,0x6e5250bfd3b03a9fULL,0x79d98930fd0d536eULL,0x8c4cbbabfa0c3832ULL,+ 0x2d500910cab91f1eULL,0xbedd9e444d1cd216ULL,0xd634b74fedd02252ULL,0xbd60f8e11258617aULL,0xd8c7537b9e05614aULL,0xfd26c766e7af5fc5ULL,0x0660b581582bd926ULL,0x87019244acf07fc8ULL,+ 0xafa26ccfaf64ecb6ULL,0xe6054f974bd72775ULL,0xbbcbab5b140f695aULL,0xbc71b4a4e348efdeULL,0xfc2e52becc96d963ULL,0x150abf5f5e5d9018ULL,0xbd182fa604568771ULL,0x35b4c06170339f83ULL,+ 0x8928e99aeeaf8c49ULL,0xee7aa73d6e24d728ULL,0x4c5007c2e72b156cULL,0x5fcf57c5ed408a1dULL,0x9f719e39b6057604ULL,0x7d343c01c2868bbfULL,0x2cca254b7e103e2dULL,0xe6eb38a9f131bea2ULL,+ 0xc624a04e5f40ff52ULL,0x3611d7cffcd2914aULL,0xb7e8b42b1fd3bfd6ULL,0x6cde40fdfa85063aULL,0x7811c449178b7e5bULL,0x4cb609312972cc13ULL,0xf579125e33b46135ULL,0xca102ef788a4e56eULL,+ 0x0ba4e3520a981b0dULL,0x1c354cb3bd1a41a4ULL,0x1aabaa3adf9fab9cULL,0x0701a7d153c418d5ULL,0xdd1a7cefdcf2b921ULL,0x6ceef0b3bcf48061ULL,0x1083b598de25cce6ULL,0x890a54c7e90a5e34ULL,+ 0xc535956640ac1807ULL,0xd4c1e56684da0b1eULL,0xc4b33f97e0b82421ULL,0xd0bd23177b41be00ULL,0x53a4b42e147b72e1ULL,0xf8d39f5ff777104cULL,0x36e64e64d3fb530dULL,0xa7a6ba6756074fddULL,+ 0x405718db4f6d01b1ULL,0xe73c6bc28f11e8a0ULL,0xac11bb8ca0591a3bULL,0x12d09a5a0acc4531ULL,0xcbf174eee7de13f4ULL,0x177e2be6044fd682ULL,0x65f574cb1c48af70ULL,0xce5966929961cb7cULL,+ 0x989fe84ebc6fab9fULL,0xe70ce6b1c80f6474ULL,0xbe9ff3053b02a1bcULL,0x12ef486699c0afd3ULL,0x22d957f9e3411a26ULL,0x0b41d8817b485b98ULL,0x820e56d04ae20119ULL,0x81e3d01f328528e0ULL,+ 0xc59eed6c048752a1ULL,0x41f2702ea01341b4ULL,0x6e35903b9dc6b092ULL,0x4291aba81f5b5b23ULL,0x8173aa70a653d61dULL,0xd1b648d44f2eb51eULL,0x31b7ce065ab93f8fULL,0xa55408ee99e2f4feULL,+ 0x1fa4ed0985e34160ULL,0xa26d7dc37a03cde2ULL,0x1dac0848fa84df2dULL,0x5e9a28d61b697108ULL,0xa88004d914ea0ea1ULL,0xa8d154283ffe5520ULL,0x4f422dae639b139cULL,0xeedccc0dd4b5a861ULL,+ 0xb33e624f8be762b4ULL,0x2a9ee4d1058e3413ULL,0x968e636967d805faULL,0x9848949b7db8bfd7ULL,0x5308d7e5d23a8417ULL,0x892f3b1df3e29da5ULL,0xc95c139e3dee471fULL,0x8631594dd757e089ULL,+ 0x1083e2ea1f095615ULL,0x0a28ad7714e68c33ULL,0x6bfc02523d8818beULL,0xb585113af35850cdULL,0x7d935f0b30df8aa1ULL,0xaddda07c4ab7e3acULL,0x92c34299552f00cbULL,0xc33ed1de2909df6cULL,+ 0x2dc40d483e07113cULL,0x6e4a5d397d8b63aeULL,0x5582a94b79684c2bULL,0x932b33d4622da26cULL,0xf534f6510dbbf08dULL,0x211d07c964c23a52ULL,0x0eeece0fee5bdc9bULL,0xdf178168f7015558ULL,+ 0xabe7905a83cdd60eULL,0x50602fb5a1170184ULL,0x689886cdb023642aULL,0xd568d090a6e1fb00ULL,0x5b1922c70259217fULL,0x93831cd9c43141e4ULL,0xdfca35870c95f86eULL,0xdec2057a568ae828ULL,+ 0x568f8925913cc16dULL,0x18bc5b6de1a26f5aULL,0xdfa413bef5f499aeULL,0xf8835decc3f0ae84ULL,0xb6e60bd865a40ab0ULL,0x65596439194b377eULL,0xbcd8562592084a69ULL,0x5ce433b94f23ede0ULL,+ 0x860d523d42e06189ULL,0xbf0779414e3aff13ULL,0x0b616dcac1b20650ULL,0xe66dd6d12131300dULL,0xd4a0fd67ff99abdeULL,0xc9903550c7aac50dULL,0x022ecf8b7c46b2d7ULL,0x3333b1e83abf92afULL,+ 0xc0da65e784d6365dULL,0xbcb7443f8f759fb8ULL,0x35c712b17ae81930ULL,0x80428dff4c6e08abULL,0xf19dafefa4faf843ULL,0xced8538dffa9855fULL,0x20ac409cbe3ac7ceULL,0x358c1fb6882da71eULL,+ 0xefecdef7be42a582ULL,0xd3fc608065046be6ULL,0xc9af13c809e8dba9ULL,0x1e6c9847641491ffULL,0x3b574925d30c31f7ULL,0xb7eb72baac2a2122ULL,0x776a0dacef0859e7ULL,0x06fec31421900942ULL,+ 0x324794b07e50122bULL,0xdd744f8b4af07ca5ULL,0x30a12f08d63fc97bULL,0x39650f1a76626d9dULL,0x101b47f71fa38477ULL,0x3d815f19d4dc124fULL,0x1569ae95b26eb58aULL,0xc3cde18895fb1887ULL,+ 0x7ec62fbbf4737f21ULL,0xd8dba5ab6209f5acULL,0x24b5d7a9a5f9adbeULL,0x707d28f7a61dc768ULL,0x7711460bcaa999eaULL,0xba7b174d1c92e4ccULL,0x3c4bab6618d4bf2dULL,0xb8f0c980eb8bd279ULL,+ 0x9d658932790691bfULL,0xed61058906b736aeULL,0x712c2f04c0d63b6eULL,0x5cf06fd5c63d488fULL,0x97363facd9588e41ULL,0x1f9bf7622b93257eULL,0xa9d1ffc4667acaceULL,0x1cf4a1aa0a061ecfULL,+ 0x28d675b2c0519a23ULL,0x9ebf94fe4f6952e3ULL,0xf28bb767a2294a8aULL,0x85512b4dfe0af3f5ULL,0x18958ba899b16a0dULL,0x95c2430cba7548a7ULL,0xb30d1b10a16be615ULL,0xe3ebbb9785bfb74cULL,+ 0x07b53f5eb2e63645ULL,0xbe57e54784c84232ULL,0xd779c2167214d5cfULL,0x617969cd029a3acaULL,0xd17668cd8a7017a0ULL,0x77b4d19abe9b7ee8ULL,0x58fd0e939c161776ULL,0xa8c4f4efd5968a72ULL,+ 0x81eeb865d2fdca23ULL,0x5a15ee08cc8ef895ULL,0x768fa10a01905614ULL,0xeff5b8ef880ee19bULL,0xf0c0cabbcb1c8a0eULL,0x2e1ee9cdb8c838f9ULL,0x0587d8b88a4a14c0ULL,0xf6f278962ff698e5ULL,+ 0x519d34b3bf44da80ULL,0x283834f95ab32e66ULL,0x6e6087976278a000ULL,0x1e62960e627312f6ULL,0x9b87b27be6901c55ULL,0x80e7853824fdbc1fULL,0xbbbc09512facc27dULL,0x06394239ac143b5aULL,+ 0x9c4b646e9e2fce99ULL,0x68a210811e80857fULL,0x06d54e443643b52aULL,0xde8d6d630d8eb843ULL,0x7032156342146a0aULL,0x8ba826f25eaa3622ULL,0x227a58bd86138787ULL,0x43b6c03c10281d37ULL,+ 0x02b37a952f41deffULL,0x0e44a59ae63b89b7ULL,0x673257dc143ff951ULL,0x19c02205d752baf4ULL,0x46c23069c4b7d692ULL,0x2e6392c3fd1502acULL,0x6057b1a21b220846ULL,0xe51ff9460c1b5b63ULL,+ 0x6e85cb51566c5c43ULL,0xcff9c9193597f046ULL,0x9354e90c4994d94aULL,0xe0a393322147927dULL,0x8427fac10dc1eb2bULL,0x88cfd8c22ff319faULL,0xe2d4e68401965274ULL,0xfa2e067d67aaa746ULL,+ 0xb6d92a7f3e5f9f11ULL,0x9afe153ad6cb3b8eULL,0x4d1a6dd7ddf800bdULL,0xf6c13cc0caf17e19ULL,0x15f6c58e325fc3eeULL,0x71095400a31dc3b2ULL,0x168e7c07afa3d3e7ULL,0x3f8417a194c7ae2dULL,+ 0xec234772813b230dULL,0x634d0f5f17344427ULL,0x11548ab1d77fc56aULL,0x7fab1750ce06af77ULL,0xb62c10a74f7c4f83ULL,0xa7d2edc4220a67d9ULL,0x1c404170921209a0ULL,0x0b9815a0face59f0ULL,+ 0x2842589b319540c3ULL,0x18490f59a283d6f8ULL,0xa2731f84daae9fcbULL,0x3db6d960c3683ba0ULL,0xc85c63bb14611069ULL,0xb19436af0788bf05ULL,0x905459df347460d2ULL,0x73f6e094e11a7db1ULL,+ 0xdc7f938eb6357f37ULL,0xc5d00f792bd8aa62ULL,0xc878dcb92ca979fcULL,0x37e83ed9eb023a99ULL,0x6b23e2731560bf3dULL,0x1086e4591d0fae61ULL,0x782483169a9414bdULL,0x1b956bc0f0ea9ea1ULL,+ 0x7b85bb91c31b9c38ULL,0x0c5aa90b48ef57b5ULL,0xdedeb169af3bab6fULL,0xe610ad732d373685ULL,0xf13870df02ba8e15ULL,0x0337edb68ca7f771ULL,0xe4acf747b62c036cULL,0xd921d576b6b94e81ULL,+ 0xdbc864392c422f7aULL,0xfb635362ed348898ULL,0x83084668c45bfcd1ULL,0xc357c9e32b315e11ULL,0xb173b5405b2e5b8cULL,0x7e946931e102b9a4ULL,0x17c890eb7b0fb199ULL,0xec225a83d61b662bULL,+ 0xf306a3c8ee3c76cbULL,0x3cf11623d32a1f6eULL,0xe6d5ab646863e956ULL,0x3b8a4cbe5c005c26ULL,0xdcd529a59ce6bb27ULL,0xc4afaa5204d4b16fULL,0xb0624a267923798dULL,0x85e56df66b307fabULL,+ 0x0281893c2bf29698ULL,0x91fc19a4d7ce7603ULL,0x75a5dca3ad9a558fULL,0x40ceb3fa4d50bf77ULL,0x1baf6060bc9ba369ULL,0x927e1037597888c2ULL,0xd936bf1986a34c07ULL,0xd4cf10c1c34ae980ULL,+ 0x3a3e5334859dd614ULL,0x9c475b5b18d0c8eeULL,0x63080d1f07cd51d5ULL,0xc9c0d0a6b88b4326ULL,0x1ac98691c234296fULL,0x2a0a83a494887fb6ULL,0x565114270cea9cf2ULL,0x5230a6e8a24802f5ULL,+ 0xf7a2bf0f72e3d5c1ULL,0x377174464f21439eULL,0xfedcbf259ce30334ULL,0xe0030a787ce202f9ULL,0x6f2d9ebf1202e9caULL,0xe79dde6c75e6e591ULL,0xf52072aff1dac4f8ULL,0x6c8d087ebb9b404dULL,+ 0xad0fc73dbce913afULL,0x909e587b458a07cbULL,0x1300da84d4f00c8aULL,0x425cd048b54466acULL,0xb59cb9be90e9d8bfULL,0x991616db3e431b0eULL,0xd3aa117a531aecffULL,0x91af92d359f4dc3bULL,+ 0x9b1ec292e93fda29ULL,0x76bb6c17e97d91bcULL,0x7509d95faface1e6ULL,0x3653fe47be855ae3ULL,0x73180b280f680e75ULL,0x75eefd1beeb6c26cULL,0xa4cdf29fb66d4236ULL,0x2d70a9976b5821d8ULL,+ 0x7a3ee20720445c36ULL,0x71d1ac8259877174ULL,0x0fc539f7949f73e9ULL,0xd05cf3d7982e3081ULL,0x8758e20b7b1c7129ULL,0xffadcc20569e61f2ULL,0xb05d3a2f59544c2dULL,0xbe16f5c19fff5e53ULL,+ 0x73cf65b8aad58135ULL,0x622c2119037aa5beULL,0x79373b3f646fd6a0ULL,0x0e029db50d3978cfULL,0x8bdfc43794fba037ULL,0xaefbd687620797a6ULL,0x3fa5382bbd30d38eULL,0x7627cfbf585d7464ULL,+ 0xb2330fef4e4ca463ULL,0xbcef72873566cc63ULL,0xd161d2cacf780900ULL,0x135dc5395b54827dULL,0x638f052e27bf1bc6ULL,0x10a224f007dfa06cULL,0xe973586d6d3321daULL,0x8b0c573826152c8fULL,+ 0x9910ba6b23a5d896ULL,0x1fe19e357fe4364eULL,0x6e1da8c39a33c677ULL,0x15b4488b29fd9fd0ULL,0x1f4392541a1f22bfULL,0x920a8a70ab8163e8ULL,0x3fd1b24907e5658eULL,0xf2c4f79cb6ec839bULL,+ 0x8b5c619c76497ee8ULL,0x5d2b0ac6c717370eULL,0x98204cb64fcf68e1ULL,0x0bdec21162bc6792ULL,0x6973ccefa63b1011ULL,0xf9e3fa97e0de1ac5ULL,0x5efb693e3d0e0c8bULL,0x037248e9d2d4fcb4ULL,+ 0xd3694e2ab20364e4ULL,0x62699718e770b20dULL,0x6183291b6ed77d1cULL,0x69aada7f6d6180a5ULL,0x51f9054bf185509bULL,0xfd7e845678701077ULL,0xd6a2308a7fb96d8dULL,0xd53e48d228dc87eeULL,+ 0x80802dc91ec34f9eULL,0xd8772d3533810603ULL,0x3f06d66c530cb4f3ULL,0x7be5ed0dc475c129ULL,0xcb9e3c1931e82b10ULL,0xc63d2857c9ff6b4cULL,0xb92118c692a1b45eULL,0x0aec44147285bbcaULL,+ 0x37071afbe8316c45ULL,0x982be4fd46700b8bULL,0x8d5d177c64ff8578ULL,0x5ec40582c9a82fa7ULL,0x5518e37bcfa86678ULL,0x24e809f49f031284ULL,0x312f39604bbbb74cULL,0xad4b4f6fc0c14de6ULL,+ 0xa3d6f4868eb6e843ULL,0x6415834bac4ab3abULL,0x028a81514f3cf2dcULL,0xf3b4962f5f3e6c3eULL,0x9119ae90987dd2f2ULL,0x437a6d8ae10bce55ULL,0xc31cdd6b9b149ed6ULL,0x1b77791d06871332ULL,+ 0x9c34b650e16e05e9ULL,0x965a774094e74640ULL,0xa3fd22fbcea3f029ULL,0x1eb6a9688f95277cULL,0x2520a63d7bad84f6ULL,0xad917201f58f2feeULL,0xea92c1669b840d48ULL,0x12109c4aacef5cbdULL,+ 0xfc189ae71e29a3efULL,0xcbe906f04c93302eULL,0xd0107914ceaae10eULL,0xb7a23f34b68e19f8ULL,0xe9d875c2efd2119dULL,0x03198c6efcadc9c8ULL,0x65591bf64da17113ULL,0x3cf0bbf83d443038ULL,+ 0xab293027aad991c1ULL,0x598d0bf8849be4b7ULL,0x8c94a21ab972da90ULL,0xada4cfdd7ecfa840ULL,0x93d4b9c0fbcec63aULL,0x7ca617a203219a34ULL,0x900424eb6a652a55ULL,0xaf9346e9eb8562e0ULL,+ 0xc3e04d7902381461ULL,0xb1643ab5911bc478ULL,0xc92becfa390b3ef2ULL,0x54476778acd2f1b6ULL,0x8daa0c4d66bf3aafULL,0x2bc1287b2c21c65aULL,0xee182910b5a13ac3ULL,0xbb04730090b0790aULL,+ 0x83766947d17d4e0bULL,0xc5772beefdc3a47bULL,0x765a50db1a6fd0ffULL,0x17f904ba45b0995eULL,0xcee643832883487eULL,0xf56db7f3c270aaedULL,0x6738d94f46cb1fd9ULL,0xc8fa426a142fd4d5ULL,+ 0xae485bb72b724759ULL,0x945353e1b2d4c63aULL,0x82159d07de7d6f2cULL,0x389caef34ec5b109ULL,0x4a8ebb53db65ef14ULL,0x2dc2cb7edd99de43ULL,0x816fa3ed83f2405fULL,0x73429bb9c14208a3ULL,+ 0x08ed8febd56daf06ULL,0x8d98277b4a837f69ULL,0x9947c636a9b6e05aULL,0x58c8a77ac0d58abdULL,0xf45496a45f121e4fULL,0x16cd67c71076d3d3ULL,0xecbd1958e3fb0c5dULL,0xfbe185ec38e1eb47ULL,+ 0xb7ef9760ff79d2eeULL,0xdd4d06aff39e7832ULL,0xfd025001b905b499ULL,0x98fe1c61f5b61d31ULL,0xa9f83980c5f12805ULL,0x376e3b783009cd9aULL,0xa322b09f514eb16dULL,0x08e213122c3832dfULL,+ 0xaea68626dc4ad4f4ULL,0x5dc516824ddbc0b6ULL,0xa76697bd602e9065ULL,0xbeeb3ea58c37888eULL,0x1ec4a2f214569113ULL,0xe48b820ca35f4484ULL,0x9fb560949ae44df2ULL,0x6ca1346292cc09fdULL,+ 0xb618d590b01e6e27ULL,0x047e2ccde180b2dcULL,0xd1b299b504aea4a9ULL,0x412c9e1e9fa403a4ULL,0x88d28a3679407552ULL,0x49c50136f332b8e3ULL,0x3a1b6fcce668de19ULL,0x178851bc75122b97ULL,+ 0x197dd46d95a7b1a2ULL,0x9c4e7ad63c6341fbULL,0x426eca29484c2eceULL,0x9211e489de7f4f8aULL,0x14997f6ec78ef1f4ULL,0x2b2c091006574586ULL,0x17286a6e1c3eede8ULL,0x25f92e470f60e018ULL,+ 0xb4e370af3aeac968ULL,0xe4f7fee9c4b63266ULL,0xb4acd4c2e3ac5664ULL,0xf8910bd2ceb38cbfULL,0x1c3ae50cc9c0726eULL,0x15309569d97b40bfULL,0x70884b7ffd5a5a1bULL,0x3890896aef8314cdULL,+ 0x090d7d205ffe7b37ULL,0x3b7f3efb1747d2daULL,0xa2cb525fb54fc519ULL,0x6e220932f66a971eULL,0xddc160dfb486d440ULL,0x7fcfec463fe13465ULL,0x83da7e4e76e4c151ULL,0xd6fa48a1d8d302b5ULL,+ 0x5ced3c9f82e4c634ULL,0x8efb83143a4464f8ULL,0xe706381b7a1dca25ULL,0x6cd15a3c5a2a412bULL,0x9347a8fdbfcd8fb5ULL,0x31db2eef6e54cd22ULL,0xc4aeb11ef8d8932fULL,0x11e7c1ed344411afULL,+ 0xae4065ef12045cf9ULL,0x6fcb2caf9ccce8bdULL,0x1fa0ba4ef2cf6525ULL,0xf683125dcb72c312ULL,0xa01da4eae312410eULL,0x67e286776cd8e830ULL,0xabd9575298fb3f07ULL,0x05f11e11eef649a5ULL,+ 0x996884f5903fa271ULL,0xe6da0fd2b9da921eULL,0xa6f2f2695db01e54ULL,0x1ee3e9bd6876214eULL,0xa26e181ce27a9497ULL,0x36d254e48e215e04ULL,0x42f32a6c252cabcaULL,0x9948148780b57614ULL,+ 0xea961058fa28a7e0ULL,0xc726cf250bf5ec74ULL,0xe74d55c8db229666ULL,0x0bd9abbfa57f5799ULL,0x7479ef074dfc47b3ULL,0xd9c65fc30c52f91dULL,0x8e0283fe36a8bde2ULL,0xa32a8b5e7d4b7280ULL,+ 0xab41b43a43228d83ULL,0x24ae1c304ad63f99ULL,0x8e525f1a46a51229ULL,0x14af860fcd26d2b4ULL,0xd6baef613f714aa1ULL,0xf51865adeb78795eULL,0xd3e21fcee6a9d694ULL,0x82ceb1dd8a37b527ULL,+ 0x8605d27d48307682ULL,0x745aaba3e10566daULL,0xe57cae36bff2d7abULL,0x91332ba14b127823ULL,0xcb5c3638f3429f43ULL,0x43a21c4fec462929ULL,0xe9bc95352b18b7bdULL,0x8c2addf3e78cb0c6ULL,+ 0x4a665bfd2f9fd51aULL,0x7f2f1fe2481b97f7ULL,0xcad05d69ad36ce50ULL,0x314fc2a4844f4dedULL,0xd5593d8cb55fc5c6ULL,0xe3510ce8bfb1e23dULL,0xf9b7be6937453cceULL,0xd3541b7969fae631ULL,+ 0xb013cbcad7154cedULL,0x949b28573f52651aULL,0x03b41f6e9f5e642eULL,0xc3a3462986ed94a4ULL,0xf3c86cd6222b24dcULL,0x7578fe8a028c9c26ULL,0xaac7bfa12edad3b6ULL,0x4112c5d78847940aULL,+ 0x99296525eca445dfULL,0xf1af24f22cdfa4c6ULL,0xf5b4eb61eba6d3bcULL,0x4560910c98972cc7ULL,0x54751c32093eaa32ULL,0x018313497d3c67bbULL,0x3bd90ce62d871110ULL,0x75fc863a538baa7eULL,+ 0x8fe1f8b64ae3a278ULL,0x160c5306137cdf65ULL,0x22f029e733be0492ULL,0x79a680427a75cd82ULL,0x1d8c094a5b3f3adaULL,0x5d723bbe165c3250ULL,0x08b958ffa5792e22ULL,0x829fa986b11c1eaaULL,+ 0x711b8a4176a9f05dULL,0x06ca4e4b9011d488ULL,0x543bc62ba248a65eULL,0x017535ffc9290894ULL,0x840b84ce406851d7ULL,0xafa3acdf90e960b4ULL,0xac3394af7128fd34ULL,0x54eb4d5b2ac0f92cULL,+ 0x923ea73e4a14f836ULL,0xc8cc8c57f0946328ULL,0xce3f117fe917a4dfULL,0x6372f933f72ce929ULL,0x75000249c29ba567ULL,0xcbd437e68c829ccaULL,0x6c63aaabdd02ec7aULL,0xe9b2f90c7b42bd17ULL,+ 0xdb09e87355dbd4b3ULL,0x1f8799286639bbb1ULL,0xb83e47e51c651962ULL,0xd4ef0fb6c43fb574ULL,0x27d3b9d8f1bfb12aULL,0x6ab877e86e5e8b72ULL,0x8eebdc9d157b9014ULL,0x4c2110053aa5cb64ULL,+};
@@ -33,8 +33,18 @@ // See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. #include "p256/p256_gf.h"+#include "crypton_bzero.h" +#ifdef CRYPTON_S2N_BIGNUM+#include "p256/p256_s2n.h"+#include "p256/p256_verify.h"+/* the memcpy below is the two representations being the same thing */+#if P256_BITSPERDIGIT != 64 || P256_NDIGITS != 4+#error "CRYPTON_S2N_BIGNUM wants the 64-bit crypton_p256_int"+#endif+#endif + /* Field element operations: */ /* felem_inv calculates |out| = |in|^{-1}@@ -43,69 +53,95 @@ * a^p = a (mod p) * a^{p-1} = 1 (mod p) * a^{p-2} = a^{-1} (mod p)- */+ *+ * The exponent is built left to right from the shape of p - 2, which for+ * this prime is+ *+ * ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffd+ * \__32 ones__/ \_31 zeros, one 1_/ \______ 96 zeros ______/ \_94 ones, 0, 1_/+ *+ * A run of k zeros is k squarings; a run of k ones is k squarings and one+ * multiplication by a^(2^k - 1), which is why the powers below are kept. The+ * whole chain is 255 squarings, which is the least an exponent of 256 bits+ * can be done in, and 13 multiplications.+ *+ * The chain this replaces built the low 94 ones in a second accumulator and+ * multiplied the two at the end, which cost 32 squarings more than the 255. */ static void felem_inv(felem out, const felem in) {- felem ftmp, ftmp2;- /* each e_I will hold |in|^{2^I - 1} */- felem e2, e4, e8, e16, e32, e64;+ felem ftmp, x2, x4, x8, x16, x32; unsigned i; - felem_square(ftmp, in); /* 2^1 */- felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */- felem_assign(e2, ftmp);- felem_square(ftmp, ftmp); /* 2^3 - 2^1 */- felem_square(ftmp, ftmp); /* 2^4 - 2^2 */- felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */- felem_assign(e4, ftmp);- felem_square(ftmp, ftmp); /* 2^5 - 2^1 */- felem_square(ftmp, ftmp); /* 2^6 - 2^2 */- felem_square(ftmp, ftmp); /* 2^7 - 2^3 */- felem_square(ftmp, ftmp); /* 2^8 - 2^4 */- felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */- felem_assign(e8, ftmp);+ /* x{k} holds in^(2^k - 1), a run of k ones. */+ felem_square(ftmp, in);+ felem_mul(x2, ftmp, in); /* 2^2 - 1 */++ felem_square(ftmp, x2);+ felem_square(ftmp, ftmp);+ felem_mul(x4, ftmp, x2); /* 2^4 - 1 */++ felem_assign(ftmp, x4);+ for (i = 0; i < 4; i++) {+ felem_square(ftmp, ftmp);+ }+ felem_mul(x8, ftmp, x4); /* 2^8 - 1 */++ felem_assign(ftmp, x8); for (i = 0; i < 8; i++) { felem_square(ftmp, ftmp);- } /* 2^16 - 2^8 */- felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */- felem_assign(e16, ftmp);+ }+ felem_mul(x16, ftmp, x8); /* 2^16 - 1 */++ felem_assign(ftmp, x16); for (i = 0; i < 16; i++) { felem_square(ftmp, ftmp);- } /* 2^32 - 2^16 */- felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */- felem_assign(e32, ftmp);+ }+ felem_mul(x32, ftmp, x16); /* 2^32 - 1 */++ /* The top 32 ones. */+ felem_assign(ftmp, x32);++ /* 31 zeros and a one: the 00000001 word. */ for (i = 0; i < 32; i++) { felem_square(ftmp, ftmp);- } /* 2^64 - 2^32 */- felem_assign(e64, ftmp);- felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */- for (i = 0; i < 192; i++) {+ }+ felem_mul(ftmp, ftmp, in);++ /* 96 zeros. */+ for (i = 0; i < 96; i++) { felem_square(ftmp, ftmp);- } /* 2^256 - 2^224 + 2^192 */+ } - felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */+ /* 94 ones, as 32 + 32 + 16 + 8 + 4 + 2. */+ for (i = 0; i < 32; i++) {+ felem_square(ftmp, ftmp);+ }+ felem_mul(ftmp, ftmp, x32);+ for (i = 0; i < 32; i++) {+ felem_square(ftmp, ftmp);+ }+ felem_mul(ftmp, ftmp, x32); for (i = 0; i < 16; i++) {- felem_square(ftmp2, ftmp2);- } /* 2^80 - 2^16 */- felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */+ felem_square(ftmp, ftmp);+ }+ felem_mul(ftmp, ftmp, x16); for (i = 0; i < 8; i++) {- felem_square(ftmp2, ftmp2);- } /* 2^88 - 2^8 */- felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */+ felem_square(ftmp, ftmp);+ }+ felem_mul(ftmp, ftmp, x8); for (i = 0; i < 4; i++) {- felem_square(ftmp2, ftmp2);- } /* 2^92 - 2^4 */- felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */- felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */- felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */- felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */- felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */- felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */- felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */+ felem_square(ftmp, ftmp);+ }+ felem_mul(ftmp, ftmp, x4);+ felem_square(ftmp, ftmp);+ felem_square(ftmp, ftmp);+ felem_mul(ftmp, ftmp, x2); - felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */+ /* A zero and a one: the d of fffffffd. */+ felem_square(ftmp, ftmp);+ felem_square(ftmp, ftmp);+ felem_mul(out, ftmp, in); } - /* Group operations: * * Elements of the elliptic curve group are represented in Jacobian@@ -298,7 +334,8 @@ } /* select_affine_point sets {out_x,out_y} to the index'th entry of table.- * On entry: index < 16, table[0] must be zero. */+ * On entry: index < 16. Every entry is a point of its own -- the signed+ * representation has no zero digit -- so the scan starts at zero. */ static void select_affine_point(felem out_x, felem out_y, const limb* table, limb index) { limb i, j;@@ -306,7 +343,7 @@ memset(out_x, 0, sizeof(felem)); memset(out_y, 0, sizeof(felem)); - for (i = 1; i < 16; i++) {+ for (i = 0; i < 16; i++) { limb mask = i ^ index; mask |= mask >> 2; mask |= mask >> 1;@@ -321,95 +358,306 @@ } } -/* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of- * table. On entry: index < 16, table[0] must be zero. */-static void select_jacobian_point(felem out_x, felem out_y, felem out_z,- const limb* table, limb index) {- limb i, j;+/* words_are_zero returns 1 when |v| is zero and 0 otherwise, without a+ * branch. */+static u32 words_are_zero(u32 v) {+ v |= v >> 16;+ v |= v >> 8;+ v |= v >> 4;+ v |= v >> 2;+ v |= v >> 1;+ return (v & 1) ^ 1;+} - memset(out_x, 0, sizeof(felem));- memset(out_y, 0, sizeof(felem));- memset(out_z, 0, sizeof(felem));+/* The comb: five teeth to a block, the teeth of a block 52 apart and the two+ * blocks 26 from each other, so 26 steps cover all 260 bits between them.+ *+ * first block i, 52+i, 104+i, 156+i, 208+i+ * second block 26+i, 78+i, 130+i, 182+i, 234+i+ *+ * Five teeth would want a table of 32, but the signed representation makes+ * every digit +-1, so the thirty-two values come in pairs that differ by sign+ * and sixteen entries serve: kPrecomputed holds the ones whose top tooth is+ * positive and the other sign is a negated y. That is the whole of the gain+ * over the four-tooth unsigned comb this replaces, which took 32 steps for+ * the same 256 bits: 25 doublings and 52 mixed additions against 31 and 64.+ */+#define COMB_TEETH 5+#define COMB_STEPS 26+#define COMB_SPAN (2 * COMB_STEPS) /* 52, the distance between a block's teeth */+#define COMB_WORDS 9 /* 260 bits of signs, with room to add into */+#define COMB_BIT(t, q) (((t)[(q) >> 5] >> ((q) & 31)) & 1) - /* The implicit value at index 0 is all zero. We don't need to perform that- * iteration of the loop because we already set out_* to zero. */- table += 3 * NLIMBS;+/* comb_recode writes into |out| the value whose bits are the signs of the+ * scalar's all-bits-set representation: digit j is +1 where bit j of |out| is+ * set and -1 where it is not.+ *+ * For an odd k below 2^260 there is exactly one such representation, and it+ * is (k + 2^260 - 1) / 2 read as bits -- an addition and a shift, and that is+ * all the recoding is. An even scalar has the order added to make it odd,+ * which changes the scalar and not the point it selects.+ *+ * Constant time in the scalar: every branch below is on a loop counter. */+static void comb_recode(u32 out[COMB_WORDS],+ const crypton_p256_int* scalar) {+ u32 k[COMB_WORDS], ord[COMB_WORDS];+ u64 carry;+ int i; - // Hit all entries to obscure cache profiling.- for (i = 1; i < 16; i++) {- limb mask = i ^ index;- mask |= mask >> 2;- mask |= mask >> 1;- mask &= 1;- mask--;- for (j = 0; j < NLIMBS; j++, table++) {- out_x[j] |= *table & mask;- }- for (j = 0; j < NLIMBS; j++, table++) {- out_y[j] |= *table & mask;- }- for (j = 0; j < NLIMBS; j++, table++) {- out_z[j] |= *table & mask;+ for (i = 0; i < COMB_WORDS; i++) {+ k[i] = 0;+ ord[i] = 0;+ }+ for (i = 0; i < 256; i += 32) {+ k[i >> 5] = (u32)(P256_DIGIT(scalar, i / P256_BITSPERDIGIT)+ >> (i % P256_BITSPERDIGIT));+ ord[i >> 5] = (u32)(P256_DIGIT(&crypton_SECP256r1_n, i / P256_BITSPERDIGIT)+ >> (i % P256_BITSPERDIGIT));+ }++ /* an even scalar becomes odd by taking on the order */+ {+ u32 addmask = (u32)0 - (u32)((k[0] & 1) ^ 1);++ carry = 0;+ for (i = 0; i < COMB_WORDS; i++) {+ u64 v = (u64)k[i] + (u64)(ord[i] & addmask) + carry;+ k[i] = (u32)v;+ carry = v >> 32; } }++ /* out = (k + 2^260 - 1) >> 1 */+ carry = 0;+ for (i = 0; i < COMB_WORDS; i++) {+ u64 v = (u64)k[i] + (u64)(i < 8 ? 0xffffffffu : 0xfu) + carry;+ out[i] = (u32)v;+ carry = v >> 32;+ }+ for (i = 0; i < COMB_WORDS - 1; i++) {+ out[i] = (out[i] >> 1) | (out[i + 1] << 31);+ }+ out[COMB_WORDS - 1] >>= 1;+ } +/* point_add_complete_mixed sets {x3,y3,z3} = {x1,y1,z1} + {x2,y2}, where the+ * accumulator is in projective coordinates and the added point is affine.+ *+ * This is Renes-Costello-Batina algorithm 5, for a curve with a = -3. It is+ * complete: it is right when the two points are the same, when either is the+ * point at infinity, and when they are each other's negation, which is what+ * point_add_mixed cannot say. It costs 11 multiplications and two by b,+ * against point_add_mixed's 8 multiplications and 3 squarings.+ *+ * The table this comb reads is affine, and an affine point has Z = 1, so+ * Z = Z^2 = Z^3 and the same three numbers are the point in projective+ * coordinates and in Jacobian ones. That is what lets a comb built on+ * Jacobian arithmetic step into this formula for one addition and back out.+ */+static void point_add_complete_mixed(felem x3, felem y3, felem z3,+ const felem x1, const felem y1,+ const felem z1, const felem x2,+ const felem y2) {+ felem t0, t1, t2, t3, t4, xx, yy, zz;++ felem_mul(t0, x1, x2);+ felem_mul(t1, y1, y2);+ felem_sum(t3, x2, y2);+ felem_sum(t4, x1, y1);+ felem_mul(t3, t3, t4);+ felem_sum(t4, t0, t1);+ felem_diff(t3, t3, t4);+ felem_mul(t4, y2, z1);+ felem_sum(t4, t4, y1);+ felem_mul(yy, x2, z1);+ felem_sum(yy, yy, x1);+ felem_mul(zz, kB, z1);+ felem_diff(xx, yy, zz);+ felem_sum(zz, xx, xx);+ felem_sum(xx, xx, zz);+ felem_diff(zz, t1, xx);+ felem_sum(xx, t1, xx);+ felem_mul(yy, kB, yy);+ felem_sum(t1, z1, z1);+ felem_sum(t2, t1, z1);+ felem_diff(yy, yy, t2);+ felem_diff(yy, yy, t0);+ felem_sum(t1, yy, yy);+ felem_sum(yy, t1, yy);+ felem_sum(t1, t0, t0);+ felem_sum(t0, t1, t0);+ felem_diff(t0, t0, t2);+ felem_mul(t1, t4, yy);+ felem_mul(t2, t0, yy);+ felem_mul(yy, xx, zz);+ felem_sum(y3, yy, t2);+ felem_mul(xx, t3, xx);+ felem_diff(x3, xx, t1);+ felem_mul(zz, t4, zz);+ felem_mul(t1, t3, t0);+ felem_sum(z3, zz, t1);+}++/* point_add_complete sets {x3,y3,z3} = {x1,y1,z1} + {x2,y2,z2}, both in+ * projective coordinates.+ *+ * Renes-Costello-Batina algorithm 4, for a = -3, and complete for the same+ * reasons as the mixed one above. It costs 12 multiplications and two by b,+ * against point_add's 11 multiplications and 5 squarings.+ */+static void point_add_complete(felem x3, felem y3, felem z3, const felem x1,+ const felem y1, const felem z1, const felem x2,+ const felem y2, const felem z2) {+ felem t0, t1, t2, t3, t4, xx, yy, zz;++ felem_mul(t0, x1, x2);+ felem_mul(t1, y1, y2);+ felem_mul(t2, z1, z2);+ felem_sum(t3, x1, y1);+ felem_sum(t4, x2, y2);+ felem_mul(t3, t3, t4);+ felem_sum(t4, t0, t1);+ felem_diff(t3, t3, t4);+ felem_sum(t4, y1, z1);+ felem_sum(xx, y2, z2);+ felem_mul(t4, t4, xx);+ felem_sum(xx, t1, t2);+ felem_diff(t4, t4, xx);+ felem_sum(xx, x1, z1);+ felem_sum(yy, x2, z2);+ felem_mul(xx, xx, yy);+ felem_sum(yy, t0, t2);+ felem_diff(yy, xx, yy);+ felem_mul(zz, kB, t2);+ felem_diff(xx, yy, zz);+ felem_sum(zz, xx, xx);+ felem_sum(xx, xx, zz);+ felem_diff(zz, t1, xx);+ felem_sum(xx, t1, xx);+ felem_mul(yy, kB, yy);+ felem_sum(t1, t2, t2);+ felem_sum(t2, t1, t2);+ felem_diff(yy, yy, t2);+ felem_diff(yy, yy, t0);+ felem_sum(t1, yy, yy);+ felem_sum(yy, t1, yy);+ felem_sum(t1, t0, t0);+ felem_sum(t0, t1, t0);+ felem_diff(t0, t0, t2);+ felem_mul(t1, t4, yy);+ felem_mul(t2, t0, yy);+ felem_mul(yy, xx, zz);+ felem_sum(y3, yy, t2);+ felem_mul(xx, t3, xx);+ felem_diff(x3, xx, t1);+ felem_mul(zz, t4, zz);+ felem_mul(t1, t3, t0);+ felem_sum(z3, zz, t1);+}++/* jacobian_to_projective sets {x2,y2,z2} to the projective form of the+ * Jacobian point {x1,y1,z1}: (X/Z^2, Y/Z^3) is (XZ : Y : Z^3). */+static void jacobian_to_projective(felem x2, felem y2, felem z2,+ const felem x1, const felem y1,+ const felem z1) {+ felem zz, zzz;++ felem_square(zz, z1);+ felem_mul(zzz, zz, z1);+ felem_mul(x2, x1, z1);+ memcpy(y2, y1, sizeof(felem));+ memcpy(z2, zzz, sizeof(felem));+}++/* projective_to_jacobian is the other way: (X/Z) is (XZ : YZ^2 : Z). */+static void projective_to_jacobian(felem x2, felem y2, felem z2,+ const felem x1, const felem y1,+ const felem z1) {+ felem zz;++ felem_square(zz, z1);+ felem_mul(x2, x1, z1);+ felem_mul(y2, y1, zz);+ memcpy(z2, z1, sizeof(felem));+}+ /* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian * number. Note that the value of scalar must be less than the order of the * group. */ static void scalar_base_mult(felem nx, felem ny, felem nz, const crypton_p256_int* scalar) {- int i, j;- limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask;- u32 table_offset;+ u32 rec[COMB_WORDS];+ limb n_is_infinity_mask = -1, mask;+ felem px, py, negy, tx, ty, tz, jx, jy, jz, cx, cy, cz;+ int i, blk, j; - felem px, py;- felem tx, ty, tz;+ comb_recode(rec, scalar); memset(nx, 0, sizeof(felem)); memset(ny, 0, sizeof(felem)); memset(nz, 0, sizeof(felem)); - /* The loop adds bits at positions 0, 64, 128 and 192, followed by- * positions 32,96,160 and 224 and does this 32 times. */- for (i = 0; i < 32; i++) {- if (i) {+ for (i = COMB_STEPS - 1; i >= 0; i--) {+ if (i != COMB_STEPS - 1) { point_double(nx, ny, nz, nx, ny, nz); }- table_offset = 0;- for (j = 0; j <= 32; j += 32) {- char bit0 = crypton_p256_get_bit(scalar, 31 - i + j);- char bit1 = crypton_p256_get_bit(scalar, 95 - i + j);- char bit2 = crypton_p256_get_bit(scalar, 159 - i + j);- char bit3 = crypton_p256_get_bit(scalar, 223 - i + j);- limb index = bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3); - select_affine_point(px, py, kPrecomputed + table_offset, index);- table_offset += 30 * NLIMBS;+ for (blk = 0; blk < 2; blk++) {+ u32 base = (u32)(blk * COMB_STEPS + i);+ u32 top = COMB_BIT(rec, base + (COMB_TEETH - 1) * COMB_SPAN);+ limb index = 0; - /* Since scalar is less than the order of the group, we know that- * {nx,ny,nz} != {px,py,1}, unless both are zero, which we handle- * below. */- point_add_mixed(tx, ty, tz, nx, ny, nz, px, py);- /* The result of point_add_mixed is incorrect if {nx,ny,nz} is zero- * (a.k.a. the point at infinity). We handle that situation by- * copying the point from the table. */+ for (j = 0; j < COMB_TEETH - 1; j++) {+ /* a tooth agreeing with the top one is a set bit of the index */+ index |= (limb)(COMB_BIT(rec, base + (u32)j * COMB_SPAN) ^ top ^ 1)+ << j;+ }++ select_affine_point(px, py, kPrecomputed + blk * 16 * 2 * NLIMBS, index);+ felem_diff(negy, kZero, py);+ copy_conditional(py, negy, (limb)0 - (limb)(top ^ 1));++ /* The last addition is the one that can be a point added to itself:+ * entering it the accumulator is (k' - B)*G and what it adds is B*G,+ * where B is the second block's digit at step zero, so the two meet+ * when k' = 2B modulo the order. One scalar below the order does+ * that, and point_add_mixed cannot answer it.+ *+ * So that one addition goes through the complete formula instead.+ * The table is affine, so the point just selected is the same three+ * numbers read as projective coordinates as read as Jacobian ones --+ * which is what lets a comb built on Jacobian arithmetic step into+ * the formula for an addition and back out of it. The accumulator+ * is not affine and is converted.+ *+ * Measured on an M4, thread CPU time, the whole base point+ * multiplication is 17.34 us this way against 17.30 us with an extra+ * doubling and a mask, which is inside the spread of either. */+ if (i == 0 && blk == 1) {+ jacobian_to_projective(jx, jy, jz, nx, ny, nz);+ point_add_complete_mixed(cx, cy, cz, jx, jy, jz, px, py);+ projective_to_jacobian(tx, ty, tz, cx, cy, cz);+ } else {+ point_add_mixed(tx, ty, tz, nx, ny, nz, px, py);+ }++ /* The accumulator is the infinity until the first of these, and+ * point_add_mixed cannot start from it; the point itself is the sum. */ copy_conditional(nx, px, n_is_infinity_mask); copy_conditional(ny, py, n_is_infinity_mask); copy_conditional(nz, kOne, n_is_infinity_mask);-- /* Equally, the result is also wrong if the point from the table is- * zero, which happens when the index is zero. We handle that by- * only copying from {tx,ty,tz} to {nx,ny,nz} if index != 0. */- p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);- mask = p_is_noninfinite_mask & ~n_is_infinity_mask;+ mask = ~n_is_infinity_mask; copy_conditional(nx, tx, mask); copy_conditional(ny, ty, mask); copy_conditional(nz, tz, mask);- /* If p was not zero, then n is now non-zero. */- n_is_infinity_mask &= ~p_is_noninfinite_mask;+ n_is_infinity_mask = 0; } }++ /* The recoded scalar is the private key in another representation, so it+ * does not stay on the stack. */+ crypton_bzero(rec, sizeof(rec)); } /* point_to_affine converts a Jacobian point to an affine point. If the input@@ -424,67 +672,309 @@ felem_mul(y_out, ny, z_inv); } -/* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */-static void scalar_mult(felem nx, felem ny, felem nz, const felem x,- const felem y, const crypton_p256_int* scalar) {- int i;- felem px, py, pz, tx, ty, tz;- felem precomp[16][3];- limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask;+/* point_add_mixed_pm sets {xp,yp,zp} = {x1,y1,z1} + {x2,y2} and+ * {xm,ym,zm} = {x1,y1,z1} - {x2,y2}, where {x2,y2} is affine.+ *+ * Negating the second point changes the sign of s2 and so of r, and nothing+ * else: z1z1, tmp, u2, z1z1z1, h, i, j, v, the output z and the product y1*j+ * are common to the two. What the second point costs over the first is one+ * squaring (r*r) and one multiplication (by r), rather than another eleven.+ *+ * The same restrictions as point_add_mixed: this does not handle P+P,+ * infinity+P nor P+infinity. */+static void point_add_mixed_pm(felem xp, felem yp, felem zp,+ felem xm, felem ym, felem zm,+ const felem x1, const felem y1, const felem z1,+ const felem x2, const felem y2) {+ felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, y1j, tmp; - /* We precompute 0,1,2,... times {x,y}. */- memset(precomp, 0, sizeof(felem) * 3);- memcpy(&precomp[1][0], x, sizeof(felem));- memcpy(&precomp[1][1], y, sizeof(felem));- memcpy(&precomp[1][2], kOne, sizeof(felem));+ felem_square(z1z1, z1);+ felem_sum(tmp, z1, z1); - for (i = 2; i < 16; i += 2) {- point_double(precomp[i][0], precomp[i][1], precomp[i][2],- precomp[i / 2][0], precomp[i / 2][1], precomp[i / 2][2]);+ felem_mul(u2, x2, z1z1);+ felem_mul(z1z1z1, z1, z1z1);+ felem_mul(s2, y2, z1z1z1);+ felem_diff(h, u2, x1);+ felem_sum(i, h, h);+ felem_square(i, i);+ felem_mul(j, h, i);+ felem_mul(v, x1, i);+ felem_mul(y1j, y1, j); - point_add_mixed(precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2],- precomp[i][0], precomp[i][1], precomp[i][2], x, y);+ /* The two points share their z. */+ felem_mul(zp, tmp, h);+ felem_assign(zm, zp);++ /* X + P */+ felem_diff(r, s2, y1);+ felem_sum(r, r, r);+ felem_square(rr, r);+ felem_diff(xp, rr, j);+ felem_diff(xp, xp, v);+ felem_diff(xp, xp, v);+ felem_diff(tmp, v, xp);+ felem_mul(yp, tmp, r);+ felem_diff(yp, yp, y1j);+ felem_diff(yp, yp, y1j);++ /* X - P. Negating the point negates s2, so r becomes -q where+ * q = 2*(s2 + y1). The square is the same either way, and the sign is+ * carried into y by taking (xm - v) where the other took (v - xp):+ * xm = q^2 - j - 2v+ * ym = (v - xm)*(-q) - 2*y1*j = (xm - v)*q - 2*y1*j+ * so no field negation is needed. */+ felem_sum(r, s2, y1);+ felem_sum(r, r, r);+ felem_square(rr, r);+ felem_diff(xm, rr, j);+ felem_diff(xm, xm, v);+ felem_diff(xm, xm, v);+ felem_diff(tmp, xm, v);+ felem_mul(ym, tmp, r);+ felem_diff(ym, ym, y1j);+ felem_diff(ym, ym, y1j);+}++/* select_jacobian_odd sets {out_x,out_y,out_z} to the index'th of the 16+ * entries of table, for index < 16. There is no implicit infinity at index+ * zero, as the unsigned window this replaces had: every entry is a real+ * point, which is what lets the signed representation below do without the+ * infinity masks. */+static void select_jacobian_odd(felem out_x, felem out_y, felem out_z,+ const limb* table, limb index) {+ limb i, j;++ memset(out_x, 0, sizeof(felem));+ memset(out_y, 0, sizeof(felem));+ memset(out_z, 0, sizeof(felem));++ for (i = 0; i < 16; i++) {+ limb mask = i ^ index;+ mask |= mask >> 2;+ mask |= mask >> 1;+ mask &= 1;+ mask--;+ for (j = 0; j < NLIMBS; j++, table++) {+ out_x[j] |= *table & mask;+ }+ for (j = 0; j < NLIMBS; j++, table++) {+ out_y[j] |= *table & mask;+ }+ for (j = 0; j < NLIMBS; j++, table++) {+ out_z[j] |= *table & mask;+ } }+} - memset(nx, 0, sizeof(felem));- memset(ny, 0, sizeof(felem));- memset(nz, 0, sizeof(felem));- n_is_infinity_mask = -1;+/* The scalar, recoded: 52 signed odd digits, each in {+-1,+-3,...,+-31}, so+ * that scalar = sum d_i * 32^i. A digit is one byte: the low four bits are+ * the table index (|d|-1)/2, and bit four is set when d is negative. One+ * byte rather than a byte and a word because this is the private key in+ * another form and has to be wiped afterwards. */+#define SABS_DIGITS 52+#define SABS_INDEX(b) ((limb)((b) & 15))+#define SABS_NEGMASK(b) ((limb)0 - (limb)((b) >> 4))+typedef struct {+ u8 digit[SABS_DIGITS];+} sabs_scalar; - /* We add in a window of four bits each iteration and do this 64 times. */- for (i = 0; i < 256; i += 4) {- if (i) {- point_double(nx, ny, nz, nx, ny, nz);- point_double(nx, ny, nz, nx, ny, nz);- point_double(nx, ny, nz, nx, ny, nz);- point_double(nx, ny, nz, nx, ny, nz);++/* sabs_recode writes the signed representation of |scalar| into |out|.+ *+ * The recoding is the regular one of Joye and Tunstall: take the low six bits,+ * subtract 32, and carry the difference upwards. It needs an odd input, which+ * is arranged by adding the group order to an even scalar -- that changes the+ * scalar but not the point it selects, the order being the order. A zero+ * scalar is replaced by one and the caller is told, since zero times a point+ * is the infinity this code deliberately cannot represent.+ *+ * Constant time in the scalar: every branch below is on a loop counter. */+static limb sabs_recode(sabs_scalar* out,+ const crypton_p256_int* scalar) {+ u32 k[9], n[9];+ u32 nonzero;+ limb is_zero_mask;+ int i, b;++ for (i = 0; i < 9; i++) {+ k[i] = 0;+ n[i] = 0;+ }+ /* A word at a time. Bit at a time would be 512 calls into another+ * translation unit, which the compiler cannot inline away. */+ for (b = 0; b < 256; b += 32) {+ k[b >> 5] = (u32)(P256_DIGIT(scalar, b / P256_BITSPERDIGIT)+ >> (b % P256_BITSPERDIGIT));+ n[b >> 5] = (u32)(P256_DIGIT(&crypton_SECP256r1_n, b / P256_BITSPERDIGIT)+ >> (b % P256_BITSPERDIGIT));+ }++ /* Replace a zero scalar by one, and report it. */+ nonzero = 0;+ for (i = 0; i < 9; i++) {+ nonzero |= k[i];+ }+ {+ u32 z = words_are_zero(nonzero);+ k[0] |= z;+ is_zero_mask = (limb)0 - (limb)z;+ }++ /* An even scalar becomes odd by adding the order. The sum is below 2^257,+ * which is why nine words and fifty-two digits are enough. */+ {+ u32 addmask = (u32)0 - (u32)((k[0] & 1) ^ 1);+ u64 carry = 0;+ for (i = 0; i < 9; i++) {+ u64 t = (u64)k[i] + (u64)(n[i] & addmask) + carry;+ k[i] = (u32)t;+ carry = t >> 32; }+ } - index = (crypton_p256_get_bit(scalar, 255 - i - 0) << 3) |- (crypton_p256_get_bit(scalar, 255 - i - 1) << 2) |- (crypton_p256_get_bit(scalar, 255 - i - 2) << 1) |- crypton_p256_get_bit(scalar, 255 - i - 3);+ for (i = 0; i < SABS_DIGITS - 1; i++) {+ u32 r6 = k[0] & 63; /* odd, so never 32 */+ u32 hi = (r6 >> 5) & 1; /* 1 when the digit is positive */+ u32 wabs = ((r6 - 32) & (0u - hi)) | ((32 - r6) & (hi - 1));+ u32 mlo = 32u - r6; /* two's complement of the digit's negation */+ u32 ext = 0u - hi; /* its sign extension */+ u64 carry = 0;+ int w; - /* See the comments in scalar_base_mult about handling infinities. */- select_jacobian_point(px, py, pz, precomp[0][0], index);- point_add(tx, ty, tz, nx, ny, nz, px, py, pz);- copy_conditional(nx, px, n_is_infinity_mask);- copy_conditional(ny, py, n_is_infinity_mask);- copy_conditional(nz, pz, n_is_infinity_mask);+ out->digit[i] = (u8)(((wabs - 1) >> 1) | ((hi ^ 1) << 4)); - p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);- mask = p_is_noninfinite_mask & ~n_is_infinity_mask;+ /* k -= digit, i.e. k += -digit, sign extended over the nine words. */+ for (w = 0; w < 9; w++) {+ u64 t = (u64)k[w] + (u64)(w == 0 ? mlo : ext) + carry;+ k[w] = (u32)t;+ carry = t >> 32;+ }+ /* k >>= 5 */+ for (w = 0; w < 8; w++) {+ k[w] = (k[w] >> 5) | (k[w + 1] << 27);+ }+ k[8] >>= 5;+ } - copy_conditional(nx, tx, mask);- copy_conditional(ny, ty, mask);- copy_conditional(nz, tz, mask);- n_is_infinity_mask &= ~p_is_noninfinite_mask;+ /* What is left is odd, positive and at most five: the scalar is below+ * 2^257 and fifty-one digits have taken 255 bits off it, each leaving a+ * remainder below one. */+ out->digit[SABS_DIGITS - 1] = (u8)((k[0] - 1) >> 1);++ return is_zero_mask;+}++/* scalar_mult sets {nx,ny,nz} = scalar*{x,y}.+ *+ * A five-bit signed window. The scalar is recoded into 52 digits, every one+ * of them odd and none of them zero, so the table holds only the odd+ * multiples P, 3P, ..., 31P and a negative digit is served by negating y,+ * which is free. Against the four-bit unsigned window this replaces, the+ * main loop trades 252 doublings and 64 additions for 255 and 51, and --+ * because no digit is zero and no partial sum is the infinity -- it drops the+ * masks that stood in for infinity on every iteration.+ *+ * The table is built so that each pair of neighbouring odd multiples comes+ * out of one doubling and one shared addition:+ *+ * 2P = 2*P 3P = 2P + P+ * 6P = 2*(3P) 5P = 6P - P, 7P = 6P + P+ * 10P = 2*(5P) 9P = 10P - P, 11P = 10P + P+ * ...+ * 30P = 2*(15P) 29P = 30P - P, 31P = 30P + P+ *+ * which is eight doublings, one mixed addition and seven shared pairs. */+static void scalar_mult(felem nx, felem ny, felem nz, const felem x,+ const felem y, const crypton_p256_int* scalar) {+ /* odd[k] is (2k+1)*P, for k in 0..15. */+ felem odd[16][3];+ felem dx, dy, dz, px, py, pz, negy, ddx, ddy, ddz, qx, qy, qz, cx, cy, cz;+ sabs_scalar rec;+ limb is_zero_mask;+ int i, k;++ is_zero_mask = sabs_recode(&rec, scalar);++ felem_assign(odd[0][0], x);+ felem_assign(odd[0][1], y);+ memcpy(odd[0][2], kOne, sizeof(felem));++ /* 3P = 2P + P */+ point_double(dx, dy, dz, x, y, kOne);+ point_add_mixed(odd[1][0], odd[1][1], odd[1][2], dx, dy, dz, x, y);++ /* (4k+2)P from (2k+1)P, then (4k+1)P and (4k+3)P from it. */+ for (k = 1; k < 8; k++) {+ point_double(dx, dy, dz, odd[k][0], odd[k][1], odd[k][2]);+ point_add_mixed_pm(odd[2 * k + 1][0], odd[2 * k + 1][1], odd[2 * k + 1][2],+ odd[2 * k][0], odd[2 * k][1], odd[2 * k][2],+ dx, dy, dz, x, y); }++ /* The top digit initialises the accumulator; it is always positive. */+ select_jacobian_odd(nx, ny, nz, odd[0][0],+ SABS_INDEX(rec.digit[SABS_DIGITS - 1]));++ for (i = SABS_DIGITS - 2; i >= 0; i--) {+ point_double(nx, ny, nz, nx, ny, nz);+ point_double(nx, ny, nz, nx, ny, nz);+ point_double(nx, ny, nz, nx, ny, nz);+ point_double(nx, ny, nz, nx, ny, nz);+ point_double(nx, ny, nz, nx, ny, nz);++ select_jacobian_odd(px, py, pz, odd[0][0], SABS_INDEX(rec.digit[i]));+ felem_diff(negy, kZero, py);+ copy_conditional(py, negy, SABS_NEGMASK(rec.digit[i]));++ /* On the last step alone the accumulator can be the very point being+ * added -- the accumulator is (k' - d0)*P and it adds d0*P, so the two+ * meet when k' = 2*d0 modulo the order, which the scalar 30 does with a+ * digit of 15 -- and point_add answers the infinity where the truth is+ * twice that point. That one addition goes through the complete formula+ * instead, with both points converted to projective coordinates and the+ * answer converted back. One of fifty-one iterations pays for it, and+ * it comes to a field multiplication less than the doubling and the mask+ * it replaces.+ *+ * point_add finishes with z before it touches x, and with each of x and+ * y before the next, so on every other step the accumulator can be its+ * own output. */+ if (i == 0) {+ jacobian_to_projective(ddx, ddy, ddz, nx, ny, nz);+ jacobian_to_projective(qx, qy, qz, px, py, pz);+ point_add_complete(cx, cy, cz, ddx, ddy, ddz, qx, qy, qz);+ projective_to_jacobian(nx, ny, nz, cx, cy, cz);+ } else {+ point_add(nx, ny, nz, nx, ny, nz, px, py, pz);+ }+ }++ /* Zero was replaced by one on the way in; put the infinity back. All+ * three coordinates, not just z: crypton_p256_points_mul_vartime reads the+ * comment above it as saying the whole point is zero. */+ for (i = 0; i < NLIMBS; i++) {+ nx[i] &= ~is_zero_mask;+ ny[i] &= ~is_zero_mask;+ nz[i] &= ~is_zero_mask;+ }++ /* The recoded scalar is the private key in another representation, so it+ * does not stay on the stack. */+ crypton_bzero(&rec, sizeof(rec)); } /* crypton_p256_base_point_mul sets {out_x,out_y} = nG, where n is < the * order of the group. */ void crypton_p256_base_point_mul(const crypton_p256_int* n, crypton_p256_int* out_x, crypton_p256_int* out_y) {+#ifdef CRYPTON_S2N_BIGNUM+ /* The assembly, four times faster, and constant time as this has to be:+ * it is how a public key is derived from a private one. */+ uint64_t res[8];++ crypton_s2n_p256_scalarmulbase(res, P256_DIGITS(n));+ memcpy(P256_DIGITS(out_x), res, P256_NBYTES);+ memcpy(P256_DIGITS(out_y), res + P256_NDIGITS, P256_NBYTES);+#else felem x, y, z; scalar_base_mult(x, y, z, n);@@ -496,8 +986,29 @@ from_montgomery(out_x, x_affine); from_montgomery(out_y, y_affine); }+#endif } +#ifdef CRYPTON_S2N_BIGNUM+/* An affine point from the assembly as the Jacobian triple the addition+ * below wants, keeping this file's convention that the point at infinity is+ * all three coordinates zero -- the assembly says it with (0, 0). */+static void s2n_lift(felem x, felem y, felem z, const uint64_t res[8]) {+ crypton_p256_int t;+ uint64_t any = 0;+ int i;++ for (i = 0; i < 2 * P256_NDIGITS; i++)+ any |= res[i];++ memcpy(P256_DIGITS(&t), res, P256_NBYTES);+ to_montgomery(x, &t);+ memcpy(P256_DIGITS(&t), res + P256_NDIGITS, P256_NBYTES);+ to_montgomery(y, &t);+ memcpy(z, any != 0 ? kOne : kZero, sizeof(felem));+}+#endif+ /* crypton_p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where * n1 and n2 are < the order of the group. *@@ -516,10 +1027,48 @@ return; } +#ifdef CRYPTON_S2N_BIGNUM+ {+ /* Both scalars at once, in variable time, which is what the two+ * multiplications below are not: they are constant time, and pay for it,+ * over values that are all public here. It gives up on the one case the+ * assembly's addition does not cover -- adding a point to itself -- and+ * then the constant-time pair answers instead. */+ uint64_t jr[3 * P256_NDIGITS];++ if (crypton_p256_verify_mul(jr, P256_DIGITS(n1), P256_DIGITS(n2),+ P256_DIGITS(in_x), P256_DIGITS(in_y))) {+ crypton_p256_int t;++ memcpy(P256_DIGITS(&t), jr, P256_NBYTES);+ to_montgomery(x1, &t);+ memcpy(P256_DIGITS(&t), jr + P256_NDIGITS, P256_NBYTES);+ to_montgomery(y1, &t);+ memcpy(P256_DIGITS(&t), jr + 2 * P256_NDIGITS, P256_NBYTES);+ to_montgomery(z1, &t);++ point_to_affine(px, py, x1, y1, z1);+ from_montgomery(out_x, px);+ from_montgomery(out_y, py);+ return;+ }+ }+ {+ uint64_t r1[8], r2[8], pt[2 * P256_NDIGITS];++ memcpy(pt, P256_DIGITS(in_x), P256_NBYTES);+ memcpy(pt + P256_NDIGITS, P256_DIGITS(in_y), P256_NBYTES);+ crypton_s2n_p256_scalarmulbase(r1, P256_DIGITS(n1));+ crypton_s2n_p256_scalarmul(r2, P256_DIGITS(n2), pt);+ s2n_lift(x1, y1, z1, r1);+ s2n_lift(x2, y2, z2, r2);+ }+#else to_montgomery(px, in_x); to_montgomery(py, in_y); scalar_base_mult(x1, y1, z1, n1); scalar_mult(x2, y2, z2, px, py, n2);+#endif if (crypton_p256_is_zero(n2) != 0) { /* If n2 == 0, then {x2,y2,z2} is zero and the result is just@@ -581,6 +1130,19 @@ void crypton_p256e_point_mul(const crypton_p256_int* n, const crypton_p256_int* in_x, const crypton_p256_int* in_y, crypton_p256_int* out_x, crypton_p256_int* out_y) {+#ifdef CRYPTON_S2N_BIGNUM+ /* The vendored assembly, which answers the same thing two and a half to+ * three times faster. Both sides are four little-endian 64-bit words of+ * an ordinary affine coordinate, so the points cross as they are, and+ * both give (0, 0) for the point at infinity. See cbits/s2n/README.md. */+ uint64_t point[8], res[8];++ memcpy(point, P256_DIGITS(in_x), P256_NBYTES);+ memcpy(point + P256_NDIGITS, P256_DIGITS(in_y), P256_NBYTES);+ crypton_s2n_p256_scalarmul(res, P256_DIGITS(n), point);+ memcpy(P256_DIGITS(out_x), res, P256_NBYTES);+ memcpy(P256_DIGITS(out_y), res + P256_NDIGITS, P256_NBYTES);+#else felem x, y, z, px, py; to_montgomery(px, in_x);@@ -589,4 +1151,5 @@ point_to_affine(px, py, x, y, z); from_montgomery(out_x, px); from_montgomery(out_y, py);+#endif }
@@ -0,0 +1,61 @@+/*+ * Choosing between s2n-bignum's two forms of each routine. The reasoning+ * is in cbits/s2n/README.md; in short, on ARM the choice is a+ * microarchitecture one that no feature bit answers, and on x86-64 it is+ * exactly a feature bit.+ */+#include "p256/p256_s2n.h"+#include "crypton_cpu.h"++extern void p256_scalarmul(uint64_t res[8], const uint64_t scalar[4],+ const uint64_t point[8]);+extern void p256_scalarmul_alt(uint64_t res[8], const uint64_t scalar[4],+ const uint64_t point[8]);+extern void p256_scalarmulbase(uint64_t res[8], const uint64_t scalar[4],+ uint64_t blocksize, const uint64_t *table);+extern void p256_scalarmulbase_alt(uint64_t res[8], const uint64_t scalar[4],+ uint64_t blocksize, const uint64_t *table);++extern const uint64_t crypton_p256_s2n_base_blocksize;+extern const uint64_t crypton_p256_s2n_base_table[];++void crypton_s2n_p256_scalarmul(uint64_t res[8], const uint64_t scalar[4],+ const uint64_t point[8])+{+#if defined(__aarch64__) || defined(__arm64__)+#ifdef __APPLE__+ /* the _alt form is the one written for high multiplier throughput,+ * and it is 30-40% faster on Apple silicon */+ p256_scalarmul_alt(res, scalar, point);+#else+ p256_scalarmul(res, scalar, point);+#endif+#else+ if (crypton_x86_simd_features() & CRYPTON_X86_ADX)+ p256_scalarmul(res, scalar, point);+ else+ p256_scalarmul_alt(res, scalar, point);+#endif+}++void crypton_s2n_p256_scalarmulbase(uint64_t res[8], const uint64_t scalar[4])+{+#if defined(__aarch64__) || defined(__arm64__)+#ifdef __APPLE__+ p256_scalarmulbase_alt(res, scalar, crypton_p256_s2n_base_blocksize,+ crypton_p256_s2n_base_table);+#else+ p256_scalarmulbase(res, scalar, crypton_p256_s2n_base_blocksize,+ crypton_p256_s2n_base_table);+#endif+#else+ if (crypton_x86_simd_features() & CRYPTON_X86_ADX)+ p256_scalarmulbase(res, scalar,+ crypton_p256_s2n_base_blocksize,+ crypton_p256_s2n_base_table);+ else+ p256_scalarmulbase_alt(res, scalar,+ crypton_p256_s2n_base_blocksize,+ crypton_p256_s2n_base_table);+#endif+}
@@ -0,0 +1,300 @@+/*+ * The double scalar multiplication ECDSA verification does, in variable+ * time.+ *+ * Verification asks for u1*G + u2*Q, and crypton used to work that out as+ * two separate constant-time multiplications and an addition. Nothing here+ * is secret -- the message, the signature and the public key are all sent in+ * the clear -- so the constant-time work is paid for nothing, and the two+ * multiplications can share their doublings besides. Measured, those two+ * were 84% of a verification.+ *+ * So this is the usual interleaved windowed form: both scalars in+ * width-5 non-adjacent form, a table of odd multiples of each point, and one+ * pass down the digits with a doubling at every step and an addition where a+ * digit is not zero. It is s2n-bignum's Jacobian point arithmetic+ * underneath, the same assembly the constant-time paths use.+ *+ * s2n-bignum's p256_montjadd is correct except when its two arguments are+ * the same point -- that is the side condition its proof carries -- so every+ * sum is checked for the sign of that, which is a zero z where neither+ * argument had one. There the answer is given up on and the caller falls+ * back to the constant-time pair, which has no such condition. With random+ * inputs it does not happen; it is here because an attacker chooses the+ * public key and the signature.+ */+#include <string.h>++#include "p256/p256.h"++#ifdef CRYPTON_S2N_BIGNUM++#include "crypton_cpu.h"+#include "p256/p256_verify.h"++/* a Jacobian triple in the Montgomery domain, as the assembly keeps them */+#define JAC 12+#define AFF 8++extern void p256_montjadd(uint64_t p3[JAC], const uint64_t p1[JAC],+ const uint64_t p2[JAC]);+extern void p256_montjadd_alt(uint64_t p3[JAC], const uint64_t p1[JAC],+ const uint64_t p2[JAC]);+extern void p256_montjdouble(uint64_t p3[JAC], const uint64_t p1[JAC]);+extern void p256_montjdouble_alt(uint64_t p3[JAC], const uint64_t p1[JAC]);+extern void p256_montjmixadd(uint64_t p3[JAC], const uint64_t p1[JAC],+ const uint64_t p2[AFF]);+extern void p256_montjmixadd_alt(uint64_t p3[JAC], const uint64_t p1[JAC],+ const uint64_t p2[AFF]);++/* the odd multiples of the base point, from cbits/p256/gen_base_table.py */+extern const uint64_t crypton_p256_wnaf_width;+extern const uint64_t crypton_p256_wnaf_table[];+extern void bignum_tomont_p256(uint64_t z[4], const uint64_t x[4]);+extern void bignum_demont_p256(uint64_t z[4], const uint64_t x[4]);+extern void bignum_neg_p256(uint64_t z[4], const uint64_t x[4]);+#if !defined(__aarch64__) && !defined(__arm64__)+extern void bignum_tomont_p256_alt(uint64_t z[4], const uint64_t x[4]);+extern void bignum_demont_p256_alt(uint64_t z[4], const uint64_t x[4]);+#endif++/* The same question as everywhere else in cbits/s2n: a microarchitecture one+ * on ARM that no feature bit answers, and exactly a feature bit on x86-64. */+static int use_alt(void)+{+#if defined(__aarch64__) || defined(__arm64__)+#ifdef __APPLE__+ return 1;+#else+ return 0;+#endif+#else+ return (crypton_x86_simd_features() & CRYPTON_X86_ADX) == 0;+#endif+}++static void padd(uint64_t r[JAC], const uint64_t a[JAC], const uint64_t b[JAC],+ int alt)+{+ if (alt)+ p256_montjadd_alt(r, a, b);+ else+ p256_montjadd(r, a, b);+}++static void pmixadd(uint64_t r[JAC], const uint64_t a[JAC],+ const uint64_t b[AFF], int alt)+{+ if (alt)+ p256_montjmixadd_alt(r, a, b);+ else+ p256_montjmixadd(r, a, b);+}++static void pdouble(uint64_t r[JAC], const uint64_t a[JAC], int alt)+{+ if (alt)+ p256_montjdouble_alt(r, a);+ else+ p256_montjdouble(r, a);+}++static void tomont(uint64_t z[4], const uint64_t x[4])+{+#if defined(__aarch64__) || defined(__arm64__)+ bignum_tomont_p256(z, x);+#else+ if (use_alt())+ bignum_tomont_p256_alt(z, x);+ else+ bignum_tomont_p256(z, x);+#endif+}++static void demont(uint64_t z[4], const uint64_t x[4])+{+#if defined(__aarch64__) || defined(__arm64__)+ bignum_demont_p256(z, x);+#else+ if (use_alt())+ bignum_demont_p256_alt(z, x);+ else+ bignum_demont_p256(z, x);+#endif+}++static int is_infinity(const uint64_t p[JAC])+{+ return (p[8] | p[9] | p[10] | p[11]) == 0;+}++/*+ * The base point's table is a constant, so its window is as wide as the+ * table is worth carrying: seven bits, thirty-two odd multiples, two+ * kilobytes, and one addition every eight digits. The public key's table+ * has to be built for each verification, so five bits is the trade there --+ * eight entries, seven point operations to build, and one addition every+ * six digits.+ */+#define WG 7+#define TG (1 << (WG - 2))+#define WQ 5+#define TQ (1 << (WQ - 2))+#define NAF_MAX 258++/*+ * The width-W non-adjacent form of a scalar, one signed digit per bit+ * position: odd or zero, and never two non-zero digits within W of each+ * other. Returns how many digits were written.+ *+ * The scalar is public, so the loop may look at it.+ */+static int wnaf(int8_t out[NAF_MAX], const uint64_t in[4], int w)+{+ uint64_t k[5];+ int len = 0;++ memcpy(k, in, 32);+ k[4] = 0;++ while (k[0] | k[1] | k[2] | k[3] | k[4]) {+ int d = 0;++ if (k[0] & 1) {+ d = (int) (k[0] & ((1u << w) - 1));+ if (d >= (1 << (w - 1)))+ d -= 1 << w;+ if (d > 0) {+ uint64_t borrow = (uint64_t) d;+ int i;++ for (i = 0; i < 5 && borrow; i++) {+ uint64_t t = k[i];++ k[i] = t - borrow;+ borrow = (k[i] > t);+ }+ } else {+ uint64_t carry = (uint64_t) (-d);+ int i;++ for (i = 0; i < 5 && carry; i++) {+ k[i] += carry;+ carry = (k[i] < carry);+ }+ }+ }+ out[len++] = (int8_t) d;++ { /* k >>= 1 */+ int i;++ for (i = 0; i < 4; i++)+ k[i] = (k[i] >> 1) | (k[i + 1] << 63);+ k[4] >>= 1;+ }+ }+ return len;+}++/* P, 3P, 5P, ..., (2*TQ-1)P from a Jacobian P */+static int build_table(uint64_t t[TQ][JAC], const uint64_t p[JAC], int alt)+{+ uint64_t twice[JAC];+ int i;++ memcpy(t[0], p, sizeof(uint64_t) * JAC);+ pdouble(twice, p, alt);+ for (i = 1; i < TQ; i++) {+ padd(t[i], t[i - 1], twice, alt);+ /* the table is built from a point and its double, which are+ * never the same point unless the point has order two, and+ * P-256 has none */+ if (is_infinity(t[i]) && !is_infinity(t[i - 1])+ && !is_infinity(twice))+ return 0;+ }+ return 1;+}++/* the table entry for a digit, negated when the digit is */+static void pick(uint64_t out[JAC], const uint64_t t[TQ][JAC], int digit)+{+ int idx = (digit > 0 ? digit : -digit) / 2;++ memcpy(out, t[idx], sizeof(uint64_t) * JAC);+ if (digit < 0)+ bignum_neg_p256(out + 4, out + 4);+}++/* the same from the base point's affine table */+static void pick_affine(uint64_t out[AFF], int digit)+{+ int idx = (digit > 0 ? digit : -digit) / 2;++ memcpy(out, crypton_p256_wnaf_table + (size_t) idx * AFF,+ sizeof(uint64_t) * AFF);+ if (digit < 0)+ bignum_neg_p256(out + 4, out + 4);+}++int crypton_p256_verify_mul(uint64_t out[JAC], const uint64_t n1[4],+ const uint64_t n2[4], const uint64_t qx[4],+ const uint64_t qy[4])+{+ /* the Montgomery form of one, which is the z of an affine point */+ static const uint64_t mont_one[4] = {+ 0x0000000000000001ULL, 0xffffffff00000000ULL,+ 0xffffffffffffffffULL, 0x00000000fffffffeULL+ };+ uint64_t tq[TQ][JAC];+ uint64_t q[JAC], acc[JAC], addend[JAC], aff[AFF], sum[JAC];+ int8_t naf1[NAF_MAX], naf2[NAF_MAX];+ int len1, len2, len, i;+ /* asked once rather than at every point operation */+ const int alt = use_alt();++ /* the generated table has to be the width this file walks it at */+ if (crypton_p256_wnaf_width != WG)+ return 0;++ tomont(q, qx);+ tomont(q + 4, qy);+ memcpy(q + 8, mont_one, sizeof mont_one);++ if (!build_table(tq, q, alt))+ return 0;++ len1 = wnaf(naf1, n1, WG);+ len2 = wnaf(naf2, n2, WQ);+ len = len1 > len2 ? len1 : len2;++ memset(acc, 0, sizeof acc);+ for (i = len - 1; i >= 0; i--) {+ pdouble(acc, acc, alt);++ if (i < len1 && naf1[i] != 0) {+ /* the base point's entries are affine, which is a+ * cheaper addition and no table to build */+ pick_affine(aff, naf1[i]);+ pmixadd(sum, acc, aff, alt);+ if (is_infinity(sum) && !is_infinity(acc))+ return 0;+ memcpy(acc, sum, sizeof acc);+ }+ if (i < len2 && naf2[i] != 0) {+ pick(addend, tq, naf2[i]);+ padd(sum, acc, addend, alt);+ if (is_infinity(sum) && !is_infinity(acc))+ return 0;+ memcpy(acc, sum, sizeof acc);+ }+ }++ demont(out, acc);+ demont(out + 4, acc + 4);+ demont(out + 8, acc + 8);+ return 1;+}++#endif
@@ -0,0 +1,19 @@+#ifndef CRYPTON_P256_VERIFY_H+#define CRYPTON_P256_VERIFY_H++#include <stdint.h>++/*+ * n1*G + n2*Q, in variable time, as a Jacobian triple in the plain domain.+ *+ * Returns 1 when the answer is in `out`, and 0 when the walk met the one+ * case s2n-bignum's point addition does not cover -- adding a point to+ * itself -- in which case the caller works the answer out the constant-time+ * way instead. Nothing here is secret: it is all in the signature and the+ * public key.+ */+int crypton_p256_verify_mul(uint64_t out[12], const uint64_t n1[4],+ const uint64_t n2[4], const uint64_t qx[4],+ const uint64_t qy[4]);++#endif
@@ -0,0 +1,42 @@+/* Generated by cbits/p256/gen_base_table.py; do not hand-edit.+ * The odd multiples of the base point, in Montgomery-affine+ * form, which cbits/p256/p256_verify.c reads. A verification+ * is public, so this table is walked in variable time. */+#include <stdint.h>++const uint64_t crypton_p256_wnaf_width = 7;++const uint64_t crypton_p256_wnaf_table[256] = {+ 0x79e730d418a9143cULL,0x75ba95fc5fedb601ULL,0x79fb732b77622510ULL,0x18905f76a53755c6ULL,0xddf25357ce95560aULL,0x8b4ab8e4ba19e45cULL,0xd2e88688dd21f325ULL,0x8571ff1825885d85ULL,+ 0xffac3f904eebc127ULL,0xb027f84a087d81fbULL,0x66ad77dd87cbbc98ULL,0x26936a3fb6ff747eULL,0xb04c5c1fc983a7ebULL,0x583e47ad0861fe1aULL,0x788208311a2ee98eULL,0xd5f06a29e587cc07ULL,+ 0xbe1b8aaec45c61f5ULL,0x90ec649a94b9537dULL,0x941cb5aad076c20cULL,0xc9079605890523c8ULL,0xeb309b4ae7ba4f10ULL,0x73c568efe5eb882bULL,0x3540a9877e7a1f68ULL,0x73a076bb2dd1e916ULL,+ 0x0746354ea0173b4fULL,0x2bd20213d23c00f7ULL,0xf43eaab50c23bb08ULL,0x13ba5119c3123e03ULL,0x2847d0303f5b9d4dULL,0x6742f2f25da67bddULL,0xef933bdc77c94195ULL,0xeaedd9156e240867ULL,+ 0x75c96e8f264e20e8ULL,0xabe6bfed59a7a841ULL,0x2cc09c0444c8eb00ULL,0xe05b3080f0c4e16bULL,0x1eb7777aa45f3314ULL,0x56af7bedce5d45e3ULL,0x2b6e019a88b12f1aULL,0x086659cdfd835f9bULL,+ 0xea7d260a6245e404ULL,0x9de407956e7fdfe0ULL,0x1ff3a4158dac1ab5ULL,0x3e7090f1649c9073ULL,0x1a7685612b944e88ULL,0x250f939ee57f61c8ULL,0x0c0daa891ead643dULL,0x68930023e125b88eULL,+ 0xccc425634b2ed709ULL,0x0e356769856fd30dULL,0xbcbcd43f559e9811ULL,0x738477ac5395b759ULL,0x35752b90c00ee17fULL,0x68748390742ed2e3ULL,0x7cd06422bd1f5bc1ULL,0xfbc08769c9e7b797ULL,+ 0x72bcd8b7bc60055bULL,0x03cc23ee56e27e4bULL,0xee337424e4819370ULL,0xe2aa0e430ad3da09ULL,0x40b8524f6383c45dULL,0xd766355442a41b25ULL,0x64efa6de778a4797ULL,0x2042170a7079adf4ULL,+ 0x97091dcbd53c5c9dULL,0xf17624b6ac0a177bULL,0xb0f139752cfe2dffULL,0xc1a35c0a6c7a574eULL,0x227d314693e79987ULL,0x0575bf30e89cb80eULL,0x2f4e247f0d1883bbULL,0xebd512263274c3d0ULL,+ 0xfea912baa5659ae8ULL,0x68363aba25e1a16eULL,0xb8842277752c41acULL,0xfe545c282897c3fcULL,0x2d36e9e7dc4c696bULL,0x5806244afba977c5ULL,0x85665e9be39508c1ULL,0xf720ee256d12597bULL,+ 0x562e4cecc135b208ULL,0x74e1b2654783f47dULL,0x6d2a506c5a3f3b30ULL,0xecead9f4c16762fcULL,0xf29dd4b2e286e5b9ULL,0x1b0fadc083bb3c61ULL,0x7a75023e7fac29a4ULL,0xc086d5f1c9477fa3ULL,+ 0xf4f876532de45068ULL,0x37c7a7e89e2e1f6eULL,0xd0825fa2a3584069ULL,0xaf2cea7c1727bf42ULL,0x0360a4fb9e4785a9ULL,0xe5fda49c27299f4aULL,0x48068e1371ac2f71ULL,0x83d0687b9077666fULL,+ 0xa4a319acd837879fULL,0x6fc1b49eed6b67b0ULL,0xe395993332f1f3afULL,0x966742eb65432a2eULL,0x4b8dc9feb4966228ULL,0x96cc631243f43950ULL,0x12068859c9b731eeULL,0x7b948dc356f79968ULL,+ 0x042c2af497e2feb4ULL,0xd36a42d7aebf7313ULL,0x49d2c9eb084ffdd7ULL,0x9f8aa54b2ef7c76aULL,0x9200b7ba09895e70ULL,0x3bd0c66fddb7fb58ULL,0x2d97d10878eb4cbbULL,0x2d431068d84bde31ULL,+ 0x5e5db46acb66e132ULL,0xf1be963a0d925880ULL,0x944a70270317b9e2ULL,0xe266f95948603d48ULL,0x98db66735c208899ULL,0x90472447a2fb18a3ULL,0x8a966939777c619fULL,0x3798142a2a3be21bULL,+ 0xe2f73c696755ff89ULL,0xdd3cf7e7473017e6ULL,0x8ef5689d3cf7600dULL,0x948dc4f8b1fc87b4ULL,0xd9e9fe814ea53299ULL,0x2d921ca298eb6028ULL,0xfaecedfd0c9803fcULL,0xf38ae8914d7b4745ULL,+ 0x871514560f664534ULL,0x85ceae7c4b68f103ULL,0xac09c4ae65578ab9ULL,0x33ec6868f044b10cULL,0x6ac4832b3a8ec1f1ULL,0x5509d1285847d5efULL,0xf909604f763f1574ULL,0xb16c4303c32f63c4ULL,+ 0xfd16847fdec67ef5ULL,0x742ee464233e76b7ULL,0x0b8e4134efc2b4c8ULL,0xca640b8642a3e521ULL,0x653a01908ceb6aa9ULL,0x313c300c547852d5ULL,0x24e4ab126b237af7ULL,0x2ba901628bb47af8ULL,+ 0x00467bc58cce08b5ULL,0xb636458c7f178d55ULL,0xc5748baea677d806ULL,0x2763a387dfa394ebULL,0xa12b448a7d3cebb6ULL,0xe7adda3e6f20d850ULL,0xf63ebce51558462cULL,0x58b36143620088a8ULL,+ 0xa9d89488a059c142ULL,0x6f5ae714ff0b9346ULL,0x068f237d16fb3664ULL,0x5853e4c4363186acULL,0xe2d87d2363c52f98ULL,0x2ec4a76681828876ULL,0x47b864fae14e7b1cULL,0x0c0bc0e569192408ULL,+ 0x624d60492ed22e91ULL,0x6fdfe0b56f072822ULL,0xeeca111539ce2271ULL,0x98100a4fdb01614fULL,0xb6b0daa2a35c628fULL,0xb6f94d2ec87e9a47ULL,0xc67732591d57d9ceULL,0xf70bfeec03884a7bULL,+ 0x4ff23ffd248a7d06ULL,0x80c5bfb4878873faULL,0xb7d9ad9005745981ULL,0x179c85db3db01994ULL,0xba41b06261a6966cULL,0x4d82d052eadce5a8ULL,0x9e91cd3ba5e6a318ULL,0x47795f4f95b2dda0ULL,+ 0x1ee426ccd5cd79bfULL,0x0032940b946c6e18ULL,0x1b1e8ae057477f58ULL,0xe94f7d346d823278ULL,0xc747cb96782ba21aULL,0xc5254469f72b33a5ULL,0x772ef6dec7f80c81ULL,0xd73acbfe2cd9e6b5ULL,+ 0x283c7513caa76097ULL,0x0a624fa936c83906ULL,0x6b20afec715af2c7ULL,0x4b969974eba78bfdULL,0x220755ccd921d60eULL,0x9b944e107baeca13ULL,0x04819d515ded93d4ULL,0x9bbff86e6dddfd27ULL,+ 0x21950b421ff6acd3ULL,0xffe7048453dc6909ULL,0xff4cd0b228766127ULL,0xabdbe6084fb7db2bULL,0x837c92285e1109e8ULL,0x26147d27f4645b5aULL,0x4d78f592f7818ed8ULL,0xd394077ef247fa36ULL,+ 0x508cec1c3b3f64c9ULL,0xe20bc0ba1e5edf3fULL,0xda1deb852f4318d4ULL,0xd20ebe0d5c3fa443ULL,0x370b4ea773241ea3ULL,0x61f1511c5e1a5f65ULL,0x99a5e23d82681c62ULL,0xd731e383a2f54c2dULL,+ 0x97359638546c4d8dULL,0x5f9c3fc492f24679ULL,0x912e8beda8c8acd9ULL,0xec3a318d306634b0ULL,0x80167f41c31cb264ULL,0x3db82f6f522113f2ULL,0xb155bcd2dcafe197ULL,0xfba1da5943465283ULL,+ 0x258bbbf9e7305683ULL,0x31eea5bf07ef5be6ULL,0x0deb0e4a46c814c1ULL,0x5cee8449a7b730ddULL,0xeab495c5a0182bdeULL,0xee759f879e27a6b4ULL,0xc2cf6a6880e518caULL,0x25e8013ff14cf3f4ULL,+ 0x3ec832e77acaca28ULL,0x1bfeea57c7385b29ULL,0x068212e3fd1eaf38ULL,0xc13298306acf8cccULL,0xb909f2db2aac9e59ULL,0x5748060db661782aULL,0xc5ab2632c79b7a01ULL,0xda44c6c600017626ULL,+ 0x69d44ed65c46aa8eULL,0x2100d5d3a8d063d1ULL,0xcb9727eaa2d17c36ULL,0x4c2bab1b8add53b7ULL,0xa084e90c15426704ULL,0x778afcd3a837ebeaULL,0x6651f7017ce477f8ULL,0xa062499846fb7a8bULL,+ 0x3667eb1a7f4c04ccULL,0x59556621a9404f84ULL,0x71cdf6537eceb50aULL,0x994a44a69b8335faULL,0xd7faf819dbeb9b69ULL,0x473c5680eed4350dULL,0xb6658466da44bba2ULL,0x0d1bc780872bdbf3ULL,+ 0xb8d3d9319ff91fe5ULL,0x039c4800f0518eedULL,0x95c376329182cb26ULL,0x0763a43482fc568dULL,0x707c04d5383e76baULL,0xac98b930824e8197ULL,0x92bf7c8f91230de0ULL,0x90876a0140959b70ULL,+};
@@ -0,0 +1,1 @@+62ec77dc6c2c8cc4c48c768f5f785240b55a47bf
@@ -0,0 +1,222 @@+SPDX-License-Identifier: Apache-2.0 OR ISC or MIT-0+++Apache 2.0 license+-------------------------------------+++ Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++ 1. Definitions.++ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document.++ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License.++ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity.++ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License.++ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files.++ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types.++ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below).++ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof.++ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution."++ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work.++ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form.++ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed.++ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions:++ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and++ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and++ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and++ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License.++ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License.++ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions.++ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file.++ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License.++ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages.++ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability.++ END OF TERMS AND CONDITIONS+++ISC license+-------------------------------------++Copyright Amazon.com, Inc. or its affiliates.++Permission to use, copy, modify, and/or distribute this software for any+purpose with or without fee is hereby granted, provided that the above+copyright notice and this permission notice appear in all copies.++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.+++MIT-0 license+-------------------------------------++Copyright 2021-2024 Amazon.com, Inc. or its affiliates.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and associated documentation files (the "Software"),+to deal in the Software without restriction, including without limitation+the rights to use, copy, modify, merge, publish, distribute, sublicense,+and/or sell copies of the Software, and to permit persons to whom the+Software is furnished to do so.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER+DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,184 @@+# s2n-bignum++Assembly for the NIST prime curves from AWS's+[s2n-bignum](https://github.com/awslabs/s2n-bignum), vendored here.++`COMMIT` holds the upstream revision these files came from, and `import.sh`+fetches them again. The files are unmodified: the choice between the two+variants of each routine is made in crypton's own C, not by editing theirs.++## Why++crypton's P-256 is portable C, and on the two architectures s2n-bignum+covers, hand-written assembly beats it by a lot. Measured against crypton's+own code in the same process, agreeing with it on every scalar tried:++| | crypton | s2n-bignum |+| --- | ---: | ---: |+| Apple M4 | 52.9 us | **20.6** |+| x86-64 with ADX (EPYC 9V74) | 175.9 | **54.5** |+| x86-64, ADX not advertised | 156.1 | **59.4** |++The third row is the `_alt` path, which is what crypton picks where `CPUID`+does not report ADX. It was measured on a KVM guest whose `CPUID` says so+while the host underneath runs ADX instructions anyway, so it says what the+two implementations cost relative to each other on that path, not what an+actual pre-Broadwell part would do.++Each routine also carries a machine-checked proof in HOL-Light that it+computes what it says, and is written in a constant-time style.++## Licence++`Apache-2.0 OR ISC OR MIT-0`, one of which is on every file and all three in+`LICENSE`. crypton is BSD-3, so it takes these under **ISC** -- the MIT-0+option would do as well, and the Apache one is the reason OpenSSL's and+BoringSSL's `ecp_nistz256`, which is Apache-2.0 only, cannot be used here.++## Which variant++Both forms of each routine are vendored, because which one is faster is not+the same question on the two architectures:++* **On ARM**, `_alt` is written for parts with high multiplier throughput,+ which is what Apple silicon is, and it wins there by 30-40%. The plain+ form is for parts that pipeline `UMULH` less well. There is no feature bit+ for this, so the choice is made at compile time on `__APPLE__`.+* **On x86-64**, the plain form uses `MULX`, `ADCX` and `ADOX`, and `_alt` is+ the fallback for processors without them. That *is* a feature bit, so the+ choice is made at run time, from `crypton_x86_simd_features()`.++## RSA++`crypton_powm.c`'s modular exponentiation also borrows from here, but only its+innermost step and only on x86-64: `bignum_kmul_16_32`, `bignum_ksqr_16_32`,+`bignum_kmul_32_64`, `bignum_ksqr_32_64` and `bignum_emontredc_8n` replace the+C's Montgomery multiplication and square, and at RSA-3072's 24 limbs the square+is built from `bignum_sqr_8_16` and `bignum_mul_8_16`. The window, the table and its masked+scan are crypton's throughout. Sixteen limbs is 1024 bits and thirty-two is+2048: the halves a CRT exponentiation works in for RSA-2048 and RSA-4096, and+the whole thing without CRT. The reduction wants ADX, so the choice is made at+run time like the other x86-64 ones.++It is twice the C, because the C cannot form the two carry chains `ADCX` and+`ADOX` give. Measured on an EPYC 7763 at 1024 bits:++| | C | s2n-bignum |+| --- | ---: | ---: |+| multiplication | 0.4832 us | **0.2479** |+| square | 0.3984 | **0.1994** |++### The Montgomery constant++`bignum_montifier` is vendored for **both** architectures. It is the one+routine here that is not about a particular curve or a particular size: every+modular exponentiation and every setup in `crypton_ecc.c` starts by computing+R^2 mod m, and this computes it. crypton's C climbs to it by a+binary ladder of Montgomery squarings -- log2 of the modulus' bits of them,+eleven at 2048 -- and the assembly is between two and three and a half times+faster, the gap being the carry chains again:++| | C | s2n-bignum |+| --- | ---: | ---: |+| M4, 1024 bits | 1.853 us | **0.771** |+| M4, 2048 bits | 5.835 | **2.407** |+| an Intel x86-64, 1024 bits | 6.145 | **1.995** |+| an Intel x86-64, 2048 bits | 23.332 | **6.852** |++A CRT signature computes it twice, so an RSA-2048 private operation on the+EPYC 7763 goes from 613.5 to 606.4 microseconds -- a little over one per+cent, which is all a constant computed twice out of some two and a half+thousand multiplications can be. It is worth much more than that to anything+whose exponent is short, which is why it is here: see `crypton_powm.c`.++The two agree bit for bit; `cbits/tests/powm` requires it at six widths, with+moduli that fill their limbs and moduli that do not, and a build without the+assembly (`-DCRYPTON_NO_MONTIFIER`) is what it is checked against.++**None of the five above is vendored for AArch64**, where they measure level+with the C. That took three attempts to establish, and the first two were+wrong in opposite directions: a reading when the x86-64 routines went in put+the C 5% ahead, and one on 2026-09-26 put the assembly 4% ahead. Both were+wall-clock times on a machine with other work on it, where a swing of that size+says nothing. Measured by thread CPU time, taking the best of twenty-five+batches and alternating the two binaries with the order swapped, one RSA-2048+CRT private operation is 598.9 us through the C and 597.7 through the assembly:+two tenths of a per cent, which is nothing. The two agree on 200 random cases+at 1024 and 2048 bits, so both were computing the same thing. Five files for+nothing is not a trade, so the C stays.++The gap to OpenSSL on Apple silicon -- about half its speed -- is assembly and+not the C, and no portable C closes it. BearSSL's `i62`, which is as far as+portable C is known to go -- 62-bit limbs in 64-bit words, so that a+multiply-accumulate fits an `__int128` with no carry chain at all, and a+five-bit window against crypton's four -- was built and measured the same way+on the same machine: 626.4 us against crypton's C at 668.0, a tie.++`bignum_emontredc_8n_cdiff` was tried too and is not the answer either: it+wants a precomputation this test did not give it, and was slower besides. What+the window is worth, and why it is four and not five, is in+`cbits/crypton_powm.c` beside the constant.++## Windows++x86-64 Windows takes the assembly as every other x86-64 does. Two things+stood in the way, and neither is fixed in a vendored file:++* **The ELF directives.** Each file ends its symbols with `.type` and+ `.size`, which the COFF assemblers refuse -- mingw's gas says "junk at end+ of line" after a warning, clang says "expected absolute expression".+ There is nothing in a PE object for them to say, so on `_WIN32` they are+ emptied, as upstream already does for Mach-O.+* **The calling convention.** Each file carries a prologue that moves+ Microsoft's argument registers into System V's, under `WINDOWS_ABI`, which+ upstream leaves to the build to define. On `_WIN32` it is defined.++Both are done in `x86_att/_internal_s2n_bignum_x86_att.h`, which is crypton's+and not upstream's. Every vendored file includes that name in quotes, and a+quoted include looks first beside the file that asks for it, so this is the+one each gets; it hands on to upstream's in `include/` by a relative path.+**It must not be removed as an upstream file that went missing**: without it+Windows does not assemble. On Linux and macOS it changes nothing -- the+objects are byte for byte what they were without it.++Not `#include_next`, which is the obvious way to hand on: clang, finding this+header beside the file that asked for it, starts that search from the top+and finds this header again, without end.++Windows on ARM keeps the C. The AArch64 files have the same directives and+would want the same header, and there is no runner to check one.++## What is not here++s2n-bignum has only x86-64 and AArch64, so crypton's C stays and is what+every other architecture uses.++Its `generic` directory holds a complete variable-size bignum library on both+architectures -- `bignum_montmul`, `bignum_montredc`, `bignum_emontredc`,+`bignum_modinv` and a whole `bignum_modexp` -- and only `bignum_montifier` is+taken from it. **The rest was measured on an M4 and is slower than what is+here**, which is why it stays out; they agree with crypton's answers in every+case first, so both were computing the same thing.++| nanoseconds, AArch64 | C | s2n-bignum |+| --- | ---: | ---: |+| Montgomery multiply, 1024 bits | **171.7** | 227.9 |+| Montgomery multiply, 2048 bits | **649.6** | 870.3 |+| Montgomery square, 1024 bits | **157.3** | 202.6 |+| Montgomery square, 2048 bits | **539.2** | 870.8 |++That is the inline assembly above doing its job: four limbs to an iteration+with two carry chains, where a size-parametric routine takes them one at a+time. `bignum_modexp`, which would have replaced `crypton_powm_sec` outright,+loses by more again -- 421.0 microseconds against 246.4 at 1024 bits and 3578+against 1534 at 2048 -- because it has that multiplication inside it and no+window, so it pays about twice the multiplications as well.++The README there says every function is written in a constant-time style, with+one named exception that is none of these, though it also says that unlike+functional correctness this is not machine-checked.++`p384_montjscalarmul` and `p521_jscalarmul`+have no affine wrapper upstream; crypton's is in `cbits/p256/p256_s2n.c`'s+sibling for those curves. There is no fixed-base routine for P-384 or+P-521 at all, so signing on those curves keeps crypton's comb.
@@ -0,0 +1,151 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Convert from almost-Montgomery form, z := (x / 2^384) mod p_384+// Input x[6]; output z[6]+//+// extern void bignum_deamont_p384(uint64_t z[static 6],+// const uint64_t x[static 6]);+//+// Convert a 6-digit bignum x out of its (optionally almost) Montgomery form,+// "almost" meaning any 6-digit input will work, with no range restriction.+//+// Standard ARM ABI: X0 = z, X1 = x+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_deamont_p384)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_deamont_p384)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_deamont_p384)+ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_deamont_p384_alt)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_deamont_p384_alt)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_deamont_p384_alt)+ .text+ .balign 4++// ---------------------------------------------------------------------------+// Core one-step "short" Montgomery reduction macro. Takes input in+// [d5;d4;d3;d2;d1;d0] and returns result in [d6;d5;d4;d3;d2;d1],+// adding to the existing contents of [d5;d4;d3;d2;d1]. It is fine+// for d6 to be the same register as d0.+//+// We want to add (2^384 - 2^128 - 2^96 + 2^32 - 1) * w+// where w = [d0 + (d0<<32)] mod 2^64+// ---------------------------------------------------------------------------++#define montreds(d6,d5,d4,d3,d2,d1,d0, t3,t2,t1) \+/* Our correction multiplier is w = [d0 + (d0<<32)] mod 2^64 */ \+/* Recycle d0 (which we know gets implicitly cancelled) to store it */ \+ lsl t1, d0, #32 __LF \+ add d0, t1, d0 __LF \+/* Now let [t2;t1] = 2^64 * w - w + w_hi where w_hi = floor(w/2^32) */ \+/* We need to subtract 2^32 * this, and we can ignore its lower 32 */ \+/* bits since by design it will cancel anyway; we only need the w_hi */ \+/* part to get the carry propagation going. */ \+ lsr t1, d0, #32 __LF \+ subs t1, t1, d0 __LF \+ sbc t2, d0, xzr __LF \+/* Now select in t1 the field to subtract from d1 */ \+ extr t1, t2, t1, #32 __LF \+/* And now get the terms to subtract from d2 and d3 */ \+ lsr t2, t2, #32 __LF \+ adds t2, t2, d0 __LF \+ adc t3, xzr, xzr __LF \+/* Do the subtraction of that portion */ \+ subs d1, d1, t1 __LF \+ sbcs d2, d2, t2 __LF \+ sbcs d3, d3, t3 __LF \+ sbcs d4, d4, xzr __LF \+ sbcs d5, d5, xzr __LF \+/* Now effectively add 2^384 * w by taking d0 as the input for last sbc */ \+ sbc d6, d0, xzr++// Input parameters++#define z x0+#define x x1++// Rotating registers for the intermediate windows++#define d0 x2+#define d1 x3+#define d2 x4+#define d3 x5+#define d4 x6+#define d5 x7++// Other temporaries++#define u x8+#define v x9+#define w x10++S2N_BN_SYMBOL(bignum_deamont_p384):++S2N_BN_SYMBOL(bignum_deamont_p384_alt):+ CFI_START++// Set up an initial window with the input x and an extra leading zero++ ldp d0, d1, [x]+ ldp d2, d3, [x, #16]+ ldp d4, d5, [x, #32]++// Systematically scroll left doing 1-step reductions++ montreds(d0,d5,d4,d3,d2,d1,d0, u,v,w)++ montreds(d1,d0,d5,d4,d3,d2,d1, u,v,w)++ montreds(d2,d1,d0,d5,d4,d3,d2, u,v,w)++ montreds(d3,d2,d1,d0,d5,d4,d3, u,v,w)++ montreds(d4,d3,d2,d1,d0,d5,d4, u,v,w)++ montreds(d5,d4,d3,d2,d1,d0,d5, u,v,w)++// Now compare end result in [d5;d4;d3;d2;d1;d0] = dd with p_384 by *adding*+// 2^384 - p_384 = [0;0;0;w;v;u]. This will set CF if+// dd + (2^384 - p_384) >= 2^384, hence iff dd >= p_384++ mov u, #0xffffffff00000001+ mov v, #0x00000000ffffffff+ mov w, #0x0000000000000001++ adds xzr, d0, u+ adcs xzr, d1, v+ adcs xzr, d2, w+ adcs xzr, d3, xzr+ adcs xzr, d4, xzr+ adcs xzr, d5, xzr++// Convert the condition dd >= p_384 into a bitmask in w and do a masked+// subtraction of p_384, via a masked addition of 2^384 - p_384:++ csetm w, cs+ and u, u, w+ adds d0, d0, u+ and v, v, w+ adcs d1, d1, v+ and w, w, #1+ adcs d2, d2, w+ adcs d3, d3, xzr+ adcs d4, d4, xzr+ adc d5, d5, xzr++// Store it back++ stp d0, d1, [z]+ stp d2, d3, [z, #16]+ stp d4, d5, [z, #32]++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_deamont_p384)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,99 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Convert from Montgomery form z := (x / 2^256) mod p_256, assuming x reduced+// Input x[4]; output z[4]+//+// extern void bignum_demont_p256(uint64_t z[static 4],+// const uint64_t x[static 4]);+//+// This assumes the input is < p_256 for correctness. If this is not the case,+// use the variant "bignum_deamont_p256" instead.+//+// Standard ARM ABI: X0 = z, X1 = x+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_demont_p256)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_demont_p256)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_demont_p256)+ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_demont_p256_alt)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_demont_p256_alt)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_demont_p256_alt)+ .text+ .balign 4++// ---------------------------------------------------------------------------+// Core one-step "short" Montgomery reduction macro. Takes input in+// [d3;d2;d1;d0] and returns result in [d4;d3;d2;d1], adding to the+// existing contents of [d3;d2;d1] and generating d4 from zero, re-using+// d0 as a temporary internally together with t0, t1 and t2.+// It is fine for d4 to be the same register as d0, and it often is.+// ---------------------------------------------------------------------------++#define montreds(d4,d3,d2,d1,d0, t2,t1,t0) \+/* Let w = d0, the original word we use as offset; d0 gets recycled */ \+/* First let [t2;t1] = 2^32 * w */ \+/* then let [d0;t0] = (2^64 - 2^32 + 1) * w (overwrite old d0) */ \+ lsl t1, d0, #32 __LF \+ subs t0, d0, t1 __LF \+ lsr t2, d0, #32 __LF \+ sbc d0, d0, t2 __LF \+/* Hence [d4;..;d1] := [d3;d2;d1;0] + (2^256 - 2^224 + 2^192 + 2^96) * w */ \+ adds d1, d1, t1 __LF \+ adcs d2, d2, t2 __LF \+ adcs d3, d3, t0 __LF \+ adc d4, d0, xzr++// Input parameters++#define z x0+#define x x1++// Rotating registers for the intermediate windows (with repetitions)++#define d0 x2+#define d1 x3+#define d2 x4+#define d3 x5++// Other temporaries++#define u x6+#define v x7+#define w x8++S2N_BN_SYMBOL(bignum_demont_p256):++S2N_BN_SYMBOL(bignum_demont_p256_alt):+ CFI_START++// Set up an initial window with the input x and an extra leading zero++ ldp d0, d1, [x]+ ldp d2, d3, [x, #16]++// Systematically scroll left doing 1-step reductions++ montreds(d0,d3,d2,d1,d0, u,v,w)++ montreds(d1,d0,d3,d2,d1, u,v,w)++ montreds(d2,d1,d0,d3,d2, u,v,w)++ montreds(d3,d2,d1,d0,d3, u,v,w)++// Write back result++ stp d0, d1, [z]+ stp d2, d3, [z, #16]++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_demont_p256)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,1701 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Modular inverse modulo p_521 = 2^521 - 1+// Input x[9]; output z[9]+//+// extern void bignum_inv_p521(uint64_t z[static 9],const uint64_t x[static 9]);+//+// Assuming the 9-digit input x is coprime to p_521, i.e. is not divisible+// by it, returns z < p_521 such that x * z == 1 (mod p_521). Note that+// x does not need to be reduced modulo p_521, but the output always is.+//+// Standard ARM ABI: X0 = z, X1 = x+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_inv_p521)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_inv_p521)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_inv_p521)++ .text+ .balign 4++// Size in bytes of a 64-bit word++#define N 8++// Used for the return pointer++#define res x20++// Loop counter and d = 2 * delta value for divstep++#define i x21+#define d x22++// Registers used for matrix element magnitudes and signs++#define m00 x10+#define m01 x11+#define m10 x12+#define m11 x13+#define s00 x14+#define s01 x15+#define s10 x16+#define s11 x17++// Initial carries for combinations++#define car0 x9+#define car1 x19++// Input and output, plain registers treated according to pattern++#define reg0 x0, #0+#define reg1 x1, #0+#define reg2 x2, #0+#define reg3 x3, #0+#define reg4 x4, #0++#define x x1, #0+#define z x0, #0++// Pointer-offset pairs for temporaries on stack++#define f sp, #0+#define g sp, #(9*N)+#define u sp, #(18*N)+#define v sp, #(27*N)++// Total size to reserve on the stack++#define NSPACE 36*N++// Very similar to a subroutine call to the s2n-bignum word_divstep59.+// But different in register usage and returning the final matrix in+// registers as follows+//+// [ m00 m01]+// [ m10 m11]++#define divstep59() \+ and x4, x2, #0xfffff __LF \+ orr x4, x4, #0xfffffe0000000000 __LF \+ and x5, x3, #0xfffff __LF \+ orr x5, x5, #0xc000000000000000 __LF \+ tst x5, #0x1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ asr x5, x5, #1 __LF \+ add x8, x4, #0x100, lsl #12 __LF \+ sbfx x8, x8, #21, #21 __LF \+ mov x11, #0x100000 __LF \+ add x11, x11, x11, lsl #21 __LF \+ add x9, x4, x11 __LF \+ asr x9, x9, #42 __LF \+ add x10, x5, #0x100, lsl #12 __LF \+ sbfx x10, x10, #21, #21 __LF \+ add x11, x5, x11 __LF \+ asr x11, x11, #42 __LF \+ mul x6, x8, x2 __LF \+ mul x7, x9, x3 __LF \+ mul x2, x10, x2 __LF \+ mul x3, x11, x3 __LF \+ add x4, x6, x7 __LF \+ add x5, x2, x3 __LF \+ asr x2, x4, #20 __LF \+ asr x3, x5, #20 __LF \+ and x4, x2, #0xfffff __LF \+ orr x4, x4, #0xfffffe0000000000 __LF \+ and x5, x3, #0xfffff __LF \+ orr x5, x5, #0xc000000000000000 __LF \+ tst x5, #0x1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ asr x5, x5, #1 __LF \+ add x12, x4, #0x100, lsl #12 __LF \+ sbfx x12, x12, #21, #21 __LF \+ mov x15, #0x100000 __LF \+ add x15, x15, x15, lsl #21 __LF \+ add x13, x4, x15 __LF \+ asr x13, x13, #42 __LF \+ add x14, x5, #0x100, lsl #12 __LF \+ sbfx x14, x14, #21, #21 __LF \+ add x15, x5, x15 __LF \+ asr x15, x15, #42 __LF \+ mul x6, x12, x2 __LF \+ mul x7, x13, x3 __LF \+ mul x2, x14, x2 __LF \+ mul x3, x15, x3 __LF \+ add x4, x6, x7 __LF \+ add x5, x2, x3 __LF \+ asr x2, x4, #20 __LF \+ asr x3, x5, #20 __LF \+ and x4, x2, #0xfffff __LF \+ orr x4, x4, #0xfffffe0000000000 __LF \+ and x5, x3, #0xfffff __LF \+ orr x5, x5, #0xc000000000000000 __LF \+ tst x5, #0x1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ mul x2, x12, x8 __LF \+ mul x3, x12, x9 __LF \+ mul x6, x14, x8 __LF \+ mul x7, x14, x9 __LF \+ madd x8, x13, x10, x2 __LF \+ madd x9, x13, x11, x3 __LF \+ madd x16, x15, x10, x6 __LF \+ madd x17, x15, x11, x7 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ asr x5, x5, #1 __LF \+ add x12, x4, #0x100, lsl #12 __LF \+ sbfx x12, x12, #22, #21 __LF \+ mov x15, #0x100000 __LF \+ add x15, x15, x15, lsl #21 __LF \+ add x13, x4, x15 __LF \+ asr x13, x13, #43 __LF \+ add x14, x5, #0x100, lsl #12 __LF \+ sbfx x14, x14, #22, #21 __LF \+ add x15, x5, x15 __LF \+ asr x15, x15, #43 __LF \+ mneg x2, x12, x8 __LF \+ mneg x3, x12, x9 __LF \+ mneg x4, x14, x8 __LF \+ mneg x5, x14, x9 __LF \+ msub m00, x13, x16, x2 __LF \+ msub m01, x13, x17, x3 __LF \+ msub m10, x15, x16, x4 __LF \+ msub m11, x15, x17, x5++// Loading large constants++#define movbig(nn,n3,n2,n1,n0) \+ movz nn, n0 __LF \+ movk nn, n1, lsl #16 __LF \+ movk nn, n2, lsl #32 __LF \+ movk nn, n3, lsl #48++S2N_BN_SYMBOL(bignum_inv_p521):+ CFI_START++// Save registers and make room for temporaries++ CFI_PUSH2(x19,x20)+ CFI_PUSH2(x21,x22)+ CFI_DEC_SP(NSPACE)++// Save the return pointer for the end so we can overwrite x0 later++ mov res, x0++// Copy the prime p_521 = 2^521 - 1 into the f variable++ mov x10, #0xFFFFFFFFFFFFFFFF+ stp x10, x10, [f]+ stp x10, x10, [f+16]+ stp x10, x10, [f+32]+ stp x10, x10, [f+48]+ mov x11, #0x1FF+ str x11, [f+64]++// Copy the input into the g variable, but reduce it strictly mod p_521+// so that g <= f as assumed in the bound proof. This code fragment is+// very similar to bignum_mod_p521_9 complete with carry condensation.++ ldr x8, [x1, #64]+ lsr x9, x8, #9++ subs xzr, xzr, xzr+ ldp x10, x11, [x1]+ adcs xzr, x10, x9+ adcs xzr, x11, xzr+ ldp x12, x13, [x1, #16]+ and x7, x12, x13+ adcs xzr, x7, xzr+ ldp x14, x15, [x1, #32]+ and x7, x14, x15+ adcs xzr, x7, xzr+ ldp x16, x17, [x1, #48]+ and x7, x16, x17+ adcs xzr, x7, xzr+ orr x7, x8, #~0x1FF+ adcs x7, x7, xzr++ adcs x10, x10, x9+ adcs x11, x11, xzr+ adcs x12, x12, xzr+ adcs x13, x13, xzr+ adcs x14, x14, xzr+ adcs x15, x15, xzr+ adcs x16, x16, xzr+ adcs x17, x17, xzr+ adc x8, x8, xzr+ and x8, x8, #0x1FF++ stp x10, x11, [g]+ stp x12, x13, [g+16]+ stp x14, x15, [g+32]+ stp x16, x17, [g+48]+ str x8, [g+64]++// Also maintain weakly reduced < 2*p_521 vector [u,v] such that+// [f,g] == x * 2^{1239-59*i} * [u,v] (mod p_521)+// starting with [p_521,x] == x * 2^{1239-59*0} * [0,2^-1239] (mod p_521)+// Note that because (2^{a+521} == 2^a) (mod p_521) we simply have+// (2^-1239 == 2^324) (mod p_521) so the constant initializer is simple.+//+// Based on the standard divstep bound, for inputs <= 2^b we need at least+// n >= (9437 * b + 1) / 4096. Since b is 521, that means 1201 iterations.+// Since we package divstep in multiples of 59 bits, we do 21 blocks of 59+// making *1239* total. (With a bit more effort we could avoid the full 59+// divsteps and use a shorter tail computation, but we keep it simple.)+// Hence, after the 21st iteration we have [f,g] == x * [u,v] and since+// |f| = 1 we get the modular inverse from u by flipping its sign with f.++ stp xzr, xzr, [u]+ stp xzr, xzr, [u+16]+ stp xzr, xzr, [u+32]+ stp xzr, xzr, [u+48]+ str xzr, [u+64]++ mov x10, #16+ stp xzr, xzr, [v]+ stp xzr, xzr, [v+16]+ stp xzr, x10, [v+32]+ stp xzr, xzr, [v+48]+ str xzr, [v+64]++// Start of main loop. We jump into the middle so that the divstep+// portion is common to the special 21st iteration after a uniform+// first 20.++ mov i, #21+ mov d, #1+ b Lbignum_inv_p521_midloop++Lbignum_inv_p521_loop:++// Separate the matrix elements into sign-magnitude pairs++ cmp m00, xzr+ csetm s00, mi+ cneg m00, m00, mi++ cmp m01, xzr+ csetm s01, mi+ cneg m01, m01, mi++ cmp m10, xzr+ csetm s10, mi+ cneg m10, m10, mi++ cmp m11, xzr+ csetm s11, mi+ cneg m11, m11, mi++// Adjust the initial values to allow for complement instead of negation+// This initial offset is the same for [f,g] and [u,v] compositions.+// Save it in stable registers for the [u,v] part and do [f,g] first.++ and x0, m00, s00+ and x1, m01, s01+ add car0, x0, x1++ and x0, m10, s10+ and x1, m11, s11+ add car1, x0, x1++// Now the computation of the updated f and g values. This maintains a+// 2-word carry between stages so we can conveniently insert the shift+// right by 59 before storing back, and not overwrite digits we need+// again of the old f and g values.+//+// Digit 0 of [f,g]++ ldr x7, [f]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, car0, x0+ adc x2, xzr, x1+ ldr x8, [g]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ adc x2, x2, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x5, car1, x0+ adc x3, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x5, x5, x0+ adc x3, x3, x1++// Digit 1 of [f,g]++ ldr x7, [f+N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x2, x2, x0+ adc x6, xzr, x1+ ldr x8, [g+N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x2, x2, x0+ adc x6, x6, x1+ extr x4, x2, x4, #59+ str x4, [f]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x3, x3, x0+ adc x4, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x3, x3, x0+ adc x4, x4, x1+ extr x5, x3, x5, #59+ str x5, [g]++// Digit 2 of [f,g]++ ldr x7, [f+2*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x6, x6, x0+ adc x5, xzr, x1+ ldr x8, [g+2*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x6, x6, x0+ adc x5, x5, x1+ extr x2, x6, x2, #59+ str x2, [f+N]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x4, x4, x0+ adc x2, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x4, x4, x0+ adc x2, x2, x1+ extr x3, x4, x3, #59+ str x3, [g+N]++// Digit 3 of [f,g]++ ldr x7, [f+3*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x5, x5, x0+ adc x3, xzr, x1+ ldr x8, [g+3*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x5, x5, x0+ adc x3, x3, x1+ extr x6, x5, x6, #59+ str x6, [f+2*N]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x2, x2, x0+ adc x6, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x2, x2, x0+ adc x6, x6, x1+ extr x4, x2, x4, #59+ str x4, [g+2*N]++// Digit 4 of [f,g]++ ldr x7, [f+4*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x3, x3, x0+ adc x4, xzr, x1+ ldr x8, [g+4*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x3, x3, x0+ adc x4, x4, x1+ extr x5, x3, x5, #59+ str x5, [f+3*N]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x6, x6, x0+ adc x5, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x6, x6, x0+ adc x5, x5, x1+ extr x2, x6, x2, #59+ str x2, [g+3*N]++// Digit 5 of [f,g]++ ldr x7, [f+5*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, x4, x0+ adc x2, xzr, x1+ ldr x8, [g+5*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ adc x2, x2, x1+ extr x3, x4, x3, #59+ str x3, [f+4*N]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x5, x5, x0+ adc x3, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x5, x5, x0+ adc x3, x3, x1+ extr x6, x5, x6, #59+ str x6, [g+4*N]++// Digit 6 of [f,g]++ ldr x7, [f+6*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x2, x2, x0+ adc x6, xzr, x1+ ldr x8, [g+6*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x2, x2, x0+ adc x6, x6, x1+ extr x4, x2, x4, #59+ str x4, [f+5*N]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x3, x3, x0+ adc x4, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x3, x3, x0+ adc x4, x4, x1+ extr x5, x3, x5, #59+ str x5, [g+5*N]++// Digit 7 of [f,g]++ ldr x7, [f+7*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x6, x6, x0+ adc x5, xzr, x1+ ldr x8, [g+7*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x6, x6, x0+ adc x5, x5, x1+ extr x2, x6, x2, #59+ str x2, [f+6*N]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x4, x4, x0+ adc x2, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x4, x4, x0+ adc x2, x2, x1+ extr x3, x4, x3, #59+ str x3, [g+6*N]++// Digits 8 and 9 of [f,g]++ ldr x7, [f+8*N]+ eor x1, x7, s00+ asr x3, x1, #63+ and x3, x3, m00+ neg x3, x3+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x5, x5, x0+ adc x3, x3, x1+ ldr x8, [g+8*N]+ eor x1, x8, s01+ asr x0, x1, #63+ and x0, x0, m01+ sub x3, x3, x0+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x5, x5, x0+ adc x3, x3, x1+ extr x6, x5, x6, #59+ str x6, [f+7*N]+ extr x5, x3, x5, #59+ str x5, [f+8*N]++ eor x1, x7, s10+ asr x5, x1, #63+ and x5, x5, m10+ neg x5, x5+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x2, x2, x0+ adc x5, x5, x1+ eor x1, x8, s11+ asr x0, x1, #63+ and x0, x0, m11+ sub x5, x5, x0+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x2, x2, x0+ adc x5, x5, x1+ extr x4, x2, x4, #59+ str x4, [g+7*N]+ extr x2, x5, x2, #59+ str x2, [g+8*N]++// Now the computation of the updated u and v values and their+// modular reductions. A very similar accumulation except that+// the top words of u and v are unsigned and we don't shift.+//+// Digit 0 of [u,v]++ ldr x7, [u]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, car0, x0+ adc x2, xzr, x1+ ldr x8, [v]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ str x4, [u]+ adc x2, x2, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x5, car1, x0+ adc x3, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x5, x5, x0+ str x5, [v]+ adc x3, x3, x1++// Digit 1 of [u,v]++ ldr x7, [u+N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x2, x2, x0+ adc x6, xzr, x1+ ldr x8, [v+N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x2, x2, x0+ str x2, [u+N]+ adc x6, x6, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x3, x3, x0+ adc x4, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x3, x3, x0+ str x3, [v+N]+ adc x4, x4, x1++// Digit 2 of [u,v]++ ldr x7, [u+2*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x6, x6, x0+ adc x5, xzr, x1+ ldr x8, [v+2*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x6, x6, x0+ str x6, [u+2*N]+ adc x5, x5, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x4, x4, x0+ adc x2, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x4, x4, x0+ str x4, [v+2*N]+ adc x2, x2, x1++// Digit 3 of [u,v]++ ldr x7, [u+3*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x5, x5, x0+ adc x3, xzr, x1+ ldr x8, [v+3*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x5, x5, x0+ str x5, [u+3*N]+ adc x3, x3, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x2, x2, x0+ adc x6, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x2, x2, x0+ str x2, [v+3*N]+ adc x6, x6, x1++// Digit 4 of [u,v]++ ldr x7, [u+4*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x3, x3, x0+ adc x4, xzr, x1+ ldr x8, [v+4*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x3, x3, x0+ str x3, [u+4*N]+ adc x4, x4, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x6, x6, x0+ adc x5, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x6, x6, x0+ str x6, [v+4*N]+ adc x5, x5, x1++// Digit 5 of [u,v]++ ldr x7, [u+5*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, x4, x0+ adc x2, xzr, x1+ ldr x8, [v+5*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ str x4, [u+5*N]+ adc x2, x2, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x5, x5, x0+ adc x3, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x5, x5, x0+ str x5, [v+5*N]+ adc x3, x3, x1++// Digit 6 of [u,v]++ ldr x7, [u+6*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x2, x2, x0+ adc x6, xzr, x1+ ldr x8, [v+6*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x2, x2, x0+ str x2, [u+6*N]+ adc x6, x6, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x3, x3, x0+ adc x4, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x3, x3, x0+ str x3, [v+6*N]+ adc x4, x4, x1++// Digit 7 of [u,v]++ ldr x7, [u+7*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x6, x6, x0+ adc x5, xzr, x1+ ldr x8, [v+7*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x6, x6, x0+ str x6, [u+7*N]+ adc x5, x5, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x4, x4, x0+ adc x2, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x4, x4, x0+ str x4, [v+7*N]+ adc x2, x2, x1++// Digits 8 and 9 of u (top is unsigned)++ ldr x7, [u+8*N]+ eor x1, x7, s00+ and x3, s00, m00+ neg x3, x3+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x5, x5, x0+ adc x3, x3, x1+ ldr x8, [v+8*N]+ eor x1, x8, s01+ and x0, s01, m01+ sub x3, x3, x0+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x5, x5, x0+ adc x3, x3, x1++// Modular reduction of u, reloading as needed from u[0],...,u[7],x5,x3++ extr x6, x3, x5, #9+ ldp x0, x1, [u]+ add x6, x6, x3, asr #63+ sub x5, x5, x6, lsl #9+ adds x0, x0, x6+ asr x6, x6, #63+ adcs x1, x1, x6+ stp x0, x1, [u]+ ldp x0, x1, [u+16]+ adcs x0, x0, x6+ adcs x1, x1, x6+ stp x0, x1, [u+16]+ ldp x0, x1, [u+32]+ adcs x0, x0, x6+ adcs x1, x1, x6+ stp x0, x1, [u+32]+ ldp x0, x1, [u+48]+ adcs x0, x0, x6+ adcs x1, x1, x6+ stp x0, x1, [u+48]+ adc x5, x5, x6+ str x5, [u+64]++// Digits 8 and 9 of v (top is unsigned)++ eor x1, x7, s10+ and x5, s10, m10+ neg x5, x5+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x2, x2, x0+ adc x5, x5, x1+ eor x1, x8, s11+ and x0, s11, m11+ sub x5, x5, x0+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x2, x2, x0+ adc x5, x5, x1++// Modular reduction of v, reloading as needed from v[0],...,v[7],x2,x5++ extr x6, x5, x2, #9+ ldp x0, x1, [v]+ add x6, x6, x5, asr #63+ sub x2, x2, x6, lsl #9+ adds x0, x0, x6+ asr x6, x6, #63+ adcs x1, x1, x6+ stp x0, x1, [v]+ ldp x0, x1, [v+16]+ adcs x0, x0, x6+ adcs x1, x1, x6+ stp x0, x1, [v+16]+ ldp x0, x1, [v+32]+ adcs x0, x0, x6+ adcs x1, x1, x6+ stp x0, x1, [v+32]+ ldp x0, x1, [v+48]+ adcs x0, x0, x6+ adcs x1, x1, x6+ stp x0, x1, [v+48]+ adc x2, x2, x6+ str x2, [v+64]++Lbignum_inv_p521_midloop:++ mov x1, d+ ldr x2, [f]+ ldr x3, [g]+ divstep59()+ mov d, x1++// Next iteration++ subs i, i, #1+ bne Lbignum_inv_p521_loop++// The 21st and last iteration does not need anything except the+// u value and the sign of f; the latter can be obtained from the+// lowest word of f. So it's done differently from the main loop.+// Find the sign of the new f. For this we just need one digit+// since we know (for in-scope cases) that f is either +1 or -1.+// We don't explicitly shift right by 59 either, but looking at+// bit 63 (or any bit >= 60) of the unshifted result is enough+// to distinguish -1 from +1; this is then made into a mask.++ ldr x0, [f]+ ldr x1, [g]+ mul x0, x0, m00+ madd x1, x1, m01, x0+ asr x0, x1, #63++// Now separate out the matrix into sign-magnitude pairs+// and adjust each one based on the sign of f.+//+// Note that at this point we expect |f|=1 and we got its+// sign above, so then since [f,0] == x * [u,v] (mod p_521)+// we want to flip the sign of u according to that of f.++ cmp m00, xzr+ csetm s00, mi+ cneg m00, m00, mi+ eor s00, s00, x0++ cmp m01, xzr+ csetm s01, mi+ cneg m01, m01, mi+ eor s01, s01, x0++ cmp m10, xzr+ csetm s10, mi+ cneg m10, m10, mi+ eor s10, s10, x0++ cmp m11, xzr+ csetm s11, mi+ cneg m11, m11, mi+ eor s11, s11, x0++// Adjust the initial value to allow for complement instead of negation++ and x0, m00, s00+ and x1, m01, s01+ add car0, x0, x1++// Digit 0 of [u]++ ldr x7, [u]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, car0, x0+ adc x2, xzr, x1+ ldr x8, [v]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ str x4, [u]+ adc x2, x2, x1++// Digit 1 of [u]++ ldr x7, [u+N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x2, x2, x0+ adc x6, xzr, x1+ ldr x8, [v+N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x2, x2, x0+ str x2, [u+N]+ adc x6, x6, x1++// Digit 2 of [u]++ ldr x7, [u+2*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x6, x6, x0+ adc x5, xzr, x1+ ldr x8, [v+2*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x6, x6, x0+ str x6, [u+2*N]+ adc x5, x5, x1++// Digit 3 of [u]++ ldr x7, [u+3*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x5, x5, x0+ adc x3, xzr, x1+ ldr x8, [v+3*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x5, x5, x0+ str x5, [u+3*N]+ adc x3, x3, x1++// Digit 4 of [u]++ ldr x7, [u+4*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x3, x3, x0+ adc x4, xzr, x1+ ldr x8, [v+4*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x3, x3, x0+ str x3, [u+4*N]+ adc x4, x4, x1++// Digit 5 of [u]++ ldr x7, [u+5*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, x4, x0+ adc x2, xzr, x1+ ldr x8, [v+5*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ str x4, [u+5*N]+ adc x2, x2, x1++// Digit 6 of [u]++ ldr x7, [u+6*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x2, x2, x0+ adc x6, xzr, x1+ ldr x8, [v+6*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x2, x2, x0+ str x2, [u+6*N]+ adc x6, x6, x1++// Digit 7 of [u]++ ldr x7, [u+7*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x6, x6, x0+ adc x5, xzr, x1+ ldr x8, [v+7*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x6, x6, x0+ str x6, [u+7*N]+ adc x5, x5, x1++// Digits 8 and 9 of u (top is unsigned)++ ldr x7, [u+8*N]+ eor x1, x7, s00+ and x3, s00, m00+ neg x3, x3+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x5, x5, x0+ adc x3, x3, x1+ ldr x8, [v+8*N]+ eor x1, x8, s01+ and x0, s01, m01+ sub x3, x3, x0+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x5, x5, x0+ adc x3, x3, x1++// Modular reduction of u, reloading as needed from u[0],...,u[7],x5,x3++ extr x6, x3, x5, #9+ ldp x10, x11, [u]+ add x6, x6, x3, asr #63+ sub x5, x5, x6, lsl #9+ adds x10, x10, x6+ asr x6, x6, #63+ adcs x11, x11, x6+ ldp x12, x13, [u+16]+ adcs x12, x12, x6+ adcs x13, x13, x6+ ldp x14, x15, [u+32]+ adcs x14, x14, x6+ adcs x15, x15, x6+ ldp x16, x17, [u+48]+ adcs x16, x16, x6+ adcs x17, x17, x6+ adc x19, x5, x6++// Further strict reduction ready for the output, which just means+// a conditional subtraction of p_521++ subs x0, x10, #-1+ adcs x1, x11, xzr+ adcs x2, x12, xzr+ adcs x3, x13, xzr+ adcs x4, x14, xzr+ adcs x5, x15, xzr+ adcs x6, x16, xzr+ adcs x7, x17, xzr+ mov x8, #0x1FF+ sbcs x8, x19, x8++ csel x0, x0, x10, cs+ csel x1, x1, x11, cs+ csel x2, x2, x12, cs+ csel x3, x3, x13, cs+ csel x4, x4, x14, cs+ csel x5, x5, x15, cs+ csel x6, x6, x16, cs+ csel x7, x7, x17, cs+ csel x8, x8, x19, cs++// Store it back to the final output++ stp x0, x1, [res]+ stp x2, x3, [res, #16]+ stp x4, x5, [res, #32]+ stp x6, x7, [res, #48]+ str x8, [res, #64]++// Restore stack and registers++ CFI_INC_SP(NSPACE)+ CFI_POP2(x21,x22)+ CFI_POP2(x19,x20)+ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_inv_p521)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack, "", %progbits+#endif
@@ -0,0 +1,613 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Invert modulo m, z = (1/a) mod b, assuming b is an odd number > 1, coprime a+// Inputs a[k], b[k]; output z[k]; temporary buffer t[>=3*k]+//+// extern void bignum_modinv(uint64_t k, uint64_t *z, const uint64_t *a,+// const uint64_t *b, uint64_t *t);+//+// k-digit (digit=64 bits) "z := a^-1 mod b" (modular inverse of a modulo b)+// using t as a temporary buffer (t at least 3*k words = 24*k bytes), and+// assuming that a and b are coprime *and* that b is an odd number > 1.+//+// Standard ARM ABI: X0 = k, X1 = z, X2 = a, X3 = b, X4 = t+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_modinv)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_modinv)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_modinv)+ .text+ .balign 4++// We get CHUNKSIZE bits per outer iteration, 64 minus a few for proxy errors++#define CHUNKSIZE 58++// Pervasive variables++#define k x0+#define z x1+#define b x3+#define w x4++// This one is recycled after initial copying in of a as outer loop counter++#define a x2+#define t x2++// Additional variables; later ones are currently rather high regs++#define l x5++#define m x21+#define n x22++// The matrix of update factors to apply to m and n+// Also used a couple of additional temporary variables for the swapping loop+// Also used as an extra down-counter in corrective negation loops++#define m_m x6+#define m_n x7+#define n_m x8+#define n_n x9++#define j x6++// General temporary variables and loop counters++#define i x10+#define t1 x11+#define t2 x12++// High and low proxies for the inner loop+// Then re-used for high and carry words during actual cross-multiplications++#define m_hi x13+#define n_hi x14+#define m_lo x15+#define n_lo x16++#define h1 x13+#define h2 x14+#define l1 x15+#define l2 x16++#define c1 x17+#define c2 x19++// Negated modular inverse for Montgomery++#define v x20++// Some more intuitive names for temp regs in initial word-level negmodinv.+// These just use t1 and t2 again, though carefully since t1 = initial b[0]++#define one t2+#define e1 t2+#define e2 t1+#define e4 t2+#define e8 t1++S2N_BN_SYMBOL(bignum_modinv):+ CFI_START++// We make use of registers beyond the modifiable++ CFI_PUSH2(x19,x20)+ CFI_PUSH2(x21,x22)++// If k = 0 then do nothing (this is out of scope anyway)++ cbz k, Lbignum_modinv_end++// Set up the additional two buffers m and n beyond w in temp space++ lsl i, k, #3+ add m, w, i+ add n, m, i++// Initialize the main buffers with their starting values:+// m = a, n = b, w = b (to be tweaked to b - 1) and z = 0++ mov i, xzr+Lbignum_modinv_copyloop:+ ldr t1, [a, i, lsl #3]+ ldr t2, [b, i, lsl #3]+ str t1, [m, i, lsl #3]+ str t2, [n, i, lsl #3]+ str t2, [w, i, lsl #3]+ str xzr, [z, i, lsl #3]+ add i, i, #1+ cmp i, k+ bcc Lbignum_modinv_copyloop++// Tweak down w to b - 1 (this crude approach is safe as b needs to be odd+// for it to be in scope). We have then established the congruence invariant:+//+// a * w == -m (mod b)+// a * z == n (mod b)+//+// This, with the bound w <= b and z <= b, is maintained round the outer loop++ ldr t1, [w]+ sub t2, t1, #1+ str t2, [w]++// Compute v = negated modular inverse of b mod 2^64, reusing t1 from above+// This is used for Montgomery reduction operations each time round the loop++ lsl v, t1, #2+ sub v, t1, v+ eor v, v, #2+ mov one, #1+ madd e1, t1, v, one+ mul e2, e1, e1+ madd v, e1, v, v+ mul e4, e2, e2+ madd v, e2, v, v+ mul e8, e4, e4+ madd v, e4, v, v+ madd v, e8, v, v++// Set up the outer loop count of 128 * k+// The invariant is that m * n < 2^t at all times.++ lsl t, k, #7++// Start of the main outer loop iterated t / CHUNKSIZE times++Lbignum_modinv_outerloop:++// We need only bother with sharper l = min k (ceil(t/64)) digits+// for the computations on m and n (but we still need k for w and z).+// Either both m and n fit in l digits, or m has become zero and so+// nothing happens in the loop anyway and this makes no difference.++ add i, t, #63+ lsr l, i, #6+ cmp l, k+ csel l, k, l, cs++// Select upper and lower proxies for both m and n to drive the inner+// loop. The lower proxies are simply the lowest digits themselves,+// m_lo = m[0] and n_lo = n[0], while the upper proxies are bitfields+// of the two inputs selected so their top bit (63) aligns with the+// most significant bit of *either* of the two inputs.++ mov h1, xzr // Previous high and low for m+ mov l1, xzr+ mov h2, xzr // Previous high and low for n+ mov l2, xzr+ mov c2, xzr // Mask flag: previous word of one was nonzero+ // and in this case h1 and h2 are those words+ mov i, xzr+Lbignum_modinv_toploop:+ ldr t1, [m, i, lsl #3]+ ldr t2, [n, i, lsl #3]+ orr c1, t1, t2+ cmp c1, xzr+ and c1, c2, h1+ csel l1, c1, l1, ne+ and c1, c2, h2+ csel l2, c1, l2, ne+ csel h1, t1, h1, ne+ csel h2, t2, h2, ne+ csetm c2, ne+ add i, i, #1+ cmp i, l+ bcc Lbignum_modinv_toploop++ orr t1, h1, h2+ clz t2, t1+ negs c1, t2+ lsl h1, h1, t2+ csel l1, l1, xzr, ne+ lsl h2, h2, t2+ csel l2, l2, xzr, ne+ lsr l1, l1, c1+ lsr l2, l2, c1+ orr m_hi, h1, l1+ orr n_hi, h2, l2++ ldr m_lo, [m]+ ldr n_lo, [n]++// Now the inner loop, with i as loop counter from CHUNKSIZE down.+// This records a matrix of updates to apply to the initial+// values of m and n with, at stage j:+//+// sgn * m' = (m_m * m - m_n * n) / 2^j+// -sgn * n' = (n_m * m - n_n * n) / 2^j+//+// where "sgn" is either +1 or -1, and we lose track of which except+// that both instance above are the same. This throwing away the sign+// costs nothing (since we have to correct in general anyway because+// of the proxied comparison) and makes things a bit simpler. But it+// is simply the parity of the number of times the first condition,+// used as the swapping criterion, fires in this loop.++ mov m_m, #1+ mov m_n, xzr+ mov n_m, xzr+ mov n_n, #1++ mov i, #CHUNKSIZE++// Conceptually in the inner loop we follow these steps:+//+// * If m_lo is odd and m_hi < n_hi, then swap the four pairs+// (m_hi,n_hi); (m_lo,n_lo); (m_m,n_m); (m_n,n_n)+//+// * Now, if m_lo is odd (old or new, doesn't matter as initial n_lo is odd)+// m_hi := m_hi - n_hi, m_lo := m_lo - n_lo+// m_m := m_m + n_m, m_n := m_n + n_n+//+// * Halve and double them+// m_hi := m_hi / 2, m_lo := m_lo / 2+// n_m := n_m * 2, n_n := n_n * 2+//+// The actual computation computes updates before actually swapping and+// then corrects as needed. It also maintains the invariant ~ZF <=> odd(m_lo),+// since it seems to reduce the dependent latency. Set that up first.++ ands xzr, m_lo, #1++Lbignum_modinv_innerloop:++// At the start of the loop ~ZF <=> m_lo is odd; mask values accordingly+// Set the flags for m_hi - [~ZF] * n_hi so we know to flip things.++ csel t1, n_hi, xzr, ne+ csel t2, n_lo, xzr, ne+ csel c1, n_m, xzr, ne+ csel c2, n_n, xzr, ne+ ccmp m_hi, n_hi, #0x2, ne++// Compute subtractive updates, trivial in the case ZF <=> even(m_lo).++ sub t1, m_hi, t1+ sub t2, m_lo, t2++// If the subtraction borrows, swap things appropriately, negating where+// we've already subtracted so things are as if we actually swapped first.++ csel n_hi, n_hi, m_hi, cs+ cneg t1, t1, cc+ csel n_lo, n_lo, m_lo, cs+ cneg m_lo, t2, cc+ csel n_m, n_m, m_m, cs+ csel n_n, n_n, m_n, cs++// Update and shift while setting oddness flag for next iteration+// We look at bit 1 of t2 (m_lo before possible negation), which is+// safe because it is even.++ ands xzr, t2, #2+ add m_m, m_m, c1+ add m_n, m_n, c2+ lsr m_hi, t1, #1+ lsr m_lo, m_lo, #1+ add n_m, n_m, n_m+ add n_n, n_n, n_n++// Next iteration; don't disturb the flags since they are used at entry++ sub i, i, #1+ cbnz i, Lbignum_modinv_innerloop++// Apply the update to w and z, using addition in this case, and also take+// the chance to shift an additional 6 = 64-CHUNKSIZE bits to be ready for a+// Montgomery multiplication. Because we know that m_m + m_n <= 2^58 and+// w, z <= b < 2^{64k}, we know that both of these fit in k+1 words.+// We do this before the m-n update to allow us to play with c1 and c2 here.+//+// h1::w = 2^6 * (m_m * w + m_n * z)+// h2::z = 2^6 * (n_m * w + n_n * z)+//+// with c1 and c2 recording previous words for the shifting part++ mov h1, xzr+ mov h2, xzr+ mov c1, xzr+ mov c2, xzr++ mov i, xzr+Lbignum_modinv_congloop:+ ldr t1, [w, i, lsl #3]+ ldr t2, [z, i, lsl #3]++ mul l1, m_m, t1+ mul l2, m_n, t2+ adds l1, l1, h1+ umulh h1, m_m, t1+ adc h1, h1, xzr+ adds l1, l1, l2+ extr c1, l1, c1, #CHUNKSIZE+ str c1, [w, i, lsl #3]+ mov c1, l1+ umulh l1, m_n, t2+ adc h1, h1, l1++ mul l1, n_m, t1+ mul l2, n_n, t2+ adds l1, l1, h2+ umulh h2, n_m, t1+ adc h2, h2, xzr+ adds l1, l1, l2+ extr c2, l1, c2, #CHUNKSIZE+ str c2, [z, i, lsl #3]+ mov c2, l1+ umulh l1, n_n, t2+ adc h2, h2, l1++ add i, i, #1+ cmp i, k+ bcc Lbignum_modinv_congloop++ extr h1, h1, c1, #CHUNKSIZE+ extr h2, h2, c2, #CHUNKSIZE++// Do a Montgomery reduction of h1::w++ ldr t1, [w]+ mul c1, t1, v+ ldr t2, [b]+ mul l1, c1, t2+ umulh l2, c1, t2+ adds t1, t1, l1 // Will be zero but want the carry++ mov i, #1+ sub t1, k, #1+ cbz t1, Lbignum_modinv_wmontend+Lbignum_modinv_wmontloop:+ ldr t1, [b, i, lsl #3]+ ldr t2, [w, i, lsl #3]+ mul l1, c1, t1+ adcs t2, t2, l2+ umulh l2, c1, t1+ adc l2, l2, xzr+ adds t2, t2, l1+ sub l1, i, #1+ str t2, [w, l1, lsl #3]+ add i, i, #1+ sub t1, i, k+ cbnz t1, Lbignum_modinv_wmontloop+Lbignum_modinv_wmontend:+ adcs l2, l2, h1+ adc h1, xzr, xzr+ sub l1, i, #1+ str l2, [w, l1, lsl #3]++ subs i, xzr, xzr+Lbignum_modinv_wcmploop:+ ldr t1, [w, i, lsl #3]+ ldr t2, [b, i, lsl #3]+ sbcs xzr, t1, t2+ add i, i, #1+ sub t1, i, k+ cbnz t1, Lbignum_modinv_wcmploop++ sbcs xzr, h1, xzr+ csetm h1, cs++ subs i, xzr, xzr+Lbignum_modinv_wcorrloop:+ ldr t1, [w, i, lsl #3]+ ldr t2, [b, i, lsl #3]+ and t2, t2, h1+ sbcs t1, t1, t2+ str t1, [w, i, lsl #3]+ add i, i, #1+ sub t1, i, k+ cbnz t1, Lbignum_modinv_wcorrloop++// Do a Montgomery reduction of h2::z++ ldr t1, [z]+ mul c1, t1, v+ ldr t2, [b]+ mul l1, c1, t2+ umulh l2, c1, t2+ adds t1, t1, l1 // Will be zero but want the carry++ mov i, #1+ sub t1, k, #1+ cbz t1, Lbignum_modinv_zmontend+Lbignum_modinv_zmontloop:+ ldr t1, [b, i, lsl #3]+ ldr t2, [z, i, lsl #3]+ mul l1, c1, t1+ adcs t2, t2, l2+ umulh l2, c1, t1+ adc l2, l2, xzr+ adds t2, t2, l1+ sub l1, i, #1+ str t2, [z, l1, lsl #3]+ add i, i, #1+ sub t1, i, k+ cbnz t1, Lbignum_modinv_zmontloop+Lbignum_modinv_zmontend:+ adcs l2, l2, h2+ adc h2, xzr, xzr+ sub l1, i, #1+ str l2, [z, l1, lsl #3]++ subs i, xzr, xzr+Lbignum_modinv_zcmploop:+ ldr t1, [z, i, lsl #3]+ ldr t2, [b, i, lsl #3]+ sbcs xzr, t1, t2+ add i, i, #1+ sub t1, i, k+ cbnz t1, Lbignum_modinv_zcmploop++ sbcs xzr, h2, xzr+ csetm h2, cs++ subs i, xzr, xzr+Lbignum_modinv_zcorrloop:+ ldr t1, [z, i, lsl #3]+ ldr t2, [b, i, lsl #3]+ and t2, t2, h2+ sbcs t1, t1, t2+ str t1, [z, i, lsl #3]+ add i, i, #1+ sub t1, i, k+ cbnz t1, Lbignum_modinv_zcorrloop++// Now actually compute the updates to m and n corresponding to the matrix,+// and correct the signs if they have gone negative. First we compute the+// (k+1)-sized updates with the following invariant (here c1 and c2 are in+// fact carry bitmasks, either 0 or -1):+//+// c1::h1::m = m_m * m - m_n * n+// c2::h2::n = n_m * m - n_n * n++ mov h1, xzr+ mov h2, xzr+ mov c1, xzr+ mov c2, xzr+ mov i, xzr+Lbignum_modinv_crossloop:+ ldr t1, [m, i, lsl #3]+ ldr t2, [n, i, lsl #3]++ mul l1, m_m, t1+ mul l2, m_n, t2+ adds l1, l1, h1+ umulh h1, m_m, t1+ adc h1, h1, xzr+ subs l1, l1, l2+ str l1, [m, i, lsl #3]+ umulh l1, m_n, t2+ sub c1, l1, c1+ sbcs h1, h1, c1+ csetm c1, cc++ mul l1, n_m, t1+ mul l2, n_n, t2+ adds l1, l1, h2+ umulh h2, n_m, t1+ adc h2, h2, xzr+ subs l1, l1, l2+ str l1, [n, i, lsl #3]+ umulh l1, n_n, t2+ sub c2, l1, c2+ sbcs h2, h2, c2+ csetm c2, cc++ add i, i, #1+ cmp i, l+ bcc Lbignum_modinv_crossloop++// Write back m optionally negated and shifted right CHUNKSIZE bits++ adds xzr, c1, c1++ ldr l1, [m]+ mov i, xzr+ sub j, l, #1+ cbz j, Lbignum_modinv_negskip1++Lbignum_modinv_negloop1:+ add t1, i, #8+ ldr t2, [m, t1]+ extr l1, t2, l1, #CHUNKSIZE+ eor l1, l1, c1+ adcs l1, l1, xzr+ str l1, [m, i]+ mov l1, t2+ add i, i, #8+ sub j, j, #1+ cbnz j, Lbignum_modinv_negloop1+Lbignum_modinv_negskip1:+ extr l1, h1, l1, #CHUNKSIZE+ eor l1, l1, c1+ adcs l1, l1, xzr+ str l1, [m, i]++// Write back n optionally negated and shifted right CHUNKSIZE bits++ adds xzr, c2, c2++ ldr l1, [n]+ mov i, xzr+ sub j, l, #1+ cbz j, Lbignum_modinv_negskip2+Lbignum_modinv_negloop2:+ add t1, i, #8+ ldr t2, [n, t1]+ extr l1, t2, l1, #CHUNKSIZE+ eor l1, l1, c2+ adcs l1, l1, xzr+ str l1, [n, i]+ mov l1, t2+ add i, i, #8+ sub j, j, #1+ cbnz j, Lbignum_modinv_negloop2+Lbignum_modinv_negskip2:+ extr l1, h2, l1, #CHUNKSIZE+ eor l1, l1, c2+ adcs l1, l1, xzr+ str l1, [n, i]++// Finally, use the signs c1 and c2 to do optional modular negations of+// w and z respectively, flipping c2 to make signs work. We don't make+// any checks for zero values, but we certainly retain w <= b and z <= b.+// This is enough for the Montgomery step in the next iteration to give+// strict reduction w < b amd z < b, and anyway when we terminate we+// could not have z = b since it violates the coprimality assumption for+// in-scope cases.++ mov i, xzr+ adds xzr, c1, c1+Lbignum_modinv_wfliploop:+ ldr t1, [b, i, lsl #3]+ ldr t2, [w, i, lsl #3]+ and t1, t1, c1+ eor t2, t2, c1+ adcs t1, t1, t2+ str t1, [w, i, lsl #3]+ add i, i, #1+ sub t1, i, k+ cbnz t1, Lbignum_modinv_wfliploop++ mvn c2, c2++ mov i, xzr+ adds xzr, c2, c2+Lbignum_modinv_zfliploop:+ ldr t1, [b, i, lsl #3]+ ldr t2, [z, i, lsl #3]+ and t1, t1, c2+ eor t2, t2, c2+ adcs t1, t1, t2+ str t1, [z, i, lsl #3]+ add i, i, #1+ sub t1, i, k+ cbnz t1, Lbignum_modinv_zfliploop++// End of main loop. We can stop if t' <= 0 since then m * n < 2^0, which+// since n is odd and m and n are coprime (in the in-scope cases) means+// m = 0, n = 1 and hence from the congruence invariant a * z == 1 (mod b).+// Moreover we do in fact need to maintain strictly t > 0 in the main loop,+// or the computation of the optimized digit bound l could collapse to 0.++ subs t, t, #CHUNKSIZE+ bhi Lbignum_modinv_outerloop++Lbignum_modinv_end:+ CFI_POP2(x21,x22)+ CFI_POP2(x19,x20)++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_modinv)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,462 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Compute "montification" constant z := 2^{128k} mod m+// Input m[k]; output z[k]; temporary buffer t[>=k]+//+// extern void bignum_montifier(uint64_t k, uint64_t *z, const uint64_t *m,+// uint64_t *t);+//+// The last argument points to a temporary buffer t that should have size >= k.+// This is called "montifier" because given any other k-digit number x,+// whether or not it's reduced modulo m, it can be mapped to its Montgomery+// representation (2^{64k} * x) mod m just by Montgomery multiplication by z.+//+// Standard ARM ABI: X0 = k, X1 = z, X2 = m, X3 = t+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_montifier)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_montifier)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_montifier)+ .text+ .balign 4++#define k x0+#define z x1+#define m x2+#define t x3++// Some variables+// Modular inverse w is aliased to i, but we never use them together++#define i x4+#define w x4+#define j x5+#define h x6+#define a x7+#define l x8+#define c x9+#define b x10+#define d x11++// Some aliases for the values b and d++#define r x10+#define q x11+++S2N_BN_SYMBOL(bignum_montifier):+ CFI_START++// If k = 0 the whole operation is trivial++ cbz k, Lbignum_montifier_end++// Copy the input m into the temporary buffer t. The temporary register+// c matters since we want it to hold the highest digit, ready for the+// normalization phase.++ mov i, xzr+Lbignum_montifier_copyinloop:+ ldr c, [m, i, lsl #3]+ str c, [t, i, lsl #3]+ add i, i, #1+ cmp i, k+ bcc Lbignum_montifier_copyinloop++// Do a rather stupid but constant-time digit normalization, conditionally+// shifting left (k-1) times based on whether the top word is zero.+// With careful binary striding this could be O(k*log(k)) instead of O(k^2)+// while still retaining the constant-time style.+// The "cmp c, xzr" sets the zeroness predicate (ZF) for the entire inner loop++ subs i, k, #1+ beq Lbignum_montifier_normalized+Lbignum_montifier_normloop:+ mov j, xzr+ cmp c, xzr+ mov a, xzr+Lbignum_montifier_shufloop:+ mov c, a+ ldr a, [t, j, lsl #3]+ csel c, c, a, eq+ str c, [t, j, lsl #3]+ add j, j, #1+ sub d, j, k+ cbnz d, Lbignum_montifier_shufloop+ subs i, i, #1+ bne Lbignum_montifier_normloop++// We now have the top digit nonzero, assuming the input was nonzero,+// and as per the invariant of the loop above, c holds that digit. So+// now just count c's leading zeros and shift t bitwise that many bits.++Lbignum_montifier_normalized:+ clz c, c++ mov b, xzr+ mov i, xzr+ ands xzr, c, #63+ csetm l, ne+ neg d, c+Lbignum_montifier_bitloop:+ ldr j, [t, i, lsl #3]+ lsl a, j, c+ orr a, a, b+ lsr b, j, d+ and b, b, l+ str a, [t, i, lsl #3]+ add i, i, #1+ cmp i, k+ bcc Lbignum_montifier_bitloop++// Let h be the high word of n, which in all the in-scope cases is >= 2^63.+// Now successively form q = 2^i div h and r = 2^i mod h as i goes from+// 64 to 126. We avoid just using division out of constant-time concerns+// (at the least we would need to fix up h = 0 for out-of-scope inputs) and+// don't bother with Newton-Raphson, since this stupid simple loop doesn't+// contribute much of the overall runtime at typical sizes.++ sub h, k, #1+ ldr h, [t, h, lsl #3]+ mov q, #1+ neg r, h+ mov i, #62+Lbignum_montifier_estloop:+ add q, q, q+ mov a, h+ sub a, a, r+ cmp r, a // CF <=> r >= h - r <=> 2 * r >= h+ csetm a, cs+ sub q, q, a+ add r, r, r+ and a, a, h+ sub r, r, a+ subs i, i, #1+ bne Lbignum_montifier_estloop++// Strictly speaking the above loop doesn't quite give the true remainder+// and quotient in the special case r = h = 2^63, so fix it up. We get+// q = 2^63 - 1 and r = 2^63 and really want q = 2^63 and r = 0. This is+// supererogatory, because the main property of q used below still holds+// in this case unless the initial m = 1, and then anyway the overall+// specification (congruence modulo m) holds degenerately. But it seems+// nicer to get a "true" quotient and remainder.++ cmp r, h+ csinc q, q, q, ne++// So now we have q and r with 2^126 = q * h + r (imagining r = 0 in the+// fixed-up case above: note that we never actually use the computed+// value of r below and so didn't adjust it). And we can assume the ranges+// q <= 2^63 and r < h < 2^64.+//+// The idea is to use q as a first quotient estimate for a remainder+// of 2^{p+62} mod n, where p = 64 * k. We have, splitting n into the+// high and low parts h and l:+//+// 2^{p+62} - q * n = 2^{p+62} - q * (2^{p-64} * h + l)+// = 2^{p+62} - (2^{p-64} * (q * h) + q * l)+// = 2^{p+62} - 2^{p-64} * (2^126 - r) - q * l+// = 2^{p-64} * r - q * l+//+// Note that 2^{p-64} * r < 2^{p-64} * h <= n+// and also q * l < 2^63 * 2^{p-64} = 2^{p-1} <= n+// so |diff| = |2^{p-64} * r - q * l| < n.+//+// If in fact diff >= 0 then it is already 2^{p+62} mod n.+// otherwise diff + n is the right answer.+//+// To (maybe?) make the computation slightly easier we actually flip+// the sign and compute d = q * n - 2^{p+62}. Then the answer is either+// -d (when negative) or n - d; in either case we effectively negate d.+// This negating tweak in fact spoils the result for cases where+// 2^{p+62} mod n = 0, when we get n instead. However the only case+// where this can happen is m = 1, when the whole spec holds trivially,+// and actually the remainder of the logic below works anyway since+// the latter part of the code only needs a congruence for the k-digit+// result, not strict modular reduction (the doublings will maintain+// the non-strict inequality).++ mov c, xzr+ adds i, xzr, xzr+Lbignum_montifier_mulloop:+ ldr a, [t, i, lsl #3]+ mul l, q, a+ adcs l, l, c+ umulh c, q, a+ str l, [z, i, lsl #3]+ add i, i, #1+ sub a, i, k+ cbnz a, Lbignum_montifier_mulloop++ adc c, c, xzr+ mov a, #0x4000000000000000+ subs c, c, a+ csetm q, cs++// Now do [c] * n - d for our final answer++ subs i, xzr, xzr+Lbignum_montifier_remloop:+ ldr a, [t, i, lsl #3]+ ldr b, [z, i, lsl #3]+ and a, a, q+ sbcs a, a, b+ str a, [z, i, lsl #3]+ add i, i, #1+ sub a, i, k+ cbnz a, Lbignum_montifier_remloop++// Now still need to do a couple of modular doublings to get us all the+// way up to 2^{p+64} == r from the initial 2^{p+62} == r (mod n).++ mov c, xzr+ subs j, xzr, xzr+Lbignum_montifier_dubloop1:+ ldr a, [z, j, lsl #3]+ extr c, a, c, #63+ ldr b, [t, j, lsl #3]+ sbcs c, c, b+ str c, [z, j, lsl #3]+ mov c, a+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_dubloop1+ lsr c, c, #63+ sbc c, c, xzr+ adds j, xzr, xzr+Lbignum_montifier_corrloop1:+ ldr a, [z, j, lsl #3]+ ldr b, [t, j, lsl #3]+ and b, b, c+ adcs a, a, b+ str a, [z, j, lsl #3]+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_corrloop1++// This is not exactly the same: we also copy output to t giving the+// initialization t_1 = r == 2^{p+64} mod n for the main loop next.++ mov c, xzr+ subs j, xzr, xzr+Lbignum_montifier_dubloop2:+ ldr a, [z, j, lsl #3]+ extr c, a, c, #63+ ldr b, [t, j, lsl #3]+ sbcs c, c, b+ str c, [z, j, lsl #3]+ mov c, a+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_dubloop2+ lsr c, c, #63+ sbc c, c, xzr+ adds j, xzr, xzr+Lbignum_montifier_corrloop2:+ ldr a, [z, j, lsl #3]+ ldr b, [t, j, lsl #3]+ and b, b, c+ adcs a, a, b+ str a, [z, j, lsl #3]+ str a, [t, j, lsl #3]+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_corrloop2++// We then successively generate (k+1)-digit values satisfying+// t_i == 2^{p+64*i} mod n, each of which is stored in h::t. Finish+// initialization by zeroing h initially++ mov h, xzr++// Then if t_i = 2^{p} * h + l+// we have t_{i+1} == 2^64 * t_i+// = (2^{p+64} * h) + (2^64 * l)+// == r * h + l<<64+// Do this 2*k more times so we end up == 2^{192*k+64}, one more than we want+//+// Writing B = 2^{64k}, the possible correction of adding r, which for+// a (k+1)-digit result is equivalent to subtracting q = 2^{64*(k+1)} - r+// would give the overall worst-case value minus q of+// [ B * (B^k - 1) + (B - 1) * r ] - [B^{k+1} - r]+// = B * (r - 1) < B^{k+1} so we keep inside k+1 digits as required.+//+// This implementation makes the shift implicit by starting b with the+// "previous" digit (initially 0) to offset things by 1.++ add i, k, k+Lbignum_montifier_modloop:+ mov j, xzr+ mov b, xzr+ adds c, xzr, xzr+Lbignum_montifier_cmaloop:+ ldr a, [z, j, lsl #3]+ mul l, h, a+ adcs b, b, c+ umulh c, h, a+ adc c, c, xzr+ adds l, b, l+ ldr b, [t, j, lsl #3]+ str l, [t, j, lsl #3]+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_cmaloop++ adcs h, b, c++ csetm l, cs++ adds j, xzr, xzr+Lbignum_montifier_oaloop:+ ldr a, [t, j, lsl #3]+ ldr b, [z, j, lsl #3]+ and b, b, l+ adcs a, a, b+ str a, [t, j, lsl #3]+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_oaloop+ adc h, h, xzr++ subs i, i, #1+ bne Lbignum_montifier_modloop++// Compute the negated modular inverse w (same register as i, not used again).++ ldr a, [m]+ lsl w, a, #2+ sub w, a, w+ eor w, w, #2+ mov l, #1+ madd c, a, w, l+ mul b, c, c+ madd w, c, w, w+ mul c, b, b+ madd w, b, w, w+ mul b, c, c+ madd w, c, w, w+ madd w, b, w, w++// Now do one almost-Montgomery reduction w.r.t. the original m+// which lops off one 2^64 from the congruence and, with the usual+// almost-Montgomery correction, gets us back inside k digits for+// the end result.++ ldr b, [t]+ mul d, b, w++ mul l, d, a+ umulh c, d, a+ mov j, #1+ sub a, k, #1+ adds xzr, b, l+ cbz a, Lbignum_montifier_amontend++Lbignum_montifier_amontloop:+ ldr a, [m, j, lsl #3]+ ldr b, [t, j, lsl #3]+ mul l, d, a+ adcs b, b, c+ umulh c, d, a+ adc c, c, xzr+ adds b, b, l+ sub a, j, #1+ str b, [t, a, lsl #3]+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_amontloop+Lbignum_montifier_amontend:+ adcs h, h, c+ csetm l, cs+ sub a, k, #1+ str h, [t, a, lsl #3]++ subs j, xzr, xzr+Lbignum_montifier_osloop:+ ldr a, [t, j, lsl #3]+ ldr b, [m, j, lsl #3]+ and b, b, l+ sbcs a, a, b+ str a, [z, j, lsl #3]+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_osloop++// So far, the code(basically a variant of bignum_amontifier) has produced+// a k-digit value z == 2^{192k} (mod m), not necessarily fully reduced mod m.+// We now do a short Montgomery reduction (similar to bignum_demont) so that+// we achieve full reduction mod m while lopping 2^{64k} off the congruence.+// We recycle h as the somewhat strangely-named outer loop counter.++ mov h, k++Lbignum_montifier_montouterloop:+ ldr b, [z]+ mul d, b, w+ ldr a, [m]+ mul l, d, a+ umulh c, d, a+ mov j, #1+ sub a, k, #1+ adds xzr, b, l+ cbz a, Lbignum_montifier_montend+Lbignum_montifier_montloop:+ ldr a, [m, j, lsl #3]+ ldr b, [z, j, lsl #3]+ mul l, d, a+ adcs b, b, c+ umulh c, d, a+ adc c, c, xzr+ adds b, b, l+ sub a, j, #1+ str b, [z, a, lsl #3]+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_montloop+Lbignum_montifier_montend:+ adc c, c, xzr+ sub a, k, #1+ str c, [z, a, lsl #3]++ subs h, h, #1+ bne Lbignum_montifier_montouterloop++// Now do a comparison of z with m to set a final correction mask+// indicating that z >= m and so we need to subtract m.++ subs j, xzr, xzr+Lbignum_montifier_cmploop:+ ldr a, [z, j, lsl #3]+ ldr b, [m, j, lsl #3]+ sbcs xzr, a, b+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_cmploop+ csetm h, cs++// Now do a masked subtraction of m for the final reduced result.++ subs j, xzr, xzr+Lbignum_montifier_corrloop:+ ldr a, [z, j, lsl #3]+ ldr b, [m, j, lsl #3]+ and b, b, h+ sbcs a, a, b+ str a, [z, j, lsl #3]+ add j, j, #1+ sub a, j, k+ cbnz a, Lbignum_montifier_corrloop++Lbignum_montifier_end:+ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_montifier)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,1493 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Montgomery inverse modulo p_384 = 2^384 - 2^128 - 2^96 + 2^32 - 1+// Input x[6]; output z[6]+//+// extern void bignum_montinv_p384(uint64_t z[static 6],+// const uint64_t x[static 6]);+//+// If the 6-digit input x is coprime to p_384, i.e. is not divisible+// by it, returns z < p_384 such that x * z == 2^768 (mod p_384). This+// is effectively "Montgomery inverse" because if we consider x and z as+// Montgomery forms of X and Z, i.e. x == 2^384 * X and z == 2^384 * Z+// (both mod p_384) then X * Z == 1 (mod p_384). That is, this function+// gives the analog of the modular inverse bignum_inv_p384 but with both+// input and output in the Montgomery domain. Note that x does not need+// to be reduced modulo p_384, but the output always is. If the input+// is divisible (i.e. is 0 or p_384), then there can be no solution to+// the congruence x * z == 2^768 (mod p_384), and z = 0 is returned.+//+// Standard ARM ABI: X0 = z, X1 = x+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_montinv_p384)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_montinv_p384)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_montinv_p384)++ .text+ .balign 4++// Size in bytes of a 64-bit word++#define N 8++// Used for the return pointer++#define res x20++// Loop counter and d = 2 * delta value for divstep++#define i x21+#define d x22++// Registers used for matrix element magnitudes and signs++#define m00 x10+#define m01 x11+#define m10 x12+#define m11 x13+#define s00 x14+#define s01 x15+#define s10 x16+#define s11 x17++// Initial carries for combinations++#define car0 x9+#define car1 x19++// Input and output, plain registers treated according to pattern++#define reg0 x0, #0+#define reg1 x1, #0+#define reg2 x2, #0+#define reg3 x3, #0+#define reg4 x4, #0++#define x x1, #0+#define z x0, #0++// Pointer-offset pairs for temporaries on stack+// The u and v variables are 6 words each as expected, but the f and g+// variables are 8 words each -- they need to have at least one extra+// word for a sign word, and to preserve alignment we "round up" to 8.+// In fact, we currently keep an extra word in u and v as well.++#define f sp, #0+#define g sp, #(8*N)+#define u sp, #(16*N)+#define v sp, #(24*N)++// Total size to reserve on the stack++#define NSPACE 32*N++// ---------------------------------------------------------------------------+// Core signed almost-Montgomery reduction macro. Takes input in+// [d6;d5;d4;d3;d2;d1;d0] and returns result in [d6;d5d4;d3;d2;d1], adding+// to the existing [d6;d5;d4;d3;d2;d1], and re-using d0 as a temporary+// internally as well as t0, t1, t2. This is almost-Montgomery, i.e. the+// result fits in 6 digits but is not necessarily strictly reduced mod p_384.+// ---------------------------------------------------------------------------++#define amontred(d6,d5,d4,d3,d2,d1,d0, t3,t2,t1) \+/* We only know the input is -2^444 < x < 2^444. To do traditional */ \+/* unsigned Montgomery reduction, start by adding 2^61 * p_384. */ \+ mov t1, #0xe000000000000000 __LF \+ adds d0, d0, t1 __LF \+ mov t2, #0x000000001fffffff __LF \+ adcs d1, d1, t2 __LF \+ mov t3, #0xffffffffe0000000 __LF \+ bic t3, t3, #0x2000000000000000 __LF \+ adcs d2, d2, t3 __LF \+ sbcs d3, d3, xzr __LF \+ sbcs d4, d4, xzr __LF \+ sbcs d5, d5, xzr __LF \+ mov t1, #0x1fffffffffffffff __LF \+ adc d6, d6, t1 __LF \+/* Our correction multiplier is w = [d0 + (d0<<32)] mod 2^64 */ \+/* Store it back into d0 since we no longer need that digit. */ \+ add d0, d0, d0, lsl #32 __LF \+/* Now let [t3;t2;t1;-] = (2^384 - p_384) * w */ \+/* We know the lowest word will cancel d0 so we don't need it */ \+ mov t1, #0xffffffff00000001 __LF \+ umulh t1, t1, d0 __LF \+ mov t2, #0x00000000ffffffff __LF \+ mul t3, t2, d0 __LF \+ umulh t2, t2, d0 __LF \+ adds t1, t1, t3 __LF \+ adcs t2, t2, d0 __LF \+ cset t3, cs __LF \+/* Now x + p_384 * w = (x + 2^384 * w) - (2^384 - p_384) * w */ \+/* We catch the net top carry from add-subtract in the digit d0 */ \+ adds d6, d6, d0 __LF \+ cset d0, cs __LF \+ subs d1, d1, t1 __LF \+ sbcs d2, d2, t2 __LF \+ sbcs d3, d3, t3 __LF \+ sbcs d4, d4, xzr __LF \+ sbcs d5, d5, xzr __LF \+ sbcs d6, d6, xzr __LF \+ sbcs d0, d0, xzr __LF \+/* Now if d0 is nonzero we subtract p_384 (almost-Montgomery) */ \+ neg d0, d0 __LF \+ and t1, d0, #0x00000000ffffffff __LF \+ and t2, d0, #0xffffffff00000000 __LF \+ and t3, d0, #0xfffffffffffffffe __LF \+ subs d1, d1, t1 __LF \+ sbcs d2, d2, t2 __LF \+ sbcs d3, d3, t3 __LF \+ sbcs d4, d4, d0 __LF \+ sbcs d5, d5, d0 __LF \+ sbc d6, d6, d0++// Very similar to a subroutine call to the s2n-bignum word_divstep59.+// But different in register usage and returning the final matrix in+// registers as follows+//+// [ m00 m01]+// [ m10 m11]++#define divstep59() \+ and x4, x2, #0xfffff __LF \+ orr x4, x4, #0xfffffe0000000000 __LF \+ and x5, x3, #0xfffff __LF \+ orr x5, x5, #0xc000000000000000 __LF \+ tst x5, #0x1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ asr x5, x5, #1 __LF \+ add x8, x4, #0x100, lsl #12 __LF \+ sbfx x8, x8, #21, #21 __LF \+ mov x11, #0x100000 __LF \+ add x11, x11, x11, lsl #21 __LF \+ add x9, x4, x11 __LF \+ asr x9, x9, #42 __LF \+ add x10, x5, #0x100, lsl #12 __LF \+ sbfx x10, x10, #21, #21 __LF \+ add x11, x5, x11 __LF \+ asr x11, x11, #42 __LF \+ mul x6, x8, x2 __LF \+ mul x7, x9, x3 __LF \+ mul x2, x10, x2 __LF \+ mul x3, x11, x3 __LF \+ add x4, x6, x7 __LF \+ add x5, x2, x3 __LF \+ asr x2, x4, #20 __LF \+ asr x3, x5, #20 __LF \+ and x4, x2, #0xfffff __LF \+ orr x4, x4, #0xfffffe0000000000 __LF \+ and x5, x3, #0xfffff __LF \+ orr x5, x5, #0xc000000000000000 __LF \+ tst x5, #0x1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ asr x5, x5, #1 __LF \+ add x12, x4, #0x100, lsl #12 __LF \+ sbfx x12, x12, #21, #21 __LF \+ mov x15, #0x100000 __LF \+ add x15, x15, x15, lsl #21 __LF \+ add x13, x4, x15 __LF \+ asr x13, x13, #42 __LF \+ add x14, x5, #0x100, lsl #12 __LF \+ sbfx x14, x14, #21, #21 __LF \+ add x15, x5, x15 __LF \+ asr x15, x15, #42 __LF \+ mul x6, x12, x2 __LF \+ mul x7, x13, x3 __LF \+ mul x2, x14, x2 __LF \+ mul x3, x15, x3 __LF \+ add x4, x6, x7 __LF \+ add x5, x2, x3 __LF \+ asr x2, x4, #20 __LF \+ asr x3, x5, #20 __LF \+ and x4, x2, #0xfffff __LF \+ orr x4, x4, #0xfffffe0000000000 __LF \+ and x5, x3, #0xfffff __LF \+ orr x5, x5, #0xc000000000000000 __LF \+ tst x5, #0x1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ mul x2, x12, x8 __LF \+ mul x3, x12, x9 __LF \+ mul x6, x14, x8 __LF \+ mul x7, x14, x9 __LF \+ madd x8, x13, x10, x2 __LF \+ madd x9, x13, x11, x3 __LF \+ madd x16, x15, x10, x6 __LF \+ madd x17, x15, x11, x7 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ tst x5, #0x2 __LF \+ asr x5, x5, #1 __LF \+ csel x6, x4, xzr, ne __LF \+ ccmp x1, xzr, #0x8, ne __LF \+ cneg x1, x1, ge __LF \+ cneg x6, x6, ge __LF \+ csel x4, x5, x4, ge __LF \+ add x5, x5, x6 __LF \+ add x1, x1, #0x2 __LF \+ asr x5, x5, #1 __LF \+ add x12, x4, #0x100, lsl #12 __LF \+ sbfx x12, x12, #22, #21 __LF \+ mov x15, #0x100000 __LF \+ add x15, x15, x15, lsl #21 __LF \+ add x13, x4, x15 __LF \+ asr x13, x13, #43 __LF \+ add x14, x5, #0x100, lsl #12 __LF \+ sbfx x14, x14, #22, #21 __LF \+ add x15, x5, x15 __LF \+ asr x15, x15, #43 __LF \+ mneg x2, x12, x8 __LF \+ mneg x3, x12, x9 __LF \+ mneg x4, x14, x8 __LF \+ mneg x5, x14, x9 __LF \+ msub m00, x13, x16, x2 __LF \+ msub m01, x13, x17, x3 __LF \+ msub m10, x15, x16, x4 __LF \+ msub m11, x15, x17, x5++S2N_BN_SYMBOL(bignum_montinv_p384):+ CFI_START++// Save registers and make room for temporaries++ CFI_PUSH2(x19,x20)+ CFI_PUSH2(x21,x22)+ CFI_PUSH2(x23,x24)+ CFI_DEC_SP(NSPACE)++// Save the return pointer for the end so we can overwrite x0 later++ mov res, x0++// Copy the prime and input into the main f and g variables respectively.+// Make sure x is reduced so that g <= f as assumed in the bound proof.++ mov x10, #0x00000000ffffffff+ mov x11, #0xffffffff00000000+ mov x12, #0xfffffffffffffffe+ mov x15, #0xffffffffffffffff+ stp x10, x11, [f]+ stp x12, x15, [f+2*N]+ stp x15, x15, [f+4*N]+ str xzr, [f+6*N]++ ldp x2, x3, [x1]+ subs x10, x2, x10+ sbcs x11, x3, x11+ ldp x4, x5, [x1, #(2*N)]+ sbcs x12, x4, x12+ sbcs x13, x5, x15+ ldp x6, x7, [x1, #(4*N)]+ sbcs x14, x6, x15+ sbcs x15, x7, x15++ csel x2, x2, x10, cc+ csel x3, x3, x11, cc+ csel x4, x4, x12, cc+ csel x5, x5, x13, cc+ csel x6, x6, x14, cc+ csel x7, x7, x15, cc++ stp x2, x3, [g]+ stp x4, x5, [g+2*N]+ stp x6, x7, [g+4*N]+ str xzr, [g+6*N]++// Also maintain reduced < 2^384 vector [u,v] such that+// [f,g] == x * 2^{5*i-843} * [u,v] (mod p_384)+// starting with [p_384,x] == x * 2^{5*0-843} * [0,2^843] (mod p_384)+// The weird-looking 5*i modifications come in because we are doing+// 64-bit word-sized Montgomery reductions at each stage, which is+// 5 bits more than the 59-bit requirement to keep things stable.+// After the 15th and last iteration and sign adjustment, when+// f == 1 for in-scope cases, we have x * 2^{75-843} * u == 1, i.e.+// x * u == 2^768 as required.++ stp xzr, xzr, [u]+ stp xzr, xzr, [u+2*N]+ stp xzr, xzr, [u+4*N]++// The starting constant 2^843 mod p_384 is+// 0x0000000000000800:00001000000007ff:fffff00000000000+// :00001000000007ff:fffff00000000800:0000000000000000+// where colons separate 64-bit subwords, least significant at the right.+// Not all of these are single loads on ARM so this is a bit dynamic++ mov x12, #0xfffff00000000000+ orr x10, x12, #0x0000000000000800+ stp xzr, x10, [v]+ mov x11, #0x00000000000007ff+ orr x11, x11, #0x0000100000000000+ stp x11, x12, [v+2*N]+ mov x12, #0x0000000000000800+ stp x11, x12, [v+4*N]++// Start of main loop. We jump into the middle so that the divstep+// portion is common to the special fifteenth iteration after a uniform+// first 14.++ mov i, #15+ mov d, #1+ b Lbignum_montinv_p384_midloop++Lbignum_montinv_p384_loop:++// Separate the matrix elements into sign-magnitude pairs++ cmp m00, xzr+ csetm s00, mi+ cneg m00, m00, mi++ cmp m01, xzr+ csetm s01, mi+ cneg m01, m01, mi++ cmp m10, xzr+ csetm s10, mi+ cneg m10, m10, mi++ cmp m11, xzr+ csetm s11, mi+ cneg m11, m11, mi++// Adjust the initial values to allow for complement instead of negation+// This initial offset is the same for [f,g] and [u,v] compositions.+// Save it in stable registers for the [u,v] part and do [f,g] first.++ and x0, m00, s00+ and x1, m01, s01+ add car0, x0, x1++ and x0, m10, s10+ and x1, m11, s11+ add car1, x0, x1++// Now the computation of the updated f and g values. This maintains a+// 2-word carry between stages so we can conveniently insert the shift+// right by 59 before storing back, and not overwrite digits we need+// again of the old f and g values.+//+// Digit 0 of [f,g]++ ldr x7, [f]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, car0, x0+ adc x2, xzr, x1+ ldr x8, [g]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ adc x2, x2, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x5, car1, x0+ adc x3, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x5, x5, x0+ adc x3, x3, x1++// Digit 1 of [f,g]++ ldr x7, [f+N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x2, x2, x0+ adc x6, xzr, x1+ ldr x8, [g+N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x2, x2, x0+ adc x6, x6, x1+ extr x4, x2, x4, #59+ str x4, [f]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x3, x3, x0+ adc x4, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x3, x3, x0+ adc x4, x4, x1+ extr x5, x3, x5, #59+ str x5, [g]++// Digit 2 of [f,g]++ ldr x7, [f+2*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x6, x6, x0+ adc x5, xzr, x1+ ldr x8, [g+2*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x6, x6, x0+ adc x5, x5, x1+ extr x2, x6, x2, #59+ str x2, [f+N]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x4, x4, x0+ adc x2, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x4, x4, x0+ adc x2, x2, x1+ extr x3, x4, x3, #59+ str x3, [g+N]++// Digit 3 of [f,g]++ ldr x7, [f+3*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x5, x5, x0+ adc x3, xzr, x1+ ldr x8, [g+3*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x5, x5, x0+ adc x3, x3, x1+ extr x6, x5, x6, #59+ str x6, [f+2*N]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x2, x2, x0+ adc x6, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x2, x2, x0+ adc x6, x6, x1+ extr x4, x2, x4, #59+ str x4, [g+2*N]++// Digit 4 of [f,g]++ ldr x7, [f+4*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x3, x3, x0+ adc x4, xzr, x1+ ldr x8, [g+4*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x3, x3, x0+ adc x4, x4, x1+ extr x5, x3, x5, #59+ str x5, [f+3*N]++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x6, x6, x0+ adc x5, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x6, x6, x0+ adc x5, x5, x1+ extr x2, x6, x2, #59+ str x2, [g+3*N]++// Digits 5 and 6 of [f,g]++ ldr x7, [f+5*N]+ eor x1, x7, s00+ ldr x23, [f+6*N]+ eor x2, x23, s00+ and x2, x2, m00+ neg x2, x2+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, x4, x0+ adc x2, x2, x1+ ldr x8, [g+5*N]+ eor x1, x8, s01+ ldr x24, [g+6*N]+ eor x0, x24, s01+ and x0, x0, m01+ sub x2, x2, x0+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ adc x2, x2, x1+ extr x3, x4, x3, #59+ str x3, [f+4*N]+ extr x4, x2, x4, #59+ str x4, [f+5*N]+ asr x2, x2, #59+ str x2, [f+6*N]++ eor x1, x7, s10+ eor x4, x23, s10+ and x4, x4, m10+ neg x4, x4+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x5, x5, x0+ adc x4, x4, x1+ eor x1, x8, s11+ eor x0, x24, s11+ and x0, x0, m11+ sub x4, x4, x0+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x5, x5, x0+ adc x4, x4, x1+ extr x6, x5, x6, #59+ str x6, [g+4*N]+ extr x5, x4, x5, #59+ str x5, [g+5*N]+ asr x4, x4, #59+ str x4, [g+6*N]++// Now the computation of the updated u and v values and their+// Montgomery reductions. A very similar accumulation except that+// the top words of u and v are unsigned and we don't shift.+//+// Digit 0 of [u,v]++ ldr x7, [u]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, car0, x0+ adc x2, xzr, x1+ ldr x8, [v]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ str x4, [u]+ adc x2, x2, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x5, car1, x0+ adc x3, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x5, x5, x0+ str x5, [v]+ adc x3, x3, x1++// Digit 1 of [u,v]++ ldr x7, [u+N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x2, x2, x0+ adc x6, xzr, x1+ ldr x8, [v+N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x2, x2, x0+ str x2, [u+N]+ adc x6, x6, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x3, x3, x0+ adc x4, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x3, x3, x0+ str x3, [v+N]+ adc x4, x4, x1++// Digit 2 of [u,v]++ ldr x7, [u+2*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x6, x6, x0+ adc x5, xzr, x1+ ldr x8, [v+2*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x6, x6, x0+ str x6, [u+2*N]+ adc x5, x5, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x4, x4, x0+ adc x2, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x4, x4, x0+ str x4, [v+2*N]+ adc x2, x2, x1++// Digit 3 of [u,v]++ ldr x7, [u+3*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x5, x5, x0+ adc x3, xzr, x1+ ldr x8, [v+3*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x5, x5, x0+ str x5, [u+3*N]+ adc x3, x3, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x2, x2, x0+ adc x6, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x2, x2, x0+ str x2, [v+3*N]+ adc x6, x6, x1++// Digit 4 of [u,v]++ ldr x7, [u+4*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x3, x3, x0+ adc x4, xzr, x1+ ldr x8, [v+4*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x3, x3, x0+ str x3, [u+4*N]+ adc x4, x4, x1++ eor x1, x7, s10+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x6, x6, x0+ adc x5, xzr, x1+ eor x1, x8, s11+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x6, x6, x0+ str x6, [v+4*N]+ adc x5, x5, x1++// Digits 5 and 6 of [u,v] (top is unsigned)++ ldr x7, [u+5*N]+ eor x1, x7, s00+ and x2, s00, m00+ neg x2, x2+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, x4, x0+ adc x2, x2, x1+ ldr x8, [v+5*N]+ eor x1, x8, s01+ and x0, s01, m01+ sub x2, x2, x0+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ str x4, [u+5*N]+ adc x2, x2, x1+ str x2, [u+6*N]++ eor x1, x7, s10+ and x4, s10, m10+ neg x4, x4+ mul x0, x1, m10+ umulh x1, x1, m10+ adds x5, x5, x0+ adc x4, x4, x1+ eor x1, x8, s11+ and x0, s11, m11+ sub x4, x4, x0+ mul x0, x1, m11+ umulh x1, x1, m11+ adds x5, x5, x0+ str x5, [v+5*N]+ adc x4, x4, x1+ str x4, [v+6*N]++// Montgomery reduction of u++ ldp x0, x1, [u]+ ldp x2, x3, [u+16]+ ldp x4, x5, [u+32]+ ldr x6, [u+48]+ amontred(x6,x5,x4,x3,x2,x1,x0, x9,x8,x7)+ stp x1, x2, [u]+ stp x3, x4, [u+16]+ stp x5, x6, [u+32]++// Montgomery reduction of v++ ldp x0, x1, [v]+ ldp x2, x3, [v+16]+ ldp x4, x5, [v+32]+ ldr x6, [v+48]+ amontred(x6,x5,x4,x3,x2,x1,x0, x9,x8,x7)+ stp x1, x2, [v]+ stp x3, x4, [v+16]+ stp x5, x6, [v+32]++Lbignum_montinv_p384_midloop:++ mov x1, d+ ldr x2, [f]+ ldr x3, [g]+ divstep59()+ mov d, x1++// Next iteration++ subs i, i, #1+ bne Lbignum_montinv_p384_loop++// The 15th and last iteration does not need anything except the+// u value and the sign of f; the latter can be obtained from the+// lowest word of f. So it's done differently from the main loop.+// Find the sign of the new f. For this we just need one digit+// since we know (for in-scope cases) that f is either +1 or -1.+// We don't explicitly shift right by 59 either, but looking at+// bit 63 (or any bit >= 60) of the unshifted result is enough+// to distinguish -1 from +1; this is then made into a mask.++ ldr x0, [f]+ ldr x1, [g]+ mul x0, x0, m00+ madd x1, x1, m01, x0+ asr x0, x1, #63++// Now separate out the matrix into sign-magnitude pairs+// and adjust each one based on the sign of f.+//+// Note that at this point we expect |f|=1 and we got its+// sign above, so then since [f,0] == x * 2^{-768} [u,v] (mod p_384)+// we want to flip the sign of u according to that of f.++ cmp m00, xzr+ csetm s00, mi+ cneg m00, m00, mi+ eor s00, s00, x0++ cmp m01, xzr+ csetm s01, mi+ cneg m01, m01, mi+ eor s01, s01, x0++ cmp m10, xzr+ csetm s10, mi+ cneg m10, m10, mi+ eor s10, s10, x0++ cmp m11, xzr+ csetm s11, mi+ cneg m11, m11, mi+ eor s11, s11, x0++// Adjust the initial value to allow for complement instead of negation++ and x0, m00, s00+ and x1, m01, s01+ add car0, x0, x1++// Digit 0 of [u]++ ldr x7, [u]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, car0, x0+ adc x2, xzr, x1+ ldr x8, [v]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ str x4, [u]+ adc x2, x2, x1++// Digit 1 of [u]++ ldr x7, [u+N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x2, x2, x0+ adc x6, xzr, x1+ ldr x8, [v+N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x2, x2, x0+ str x2, [u+N]+ adc x6, x6, x1++// Digit 2 of [u]++ ldr x7, [u+2*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x6, x6, x0+ adc x5, xzr, x1+ ldr x8, [v+2*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x6, x6, x0+ str x6, [u+2*N]+ adc x5, x5, x1++// Digit 3 of [u]++ ldr x7, [u+3*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x5, x5, x0+ adc x3, xzr, x1+ ldr x8, [v+3*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x5, x5, x0+ str x5, [u+3*N]+ adc x3, x3, x1++// Digit 4 of [u]++ ldr x7, [u+4*N]+ eor x1, x7, s00+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x3, x3, x0+ adc x4, xzr, x1+ ldr x8, [v+4*N]+ eor x1, x8, s01+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x3, x3, x0+ str x3, [u+4*N]+ adc x4, x4, x1++// Digits 5 and 6 of [u] (top is unsigned)++ ldr x7, [u+5*N]+ eor x1, x7, s00+ and x2, s00, m00+ neg x2, x2+ mul x0, x1, m00+ umulh x1, x1, m00+ adds x4, x4, x0+ adc x2, x2, x1+ ldr x8, [v+5*N]+ eor x1, x8, s01+ and x0, s01, m01+ sub x2, x2, x0+ mul x0, x1, m01+ umulh x1, x1, m01+ adds x4, x4, x0+ str x4, [u+5*N]+ adc x2, x2, x1+ str x2, [u+6*N]++// Montgomery reduction of u. This needs to be strict not "almost"+// so it is followed by an optional subtraction of p_384++ ldp x10, x0, [u]+ ldp x1, x2, [u+16]+ ldp x3, x4, [u+32]+ ldr x5, [u+48]+ amontred(x5,x4,x3,x2,x1,x0,x10, x9,x8,x7)++ mov x10, #0x00000000ffffffff+ subs x10, x0, x10+ mov x11, #0xffffffff00000000+ sbcs x11, x1, x11+ mov x12, #0xfffffffffffffffe+ sbcs x12, x2, x12+ mov x15, #0xffffffffffffffff+ sbcs x13, x3, x15+ sbcs x14, x4, x15+ sbcs x15, x5, x15++ csel x0, x0, x10, cc+ csel x1, x1, x11, cc+ csel x2, x2, x12, cc+ csel x3, x3, x13, cc+ csel x4, x4, x14, cc+ csel x5, x5, x15, cc++// Store it back to the final output++ stp x0, x1, [res]+ stp x2, x3, [res, #16]+ stp x4, x5, [res, #32]++// Restore stack and registers++ CFI_INC_SP(NSPACE)+ CFI_POP2(x23,x24)+ CFI_POP2(x21,x22)+ CFI_POP2(x19,x20)+ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_montinv_p384)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack, "", %progbits+#endif
@@ -0,0 +1,891 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Montgomery multiply, z := (x * y / 2^384) mod p_384+// Inputs x[6], y[6]; output z[6]+//+// extern void bignum_montmul_p384(uint64_t z[static 6],+// const uint64_t x[static 6],+// const uint64_t y[static 6]);+//+// Does z := (2^{-384} * x * y) mod p_384, assuming that the inputs x and y+// satisfy x * y <= 2^384 * p_384 (in particular this is true if we are in+// the "usual" case x < p_384 and y < p_384).+//+// Standard ARM ABI: X0 = z, X1 = x, X2 = y+// ----------------------------------------------------------------------------++// bignum_montmul_p384 is functionally equivalent to+// unopt/bignum_montmul_p384_base.+// It is written in a way that+// 1. A subset of scalar multiplications in bignum_montmul_p384 are carefully+// chosen and vectorized+// 2. The vectorized assembly is rescheduled using the SLOTHY superoptimizer.+// https://github.com/slothy-optimizer/slothy+//+// The output program of step 1. is as follows:+//+// stp x19, x20, [sp, #-16]!+// stp x21, x22, [sp, #-16]!+// stp x23, x24, [sp, #-16]!+// ldp x3, x21, [x1]+// ldr q30, [x1]+// ldp x8, x24, [x1, #16]+// ldp x5, x10, [x1, #32]+// ldp x13, x23, [x2]+// ldr q19, [x2]+// ldp x6, x14, [x2, #16]+// ldp x15, x17, [x2, #32]+// ldr q1, [x1, #32]+// ldr q28, [x2, #32]+// uzp1 v5.4S, v19.4S, v30.4S+// rev64 v19.4S, v19.4S+// uzp1 v0.4S, v30.4S, v30.4S+// mul v21.4S, v19.4S, v30.4S+// uaddlp v19.2D, v21.4S+// shl v19.2D, v19.2D, #32+// umlal v19.2D, v0.2S, v5.2S+// mov x12, v19.d[0]+// mov x16, v19.d[1]+// mul x20, x8, x6+// umulh x4, x3, x13+// umulh x1, x21, x23+// umulh x2, x8, x6+// adds x4, x4, x16+// adcs x19, x1, x20+// adc x20, x2, xzr+// adds x11, x4, x12+// adcs x16, x19, x4+// adcs x1, x20, x19+// adc x2, x20, xzr+// adds x7, x16, x12+// adcs x4, x1, x4+// adcs x9, x2, x19+// adc x19, x20, xzr+// subs x2, x3, x21+// cneg x20, x2, cc+// csetm x16, cc+// subs x2, x23, x13+// cneg x2, x2, cc+// mul x1, x20, x2+// umulh x2, x20, x2+// cinv x16, x16, cc+// eor x1, x1, x16+// eor x2, x2, x16+// cmn x16, #0x1+// adcs x11, x11, x1+// adcs x7, x7, x2+// adcs x4, x4, x16+// adcs x9, x9, x16+// adc x19, x19, x16+// subs x2, x3, x8+// cneg x20, x2, cc+// csetm x16, cc+// subs x2, x6, x13+// cneg x2, x2, cc+// mul x1, x20, x2+// umulh x2, x20, x2+// cinv x16, x16, cc+// eor x1, x1, x16+// eor x2, x2, x16+// cmn x16, #0x1+// adcs x7, x7, x1+// adcs x4, x4, x2+// adcs x9, x9, x16+// adc x19, x19, x16+// subs x2, x21, x8+// cneg x20, x2, cc+// csetm x16, cc+// subs x2, x6, x23+// cneg x2, x2, cc+// mul x1, x20, x2+// umulh x2, x20, x2+// cinv x16, x16, cc+// eor x1, x1, x16+// eor x2, x2, x16+// cmn x16, #0x1+// adcs x4, x4, x1+// adcs x20, x9, x2+// adc x16, x19, x16+// lsl x2, x12, #32+// add x19, x2, x12+// lsr x2, x19, #32+// subs x1, x2, x19+// sbc x2, x19, xzr+// extr x1, x2, x1, #32+// lsr x2, x2, #32+// adds x12, x2, x19+// adc x2, xzr, xzr+// subs x1, x11, x1+// sbcs x7, x7, x12+// sbcs x4, x4, x2+// sbcs x20, x20, xzr+// sbcs x16, x16, xzr+// sbc x9, x19, xzr+// lsl x2, x1, #32+// add x19, x2, x1+// lsr x2, x19, #32+// subs x1, x2, x19+// sbc x2, x19, xzr+// extr x1, x2, x1, #32+// lsr x2, x2, #32+// adds x12, x2, x19+// adc x2, xzr, xzr+// subs x1, x7, x1+// sbcs x4, x4, x12+// sbcs x20, x20, x2+// sbcs x16, x16, xzr+// sbcs x7, x9, xzr+// sbc x9, x19, xzr+// lsl x2, x1, #32+// add x19, x2, x1+// lsr x2, x19, #32+// subs x1, x2, x19+// sbc x2, x19, xzr+// extr x12, x2, x1, #32+// lsr x2, x2, #32+// adds x1, x2, x19+// adc x2, xzr, xzr+// subs x4, x4, x12+// sbcs x20, x20, x1+// sbcs x16, x16, x2+// sbcs x12, x7, xzr+// sbcs x1, x9, xzr+// sbc x2, x19, xzr+// stp x4, x20, [x0] // @slothy:writes=buffer0+// stp x16, x12, [x0, #16] // @slothy:writes=buffer16+// stp x1, x2, [x0, #32] // @slothy:writes=buffer32+// mul x22, x24, x14+// movi v31.2D, #0x00000000ffffffff+// uzp2 v16.4S, v28.4S, v28.4S+// xtn v6.2S, v1.2D+// xtn v30.2S, v28.2D+// rev64 v28.4S, v28.4S+// umull v5.2D, v6.2S, v30.2S+// umull v0.2D, v6.2S, v16.2S+// uzp2 v19.4S, v1.4S, v1.4S+// mul v20.4S, v28.4S, v1.4S+// usra v0.2D, v5.2D, #32+// umull v1.2D, v19.2S, v16.2S+// uaddlp v24.2D, v20.4S+// and v5.16B, v0.16B, v31.16B+// umlal v5.2D, v19.2S, v30.2S+// shl v19.2D, v24.2D, #32+// usra v1.2D, v0.2D, #32+// umlal v19.2D, v6.2S, v30.2S+// usra v1.2D, v5.2D, #32+// mov x20, v19.d[0]+// mov x16, v19.d[1]+// umulh x12, x24, x14+// mov x1, v1.d[0]+// mov x2, v1.d[1]+// adds x4, x12, x20+// adcs x20, x1, x16+// adc x16, x2, xzr+// adds x7, x4, x22+// adcs x12, x20, x4+// adcs x1, x16, x20+// adc x2, x16, xzr+// adds x9, x12, x22+// adcs x19, x1, x4+// adcs x4, x2, x20+// adc x20, x16, xzr+// subs x2, x24, x5+// cneg x16, x2, cc+// csetm x12, cc+// subs x2, x15, x14+// cneg x2, x2, cc+// mul x1, x16, x2+// umulh x2, x16, x2+// cinv x12, x12, cc+// eor x1, x1, x12+// eor x2, x2, x12+// cmn x12, #0x1+// adcs x11, x7, x1+// adcs x9, x9, x2+// adcs x19, x19, x12+// adcs x4, x4, x12+// adc x20, x20, x12+// subs x2, x24, x10+// cneg x16, x2, cc+// csetm x12, cc+// subs x2, x17, x14+// cneg x2, x2, cc+// mul x1, x16, x2+// umulh x2, x16, x2+// cinv x12, x12, cc+// eor x1, x1, x12+// eor x2, x2, x12+// cmn x12, #0x1+// adcs x7, x9, x1+// adcs x19, x19, x2+// adcs x4, x4, x12+// adc x20, x20, x12+// subs x2, x5, x10+// cneg x16, x2, cc+// csetm x12, cc+// subs x2, x17, x15+// cneg x2, x2, cc+// mul x1, x16, x2+// umulh x2, x16, x2+// cinv x16, x12, cc+// eor x1, x1, x16+// eor x2, x2, x16+// cmn x16, #0x1+// adcs x19, x19, x1+// adcs x12, x4, x2+// adc x1, x20, x16+// subs x2, x24, x3+// sbcs x24, x5, x21+// sbcs x21, x10, x8+// ngc x5, xzr+// cmn x5, #0x1+// eor x2, x2, x5+// adcs x4, x2, xzr+// eor x2, x24, x5+// adcs x20, x2, xzr+// eor x2, x21, x5+// adc x16, x2, xzr+// subs x2, x13, x14+// sbcs x24, x23, x15+// sbcs x8, x6, x17+// ngc x21, xzr+// cmn x21, #0x1+// eor x2, x2, x21+// adcs x15, x2, xzr+// eor x2, x24, x21+// adcs x14, x2, xzr+// eor x2, x8, x21+// adc x6, x2, xzr+// eor x9, x5, x21+// ldp x21, x2, [x0] // @slothy:reads=buffer0+// adds x10, x22, x21+// adcs x5, x11, x2+// ldp x21, x2, [x0, #16] // @slothy:reads=buffer16+// adcs x24, x7, x21+// adcs x8, x19, x2+// ldp x21, x2, [x0, #32] // @slothy:reads=buffer32+// adcs x21, x12, x21+// adcs x2, x1, x2+// adc x19, xzr, xzr+// stp x10, x5, [x0] // @slothy:writes=buffer0+// stp x24, x8, [x0, #16] // @slothy:writes=buffer16+// stp x21, x2, [x0, #32] // @slothy:writes=buffer32+// mul x12, x4, x15+// mul x5, x20, x14+// mul x24, x16, x6+// umulh x8, x4, x15+// umulh x21, x20, x14+// umulh x2, x16, x6+// adds x10, x8, x5+// adcs x5, x21, x24+// adc x24, x2, xzr+// adds x23, x10, x12+// adcs x8, x5, x10+// adcs x21, x24, x5+// adc x2, x24, xzr+// adds x13, x8, x12+// adcs x1, x21, x10+// adcs x10, x2, x5+// adc x5, x24, xzr+// subs x2, x4, x20+// cneg x24, x2, cc+// csetm x8, cc+// subs x2, x14, x15+// cneg x2, x2, cc+// mul x21, x24, x2+// umulh x2, x24, x2+// cinv x8, x8, cc+// eor x21, x21, x8+// eor x2, x2, x8+// cmn x8, #0x1+// adcs x23, x23, x21+// adcs x13, x13, x2+// adcs x1, x1, x8+// adcs x10, x10, x8+// adc x5, x5, x8+// subs x2, x4, x16+// cneg x24, x2, cc+// csetm x8, cc+// subs x2, x6, x15+// cneg x2, x2, cc+// mul x21, x24, x2+// umulh x2, x24, x2+// cinv x8, x8, cc+// eor x21, x21, x8+// eor x2, x2, x8+// cmn x8, #0x1+// adcs x4, x13, x21+// adcs x13, x1, x2+// adcs x1, x10, x8+// adc x10, x5, x8+// subs x2, x20, x16+// cneg x24, x2, cc+// csetm x8, cc+// subs x2, x6, x14+// cneg x2, x2, cc+// mul x21, x24, x2+// umulh x2, x24, x2+// cinv x5, x8, cc+// eor x21, x21, x5+// eor x2, x2, x5+// cmn x5, #0x1+// adcs x24, x13, x21+// adcs x8, x1, x2+// adc x21, x10, x5+// ldp x20, x16, [x0] // @slothy:reads=buffer0+// ldp x17, x15, [x0, #16] // @slothy:reads=buffer16+// ldp x14, x6, [x0, #32] // @slothy:reads=buffer32+// cmn x9, #0x1+// eor x2, x12, x9+// adcs x12, x2, x20+// eor x2, x23, x9+// adcs x23, x2, x16+// eor x2, x4, x9+// adcs x13, x2, x17+// eor x2, x24, x9+// adcs x10, x2, x15+// eor x2, x8, x9+// adcs x5, x2, x14+// eor x2, x21, x9+// adcs x24, x2, x6+// adcs x1, x9, x19+// adcs x8, x9, xzr+// adcs x21, x9, xzr+// adc x2, x9, xzr+// adds x10, x10, x20+// adcs x5, x5, x16+// adcs x24, x24, x17+// adcs x17, x1, x15+// adcs x15, x8, x14+// adcs x14, x21, x6+// adc x6, x2, x19+// lsl x2, x12, #32+// add x1, x2, x12+// lsr x2, x1, #32+// subs x21, x2, x1+// sbc x2, x1, xzr+// extr x21, x2, x21, #32+// lsr x2, x2, #32+// adds x8, x2, x1+// adc x2, xzr, xzr+// subs x21, x23, x21+// sbcs x23, x13, x8+// sbcs x10, x10, x2+// sbcs x5, x5, xzr+// sbcs x24, x24, xzr+// sbc x13, x1, xzr+// lsl x2, x21, #32+// add x1, x2, x21+// lsr x2, x1, #32+// subs x21, x2, x1+// sbc x2, x1, xzr+// extr x21, x2, x21, #32+// lsr x2, x2, #32+// adds x8, x2, x1+// adc x2, xzr, xzr+// subs x21, x23, x21+// sbcs x10, x10, x8+// sbcs x5, x5, x2+// sbcs x24, x24, xzr+// sbcs x23, x13, xzr+// sbc x13, x1, xzr+// lsl x2, x21, #32+// add x1, x2, x21+// lsr x2, x1, #32+// subs x21, x2, x1+// sbc x2, x1, xzr+// extr x8, x2, x21, #32+// lsr x2, x2, #32+// adds x21, x2, x1+// adc x2, xzr, xzr+// subs x10, x10, x8+// sbcs x5, x5, x21+// sbcs x24, x24, x2+// sbcs x8, x23, xzr+// sbcs x21, x13, xzr+// sbc x2, x1, xzr+// adds x23, x17, x8+// adcs x13, x15, x21+// adcs x1, x14, x2+// adc x2, x6, xzr+// add x8, x2, #0x1+// lsl x2, x8, #32+// subs x21, x8, x2+// sbc x2, x2, xzr+// adds x10, x10, x21+// adcs x5, x5, x2+// adcs x24, x24, x8+// adcs x8, x23, xzr+// adcs x21, x13, xzr+// adcs x13, x1, xzr+// csetm x1, cc+// mov x2, #0xffffffff+// and x2, x2, x1+// adds x10, x10, x2+// eor x2, x2, x1+// adcs x5, x5, x2+// mov x2, #0xfffffffffffffffe+// and x2, x2, x1+// adcs x24, x24, x2+// adcs x8, x8, x1+// adcs x21, x21, x1+// adc x2, x13, x1+// stp x10, x5, [x0] // @slothy:writes=buffer0+// stp x24, x8, [x0, #16] // @slothy:writes=buffer16+// stp x21, x2, [x0, #32] // @slothy:writes=buffer32+// ldp x23, x24, [sp], #16+// ldp x21, x22, [sp], #16+// ldp x19, x20, [sp], #16+// ret+//+// The bash script used for step 2 is as follows:+//+// # Store the assembly instructions except the last 'ret' and+// # callee-register store/loads as, say, 'input.S'.+// export OUTPUTS="[hint_buffer0,hint_buffer16,hint_buffer32]"+// export RESERVED_REGS="[x18,x25,x26,x27,x28,x29,x30,sp,q8,q9,q10,q11,q12,q13,q14,q15,v8,v9,v10,v11,v12,v13,v14,v15]"+// <s2n-bignum>/tools/external/slothy.sh input.S my_out_dir+// # my_out_dir/3.opt.s is the optimized assembly. Its output may differ+// # from this file since the sequence is non-deterministically chosen.+// # Please add 'ret' at the end of the output assembly.+++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_montmul_p384)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_montmul_p384)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_montmul_p384)+ .text+ .balign 4++S2N_BN_SYMBOL(bignum_montmul_p384):+ CFI_START++// Save some registers++ CFI_PUSH2(x19,x20)+ CFI_PUSH2(x21,x22)+ CFI_PUSH2(x23,x24)++ ldr q3, [x1]+ ldr q25, [x2]+ ldp x13, x23, [x2]+ ldp x3, x21, [x1]+ rev64 v23.4S, v25.4S+ uzp1 v17.4S, v25.4S, v3.4S+ umulh x15, x3, x13+ mul v6.4S, v23.4S, v3.4S+ uzp1 v3.4S, v3.4S, v3.4S+ ldr q27, [x2, #32]+ ldp x8, x24, [x1, #16]+ subs x6, x3, x21+ ldr q0, [x1, #32]+ movi v23.2D, #0x00000000ffffffff+ csetm x10, cc+ umulh x19, x21, x23+ rev64 v4.4S, v27.4S+ uzp2 v25.4S, v27.4S, v27.4S+ cneg x4, x6, cc+ subs x7, x23, x13+ xtn v22.2S, v0.2D+ xtn v24.2S, v27.2D+ cneg x20, x7, cc+ ldp x6, x14, [x2, #16]+ mul v27.4S, v4.4S, v0.4S+ uaddlp v20.2D, v6.4S+ cinv x5, x10, cc+ mul x16, x4, x20+ uzp2 v6.4S, v0.4S, v0.4S+ umull v21.2D, v22.2S, v25.2S+ shl v0.2D, v20.2D, #32+ umlal v0.2D, v3.2S, v17.2S+ mul x22, x8, x6+ umull v1.2D, v6.2S, v25.2S+ subs x12, x3, x8+ umull v20.2D, v22.2S, v24.2S+ cneg x17, x12, cc+ umulh x9, x8, x6+ mov x12, v0.d[1]+ eor x11, x16, x5+ mov x7, v0.d[0]+ csetm x10, cc+ usra v21.2D, v20.2D, #32+ adds x15, x15, x12+ adcs x12, x19, x22+ umulh x20, x4, x20+ adc x19, x9, xzr+ usra v1.2D, v21.2D, #32+ adds x22, x15, x7+ and v26.16B, v21.16B, v23.16B+ adcs x16, x12, x15+ uaddlp v25.2D, v27.4S+ adcs x9, x19, x12+ umlal v26.2D, v6.2S, v24.2S+ adc x4, x19, xzr+ adds x16, x16, x7+ shl v27.2D, v25.2D, #32+ adcs x9, x9, x15+ adcs x4, x4, x12+ eor x12, x20, x5+ adc x15, x19, xzr+ subs x20, x6, x13+ cneg x20, x20, cc+ cinv x10, x10, cc+ cmn x5, #0x1+ mul x19, x17, x20+ adcs x11, x22, x11+ adcs x12, x16, x12+ adcs x9, x9, x5+ umulh x17, x17, x20+ adcs x22, x4, x5+ adc x5, x15, x5+ subs x16, x21, x8+ cneg x20, x16, cc+ eor x19, x19, x10+ csetm x4, cc+ subs x16, x6, x23+ cneg x16, x16, cc+ umlal v27.2D, v22.2S, v24.2S+ mul x15, x20, x16+ cinv x4, x4, cc+ cmn x10, #0x1+ usra v1.2D, v26.2D, #32+ adcs x19, x12, x19+ eor x17, x17, x10+ adcs x9, x9, x17+ adcs x22, x22, x10+ lsl x12, x7, #32+ umulh x20, x20, x16+ eor x16, x15, x4+ ldp x15, x17, [x2, #32]+ add x2, x12, x7+ adc x7, x5, x10+ ldp x5, x10, [x1, #32]+ lsr x1, x2, #32+ eor x12, x20, x4+ subs x1, x1, x2+ sbc x20, x2, xzr+ cmn x4, #0x1+ adcs x9, x9, x16+ extr x1, x20, x1, #32+ lsr x20, x20, #32+ adcs x22, x22, x12+ adc x16, x7, x4+ adds x12, x20, x2+ umulh x7, x24, x14+ adc x4, xzr, xzr+ subs x1, x11, x1+ sbcs x20, x19, x12+ sbcs x12, x9, x4+ lsl x9, x1, #32+ add x1, x9, x1+ sbcs x9, x22, xzr+ mul x22, x24, x14+ sbcs x16, x16, xzr+ lsr x4, x1, #32+ sbc x19, x2, xzr+ subs x4, x4, x1+ sbc x11, x1, xzr+ extr x2, x11, x4, #32+ lsr x4, x11, #32+ adds x4, x4, x1+ adc x11, xzr, xzr+ subs x2, x20, x2+ sbcs x4, x12, x4+ sbcs x20, x9, x11+ lsl x12, x2, #32+ add x2, x12, x2+ sbcs x9, x16, xzr+ lsr x11, x2, #32+ sbcs x19, x19, xzr+ sbc x1, x1, xzr+ subs x16, x11, x2+ sbc x12, x2, xzr+ extr x16, x12, x16, #32+ lsr x12, x12, #32+ adds x11, x12, x2+ adc x12, xzr, xzr+ subs x16, x4, x16+ mov x4, v27.d[0]+ sbcs x11, x20, x11+ sbcs x20, x9, x12+ stp x16, x11, [x0]+ sbcs x11, x19, xzr+ sbcs x9, x1, xzr+ stp x20, x11, [x0, #16]+ mov x1, v1.d[0]+ sbc x20, x2, xzr+ subs x12, x24, x5+ mov x11, v27.d[1]+ cneg x16, x12, cc+ csetm x2, cc+ subs x19, x15, x14+ mov x12, v1.d[1]+ cinv x2, x2, cc+ cneg x19, x19, cc+ stp x9, x20, [x0, #32]+ mul x9, x16, x19+ adds x4, x7, x4+ adcs x11, x1, x11+ adc x1, x12, xzr+ adds x20, x4, x22+ umulh x19, x16, x19+ adcs x7, x11, x4+ eor x16, x9, x2+ adcs x9, x1, x11+ adc x12, x1, xzr+ adds x7, x7, x22+ adcs x4, x9, x4+ adcs x9, x12, x11+ adc x12, x1, xzr+ cmn x2, #0x1+ eor x1, x19, x2+ adcs x11, x20, x16+ adcs x19, x7, x1+ adcs x1, x4, x2+ adcs x20, x9, x2+ adc x2, x12, x2+ subs x12, x24, x10+ cneg x16, x12, cc+ csetm x12, cc+ subs x9, x17, x14+ cinv x12, x12, cc+ cneg x9, x9, cc+ subs x3, x24, x3+ sbcs x21, x5, x21+ mul x24, x16, x9+ sbcs x4, x10, x8+ ngc x8, xzr+ subs x10, x5, x10+ eor x5, x24, x12+ csetm x7, cc+ cneg x24, x10, cc+ subs x10, x17, x15+ cinv x7, x7, cc+ cneg x10, x10, cc+ subs x14, x13, x14+ sbcs x15, x23, x15+ eor x13, x21, x8+ mul x23, x24, x10+ sbcs x17, x6, x17+ eor x6, x3, x8+ ngc x21, xzr+ umulh x9, x16, x9+ cmn x8, #0x1+ eor x3, x23, x7+ adcs x23, x6, xzr+ adcs x13, x13, xzr+ eor x16, x4, x8+ adc x16, x16, xzr+ eor x4, x17, x21+ umulh x17, x24, x10+ cmn x21, #0x1+ eor x24, x14, x21+ eor x6, x15, x21+ adcs x15, x24, xzr+ adcs x14, x6, xzr+ adc x6, x4, xzr+ cmn x12, #0x1+ eor x4, x9, x12+ adcs x19, x19, x5+ umulh x5, x23, x15+ adcs x1, x1, x4+ adcs x10, x20, x12+ eor x4, x17, x7+ ldp x20, x9, [x0]+ adc x2, x2, x12+ cmn x7, #0x1+ adcs x12, x1, x3+ ldp x17, x24, [x0, #16]+ mul x1, x16, x6+ adcs x3, x10, x4+ adc x2, x2, x7+ ldp x7, x4, [x0, #32]+ adds x20, x22, x20+ mul x10, x13, x14+ adcs x11, x11, x9+ eor x9, x8, x21+ adcs x21, x19, x17+ stp x20, x11, [x0]+ adcs x12, x12, x24+ mul x8, x23, x15+ adcs x3, x3, x7+ stp x21, x12, [x0, #16]+ adcs x12, x2, x4+ adc x19, xzr, xzr+ subs x21, x23, x16+ umulh x2, x16, x6+ stp x3, x12, [x0, #32]+ cneg x3, x21, cc+ csetm x24, cc+ umulh x11, x13, x14+ subs x21, x13, x16+ eor x7, x8, x9+ cneg x17, x21, cc+ csetm x16, cc+ subs x21, x6, x15+ cneg x22, x21, cc+ cinv x21, x24, cc+ subs x20, x23, x13+ umulh x12, x3, x22+ cneg x23, x20, cc+ csetm x24, cc+ subs x20, x14, x15+ cinv x24, x24, cc+ mul x22, x3, x22+ cneg x3, x20, cc+ subs x13, x6, x14+ cneg x20, x13, cc+ cinv x15, x16, cc+ adds x13, x5, x10+ mul x4, x23, x3+ adcs x11, x11, x1+ adc x14, x2, xzr+ adds x5, x13, x8+ adcs x16, x11, x13+ umulh x23, x23, x3+ adcs x3, x14, x11+ adc x1, x14, xzr+ adds x10, x16, x8+ adcs x6, x3, x13+ adcs x8, x1, x11+ umulh x13, x17, x20+ eor x1, x4, x24+ adc x4, x14, xzr+ cmn x24, #0x1+ adcs x1, x5, x1+ eor x16, x23, x24+ eor x11, x1, x9+ adcs x23, x10, x16+ eor x2, x22, x21+ adcs x3, x6, x24+ mul x14, x17, x20+ eor x17, x13, x15+ adcs x13, x8, x24+ adc x8, x4, x24+ cmn x21, #0x1+ adcs x6, x23, x2+ mov x16, #0xfffffffffffffffe+ eor x20, x12, x21+ adcs x20, x3, x20+ eor x23, x14, x15+ adcs x2, x13, x21+ adc x8, x8, x21+ cmn x15, #0x1+ ldp x5, x4, [x0]+ ldp x21, x12, [x0, #16]+ adcs x22, x20, x23+ eor x23, x22, x9+ adcs x17, x2, x17+ adc x22, x8, x15+ cmn x9, #0x1+ adcs x15, x7, x5+ ldp x10, x14, [x0, #32]+ eor x1, x6, x9+ lsl x2, x15, #32+ adcs x8, x11, x4+ adcs x13, x1, x21+ eor x1, x22, x9+ adcs x24, x23, x12+ eor x11, x17, x9+ adcs x23, x11, x10+ adcs x7, x1, x14+ adcs x17, x9, x19+ adcs x20, x9, xzr+ add x1, x2, x15+ lsr x3, x1, #32+ adcs x11, x9, xzr+ adc x9, x9, xzr+ subs x3, x3, x1+ sbc x6, x1, xzr+ adds x24, x24, x5+ adcs x4, x23, x4+ extr x3, x6, x3, #32+ lsr x6, x6, #32+ adcs x21, x7, x21+ adcs x15, x17, x12+ adcs x7, x20, x10+ adcs x20, x11, x14+ mov x14, #0xffffffff+ adc x22, x9, x19+ adds x12, x6, x1+ adc x10, xzr, xzr+ subs x3, x8, x3+ sbcs x12, x13, x12+ lsl x9, x3, #32+ add x3, x9, x3+ sbcs x10, x24, x10+ sbcs x24, x4, xzr+ lsr x9, x3, #32+ sbcs x21, x21, xzr+ sbc x1, x1, xzr+ subs x9, x9, x3+ sbc x13, x3, xzr+ extr x9, x13, x9, #32+ lsr x13, x13, #32+ adds x13, x13, x3+ adc x6, xzr, xzr+ subs x12, x12, x9+ sbcs x17, x10, x13+ lsl x2, x12, #32+ sbcs x10, x24, x6+ add x9, x2, x12+ sbcs x6, x21, xzr+ lsr x5, x9, #32+ sbcs x21, x1, xzr+ sbc x13, x3, xzr+ subs x8, x5, x9+ sbc x19, x9, xzr+ lsr x12, x19, #32+ extr x3, x19, x8, #32+ adds x8, x12, x9+ adc x1, xzr, xzr+ subs x2, x17, x3+ sbcs x12, x10, x8+ sbcs x5, x6, x1+ sbcs x3, x21, xzr+ sbcs x19, x13, xzr+ sbc x24, x9, xzr+ adds x23, x15, x3+ adcs x8, x7, x19+ adcs x11, x20, x24+ adc x9, x22, xzr+ add x24, x9, #0x1+ lsl x7, x24, #32+ subs x21, x24, x7+ sbc x10, x7, xzr+ adds x6, x2, x21+ adcs x7, x12, x10+ adcs x24, x5, x24+ adcs x13, x23, xzr+ adcs x8, x8, xzr+ adcs x15, x11, xzr+ csetm x23, cc+ and x11, x16, x23+ and x20, x14, x23+ adds x22, x6, x20+ eor x3, x20, x23+ adcs x5, x7, x3+ adcs x14, x24, x11+ stp x22, x5, [x0]+ adcs x5, x13, x23+ adcs x21, x8, x23+ stp x14, x5, [x0, #16]+ adc x12, x15, x23+ stp x21, x12, [x0, #32]++// Restore registers and return++ CFI_POP2(x23,x24)+ CFI_POP2(x21,x22)+ CFI_POP2(x19,x20)++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_montmul_p384)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,345 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Montgomery multiply, z := (x * y / 2^384) mod p_384+// Inputs x[6], y[6]; output z[6]+//+// extern void bignum_montmul_p384_alt(uint64_t z[static 6],+// const uint64_t x[static 6],+// const uint64_t y[static 6]);+//+// Does z := (2^{-384} * x * y) mod p_384, assuming that the inputs x and y+// satisfy x * y <= 2^384 * p_384 (in particular this is true if we are in+// the "usual" case x < p_384 and y < p_384).+//+// Standard ARM ABI: X0 = z, X1 = x, X2 = y+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_montmul_p384_alt)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_montmul_p384_alt)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_montmul_p384_alt)+ .text+ .balign 4++// ---------------------------------------------------------------------------+// Core one-step "short" Montgomery reduction macro. Takes input in+// [d5;d4;d3;d2;d1;d0] and returns result in [d6;d5;d4;d3;d2;d1],+// adding to the existing contents of [d5;d4;d3;d2;d1]. It is fine+// for d6 to be the same register as d0.+//+// We want to add (2^384 - 2^128 - 2^96 + 2^32 - 1) * w+// where w = [d0 + (d0<<32)] mod 2^64+// ---------------------------------------------------------------------------++#define montreds(d6,d5,d4,d3,d2,d1,d0, t3,t2,t1) \+/* Our correction multiplier is w = [d0 + (d0<<32)] mod 2^64 */ \+/* Store it in d6 to make the 2^384 * w contribution already */ \+ lsl t1, d0, #32 __LF \+ add d6, t1, d0 __LF \+/* Now let [t3;t2;t1;-] = (2^384 - p_384) * w */ \+/* We know the lowest word will cancel d0 so we don't need it */ \+ mov t1, #0xffffffff00000001 __LF \+ umulh t1, t1, d6 __LF \+ mov t2, #0x00000000ffffffff __LF \+ mul t3, t2, d6 __LF \+ umulh t2, t2, d6 __LF \+ adds t1, t1, t3 __LF \+ adcs t2, t2, d6 __LF \+ adc t3, xzr, xzr __LF \+/* Now add it, by subtracting from 2^384 * w + x */ \+ subs d1, d1, t1 __LF \+ sbcs d2, d2, t2 __LF \+ sbcs d3, d3, t3 __LF \+ sbcs d4, d4, xzr __LF \+ sbcs d5, d5, xzr __LF \+ sbc d6, d6, xzr+++#define z x0+#define x x1+#define y x2++// These are repeated mod 2 as we load pairs of inputs++#define a0 x3+#define a1 x4+#define a2 x3+#define a3 x4+#define a4 x3+#define a5 x4++#define b0 x5+#define b1 x6+#define b2 x7+#define b3 x8+#define b4 x9+#define b5 x10++#define l x11++#define u0 x12+#define u1 x13+#define u2 x14+#define u3 x15+#define u4 x16+#define u5 x17+#define u6 x19+#define u7 x20+#define u8 x21+#define u9 x22+#define u10 x2 // same as y+#define u11 x1 // same as x+#define h b5 // same as b5++S2N_BN_SYMBOL(bignum_montmul_p384_alt):+ CFI_START++// Save more registers++ CFI_PUSH2(x19,x20)+ CFI_PUSH2(x21,x22)++// Load operands and set up row 0 = [u6;...;u0] = a0 * [b5;...;b0]++ ldp a0, a1, [x]+ ldp b0, b1, [y]++ mul u0, a0, b0+ umulh u1, a0, b0+ mul l, a0, b1+ umulh u2, a0, b1+ adds u1, u1, l++ ldp b2, b3, [y, #16]++ mul l, a0, b2+ umulh u3, a0, b2+ adcs u2, u2, l++ mul l, a0, b3+ umulh u4, a0, b3+ adcs u3, u3, l++ ldp b4, b5, [y, #32]++ mul l, a0, b4+ umulh u5, a0, b4+ adcs u4, u4, l++ mul l, a0, b5+ umulh u6, a0, b5+ adcs u5, u5, l++ adc u6, u6, xzr++// Row 1 = [u7;...;u0] = [a1;a0] * [b5;...;b0]++ mul l, a1, b0+ adds u1, u1, l+ mul l, a1, b1+ adcs u2, u2, l+ mul l, a1, b2+ adcs u3, u3, l+ mul l, a1, b3+ adcs u4, u4, l+ mul l, a1, b4+ adcs u5, u5, l+ mul l, a1, b5+ adcs u6, u6, l+ cset u7, cs++ umulh l, a1, b0+ adds u2, u2, l+ umulh l, a1, b1+ adcs u3, u3, l+ umulh l, a1, b2+ adcs u4, u4, l+ umulh l, a1, b3+ adcs u5, u5, l+ umulh l, a1, b4+ adcs u6, u6, l+ umulh l, a1, b5+ adc u7, u7, l++// Row 2 = [u8;...;u0] = [a2;a1;a0] * [b5;...;b0]++ ldp a2, a3, [x, #16]++ mul l, a2, b0+ adds u2, u2, l+ mul l, a2, b1+ adcs u3, u3, l+ mul l, a2, b2+ adcs u4, u4, l+ mul l, a2, b3+ adcs u5, u5, l+ mul l, a2, b4+ adcs u6, u6, l+ mul l, a2, b5+ adcs u7, u7, l+ cset u8, cs++ umulh l, a2, b0+ adds u3, u3, l+ umulh l, a2, b1+ adcs u4, u4, l+ umulh l, a2, b2+ adcs u5, u5, l+ umulh l, a2, b3+ adcs u6, u6, l+ umulh l, a2, b4+ adcs u7, u7, l+ umulh l, a2, b5+ adc u8, u8, l++// Row 3 = [u9;...;u0] = [a3;a2;a1;a0] * [b5;...;b0]++ mul l, a3, b0+ adds u3, u3, l+ mul l, a3, b1+ adcs u4, u4, l+ mul l, a3, b2+ adcs u5, u5, l+ mul l, a3, b3+ adcs u6, u6, l+ mul l, a3, b4+ adcs u7, u7, l+ mul l, a3, b5+ adcs u8, u8, l+ cset u9, cs++ umulh l, a3, b0+ adds u4, u4, l+ umulh l, a3, b1+ adcs u5, u5, l+ umulh l, a3, b2+ adcs u6, u6, l+ umulh l, a3, b3+ adcs u7, u7, l+ umulh l, a3, b4+ adcs u8, u8, l+ umulh l, a3, b5+ adc u9, u9, l++// Row 4 = [u10;...;u0] = [a4;a3;a2;a1;a0] * [b5;...;b0]++ ldp a4, a5, [x, #32]++ mul l, a4, b0+ adds u4, u4, l+ mul l, a4, b1+ adcs u5, u5, l+ mul l, a4, b2+ adcs u6, u6, l+ mul l, a4, b3+ adcs u7, u7, l+ mul l, a4, b4+ adcs u8, u8, l+ mul l, a4, b5+ adcs u9, u9, l+ cset u10, cs++ umulh l, a4, b0+ adds u5, u5, l+ umulh l, a4, b1+ adcs u6, u6, l+ umulh l, a4, b2+ adcs u7, u7, l+ umulh l, a4, b3+ adcs u8, u8, l+ umulh l, a4, b4+ adcs u9, u9, l+ umulh l, a4, b5+ adc u10, u10, l++// Row 5 = [u11;...;u0] = [a5;a4;a3;a2;a1;a0] * [b5;...;b0]++ mul l, a5, b0+ adds u5, u5, l+ mul l, a5, b1+ adcs u6, u6, l+ mul l, a5, b2+ adcs u7, u7, l+ mul l, a5, b3+ adcs u8, u8, l+ mul l, a5, b4+ adcs u9, u9, l+ mul l, a5, b5+ adcs u10, u10, l+ cset u11, cs++ umulh l, a5, b0+ adds u6, u6, l+ umulh l, a5, b1+ adcs u7, u7, l+ umulh l, a5, b2+ adcs u8, u8, l+ umulh l, a5, b3+ adcs u9, u9, l+ umulh l, a5, b4+ adcs u10, u10, l+ umulh l, a5, b5+ adc u11, u11, l++// Montgomery rotate the low half++ montreds(u0,u5,u4,u3,u2,u1,u0, b0,b1,b2)+ montreds(u1,u0,u5,u4,u3,u2,u1, b0,b1,b2)+ montreds(u2,u1,u0,u5,u4,u3,u2, b0,b1,b2)+ montreds(u3,u2,u1,u0,u5,u4,u3, b0,b1,b2)+ montreds(u4,u3,u2,u1,u0,u5,u4, b0,b1,b2)+ montreds(u5,u4,u3,u2,u1,u0,u5, b0,b1,b2)++// Add up the high and low parts as [h; u5;u4;u3;u2;u1;u0] = z++ adds u0, u0, u6+ adcs u1, u1, u7+ adcs u2, u2, u8+ adcs u3, u3, u9+ adcs u4, u4, u10+ adcs u5, u5, u11+ adc h, xzr, xzr++// Now add [h; u11;u10;u9;u8;u7;u6] = z + (2^384 - p_384)++ mov l, #0xffffffff00000001+ adds u6, u0, l+ mov l, #0x00000000ffffffff+ adcs u7, u1, l+ mov l, #0x0000000000000001+ adcs u8, u2, l+ adcs u9, u3, xzr+ adcs u10, u4, xzr+ adcs u11, u5, xzr+ adcs h, h, xzr++// Now z >= p_384 iff h is nonzero, so select accordingly++ csel u0, u0, u6, eq+ csel u1, u1, u7, eq+ csel u2, u2, u8, eq+ csel u3, u3, u9, eq+ csel u4, u4, u10, eq+ csel u5, u5, u11, eq++// Store back final result++ stp u0, u1, [z]+ stp u2, u3, [z, #16]+ stp u4, u5, [z, #32]++// Restore registers++ CFI_POP2(x21,x22)+ CFI_POP2(x19,x20)++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_montmul_p384_alt)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,671 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Montgomery square, z := (x^2 / 2^384) mod p_384+// Input x[6]; output z[6]+//+// extern void bignum_montsqr_p384(uint64_t z[static 6],+// const uint64_t x[static 6]);+//+// Does z := (x^2 / 2^384) mod p_384, assuming x^2 <= 2^384 * p_384, which is+// guaranteed in particular if x < p_384 initially (the "intended" case).+//+// Standard ARM ABI: X0 = z, X1 = x+// ----------------------------------------------------------------------------++// bignum_montsqr_p384 is functionally equivalent to+// unopt/bignum_montsqr_p384_base.+// It is written in a way that+// 1. A subset of scalar multiplications in bignum_montsqr_p384 are carefully+// chosen and vectorized+// 2. The vectorized assembly is rescheduled using the SLOTHY superoptimizer.+// https://github.com/slothy-optimizer/slothy+//+// The output program of step 1. is as follows:+//+// ldp x9, x2, [x1]+// ldr q18, [x1]+// ldr q19, [x1]+// ldp x4, x6, [x1, #16]+// ldp x5, x10, [x1, #32]+// ldr q21, [x1, #32]+// ldr q28, [x1, #32]+// mul x12, x9, x2+// mul x1, x9, x4+// mul x13, x2, x4+// movi v0.2D, #0x00000000ffffffff+// uzp2 v5.4S, v19.4S, v19.4S+// xtn v25.2S, v18.2D+// xtn v4.2S, v19.2D+// rev64 v23.4S, v19.4S+// umull v20.2D, v25.2S, v4.2S+// umull v30.2D, v25.2S, v5.2S+// uzp2 v19.4S, v18.4S, v18.4S+// mul v22.4S, v23.4S, v18.4S+// usra v30.2D, v20.2D, #32+// umull v18.2D, v19.2S, v5.2S+// uaddlp v22.2D, v22.4S+// and v20.16B, v30.16B, v0.16B+// umlal v20.2D, v19.2S, v4.2S+// shl v19.2D, v22.2D, #32+// usra v18.2D, v30.2D, #32+// umlal v19.2D, v25.2S, v4.2S+// usra v18.2D, v20.2D, #32+// mov x7, v19.d[0]+// mov x17, v19.d[1]+// mul x16, x4, x4+// umulh x3, x9, x2+// adds x15, x1, x3+// umulh x1, x9, x4+// adcs x13, x13, x1+// umulh x1, x2, x4+// adcs x8, x1, xzr+// mov x11, v18.d[0]+// mov x14, v18.d[1]+// umulh x1, x4, x4+// adds x3, x12, x12+// adcs x15, x15, x15+// adcs x13, x13, x13+// adcs x12, x8, x8+// adc x1, x1, xzr+// adds x11, x11, x3+// adcs x3, x17, x15+// adcs x17, x14, x13+// adcs x15, x16, x12+// adc x13, x1, xzr+// lsl x1, x7, #32+// add x16, x1, x7+// lsr x1, x16, #32+// subs x12, x1, x16+// sbc x1, x16, xzr+// extr x12, x1, x12, #32+// lsr x1, x1, #32+// adds x7, x1, x16+// adc x1, xzr, xzr+// subs x12, x11, x12+// sbcs x11, x3, x7+// sbcs x17, x17, x1+// sbcs x15, x15, xzr+// sbcs x13, x13, xzr+// sbc x3, x16, xzr+// lsl x1, x12, #32+// add x16, x1, x12+// lsr x1, x16, #32+// subs x12, x1, x16+// sbc x1, x16, xzr+// extr x12, x1, x12, #32+// lsr x1, x1, #32+// adds x7, x1, x16+// adc x1, xzr, xzr+// subs x12, x11, x12+// sbcs x17, x17, x7+// sbcs x15, x15, x1+// sbcs x13, x13, xzr+// sbcs x11, x3, xzr+// sbc x3, x16, xzr+// lsl x1, x12, #32+// add x16, x1, x12+// lsr x1, x16, #32+// subs x12, x1, x16+// sbc x1, x16, xzr+// extr x7, x1, x12, #32+// lsr x1, x1, #32+// adds x12, x1, x16+// adc x1, xzr, xzr+// subs x17, x17, x7+// sbcs x15, x15, x12+// sbcs x13, x13, x1+// sbcs x7, x11, xzr+// sbcs x12, x3, xzr+// sbc x1, x16, xzr+// stp x17, x15, [x0] // @slothy:writes=buffer0+// stp x13, x7, [x0, #16] // @slothy:writes=buffer16+// stp x12, x1, [x0, #32] // @slothy:writes=buffer32+// mul x14, x9, x6+// mul x15, x2, x5+// mul x13, x4, x10+// umulh x7, x9, x6+// umulh x12, x2, x5+// umulh x1, x4, x10+// adds x15, x7, x15+// adcs x16, x12, x13+// adc x13, x1, xzr+// adds x11, x15, x14+// adcs x7, x16, x15+// adcs x12, x13, x16+// adc x1, x13, xzr+// adds x17, x7, x14+// adcs x15, x12, x15+// adcs x3, x1, x16+// adc x16, x13, xzr+// subs x1, x9, x2+// cneg x13, x1, cc+// csetm x7, cc+// subs x1, x5, x6+// cneg x1, x1, cc+// mul x12, x13, x1+// umulh x1, x13, x1+// cinv x7, x7, cc+// eor x12, x12, x7+// eor x1, x1, x7+// cmn x7, #0x1+// adcs x11, x11, x12+// adcs x17, x17, x1+// adcs x15, x15, x7+// adcs x3, x3, x7+// adc x16, x16, x7+// subs x9, x9, x4+// cneg x13, x9, cc+// csetm x7, cc+// subs x1, x10, x6+// cneg x1, x1, cc+// mul x12, x13, x1+// umulh x1, x13, x1+// cinv x7, x7, cc+// eor x12, x12, x7+// eor x1, x1, x7+// cmn x7, #0x1+// adcs x17, x17, x12+// adcs x15, x15, x1+// adcs x13, x3, x7+// adc x7, x16, x7+// subs x2, x2, x4+// cneg x12, x2, cc+// csetm x1, cc+// subs x2, x10, x5+// cneg x2, x2, cc+// mul x4, x12, x2+// umulh x2, x12, x2+// cinv x1, x1, cc+// eor x4, x4, x1+// eor x2, x2, x1+// cmn x1, #0x1+// adcs x12, x15, x4+// adcs x4, x13, x2+// adc x2, x7, x1+// adds x1, x14, x14+// adcs x16, x11, x11+// adcs x17, x17, x17+// adcs x15, x12, x12+// adcs x13, x4, x4+// adcs x7, x2, x2+// adc x12, xzr, xzr+// ldp x4, x2, [x0] // @slothy:reads=buffer0+// adds x1, x1, x4+// adcs x16, x16, x2+// ldp x4, x2, [x0, #16] // @slothy:reads=buffer16+// adcs x17, x17, x4+// adcs x15, x15, x2+// ldp x4, x2, [x0, #32] // @slothy:reads=buffer32+// adcs x13, x13, x4+// adcs x7, x7, x2+// adc x11, x12, xzr+// lsl x2, x1, #32+// add x12, x2, x1+// lsr x2, x12, #32+// subs x4, x2, x12+// sbc x2, x12, xzr+// extr x4, x2, x4, #32+// lsr x2, x2, #32+// adds x1, x2, x12+// adc x2, xzr, xzr+// subs x4, x16, x4+// sbcs x16, x17, x1+// sbcs x17, x15, x2+// sbcs x15, x13, xzr+// sbcs x13, x7, xzr+// sbc x7, x12, xzr+// lsl x2, x4, #32+// add x12, x2, x4+// lsr x2, x12, #32+// subs x4, x2, x12+// sbc x2, x12, xzr+// extr x4, x2, x4, #32+// lsr x2, x2, #32+// adds x1, x2, x12+// adc x2, xzr, xzr+// subs x4, x16, x4+// sbcs x16, x17, x1+// sbcs x17, x15, x2+// sbcs x15, x13, xzr+// sbcs x13, x7, xzr+// sbc x7, x12, xzr+// lsl x2, x4, #32+// add x12, x2, x4+// lsr x2, x12, #32+// subs x4, x2, x12+// sbc x2, x12, xzr+// extr x1, x2, x4, #32+// lsr x2, x2, #32+// adds x4, x2, x12+// adc x2, xzr, xzr+// subs x3, x16, x1+// sbcs x17, x17, x4+// sbcs x15, x15, x2+// sbcs x1, x13, xzr+// sbcs x4, x7, xzr+// sbc x2, x12, xzr+// adds x13, x11, x1+// adcs x7, x4, xzr+// adcs x12, x2, xzr+// adcs x16, xzr, xzr+// mul x2, x6, x6+// adds x3, x3, x2+// xtn v30.2S, v28.2D+// shrn v26.2S, v28.2D, #32+// umull v26.2D, v30.2S, v26.2S+// shl v19.2D, v26.2D, #33+// umlal v19.2D, v30.2S, v30.2S+// mov x1, v19.d[0]+// mov x4, v19.d[1]+// umulh x2, x6, x6+// adcs x17, x17, x2+// umulh x2, x5, x5+// adcs x15, x15, x1+// adcs x13, x13, x2+// umulh x2, x10, x10+// adcs x7, x7, x4+// adcs x12, x12, x2+// adc x16, x16, xzr+// dup v28.2D, x6+// movi v0.2D, #0x00000000ffffffff+// uzp2 v5.4S, v21.4S, v21.4S+// xtn v25.2S, v28.2D+// xtn v4.2S, v21.2D+// rev64 v19.4S, v21.4S+// umull v30.2D, v25.2S, v4.2S+// umull v23.2D, v25.2S, v5.2S+// uzp2 v20.4S, v28.4S, v28.4S+// mul v19.4S, v19.4S, v28.4S+// usra v23.2D, v30.2D, #32+// umull v18.2D, v20.2S, v5.2S+// uaddlp v19.2D, v19.4S+// and v30.16B, v23.16B, v0.16B+// umlal v30.2D, v20.2S, v4.2S+// shl v19.2D, v19.2D, #32+// usra v18.2D, v23.2D, #32+// umlal v19.2D, v25.2S, v4.2S+// usra v18.2D, v30.2D, #32+// mov x6, v19.d[0]+// mov x1, v19.d[1]+// mul x4, x5, x10+// mov x2, v18.d[0]+// adds x1, x1, x2+// mov x2, v18.d[1]+// adcs x4, x4, x2+// umulh x5, x5, x10+// adc x2, x5, xzr+// adds x5, x6, x6+// adcs x6, x1, x1+// adcs x1, x4, x4+// adcs x4, x2, x2+// adc x2, xzr, xzr+// adds x17, x17, x5+// adcs x15, x15, x6+// adcs x13, x13, x1+// adcs x7, x7, x4+// adcs x12, x12, x2+// adc x2, x16, xzr+// mov x5, #0xffffffff00000001+// mov x6, #0xffffffff+// mov x1, #0x1+// cmn x3, x5+// adcs xzr, x17, x6+// adcs xzr, x15, x1+// adcs xzr, x13, xzr+// adcs xzr, x7, xzr+// adcs xzr, x12, xzr+// adc x2, x2, xzr+// neg x4, x2+// and x2, x5, x4+// adds x10, x3, x2+// and x2, x6, x4+// adcs x5, x17, x2+// and x2, x1, x4+// adcs x6, x15, x2+// adcs x1, x13, xzr+// adcs x4, x7, xzr+// adc x2, x12, xzr+// stp x10, x5, [x0] // @slothy:writes=buffer0+// stp x6, x1, [x0, #16] // @slothy:writes=buffer16+// stp x4, x2, [x0, #32] // @slothy:writes=buffer32+// ret+//+// The bash script used for step 2 is as follows:+//+// # Store the assembly instructions except the last 'ret' as, say, 'input.S'.+// export OUTPUTS="[hint_buffer0,hint_buffer16,hint_buffer32]"+// export RESERVED_REGS="[x18,x19,x20,x21,x22,x23,x24,x25,x26,x27,x28,x29,x30,sp,q8,q9,q10,q11,q12,q13,q14,q15,v8,v9,v10,v11,v12,v13,v14,v15]"+// <s2n-bignum>/tools/external/slothy.sh input.S my_out_dir+// # my_out_dir/3.opt.s is the optimized assembly. Its output may differ+// # from this file since the sequence is non-deterministically chosen.+// # Please add 'ret' at the end of the output assembly.++++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_montsqr_p384)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_montsqr_p384)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_montsqr_p384)+ .text+ .balign 4++S2N_BN_SYMBOL(bignum_montsqr_p384):+ CFI_START++ ldr q1, [x1]+ ldp x9, x2, [x1]+ ldr q0, [x1]+ ldp x4, x6, [x1, #16]+ rev64 v21.4S, v1.4S+ uzp2 v28.4S, v1.4S, v1.4S+ umulh x7, x9, x2+ xtn v17.2S, v1.2D+ mul v27.4S, v21.4S, v0.4S+ ldr q20, [x1, #32]+ xtn v30.2S, v0.2D+ ldr q1, [x1, #32]+ uzp2 v31.4S, v0.4S, v0.4S+ ldp x5, x10, [x1, #32]+ umulh x8, x9, x4+ uaddlp v3.2D, v27.4S+ umull v16.2D, v30.2S, v17.2S+ mul x16, x9, x4+ umull v27.2D, v30.2S, v28.2S+ shrn v0.2S, v20.2D, #32+ xtn v7.2S, v20.2D+ shl v20.2D, v3.2D, #32+ umull v3.2D, v31.2S, v28.2S+ mul x3, x2, x4+ umlal v20.2D, v30.2S, v17.2S+ umull v22.2D, v7.2S, v0.2S+ usra v27.2D, v16.2D, #32+ umulh x11, x2, x4+ movi v21.2D, #0x00000000ffffffff+ uzp2 v28.4S, v1.4S, v1.4S+ adds x15, x16, x7+ and v5.16B, v27.16B, v21.16B+ adcs x3, x3, x8+ usra v3.2D, v27.2D, #32+ dup v29.2D, x6+ adcs x16, x11, xzr+ mov x14, v20.d[0]+ umlal v5.2D, v31.2S, v17.2S+ mul x8, x9, x2+ mov x7, v20.d[1]+ shl v19.2D, v22.2D, #33+ xtn v25.2S, v29.2D+ rev64 v31.4S, v1.4S+ lsl x13, x14, #32+ uzp2 v6.4S, v29.4S, v29.4S+ umlal v19.2D, v7.2S, v7.2S+ usra v3.2D, v5.2D, #32+ adds x1, x8, x8+ umulh x8, x4, x4+ add x12, x13, x14+ mul v17.4S, v31.4S, v29.4S+ xtn v4.2S, v1.2D+ adcs x14, x15, x15+ lsr x13, x12, #32+ adcs x15, x3, x3+ umull v31.2D, v25.2S, v28.2S+ adcs x11, x16, x16+ umull v21.2D, v25.2S, v4.2S+ mov x17, v3.d[0]+ umull v18.2D, v6.2S, v28.2S+ adc x16, x8, xzr+ uaddlp v16.2D, v17.4S+ movi v1.2D, #0x00000000ffffffff+ subs x13, x13, x12+ usra v31.2D, v21.2D, #32+ sbc x8, x12, xzr+ adds x17, x17, x1+ mul x1, x4, x4+ shl v28.2D, v16.2D, #32+ mov x3, v3.d[1]+ adcs x14, x7, x14+ extr x7, x8, x13, #32+ adcs x13, x3, x15+ and v3.16B, v31.16B, v1.16B+ adcs x11, x1, x11+ lsr x1, x8, #32+ umlal v3.2D, v6.2S, v4.2S+ usra v18.2D, v31.2D, #32+ adc x3, x16, xzr+ adds x1, x1, x12+ umlal v28.2D, v25.2S, v4.2S+ adc x16, xzr, xzr+ subs x15, x17, x7+ sbcs x7, x14, x1+ lsl x1, x15, #32+ sbcs x16, x13, x16+ add x8, x1, x15+ usra v18.2D, v3.2D, #32+ sbcs x14, x11, xzr+ lsr x1, x8, #32+ sbcs x17, x3, xzr+ sbc x11, x12, xzr+ subs x13, x1, x8+ umulh x12, x4, x10+ sbc x1, x8, xzr+ extr x13, x1, x13, #32+ lsr x1, x1, #32+ adds x15, x1, x8+ adc x1, xzr, xzr+ subs x7, x7, x13+ sbcs x13, x16, x15+ lsl x3, x7, #32+ umulh x16, x2, x5+ sbcs x15, x14, x1+ add x7, x3, x7+ sbcs x3, x17, xzr+ lsr x1, x7, #32+ sbcs x14, x11, xzr+ sbc x11, x8, xzr+ subs x8, x1, x7+ sbc x1, x7, xzr+ extr x8, x1, x8, #32+ lsr x1, x1, #32+ adds x1, x1, x7+ adc x17, xzr, xzr+ subs x13, x13, x8+ umulh x8, x9, x6+ sbcs x1, x15, x1+ sbcs x15, x3, x17+ sbcs x3, x14, xzr+ mul x17, x2, x5+ sbcs x11, x11, xzr+ stp x13, x1, [x0] // @slothy:writes=buffer0+ sbc x14, x7, xzr+ mul x7, x4, x10+ subs x1, x9, x2+ stp x15, x3, [x0, #16] // @slothy:writes=buffer16+ csetm x15, cc+ cneg x1, x1, cc+ stp x11, x14, [x0, #32] // @slothy:writes=buffer32+ mul x14, x9, x6+ adds x17, x8, x17+ adcs x7, x16, x7+ adc x13, x12, xzr+ subs x12, x5, x6+ cneg x3, x12, cc+ cinv x16, x15, cc+ mul x8, x1, x3+ umulh x1, x1, x3+ eor x12, x8, x16+ adds x11, x17, x14+ adcs x3, x7, x17+ adcs x15, x13, x7+ adc x8, x13, xzr+ adds x3, x3, x14+ adcs x15, x15, x17+ adcs x17, x8, x7+ eor x1, x1, x16+ adc x13, x13, xzr+ subs x9, x9, x4+ csetm x8, cc+ cneg x9, x9, cc+ subs x4, x2, x4+ cneg x4, x4, cc+ csetm x7, cc+ subs x2, x10, x6+ cinv x8, x8, cc+ cneg x2, x2, cc+ cmn x16, #0x1+ adcs x11, x11, x12+ mul x12, x9, x2+ adcs x3, x3, x1+ adcs x15, x15, x16+ umulh x9, x9, x2+ adcs x17, x17, x16+ adc x13, x13, x16+ subs x1, x10, x5+ cinv x2, x7, cc+ cneg x1, x1, cc+ eor x9, x9, x8+ cmn x8, #0x1+ eor x7, x12, x8+ mul x12, x4, x1+ adcs x3, x3, x7+ adcs x7, x15, x9+ adcs x15, x17, x8+ ldp x9, x17, [x0, #16] // @slothy:reads=buffer16+ umulh x4, x4, x1+ adc x8, x13, x8+ cmn x2, #0x1+ eor x1, x12, x2+ adcs x1, x7, x1+ ldp x7, x16, [x0] // @slothy:reads=buffer0+ eor x12, x4, x2+ adcs x4, x15, x12+ ldp x15, x12, [x0, #32] // @slothy:reads=buffer32+ adc x8, x8, x2+ adds x13, x14, x14+ umulh x14, x5, x10+ adcs x2, x11, x11+ adcs x3, x3, x3+ adcs x1, x1, x1+ adcs x4, x4, x4+ adcs x11, x8, x8+ adc x8, xzr, xzr+ adds x13, x13, x7+ adcs x2, x2, x16+ mul x16, x5, x10+ adcs x3, x3, x9+ adcs x1, x1, x17+ umulh x5, x5, x5+ lsl x9, x13, #32+ add x9, x9, x13+ adcs x4, x4, x15+ mov x13, v28.d[1]+ adcs x15, x11, x12+ lsr x7, x9, #32+ adc x11, x8, xzr+ subs x7, x7, x9+ umulh x10, x10, x10+ sbc x17, x9, xzr+ extr x7, x17, x7, #32+ lsr x17, x17, #32+ adds x17, x17, x9+ adc x12, xzr, xzr+ subs x8, x2, x7+ sbcs x17, x3, x17+ lsl x7, x8, #32+ sbcs x2, x1, x12+ add x3, x7, x8+ sbcs x12, x4, xzr+ lsr x1, x3, #32+ sbcs x7, x15, xzr+ sbc x15, x9, xzr+ subs x1, x1, x3+ sbc x4, x3, xzr+ lsr x9, x4, #32+ extr x8, x4, x1, #32+ adds x9, x9, x3+ adc x4, xzr, xzr+ subs x1, x17, x8+ lsl x17, x1, #32+ sbcs x8, x2, x9+ sbcs x9, x12, x4+ add x17, x17, x1+ mov x1, v18.d[1]+ lsr x2, x17, #32+ sbcs x7, x7, xzr+ mov x12, v18.d[0]+ sbcs x15, x15, xzr+ sbc x3, x3, xzr+ subs x4, x2, x17+ sbc x2, x17, xzr+ adds x12, x13, x12+ adcs x16, x16, x1+ lsr x13, x2, #32+ extr x1, x2, x4, #32+ adc x2, x14, xzr+ adds x4, x13, x17+ mul x13, x6, x6+ adc x14, xzr, xzr+ subs x1, x8, x1+ sbcs x4, x9, x4+ mov x9, v28.d[0]+ sbcs x7, x7, x14+ sbcs x8, x15, xzr+ sbcs x3, x3, xzr+ sbc x14, x17, xzr+ adds x17, x9, x9+ adcs x12, x12, x12+ mov x15, v19.d[0]+ adcs x9, x16, x16+ umulh x6, x6, x6+ adcs x16, x2, x2+ adc x2, xzr, xzr+ adds x11, x11, x8+ adcs x3, x3, xzr+ adcs x14, x14, xzr+ adcs x8, xzr, xzr+ adds x13, x1, x13+ mov x1, v19.d[1]+ adcs x6, x4, x6+ mov x4, #0xffffffff+ adcs x15, x7, x15+ adcs x7, x11, x5+ adcs x1, x3, x1+ adcs x14, x14, x10+ adc x11, x8, xzr+ adds x6, x6, x17+ adcs x8, x15, x12+ adcs x3, x7, x9+ adcs x15, x1, x16+ mov x16, #0xffffffff00000001+ adcs x14, x14, x2+ mov x2, #0x1+ adc x17, x11, xzr+ cmn x13, x16+ adcs xzr, x6, x4+ adcs xzr, x8, x2+ adcs xzr, x3, xzr+ adcs xzr, x15, xzr+ adcs xzr, x14, xzr+ adc x1, x17, xzr+ neg x9, x1+ and x1, x16, x9+ adds x11, x13, x1+ and x13, x4, x9+ adcs x5, x6, x13+ and x1, x2, x9+ adcs x7, x8, x1+ stp x11, x5, [x0] // @slothy:writes=buffer0+ adcs x11, x3, xzr+ adcs x2, x15, xzr+ stp x7, x11, [x0, #16] // @slothy:writes=buffer16+ adc x17, x14, xzr+ stp x2, x17, [x0, #32] // depth 72 // @slothy:writes=buffer32++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_montsqr_p384)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,273 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Montgomery square, z := (x^2 / 2^384) mod p_384+// Input x[6]; output z[6]+//+// extern void bignum_montsqr_p384_alt(uint64_t z[static 6],+// const uint64_t x[static 6]);+//+// Does z := (x^2 / 2^384) mod p_384, assuming x^2 <= 2^384 * p_384, which is+// guaranteed in particular if x < p_384 initially (the "intended" case).+//+// Standard ARM ABI: X0 = z, X1 = x+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_montsqr_p384_alt)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_montsqr_p384_alt)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_montsqr_p384_alt)+ .text+ .balign 4++// ---------------------------------------------------------------------------+// Core one-step "short" Montgomery reduction macro. Takes input in+// [d5;d4;d3;d2;d1;d0] and returns result in [d6;d5;d4;d3;d2;d1],+// adding to the existing contents of [d5;d4;d3;d2;d1]. It is fine+// for d6 to be the same register as d0.+//+// We want to add (2^384 - 2^128 - 2^96 + 2^32 - 1) * w+// where w = [d0 + (d0<<32)] mod 2^64+// ---------------------------------------------------------------------------++#define montreds(d6,d5,d4,d3,d2,d1,d0, t3,t2,t1) \+/* Our correction multiplier is w = [d0 + (d0<<32)] mod 2^64 */ \+/* Store it in d6 to make the 2^384 * w contribution already */ \+ lsl t1, d0, #32 __LF \+ add d6, t1, d0 __LF \+/* Now let [t3;t2;t1;-] = (2^384 - p_384) * w */ \+/* We know the lowest word will cancel d0 so we don't need it */ \+ mov t1, #0xffffffff00000001 __LF \+ umulh t1, t1, d6 __LF \+ mov t2, #0x00000000ffffffff __LF \+ mul t3, t2, d6 __LF \+ umulh t2, t2, d6 __LF \+ adds t1, t1, t3 __LF \+ adcs t2, t2, d6 __LF \+ adc t3, xzr, xzr __LF \+/* Now add it, by subtracting from 2^384 * w + x */ \+ subs d1, d1, t1 __LF \+ sbcs d2, d2, t2 __LF \+ sbcs d3, d3, t3 __LF \+ sbcs d4, d4, xzr __LF \+ sbcs d5, d5, xzr __LF \+ sbc d6, d6, xzr++#define z x0+#define x x1++#define a0 x2+#define a1 x3+#define a2 x4+#define a3 x5+#define a4 x6+#define a5 x7++#define l x8++#define u0 x2 // The same as a0, which is safe+#define u1 x9+#define u2 x10+#define u3 x11+#define u4 x12+#define u5 x13+#define u6 x14+#define u7 x15+#define u8 x16+#define u9 x17+#define u10 x19+#define u11 x20+#define h x6 // same as a4++S2N_BN_SYMBOL(bignum_montsqr_p384_alt):+ CFI_START++// It's convenient to have two more registers to play with++ CFI_PUSH2(x19,x20)++// Load all the elements as [a5;a4;a3;a2;a1;a0], set up an initial+// window [u8;u7; u6;u5; u4;u3; u2;u1] = [34;05;03;01], and then+// chain in the addition of 02 + 12 + 13 + 14 + 15 to that window+// (no carry-out possible since we add it to the top of a product).++ ldp a0, a1, [x]++ mul u1, a0, a1+ umulh u2, a0, a1++ ldp a2, a3, [x, #16]++ mul l, a0, a2+ adds u2, u2, l++ mul u3, a0, a3+ mul l, a1, a2+ adcs u3, u3, l++ umulh u4, a0, a3+ mul l, a1, a3+ adcs u4, u4, l++ ldp a4, a5, [x, #32]++ mul u5, a0, a5+ mul l, a1, a4+ adcs u5, u5, l++ umulh u6, a0, a5+ mul l, a1, a5+ adcs u6, u6, l++ mul u7, a3, a4+ adcs u7, u7, xzr++ umulh u8, a3, a4+ adc u8, u8, xzr++ umulh l, a0, a2+ adds u3, u3, l+ umulh l, a1, a2+ adcs u4, u4, l+ umulh l, a1, a3+ adcs u5, u5, l+ umulh l, a1, a4+ adcs u6, u6, l+ umulh l, a1, a5+ adcs u7, u7, l+ adc u8, u8, xzr++// Now chain in the 04 + 23 + 24 + 25 + 35 + 45 terms++ mul l, a0, a4+ adds u4, u4, l+ mul l, a2, a3+ adcs u5, u5, l+ mul l, a2, a4+ adcs u6, u6, l+ mul l, a2, a5+ adcs u7, u7, l+ mul l, a3, a5+ adcs u8, u8, l+ mul u9, a4, a5+ adcs u9, u9, xzr+ umulh u10, a4, a5+ adc u10, u10, xzr++ umulh l, a0, a4+ adds u5, u5, l+ umulh l, a2, a3+ adcs u6, u6, l+ umulh l, a2, a4+ adcs u7, u7, l+ umulh l, a2, a5+ adcs u8, u8, l+ umulh l, a3, a5+ adcs u9, u9, l+ adc u10, u10, xzr++// Double that, with u11 holding the top carry++ adds u1, u1, u1+ adcs u2, u2, u2+ adcs u3, u3, u3+ adcs u4, u4, u4+ adcs u5, u5, u5+ adcs u6, u6, u6+ adcs u7, u7, u7+ adcs u8, u8, u8+ adcs u9, u9, u9+ adcs u10, u10, u10+ cset u11, cs++// Add the homogeneous terms 00 + 11 + 22 + 33 + 44 + 55++ umulh l, a0, a0+ mul u0, a0, a0+ adds u1, u1, l++ mul l, a1, a1+ adcs u2, u2, l+ umulh l, a1, a1+ adcs u3, u3, l++ mul l, a2, a2+ adcs u4, u4, l+ umulh l, a2, a2+ adcs u5, u5, l++ mul l, a3, a3+ adcs u6, u6, l+ umulh l, a3, a3+ adcs u7, u7, l++ mul l, a4, a4+ adcs u8, u8, l+ umulh l, a4, a4+ adcs u9, u9, l++ mul l, a5, a5+ adcs u10, u10, l+ umulh l, a5, a5+ adc u11, u11, l++// Montgomery rotate the low half++ montreds(u0,u5,u4,u3,u2,u1,u0, a1,a2,a3)+ montreds(u1,u0,u5,u4,u3,u2,u1, a1,a2,a3)+ montreds(u2,u1,u0,u5,u4,u3,u2, a1,a2,a3)+ montreds(u3,u2,u1,u0,u5,u4,u3, a1,a2,a3)+ montreds(u4,u3,u2,u1,u0,u5,u4, a1,a2,a3)+ montreds(u5,u4,u3,u2,u1,u0,u5, a1,a2,a3)++// Add up the high and low parts as [h; u5;u4;u3;u2;u1;u0] = z++ adds u0, u0, u6+ adcs u1, u1, u7+ adcs u2, u2, u8+ adcs u3, u3, u9+ adcs u4, u4, u10+ adcs u5, u5, u11+ adc h, xzr, xzr++// Now add [h; u11;u10;u9;u8;u7;u6] = z + (2^384 - p_384)++ mov l, #0xffffffff00000001+ adds u6, u0, l+ mov l, #0x00000000ffffffff+ adcs u7, u1, l+ mov l, #0x0000000000000001+ adcs u8, u2, l+ adcs u9, u3, xzr+ adcs u10, u4, xzr+ adcs u11, u5, xzr+ adcs h, h, xzr++// Now z >= p_384 iff h is nonzero, so select accordingly++ csel u0, u0, u6, eq+ csel u1, u1, u7, eq+ csel u2, u2, u8, eq+ csel u3, u3, u9, eq+ csel u4, u4, u10, eq+ csel u5, u5, u11, eq++// Store back final result++ stp u0, u1, [z]+ stp u2, u3, [z, #16]+ stp u4, u5, [z, #32]++// Restore registers++ CFI_POP2(x19,x20)++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_montsqr_p384_alt)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,1407 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Multiply modulo p_521, z := (x * y) mod p_521, assuming x and y reduced+// Inputs x[9], y[9]; output z[9]+//+// extern void bignum_mul_p521(uint64_t z[static 9], const uint64_t x[static 9],+// const uint64_t y[static 9]);+//+// Standard ARM ABI: X0 = z, X1 = x, X2 = y+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++// bignum_mul_p521 is functionally equivalent to unopt/bignum_mul_p521_base.+// It is written in a way that+// 1. A subset of scalar multiplications in bignum_montmul_p384 are carefully+// chosen and vectorized+// 2. The vectorized assembly is rescheduled using the SLOTHY superoptimizer.+// https://github.com/slothy-optimizer/slothy+//+// The output program of step 1. is as follows:+//+// stp x19, x20, [sp, #-16]!+// stp x21, x22, [sp, #-16]!+// stp x23, x24, [sp, #-16]!+// stp x25, x26, [sp, #-16]!+// sub sp, sp, #80+// ldp x15, x21, [x1]+// ldp x10, x17, [x1, #16]+// ldp x13, x16, [x2]+// ldr q18, [x1]+// ldr q28, [x2]+// ldp x5, x20, [x2, #16]+// movi v16.2D, #0x00000000ffffffff+// uzp2 v7.4S, v28.4S, v28.4S+// xtn v4.2S, v18.2D+// xtn v1.2S, v28.2D+// rev64 v27.4S, v28.4S+// umull v21.2D, v4.2S, v1.2S+// umull v28.2D, v4.2S, v7.2S+// uzp2 v5.4S, v18.4S, v18.4S+// mul v18.4S, v27.4S, v18.4S+// usra v28.2D, v21.2D, #32+// umull v29.2D, v5.2S, v7.2S+// uaddlp v18.2D, v18.4S+// and v16.16B, v28.16B, v16.16B+// umlal v16.2D, v5.2S, v1.2S+// shl v18.2D, v18.2D, #32+// usra v29.2D, v28.2D, #32+// umlal v18.2D, v4.2S, v1.2S+// usra v29.2D, v16.2D, #32+// mov x8, v18.d[0]+// mov x9, v18.d[1]+// mul x6, x10, x5+// mul x19, x17, x20+// mov x14, v29.d[0]+// adds x9, x9, x14+// mov x14, v29.d[1]+// adcs x6, x6, x14+// umulh x14, x10, x5+// adcs x19, x19, x14+// umulh x14, x17, x20+// adc x14, x14, xzr+// adds x11, x9, x8+// adcs x9, x6, x9+// adcs x6, x19, x6+// adcs x19, x14, x19+// adc x14, xzr, x14+// adds x3, x9, x8+// adcs x24, x6, x11+// adcs x9, x19, x9+// adcs x6, x14, x6+// adcs x19, xzr, x19+// adc x14, xzr, x14+// subs x4, x10, x17+// cneg x4, x4, cc+// csetm x7, cc+// subs x23, x20, x5+// cneg x23, x23, cc+// mul x22, x4, x23+// umulh x4, x4, x23+// cinv x7, x7, cc+// cmn x7, #0x1+// eor x23, x22, x7+// adcs x6, x6, x23+// eor x4, x4, x7+// adcs x19, x19, x4+// adc x14, x14, x7+// subs x4, x15, x21+// cneg x4, x4, cc+// csetm x7, cc+// subs x23, x16, x13+// cneg x23, x23, cc+// mul x22, x4, x23+// umulh x4, x4, x23+// cinv x7, x7, cc+// cmn x7, #0x1+// eor x23, x22, x7+// adcs x11, x11, x23+// eor x4, x4, x7+// adcs x3, x3, x4+// adcs x24, x24, x7+// adcs x9, x9, x7+// adcs x6, x6, x7+// adcs x19, x19, x7+// adc x14, x14, x7+// subs x4, x21, x17+// cneg x4, x4, cc+// csetm x7, cc+// subs x23, x20, x16+// cneg x23, x23, cc+// mul x22, x4, x23+// umulh x4, x4, x23+// cinv x7, x7, cc+// cmn x7, #0x1+// eor x23, x22, x7+// adcs x9, x9, x23+// eor x4, x4, x7+// adcs x6, x6, x4+// adcs x19, x19, x7+// adc x14, x14, x7+// subs x4, x15, x10+// cneg x4, x4, cc+// csetm x7, cc+// subs x23, x5, x13+// cneg x23, x23, cc+// mul x22, x4, x23+// umulh x4, x4, x23+// cinv x7, x7, cc+// cmn x7, #0x1+// eor x23, x22, x7+// adcs x3, x3, x23+// eor x4, x4, x7+// adcs x24, x24, x4+// adcs x9, x9, x7+// adcs x6, x6, x7+// adcs x19, x19, x7+// adc x14, x14, x7+// subs x17, x15, x17+// cneg x17, x17, cc+// csetm x4, cc+// subs x13, x20, x13+// cneg x13, x13, cc+// mul x20, x17, x13+// umulh x17, x17, x13+// cinv x13, x4, cc+// cmn x13, #0x1+// eor x20, x20, x13+// adcs x20, x24, x20+// eor x17, x17, x13+// adcs x17, x9, x17+// adcs x9, x6, x13+// adcs x6, x19, x13+// adc x13, x14, x13+// subs x21, x21, x10+// cneg x21, x21, cc+// csetm x10, cc+// subs x16, x5, x16+// cneg x16, x16, cc+// mul x5, x21, x16+// umulh x21, x21, x16+// cinv x10, x10, cc+// cmn x10, #0x1+// eor x16, x5, x10+// adcs x16, x20, x16+// eor x21, x21, x10+// adcs x21, x17, x21+// adcs x17, x9, x10+// adcs x5, x6, x10+// adc x10, x13, x10+// lsl x13, x8, #9+// extr x20, x11, x8, #55+// extr x8, x3, x11, #55+// extr x9, x16, x3, #55+// lsr x16, x16, #55+// stp x21, x17, [sp] // @slothy:writes=stack0+// stp x5, x10, [sp, #16] // @slothy:writes=stack16+// stp x13, x20, [sp, #32] // @slothy:writes=stack32+// stp x8, x9, [sp, #48] // @slothy:writes=stack48+// str x16, [sp, #64] // @slothy:writes=stack64+// ldp x21, x10, [x1, #32]+// ldp x17, x13, [x1, #48]+// ldp x16, x5, [x2, #32]+// ldr q18, [x1, #32]+// ldr q28, [x2, #32]+// ldp x20, x8, [x2, #48]+// movi v16.2D, #0x00000000ffffffff+// uzp2 v7.4S, v28.4S, v28.4S+// xtn v4.2S, v18.2D+// xtn v1.2S, v28.2D+// rev64 v28.4S, v28.4S+// umull v27.2D, v4.2S, v1.2S+// umull v29.2D, v4.2S, v7.2S+// uzp2 v21.4S, v18.4S, v18.4S+// mul v28.4S, v28.4S, v18.4S+// usra v29.2D, v27.2D, #32+// umull v18.2D, v21.2S, v7.2S+// uaddlp v28.2D, v28.4S+// and v16.16B, v29.16B, v16.16B+// umlal v16.2D, v21.2S, v1.2S+// shl v28.2D, v28.2D, #32+// usra v18.2D, v29.2D, #32+// umlal v28.2D, v4.2S, v1.2S+// usra v18.2D, v16.2D, #32+// mov x9, v28.d[0]+// mov x6, v28.d[1]+// mul x19, x17, x20+// mul x14, x13, x8+// mov x11, v18.d[0]+// adds x6, x6, x11+// mov x11, v18.d[1]+// adcs x19, x19, x11+// umulh x11, x17, x20+// adcs x14, x14, x11+// umulh x11, x13, x8+// adc x11, x11, xzr+// adds x3, x6, x9+// adcs x6, x19, x6+// adcs x19, x14, x19+// adcs x14, x11, x14+// adc x11, xzr, x11+// adds x24, x6, x9+// adcs x4, x19, x3+// adcs x6, x14, x6+// adcs x19, x11, x19+// adcs x14, xzr, x14+// adc x11, xzr, x11+// subs x7, x17, x13+// cneg x7, x7, cc+// csetm x23, cc+// subs x22, x8, x20+// cneg x22, x22, cc+// mul x12, x7, x22+// umulh x7, x7, x22+// cinv x23, x23, cc+// cmn x23, #0x1+// eor x22, x12, x23+// adcs x19, x19, x22+// eor x7, x7, x23+// adcs x14, x14, x7+// adc x11, x11, x23+// subs x7, x21, x10+// cneg x7, x7, cc+// csetm x23, cc+// subs x22, x5, x16+// cneg x22, x22, cc+// mul x12, x7, x22+// umulh x7, x7, x22+// cinv x23, x23, cc+// cmn x23, #0x1+// eor x22, x12, x23+// adcs x3, x3, x22+// eor x7, x7, x23+// adcs x24, x24, x7+// adcs x4, x4, x23+// adcs x6, x6, x23+// adcs x19, x19, x23+// adcs x14, x14, x23+// adc x11, x11, x23+// subs x7, x10, x13+// cneg x7, x7, cc+// csetm x23, cc+// subs x22, x8, x5+// cneg x22, x22, cc+// mul x12, x7, x22+// umulh x7, x7, x22+// cinv x23, x23, cc+// cmn x23, #0x1+// eor x22, x12, x23+// adcs x6, x6, x22+// eor x7, x7, x23+// adcs x19, x19, x7+// adcs x14, x14, x23+// adc x11, x11, x23+// subs x7, x21, x17+// cneg x7, x7, cc+// csetm x23, cc+// subs x22, x20, x16+// cneg x22, x22, cc+// mul x12, x7, x22+// umulh x7, x7, x22+// cinv x23, x23, cc+// cmn x23, #0x1+// eor x22, x12, x23+// adcs x24, x24, x22+// eor x7, x7, x23+// adcs x4, x4, x7+// adcs x6, x6, x23+// adcs x19, x19, x23+// adcs x14, x14, x23+// adc x11, x11, x23+// subs x7, x21, x13+// cneg x7, x7, cc+// csetm x23, cc+// subs x22, x8, x16+// cneg x22, x22, cc+// mul x12, x7, x22+// umulh x7, x7, x22+// cinv x23, x23, cc+// cmn x23, #0x1+// eor x22, x12, x23+// adcs x4, x4, x22+// eor x7, x7, x23+// adcs x6, x6, x7+// adcs x19, x19, x23+// adcs x14, x14, x23+// adc x11, x11, x23+// subs x7, x10, x17+// cneg x7, x7, cc+// csetm x23, cc+// subs x22, x20, x5+// cneg x22, x22, cc+// mul x12, x7, x22+// umulh x7, x7, x22+// cinv x23, x23, cc+// cmn x23, #0x1+// eor x22, x12, x23+// adcs x4, x4, x22+// eor x7, x7, x23+// adcs x6, x6, x7+// adcs x19, x19, x23+// adcs x14, x14, x23+// adc x11, x11, x23+// ldp x7, x23, [sp] // @slothy:reads=stack0+// adds x9, x9, x7+// adcs x3, x3, x23+// stp x9, x3, [sp] // @slothy:writes=stack0+// ldp x9, x3, [sp, #16] // @slothy:reads=stack16+// adcs x9, x24, x9+// adcs x3, x4, x3+// stp x9, x3, [sp, #16] // @slothy:writes=stack16+// ldp x9, x3, [sp, #32] // @slothy:reads=stack32+// adcs x9, x6, x9+// adcs x6, x19, x3+// stp x9, x6, [sp, #32] // @slothy:writes=stack32+// ldp x9, x6, [sp, #48] // @slothy:reads=stack48+// adcs x9, x14, x9+// adcs x6, x11, x6+// stp x9, x6, [sp, #48] // @slothy:writes=stack48+// ldr x9, [sp, #64] // @slothy:reads=stack64+// adc x9, x9, xzr+// str x9, [sp, #64] // @slothy:writes=stack64+// ldp x9, x6, [x1]+// subs x21, x21, x9+// sbcs x10, x10, x6+// ldp x9, x6, [x1, #16]+// sbcs x17, x17, x9+// sbcs x13, x13, x6+// csetm x9, cc+// ldp x6, x19, [x2]+// subs x16, x6, x16+// sbcs x5, x19, x5+// ldp x6, x19, [x2, #16]+// sbcs x20, x6, x20+// sbcs x8, x19, x8+// csetm x6, cc+// eor x21, x21, x9+// subs x21, x21, x9+// eor x10, x10, x9+// sbcs x10, x10, x9+// eor x17, x17, x9+// sbcs x17, x17, x9+// eor x13, x13, x9+// sbc x13, x13, x9+// eor x16, x16, x6+// subs x16, x16, x6+// eor x5, x5, x6+// sbcs x5, x5, x6+// eor x20, x20, x6+// sbcs x20, x20, x6+// eor x8, x8, x6+// sbc x8, x8, x6+// eor x9, x6, x9+// mul x6, x21, x16+// mul x19, x10, x5+// mul x14, x17, x20+// mul x11, x13, x8+// umulh x3, x21, x16+// adds x19, x19, x3+// umulh x3, x10, x5+// adcs x14, x14, x3+// umulh x3, x17, x20+// adcs x11, x11, x3+// umulh x3, x13, x8+// adc x3, x3, xzr+// adds x24, x19, x6+// adcs x19, x14, x19+// adcs x14, x11, x14+// adcs x11, x3, x11+// adc x3, xzr, x3+// adds x4, x19, x6+// adcs x7, x14, x24+// adcs x19, x11, x19+// adcs x14, x3, x14+// adcs x11, xzr, x11+// adc x3, xzr, x3+// subs x23, x17, x13+// cneg x23, x23, cc+// csetm x22, cc+// subs x12, x8, x20+// cneg x12, x12, cc+// mul x15, x23, x12+// umulh x23, x23, x12+// cinv x22, x22, cc+// cmn x22, #0x1+// eor x12, x15, x22+// adcs x14, x14, x12+// eor x23, x23, x22+// adcs x11, x11, x23+// adc x3, x3, x22+// subs x23, x21, x10+// cneg x23, x23, cc+// csetm x22, cc+// subs x12, x5, x16+// cneg x12, x12, cc+// mul x15, x23, x12+// umulh x23, x23, x12+// cinv x22, x22, cc+// cmn x22, #0x1+// eor x12, x15, x22+// adcs x24, x24, x12+// eor x23, x23, x22+// adcs x4, x4, x23+// adcs x7, x7, x22+// adcs x19, x19, x22+// adcs x14, x14, x22+// adcs x11, x11, x22+// adc x3, x3, x22+// subs x23, x10, x13+// cneg x23, x23, cc+// csetm x22, cc+// subs x12, x8, x5+// cneg x12, x12, cc+// mul x15, x23, x12+// umulh x23, x23, x12+// cinv x22, x22, cc+// cmn x22, #0x1+// eor x12, x15, x22+// adcs x19, x19, x12+// eor x23, x23, x22+// adcs x14, x14, x23+// adcs x11, x11, x22+// adc x3, x3, x22+// subs x23, x21, x17+// cneg x23, x23, cc+// csetm x22, cc+// subs x12, x20, x16+// cneg x12, x12, cc+// mul x15, x23, x12+// umulh x23, x23, x12+// cinv x22, x22, cc+// cmn x22, #0x1+// eor x12, x15, x22+// adcs x4, x4, x12+// eor x23, x23, x22+// adcs x7, x7, x23+// adcs x19, x19, x22+// adcs x14, x14, x22+// adcs x11, x11, x22+// adc x3, x3, x22+// subs x21, x21, x13+// cneg x21, x21, cc+// csetm x13, cc+// subs x16, x8, x16+// cneg x16, x16, cc+// mul x8, x21, x16+// umulh x21, x21, x16+// cinv x13, x13, cc+// cmn x13, #0x1+// eor x16, x8, x13+// adcs x16, x7, x16+// eor x21, x21, x13+// adcs x21, x19, x21+// adcs x8, x14, x13+// adcs x19, x11, x13+// adc x13, x3, x13+// subs x10, x10, x17+// cneg x10, x10, cc+// csetm x17, cc+// subs x5, x20, x5+// cneg x5, x5, cc+// mul x20, x10, x5+// umulh x10, x10, x5+// cinv x17, x17, cc+// cmn x17, #0x1+// eor x5, x20, x17+// adcs x16, x16, x5+// eor x10, x10, x17+// adcs x21, x21, x10+// adcs x10, x8, x17+// adcs x5, x19, x17+// adc x17, x13, x17+// ldp x13, x20, [sp] // @slothy:reads=stack0+// ldp x8, x19, [sp, #16] // @slothy:reads=stack16+// eor x6, x6, x9+// adds x6, x6, x13+// eor x14, x24, x9+// adcs x14, x14, x20+// eor x11, x4, x9+// adcs x11, x11, x8+// eor x16, x16, x9+// adcs x16, x16, x19+// eor x21, x21, x9+// ldp x3, x24, [sp, #32] // @slothy:reads=stack32+// ldp x4, x7, [sp, #48] // @slothy:reads=stack48+// ldr x23, [sp, #64] // @slothy:reads=stack64+// adcs x21, x21, x3+// eor x10, x10, x9+// adcs x10, x10, x24+// eor x5, x5, x9+// adcs x5, x5, x4+// eor x17, x17, x9+// adcs x17, x17, x7+// adc x22, x23, xzr+// adds x21, x21, x13+// adcs x10, x10, x20+// adcs x13, x5, x8+// adcs x17, x17, x19+// and x5, x9, #0x1ff+// lsl x20, x6, #9+// orr x5, x20, x5+// adcs x5, x3, x5+// extr x20, x14, x6, #55+// adcs x20, x24, x20+// extr x8, x11, x14, #55+// adcs x8, x4, x8+// extr x9, x16, x11, #55+// adcs x9, x7, x9+// lsr x16, x16, #55+// adc x16, x16, x23+// ldr x6, [x2, #64]+// ldp x19, x14, [x1]+// and x11, x19, #0xfffffffffffff+// mul x11, x6, x11+// ldr x3, [x1, #64]+// ldp x24, x4, [x2]+// and x7, x24, #0xfffffffffffff+// mul x7, x3, x7+// add x11, x11, x7+// extr x19, x14, x19, #52+// and x19, x19, #0xfffffffffffff+// mul x19, x6, x19+// extr x24, x4, x24, #52+// and x24, x24, #0xfffffffffffff+// mul x24, x3, x24+// add x19, x19, x24+// lsr x24, x11, #52+// add x19, x19, x24+// lsl x11, x11, #12+// extr x11, x19, x11, #12+// adds x21, x21, x11+// ldp x11, x24, [x1, #16]+// ldp x7, x23, [x2, #16]+// extr x14, x11, x14, #40+// and x14, x14, #0xfffffffffffff+// mul x14, x6, x14+// extr x4, x7, x4, #40+// and x4, x4, #0xfffffffffffff+// mul x4, x3, x4+// add x14, x14, x4+// lsr x4, x19, #52+// add x14, x14, x4+// lsl x19, x19, #12+// extr x19, x14, x19, #24+// adcs x10, x10, x19+// extr x19, x24, x11, #28+// and x19, x19, #0xfffffffffffff+// mul x19, x6, x19+// extr x11, x23, x7, #28+// and x11, x11, #0xfffffffffffff+// mul x11, x3, x11+// add x19, x19, x11+// lsr x11, x14, #52+// add x19, x19, x11+// lsl x14, x14, #12+// extr x14, x19, x14, #36+// adcs x13, x13, x14+// and x14, x10, x13+// ldp x11, x4, [x1, #32]+// ldp x7, x12, [x2, #32]+// extr x24, x11, x24, #16+// and x24, x24, #0xfffffffffffff+// mul x24, x6, x24+// extr x23, x7, x23, #16+// and x23, x23, #0xfffffffffffff+// mul x23, x3, x23+// add x24, x24, x23+// lsl x23, x22, #48+// add x24, x24, x23+// lsr x23, x19, #52+// add x24, x24, x23+// lsl x19, x19, #12+// extr x19, x24, x19, #48+// adcs x17, x17, x19+// and x19, x14, x17+// lsr x14, x11, #4+// and x14, x14, #0xfffffffffffff+// mul x14, x6, x14+// lsr x23, x7, #4+// and x23, x23, #0xfffffffffffff+// mul x23, x3, x23+// add x14, x14, x23+// lsr x23, x24, #52+// add x14, x14, x23+// lsl x24, x24, #12+// extr x24, x14, x24, #60+// extr x11, x4, x11, #56+// and x11, x11, #0xfffffffffffff+// mul x11, x6, x11+// extr x7, x12, x7, #56+// and x7, x7, #0xfffffffffffff+// mul x7, x3, x7+// add x11, x11, x7+// lsr x14, x14, #52+// add x14, x11, x14+// lsl x11, x24, #8+// extr x11, x14, x11, #8+// adcs x5, x5, x11+// and x19, x19, x5+// ldp x11, x24, [x1, #48]+// ldp x2, x7, [x2, #48]+// extr x4, x11, x4, #44+// and x4, x4, #0xfffffffffffff+// mul x4, x6, x4+// extr x23, x2, x12, #44+// and x23, x23, #0xfffffffffffff+// mul x23, x3, x23+// add x4, x4, x23+// lsr x23, x14, #52+// add x4, x4, x23+// lsl x14, x14, #12+// extr x14, x4, x14, #20+// adcs x20, x20, x14+// and x19, x19, x20+// extr x14, x24, x11, #32+// and x14, x14, #0xfffffffffffff+// mul x14, x6, x14+// extr x2, x7, x2, #32+// and x2, x2, #0xfffffffffffff+// mul x2, x3, x2+// add x2, x14, x2+// lsr x14, x4, #52+// add x2, x2, x14+// lsl x14, x4, #12+// extr x14, x2, x14, #32+// adcs x8, x8, x14+// and x19, x19, x8+// lsr x14, x24, #20+// mul x14, x6, x14+// lsr x11, x7, #20+// mul x11, x3, x11+// add x14, x14, x11+// lsr x11, x2, #52+// add x14, x14, x11+// lsl x2, x2, #12+// extr x2, x14, x2, #44+// adcs x9, x9, x2+// and x2, x19, x9+// mul x6, x6, x3+// lsr x19, x14, #44+// add x6, x6, x19+// adc x16, x16, x6+// lsr x6, x16, #9+// orr x16, x16, #0xfffffffffffffe00+// cmp xzr, xzr+// adcs xzr, x21, x6+// adcs xzr, x2, xzr+// adcs xzr, x16, xzr+// adcs x21, x21, x6+// adcs x10, x10, xzr+// adcs x13, x13, xzr+// adcs x17, x17, xzr+// adcs x5, x5, xzr+// adcs x20, x20, xzr+// adcs x8, x8, xzr+// adcs x9, x9, xzr+// adc x16, x16, xzr+// and x2, x21, #0x1ff+// extr x21, x10, x21, #9+// extr x10, x13, x10, #9+// stp x21, x10, [x0] // @slothy:writes=buffer0+// extr x21, x17, x13, #9+// extr x10, x5, x17, #9+// stp x21, x10, [x0, #16] // @slothy:writes=buffer16+// extr x21, x20, x5, #9+// extr x10, x8, x20, #9+// stp x21, x10, [x0, #32] // @slothy:writes=buffer32+// extr x21, x9, x8, #9+// extr x10, x16, x9, #9+// stp x21, x10, [x0, #48] // @slothy:writes=buffer48+// str x2, [x0, #64] // @slothy:writes=buffer64+// add sp, sp, #80+// ldp x25, x26, [sp], #16+// ldp x23, x24, [sp], #16+// ldp x21, x22, [sp], #16+// ldp x19, x20, [sp], #16+// ret+//+// The bash script used for step 2 is as follows:+//+// # Store the assembly instructions except the last 'ret',+// # callee-register store/loads and add/sub sp #80 as, say, 'input.S'.+// export OUTPUTS="[hint_buffer0,hint_buffer16,hint_buffer32,hint_buffer48,hint_buffer64]"+// export RESERVED_REGS="[x18,x27,x28,x29,x30,sp,q8,q9,q10,q11,q12,q13,q14,q15,v8,v9,v10,v11,v12,v13,v14,v15]"+// <s2n-bignum>/tools/external/slothy.sh input.S my_out_dir+// # my_out_dir/3.opt.s is the optimized assembly. Its output may differ+// # from this file since the sequence is non-deterministically chosen.+// # Please add 'ret' at the end of the output assembly.++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_mul_p521)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_mul_p521)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_mul_p521)+ .text+ .balign 4++S2N_BN_SYMBOL(bignum_mul_p521):+ CFI_START++// Save registers and make space for the temporary buffer++ CFI_PUSH2(x19,x20)+ CFI_PUSH2(x21,x22)+ CFI_PUSH2(x23,x24)+ CFI_PUSH2(x25,x26)+ CFI_DEC_SP(80)++ ldr q6, [x2]+ ldp x10, x17, [x1, #16]+ ldr q4, [x1]+ ldr q16, [x2, #32]+ ldp x5, x20, [x2, #16]+ ldr q2, [x1, #32]+ movi v31.2D, #0x00000000ffffffff+ uzp2 v17.4S, v6.4S, v6.4S+ rev64 v7.4S, v6.4S+ ldp x15, x21, [x1]+ xtn v25.2S, v6.2D+ xtn v22.2S, v4.2D+ subs x14, x10, x17+ mul v7.4S, v7.4S, v4.4S+ csetm x8, cc+ rev64 v3.4S, v16.4S+ xtn v1.2S, v16.2D+ ldp x13, x16, [x2]+ mul x26, x10, x5+ uzp2 v16.4S, v16.4S, v16.4S+ uaddlp v26.2D, v7.4S+ cneg x4, x14, cc+ subs x24, x15, x21+ xtn v5.2S, v2.2D+ mul v28.4S, v3.4S, v2.4S+ shl v26.2D, v26.2D, #32+ mul x22, x17, x20+ umull v20.2D, v22.2S, v25.2S+ uzp2 v6.4S, v4.4S, v4.4S+ umull v18.2D, v22.2S, v17.2S+ uzp2 v4.4S, v2.4S, v2.4S+ cneg x14, x24, cc+ csetm x7, cc+ umulh x11, x17, x20+ usra v18.2D, v20.2D, #32+ uaddlp v7.2D, v28.4S+ subs x19, x16, x13+ umlal v26.2D, v22.2S, v25.2S+ cneg x19, x19, cc+ shl v28.2D, v7.2D, #32+ umull v7.2D, v5.2S, v1.2S+ umull v30.2D, v5.2S, v16.2S+ cinv x6, x7, cc+ mul x25, x14, x19+ umlal v28.2D, v5.2S, v1.2S+ umull v21.2D, v6.2S, v17.2S+ umulh x14, x14, x19+ usra v30.2D, v7.2D, #32+ subs x9, x20, x5+ and v29.16B, v18.16B, v31.16B+ cinv x23, x8, cc+ mov x8, v26.d[1]+ cneg x12, x9, cc+ usra v21.2D, v18.2D, #32+ umlal v29.2D, v6.2S, v25.2S+ mul x24, x4, x12+ umull v18.2D, v4.2S, v16.2S+ movi v25.2D, #0x00000000ffffffff+ eor x9, x14, x6+ and v7.16B, v30.16B, v25.16B+ usra v21.2D, v29.2D, #32+ umulh x7, x10, x5+ usra v18.2D, v30.2D, #32+ umlal v7.2D, v4.2S, v1.2S+ mov x19, v21.d[0]+ umulh x3, x4, x12+ mov x14, v21.d[1]+ usra v18.2D, v7.2D, #32+ adds x4, x8, x19+ mov x8, v26.d[0]+ adcs x19, x26, x14+ adcs x14, x22, x7+ adc x12, x11, xzr+ adds x11, x4, x8+ adcs x26, x19, x4+ adcs x22, x14, x19+ eor x4, x24, x23+ adcs x14, x12, x14+ eor x7, x25, x6+ adc x25, xzr, x12+ eor x19, x3, x23+ adds x3, x26, x8+ adcs x24, x22, x11+ adcs x12, x14, x26+ adcs x22, x25, x22+ adcs x26, xzr, x14+ adc x14, xzr, x25+ cmn x23, #0x1+ adcs x22, x22, x4+ adcs x19, x26, x19+ adc x25, x14, x23+ subs x14, x21, x17+ cneg x23, x14, cc+ csetm x26, cc+ subs x4, x20, x16+ cneg x14, x4, cc+ cinv x4, x26, cc+ cmn x6, #0x1+ adcs x11, x11, x7+ mul x7, x23, x14+ adcs x9, x3, x9+ adcs x26, x24, x6+ umulh x3, x23, x14+ adcs x14, x12, x6+ adcs x22, x22, x6+ adcs x12, x19, x6+ extr x24, x11, x8, #55+ adc x6, x25, x6+ subs x19, x15, x17+ csetm x17, cc+ cneg x23, x19, cc+ subs x19, x20, x13+ lsl x25, x8, #9+ eor x8, x7, x4+ cneg x20, x19, cc+ umulh x7, x23, x20+ cinv x19, x17, cc+ subs x17, x15, x10+ csetm x15, cc+ stp x25, x24, [sp, #32]+ cneg x24, x17, cc+ mul x20, x23, x20+ subs x25, x5, x13+ cneg x13, x25, cc+ cinv x15, x15, cc+ mul x25, x24, x13+ subs x21, x21, x10+ csetm x23, cc+ cneg x17, x21, cc+ subs x21, x5, x16+ umulh x13, x24, x13+ cinv x10, x23, cc+ cneg x23, x21, cc+ cmn x4, #0x1+ adcs x14, x14, x8+ eor x21, x3, x4+ adcs x21, x22, x21+ eor x5, x20, x19+ adcs x24, x12, x4+ mul x12, x17, x23+ eor x8, x25, x15+ adc x25, x6, x4+ cmn x15, #0x1+ adcs x6, x9, x8+ ldp x20, x8, [x2, #48]+ eor x9, x13, x15+ adcs x4, x26, x9+ umulh x26, x17, x23+ ldp x17, x13, [x1, #48]+ adcs x9, x14, x15+ adcs x16, x21, x15+ adcs x14, x24, x15+ eor x21, x7, x19+ mul x23, x17, x20+ adc x24, x25, x15+ cmn x19, #0x1+ adcs x7, x4, x5+ adcs x9, x9, x21+ umulh x3, x13, x8+ adcs x16, x16, x19+ adcs x22, x14, x19+ eor x5, x12, x10+ adc x12, x24, x19+ cmn x10, #0x1+ adcs x19, x7, x5+ eor x14, x26, x10+ mov x7, v28.d[1]+ adcs x24, x9, x14+ extr x4, x19, x6, #55+ umulh x15, x17, x20+ mov x14, v18.d[1]+ lsr x9, x19, #55+ adcs x5, x16, x10+ mov x16, v18.d[0]+ adcs x19, x22, x10+ str x9, [sp, #64]+ extr x25, x6, x11, #55+ adc x21, x12, x10+ subs x26, x17, x13+ stp x25, x4, [sp, #48]+ stp x19, x21, [sp, #16]+ csetm x6, cc+ cneg x4, x26, cc+ mul x19, x13, x8+ subs x11, x8, x20+ stp x24, x5, [sp]+ ldp x21, x10, [x1, #32]+ cinv x12, x6, cc+ cneg x6, x11, cc+ mov x9, v28.d[0]+ umulh x25, x4, x6+ adds x22, x7, x16+ ldp x16, x5, [x2, #32]+ adcs x14, x23, x14+ adcs x11, x19, x15+ adc x24, x3, xzr+ adds x3, x22, x9+ adcs x15, x14, x22+ mul x22, x4, x6+ adcs x6, x11, x14+ adcs x4, x24, x11+ eor x14, x25, x12+ adc x26, xzr, x24+ subs x7, x21, x10+ csetm x23, cc+ cneg x19, x7, cc+ subs x24, x5, x16+ cneg x11, x24, cc+ cinv x7, x23, cc+ adds x25, x15, x9+ eor x23, x22, x12+ adcs x22, x6, x3+ mul x24, x19, x11+ adcs x15, x4, x15+ adcs x6, x26, x6+ umulh x19, x19, x11+ adcs x11, xzr, x4+ adc x26, xzr, x26+ cmn x12, #0x1+ adcs x4, x6, x23+ eor x6, x24, x7+ adcs x14, x11, x14+ adc x26, x26, x12+ subs x11, x10, x13+ cneg x12, x11, cc+ csetm x11, cc+ eor x19, x19, x7+ subs x24, x8, x5+ cinv x11, x11, cc+ cneg x24, x24, cc+ cmn x7, #0x1+ adcs x3, x3, x6+ mul x23, x12, x24+ adcs x25, x25, x19+ adcs x6, x22, x7+ umulh x19, x12, x24+ adcs x22, x15, x7+ adcs x12, x4, x7+ eor x24, x23, x11+ adcs x4, x14, x7+ adc x26, x26, x7+ eor x19, x19, x11+ subs x14, x21, x17+ cneg x7, x14, cc+ csetm x14, cc+ subs x23, x20, x16+ cinv x14, x14, cc+ cneg x23, x23, cc+ cmn x11, #0x1+ adcs x22, x22, x24+ mul x24, x7, x23+ adcs x15, x12, x19+ adcs x4, x4, x11+ adc x19, x26, x11+ umulh x26, x7, x23+ subs x7, x21, x13+ eor x11, x24, x14+ cneg x23, x7, cc+ csetm x12, cc+ subs x7, x8, x16+ cneg x7, x7, cc+ cinv x12, x12, cc+ cmn x14, #0x1+ eor x26, x26, x14+ adcs x11, x25, x11+ mul x25, x23, x7+ adcs x26, x6, x26+ adcs x6, x22, x14+ adcs x24, x15, x14+ umulh x23, x23, x7+ adcs x4, x4, x14+ adc x22, x19, x14+ eor x14, x25, x12+ eor x7, x23, x12+ cmn x12, #0x1+ adcs x14, x26, x14+ ldp x19, x25, [x2]+ ldp x15, x23, [x2, #16]+ adcs x26, x6, x7+ adcs x24, x24, x12+ adcs x7, x4, x12+ adc x4, x22, x12+ subs x19, x19, x16+ ldp x16, x22, [x1]+ sbcs x6, x25, x5+ ldp x12, x25, [x1, #16]+ sbcs x15, x15, x20+ sbcs x8, x23, x8+ csetm x23, cc+ subs x21, x21, x16+ eor x16, x19, x23+ sbcs x19, x10, x22+ eor x22, x6, x23+ eor x8, x8, x23+ sbcs x6, x17, x12+ sbcs x13, x13, x25+ csetm x12, cc+ subs x10, x10, x17+ cneg x17, x10, cc+ csetm x25, cc+ subs x5, x20, x5+ eor x10, x19, x12+ cneg x19, x5, cc+ eor x20, x15, x23+ eor x21, x21, x12+ cinv x15, x25, cc+ mul x25, x17, x19+ subs x16, x16, x23+ sbcs x5, x22, x23+ eor x6, x6, x12+ sbcs x20, x20, x23+ eor x22, x13, x12+ sbc x8, x8, x23+ subs x21, x21, x12+ umulh x19, x17, x19+ sbcs x10, x10, x12+ sbcs x17, x6, x12+ eor x6, x19, x15+ eor x19, x25, x15+ umulh x25, x17, x20+ sbc x13, x22, x12+ cmn x15, #0x1+ adcs x22, x14, x19+ adcs x19, x26, x6+ ldp x6, x26, [sp]+ adcs x14, x24, x15+ umulh x24, x21, x16+ adcs x7, x7, x15+ adc x15, x4, x15+ adds x4, x9, x6+ eor x9, x23, x12+ adcs x12, x3, x26+ stp x4, x12, [sp]+ ldp x4, x26, [sp, #16]+ umulh x12, x10, x5+ ldp x6, x23, [sp, #32]+ adcs x3, x11, x4+ mul x4, x13, x8+ adcs x26, x22, x26+ ldp x22, x11, [sp, #48]+ adcs x6, x19, x6+ stp x3, x26, [sp, #16]+ mul x26, x10, x5+ adcs x14, x14, x23+ stp x6, x14, [sp, #32]+ ldr x6, [sp, #64]+ adcs x22, x7, x22+ adcs x14, x15, x11+ mul x11, x17, x20+ adc x19, x6, xzr+ stp x22, x14, [sp, #48]+ adds x14, x26, x24+ str x19, [sp, #64]+ umulh x19, x13, x8+ adcs x7, x11, x12+ adcs x22, x4, x25+ mul x6, x21, x16+ adc x19, x19, xzr+ subs x11, x17, x13+ cneg x12, x11, cc+ csetm x11, cc+ subs x24, x8, x20+ cinv x11, x11, cc+ cneg x24, x24, cc+ adds x4, x14, x6+ adcs x14, x7, x14+ mul x3, x12, x24+ adcs x7, x22, x7+ adcs x22, x19, x22+ umulh x12, x12, x24+ adc x24, xzr, x19+ adds x19, x14, x6+ eor x3, x3, x11+ adcs x26, x7, x4+ adcs x14, x22, x14+ adcs x25, x24, x7+ adcs x23, xzr, x22+ eor x7, x12, x11+ adc x12, xzr, x24+ subs x22, x21, x10+ cneg x24, x22, cc+ csetm x22, cc+ subs x15, x5, x16+ cinv x22, x22, cc+ cneg x15, x15, cc+ cmn x11, #0x1+ adcs x3, x25, x3+ mul x25, x24, x15+ adcs x23, x23, x7+ adc x11, x12, x11+ subs x7, x10, x13+ umulh x15, x24, x15+ cneg x12, x7, cc+ csetm x7, cc+ eor x24, x25, x22+ eor x25, x15, x22+ cmn x22, #0x1+ adcs x24, x4, x24+ adcs x19, x19, x25+ adcs x15, x26, x22+ adcs x4, x14, x22+ adcs x26, x3, x22+ adcs x25, x23, x22+ adc x23, x11, x22+ subs x14, x21, x17+ cneg x3, x14, cc+ csetm x11, cc+ subs x14, x8, x5+ cneg x14, x14, cc+ cinv x7, x7, cc+ subs x13, x21, x13+ cneg x21, x13, cc+ csetm x13, cc+ mul x22, x12, x14+ subs x8, x8, x16+ cinv x13, x13, cc+ umulh x14, x12, x14+ cneg x12, x8, cc+ subs x8, x20, x16+ cneg x8, x8, cc+ cinv x16, x11, cc+ eor x22, x22, x7+ cmn x7, #0x1+ eor x14, x14, x7+ adcs x4, x4, x22+ mul x11, x3, x8+ adcs x22, x26, x14+ adcs x14, x25, x7+ eor x25, x24, x9+ adc x26, x23, x7+ umulh x7, x3, x8+ subs x17, x10, x17+ cneg x24, x17, cc+ eor x3, x11, x16+ csetm x11, cc+ subs x20, x20, x5+ cneg x5, x20, cc+ cinv x11, x11, cc+ cmn x16, #0x1+ mul x17, x21, x12+ eor x8, x7, x16+ adcs x10, x19, x3+ and x19, x9, #0x1ff+ adcs x20, x15, x8+ umulh x15, x21, x12+ eor x12, x10, x9+ eor x8, x6, x9+ adcs x6, x4, x16+ adcs x4, x22, x16+ adcs x21, x14, x16+ adc x7, x26, x16+ mul x10, x24, x5+ cmn x13, #0x1+ ldp x3, x14, [x1]+ eor x17, x17, x13+ umulh x5, x24, x5+ adcs x20, x20, x17+ eor x17, x15, x13+ adcs x16, x6, x17+ eor x22, x10, x11+ adcs x23, x4, x13+ extr x10, x14, x3, #52+ and x26, x3, #0xfffffffffffff+ adcs x24, x21, x13+ and x15, x10, #0xfffffffffffff+ adc x6, x7, x13+ cmn x11, #0x1+ adcs x17, x20, x22+ eor x4, x5, x11+ ldp x21, x10, [sp]+ adcs x7, x16, x4+ eor x16, x17, x9+ eor x13, x7, x9+ ldp x3, x17, [sp, #16]+ adcs x7, x23, x11+ eor x23, x7, x9+ ldp x5, x22, [sp, #32]+ adcs x7, x24, x11+ adc x24, x6, x11+ ldr x6, [x2, #64]+ adds x20, x8, x21+ lsl x11, x20, #9+ eor x4, x7, x9+ orr x7, x11, x19+ eor x8, x24, x9+ adcs x11, x25, x10+ mul x26, x6, x26+ ldp x19, x24, [sp, #48]+ adcs x12, x12, x3+ adcs x16, x16, x17+ adcs x9, x13, x5+ ldr x25, [sp, #64]+ extr x20, x11, x20, #55+ adcs x13, x23, x22+ adcs x4, x4, x19+ extr x23, x12, x11, #55+ adcs x8, x8, x24+ adc x11, x25, xzr+ adds x21, x9, x21+ extr x9, x16, x12, #55+ lsr x12, x16, #55+ adcs x10, x13, x10+ mul x15, x6, x15+ adcs x13, x4, x3+ ldp x16, x4, [x2]+ ldr x3, [x1, #64]+ adcs x17, x8, x17+ adcs x5, x5, x7+ adcs x20, x22, x20+ adcs x8, x19, x23+ and x22, x16, #0xfffffffffffff+ ldp x19, x7, [x1, #16]+ adcs x9, x24, x9+ extr x24, x4, x16, #52+ adc x16, x12, x25+ mul x22, x3, x22+ and x25, x24, #0xfffffffffffff+ extr x14, x19, x14, #40+ and x12, x14, #0xfffffffffffff+ extr x23, x7, x19, #28+ ldp x19, x24, [x2, #16]+ mul x14, x3, x25+ and x23, x23, #0xfffffffffffff+ add x22, x26, x22+ lsl x11, x11, #48+ lsr x26, x22, #52+ lsl x25, x22, #12+ mul x22, x6, x12+ extr x12, x19, x4, #40+ add x4, x15, x14+ mul x15, x6, x23+ add x4, x4, x26+ extr x23, x24, x19, #28+ ldp x14, x19, [x1, #32]+ and x26, x12, #0xfffffffffffff+ extr x12, x4, x25, #12+ and x25, x23, #0xfffffffffffff+ adds x21, x21, x12+ mul x12, x3, x26+ extr x23, x14, x7, #16+ and x23, x23, #0xfffffffffffff+ mul x7, x3, x25+ ldp x25, x26, [x2, #32]+ add x12, x22, x12+ extr x22, x19, x14, #56+ mul x23, x6, x23+ lsr x14, x14, #4+ extr x24, x25, x24, #16+ add x7, x15, x7+ and x15, x24, #0xfffffffffffff+ and x22, x22, #0xfffffffffffff+ lsr x24, x4, #52+ mul x15, x3, x15+ and x14, x14, #0xfffffffffffff+ add x12, x12, x24+ lsl x24, x4, #12+ lsr x4, x12, #52+ extr x24, x12, x24, #24+ adcs x10, x10, x24+ lsl x24, x12, #12+ add x12, x7, x4+ mul x22, x6, x22+ add x4, x23, x15+ extr x7, x12, x24, #36+ adcs x13, x13, x7+ lsl x15, x12, #12+ add x7, x4, x11+ lsr x24, x12, #52+ ldp x23, x11, [x2, #48]+ add x4, x7, x24+ mul x12, x6, x14+ extr x7, x26, x25, #56+ extr x14, x4, x15, #48+ and x2, x7, #0xfffffffffffff+ extr x24, x11, x23, #32+ ldp x15, x7, [x1, #48]+ and x1, x24, #0xfffffffffffff+ lsr x24, x4, #52+ mul x2, x3, x2+ extr x26, x23, x26, #44+ lsr x23, x25, #4+ and x23, x23, #0xfffffffffffff+ and x25, x26, #0xfffffffffffff+ extr x26, x7, x15, #32+ extr x19, x15, x19, #44+ mul x23, x3, x23+ and x15, x26, #0xfffffffffffff+ lsl x26, x4, #12+ and x4, x19, #0xfffffffffffff+ lsr x11, x11, #20+ mul x19, x6, x4+ adcs x17, x17, x14+ add x14, x22, x2+ add x22, x12, x23+ lsr x7, x7, #20+ add x22, x22, x24+ extr x2, x22, x26, #60+ mul x24, x3, x25+ lsr x22, x22, #52+ add x14, x14, x22+ lsl x22, x2, #8+ extr x22, x14, x22, #8+ lsl x2, x14, #12+ mul x1, x3, x1+ adcs x12, x5, x22+ mul x5, x6, x15+ and x26, x10, x13+ and x4, x26, x17+ add x23, x19, x24+ lsr x14, x14, #52+ mul x22, x3, x11+ add x11, x23, x14+ extr x25, x11, x2, #20+ lsl x19, x11, #12+ adcs x25, x20, x25+ and x14, x4, x12+ add x1, x5, x1+ and x14, x14, x25+ mul x15, x6, x7+ add x26, x15, x22+ mul x6, x6, x3+ lsr x22, x11, #52+ add x4, x1, x22+ lsr x1, x4, #52+ extr x3, x4, x19, #32+ lsl x15, x4, #12+ add x7, x26, x1+ adcs x23, x8, x3+ extr x20, x7, x15, #44+ and x3, x14, x23+ lsr x19, x7, #44+ adcs x7, x9, x20+ add x11, x6, x19+ adc x4, x16, x11+ lsr x14, x4, #9+ cmp xzr, xzr+ and x15, x3, x7+ orr x3, x4, #0xfffffffffffffe00+ adcs xzr, x21, x14+ adcs xzr, x15, xzr+ adcs xzr, x3, xzr+ adcs x11, x21, x14+ and x14, x11, #0x1ff+ adcs x1, x10, xzr+ extr x10, x1, x11, #9+ str x14, [x0, #64]+ adcs x14, x13, xzr+ extr x11, x14, x1, #9+ adcs x1, x17, xzr+ extr x4, x1, x14, #9+ stp x10, x11, [x0]+ adcs x11, x12, xzr+ extr x14, x11, x1, #9+ adcs x10, x25, xzr+ extr x11, x10, x11, #9+ stp x4, x14, [x0, #16]+ adcs x14, x23, xzr+ extr x10, x14, x10, #9+ adcs x1, x7, xzr+ stp x11, x10, [x0, #32]+ extr x14, x1, x14, #9+ adc x10, x3, xzr+ extr x26, x10, x1, #9+ stp x14, x26, [x0, #48]++// Restore regs and return++ CFI_INC_SP(80)+ CFI_POP2(x25,x26)+ CFI_POP2(x23,x24)+ CFI_POP2(x21,x22)+ CFI_POP2(x19,x20)+ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_mul_p521)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,538 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Multiply modulo p_521, z := (x * y) mod p_521, assuming x and y reduced+// Inputs x[9], y[9]; output z[9]+//+// extern void bignum_mul_p521_alt(uint64_t z[static 9],+// const uint64_t x[static 9],+// const uint64_t y[static 9]);+//+// Standard ARM ABI: X0 = z, X1 = x, X2 = y+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_mul_p521_alt)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_mul_p521_alt)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_mul_p521_alt)+ .text+ .balign 4++#define z x0+#define x x1+#define y x2++// These are repeated mod 2 as we load paris of inputs++#define a0 x3+#define a1 x4+#define a2 x3+#define a3 x4+#define a4 x3+#define a5 x4+#define a6 x3+#define a7 x4+#define a8 x3++#define b0 x5+#define b1 x6+#define b2 x7+#define b3 x8+#define b4 x9+#define b5 x10+#define b6 x11+#define b7 x12+#define b8 x13++#define t x14++// These repeat mod 11 as we stash some intermediate results in the+// output buffer.++#define u0 x15+#define u1 x16+#define u2 x17+#define u3 x19+#define u4 x20+#define u5 x21+#define u6 x22+#define u7 x23+#define u8 x24+#define u9 x25+#define u10 x26+#define u11 x15+#define u12 x16+#define u13 x17+#define u14 x19+#define u15 x20+#define u16 x21++S2N_BN_SYMBOL(bignum_mul_p521_alt):+ CFI_START++// Save more registers and make temporary space on stack++ CFI_PUSH2(x19,x20)+ CFI_PUSH2(x21,x22)+ CFI_PUSH2(x23,x24)+ CFI_PUSH2(x25,x26)+ CFI_DEC_SP(64)++// Load operands and set up row 0 = [u9;...;u0] = a0 * [b8;...;b0]++ ldp a0, a1, [x]+ ldp b0, b1, [y]++ mul u0, a0, b0+ umulh u1, a0, b0+ mul t, a0, b1+ umulh u2, a0, b1+ adds u1, u1, t++ ldp b2, b3, [y, #16]++ mul t, a0, b2+ umulh u3, a0, b2+ adcs u2, u2, t++ mul t, a0, b3+ umulh u4, a0, b3+ adcs u3, u3, t++ ldp b4, b5, [y, #32]++ mul t, a0, b4+ umulh u5, a0, b4+ adcs u4, u4, t++ mul t, a0, b5+ umulh u6, a0, b5+ adcs u5, u5, t++ ldp b6, b7, [y, #48]++ mul t, a0, b6+ umulh u7, a0, b6+ adcs u6, u6, t++ ldr b8, [y, #64]++ mul t, a0, b7+ umulh u8, a0, b7+ adcs u7, u7, t++ mul t, a0, b8+ umulh u9, a0, b8+ adcs u8, u8, t++ adc u9, u9, xzr++// Row 1 = [u10;...;u0] = [a1;a0] * [b8;...;b0]++ mul t, a1, b0+ adds u1, u1, t+ mul t, a1, b1+ adcs u2, u2, t+ mul t, a1, b2+ adcs u3, u3, t+ mul t, a1, b3+ adcs u4, u4, t+ mul t, a1, b4+ adcs u5, u5, t+ mul t, a1, b5+ adcs u6, u6, t+ mul t, a1, b6+ adcs u7, u7, t+ mul t, a1, b7+ adcs u8, u8, t+ mul t, a1, b8+ adcs u9, u9, t+ cset u10, cs++ umulh t, a1, b0+ adds u2, u2, t+ umulh t, a1, b1+ adcs u3, u3, t+ umulh t, a1, b2+ adcs u4, u4, t+ umulh t, a1, b3+ adcs u5, u5, t+ umulh t, a1, b4+ adcs u6, u6, t+ umulh t, a1, b5+ adcs u7, u7, t+ umulh t, a1, b6+ adcs u8, u8, t+ umulh t, a1, b7+ adcs u9, u9, t+ umulh t, a1, b8+ adc u10, u10, t++ stp u0, u1, [sp]++// Row 2 = [u11;...;u0] = [a2;a1;a0] * [b8;...;b0]++ ldp a2, a3, [x, #16]++ mul t, a2, b0+ adds u2, u2, t+ mul t, a2, b1+ adcs u3, u3, t+ mul t, a2, b2+ adcs u4, u4, t+ mul t, a2, b3+ adcs u5, u5, t+ mul t, a2, b4+ adcs u6, u6, t+ mul t, a2, b5+ adcs u7, u7, t+ mul t, a2, b6+ adcs u8, u8, t+ mul t, a2, b7+ adcs u9, u9, t+ mul t, a2, b8+ adcs u10, u10, t+ cset u11, cs++ umulh t, a2, b0+ adds u3, u3, t+ umulh t, a2, b1+ adcs u4, u4, t+ umulh t, a2, b2+ adcs u5, u5, t+ umulh t, a2, b3+ adcs u6, u6, t+ umulh t, a2, b4+ adcs u7, u7, t+ umulh t, a2, b5+ adcs u8, u8, t+ umulh t, a2, b6+ adcs u9, u9, t+ umulh t, a2, b7+ adcs u10, u10, t+ umulh t, a2, b8+ adc u11, u11, t++// Row 3 = [u12;...;u0] = [a3;a2;a1;a0] * [b8;...;b0]++ mul t, a3, b0+ adds u3, u3, t+ mul t, a3, b1+ adcs u4, u4, t+ mul t, a3, b2+ adcs u5, u5, t+ mul t, a3, b3+ adcs u6, u6, t+ mul t, a3, b4+ adcs u7, u7, t+ mul t, a3, b5+ adcs u8, u8, t+ mul t, a3, b6+ adcs u9, u9, t+ mul t, a3, b7+ adcs u10, u10, t+ mul t, a3, b8+ adcs u11, u11, t+ cset u12, cs++ umulh t, a3, b0+ adds u4, u4, t+ umulh t, a3, b1+ adcs u5, u5, t+ umulh t, a3, b2+ adcs u6, u6, t+ umulh t, a3, b3+ adcs u7, u7, t+ umulh t, a3, b4+ adcs u8, u8, t+ umulh t, a3, b5+ adcs u9, u9, t+ umulh t, a3, b6+ adcs u10, u10, t+ umulh t, a3, b7+ adcs u11, u11, t+ umulh t, a3, b8+ adc u12, u12, t++ stp u2, u3, [sp, #16]++// Row 4 = [u13;...;u0] = [a4;a3;a2;a1;a0] * [b8;...;b0]++ ldp a4, a5, [x, #32]++ mul t, a4, b0+ adds u4, u4, t+ mul t, a4, b1+ adcs u5, u5, t+ mul t, a4, b2+ adcs u6, u6, t+ mul t, a4, b3+ adcs u7, u7, t+ mul t, a4, b4+ adcs u8, u8, t+ mul t, a4, b5+ adcs u9, u9, t+ mul t, a4, b6+ adcs u10, u10, t+ mul t, a4, b7+ adcs u11, u11, t+ mul t, a4, b8+ adcs u12, u12, t+ cset u13, cs++ umulh t, a4, b0+ adds u5, u5, t+ umulh t, a4, b1+ adcs u6, u6, t+ umulh t, a4, b2+ adcs u7, u7, t+ umulh t, a4, b3+ adcs u8, u8, t+ umulh t, a4, b4+ adcs u9, u9, t+ umulh t, a4, b5+ adcs u10, u10, t+ umulh t, a4, b6+ adcs u11, u11, t+ umulh t, a4, b7+ adcs u12, u12, t+ umulh t, a4, b8+ adc u13, u13, t++// Row 5 = [u14;...;u0] = [a5;a4;a3;a2;a1;a0] * [b8;...;b0]++ mul t, a5, b0+ adds u5, u5, t+ mul t, a5, b1+ adcs u6, u6, t+ mul t, a5, b2+ adcs u7, u7, t+ mul t, a5, b3+ adcs u8, u8, t+ mul t, a5, b4+ adcs u9, u9, t+ mul t, a5, b5+ adcs u10, u10, t+ mul t, a5, b6+ adcs u11, u11, t+ mul t, a5, b7+ adcs u12, u12, t+ mul t, a5, b8+ adcs u13, u13, t+ cset u14, cs++ umulh t, a5, b0+ adds u6, u6, t+ umulh t, a5, b1+ adcs u7, u7, t+ umulh t, a5, b2+ adcs u8, u8, t+ umulh t, a5, b3+ adcs u9, u9, t+ umulh t, a5, b4+ adcs u10, u10, t+ umulh t, a5, b5+ adcs u11, u11, t+ umulh t, a5, b6+ adcs u12, u12, t+ umulh t, a5, b7+ adcs u13, u13, t+ umulh t, a5, b8+ adc u14, u14, t++ stp u4, u5, [sp, #32]++// Row 6 = [u15;...;u0] = [a6;a5;a4;a3;a2;a1;a0] * [b8;...;b0]++ ldp a6, a7, [x, #48]++ mul t, a6, b0+ adds u6, u6, t+ mul t, a6, b1+ adcs u7, u7, t+ mul t, a6, b2+ adcs u8, u8, t+ mul t, a6, b3+ adcs u9, u9, t+ mul t, a6, b4+ adcs u10, u10, t+ mul t, a6, b5+ adcs u11, u11, t+ mul t, a6, b6+ adcs u12, u12, t+ mul t, a6, b7+ adcs u13, u13, t+ mul t, a6, b8+ adcs u14, u14, t+ cset u15, cs++ umulh t, a6, b0+ adds u7, u7, t+ umulh t, a6, b1+ adcs u8, u8, t+ umulh t, a6, b2+ adcs u9, u9, t+ umulh t, a6, b3+ adcs u10, u10, t+ umulh t, a6, b4+ adcs u11, u11, t+ umulh t, a6, b5+ adcs u12, u12, t+ umulh t, a6, b6+ adcs u13, u13, t+ umulh t, a6, b7+ adcs u14, u14, t+ umulh t, a6, b8+ adc u15, u15, t++// Row 7 = [u16;...;u0] = [a7;a6;a5;a4;a3;a2;a1;a0] * [b8;...;b0]++ mul t, a7, b0+ adds u7, u7, t+ mul t, a7, b1+ adcs u8, u8, t+ mul t, a7, b2+ adcs u9, u9, t+ mul t, a7, b3+ adcs u10, u10, t+ mul t, a7, b4+ adcs u11, u11, t+ mul t, a7, b5+ adcs u12, u12, t+ mul t, a7, b6+ adcs u13, u13, t+ mul t, a7, b7+ adcs u14, u14, t+ mul t, a7, b8+ adcs u15, u15, t+ cset u16, cs++ umulh t, a7, b0+ adds u8, u8, t+ umulh t, a7, b1+ adcs u9, u9, t+ umulh t, a7, b2+ adcs u10, u10, t+ umulh t, a7, b3+ adcs u11, u11, t+ umulh t, a7, b4+ adcs u12, u12, t+ umulh t, a7, b5+ adcs u13, u13, t+ umulh t, a7, b6+ adcs u14, u14, t+ umulh t, a7, b7+ adcs u15, u15, t+ umulh t, a7, b8+ adc u16, u16, t++ stp u6, u7, [sp, #48]++// Row 8 = [u16;...;u0] = [a8;a7;a6;a5;a4;a3;a2;a1;a0] * [b8;...;b0]++ ldr a8, [x, #64]++ mul t, a8, b0+ adds u8, u8, t+ mul t, a8, b1+ adcs u9, u9, t+ mul t, a8, b2+ adcs u10, u10, t+ mul t, a8, b3+ adcs u11, u11, t+ mul t, a8, b4+ adcs u12, u12, t+ mul t, a8, b5+ adcs u13, u13, t+ mul t, a8, b6+ adcs u14, u14, t+ mul t, a8, b7+ adcs u15, u15, t+ mul t, a8, b8+ adc u16, u16, t++ umulh t, a8, b0+ adds u9, u9, t+ umulh t, a8, b1+ adcs u10, u10, t+ umulh t, a8, b2+ adcs u11, u11, t+ umulh t, a8, b3+ adcs u12, u12, t+ umulh t, a8, b4+ adcs u13, u13, t+ umulh t, a8, b5+ adcs u14, u14, t+ umulh t, a8, b6+ adcs u15, u15, t+ umulh t, a8, b7+ adc u16, u16, t++// Now we have the full product, which we consider as+// 2^521 * h + l. Form h + l + 1++ subs xzr, xzr, xzr+ ldp b0, b1, [sp]+ extr t, u9, u8, #9+ adcs b0, b0, t+ extr t, u10, u9, #9+ adcs b1, b1, t+ ldp b2, b3, [sp, #16]+ extr t, u11, u10, #9+ adcs b2, b2, t+ extr t, u12, u11, #9+ adcs b3, b3, t+ ldp b4, b5, [sp, #32]+ extr t, u13, u12, #9+ adcs b4, b4, t+ extr t, u14, u13, #9+ adcs b5, b5, t+ ldp b6, b7, [sp, #48]+ extr t, u15, u14, #9+ adcs b6, b6, t+ extr t, u16, u15, #9+ adcs b7, b7, t+ orr b8, u8, #~0x1FF+ lsr t, u16, #9+ adcs b8, b8, t++// Now CF is set if h + l + 1 >= 2^521, which means it's already+// the answer, while if ~CF the answer is h + l so we should subtract+// 1 (all considered in 521 bits). Hence subtract ~CF and mask.++ sbcs b0, b0, xzr+ sbcs b1, b1, xzr+ sbcs b2, b2, xzr+ sbcs b3, b3, xzr+ sbcs b4, b4, xzr+ sbcs b5, b5, xzr+ sbcs b6, b6, xzr+ sbcs b7, b7, xzr+ sbc b8, b8, xzr+ and b8, b8, #0x1FF++// Store back digits of final result++ stp b0, b1, [z]+ stp b2, b3, [z, #16]+ stp b4, b5, [z, #32]+ stp b6, b7, [z, #48]+ str b8, [z, #64]++// Restore registers++ CFI_INC_SP(64)+ CFI_POP2(x25,x26)+ CFI_POP2(x23,x24)+ CFI_POP2(x21,x22)+ CFI_POP2(x19,x20)++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_mul_p521_alt)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,72 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Negate modulo p_256, z := (-x) mod p_256, assuming x reduced+// Input x[4]; output z[4]+//+// extern void bignum_neg_p256(uint64_t z[static 4], const uint64_t x[static 4]);+//+// Standard ARM ABI: X0 = z, X1 = x+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_neg_p256)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_neg_p256)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_neg_p256)+ .text+ .balign 4++#define z x0+#define x x1++#define p x2+#define t x3++#define d0 x4+#define d1 x5+#define d2 x6+#define d3 x7+++S2N_BN_SYMBOL(bignum_neg_p256):+ CFI_START++// Load the 4 digits of x++ ldp d0, d1, [x]+ ldp d2, d3, [x, #16]++// Set a bitmask p for the input being nonzero, so that we avoid doing+// -0 = p_256 and hence maintain strict modular reduction++ orr t, d0, d1+ orr p, d2, d3+ orr p, p, t+ cmp p, #0+ csetm p, ne++// Mask the nontrivial words of p_256 = [n3;0;n1;-1] and subtract++ subs d0, p, d0+ and t, p, #0x00000000ffffffff+ sbcs d1, t, d1+ sbcs d2, xzr, d2+ and t, p, #0xffffffff00000001+ sbc d3, t, d3++// Write back the result++ stp d0, d1, [z]+ stp d2, d3, [z, #16]++// Return++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_neg_p256)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
@@ -0,0 +1,1125 @@+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.+// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0++// ----------------------------------------------------------------------------+// Square modulo p_521, z := (x^2) mod p_521, assuming x reduced+// Input x[9]; output z[9]+//+// extern void bignum_sqr_p521(uint64_t z[static 9], const uint64_t x[static 9]);+//+// Standard ARM ABI: X0 = z, X1 = x+// ----------------------------------------------------------------------------++#include "_internal_s2n_bignum_arm.h"++// bignum_sqr_p521 is functionally equivalent to unopt/bignum_sqr_p521_base.+// It is written in a way that+// 1. A subset of scalar multiplications in bignum_montmul_p384 are carefully+// chosen and vectorized+// 2. The vectorized assembly is rescheduled using the SLOTHY superoptimizer.+// https://github.com/slothy-optimizer/slothy+//+// The output program of step 1. is as follows:+//+// stp x19, x20, [sp, #-16]!+// stp x21, x22, [sp, #-16]!+// stp x23, x24, [sp, #-16]!+// ldp x20, x19, [x1]+// ldr q23, [x1]+// ldr q1, [x1]+// ldr q16, [x1]+// ldp x14, x12, [x1, #16]+// ldr q28, [x1, #16]+// ldr q31, [x1, #16]+// ldp x9, x2, [x1, #32]+// ldr q29, [x1, #32]+// ldr q4, [x1, #32]+// ldr q5, [x1]+// ldr q2, [x1, #32]+// ldp x6, x13, [x1, #48]+// ldr q24, [x1, #48]+// ldr q27, [x1, #48]+// ldr q0, [x1, #16]+// ldr q30, [x1, #48]+// mul x17, x9, x6+// mul x10, x2, x13+// umulh x24, x9, x6+// subs x4, x9, x2+// cneg x4, x4, cc+// csetm x16, cc+// subs x3, x13, x6+// cneg x23, x3, cc+// mul x3, x4, x23+// umulh x4, x4, x23+// cinv x22, x16, cc+// eor x23, x3, x22+// eor x16, x4, x22+// adds x3, x17, x24+// adc x24, x24, xzr+// umulh x4, x2, x13+// adds x3, x3, x10+// adcs x24, x24, x4+// adc x4, x4, xzr+// adds x24, x24, x10+// adc x10, x4, xzr+// cmn x22, #0x1+// adcs x4, x3, x23+// adcs x24, x24, x16+// adc x10, x10, x22+// adds x8, x17, x17+// adcs x22, x4, x4+// adcs x5, x24, x24+// adcs x11, x10, x10+// adc x23, xzr, xzr+// movi v25.2D, #0xffffffff+// uzp2 v19.4S, v4.4S, v4.4S+// xtn v26.2S, v29.2D+// xtn v22.2S, v4.2D+// rev64 v4.4S, v4.4S+// umull v7.2D, v26.2S, v22.2S+// umull v21.2D, v26.2S, v19.2S+// uzp2 v17.4S, v29.4S, v29.4S+// mul v4.4S, v4.4S, v29.4S+// usra v21.2D, v7.2D, #32+// umull v18.2D, v17.2S, v19.2S+// uaddlp v4.2D, v4.4S+// and v7.16B, v21.16B, v25.16B+// umlal v7.2D, v17.2S, v22.2S+// shl v4.2D, v4.2D, #32+// usra v18.2D, v21.2D, #32+// umlal v4.2D, v26.2S, v22.2S+// usra v18.2D, v7.2D, #32+// mov x15, v4.d[0]+// mov x16, v4.d[1]+// mul x3, x9, x2+// mov x10, v18.d[0]+// mov x17, v18.d[1]+// umulh x4, x9, x2+// adds x24, x10, x3+// adcs x10, x16, x4+// adc x17, x17, xzr+// adds x7, x24, x3+// adcs x10, x10, x4+// adc x17, x17, xzr+// adds x8, x8, x10+// adcs x22, x22, x17+// adcs x21, x5, xzr+// adcs x5, x11, xzr+// adc x11, x23, xzr+// movi v25.2D, #0xffffffff+// uzp2 v19.4S, v27.4S, v27.4S+// xtn v26.2S, v24.2D+// xtn v22.2S, v27.2D+// rev64 v4.4S, v27.4S+// umull v7.2D, v26.2S, v22.2S+// umull v21.2D, v26.2S, v19.2S+// uzp2 v17.4S, v24.4S, v24.4S+// mul v4.4S, v4.4S, v24.4S+// usra v21.2D, v7.2D, #32+// umull v18.2D, v17.2S, v19.2S+// uaddlp v4.2D, v4.4S+// and v7.16B, v21.16B, v25.16B+// umlal v7.2D, v17.2S, v22.2S+// shl v4.2D, v4.2D, #32+// usra v18.2D, v21.2D, #32+// umlal v4.2D, v26.2S, v22.2S+// usra v18.2D, v7.2D, #32+// mov x23, v4.d[0]+// mov x16, v4.d[1]+// mul x3, x6, x13+// mov x10, v18.d[0]+// mov x17, v18.d[1]+// umulh x4, x6, x13+// adds x24, x10, x3+// adcs x10, x16, x4+// adc x17, x17, xzr+// adds x24, x24, x3+// adcs x10, x10, x4+// adc x17, x17, xzr+// adds x23, x23, x21+// adcs x16, x24, x5+// adcs x3, x10, x11+// adc x21, x17, xzr+// ldr x17, [x1, #64]+// add x5, x17, x17+// mul x11, x17, x17+// and x17, x20, #0xfffffffffffff+// mul x4, x5, x17+// extr x17, x19, x20, #52+// and x17, x17, #0xfffffffffffff+// mul x10, x5, x17+// lsr x17, x4, #52+// add x24, x10, x17+// lsl x17, x4, #12+// extr x17, x24, x17, #12+// adds x15, x15, x17+// extr x17, x14, x19, #40+// and x17, x17, #0xfffffffffffff+// mul x10, x5, x17+// lsr x17, x24, #52+// add x4, x10, x17+// lsl x17, x24, #12+// extr x17, x4, x17, #24+// adcs x7, x7, x17+// extr x17, x12, x14, #28+// and x17, x17, #0xfffffffffffff+// mul x10, x5, x17+// lsr x17, x4, #52+// add x24, x10, x17+// lsl x17, x4, #12+// extr x17, x24, x17, #36+// adcs x8, x8, x17+// extr x17, x9, x12, #16+// and x17, x17, #0xfffffffffffff+// mul x10, x5, x17+// lsr x17, x24, #52+// add x4, x10, x17+// lsl x17, x24, #12+// extr x17, x4, x17, #48+// adcs x22, x22, x17+// lsr x17, x9, #4+// and x17, x17, #0xfffffffffffff+// mul x10, x5, x17+// lsr x17, x4, #52+// add x24, x10, x17+// lsl x17, x4, #12+// extr x4, x24, x17, #60+// extr x17, x2, x9, #56+// and x17, x17, #0xfffffffffffff+// mul x10, x5, x17+// lsr x17, x24, #52+// add x24, x10, x17+// lsl x17, x4, #8+// extr x17, x24, x17, #8+// adcs x23, x23, x17+// extr x17, x6, x2, #44+// and x17, x17, #0xfffffffffffff+// mul x10, x5, x17+// lsr x17, x24, #52+// add x4, x10, x17+// lsl x17, x24, #12+// extr x17, x4, x17, #20+// adcs x16, x16, x17+// extr x17, x13, x6, #32+// and x17, x17, #0xfffffffffffff+// mul x10, x5, x17+// lsr x17, x4, #52+// add x24, x10, x17+// lsl x17, x4, #12+// extr x17, x24, x17, #32+// adcs x3, x3, x17+// lsr x17, x13, #20+// mul x10, x5, x17+// lsr x17, x24, #52+// add x10, x10, x17+// lsl x17, x24, #12+// extr x17, x10, x17, #44+// adcs x4, x21, x17+// lsr x17, x10, #44+// adc x24, x11, x17+// extr x10, x7, x15, #9+// extr x17, x8, x7, #9+// stp x10, x17, [x0] // @slothy:writes=buffer0+// extr x10, x22, x8, #9+// extr x17, x23, x22, #9+// stp x10, x17, [x0, #16] // @slothy:writes=buffer16+// extr x10, x16, x23, #9+// extr x17, x3, x16, #9+// stp x10, x17, [x0, #32] // @slothy:writes=buffer32+// extr x10, x4, x3, #9+// extr x17, x24, x4, #9+// stp x10, x17, [x0, #48] // @slothy:writes=buffer48+// and x10, x15, #0x1ff+// lsr x17, x24, #9+// add x17, x10, x17+// str x17, [x0, #64] // @slothy:writes=buffer64+// uzp1 v17.4S, v28.4S, v23.4S+// rev64 v4.4S, v28.4S+// uzp1 v7.4S, v23.4S, v23.4S+// mul v4.4S, v4.4S, v23.4S+// uaddlp v4.2D, v4.4S+// shl v4.2D, v4.2D, #32+// umlal v4.2D, v7.2S, v17.2S+// mov x8, v4.d[0]+// mov x22, v4.d[1]+// umulh x23, x20, x14+// subs x17, x20, x19+// cneg x4, x17, cc+// csetm x24, cc+// subs x17, x12, x14+// cneg x17, x17, cc+// mul x10, x4, x17+// umulh x17, x4, x17+// cinv x16, x24, cc+// eor x3, x10, x16+// eor x4, x17, x16+// adds x24, x8, x23+// adc x10, x23, xzr+// umulh x17, x19, x12+// adds x24, x24, x22+// adcs x10, x10, x17+// adc x17, x17, xzr+// adds x10, x10, x22+// adc x17, x17, xzr+// cmn x16, #0x1+// adcs x24, x24, x3+// adcs x10, x10, x4+// adc x17, x17, x16+// adds x15, x8, x8+// adcs x7, x24, x24+// adcs x8, x10, x10+// adcs x22, x17, x17+// adc x23, xzr, xzr+// movi v25.2D, #0xffffffff+// uzp2 v19.4S, v16.4S, v16.4S+// xtn v26.2S, v1.2D+// xtn v22.2S, v16.2D+// rev64 v4.4S, v16.4S+// umull v7.2D, v26.2S, v22.2S+// umull v21.2D, v26.2S, v19.2S+// uzp2 v17.4S, v1.4S, v1.4S+// mul v4.4S, v4.4S, v1.4S+// usra v21.2D, v7.2D, #32+// umull v18.2D, v17.2S, v19.2S+// uaddlp v4.2D, v4.4S+// and v7.16B, v21.16B, v25.16B+// umlal v7.2D, v17.2S, v22.2S+// shl v4.2D, v4.2D, #32+// usra v18.2D, v21.2D, #32+// umlal v4.2D, v26.2S, v22.2S+// usra v18.2D, v7.2D, #32+// mov x21, v4.d[0]+// mov x16, v4.d[1]+// mul x3, x20, x19+// mov x10, v18.d[0]+// mov x17, v18.d[1]+// umulh x4, x20, x19+// adds x24, x10, x3+// adcs x10, x16, x4+// adc x17, x17, xzr+// adds x5, x24, x3+// adcs x10, x10, x4+// adc x17, x17, xzr+// adds x11, x15, x10+// adcs x15, x7, x17+// adcs x7, x8, xzr+// adcs x8, x22, xzr+// adc x22, x23, xzr+// xtn v7.2S, v31.2D+// shrn v4.2S, v31.2D, #32+// umull v4.2D, v7.2S, v4.2S+// shl v4.2D, v4.2D, #33+// umlal v4.2D, v7.2S, v7.2S+// mov x23, v4.d[0]+// mov x16, v4.d[1]+// mul x3, x14, x12+// umulh x10, x14, x14+// umulh x17, x12, x12+// umulh x4, x14, x12+// adds x24, x10, x3+// adcs x10, x16, x4+// adc x17, x17, xzr+// adds x24, x24, x3+// adcs x10, x10, x4+// adc x17, x17, xzr+// adds x16, x23, x7+// adcs x3, x24, x8+// adcs x4, x10, x22+// adc x24, x17, xzr+// ldp x10, x17, [x0] // @slothy:reads=buffer0+// adds x10, x10, x21+// adcs x17, x17, x5+// stp x10, x17, [x0] // @slothy:writes=buffer0+// ldp x10, x17, [x0, #16] // @slothy:reads=buffer16+// adcs x10, x10, x11+// adcs x17, x17, x15+// stp x10, x17, [x0, #16] // @slothy:writes=buffer16+// ldp x10, x17, [x0, #32] // @slothy:reads=buffer32+// adcs x10, x10, x16+// adcs x17, x17, x3+// stp x10, x17, [x0, #32] // @slothy:writes=buffer32+// ldp x10, x17, [x0, #48] // @slothy:reads=buffer48+// adcs x10, x10, x4+// adcs x17, x17, x24+// stp x10, x17, [x0, #48] // @slothy:writes=buffer48+// ldr x17, [x0, #64] // @slothy:reads=buffer64+// adc x17, x17, xzr+// str x17, [x0, #64] // @slothy:writes=buffer64+// movi v25.2D, #0xffffffff+// uzp2 v19.4S, v2.4S, v2.4S+// xtn v26.2S, v5.2D+// xtn v22.2S, v2.2D+// rev64 v4.4S, v2.4S+// umull v7.2D, v26.2S, v22.2S+// umull v21.2D, v26.2S, v19.2S+// uzp2 v17.4S, v5.4S, v5.4S+// mul v4.4S, v4.4S, v5.4S+// usra v21.2D, v7.2D, #32+// umull v18.2D, v17.2S, v19.2S+// uaddlp v4.2D, v4.4S+// and v7.16B, v21.16B, v25.16B+// umlal v7.2D, v17.2S, v22.2S+// shl v4.2D, v4.2D, #32+// usra v18.2D, v21.2D, #32+// umlal v4.2D, v26.2S, v22.2S+// usra v18.2D, v7.2D, #32+// mov x5, v4.d[0]+// mov x4, v4.d[1]+// movi v25.2D, #0xffffffff+// uzp2 v17.4S, v30.4S, v30.4S+// xtn v19.2S, v0.2D+// xtn v26.2S, v30.2D+// rev64 v4.4S, v30.4S+// umull v7.2D, v19.2S, v26.2S+// umull v22.2D, v19.2S, v17.2S+// uzp2 v21.4S, v0.4S, v0.4S+// mul v4.4S, v4.4S, v0.4S+// usra v22.2D, v7.2D, #32+// umull v17.2D, v21.2S, v17.2S+// uaddlp v4.2D, v4.4S+// and v7.16B, v22.16B, v25.16B+// umlal v7.2D, v21.2S, v26.2S+// shl v4.2D, v4.2D, #32+// usra v17.2D, v22.2D, #32+// umlal v4.2D, v19.2S, v26.2S+// usra v17.2D, v7.2D, #32+// mov x24, v4.d[0]+// mov x10, v4.d[1]+// mov x17, v18.d[0]+// adds x4, x4, x17+// mov x17, v18.d[1]+// adcs x24, x24, x17+// mov x17, v17.d[0]+// adcs x10, x10, x17+// mov x17, v17.d[1]+// adc x17, x17, xzr+// adds x15, x4, x5+// adcs x4, x24, x4+// adcs x24, x10, x24+// adcs x10, x17, x10+// adc x17, xzr, x17+// adds x7, x4, x5+// adcs x8, x24, x15+// adcs x22, x10, x4+// adcs x23, x17, x24+// adcs x16, xzr, x10+// adc x3, xzr, x17+// subs x17, x14, x12+// cneg x24, x17, cc+// csetm x4, cc+// subs x17, x13, x6+// cneg x10, x17, cc+// mul x17, x24, x10+// umulh x24, x24, x10+// cinv x10, x4, cc+// cmn x10, #0x1+// eor x17, x17, x10+// adcs x23, x23, x17+// eor x17, x24, x10+// adcs x16, x16, x17+// adc x3, x3, x10+// subs x17, x20, x19+// cneg x24, x17, cc+// csetm x4, cc+// subs x17, x2, x9+// cneg x10, x17, cc+// mul x17, x24, x10+// umulh x24, x24, x10+// cinv x10, x4, cc+// cmn x10, #0x1+// eor x17, x17, x10+// adcs x11, x15, x17+// eor x17, x24, x10+// adcs x15, x7, x17+// adcs x7, x8, x10+// adcs x22, x22, x10+// adcs x23, x23, x10+// adcs x16, x16, x10+// adc x3, x3, x10+// subs x17, x19, x12+// cneg x24, x17, cc+// csetm x4, cc+// subs x17, x13, x2+// cneg x10, x17, cc+// mul x17, x24, x10+// umulh x24, x24, x10+// cinv x10, x4, cc+// cmn x10, #0x1+// eor x17, x17, x10+// adcs x8, x22, x17+// eor x17, x24, x10+// adcs x23, x23, x17+// adcs x16, x16, x10+// adc x3, x3, x10+// subs x17, x20, x14+// cneg x24, x17, cc+// csetm x4, cc+// subs x17, x6, x9+// cneg x10, x17, cc+// mul x17, x24, x10+// umulh x24, x24, x10+// cinv x10, x4, cc+// cmn x10, #0x1+// eor x17, x17, x10+// adcs x22, x15, x17+// eor x17, x24, x10+// adcs x4, x7, x17+// adcs x24, x8, x10+// adcs x23, x23, x10+// adcs x16, x16, x10+// adc x3, x3, x10+// subs x12, x20, x12+// cneg x10, x12, cc+// csetm x17, cc+// subs x12, x13, x9+// cneg x9, x12, cc+// mul x12, x10, x9+// umulh x13, x10, x9+// cinv x9, x17, cc+// cmn x9, #0x1+// eor x12, x12, x9+// adcs x4, x4, x12+// eor x12, x13, x9+// adcs x24, x24, x12+// adcs x10, x23, x9+// adcs x17, x16, x9+// adc x13, x3, x9+// subs x19, x19, x14+// cneg x12, x19, cc+// csetm x9, cc+// subs x6, x6, x2+// cneg x14, x6, cc+// mul x19, x12, x14+// umulh x12, x12, x14+// cinv x14, x9, cc+// cmn x14, #0x1+// eor x19, x19, x14+// adcs x23, x4, x19+// eor x19, x12, x14+// adcs x16, x24, x19+// adcs x6, x10, x14+// adcs x2, x17, x14+// adc x9, x13, x14+// ldp x12, x14, [x0] // @slothy:reads=buffer0+// extr x19, x6, x16, #8+// adds x10, x19, x12+// extr x19, x2, x6, #8+// adcs x17, x19, x14+// ldp x14, x12, [x0, #16] // @slothy:reads=buffer16+// extr x19, x9, x2, #8+// adcs x13, x19, x14+// and x14, x17, x13+// lsr x19, x9, #8+// adcs x6, x19, x12+// and x9, x14, x6+// ldp x14, x12, [x0, #32] // @slothy:reads=buffer32+// lsl x19, x5, #1+// adcs x2, x19, x14+// and x14, x9, x2+// extr x19, x11, x5, #63+// adcs x3, x19, x12+// and x9, x14, x3+// ldp x14, x12, [x0, #48] // @slothy:reads=buffer48+// extr x19, x22, x11, #63+// adcs x4, x19, x14+// and x14, x9, x4+// extr x19, x23, x22, #63+// adcs x24, x19, x12+// and x12, x14, x24+// ldr x14, [x0, #64] // @slothy:reads=buffer64+// extr x19, x16, x23, #63+// and x19, x19, #0x1ff+// adc x19, x14, x19+// lsr x14, x19, #9+// orr x19, x19, #0xfffffffffffffe00+// cmp xzr, xzr+// adcs xzr, x10, x14+// adcs xzr, x12, xzr+// adcs xzr, x19, xzr+// adcs x10, x10, x14+// adcs x17, x17, xzr+// adcs x13, x13, xzr+// adcs x6, x6, xzr+// adcs x2, x2, xzr+// adcs x9, x3, xzr+// adcs x12, x4, xzr+// adcs x14, x24, xzr+// adc x19, x19, xzr+// and x19, x19, #0x1ff+// stp x10, x17, [x0] // @slothy:writes=buffer0+// stp x13, x6, [x0, #16] // @slothy:writes=buffer16+// stp x2, x9, [x0, #32] // @slothy:writes=buffer32+// stp x12, x14, [x0, #48] // @slothy:writes=buffer48+// str x19, [x0, #64] // @slothy:writes=buffer64+// ldp x23, x24, [sp], #16+// ldp x21, x22, [sp], #16+// ldp x19, x20, [sp], #16+// ret+//+// The bash script used for step 2 is as follows:+//+// # Store the assembly instructions except the last 'ret',+// # callee-register store/loads as, say, 'input.S'.+// export OUTPUTS="[hint_buffer0,hint_buffer16,hint_buffer32,hint_buffer48,hint_buffer64]"+// export RESERVED_REGS="[x18,x25,x26,x27,x28,x29,x30,sp,q8,q9,q10,q11,q12,q13,q14,q15,v8,v9,v10,v11,v12,v13,v14,v15]"+// <s2n-bignum>/tools/external/slothy.sh input.S my_out_dir+// # my_out_dir/3.opt.s is the optimized assembly. Its output may differ+// # from this file since the sequence is non-deterministically chosen.+// # Please add 'ret' at the end of the output assembly.++ S2N_BN_SYM_VISIBILITY_DIRECTIVE(bignum_sqr_p521)+ S2N_BN_FUNCTION_TYPE_DIRECTIVE(bignum_sqr_p521)+ S2N_BN_SYM_PRIVACY_DIRECTIVE(bignum_sqr_p521)+ .text+ .balign 4++S2N_BN_SYMBOL(bignum_sqr_p521):+ CFI_START++// Save registers++ CFI_PUSH2(x19,x20)+ CFI_PUSH2(x21,x22)+ CFI_PUSH2(x23,x24)++ ldr q23, [x1, #32]+ ldp x9, x2, [x1, #32]+ ldr q16, [x1, #32]+ ldr q20, [x1, #48]+ ldp x6, x13, [x1, #48]+ rev64 v2.4S, v23.4S+ mul x14, x9, x2+ ldr q31, [x1, #48]+ subs x22, x9, x2+ uzp2 v26.4S, v23.4S, v23.4S+ mul v30.4S, v2.4S, v16.4S+ xtn v0.2S, v20.2D+ csetm x12, cc+ xtn v21.2S, v16.2D+ xtn v23.2S, v23.2D+ umulh x10, x9, x6+ rev64 v27.4S, v31.4S+ umull v2.2D, v21.2S, v26.2S+ cneg x23, x22, cc+ uaddlp v25.2D, v30.4S+ umull v18.2D, v21.2S, v23.2S+ mul x22, x9, x6+ mul v6.4S, v27.4S, v20.4S+ uzp2 v17.4S, v20.4S, v20.4S+ shl v20.2D, v25.2D, #32+ uzp2 v27.4S, v31.4S, v31.4S+ mul x16, x2, x13+ umlal v20.2D, v21.2S, v23.2S+ usra v2.2D, v18.2D, #32+ adds x8, x22, x10+ umull v25.2D, v17.2S, v27.2S+ xtn v31.2S, v31.2D+ movi v1.2D, #0xffffffff+ adc x3, x10, xzr+ umulh x21, x2, x13+ uzp2 v21.4S, v16.4S, v16.4S+ umull v18.2D, v0.2S, v27.2S+ subs x19, x13, x6+ and v7.16B, v2.16B, v1.16B+ umull v27.2D, v0.2S, v31.2S+ cneg x20, x19, cc+ movi v30.2D, #0xffffffff+ umull v16.2D, v21.2S, v26.2S+ umlal v7.2D, v21.2S, v23.2S+ mul x19, x23, x20+ cinv x7, x12, cc+ uaddlp v6.2D, v6.4S+ eor x12, x19, x7+ adds x11, x8, x16+ umulh x10, x23, x20+ ldr q1, [x1]+ usra v16.2D, v2.2D, #32+ adcs x19, x3, x21+ shl v2.2D, v6.2D, #32+ adc x20, x21, xzr+ adds x17, x19, x16+ usra v18.2D, v27.2D, #32+ adc x19, x20, xzr+ cmn x7, #0x1+ umlal v2.2D, v0.2S, v31.2S+ umulh x16, x9, x2+ adcs x8, x11, x12+ usra v16.2D, v7.2D, #32+ ldr x12, [x1, #64]+ eor x20, x10, x7+ umulh x10, x6, x13+ mov x23, v2.d[0]+ mov x3, v2.d[1]+ adcs x21, x17, x20+ usra v25.2D, v18.2D, #32+ and v23.16B, v18.16B, v30.16B+ adc x7, x19, x7+ adds x22, x22, x22+ ldr q7, [x1, #16]+ adcs x17, x8, x8+ umlal v23.2D, v17.2S, v31.2S+ mov x19, v16.d[0]+ mul x11, x12, x12+ ldr q4, [x1]+ usra v25.2D, v23.2D, #32+ add x5, x12, x12+ adcs x15, x21, x21+ ldr q28, [x1]+ mov x12, v20.d[1]+ adcs x24, x7, x7+ mov x21, v16.d[1]+ adc x4, xzr, xzr+ adds x19, x19, x14+ ldr q18, [x1, #16]+ xtn v26.2S, v1.2D+ adcs x8, x12, x16+ adc x21, x21, xzr+ adds x7, x19, x14+ xtn v23.2S, v7.2D+ rev64 v21.4S, v28.4S+ adcs x12, x8, x16+ ldp x20, x19, [x1]+ mov x16, v25.d[1]+ xtn v22.2S, v28.2D+ adc x14, x21, xzr+ adds x8, x22, x12+ uzp2 v24.4S, v28.4S, v28.4S+ rev64 v28.4S, v18.4S+ mul x12, x6, x13+ mul v16.4S, v21.4S, v1.4S+ shrn v31.2S, v7.2D, #32+ adcs x22, x17, x14+ mov x14, v25.d[0]+ and x21, x20, #0xfffffffffffff+ umull v17.2D, v26.2S, v24.2S+ ldr q2, [x1, #32]+ adcs x17, x15, xzr+ ldr q30, [x1, #48]+ umull v7.2D, v26.2S, v22.2S+ adcs x15, x24, xzr+ ldr q0, [x1, #16]+ movi v6.2D, #0xffffffff+ adc x4, x4, xzr+ adds x14, x14, x12+ uzp1 v27.4S, v18.4S, v4.4S+ uzp2 v19.4S, v1.4S, v1.4S+ adcs x24, x3, x10+ mul x3, x5, x21+ umull v29.2D, v23.2S, v31.2S+ ldr q5, [x1]+ adc x21, x16, xzr+ adds x16, x14, x12+ extr x12, x19, x20, #52+ umull v18.2D, v19.2S, v24.2S+ adcs x24, x24, x10+ and x10, x12, #0xfffffffffffff+ ldp x14, x12, [x1, #16]+ usra v17.2D, v7.2D, #32+ adc x21, x21, xzr+ adds x23, x23, x17+ mul x17, x5, x10+ shl v21.2D, v29.2D, #33+ lsl x10, x3, #12+ lsr x1, x3, #52+ rev64 v29.4S, v2.4S+ uaddlp v25.2D, v16.4S+ add x17, x17, x1+ adcs x16, x16, x15+ extr x3, x14, x19, #40+ mov x15, v20.d[0]+ extr x10, x17, x10, #12+ and x3, x3, #0xfffffffffffff+ shl v3.2D, v25.2D, #32+ and v6.16B, v17.16B, v6.16B+ mul x1, x5, x3+ usra v18.2D, v17.2D, #32+ adcs x3, x24, x4+ extr x4, x12, x14, #28+ umlal v6.2D, v19.2S, v22.2S+ xtn v20.2S, v2.2D+ umlal v3.2D, v26.2S, v22.2S+ movi v26.2D, #0xffffffff+ lsr x24, x17, #52+ and x4, x4, #0xfffffffffffff+ uzp2 v19.4S, v2.4S, v2.4S+ add x1, x1, x24+ mul x24, x5, x4+ lsl x4, x17, #12+ xtn v24.2S, v5.2D+ extr x17, x1, x4, #24+ adc x21, x21, xzr+ umlal v21.2D, v23.2S, v23.2S+ adds x4, x15, x10+ lsl x10, x1, #12+ adcs x15, x7, x17+ mul v23.4S, v28.4S, v4.4S+ and x7, x4, #0x1ff+ lsr x17, x1, #52+ umulh x1, x19, x12+ uzp2 v17.4S, v5.4S, v5.4S+ extr x4, x15, x4, #9+ add x24, x24, x17+ mul v29.4S, v29.4S, v5.4S+ extr x17, x24, x10, #36+ extr x10, x9, x12, #16+ uzp1 v28.4S, v4.4S, v4.4S+ adcs x17, x8, x17+ and x8, x10, #0xfffffffffffff+ umull v16.2D, v24.2S, v20.2S+ extr x10, x17, x15, #9+ mul x15, x5, x8+ stp x4, x10, [x0]+ lsl x4, x24, #12+ lsr x8, x9, #4+ uaddlp v4.2D, v23.4S+ and x8, x8, #0xfffffffffffff+ umull v23.2D, v24.2S, v19.2S+ mul x8, x5, x8+ extr x10, x2, x9, #56+ lsr x24, x24, #52+ and x10, x10, #0xfffffffffffff+ add x15, x15, x24+ extr x4, x15, x4, #48+ mul x24, x5, x10+ lsr x10, x15, #52+ usra v23.2D, v16.2D, #32+ add x10, x8, x10+ shl v4.2D, v4.2D, #32+ adcs x22, x22, x4+ extr x4, x6, x2, #44+ lsl x15, x15, #12+ lsr x8, x10, #52+ extr x15, x10, x15, #60+ and x10, x4, #0xfffffffffffff+ umlal v4.2D, v28.2S, v27.2S+ add x8, x24, x8+ extr x4, x13, x6, #32+ mul x24, x5, x10+ uzp2 v16.4S, v30.4S, v30.4S+ lsl x10, x15, #8+ rev64 v28.4S, v30.4S+ and x15, x4, #0xfffffffffffff+ extr x4, x8, x10, #8+ mul x10, x5, x15+ lsl x15, x8, #12+ adcs x23, x23, x4+ lsr x4, x8, #52+ lsr x8, x13, #20+ add x4, x24, x4+ mul x8, x5, x8+ lsr x24, x4, #52+ extr x15, x4, x15, #20+ lsl x4, x4, #12+ add x10, x10, x24+ adcs x15, x16, x15+ extr x4, x10, x4, #32+ umulh x5, x20, x14+ adcs x3, x3, x4+ usra v18.2D, v6.2D, #32+ lsl x16, x10, #12+ extr x24, x15, x23, #9+ lsr x10, x10, #52+ uzp2 v27.4S, v0.4S, v0.4S+ add x8, x8, x10+ extr x10, x3, x15, #9+ extr x4, x22, x17, #9+ and v25.16B, v23.16B, v26.16B+ lsr x17, x8, #44+ extr x15, x8, x16, #44+ extr x16, x23, x22, #9+ xtn v7.2S, v30.2D+ mov x8, v4.d[0]+ stp x24, x10, [x0, #32]+ uaddlp v30.2D, v29.4S+ stp x4, x16, [x0, #16]+ umulh x24, x20, x19+ adcs x15, x21, x15+ adc x16, x11, x17+ subs x11, x20, x19+ xtn v5.2S, v0.2D+ csetm x17, cc+ extr x3, x15, x3, #9+ mov x22, v4.d[1]+ cneg x21, x11, cc+ subs x10, x12, x14+ mul v31.4S, v28.4S, v0.4S+ cneg x10, x10, cc+ cinv x11, x17, cc+ shl v4.2D, v30.2D, #32+ umull v28.2D, v5.2S, v16.2S+ extr x23, x16, x15, #9+ adds x4, x8, x5+ mul x17, x21, x10+ umull v22.2D, v5.2S, v7.2S+ adc x15, x5, xzr+ adds x4, x4, x22+ uaddlp v2.2D, v31.4S+ lsr x5, x16, #9+ adcs x16, x15, x1+ mov x15, v18.d[0]+ adc x1, x1, xzr+ umulh x10, x21, x10+ adds x22, x16, x22+ umlal v4.2D, v24.2S, v20.2S+ umull v30.2D, v27.2S, v16.2S+ stp x3, x23, [x0, #48]+ add x3, x7, x5+ adc x16, x1, xzr+ usra v28.2D, v22.2D, #32+ mul x23, x20, x19+ eor x1, x17, x11+ cmn x11, #0x1+ mov x17, v18.d[1]+ umull v18.2D, v17.2S, v19.2S+ adcs x7, x4, x1+ eor x1, x10, x11+ umlal v25.2D, v17.2S, v20.2S+ movi v16.2D, #0xffffffff+ adcs x22, x22, x1+ usra v18.2D, v23.2D, #32+ umulh x4, x14, x14+ adc x1, x16, x11+ adds x10, x8, x8+ shl v23.2D, v2.2D, #32+ str x3, [x0, #64]+ adcs x5, x7, x7+ and v16.16B, v28.16B, v16.16B+ usra v30.2D, v28.2D, #32+ adcs x7, x22, x22+ mov x21, v3.d[1]+ adcs x11, x1, x1+ umlal v16.2D, v27.2S, v7.2S+ adc x22, xzr, xzr+ adds x16, x15, x23+ mul x8, x14, x12+ umlal v23.2D, v5.2S, v7.2S+ usra v18.2D, v25.2D, #32+ umulh x15, x14, x12+ adcs x21, x21, x24+ usra v30.2D, v16.2D, #32+ adc x1, x17, xzr+ adds x3, x16, x23+ adcs x21, x21, x24+ adc x1, x1, xzr+ adds x24, x10, x21+ umulh x21, x12, x12+ adcs x16, x5, x1+ adcs x10, x7, xzr+ mov x17, v21.d[1]+ adcs x23, x11, xzr+ adc x5, x22, xzr+ adds x1, x4, x8+ adcs x22, x17, x15+ ldp x17, x4, [x0]+ mov x11, v21.d[0]+ adc x21, x21, xzr+ adds x1, x1, x8+ adcs x15, x22, x15+ adc x8, x21, xzr+ adds x22, x11, x10+ mov x21, v3.d[0]+ adcs x11, x1, x23+ ldp x1, x10, [x0, #16]+ adcs x15, x15, x5+ adc x7, x8, xzr+ adds x8, x17, x21+ mov x23, v4.d[1]+ ldp x5, x21, [x0, #32]+ adcs x17, x4, x3+ ldr x4, [x0, #64]+ mov x3, v18.d[0]+ adcs x24, x1, x24+ stp x8, x17, [x0]+ adcs x17, x10, x16+ ldp x1, x16, [x0, #48]+ adcs x5, x5, x22+ adcs x8, x21, x11+ stp x5, x8, [x0, #32]+ adcs x1, x1, x15+ mov x15, v23.d[1]+ adcs x21, x16, x7+ stp x1, x21, [x0, #48]+ adc x10, x4, xzr+ subs x7, x14, x12+ mov x16, v18.d[1]+ cneg x5, x7, cc+ csetm x4, cc+ subs x11, x13, x6+ mov x8, v23.d[0]+ cneg x7, x11, cc+ cinv x21, x4, cc+ mov x11, v30.d[0]+ adds x4, x23, x3+ mul x22, x5, x7+ mov x23, v30.d[1]+ adcs x8, x8, x16+ adcs x16, x15, x11+ adc x11, x23, xzr+ umulh x3, x5, x7+ stp x24, x17, [x0, #16]+ mov x5, v4.d[0]+ subs x15, x20, x19+ cneg x7, x15, cc+ str x10, [x0, #64]+ csetm x1, cc+ subs x24, x2, x9+ cneg x17, x24, cc+ cinv x15, x1, cc+ adds x23, x4, x5+ umulh x1, x7, x17+ adcs x24, x8, x4+ adcs x10, x16, x8+ eor x8, x22, x21+ adcs x16, x11, x16+ mul x22, x7, x17+ eor x17, x1, x15+ adc x1, xzr, x11+ adds x11, x24, x5+ eor x7, x3, x21+ adcs x3, x10, x23+ adcs x24, x16, x24+ adcs x4, x1, x10+ eor x10, x22, x15+ adcs x16, xzr, x16+ adc x1, xzr, x1+ cmn x21, #0x1+ adcs x8, x4, x8+ adcs x22, x16, x7+ adc x7, x1, x21+ subs x21, x19, x12+ csetm x4, cc+ cneg x1, x21, cc+ subs x21, x13, x2+ cinv x16, x4, cc+ cneg x4, x21, cc+ cmn x15, #0x1+ adcs x21, x23, x10+ mul x23, x1, x4+ adcs x11, x11, x17+ adcs x3, x3, x15+ umulh x1, x1, x4+ adcs x24, x24, x15+ adcs x8, x8, x15+ adcs x22, x22, x15+ eor x17, x23, x16+ adc x15, x7, x15+ subs x7, x20, x14+ cneg x7, x7, cc+ csetm x4, cc+ subs x10, x20, x12+ cneg x23, x10, cc+ csetm x10, cc+ subs x12, x6, x9+ cinv x20, x4, cc+ cneg x12, x12, cc+ cmn x16, #0x1+ eor x1, x1, x16+ adcs x17, x24, x17+ mul x4, x7, x12+ adcs x8, x8, x1+ umulh x1, x7, x12+ adcs x24, x22, x16+ adc x7, x15, x16+ subs x12, x13, x9+ cneg x12, x12, cc+ cinv x13, x10, cc+ subs x19, x19, x14+ mul x9, x23, x12+ cneg x19, x19, cc+ csetm x10, cc+ eor x16, x1, x20+ subs x22, x6, x2+ umulh x12, x23, x12+ eor x1, x4, x20+ cinv x4, x10, cc+ cneg x22, x22, cc+ cmn x20, #0x1+ adcs x15, x11, x1+ eor x6, x12, x13+ adcs x10, x3, x16+ adcs x17, x17, x20+ eor x23, x9, x13+ adcs x2, x8, x20+ mul x11, x19, x22+ adcs x24, x24, x20+ adc x7, x7, x20+ cmn x13, #0x1+ adcs x3, x10, x23+ umulh x22, x19, x22+ adcs x17, x17, x6+ eor x12, x22, x4+ extr x22, x15, x21, #63+ adcs x8, x2, x13+ extr x21, x21, x5, #63+ ldp x16, x23, [x0]+ adcs x20, x24, x13+ eor x1, x11, x4+ adc x6, x7, x13+ cmn x4, #0x1+ ldp x2, x7, [x0, #16]+ adcs x1, x3, x1+ extr x19, x1, x15, #63+ adcs x14, x17, x12+ extr x1, x14, x1, #63+ lsl x17, x5, #1+ adcs x8, x8, x4+ extr x12, x8, x14, #8+ ldp x15, x11, [x0, #32]+ adcs x9, x20, x4+ adc x3, x6, x4+ adds x16, x12, x16+ extr x6, x9, x8, #8+ ldp x14, x12, [x0, #48]+ extr x8, x3, x9, #8+ adcs x20, x6, x23+ ldr x24, [x0, #64]+ lsr x6, x3, #8+ adcs x8, x8, x2+ and x2, x1, #0x1ff+ and x1, x20, x8+ adcs x4, x6, x7+ adcs x3, x17, x15+ and x1, x1, x4+ adcs x9, x21, x11+ and x1, x1, x3+ adcs x6, x22, x14+ and x1, x1, x9+ and x21, x1, x6+ adcs x14, x19, x12+ adc x1, x24, x2+ cmp xzr, xzr+ orr x12, x1, #0xfffffffffffffe00+ lsr x1, x1, #9+ adcs xzr, x16, x1+ and x21, x21, x14+ adcs xzr, x21, xzr+ adcs xzr, x12, xzr+ adcs x21, x16, x1+ adcs x1, x20, xzr+ adcs x19, x8, xzr+ stp x21, x1, [x0]+ adcs x1, x4, xzr+ adcs x21, x3, xzr+ stp x19, x1, [x0, #16]+ adcs x1, x9, xzr+ stp x21, x1, [x0, #32]+ adcs x21, x6, xzr+ adcs x1, x14, xzr+ stp x21, x1, [x0, #48]+ adc x1, x12, xzr+ and x1, x1, #0x1ff+ str x1, [x0, #64]++// Restore regs and return++ CFI_POP2(x23,x24)+ CFI_POP2(x21,x22)+ CFI_POP2(x19,x20)++ CFI_RET++S2N_BN_SIZE_DIRECTIVE(bignum_sqr_p521)++#if defined(__linux__) && defined(__ELF__)+.section .note.GNU-stack,"",%progbits+#endif
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff