bling_yu

Recover the truncated MRG-with-c driving sequence

Aug 31st, 2022 (edited)
497
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 76.12 KB | Source Code | 0 0
  1. '''
  2. This code is used to recover the truncated MRG-with-c's driving sequence.
  3. Suppose that the modulus, the coefficients, the initial states and the constant are unknown, given the first N truncated digits which consist of the alpha high-order bits of the sequence, we need to recover the modulus, the coefficients, the initial states and the constant.
  4. The library used is the Sagemath.
  5. The whole experimental process consists of 5 steps. Searching linear relations, Recovering the modulus, the coefficients, the differences of initial states, the initial states and the constant.
  6. '''
  7.  
  8. import time
  9.  
  10. # Search polynomials that annihilate the sequence a'
  11. def Search_linear_relations(y, r, t):
  12.     time_start = time.clock()
  13.     L = Matrix(ZZ, r, r + t)
  14.     C = Matrix(ZZ, 5, r)
  15.     for i in range(0, r):
  16.         for j in range(0, r + t):
  17.             L[i, j] = 0
  18.         L[i, i + t] = 1
  19.         for j in range(0, t):
  20.             L[i, j] = y[i + j]      
  21.     reduced_L = L.BKZ(block_size = 20)
  22.    
  23.     for i in range(0, 5):
  24.         for j in range(0, r):
  25.             C[i, j] = reduced_L[i, j + t]  
  26.    
  27.     time_end = time.clock()
  28.     print('Step 1: time of searching polynomials that annihilate the sequence a`: ', time_end - time_start, 's\n\n')
  29.     return C
  30.  
  31. # Recover the modulus by the resultant
  32. def Recover_the_modulus(C, r):
  33.     time_start = time.clock()
  34.     R.<x> = ZZ[]
  35.     f1 = C[0, 0]
  36.     f2 = C[1, 0]
  37.     f3 = C[2, 0]
  38.     f4 = C[3, 0]
  39.     f5 = C[4, 0]
  40.     for i in range(1, r):
  41.         f1 = f1 + x^i * C[0, i]
  42.         f2 = f2 + x^i * C[1, i]
  43.         f3 = f3 + x^i * C[2, i]
  44.         f4 = f4 + x^i * C[3, i]
  45.         f5 = f5 + x^i * C[4, i]
  46.    
  47.     r1 = f1.resultant(f2)
  48.     r2 = f2.resultant(f3)
  49.     r3 = f3.resultant(f1)
  50.     r4 = f4.resultant(f1)
  51.     r5 = f5.resultant(f2)
  52.     r6 = f4.resultant(f3)
  53.    
  54.     m_power = gcd(gcd(gcd(gcd(gcd(r1, r2), r3), r4), r5), r6)
  55.     m = m_power^(1/16)
  56.    
  57.     time_end = time.clock()
  58.     print('Step 2: time of recovering the modulus: ', time_end - time_start, 's\n\n')
  59.     return m
  60.  
  61. # Recover the coefficients by the Chinese Remainder Theorem
  62. def Recover_the_coefficients(C, m, r):
  63.     time_start = time.clock()
  64.     R.<x> = PolynomialRing(Integers(m), implementation='NTL')
  65.    
  66.     for i in range(0, 2):
  67.         mark = r - 1
  68.         while C[i][mark] == 0:
  69.             mark = mark - 1
  70.         for j in range(0, r):
  71.             C[i, j] = C[i, j] * ((C[i, mark]^(-1)) % m)
  72.     f = C[0, 0]
  73.     g = C[1, 0]
  74.     for i in range(1, r):
  75.         f = f + x^i * C[0, i]
  76.         g = g + x^i * C[1, i]
  77.        
  78.     time_end = time.clock()
  79.     print('Step 3: time of recovering the coefficients: ', time_end - time_start, 's\n\n')
  80.     return f.gcd(g)
  81.  
  82. # Recover the differences of initial state by Kannan's embedding technique
  83. def Recover_the_differences_of_initial_state(y, f, m, n, beta):
  84.     time_start = time.clock()
  85.     d = 31
  86.     z = vector(ZZ, n)
  87.     a = vector(ZZ, n)
  88.     Q = Matrix(ZZ, n, n)
  89.     Q_power = identity_matrix(ZZ, n)
  90.     L = Matrix(ZZ, d + 1, d + 1)
  91.    
  92.     Q[0, n - 1] = (-f.list()[0]) % m
  93.     for i in range(1, n):
  94.         Q[i, i - 1] = 1
  95.         Q[i, n - 1] = (-f.list()[i]) % m
  96.    
  97.     for i in range(1, n):
  98.         Q_power = (Q_power * Q) % m
  99.     for i in range(n, d):
  100.         Q_power = (Q_power * Q) % m
  101.         b = 0
  102.         for j in range(0, n):
  103.             L[j + 1, i + 1] = Q_power[j, 0]
  104.             b = b + Q_power[j, 0] * y[j]
  105.         L[0, i + 1] = (2^beta * (y[i] - b)) % m
  106.    
  107.     L[0, 0] = 2^beta
  108.     for i in range(1, n + 1):
  109.         L[i, i] = 1
  110.     for i in range(n + 1, d + 1):
  111.         L[i, i] = m
  112.        
  113.     reduced_L = L.BKZ(block_size = 20)
  114.    
  115.     if reduced_L[0, 0] == -2^beta:
  116.         for i in range(0, n):
  117.             z[i] = reduced_L[0, i + 1]
  118.             a[i] = y[i] * 2^(beta) + z[i]
  119.     if reduced_L[0, 0] == 2^beta:
  120.         for i in range(0, n):
  121.             z[i] = -reduced_L[0, i + 1]
  122.             a[i] = y[i] * 2^(beta) + z[i]
  123.            
  124.     time_end = time.clock()
  125.     print('Step 4: time of recovering the differences of initial state: ', time_end - time_start, 's\n\n')
  126.     return a
  127.  
  128. # Recover the constant and initial state
  129. def Recover_the_constant_and_initial_state(dif_a, y, beta, n, m, f):
  130.     time_start = time.clock()
  131.     diff_a = vector(ZZ, 9999)
  132.     diff_y = vector(ZZ, 9999)
  133.    
  134.     for i in range(0, 9999):
  135.         diff_y[i] = y[i + 1] - y[i]
  136.     for i in range(0, n):
  137.         diff_a[i] = dif_a[i]
  138.     for i in range(n, 9999):
  139.         diff_a[i] = 0
  140.         for j in range(1, n + 1):
  141.             diff_a[i] = (diff_a[i] + diff_a[i - j] * (-f.list()[n - j])) % m
  142.         if diff_y[i] < 0:
  143.             diff_a[i] = diff_a[i] - m
  144.    
  145.     z0_left = 0
  146.     z0_right = 2^beta - 1
  147.     L = 1
  148.     Y = 0
  149.     A = 0
  150.     while z0_left!= z0_right:
  151.         L = L + 1
  152.         Y = Y + diff_y[L - 2]
  153.         A = A + diff_a[L - 2]
  154.         if (A >> beta) == Y:
  155.             right = 2^beta - 1 - A % (2^beta)
  156.             if right < z0_right:
  157.                 z0_right = right
  158.         if (A >> beta) + 1 == Y:
  159.             left = 2^beta - A % (2^beta)
  160.             if left > z0_left:
  161.                 z0_left = left
  162.     z0 = z0_left
  163.    
  164.     a = vector(ZZ, n + 1)
  165.     a[0] = z0 + 2^beta * y[0]
  166.     for i in range(1, n + 1):
  167.         a[i] = a[i - 1] + dif_a[i - 1]
  168.    
  169.     c = 0
  170.     for i in range(0, n + 1):
  171.         c = (c + a[i] * f.list()[i]) % m
  172.    
  173.     time_end = time.clock()
  174.     print('Step 5: time of recovering the constant and initial state: ', time_end - time_start, 's\n\n''The modulus m = ', m, '\n\n')
  175. f = Recover_the_coefficients(C, m, r)
  176. print('The characteristic polynomial f = ', f, '\n\n')
  177. dif_a = Recover_the_differences_of_initial_state(dif_y, f, m, n, beta)
  178. print('The differences of initial state a` = ', dif_a, '\n\n')
  179. L, a, c = Recover_the_constant_and_initial_state(dif_a, y, beta, n, m, f)
  180. print('The least number of truncated digits L = ', L, '\n\n')
  181. print('The initial state a = ', a, '\n\n')
  182. print('The constant c = ', c, '\n\n')
Advertisement
Add Comment
Please, Sign In to add comment