Classic McEliece on arch which doesn't like unaligned access

NIIBE Yutaka gniibe at fsij.org
Tue May 7 04:11:34 CEST 2024


Hello,

The Classic McEliece implementation assumes that unaligned access for
64-bit and 32-bit are OK.  It is not the case for some architectures.

Here is a patch to point out the issue.  Better patch is welcome.

-- 

diff --git a/cipher/mceliece6688128f.c b/cipher/mceliece6688128f.c
index 63d20a68..fc8f921c 100644
--- a/cipher/mceliece6688128f.c
+++ b/cipher/mceliece6688128f.c
@@ -841,7 +841,7 @@ static int decrypt(unsigned char *, const unsigned char *, const unsigned char *
 #ifndef ENCRYPT_H
 #define ENCRYPT_H
 
-static void pke_encrypt(unsigned char *, const unsigned char *, unsigned char *);
+static void pke_encrypt(unsigned char *, const unsigned char *, uint64_t *);
 
 #endif
 
@@ -2248,12 +2248,12 @@ static void gen_e(unsigned char *e)
 
 /* input: public key pk, error vector e */
 /* output: syndrome s */
-static void syndrome(unsigned char *s, const unsigned char *pk, unsigned char *e)
+static void syndrome(unsigned char *s, const unsigned char *pk, const uint64_t *e_aligned)
 {
+	const unsigned char *e = (const unsigned char *)e_aligned;
 	uint64_t b;
 
-	const uint64_t *pk_ptr;
-	const uint64_t *e_ptr = ((uint64_t *) (e + SYND_BYTES));
+	const uint64_t *e_ptr = (e_aligned + SYND_BYTES/8);
 
 	int i, j;
 
@@ -2264,13 +2264,19 @@ static void syndrome(unsigned char *s, const unsigned char *pk, unsigned char *e
 
 	for (i = 0; i < PK_NROWS; i++)
 	{
-		pk_ptr = ((uint64_t *) (pk + PK_ROW_BYTES * i));
+		const unsigned char *pk_ptr = pk + PK_ROW_BYTES * i;
+		uint64_t v64;
+		uint32_t v32;
 
 		b = 0;
 		for (j = 0; j < PK_NCOLS/64; j++)
-			b ^= pk_ptr[j] & e_ptr[j];
+		{
+			v64 = buf_get_he64 (pk_ptr + j * 8);
+			b ^= v64 & e_ptr[j];
+                }
 
-		b ^= ((uint32_t *) &pk_ptr[j])[0] & ((uint32_t *) &e_ptr[j])[0];
+		v32 = buf_get_he32 (pk_ptr + j * 8);
+		b ^= v32 & ((uint32_t *) &e_ptr[j])[0];
 
 		b ^= b >> 32;
 		b ^= b >> 16;
@@ -2286,8 +2292,10 @@ static void syndrome(unsigned char *s, const unsigned char *pk, unsigned char *e
 
 /* input: public key pk */
 /* output: error vector e, syndrome s */
-static void pke_encrypt(unsigned char *s, const unsigned char *pk, unsigned char *e)
+static void pke_encrypt(unsigned char *s, const unsigned char *pk, uint64_t *e_aligned)
 {
+	unsigned char *e = (unsigned char *)e_aligned;
+
 	gen_e(e);
 
 #ifdef KAT
@@ -2301,7 +2309,7 @@ static void pke_encrypt(unsigned char *s, const unsigned char *pk, unsigned char
   }
 #endif
 
-	syndrome(s, pk, e);
+	syndrome(s, pk, e_aligned);
 }
 
 
@@ -3059,12 +3067,13 @@ static void operation_enc(
        const unsigned char *pk
 )
 {
-	unsigned char e[ SYS_N/8 ];
+	uint64_t e_aligned[ (SYS_N+63)/64 ];
+	unsigned char *e = (unsigned char *)e_aligned;
 	unsigned char one_ec[ 1 + SYS_N/8 + SYND_BYTES ] = {1};
 
 	/**/
 
-	pke_encrypt(c, pk, e);
+	pke_encrypt(c, pk, e_aligned);
 
 	memcpy(one_ec + 1, e, SYS_N/8);
 	memcpy(one_ec + 1 + SYS_N/8, c, SYND_BYTES);
diff --git a/cipher/mceliece6688128f.h b/cipher/mceliece6688128f.h
index eb9f23a0..05ecac32 100644
--- a/cipher/mceliece6688128f.h
+++ b/cipher/mceliece6688128f.h
@@ -29,6 +29,7 @@
 /**** Start of the glue code to libgcrypt ****/
 #include "g10lib.h"             /* for GCC_ATTR_UNUSED */
 #include "gcrypt-int.h"
+#include "bufhelp.h"
 
 #define mceliece6688128f_keypair _gcry_mceliece6688128f_keypair
 #define mceliece6688128f_enc     _gcry_mceliece6688128f_enc
@@ -41,6 +42,8 @@
 #define GCC_ATTR_UNUSED
 #endif
 
+/* Please implement Host-endian get macros: buf_get_he32 and buf_get_he64 */
+
 #define MCELIECE6688128F_SECRETKEY_SIZE 13932
 #define MCELIECE6688128F_PUBLICKEY_SIZE 1044992
 #define MCELIECE6688128F_CIPHERTEXT_SIZE 208



More information about the Gcrypt-devel mailing list