bling_yu

Five methods for the hidden number problem

Aug 14th, 2022 (edited)
277
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.96 KB | Source Code | 0 0
  1. '''
  2. This code is used to recover the hidden number problem.
  3. Suppose that the modulus, alpha and the middle bits of beta are given, we need to recover the hidden number.
  4. The software used is the Sagemath.
  5. This code gives five methods: the "continued fraction + lattice" method, the lattice method for finding lambda, the lattice method given in inscrypt21, a new lattice-based method and an improved data-saving method.
  6. '''
  7.  
  8. import time
  9.  
  10. # Randomly divide m into n segments, the sum of the even segments is K
  11. def distribution(n, m, K):
  12.     d = vector(ZZ, n)
  13.     known = vector(ZZ, int((n - 1)/2))
  14.     unknown = vector(ZZ, int((n + 1)/2))
  15.    
  16.     known[0] = randint(1, K - 1)
  17.     known[len(known) - 1] = K
  18.     i = 1
  19.     while i < (n - 1)/2 - 1:
  20.         k = randint(1, K - 1)
  21.         jud = 0
  22.         flag = 0
  23.         for j in range(0, i):
  24.             if k == known[j]:
  25.                 flag = 1
  26.                 break
  27.             if k < known[j]:
  28.                 for ii in range(j, i):
  29.                     known[i + j - ii] = known[i + j - ii - 1]
  30.                 known[j] = k
  31.                 break
  32.             if k > known[j]:
  33.                 jud = jud + 1
  34.         if jud == i:
  35.             known[i] = k
  36.         if flag == 0:
  37.             i = i + 1
  38.            
  39.     unknown[0] = randint(1, m - K - 1)
  40.     unknown[len(unknown) - 1] = m - K
  41.     i = 1
  42.     while i < (n + 1)/2 - 1:
  43.         k = randint(1, m - K - 1)
  44.         jud = 0
  45.         flag = 0
  46.         for j in range(0, i):
  47.             if k == unknown[j]:
  48.                 flag = 1
  49.                 break
  50.             if k < unknown[j]:
  51.                 for ii in range(j, i):
  52.                     unknown[i + j - ii] = unknown[i + j - ii - 1]
  53.                 unknown[j] = k
  54.                 break
  55.             if k > unknown[j]:
  56.                 jud = jud + 1
  57.         if jud == i:
  58.             unknown[i] = k
  59.         if flag == 0:
  60.             i = i + 1
  61.      
  62.     d[0] = unknown[0]
  63.     d[1] = known[0]
  64.     for i in range(1, len(unknown)):
  65.         d[2 * i] = unknown[i] - unknown[i - 1]
  66.     for i in range(1, len(known)):
  67.         d[2 * i + 1] = known[i] - known[i - 1]
  68.        
  69.     return d
  70.  
  71. # The "continued fraction + lattice" method
  72. def continued_fractions_method(n, q, A, R, d):
  73.     m = ceil(q.log() / 2.log())
  74.     a = 2^(d[0] + d[1])
  75.     b = q / 2^(d[0] + d[1] / 2)
  76.     PQ = convergents(a/q)
  77.     for i in range(0, len(PQ) - 1):
  78.         if PQ[i].denominator() < RDF(b) and RDF(b) <= PQ[i + 1].denominator():
  79.             lamda = PQ[i].denominator()
  80.             break
  81.    
  82.     L = Matrix(ZZ, n + 2, n + 2)
  83.     x = vector(ZZ, n + 2)
  84.     for i in range(0, n):
  85.         L[i, i] = q * 2^(ceil(d[1] / 2) - 1)
  86.         L[n, i] = ((lamda * A[0, i]) % q) * 2^(ceil(d[1] / 2) - 1)
  87.         L[n + 1, i] = ((lamda * R[0, i] * 2^d[0]) % q) * 2^(ceil(d[1] / 2) - 1)
  88.     L[n, n] = 1
  89.     L[n + 1, n + 1] = 2^(ceil(d[1] / 2) - 1)
  90.    
  91.     reduced_L = L.BKZ(block_size = 20)
  92.    
  93.     j = 0
  94.     for i in range(0, n + 2):
  95.         if reduced_L[i, n + 1].abs() == L[n + 1, n + 1]:
  96.             x[j] = reduced_L[i, n].abs()
  97.             j = j + 1
  98.    
  99.     return x
  100.  
  101. # The lattice method for finding lambda
  102. def balanced_lattice_method(n, q, A, R, d):
  103.     l = len(d)
  104.     m = 256
  105.     L = Matrix(ZZ, (l + 1) / 2, (l + 1) / 2)
  106.     for i in range(0, (l - 1) / 2):
  107.         L[i, i] = q * 2^(d[2 * (i + 1)])
  108.         L[(l - 1) / 2, i] = 1
  109.         for j in range(0, 2 * (i + 1) + 1):
  110.             L[(l - 1) / 2, i] = L[(l - 1) / 2, i] * 2^(d[j])
  111.     L[(l - 1) / 2, (l - 1) / 2] = 2^d[0]
  112.    
  113.     reduced_L = L.BKZ(block_size = 20)
  114.    
  115.     sum_unknown = 0
  116.     for i in range(0, (l + 1) / 2):
  117.         sum_unknown = sum_unknown + reduced_L[0, i].abs()
  118.     len_unknown = ceil(sum_unknown.log()/2.log())
  119.     lamda = reduced_L[0, (l - 1) / 2].abs() / 2^d[0]
  120.        
  121.     LL = Matrix(ZZ, n + 2, n + 2)
  122.     x = vector(ZZ, n + 2)
  123.     for i in range(0, n):
  124.         LL[i, i] = q * 2^(m - len_unknown)
  125.         LL[n, i] = ((lamda * A[0, i]) % q) * 2^(m - len_unknown)
  126.         LL[n + 1, i] = 0
  127.         for j in range(0, (l - 1) / 2):
  128.             known = 0
  129.             for k in range(0, 2 * j + 1):
  130.                 known = known + d[k]    
  131.             LL[n + 1, i] = LL[n + 1, i] + 2^known * R[j, i]
  132.         LL[n + 1, i] = ((lamda * LL[n + 1, i] + 2^(len_unknown - 1)) % q) * 2^(m - len_unknown)      
  133.     LL[n, n] = 1
  134.     LL[n + 1, n] = 2^(len_unknown - 1) * 2^(m - len_unknown)
  135.     LL[n + 1, n + 1] = 2^(len_unknown - 1) * 2^(m - len_unknown)
  136.    
  137.     reduced_LL = LL.BKZ(block_size = 20)
  138.    
  139.     j = 0
  140.     for i in range(0, n + 2):
  141.         if reduced_LL[i, n + 1] == -LL[n + 1, n + 1]:
  142.             x[j] = LL[n + 1, n] + reduced_LL[i, n]
  143.             j = j + 1
  144.         if reduced_LL[i, n + 1] == LL[n + 1, n + 1]:
  145.             x[j] = LL[n + 1, n] - reduced_LL[i, n]
  146.             j = j + 1
  147.    
  148.     return x
  149.  
  150. # The lattice method given in inscrypt21
  151. def lattice21_method(n, q, A, R, d):
  152.     L = Matrix(ZZ, 2 * n + 1, 2 * n + 1)
  153.     a_inv = (A[0, 0]^(-1)) % q
  154.     for i in range(0, n - 1):
  155.         L[i, i] = q
  156.         L[n - 1, i] = (A[0, i + 1] * a_inv) % q
  157.         L[n, i] = (A[0, i + 1] * a_inv * 2^(d[0] + d[1])) % q
  158.         L[n + 1 + i, i] = 2^(d[0] + d[1])
  159.         L[2 * n, i] = ((R[0, i + 1] * 2^d[0] - A[0, i + 1] * a_inv * 2^d[0] * R[0, 0]) % q) + 2^(d[0] - 1)
  160.    
  161.     L[n - 1, n - 1] = 1
  162.     L[2 * n, n - 1] = 2^(d[0] - 1)
  163.     L[2 * n, n] = 2^(d[0] - 1)
  164.     L[2 * n, 2 * n] = 2^(d[0] - 1)
  165.     for i in range(n + 1, 2 * n):
  166.         L[2 * n, i] = -2^(d[0] - 1)
  167.     if d[0] >= d[2]:
  168.         for i in range(n, 2 * n):
  169.             L[i, i] = 2^(d[0] - d[2])
  170.     else:
  171.         for i in range(0, 2 * n + 1):
  172.             for j in range(0, 2 * n + 1):
  173.                 L[i, j] = L[i, j] * 2^(d[2] - d[0])
  174.         for i in range(n, 2 * n):
  175.             L[i, i] = 1
  176.  
  177.     reduced_L = L.BKZ(block_size = 20)
  178.     x = vector(ZZ, 2 * n + 1)
  179.     j = 0
  180.     for i in range(0, 2 * n + 1):
  181.         if reduced_L[i, 2 * n] == -L[2 * n, 2 * n]:
  182.             b1 = (L[2 * n, n - 1] + reduced_L[i, n - 1]) / L[n - 1, n - 1]
  183.             b3 = (L[2 * n, n] + reduced_L[i, n]) / L[n, n]
  184.             b = b1 + R[0, 0] * 2^d[0] + b3 * 2^(d[0] + d[1])
  185.             x[j] = (a_inv * b) % q
  186.             j = j + 1
  187.         if reduced_L[i, 2 * n] == L[2 * n, 2 * n]:
  188.             b1 = (L[2 * n, n - 1] - reduced_L[i, n - 1]) / L[n - 1, n - 1]
  189.             b3 = (L[2 * n, n] - reduced_L[i, n]) / L[n, n]
  190.             b = b1 + R[0, 0] * 2^d[0] + b3 * 2^(d[0] + d[1])
  191.             x[j] = (a_inv * b) % q
  192.             j = j + 1
  193.    
  194.     return x
  195.  
  196. # Our new lattice-based method
  197. def new_lattice_method(n, q, A, R, d):
  198.     m = 256
  199.     L = Matrix(ZZ, 2 * n + 2, 2 * n + 2)
  200.     for i in range(0, n):
  201.         L[i, i] = q * 2^(m - d[0])
  202.         L[n, i] = A[0, i] * 2^(m - d[0])
  203.         L[n + 1, i] = R[0, i] * 2^m + 2^(m - 1)
  204.     L[n, n] = 1
  205.     L[n + 1, n] = 2^(m - 1)
  206.     L[n + 1, n + 1] = 2^(m - 1)
  207.     for i in range(n + 2, 2 * n + 2):
  208.         L[n + 1, i] = -2^(m - 1)
  209.     for i in range(n + 2, 2 * n + 2):
  210.         L[i, i - n - 2] = 2^(m + d[1])
  211.         L[i, i] = 2^(m - d[2])
  212.  
  213.     reduced_L = L.BKZ(block_size = 20)
  214.    
  215.     x = vector(ZZ, 2 * n + 2)
  216.     j = 0
  217.     for i in range(0, 2 * n + 2):
  218.         if reduced_L[i, n + 1] == -L[n + 1, n + 1]:
  219.             x[j] = L[n + 1, n] + reduced_L[i, n]
  220.             j = j + 1
  221.         if reduced_L[i, n + 1] == L[n + 1, n + 1]:
  222.             x[j] = L[n + 1, n] - reduced_L[i, n]
  223.             j = j + 1
  224.    
  225.     return x
  226.  
  227. # An improved data-saving method
  228. def improved_lattice_method(n, q, A, R, d, gamma, X):
  229.     m = 256
  230.     L = Matrix(ZZ, 2 * n + 2, 2 * n + 2)
  231.     for i in range(0, n):
  232.         L[i, i] = q * 2^(m - d[0] - gamma)
  233.         L[n, i] = A[0, i] * 2^(m - d[0] - gamma)
  234.         L[n + 1, i] = R[0, i] * 2^(m - gamma) + 2^(m - gamma - 1)
  235.     L[n, n] = 1
  236.     L[n + 1, n] = 2^(m - gamma) * (X >> (m - gamma)) + 2^(m - gamma - 1)
  237.     L[n + 1, n + 1] = 2^(m - gamma - 1)
  238.     for i in range(n + 2, 2 * n + 2):
  239.         L[n + 1, i] = -2^(m - gamma - 1)
  240.     for i in range(n + 2, 2 * n + 2):
  241.         L[i, i - n - 2] = 2^(m + d[1] - gamma)
  242.         L[i, i] = 2^(m - d[2] - gamma)
  243.  
  244.     reduced_L = L.BKZ(block_size = 20)
  245.    
  246.     x = vector(ZZ, 2 * n + 2)
  247.     j = 0
  248.     for i in range(0, 2 * n + 2):
  249.         if reduced_L[i, n + 1] == -L[n + 1, n + 1]:
  250.             x[j] = L[n + 1, n] + reduced_L[i, n]
  251.             j = j + 1
  252.         if reduced_L[i, n + 1] == L[n + 1, n + 1]:
  253.             x[j] = L[n + 1, n] - reduced_L[i, n]
  254.             j = j + 1
  255.    
  256.     return x
  257.  
  258. # Judge whether x is the hidden number
  259. def judgement_x(X, x):
  260.     jud = 0
  261.     for i in range(0, len(x)):
  262.         if X == x[i]:
  263.             jud = 1
  264.             break
  265.            
  266.     return jud
  267.              
  268.  
  269. m = 256
  270. q = 115792089237316195423570985008687907853269984665640564039457584007913129639747
  271. K = 8    # The number of unknown bits
  272. N = 500
  273. gamma = 6
  274. Tn = 40
  275. start = time.time()
  276. for n_i in range(0, Tn):
  277.     n = Tn - n_i
  278.     print(n)
  279.     success_x = vector(ZZ, 5)
  280.     for count in range(0, 10):
  281.         A = random_matrix(ZZ, 1, N, x = 0, y = q)
  282.         X = randint(0, q - 1)
  283.         R = Matrix(ZZ, 1, N)
  284.         d = distribution(3, m, K)
  285.         for i in range(0, N):
  286.             R[0, i] = (((A[0, i] * X) % q) >> d[0]) % (2^d[1])
  287.  
  288.         x1 = continued_fractions_method(n, q, A, R, d)
  289.         jx1 = judgement_x(X, x1)
  290.         success_x[0] = success_x[0] + jx1
  291.  
  292.         x2 = balanced_lattice_method(n, q, A, R, d)
  293.         jx2 = judgement_x(X, x2)
  294.         success_x[1] = success_x[1] + jx2
  295.        
  296.         x3 = lattice21_method(n, q, A, R, d)
  297.         jx3 = judgement_x(X, x3)
  298.         success_x[2] = success_x[2] + jx3
  299.  
  300.         x4 = new_lattice_method(n, q, A, R, d)
  301.         jx4 = judgement_x(X, x4)
  302.         success_x[3] = success_x[3] + jx4
  303.  
  304.         x5 = improved_lattice_method(n, q, A, R, d, gamma, X)
  305.         jx5 = judgement_x(X, x5)
  306.         success_x[4] = success_x[4] + jx5
  307.     print(success_x,'\n')
  308. end = time.time()
  309. print('time:',end-start,'s')
Advertisement
Add Comment
Please, Sign In to add comment