def computeR(P, Q): m = P.degree() n = Q.degree() t = trace_from_minpoly(P, 2 * m * n + 4) u = trace_from_minpoly(Q, 2 * m * n + 4) v = [t[i] * u[i] for i in range(2 * m * n + 4)] from sage.matrix.berlekamp_massey import berlekamp_massey BM = berlekamp_massey(v) return BM
def _composed_product(P, Q): 'composed product of P and Q' m = P.degree() n = Q.degree() t = _trace_from_minpoly(P, 2*m*n+4) u = _trace_from_minpoly(Q, 2*m*n+4) v = [t[i]*u[i] for i in range(2*m*n+4)] BM = berlekamp_massey(v) return BM
def computeR(P, Q): m = P.degree() n = Q.degree() t = trace_from_minpoly(P, 2*m*n+4) u = trace_from_minpoly(Q, 2*m*n+4) v = [t[i]*u[i] for i in range(2*m*n+4)] from sage.matrix.berlekamp_massey import berlekamp_massey BM = berlekamp_massey(v) return BM
def guess(self, sequence, algorithm='sage'): """ Return the minimal CFiniteSequence that generates the sequence. Assume the first value has index 0. INPUT: - ``sequence`` -- list of integers - ``algorithm`` -- string - 'sage' - the default is to use Sage's matrix kernel function - 'pari' - use Pari's implementation of LLL - 'bm' - use Sage's Berlekamp-Massey algorithm OUTPUT: - a CFiniteSequence, or 0 if none could be found With the default kernel method, trailing zeroes are chopped off before a guessing attempt. This may reduce the data below the accepted length of six values. EXAMPLES:: sage: C.<x> = CFiniteSequences(QQ) sage: C.guess([1,2,4,8,16,32]) C-finite sequence, generated by -1/2/(x - 1/2) sage: r = C.guess([1,2,3,4,5]) Traceback (most recent call last): ... ValueError: Sequence too short for guessing. With Berlekamp-Massey, if an odd number of values is given, the last one is dropped. So with an odd number of values the result may not generate the last value:: sage: r = C.guess([1,2,4,8,9], algorithm='bm'); r C-finite sequence, generated by -1/2/(x - 1/2) sage: r[0:5] [1, 2, 4, 8, 16] """ S = self.polynomial_ring() if algorithm == 'bm': from sage.matrix.berlekamp_massey import berlekamp_massey if len(sequence) < 2: raise ValueError('Sequence too short for guessing.') R = PowerSeriesRing(QQ, 'x') if len(sequence) % 2: sequence.pop() l = len(sequence) - 1 denominator = S(berlekamp_massey(sequence).reverse()) numerator = R(S(sequence) * denominator, prec=l).truncate() return CFiniteSequence(numerator / denominator) elif algorithm == 'pari': global _gp if len(sequence) < 6: raise ValueError('Sequence too short for guessing.') if _gp is None: _gp = Gp() _gp("ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q") _gp.set('gf', sequence) _gp("gf=ggf(gf)") num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1]) den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1]) if num == 0: return 0 else: return CFiniteSequence(num / den) else: from sage.matrix.constructor import matrix from sage.functions.other import ceil from numpy import trim_zeros seq = sequence[:] while seq and sequence[-1] == 0: seq.pop() l = len(seq) if l == 0: return 0 if l < 6: raise ValueError('Sequence too short for guessing.') hl = ceil(ZZ(l) / 2) A = matrix([sequence[k:k + hl] for k in range(hl)]) K = A.kernel() if K.dimension() == 0: return 0 R = PolynomialRing(QQ, 'x') den = R(trim_zeros(K.basis()[-1].list()[::-1])) if den == 1: return 0 offset = next((i for i, x in enumerate(sequence) if x), None) S = PowerSeriesRing(QQ, 'x', default_prec=l - offset) num = S(R(sequence) * den).truncate(ZZ(l) // 2 + 1) if num == 0 or sequence != S(num / den).list(): return 0 else: return CFiniteSequence(num / den)
def guess(self, sequence, algorithm="sage"): """ Return the minimal CFiniteSequence that generates the sequence. Assume the first value has index 0. INPUT: - ``sequence`` -- list of integers - ``algorithm`` -- string - 'sage' - the default is to use Sage's matrix kernel function - 'pari' - use Pari's implementation of LLL - 'bm' - use Sage's Berlekamp-Massey algorithm OUTPUT: - a CFiniteSequence, or 0 if none could be found With the default kernel method, trailing zeroes are chopped off before a guessing attempt. This may reduce the data below the accepted length of six values. EXAMPLES:: sage: C.<x> = CFiniteSequences(QQ) sage: C.guess([1,2,4,8,16,32]) C-finite sequence, generated by 1/(-2*x + 1) sage: r = C.guess([1,2,3,4,5]) Traceback (most recent call last): ... ValueError: Sequence too short for guessing. With Berlekamp-Massey, if an odd number of values is given, the last one is dropped. So with an odd number of values the result may not generate the last value:: sage: r = C.guess([1,2,4,8,9], algorithm='bm'); r C-finite sequence, generated by 1/(-2*x + 1) sage: r[0:5] [1, 2, 4, 8, 16] """ S = self.polynomial_ring() if algorithm == "bm": from sage.matrix.berlekamp_massey import berlekamp_massey if len(sequence) < 2: raise ValueError("Sequence too short for guessing.") R = PowerSeriesRing(QQ, "x") if len(sequence) % 2 == 1: sequence = sequence[:-1] l = len(sequence) - 1 denominator = S(berlekamp_massey(sequence).list()[::-1]) numerator = R(S(sequence) * denominator, prec=l).truncate() return CFiniteSequence(numerator / denominator) elif algorithm == "pari": global _gp if len(sequence) < 6: raise ValueError("Sequence too short for guessing.") if _gp is None: _gp = Gp() _gp( "ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q" ) _gp.set("gf", sequence) _gp("gf=ggf(gf)") num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1]) den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1]) if num == 0: return 0 else: return CFiniteSequence(num / den) else: from sage.matrix.constructor import matrix from sage.functions.other import floor, ceil from numpy import trim_zeros l = len(sequence) while l > 0 and sequence[l - 1] == 0: l -= 1 sequence = sequence[:l] if l == 0: return 0 if l < 6: raise ValueError("Sequence too short for guessing.") hl = ceil(ZZ(l) / 2) A = matrix([sequence[k : k + hl] for k in range(hl)]) K = A.kernel() if K.dimension() == 0: return 0 R = PolynomialRing(QQ, "x") den = R(trim_zeros(K.basis()[-1].list()[::-1])) if den == 1: return 0 offset = next((i for i, x in enumerate(sequence) if x != 0), None) S = PowerSeriesRing(QQ, "x", default_prec=l - offset) num = S(R(sequence) * den).add_bigoh(floor(ZZ(l) / 2 + 1)).truncate() if num == 0 or sequence != S(num / den).list(): return 0 else: return CFiniteSequence(num / den)
N = 128 m = 8 F2 = GF(2) XOR = lambda s1,s2: bytes([x^y for x,y in zip(s1,s2)]) BIT2BYTE = lambda l: bytes(ZZ(l[::-1], base=2).digits(base=256))[::-1] BYTE2BIT = lambda b: ZZ(list(b[::-1]), base=256).digits(base=2, padto=8*len(b))[::-1] cipher = open('msg.enc', 'rb').read() cipherstream = BYTE2BIT(cipher) BITS_LENGTH = len(cipherstream) c = [F2(cipherstream[m*i]) for i in range(2*N)] Pol = berlekamp_massey(c) per = 2**Pol.degree() - 1 m_inv = inverse_mod(m, per) T = companion_matrix(Pol, format='right') TT = T**m_inv cc = Matrix(F2, c[:N]) bb = [] for _ in range(2*N): bb.append( cc[0, 0] ) cc = cc*TT fill = bb[:N] gg = berlekamp_massey(bb) key = gg.coefficients(sparse=False)[:-1]
def guess(sequence, algorithm='pari'): """ Return the minimal CFiniteSequence that generates the sequence. Assume the first value has index 0. INPUT: - ``sequence`` -- list of integers - ``algorithm`` -- string - 'pari' - use Pari's implementation of LLL (fast) - 'bm' - use Sage's Berlekamp-Massey algorithm OUTPUT: - a CFiniteSequence, or 0 if none could be found EXAMPLES:: sage: CFiniteSequence.guess([1,2,4,8,16,32]) C-finite sequence, generated by 1/(-2*x + 1) sage: r = CFiniteSequence.guess([1,2,3,4,5]) Traceback (most recent call last): ... ValueError: Sequence too short for guessing. sage: CFiniteSequence.guess([1,0,0,0,0,0]) Finite sequence [1], offset = 0 With Pari LLL, all values are taken into account, and if no o.g.f. can be found, `0` is returned:: sage: CFiniteSequence.guess([1,0,0,0,0,1]) 0 With Berlekamp-Massey, if an odd number of values is given, the last one is dropped. So with an odd number of values the result may not generate the last value:: sage: r = CFiniteSequence.guess([1,2,4,8,9], algorithm='bm'); r C-finite sequence, generated by 1/(-2*x + 1) sage: r[0:5] [1, 2, 4, 8, 16] """ S = PolynomialRing(QQ, 'x') if algorithm == 'bm': if len(sequence) < 2: raise ValueError('Sequence too short for guessing.') R = PowerSeriesRing(QQ, 'x') if len(sequence) % 2 == 1: sequence = sequence[:-1] l = len(sequence) - 1 denominator = S(berlekamp_massey(sequence).list()[::-1]) numerator = R(S(sequence) * denominator, prec=l).truncate() return CFiniteSequence(numerator / denominator) else: global _gp if len(sequence) < 6: raise ValueError('Sequence too short for guessing.') if _gp is None: _gp = Gp() _gp("ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q") _gp.set('gf', sequence) _gp("gf=ggf(gf)") num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1]) den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1]) if num == 0: return 0 else: return CFiniteSequence(num / den) """