Example #1
0
def proofll(ifthen, reductors, redsb=True, prot=True):

    if prot and (not ifthen.supposedToBeValid):
        print "THIS THEOREM IS NOT SUPPOSED TO BE VALID"
    ip_pre = ifthen.ifpart
    ip = []

    for p in ip_pre:
        p = Polynomial(p)
        if p.is_zero():
            continue
        li = list(p.lead().variables())
        if len(li) == 1 and (not (li[0] in list(Polynomial(reductors).lead().
            variables()))):
            assert not Polynomial(reductors).is_zero()
            lead_index = li[0]
            if redsb:
                p = ll_red_nf_redsb(p, reductors)
                reductors = ll_red_nf_redsb(Polynomial(reductors), BooleSet(p.
                    set()))

            p_nav = p.navigation()
            reductors = recursively_insert(p_nav.else_branch(), p_nav.value(),
                reductors)
        else:
            ip.append(p)
    it = ifthen.thenpart
    if prot:
        print "proofing:", ifthen
    ip = logicaland(ip)
    for c in it:
        if prot:
            print "proofing part:", c
        c = logicalor([BooleConstant(1) + ip, c])

        if c.is_zero():
            if prot:
                print "TRUE (trivial)"
            return True
        else:
            c_orig = c
            if redsb:
                c = ll_red_nf_redsb(c, reductors)
            else:
                c = ll_red_nf_noredsb(c, reductors)
            if c.is_zero():
                if prot:
                    print "TRUE"
                return True
            else:
                if prot:
                    print "FAILED"
                    print "can construct COUNTER EXAMPLE with:", find_one(c)
                return False
Example #2
0
def proofll(ifthen, reductors, redsb=True, prot=True):

    if prot and (not ifthen.supposedToBeValid):
        print "THIS THEOREM IS NOT SUPPOSED TO BE VALID"
    ip_pre = ifthen.ifpart
    ip = []

    for p in ip_pre:
        p = Polynomial(p)
        if p.is_zero():
            continue
        li = list(p.lead().variables())
        if len(li) == 1 and (not (li[0] in list(
                Polynomial(reductors).lead().variables()))):
            assert not Polynomial(reductors).is_zero()
            lead_index = li[0]
            if redsb:
                p = ll_red_nf_redsb(p, reductors)
                reductors = ll_red_nf_redsb(Polynomial(reductors),
                                            BooleSet(p.set()))

            p_nav = p.navigation()
            reductors = recursively_insert(p_nav.else_branch(), p_nav.value(),
                                           reductors)
        else:
            ip.append(p)
    it = ifthen.thenpart
    if prot:
        print "proofing:", ifthen
    ip = logicaland(ip)
    for c in it:
        if prot:
            print "proofing part:", c
        c = logicalor([BooleConstant(1) + ip, c])

        if c.is_zero():
            if prot:
                print "TRUE (trivial)"
            return True
        else:
            c_orig = c
            if redsb:
                c = ll_red_nf_redsb(c, reductors)
            else:
                c = ll_red_nf_noredsb(c, reductors)
            if c.is_zero():
                if prot:
                    print "TRUE"
                return True
            else:
                if prot:
                    print "FAILED"
                    print "can construct COUNTER EXAMPLE with:", find_one(c)
                return False
Example #3
0
def add_bit_expressions(bit_expressions):
    """Adds n bits, which can be arbitrary expressions, the first n variables of the ring    are reversed for usage in this function.

    >>> from polybori import *
    >>> r=Ring(20)
    >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)])
    [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)]
    >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)])
    [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)]
    >>> add_bit_expressions([r.variable(11), r.variable(11)])
    [0, x(11)]
    >>> add_bit_expressions([r.variable(11),r.variable(12),r.variable(13)])
    [x(11) + x(12) + x(13), x(11)*x(12) + x(11)*x(13) + x(12)*x(13)]
    """

    bit_variables = []
    if bit_expressions:
        ring = bit_expressions[0].ring()
        bit_variables = [
            ring.variable(i) for i in xrange(len(bit_expressions))
        ]
    for expr in bit_expressions:
        assert BooleSet(expr).navigation().value() >= len(bit_variables)
    mapping = ll_encode(
        [b + expr for (b, expr) in zip(bit_variables, bit_expressions)])
    return [ll_red_nf_redsb(p, mapping) for p in add_bits(bit_variables)]
