Link for Download

Reaction_attack.ipynb

attack.sage

utils.sage

A Reaction Attack against Cryptosystems based on LRPC Codes

First we need to load auxiliary functions used in the attack and parameters

load("utils.sage")
q=2
m=5
n=30
k=20
r=3
d=3
t=ceil(d*n/(n-k)-1)

create field and polinomial ring

field_K =GF(q)
field_K_extension, iso_K_to_Kext = field_K.extension(m, 'z', map=True)
R = PolynomialRing(field_K_extension,'x', d+r+d*n+(n-k)^2, order='lex'); 
x = R.gens()

In our case, R is the bases of H and e, and the unknown coefficients of H, and the unknown coefficients of $S’$ (Sprime)

First, we create private basis and elements of H and the coefficients.

private H, S, Hknown created using the chosen bases

basisHknown=matrix(R,1,d,[field_K_extension.random_element() for a in range(d)])

coef1,coef2,coef3 = createvectorsH(n,k,d)

Hknown= creatematrixH(n,k,d,basisHknown,coef1,coef2,coef3)

S=creatematrixS(n,k)

We then generate the public key, the basis, and create a H matrix with the secret coefficients and unkown basis

Gprime=creatematrixGprime(n,k)
F=creatematrixF(n,k,Gprime,Hknown,S)

basisH=matrix(R,1,d,[x[a] for a in range(d)])
basisE=matrix(R,1,r,[x[a] for a in range(d,r+d)])
H=creatematrixH(n,k,d,basisH,coef1,coef2,coef3)
print "Matrix H is:"
print H

Matrix H is:
[     x0 + x2           x2            0      x0 + x2      x1 + x2           x2           x2           x0           x2      x0 + x1           x0           x2            0      x1 + x2           x2           x0 x0 + x1 + x2           x1           x0      x0 + x2           x1      x0 + x2 x0 + x1 + x2      x0 + x2 x0 + x1 + x2            0           x1 x0 + x1 + x2            0           x1]
[     x0 + x1      x0 + x2           x2            0      x0 + x2      x1 + x2           x2           x2           x0           x2      x0 + x2           x0           x2            0      x1 + x2           x2           x0 x0 + x1 + x2           x1           x0           x1           x1      x0 + x2 x0 + x1 + x2      x0 + x2 x0 + x1 + x2            0           x1 x0 + x1 + x2            0]
[          x2      x0 + x1      x0 + x2           x2            0      x0 + x2      x1 + x2           x2           x2           x0           x0      x0 + x2           x0           x2            0      x1 + x2           x2           x0 x0 + x1 + x2           x1            0           x1           x1      x0 + x2 x0 + x1 + x2      x0 + x2 x0 + x1 + x2            0           x1 x0 + x1 + x2]
[          x0           x2      x0 + x1      x0 + x2           x2            0      x0 + x2      x1 + x2           x2           x2           x1           x0      x0 + x2           x0           x2            0      x1 + x2           x2           x0 x0 + x1 + x2 x0 + x1 + x2            0           x1           x1      x0 + x2 x0 + x1 + x2      x0 + x2 x0 + x1 + x2            0           x1]
[          x2           x0           x2      x0 + x1      x0 + x2           x2            0      x0 + x2      x1 + x2           x2 x0 + x1 + x2           x1           x0      x0 + x2           x0           x2            0      x1 + x2           x2           x0           x1 x0 + x1 + x2            0           x1           x1      x0 + x2 x0 + x1 + x2      x0 + x2 x0 + x1 + x2            0]
[          x2           x2           x0           x2      x0 + x1      x0 + x2           x2            0      x0 + x2      x1 + x2           x0 x0 + x1 + x2           x1           x0      x0 + x2           x0           x2            0      x1 + x2           x2            0           x1 x0 + x1 + x2            0           x1           x1      x0 + x2 x0 + x1 + x2      x0 + x2 x0 + x1 + x2]
[     x1 + x2           x2           x2           x0           x2      x0 + x1      x0 + x2           x2            0      x0 + x2           x2           x0 x0 + x1 + x2           x1           x0      x0 + x2           x0           x2            0      x1 + x2 x0 + x1 + x2            0           x1 x0 + x1 + x2            0           x1           x1      x0 + x2 x0 + x1 + x2      x0 + x2]
[     x0 + x2      x1 + x2           x2           x2           x0           x2      x0 + x1      x0 + x2           x2            0      x1 + x2           x2           x0 x0 + x1 + x2           x1           x0      x0 + x2           x0           x2            0      x0 + x2 x0 + x1 + x2            0           x1 x0 + x1 + x2            0           x1           x1      x0 + x2 x0 + x1 + x2]
[           0      x0 + x2      x1 + x2           x2           x2           x0           x2      x0 + x1      x0 + x2           x2            0      x1 + x2           x2           x0 x0 + x1 + x2           x1           x0      x0 + x2           x0           x2 x0 + x1 + x2      x0 + x2 x0 + x1 + x2            0           x1 x0 + x1 + x2            0           x1           x1      x0 + x2]
[          x2            0      x0 + x2      x1 + x2           x2           x2           x0           x2      x0 + x1      x0 + x2           x2            0      x1 + x2           x2           x0 x0 + x1 + x2           x1           x0      x0 + x2           x0      x0 + x2 x0 + x1 + x2      x0 + x2 x0 + x1 + x2            0           x1 x0 + x1 + x2            0           x1           x1]

