-rw-r--r-- 8543 mceliece-sage-20221023/parameters.sage raw
F2 = GF(2)
F2z.<z> = F2[]
F2zy.<y> = F2z[]
f12 = z^12+z^3+1
f13 = z^13+z^4+z^3+z+1
F64 = y^64+y^3+y+z
F96 = y^96+y^10+y^9+y^6+1
F119 = y^119+y^8+1
F128 = y^128+y^7+y^2+y+1
selected = {
# "mceliece348864": "m = 12, n = 3488, t = 64. Field polynomials f(z) = z^12+z^3+1 and F(y) = y^64+y^3+y+z."
'mceliece348864':{'m':12,'n':3488,'t':64,'f':f12,'F':F64},
# "mceliece348864f": "m = 12, n = 3488, t = 64. Field polynomials f(z) = z^12+z^3+1 and F(y) = y^64+y^3+y+z. Semi-systematic parameters (mu,nu) = (32,64)."
'mceliece348864f':{'m':12,'n':3488,'t':64,'f':f12,'F':F64,'mu':32,'nu':64},
# "mceliece460896": "m = 13, n = 4608, t = 96. Field polynomials f(z) = z^13+z^4+z^3+z+1 and F(y) = y^96+y^10+y^9+y^6+1."
'mceliece460896':{'m':13,'n':4608,'t':96,'f':f13,'F':F96},
# "mceliece460896f": "m = 13, n = 4608, t = 96. Field polynomials f(z) = z^13+z^4+z^3+z+1 and F(y) = y^96+y^10+y^9+y^6+1. Semi-systematic parameters (mu,nu) = (32,64)."
'mceliece460896f':{'m':13,'n':4608,'t':96,'f':f13,'F':F96,'mu':32,'nu':64},
# "mceliece6688128": "m = 13, n = 6688, t = 128. Field polynomials f(z) = z^13+z^4+z^3+z+1 and F(y) = y^128+y^7+y^2+y+1."
'mceliece6688128':{'m':13,'n':6688,'t':128,'f':f13,'F':F128},
# "mceliece6688128f": "m = 13, n = 6688, t = 128. Field polynomials f(z) = z^13+z^4+z^3+z+1 and F(y) = y^128+y^7+y^2+y+1. Semi-systematic parameters (mu,nu) = (32,64)."
'mceliece6688128f':{'m':13,'n':6688,'t':128,'f':f13,'F':F128,'mu':32,'nu':64},
# "mceliece6960119": "m = 13, n = 6960, t = 119. Field polynomials f(z) = z^13+z^4+z^3+z+1 and F(y) = y^119+y^8+1."
'mceliece6960119':{'m':13,'n':6960,'t':119,'f':f13,'F':F119},
# "mceliece6960119f": "m = 13, n = 6960, t = 119. Field polynomials f(z) = z^13+z^4+z^3+z+1 and F(y) = y^119+y^8+1. Semi-systematic parameters (mu,nu) = (32,64)."
'mceliece6960119f':{'m':13,'n':6960,'t':119,'f':f13,'F':F119,'mu':32,'nu':64},
# "mceliece8192128": "m = 13, n = 8192, t = 128. Field polynomials f(z) = z^13+z^4+z^3+z+1 and F(y) = y^128+y^7+y^2+y+1."
'mceliece8192128':{'m':13,'n':8192,'t':128,'f':f13,'F':F128},
# "mceliece8192128f": "m = 13, n = 8192, t = 128. Field polynomials f(z) = z^13+z^4+z^3+z+1 and F(y) = y^128+y^7+y^2+y+1. Semi-systematic parameters (mu,nu) = (32,64)."
'mceliece8192128f':{'m':13,'n':8192,'t':128,'f':f13,'F':F128,'mu':32,'nu':64},
}
f9 = z^9+z^1+1 # for testing
f10 = z^10+z^3+1 # for testing
F20 = z^20+z^3+1 # for testing
F50 = y^50+y^5+y^2+z # for testing
testing = {
'mceliece51220f':{'m':9,'n':512,'t':20,'f':f9,'F':F20,'mu':32,'nu':64},
'mceliece51220':{'m':9,'n':512,'t':20,'f':f9,'F':F20},
'mceliece102450f':{'m':10,'n':1024,'t':50,'f':f10,'F':F50,'mu':32,'nu':64},
'mceliece102450':{'m':10,'n':1024,'t':50,'f':f10,'F':F50},
}
supportpc = True # for testing against previous versions
if supportpc:
for which in selected,testing:
for system in list(which):
systempc = system+'pc'
systempc = systempc.replace('fpc','pcf')
assert systempc not in which
which[systempc] = dict(which[system])
which[systempc]['pc'] = True
alltests = list(testing)+list(selected)
import byterepr
import hashlib
class parameters:
def __init__(self,system,checkirred=False,allowtestparams=False):
r'''
Return one of the selected Classic McEliece parameter sets,
specifically the one named by "system".
INPUT:
"system" - a string such as 'mceliece6960119'
"checkirred" (optional, default False) -
check irreducibility of the f and F polynomials
"allowtestparams" (optional, default False) -
allow test parameter sets, not just selected parameter sets
'''
if allowtestparams and system in testing:
S = testing[system]
else:
assert system in selected
S = selected[system]
m = S['m']
n = S['n']
t = S['t']
f = S['f']
F = S['F']
if 'mu' in S and 'nu' in S:
mu = S['mu']
nu = S['nu']
else:
# "parameter sets that do not mention these parameters define them as (0,0) by default"
mu = 0
nu = 0
q = 1<<m
k = n-m*t
if supportpc:
self.pc = S.get('pc',False)
# "positive integer m"
assert parent(m) is ZZ
assert m > 0
self.m = m
# "also defines a parameter q = 2^m"
assert parent(q) is ZZ
assert q == 2^m
self.q = q
# "positive integer n with n <= q"
assert parent(n) is ZZ
assert n > 0
assert n <= q
self.n = n
# "positive integer t >= 2 with mt < n"
assert parent(t) is ZZ
assert t >= 2
assert m*t < n
self.t = t
# "also defines a parameter k = n-mt"
assert parent(k) is ZZ
assert k == n-m*t
self.k = k
# "monic irreducible polynomial f(z) in F_2[z] of degree m"
assert parent(f) is F2z
assert f.is_monic()
if checkirred: assert f.is_irreducible()
assert f.degree() == m
self.f = f
# "defines a representation F2[z]/f(z) of the field Fq"
Fq.<zinFq> = GF(q,name='zinFq',modulus=f,check_irreducible=checkirred)
assert Fq.is_field()
assert Fq.cardinality() == q
self.Fq = Fq
F = F.change_ring(Fq) # now F is in Fq[y] instead of F2[z][y]
# "monic irreducible polynomial F(y) in F_q[y] of degree t"
assert F.base_ring() == Fq
assert F.is_monic()
if checkirred: assert F.is_irreducible()
assert F.degree() == t
self.F = F
# "defines a representation F_q[y]/F(y) of the field F_{q^t} = F_{2^{mt}}"
Fqt.<yinFqt> = Fq.extension(F) # no easy way to pass checkirred to this
assert Fqt.is_field()
assert Fqt.cardinality() == q^t
self.Fqt = Fqt
# "integers nu >= mu >= 0 with nu <= k+mu"
assert parent(mu) is ZZ
assert parent(nu) is ZZ
assert nu >= mu
assert mu >= 0
assert nu <= k+mu
self.mu = mu
self.nu = nu
# ----- symmetric-cryptography parameters
# "positive integer l"
# selected symmetric-cryptography parameters:
# "The integer l is 256"
l = 256
self.l = l
# "integer sigma1 >= m"
# selected symmetric-cryptography parameters:
# "The integer sigma1 is 16"
sigma1 = 16
assert sigma1 >= m
self.sigma1 = sigma1
# "integer sigma2 >= 2m"
# selected symmetric-cryptography parameters:
# "The integer sigma2 is 32"
sigma2 = 32
assert sigma2 >= 2*m
self.sigma2 = sigma2
# extra parameter constraints for the H,G implementations below,
# all satisfied by the selected parameter sets:
assert n%8 == 0
assert l%8 == 0
assert sigma1%8 == 0
assert sigma2%8 == 0
def shake256(input,outlen):
h = hashlib.shake_256()
h.update(input)
return h.digest(int(outlen))
# "cryptographic hash function H that outputs l bits"
def H(x):
# selected symmetric-cryptography parameters:
# "The l-bit string H(x) is defined as the first l bits of output of SHAKE256(x)."
outlen = l
assert outlen%8 == 0
inbytes = byterepr.from_hashinput(x,self)
if supportpc and self.pc:
# for testing against previous versions
assert list(bytearray(inbytes[0:1])) in ([0],[1],[2])
else:
# "All H inputs used in Classic McEliece begin with byte 0 or 1"
assert list(bytearray(inbytes[0:1])) in ([0],[1])
result = shake256(inbytes,outlen/8)
return byterepr.to_vector(result,outlen)
self.H = H
# "pseudorandom bit generator G mapping a string of l bits
# to a string of n + sigma2 q + sigma1 t + l bits"
def G(delta):
# selected symmetric-cryptography parameters:
# "The (n + sigma_2 q + sigma_1 t + l)-bit string G(delta)
# is defined as the first n + sigma_2 q + sigma_1 t + l bits
# of output of SHAKE256(64,delta).
# Here 64,delta means the 33-byte string
# that begins with byte 64 and continues with delta."
inbytes = byterepr.from_vector(delta)
inbytes = bytes(bytearray([64]))+inbytes
outlen = n+sigma2*q+sigma1*t+l
assert outlen%8 == 0
# G input begins with byte 64
assert list(bytearray(inbytes[0:1])) == [64]
result = shake256(inbytes,outlen/8)
return byterepr.to_vector(result,outlen)
self.G = G
# ----- miscellaneous tests
def test_assertions():
for system in selected:
print('parameters %s' % system)
sys.stdout.flush()
P = parameters(system,checkirred=True)
assert P.m == selected[system]['m']
assert P.n == selected[system]['n']
assert P.t == selected[system]['t']
if __name__ == '__main__':
test_assertions()