En el 1978 McEliece presentó un nuevo criptosistema de clave pública, basado en la Teoría de los Códigos. Dado que esta teoría es muy compleja, los expertos recomiendan una familiarización matemática preliminar con la Teoría de la Codificación, los Códigos de Goppa, y los Cuerpos de Galois.
En el sistema de McEliece, cada usuario ha de elegir un polinomio irreducible de grado delta, y construir una matriz generadora del correspondiente código de Goppa, matriz G, de orden k x n. También ha de calcular la llave pública, que es una matriz generadora del código Goppa. Este código debe ser tal que no exista un algoritmo computable que corrija los errores con éste código en un tiempo pequeño. La llave pública es obtenida a partir de la multiplicación de una matriz aleatoria no singular de orden 2^m-k*m, y una matriz de permutaciones de orden 2^m. Todos los usuarios del sistema mantienen sus respectivas llaves públicas, mientras que las matrices S,G e P serán secretas.
A continuación presentamos el algoritmo para generación de las llaves, cifrado de un texto plano y descifrado de un texto cifrado, según wikipedia, y su respectiva implementación mediante un ejemplo en SAGE. Es necesario "correr" primero la última de las celdas de este post, la cual contiene los algoritmos auxiliares como por ejemplo el algoritmo de Patterson.
Generación de Llaves
- Alicia selecciona un código de Goppa binario Gamma com parâmetros (n,k) y capacidad de correción de delta errores;
- Alicia gera a matriz geradora G, de dimensiones n-m*k x n, del código \Gamma; Selecciona una matriz binaria no singular S, de dimensiones;n-m*k x n-m*k;
- Selecciona una matriz de permutación P, de dimensión n;
- Computa a matriz $G' = SGP;
- La llave pública de Alicia é (G',delta) y su llave privada es (S,G,P).
xxxxxxxxxx
m = 4;delta = 3;N = 2^m
K_.<a> = GF(2);
F.<a> = GF(2^m);#creado el campo donde "vivirá" el código
PR = PolynomialRing(F,'X')
X = PR.gen()
g = X^3+X+1# Polinomio de Goppa
L = [a^i for i in range(N)] # Soporte del codigo
xxxxxxxxxx
T = matrix(F,delta,delta)
for i in range(delta):
count = delta - i + 1 - 1
for j in range(delta):
if i > j:
T[i,j]=g.list()[count]
count = count + 1
if i < j:
T[i,j] = 0
if i == j:
T[i,j] = 1
V = matrix([[L[j]^i for j in range(N)] for i in range(delta)])
D = diagonal_matrix([1/g(L[i]) for i in range(N)])
H = T*V*D
H_Goppa_K = matrix(K_, m*H.nrows(),H.ncols())
for i in range(H.nrows()):
for j in range(H.ncols()):
be = bin(eval(H[i,j].int_repr()))[2:];
be = '0'*(m-len(be))+be; be = list(be);
H_Goppa_K[m*i:m*(i+1),j]=vector(map(int,be));
print H_Goppa_K
xxxxxxxxxx
Krnl = H_Goppa_K.right_kernel();
G = Krnl.basis_matrix();
S = random_matrix(GF(2), N-m*delta)
while (S.determinant()==0):
S = random_matrix(GF(2), N-m*delta)
rng = range(N);
P = matrix(GF(2),N);
for i in range(N):
p = floor(len(rng)*random());
P[i,rng[p]]=1; rng=rng[:p]+rng[p+1:];
G_pub = S*G*P
print G_pub
- Bob cifra el mensaje m como una cadena binaria de tamaño n-m*delta;
- Bob computa el vector c' = mG';
- Bob genera un vector de tamaño n randomico conteniendo hasta delta unos
- Bob computa el texto cifrado como c = c' + z.
xxxxxxxxxx
u = vector(K_,[randint(0,1) for _ in range(G_pub.nrows())])
c = u*G_pub
print 'u=',u
print 'c=',c
e = vector(K_,N)
e[8] = 1
e[9] = 1
print 'e=',e
y = c + e
print 'y',y
- Alice computa el inverso de P
- Alice computa cP^{-1}.
- Alice usa un algoitmo de decodificación para el código G y decodifica c en m' .
- Alice computa m'S .
xxxxxxxxxx
yP = y*(P.inverse())
yd= decodePatterson(yP)
print (G.transpose()\yd)*S.inverse()
xxxxxxxxxx
def split(p):
# split polynomial p over F into even part po
# and odd part p1 such that p(z) = p2 (z) + z p2 (z)
Phi1 = p.parent()
p0 = Phi1([sqrt(c) for c in p.list()[0::2]])
p1 = Phi1([sqrt(c) for c in p.list()[1::2]])
return (p0,p1)
def xgcdm1(self, other):
delta = self.degree()
if other.is_zero():
R = self.parent()
return self, R.one_element(), R.zero_element()
# Algorithm 3.2.2 of Cohen, GTM 138
R = self.parent()
A = self
B = other
U = R.one_element()
G = A
V1 = R.zero_element()
V3 = B
while true:
Q,R = G.quo_rem(V3)
T = U - V1*Q
U = V1
G = V3
V1 = T
V3 = R
if V3.degree() <= floor((delta-1)/2) and G.degree() <= floor((delta)/2):
#if V3.degree() < floor((delta-1)/2):# or Q.degree() < floor((delta-1)/2):#(delta-2)/2)):# or V3 == 0:
break
V = (G-A*U)//B
lc = G.leading_coefficient()
return G/lc, U/lc, V/lc
def g_inverse(p,g):
(d,u,v) = xgcd(p,g)
return u.mod(g)
def binPolyToF_Poly(X, a, PR, delta, m, v):
polySym = PR(0)
sum = PR(0)
count = delta-1
for i in range(len(v)):
j = mod(i,m)
if j == 0 and i>1:
polySym = polySym + (X^count)*sum
sum = 0
count = count - 1
sum = sum + v[i]*a^(m-j-1)
polySym = polySym + (X^count)*sum
return polySym
def decodePatterson(y):
s2 = H_Goppa_K*y
#print 's2',s2
X1 = X;
g1 = g
#polSyn1 = PR(0);
#for i in range(len(s2)):
# polSyn1 = polSyn1 + s2[i]*(X1^(len(s2)-i-1))
polSyn1 = binPolyToF_Poly(X1, a, PR, delta, m, s2)
#print 'sydrome',polSyn1
g0g1 = split(g1);
w = ((g0g1[0])*g_inverse(g0g1[1],g1)).mod(g1)
#print g_inverse(polSyn1,g1)
T0T1 = split(g_inverse(polSyn1,g1) + X1)
R = (T0T1[0]+(w)*(T0T1[1])).mod(g1)
(a11,b11,c11) = xgcdm1(g1,R);
#print 'a11',a11,'\nc11',c11,'\nR',R,'\ng1',g1
sigma = a11^2+X1*(c11^2)
#print 'sigma',sigma
#print sigma.roots()
#for i in range(len(sigma.roots())):
# print 'Hola', sigma.roots()[i]
for i in range(N):
if (sigma(a^i)==0): # an error occured
print 'error position',i
y[i] = y[i] + 1
return y
No comments:
Post a Comment