# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   File Name :      broadcast_attack_with_linear_padding.sage
   Description :
   Author :         x3nny
   date :           2021/7/14
-------------------------------------------------
   Change Activity:
                    2021/7/14: Init
-------------------------------------------------
"""


# This file was *autogenerated* from the file /Users/x3nny/tools/pypackages/xenny/xenny/ctf/crypto/modern/asymmetric/rsa/copper_smith/broadcast_attack_with_linear_padding.sage
from sage.all_cmdline import *   # import sage library

_sage_const_1 = Integer(1); _sage_const_0 = Integer(0); _sage_const_1p = RealNumber('1.'); _sage_const_1000 = Integer(1000); _sage_const_7p = RealNumber('7.'); _sage_const_8 = Integer(8); _sage_const_2 = Integer(2)
__author__ = 'x3nny'

# coding:utf-8
x_calc = lambda x, n: ((n-x)//x+_sage_const_1 , (n-x)%x)


def x_change(e_list):
   e_list = [(i, e_list[i]) for i in range(len(e_list))]
   e_list = sorted(e_list, key=lambda x:x[_sage_const_1 ])
   sum = max_i = _sage_const_0 
   indexs = []
   exponents = []
   for index, exp in e_list:
      sum += _sage_const_1 /exp
      indexs.append(index)
      if exp > max_i:
         max_i = exp
      if sum > _sage_const_1p :
         break
   for i in range(len(indexs)):
      exponents.append(x_calc(e_list[i][_sage_const_1 ], max_i))
   return indexs, exponents


def hastad_attack(c_list, n_list, a_list, b_list, e, bits=_sage_const_1000 , beta=_sage_const_7p /_sage_const_8 ):
   PR = PolynomialRing(ZZ, names=('x',)); (x,) = PR._first_ngens(1)
   f_list = []
   for i in range(len(c_list)):
      f = PR((a_list[i]*x + b_list[i])**e - c_list[i])
      ff = f.change_ring(Zmod(n_list[i]))
      ff = ff.monic()
      f = ff.change_ring(ZZ)
      f_list.append(f)

   F = crt(f_list, n_list)
   M = reduce(lambda x, y: x * y, n_list)
   FF = F.change_ring(Zmod(M))
   m = FF.small_roots(X=_sage_const_2 **bits, beta=beta)
   if m:
      return m[_sage_const_0 ]
   return None


def smupe(c_list, n_list, a_list, b_list, e_list, bits=_sage_const_1000 , beta=_sage_const_7p /_sage_const_8 ):
   PR = PolynomialRing(ZZ, names=('x',)); (x,) = PR._first_ngens(1)
   f_list = []
   indexs, exponents = x_change(e_list)
   for i in indexs:
      f =  PR((a_list[i]*x + b_list[i])**e_list[i] - c_list[i] )
      ff = f.change_ring(Zmod(n_list[i]))
      ff = ff.monic()
      f = ff.change_ring(ZZ)
      f_list.append(f)
   F = crt([(f_list[i]**exponents[i][_sage_const_0 ]) * (x**exponents[i][_sage_const_1 ]) for i in range(len(exponents))], [n_list[i] for i in indexs])

   M = reduce(lambda x, y: x * y, [n_list[i] for i in indexs])
   FF = F.change_ring(Zmod(M))
   m = FF.small_roots(X=_sage_const_2 **bits, beta=beta)
   if m:
      return m[_sage_const_0 ]
   return None


def attack(c_list, n_list, a_list, b_list, e=None, e_list=None, bits=_sage_const_1000 , beta=_sage_const_7p /_sage_const_8 ):
   if e is not None:
      return hastad_attack(c_list, n_list, a_list, b_list, e, bits, beta)
   elif e_list is not None:
      return smupe(c_list, n_list, a_list, b_list, e_list, bits, beta)
   return None