Creation of the errorList, valid messages and the ciphertexts.


errorsList=[]
for i in range(n):
	basisEknown=matrix(R,1,r,[field_K_extension.random_element() for a in range(r)])
	etemp,coef=createerrorE(n,r,basisE)
	e=createerrorEknown(n,r,basisEknown,coef)
	errorsList.append(e)


messageList=[]
for i in range(n):
	mtemp=matrix(R,1,k,[field_K_extension.random_element() for a in range(k)])
	messageList.append(mtemp)

ciphertextList=[]
for i in range(n):
	c1=messageList[i]*Gprime+errorsList[i]
	c2=messageList[i]*F
	ciphertextList.append((c1,c2))

Now, we start the attack. We create H with unknown coefficients in basisH.

Hunknown=createUnknownMatrixH(n,k,d,basisH,[x[i] for i in range(r+d,r+d+n*d)])
trials=0
repeatflag=true
while repeatflag:
	flagSuccess=false
	while not flagSuccess:
		trials+=1
        # known errors that cause decryption failures together with the corresponding kernel elements
		eknown,kerknown=FindErrorsAndKernels(H,t,n,k,r,d) 

		SunknownList=CreateSunknown(Hunknown,eknown,t,n,k,r,d)
        
        # candidate kernel elements
		kerunknown=CreateRandom(t,n,k,r,d) 
 
        # use this if you want to test the validity of the algorithm for known kernel elements
		system=CreateSystem(SunknownList,kerknown, t,n,k,r,d) 
		flagSuccess,solution=SolveSystem(system,n,k,r,d)
		print(flagSuccess, len(solution))

	print("Found valid kernel elements in ", trials, "trials")
	if flagSuccess:
		sol=FindOneSolution(solution,n,k,r,d)
		basisH=matrix(R,1,d,[x[a] for a in range(d)])
		HunknownBasis=createUnknownMatrixH(n,k,d,basisH,sol)
		# create the unknown matrix S
		MatrixSunknown=creatematrixSunknown(n,k)
        #This function uses the equivalent keys, i.e., Section 4 
		Hfound,Sfound,repeatflag=FindSolutionCoefHandS(basisH,HunknownBasis,MatrixSunknown,ciphertextList,errorsList,n,k,r,d)
		if repeatflag==false:
			# perform check on the ciphertexts
			Ffound=creatematrixF(n,k,Gprime,Hfound,Sfound.inverse())
			ciphertextFoundList=[]
			for i in range(n):
				c1=messageList[i]*Gprime+errorsList[i]
				c2=messageList[i]*Ffound
				ciphertextFoundList.append((c1,c2))
				eq=(c1-errorsList[i])*Hfound.transpose()-c2*Sfound.inverse()
			print(" ")
			print("Check whether the final solution produces the same ciphertexts...")
			countsame=0
			for i in range(n):
				if ciphertextList[i][1]==ciphertextFoundList[i][1]:
					countsame+=1
			if countsame==n:
				print ("found matrix H equals to:")
				print Hfound
				print("Everything OK! Attack successful!")
				repeatflag=false
				break
			repeatflag=false
		else:
			repeatflag=true
		################################


print("Complexity is:")
print(float(((r*d - 1)*t)+3*log(n*d,2)))
(True, 20)
('Found valid kernel elements in ', 1, 'trials')
(True, 20)
('Found valid kernel elements in ', 2, 'trials')
(True, 21)
('Found valid kernel elements in ', 3, 'trials')
(True, 21)
('Found valid kernel elements in ', 4, 'trials')
(True, 20)
('Found valid kernel elements in ', 5, 'trials')
(True, 20)
('Found valid kernel elements in ', 6, 'trials')
Found S is nonsingular
 
