Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/attacks/hnp/extended_hnp.py
2589 views
1
import os
2
import sys
3
4
from sage.all import QQ
5
from sage.all import ZZ
6
from sage.all import block_matrix
7
from sage.all import identity_matrix
8
from sage.all import matrix
9
from sage.all import vector
10
11
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))
12
if sys.path[1] != path:
13
sys.path.insert(1, path)
14
15
from shared.lattice import closest_vectors
16
17
18
def attack(x_, N, pi, nu, a, p, u, b, delta=None):
19
"""
20
Solves the extended hidden number problem (definition 6 in the source paper).
21
More information: Hlavac M., Rosa T., "Extended Hidden Number Problem and Its Cryptanalytic Applications" (Section 4)
22
:param x_: the known bits of x
23
:param N: the modulus
24
:param pi: the pi values
25
:param nu: the nu values
26
:param a: the alpha values
27
:param p: the rho values
28
:param u: the mu values
29
:param b: the beta values
30
:param delta: the delta value (default: automatically computed)
31
:return: a generator generating possible values of x
32
"""
33
assert len(pi) == len(nu), "pi and v lists should be of equal length."
34
assert len(a) == len(p) == len(u) == len(b), "a, p, u, and b lists should be of equal length."
35
36
m = len(pi)
37
d = len(a)
38
l = []
39
for i in range(d):
40
assert len(p[i]) == len(u[i]), "p[i] and u[i] lists should be of equal length."
41
l.append(len(p[i]))
42
43
L = sum(l)
44
D = d + m + L
45
KD = QQ(2 ** (D / 4) * (m + L) ** (1 / 2) + 1) / 2
46
delta = QQ(1 / (2 * KD)) if delta is None else QQ(delta)
47
assert 0 < KD * delta < 1
48
49
Id = identity_matrix(ZZ, d)
50
P = matrix(ZZ, L, d)
51
row = 0
52
for i in range(d):
53
for j in range(l[i]):
54
P[row, i] = p[i][j]
55
row += 1
56
57
A = matrix(ZZ, m, d)
58
for i in range(d):
59
for j in range(m):
60
A[j, i] = a[i] * 2 ** pi[j]
61
62
X = matrix(QQ, m, m)
63
for j in range(m):
64
X[j, j] = delta / (2 ** nu[j])
65
66
K = matrix(QQ, L, L)
67
pos = 0
68
for i in range(d):
69
for j in range(l[i]):
70
K[pos, pos] = delta / (2 ** u[i][j])
71
pos += 1
72
73
B = block_matrix(QQ, [
74
[N * Id, matrix(QQ, d, m), matrix(QQ, d, L)],
75
[A, X, matrix(QQ, m, L)],
76
[P, matrix(QQ, L, m), K]
77
])
78
79
v = vector(QQ, [delta / 2] * D)
80
for i in range(d):
81
v[i] = (b[i] - a[i] * x_) % N
82
83
for W in closest_vectors(B, v, algorithm="babai"):
84
z = x_
85
for j in range(m):
86
z += 2 ** pi[j] * int((W[d + j] * 2 ** nu[j]) / delta)
87
z %= N
88
89
yield z
90
91
92
def dsa_known_bits(N, h, r, s, x, k):
93
"""
94
Recovers the (EC)DSA private key if any nonce bits are known.
95
:param N: the modulus
96
:param h: a list containing the hashed messages
97
:param r: a list containing the r values
98
:param s: a list containing the s values
99
:param x: the partial private key (PartialInteger, can be fully unknown)
100
:param k: a list containing the partial nonces (PartialIntegers)
101
:return: a generator generating possible private keys
102
"""
103
assert len(h) == len(r) == len(s) == len(k), "h, r, s, and k lists should be of equal length."
104
x_, pi, nu = x.get_known_and_unknowns()
105
a = []
106
p = []
107
u = []
108
b = []
109
for hi, ri, si, ki in zip(h, r, s, k):
110
a.append(ri)
111
ki_, li, ui = ki.get_known_and_unknowns()
112
p.append([(-si * 2 ** lij) % N for lij in li])
113
u.append(ui)
114
b.append((si * ki_ - hi) % N)
115
116
yield from attack(x_, N, pi, nu, a, p, u, b)
117
118