I am using this library to try and make a mceliece encrypter with reed solomon. My problem is when I try to decrypt, after applying P_inv the decoder does not recognize the coded data and gives me an error. I cannot apply S_inv before using the decoder as the matrix sizes do not match. I know the library is not focusded in cryptography but in error correction, anyway I am trying to use it correction capability to get mceliece to work as secure as possible and faster than with the goppa codes. My code is:
from ecc import galois as g
from ecc import reed_solomon as rs
from ecc import polynomial as p
from Crypto.Random import get_random_bytes
import numpy as np
import random
import os
def generate_permutation_matrix(n):
# Crear una matriz identidad
P = np.eye(n, dtype=int)
# Generar una permutación aleatoria
perm = np.random.permutation(n)
# Reorganizar las filas de la matriz identidad de acuerdo con la permutación
P = P[perm]
return P
def generate_keys(key_length, priv_key_name, pub_key_name):
# Crear el campo GF 2^8
field = g.Field(reversed([1, 0, 0, 0, 1, 1, 1, 0, 1]), p=2)
# La matriz G es la matriz generadora del código Reed-Solomon G
k = key_length
n = 254
gen = rs.generator(field, n)
msg = [0] * k
rev = msg[:]
msg_encoded = msg[:] * k
# Crear la matriz generadora
G = np.zeros((k, n), dtype=int)
for i in range(k):
G[i, i] = 1 # Matriz de identidad
for j in range(k): #Matriz parities
msg[j] = G[i, j]
for j in range(k): #reverse
rev[k-1-j] = msg[j]
rev_encoded = rs.encode(rev, gen)
for j in range(n): #un-reverse
msg_encoded[n-1-j] = rev_encoded[j]
for j in range(n-k):
G[i, k+j] = msg_encoded[k+j]
# Generar una matriz S invertible de tamaño k × k
S = np.random.randint(0, 2, size=(k, k))
while np.linalg.det(S) == 0: # asegurarse de que la matriz es invertible ya que su determinante debe ser distinto de zero para que lo sea
S = np.random.randint(0, 2, size=(k, k))
# Generar una matriz de permutación P de tamaño n × n
P = generate_permutation_matrix(n)
# print("Matriz S:")
# print(S)
# print("Matriz P:")
# print(P)
# print("Matriz G:")
#print(G)
# Paso 3: Generar las claves
# La clave pública es la matriz G1 = SGP
if not os.path.exists(priv_key_name):
with open(pub_key_name, 'wb') as f:
pass
with open(priv_key_name, 'wb') as f:
pass
pub_key = np.dot(S, np.dot(G, P))
np.savez_compressed(pub_key_name, pub_key=pub_key)
# La clave privada es la terna (S, gen, P)
np.savez_compressed(priv_key_name, S=S, gen_coeffs=gen.coeffs, P=P)
def encrypt(pub_key_name, msg):
pub_key_data = np.load(str(pub_key_name), allow_pickle=True)
# print(pub_key_name)
pub_key = pub_key_data['pub_key']
# msg_encoded = rs.encode(msg, gen)
print(np.shape(pub_key))
print(len(msg))
msg_encrypted = np.dot(msg, pub_key)
for _ in range(111):
# Elige una posición aleatoria en el rango de los datos codificados
pos = random.randint(0, len(msg_encrypted) - 1)
# Cambia el byte en esa posición a un valor aleatorio en el rango del campo Galois
msg_encrypted[pos] = random.randint(0, 1)
return msg_encrypted
def decrypt(priv_key_name, msg_encrypted, password):
private_key_data = np.load(str(priv_key_name), allow_pickle=True)
S = private_key_data['S']
gen_coeffs = private_key_data['gen_coeffs']
P = private_key_data['P']
field = g.Field(reversed([1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1]), p=2)
gen = p.Polynomial(field, gen_coeffs)
print(gen.field)
S_inv = np.linalg.inv(S)
P_inv = np.linalg.inv(P)
# Aplicar la inversa de la matriz de permutación a la palabra de código
msg_encrypted = np.dot(msg_encrypted, P_inv)
# Decodificar la palabra de código utilizando la matriz generadora
msg_encrypted = rs.decode(msg_encrypted, gen)
msg = np.dot(msg_encrypted, S_inv)
# Aplicar la inversa de la matriz de dispersión al mensaje
return msg
def main():
key = get_random_bytes(32)
password = ''
generate_keys(32, 'priv_key.npz', 'pub_key.npz')
key_enc = encrypt('pub_key.npz', list(key))
key_dec = decrypt('priv_key.npz', key_enc, password)
assert key==key_dec
if __name__ == "__main__":
main()
I have tried changing the library, the way I generate the keys but i cannot get it to work, the error I am currently given is:
Traceback (most recent call last):
File "test.py", line 25, in <module>
main()
File "\test.py", line 17, in main
decrypted_key = decrypt(priv_key_name, encrypted_key, password)
File "\mceliece.py", line 106, in decrypt
msg_encrypted = rs.decode(msg_encrypted, gen)
File "C:\Users\x\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\ecc\reed_solomon.py", line 27, in decode
synd = syndrome(msg, gen)
File "C:\Users\x\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\ecc\reed_solomon.py", line 48, in syndrome
return [p.eval(field.exp[i]) for i in range(degree)]
File "C:\Users\x\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\ecc\reed_solomon.py", line 48, in <listcomp>
return [p.eval(field.exp[i]) for i in range(degree)]
File "C:\Users\x\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\ecc\polynomial.py", line 43, in eval
result = self.field.add(result, c)
File "C:\Users\x\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\ecc\galois.py", line 52, in add
pairs = zip(self.to_poly[x], self.to_poly[y])
KeyError: 31869579.0
Looking at the RS library you were using, the ordering of data is not standard, making it awkward to generate G compatible with rs.encode(). From your comments, I see you have switched to another RS library.
I modified one of my ECC programs written in C to do McEliece encryption. Here is a simple example using GF(2^8), K = 9, N = 15