Check whether the final solution produces the same ciphertexts...
found matrix H equals to:
[      (z + 1)           (z) (z^3 + z + 1) (z^3 + z + 1)     (z^3 + 1)     (z^3 + 1)     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)       (z + 1)     (z^3 + 1) (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)           (z)             1 (z^3 + z + 1)             0       (z + 1)       (z + 1)     (z^3 + z)       (z + 1)     (z^3 + z)     (z^3 + z)       (z + 1)             0     (z^3 + z)     (z^3 + z)]
[      (z + 1)       (z + 1)           (z) (z^3 + z + 1) (z^3 + z + 1)     (z^3 + 1)     (z^3 + 1)     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)           (z)             1 (z^3 + z + 1)     (z^3 + z)       (z + 1)       (z + 1)     (z^3 + z)       (z + 1)     (z^3 + z)     (z^3 + z)       (z + 1)             0     (z^3 + z)]
[(z^3 + z + 1)       (z + 1)       (z + 1)           (z) (z^3 + z + 1) (z^3 + z + 1)     (z^3 + 1)     (z^3 + 1)     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)           (z)             1     (z^3 + z)     (z^3 + z)       (z + 1)       (z + 1)     (z^3 + z)       (z + 1)     (z^3 + z)     (z^3 + z)       (z + 1)             0]
[(z^3 + z + 1) (z^3 + z + 1)       (z + 1)       (z + 1)           (z) (z^3 + z + 1) (z^3 + z + 1)     (z^3 + 1)     (z^3 + 1)     (z^3 + 1)             1 (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)           (z)             0     (z^3 + z)     (z^3 + z)       (z + 1)       (z + 1)     (z^3 + z)       (z + 1)     (z^3 + z)     (z^3 + z)       (z + 1)]
[    (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)       (z + 1)       (z + 1)           (z) (z^3 + z + 1) (z^3 + z + 1)     (z^3 + 1)     (z^3 + 1)           (z)             1 (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)       (z + 1)             0     (z^3 + z)     (z^3 + z)       (z + 1)       (z + 1)     (z^3 + z)       (z + 1)     (z^3 + z)     (z^3 + z)]
[    (z^3 + 1)     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)       (z + 1)       (z + 1)           (z) (z^3 + z + 1) (z^3 + z + 1)     (z^3 + 1) (z^3 + z + 1)           (z)             1 (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1)     (z^3 + z)       (z + 1)             0     (z^3 + z)     (z^3 + z)       (z + 1)       (z + 1)     (z^3 + z)       (z + 1)     (z^3 + z)]
[    (z^3 + 1)     (z^3 + 1)     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)       (z + 1)       (z + 1)           (z) (z^3 + z + 1) (z^3 + z + 1) (z^3 + z + 1) (z^3 + z + 1)           (z)             1 (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1)             0     (z^3 + 1)     (z^3 + z)     (z^3 + z)       (z + 1)             0     (z^3 + z)     (z^3 + z)       (z + 1)       (z + 1)     (z^3 + z)       (z + 1)]
[(z^3 + z + 1)     (z^3 + 1)     (z^3 + 1)     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)       (z + 1)       (z + 1)           (z) (z^3 + z + 1)     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)           (z)             1 (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1)             0       (z + 1)     (z^3 + z)     (z^3 + z)       (z + 1)             0     (z^3 + z)     (z^3 + z)       (z + 1)       (z + 1)     (z^3 + z)]
[(z^3 + z + 1) (z^3 + z + 1)     (z^3 + 1)     (z^3 + 1)     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)       (z + 1)       (z + 1)           (z)             0     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)           (z)             1 (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1)     (z^3 + z)       (z + 1)     (z^3 + z)     (z^3 + z)       (z + 1)             0     (z^3 + z)     (z^3 + z)       (z + 1)       (z + 1)]
[          (z) (z^3 + z + 1) (z^3 + z + 1)     (z^3 + 1)     (z^3 + 1)     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)       (z + 1)       (z + 1) (z^3 + z + 1)             0     (z^3 + 1) (z^3 + z + 1) (z^3 + z + 1)           (z)             1 (z^3 + z + 1)             0     (z^3 + 1)       (z + 1)     (z^3 + z)       (z + 1)     (z^3 + z)     (z^3 + z)       (z + 1)             0     (z^3 + z)     (z^3 + z)       (z + 1)]
Everything OK! Attack successful!
Complexity is:
83.475559289