Example #4
0
def add_bit_expressions(bit_expressions):
    """Adds n bits, which can be arbitrary expressions, the first n variables of the ring    are reversed for usage in this function.

    >>> from polybori import *
    >>> r=Ring(20)
    >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)])
    [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)]
    >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)])
    [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)]
    >>> add_bit_expressions([r.variable(11), r.variable(11)])
    [0, x(11)]
    >>> add_bit_expressions([r.variable(11),r.variable(12),r.variable(13)])
    [x(11) + x(12) + x(13), x(11)*x(12) + x(11)*x(13) + x(12)*x(13)]
    """

    bit_variables = []
    if bit_expressions:
        ring = bit_expressions[0].ring()
        bit_variables = [ring.variable(i) for i in xrange(len(bit_expressions)
            )]
    for expr in bit_expressions:
        assert BooleSet(expr).navigation().value() >= len(bit_variables)
    mapping = ll_encode([b + expr for (b, expr) in zip(bit_variables,
        bit_expressions)])
    return [ll_red_nf_redsb(p, mapping) for p in add_bits(bit_variables)]
    def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reductors=False):
        """
        Return a new system where linear leading variables are
        eliminated if the tail of the polynomial has length at most
        ``maxlength``.

        INPUT:

        - ``maxlength`` - an optional upper bound on the number of
          monomials by which a variable is replaced. If
          ``maxlength==+Infinity`` then no condition is checked.
          (default: +Infinity).

        - ``skip`` - an optional callable to skip eliminations. It
          must accept two parameters and return either ``True`` or
          ``False``. The two parameters are the leading term and the
          tail of a polynomial (default: ``None``).

        - ``return_reductors`` - if ``True`` the list of polynomials
          with linear leading terms which were used for reduction is
          also returned (default: ``False``).

        OUTPUT:

        When ``return_reductors==True``, then a pair of sequences of
        boolean polynomials are returned, along with the promises that:

          1. The union of the two sequences spans the
             same boolean ideal as the argument of the method

          2. The second sequence only contains linear polynomials, and
             it forms a reduced groebner basis (they all have pairwise
             distinct leading variables, and the leading variable of a
             polynomial does not occur anywhere in other polynomials).

          3. The leading variables of the second sequence do not occur
             anywhere in the first sequence (these variables have been
             eliminated).

        When ``return_reductors==False``, only the first sequence is
        returned.

        EXAMPLE::

            sage: B.<a,b,c,d> = BooleanPolynomialRing()
            sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c])
            sage: F.eliminate_linear_variables() # everything vanishes
            []
            sage: F.eliminate_linear_variables(maxlength=2)
            [b + c + d + 1, b*c + b*d + c, b*c*d + c]
            sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a')
            [a + c + d, a*c + a*d + a + c, c*d + c]

        The list of reductors can be requested by setting 'return_reductors' to ``True``::

            sage: B.<a,b,c,d> = BooleanPolynomialRing()
            sage: F = Sequence([a + b + d, a + b + c])
            sage: F,R = F.eliminate_linear_variables(return_reductors=True)
            sage: F
            []
            sage: R
            [a + b + d, c + d]

        TESTS:

        The function should really dispose of linear equations (:trac:`13968`)::

            sage: R.<x,y,z> = BooleanPolynomialRing()
            sage: S = Sequence([x+y+z+1, y+z])
            sage: S.eliminate_linear_variables(return_reductors=True)
            ([], [x + 1, y + z])


        The function should take care of linear variables created by previous
        substitution of linear variables ::

            sage: R.<x,y,z> = BooleanPolynomialRing()
            sage: S = Sequence([x*y*z+x*y+z*y+x*z, x+y+z+1, x+y])
            sage: S.eliminate_linear_variables(return_reductors=True)
            ([], [x + y, z + 1])

        .. NOTE::

            This is called "massaging" in [CBJ07]_.

        REFERENCES:

        .. [CBJ07] Gregory V. Bard, and Nicolas T. Courtois, and Chris Jefferson.
           *Efficient Methods for Conversion and Solution of Sparse Systems of Low-Degree
           Multivariate Polynomials over GF(2) via SAT-Solvers*.
           Cryptology ePrint Archive: Report 2007/024. available at
           http://eprint.iacr.org/2007/024
        """
        from sage.rings.polynomial.pbori import BooleanPolynomialRing
        from polybori import gauss_on_polys
        from polybori.ll import eliminate,ll_encode,ll_red_nf_redsb

        R = self.ring()

        if not isinstance(R, BooleanPolynomialRing):
            raise NotImplementedError("Only BooleanPolynomialRing's are supported.")

        F = self
        reductors = []

        if skip is None and maxlength==Infinity:
            # faster solution based on polybori.ll.eliminate
            while True:
                (this_step_reductors, _, higher) = eliminate(F)
                if this_step_reductors == []:
                   break
                reductors.extend( this_step_reductors )
                F = higher
        else:
            # slower, more flexible solution
            if skip is None:
                skip = lambda lm,tail: False

            while True:
                linear = []
                higher = []

                for f in F:
                    if f.degree() == 1 and len(f) <= maxlength + 1:
                        flm = f.lex_lead()
                        if skip(flm, f-flm):
                            higher.append(f)
                            continue
                        linear.append(f)
                    else:
                        higher.append(f)

                if not linear:
                    break

                linear = gauss_on_polys(linear)
                rb = ll_encode(linear)
                reductors.extend(linear)

                F = []
                for f in higher:
                    f = ll_red_nf_redsb(f, rb)
                    if f != 0:
                        F.append(f)

        ret = PolynomialSequence(R, higher)
        if return_reductors:
            reduced_reductors = gauss_on_polys(reductors)
            return ret, PolynomialSequence(R, reduced_reductors)
        else:
            return ret
    def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reductors=False):
        """
        Return a new system where linear leading variables are
        eliminated if the tail of the polynomial has length at most
        ``maxlength``.

        INPUT:

        - ``maxlength`` - an optional upper bound on the number of
          monomials by which a variable is replaced. If
          ``maxlength==+Infinity`` then no condition is checked.
          (default: +Infinity).

        - ``skip`` - an optional callable to skip eliminations. It
          must accept two parameters and return either ``True`` or
          ``False``. The two parameters are the leading term and the
          tail of a polynomial (default: ``None``).

        - ``return_reductors`` - if ``True`` the list of polynomials
          with linear leading terms which were used for reduction is
          also returned (default: ``False``).

        OUTPUT:

        When ``return_reductors==True``, then a pair of sequences of
        boolean polynomials are returned, along with the promises that:

          1. The union of the two sequences spans the
             same boolean ideal as the argument of the method

          2. The second sequence only contains linear polynomials, and
             it forms a reduced groebner basis (they all have pairwise
             distinct leading variables, and the leading variable of a
             polynomial does not occur anywhere in other polynomials).

          3. The leading variables of the second sequence do not occur
             anywhere in the first sequence (these variables have been
             eliminated).

        When ``return_reductors==False``, only the first sequence is
        returned.

        EXAMPLE::

            sage: B.<a,b,c,d> = BooleanPolynomialRing()
            sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c])
            sage: F.eliminate_linear_variables() # everything vanishes
            []
            sage: F.eliminate_linear_variables(maxlength=2)
            [b + c + d + 1, b*c + b*d + c, b*c*d + c]
            sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a')
            [a + c + d, a*c + a*d + a + c, c*d + c]

        The list of reductors can be requested by setting 'return_reductors' to ``True``::

            sage: B.<a,b,c,d> = BooleanPolynomialRing()
            sage: F = Sequence([a + b + d, a + b + c])
            sage: F,R = F.eliminate_linear_variables(return_reductors=True)
            sage: F
            []
            sage: R
            [a + b + d, c + d]

        TESTS:

        The function should really dispose of linear equations (:trac:`13968`)::

            sage: R.<x,y,z> = BooleanPolynomialRing()
            sage: S = Sequence([x+y+z+1, y+z])
            sage: S.eliminate_linear_variables(return_reductors=True)
            ([], [x + 1, y + z])


        The function should take care of linear variables created by previous
        substitution of linear variables ::

            sage: R.<x,y,z> = BooleanPolynomialRing()
            sage: S = Sequence([x*y*z+x*y+z*y+x*z, x+y+z+1, x+y])
            sage: S.eliminate_linear_variables(return_reductors=True)
            ([], [x + y, z + 1])

        .. NOTE::

            This is called "massaging" in [CBJ07]_.

        REFERENCES:

        .. [CBJ07] Gregory V. Bard, and Nicolas T. Courtois, and Chris Jefferson.
           *Efficient Methods for Conversion and Solution of Sparse Systems of Low-Degree
           Multivariate Polynomials over GF(2) via SAT-Solvers*.
           Cryptology ePrint Archive: Report 2007/024. available at
           http://eprint.iacr.org/2007/024
        """
        from polybori import gauss_on_polys
        from polybori.ll import eliminate,ll_encode,ll_red_nf_redsb
        from sage.rings.polynomial.pbori import BooleanPolynomialRing

        R = self.ring()

        if not isinstance(R, BooleanPolynomialRing):
            raise NotImplementedError("Only BooleanPolynomialRing's are supported.")

        F = self
        reductors = []

        if skip is None and maxlength==Infinity:
            # faster solution based on polybori.ll.eliminate
            while True:
                (this_step_reductors, _, higher) = eliminate(F)
                if this_step_reductors == []:
                   break
                reductors.extend( this_step_reductors )
                F = higher
        else:
            # slower, more flexible solution
            if skip is None:
                skip = lambda lm,tail: False

            while True:
                linear = []
                higher = []

                for f in F:
                    if f.degree() == 1 and len(f) <= maxlength + 1:
                        flm = f.lex_lead()
                        if skip(flm, f-flm):
                            higher.append(f)
                            continue
                        linear.append(f)
                    else:
                        higher.append(f)

                if not linear:
                    break

                linear = gauss_on_polys(linear)
                rb = ll_encode(linear)
                reductors.extend(linear)

                F = []
                for f in higher:
                    f = ll_red_nf_redsb(f, rb)
                    if f != 0:
                        F.append(f)

        ret = PolynomialSequence(R, higher)
        if return_reductors:
            reduced_reductors = gauss_on_polys(reductors)
            return ret, PolynomialSequence(R, reduced_reductors)
        else:
            return ret
