def phi_RMFE35(v): ###print 'Applying phi to', v if len(v)>_sage_const_99 : w=[] number_blocks=len(v)//_sage_const_99 +_sage_const_1 for i in range(number_blocks-_sage_const_1 ): w.append(v[_sage_const_99 *i:_sage_const_99 *i+_sage_const_99 ]) w.append(v[_sage_const_99 *(number_blocks-_sage_const_1 ):]) res=[] for j in range(len(w)): res=res+phi_RMFE35(w[j]) return res #First step, split the binary vector in blocks of three cordinates (fill in left-over block with zeros), apply (3,5)_2-RMFE to each block. else: k=len(v) modthree=k%_sage_const_3 if modthree==_sage_const_1 : v=v+[_sage_const_0 ,_sage_const_0 ] l=_sage_const_2 elif modthree==_sage_const_2 : v.append(_sage_const_0 ) l=_sage_const_1 else: l=_sage_const_0 v1=[] for i in range((k+l)//_sage_const_3 ): t=map35(v[_sage_const_3 *i:_sage_const_3 *i+_sage_const_3 ]) v1.append(t) #Second step, apply (k',65)_32-RMFE to result v1. Here k'=length(v1)<=33. Apply inverse FFT to first 32 elements, obtaining an interpolating polynomial of degree <=31. If input has a 33-th coordinate, adjust result by summing an appropriate multiple of X^32-X. Map the <=32-degree polynomial into an element of F_(32^65) and represent it as an element of F_(2^325) via field_iso_desc while len(v1)<_sage_const_32 : v1.append(_sage_const_0 ) #We generate the preprocessing data for the FFT (TODO: having this as a preprocessing would only be useful if the precomputation would be used for more than one evaluation of phi, not the case currently). B=[a**i for i in range(_sage_const_5 )] data=FFTpreproc(_sage_const_5 ,B) #Apply inverse FFT v2=invbinaryFFT(v1,_sage_const_5 ,B,data) #Represent result as polynomial m=_sage_const_0 for i in range(len(v2)): m+=v2[i]*Y**i #Adjust evaluation at point at infinity if necessary. if len(v1)==_sage_const_33 : m+=v1[_sage_const_32 ]*(Y**_sage_const_32 -Y) #Map the <=32-degree polynomial from F_32[X] into an element of F_(2^325) via field_iso_desc (by implicitely first mapping into an element of F_(32^65) and then changing to a representation in F_2^(325)). r=field_iso_desc(m,_sage_const_5 ,g,h,F,H,P,R) return [r]
def phi_RMFE23(v): if len(v)>_sage_const_18 : #If the vector is of length >18, then split the vector in blocks of 18, apply map to each block. w=[] number_blocks=len(v)//_sage_const_18 +_sage_const_1 for i in range(number_blocks-_sage_const_1 ): w.append(v[_sage_const_18 *i:_sage_const_18 *i+_sage_const_18 ]) w.append(v[_sage_const_18 *(number_blocks-_sage_const_1 ):]) res=[] for j in range(len(w)): res=res+phi_RMFE23(w[j]) return res else: #First step, split the binary vector in blocks of two cordinates (fill in left-over block with zeros), apply (2,3)_2-RMFE to each block. k=len(v) odd=k%_sage_const_2 if odd: v.append(_sage_const_0 ) l=_sage_const_1 else: l=_sage_const_0 v1=[] for i in range((k+l)//_sage_const_2 ): t=map23(v[_sage_const_2 *i:_sage_const_2 *i+_sage_const_2 ]) v1.append(t) #Second step, apply (k',17)_8-RMFE to result v1. Here k'=length(v1)<=9. Apply inverse FFT to the first 8 coordinates of v1 (filling in with zeros if necessary), obtaining an interpolating polynomial of degree <=7. If length(v1)=9, then sum a multiple of X^8+X so that the X^8 coeficient is the 9-th coordinate. Note this operation does not change the evaluation of the polynomial in F_8. Map the <=8-degree polynomial into an element of F_(8^17) and represent it as an element of F_(2^51) via field_iso_desc while len(v1)<_sage_const_8 : v1.append(_sage_const_0 ) #We generate the preprocessing data for the FFT (TODO: having this as a preprocessing would only be useful if the precomputation would be used for more than one evaluation of phi_RMFE23, not the case currently). B=[a**i for i in range(_sage_const_3 )] data=FFTpreproc(_sage_const_3 ,B) #Apply inverse FFT v2=invbinaryFFT(v1,_sage_const_3 ,B,data) #Represent result as polynomial m=_sage_const_0 for i in range(len(v2)): m+=v2[i]*Y**i #Adjust evaluation at point at infinity if necessary. if len(v1)==_sage_const_9 : m+=v1[_sage_const_8 ]*(Y**_sage_const_8 -Y) #Map the <=15-degree polynomial from F_16[X] into an element of F_(2^128) via field_iso_desc (by implicitely first mapping into an element of F_(16^32) and then changing to a representation in F_2^(128)). r=field_iso_desc(m,_sage_const_3 ,g,h,F,H,P,R) return [r]
def psi_RMFE23(w, k): ###print ('lengths', len(w), len(k)) if len(w) != len(k): raise Exception("inputs to psi_RMFE23 must be of same length") for i in range(len(k)): if k[i] > _sage_const_18: raise Exception( "every coordinate on second input of psi_RMFE need to be at most 18") B = [a**i for i in range(_sage_const_3)] data = FFTpreproc(_sage_const_3, B) ###print ('Applying psi to', w) res = [] for j in range(len(w)): # First change field representation to represent input as element of F_(8^17) and hence as a polynomial in F_8[X] of degree at most 16. m = field_iso_asc(w[j], _sage_const_3, g, R) m = list(m) ###print ('After translating to F_8', m) # Before applying the FFT we need to a polynomial of degree <=8. For this we take modulo X^8+X, as this does not modify evaluation in points of F_8: hredi = listsum(m[_sage_const_0:_sage_const_8], [ _sage_const_0]+m[_sage_const_8:_sage_const_15]) hred = listsum(hredi[:], [_sage_const_0]+m[_sage_const_15:]) ###print ('After reduction', hred) # Apply FFT w1 = binaryFFT(hred, _sage_const_3, B, data) ###print ('After applying FFT we get', w1) # Based on value of k, we adjust size of the output. If k is 17 or 18 we need to add the evaluation in the point at infinity. if k[j] >= _sage_const_17: if len(m) >= _sage_const_17: w1.append(m[_sage_const_16]) else: w1.append(_sage_const_0) else: upper = (k[j]+_sage_const_1)//_sage_const_2 del w1[upper:] ###print ('After adjusting we get', w1) # Apply psi from (2,3)_2-RMFE to each element of resulting vector. r = [] for i in range(len(w1)): r = r+invmap23(w1[i]) # Adjust size of output. del r[k[j]:] # Concatenate this to global vector. res = res+r return res
def phi_RMFE24(v): if len(v) > _sage_const_32: w = [] number_blocks = len(v) // _sage_const_32 + _sage_const_1 for i in range(number_blocks - _sage_const_1): w.append(v[_sage_const_32 * i:_sage_const_32 * i + _sage_const_32]) w.append(v[_sage_const_32 * (number_blocks - _sage_const_1):]) res = [] for j in range(len(w)): res = res + phi_RMFE24(w[j]) return res # First step, split the binary vector in blocks of two cordinates (fill in left-over block with zeros), apply (2,4)_2-RMFE to each block. else: k = len(v) odd = k % _sage_const_2 if odd: v.append(_sage_const_0) l = _sage_const_1 else: l = _sage_const_0 v1 = [] for i in range((k + l) // _sage_const_2): t = map24(v[_sage_const_2 * i:_sage_const_2 * i + _sage_const_2]) v1.append(t) # Second step, apply (k',32)_16-RMFE to result v1. Here k'=length(v1)<=16. Apply inverse FFT to v1, obtaining an interpolating polynomial of degree <=15. Map the <=15-degree polynomial into an element of F_(16^32) and represent it as an element of F_(2^128) via field_iso_desc while len(v1) < _sage_const_16: v1.append(_sage_const_0) # We generate the preprocessing data for the FFT (TODO: having this as a preprocessing would only be useful if the precomputation would be used for more than one evaluation of phi, not the case currently). B = [a**i for i in range(_sage_const_4)] data = FFTpreproc(_sage_const_4, B) # Apply inverse FFT v2 = invbinaryFFT(v1, _sage_const_4, B, data) # Represent result as polynomial m = _sage_const_0 for i in range(len(v2)): m += v2[i] * Y**i # Map the <=15-degree polynomial from F_16[X] into an element of F_(2^128) via field_iso_desc (by implicitely first mapping into an element of F_(16^32) and then changing to a representation in F_2^(128)). r = field_iso_desc(m, _sage_const_4, g, h, F, H, P, R) return [r]
def psi_RMFE35(w, k): if len(w) != len(k): raise Exception("inputs to psi_RMFE24 must be of same length") for i in range(len(k)): if k[i] > _sage_const_99: raise Exception( "every coordinate on second input of psi_RMFE24 needs to be at most 99" ) B = [a**i for i in range(_sage_const_5)] data = FFTpreproc(_sage_const_5, B) res = [] for j in range(len(w)): # First change field representation to represent input as element of F_(32^65) and hence as a polynomial in F_32[X] of degree at most 64. m = field_iso_asc(w[j], _sage_const_5, g, R) m = list(m) # Before applying the FFT we need to a polynomial of degree <=31. For this we take modulo X^32+X, as this does not modify evaluation in points of F_32: hred = listsum(m[_sage_const_0:_sage_const_32], [_sage_const_0] + m[_sage_const_32:_sage_const_63]) hred = listsum(hred, [_sage_const_0] + m[_sage_const_63:]) # Apply FFT w1 = binaryFFT(hred, _sage_const_5, B, data) # Based on value of k, we adjust size of the output. If k is between 97 and 99 we need to add the evaluation in the point at infinity. if k[j] >= _sage_const_97: if len(m) > _sage_const_64: w1.append(m[_sage_const_64]) else: w1.append(_sage_const_0) else: upper = (k[j] + _sage_const_2) // _sage_const_3 del w1[upper:] # Apply psi from (3,5)_2-RMFE to each element of resulting vector. r = [] for i in range(len(w1)): r = r + invmap35(w1[i]) # Adjust size of output. del r[k[j]:] # Concatenate this to global vector. res = res + r return res
def eval(p, instance): e1 = instance.e1 F = instance.F a = instance.a R = instance.R Y = instance.Y B = [a**i for i in range(e1)] if len(p) == _sage_const_2**e1 or _sage_const_2**e1 + _sage_const_1: data = FFTpreproc(e1, B) v2 = binaryFFT(p[_sage_const_0:_sage_const_2**e1], e1, B, data) return v2 if len(w) == _sage_const_2**e1 + _sage_const_1: w.append(p[-_sage_const_1]) else: EvalPoints = lin(B)[:len(p)] return [R(p)(EvalPoints[i]) for i in range(len(p))]
def psi_RMFE24(w, k): if len(w) != len(k): raise Exception("inputs to psi_RMFE24 must be of same length") for i in range(len(k)): if k[i] > _sage_const_32: raise Exception( "every coordinate on second input of psi_RMFE24 needs to be at most 32" ) B = [a**i for i in range(_sage_const_4)] data = FFTpreproc(_sage_const_4, B) res = [] for j in range(len(w)): # First change field representation to represent input as element of F_(32^65) and hence as a polynomial in F_32[X] of degree at most 64. m = field_iso_asc(w[j], _sage_const_4, g, R) m = list(m) # Before applying the FFT we need to a polynomial of degree <=15. For this we take modulo X^16+X, as this does not modify evaluation in points of F_16: hred = listsum(m[_sage_const_0:_sage_const_16], [_sage_const_0] + m[_sage_const_16:]) # Apply FFT w1 = binaryFFT(hred, _sage_const_4, B, data) # Based on value of k, we adjust size of the output. upper = (k[j] + _sage_const_1) // _sage_const_2 del w1[upper:] # Apply psi from (2,4)_2-RMFE to each element of resulting vector. r = [] for i in range(len(w1)): r = r + invmap24(w1[i]) # Adjust size of output. del r[k[j]:] # Concatenate this to global vector. res = res + r return res
def interpol(w, instance): e1 = instance.e1 m1 = instance.m1 F = instance.F a = instance.a R = instance.R Y = instance.Y B = instance.B if len(w) == _sage_const_2**e1 or len( w) == _sage_const_2**e1 + _sage_const_1: data = FFTpreproc(e1, B) v2 = invbinaryFFT(w, e1, B, data) p = sum(v2[i] * Y**i for i in range(len(v2))) #Adjust evaluation at point at infinity if necessary. if len(w) == _sage_const_2**e1 + _sage_const_1: p += w[m1] * (Y**m1 - Y) return p else: EvalPoints = lin(B)[:len(w)] Points = [(EvalPoints[i], w[i]) for i in range(len(w))] return R.lagrange_polynomial(Points)
def psi_RMFE(w,vk,instance): k1=instance.k1 k2=instance.k2 e1=instance.e1 e2=instance.e2 k=instance.k e=instance.e m1=instance.m1 m2=instance.m2 F=instance.F a=instance.a H=instance.H c=instance.c P=instance.P X=instance.X R=instance.R Y=instance.Y f=instance.f h=instance.h g=instance.g ###print ('lengths', len(w), len(k)) if len(w)!=len(vk): raise Exception("inputs to psi_RMFE must be of same length") for i in range(len(vk)): if vk[i]>k: raise Exception("every coordinate on second input of psi_RMFE need to be at most k") B=[a**i for i in range(e1)] data=FFTpreproc(e1,B) res=[] for j in range(len(w)): #First change field representation to represent input as element of F_(m1^e2) and hence as a polynomial in F[X] of degree at most e2. Recall m1=2^e1 p=field_iso_asc(w[j],instance) p=list(p) #print ('After translating to F', p) #Before applying the FFT we need to a polynomial of degree <=m1. For this we take modulo X^m1+X, as this does not modify evaluation in points of F=F_m1: hredi=listsum(p[_sage_const_0 :m1],[_sage_const_0 ]+p[m1:_sage_const_2 *m1-_sage_const_1 ]) hred=listsum(hredi[:],[_sage_const_0 ]+p[_sage_const_2 *m1-_sage_const_1 :]) #print ('After reduction', hred) #Apply FFT w1=eval(hred,instance) #print ('After applying FFT we get', w1) #At this point we have a vector w1 of m1 elements in F and want to apply psi_first to each of these coordinates (obtaining k1 coordinates in F2 at each of these m1). If we apply it directly we get an output of m1*k1 coordinates, buit this may not coincide with vk[j], because: first, the theory also allows to have one more point, the point at infinity so in fact vk[j] may be as large as (m1+1)*k1; second, it also maybe that vk[j]<m1*k1. So based on value of vk, we adjust size of the output. If vk is larger than m1*k1 we need to add the evaluation in the point at infinity. If it is smaller we adjust so that the output will have vk[j] coordinates if vk[j]>m1*k1: if len(p)>_sage_const_2 *m1: w1.append(p[_sage_const_2 *m1]) else: w1=w1+([_sage_const_0 ]*(vk[j]-len(p))) else: upper=((vk[j]-_sage_const_1 )//k1) + _sage_const_1 del w1[upper:] ###print ('After adjusting we get', w1) #Apply psi_first to each element of resulting vector. r=[] for i in range(len(w1)): r=r+psi_first(w1[i],instance) #Adjust size of output. del r[vk[j]:] #Concatenate this to global vector. res=res+r return res