Example #7
0
    def eliminate_linear_variables(self, maxlength=3, skip=lambda lm,tail: False, return_reductors=False):
        """
        Return a new system where linear leading variables are
        eliminated if the tail of the polynomial has length at most
        ``maxlength``.

        INPUT:

        - ``maxlength`` - an optional upper bound on the number of
          monomials by which a variable is replaced.

        - ``skip`` - an optional callable to skip eliminations. It
          must accept two parameters and return either ``True`` or
          ``False``. The two parameters are the leading term and the
          tail of a polynomial (default: ``lambda lm,tail: False``).

        - ``return_reductors`` - if ``True`` the list of polynomials
          with linear leading terms which were used for reduction is
          also returned (default: ``False``).

        EXAMPLE::
        
            sage: B.<a,b,c,d> = BooleanPolynomialRing()
            sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c])
            sage: F.eliminate_linear_variables() # everything vanishes
            []
            sage: F.eliminate_linear_variables(maxlength=2)
            [b + c + d + 1, b*c + b*d + c, b*c*d + c]
            sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a')
            [a + c + d, a*c + a*d + a + c, c*d + c]

        The list of reductors can be requested by setting 'return_reductors' to ``True``::

            sage: B.<a,b,c,d> = BooleanPolynomialRing()
            sage: F = Sequence([a + b + d, a + b + c])
            sage: F,R = F.eliminate_linear_variables(return_reductors=True)
            sage: F
            [c + d]
            sage: R
            [a + b + d]

        .. note:: 
          
            This is called "massaging" in [CBJ07]_.

        """
        from polybori.ll import ll_encode
        from polybori.ll import ll_red_nf_redsb
        from sage.rings.polynomial.pbori import BooleanPolynomialRing
        from sage.misc.misc import get_verbose

        R = self.ring()

        if not isinstance(R, BooleanPolynomialRing):
            raise NotImplementedError("Only BooleanPolynomialRing's are supported.")

        F = self

        elim = []

        while True: 
            linear = []
            higher = []

            for f in F:
                if f.degree() == 1 and len(f) <= maxlength + 1:
                    flm = f.lex_lead()
                    if skip(flm, f-flm):
                        higher.append(f)
                        continue
                    lex_lead = map(lambda x: x.lex_lead(), linear)
                    if not flm in lex_lead:
                        linear.append(f)
                    else:
                        higher.append(f)
                else:
                    higher.append(f)

            if not linear:
                break
            if not higher:
                higher = linear
                break

            assert len(set(linear)) == len(linear)

            rb = ll_encode(linear)

            elim.extend(linear)

            F = []

            for f in linear:
                f = ll_red_nf_redsb(f, rb)
                if f:
                    F.append(f)

            for f in higher:
                f = ll_red_nf_redsb(f, rb)
                if f:
                    F.append(f)
            if get_verbose() > 0:
                print ".",
        if get_verbose() > 0:
            print

        ret = PolynomialSequence(R, higher)
        if return_reductors:
            return ret, PolynomialSequence(R, elim)
        else:
            return ret
Example #8
0
    def eliminate_linear_variables(self,
                                   maxlength=3,
                                   skip=lambda lm, tail: False,
                                   return_reductors=False):
        """
        Return a new system where linear leading variables are
        eliminated if the tail of the polynomial has length at most
        ``maxlength``.

        INPUT:

        - ``maxlength`` - an optional upper bound on the number of
          monomials by which a variable is replaced.

        - ``skip`` - an optional callable to skip eliminations. It
          must accept two parameters and return either ``True`` or
          ``False``. The two parameters are the leading term and the
          tail of a polynomial (default: ``lambda lm,tail: False``).

        - ``return_reductors`` - if ``True`` the list of polynomials
          with linear leading terms which were used for reduction is
          also returned (default: ``False``).

        EXAMPLE::
        
            sage: B.<a,b,c,d> = BooleanPolynomialRing()
            sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c])
            sage: F.eliminate_linear_variables() # everything vanishes
            []
            sage: F.eliminate_linear_variables(maxlength=2)
            [b + c + d + 1, b*c + b*d + c, b*c*d + c]
            sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a')
            [a + c + d, a*c + a*d + a + c, c*d + c]

        The list of reductors can be requested by setting 'return_reductors' to ``True``::

            sage: B.<a,b,c,d> = BooleanPolynomialRing()
            sage: F = Sequence([a + b + d, a + b + c])
            sage: F,R = F.eliminate_linear_variables(return_reductors=True)
            sage: F
            [c + d]
            sage: R
            [a + b + d]

        .. note:: 
          
            This is called "massaging" in [CBJ07]_.

        """
        from polybori.ll import ll_encode
        from polybori.ll import ll_red_nf_redsb
        from sage.rings.polynomial.pbori import BooleanPolynomialRing
        from sage.misc.misc import get_verbose

        R = self.ring()

        if not isinstance(R, BooleanPolynomialRing):
            raise NotImplementedError(
                "Only BooleanPolynomialRing's are supported.")

        F = self

        elim = []

        while True:
            linear = []
            higher = []

            for f in F:
                if f.degree() == 1 and len(f) <= maxlength + 1:
                    flm = f.lex_lead()
                    if skip(flm, f - flm):
                        higher.append(f)
                        continue
                    lex_lead = map(lambda x: x.lex_lead(), linear)
                    if not flm in lex_lead:
                        linear.append(f)
                    else:
                        higher.append(f)
                else:
                    higher.append(f)

            if not linear:
                break
            if not higher:
                higher = linear
                break

            assert len(set(linear)) == len(linear)

            rb = ll_encode(linear)

            elim.extend(linear)

            F = []

            for f in linear:
                f = ll_red_nf_redsb(f, rb)
                if f:
                    F.append(f)

            for f in higher:
                f = ll_red_nf_redsb(f, rb)
                if f:
                    F.append(f)
            if get_verbose() > 0:
                print ".",
        if get_verbose() > 0:
            print

        ret = PolynomialSequence(R, higher)
        if return_reductors:
            return ret, PolynomialSequence(R, elim)
        else:
            return ret