You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

935 lines
25 KiB

  1. import pickle
  2. import sys
  3. try:
  4. import unittest2 as unittest
  5. except ImportError:
  6. import unittest
  7. import os
  8. import signal
  9. import pytest
  10. import threading
  11. import platform
  12. import hypothesis.strategies as st
  13. from hypothesis import given, assume, settings, example
  14. from .ellipticcurve import CurveFp, PointJacobi, INFINITY, Point
  15. from .ecdsa import (
  16. generator_256,
  17. curve_256,
  18. generator_224,
  19. generator_brainpoolp160r1,
  20. curve_brainpoolp160r1,
  21. generator_112r2,
  22. curve_112r2,
  23. )
  24. from .numbertheory import inverse_mod
  25. from .util import randrange
  26. NO_OLD_SETTINGS = {}
  27. if sys.version_info > (2, 7): # pragma: no branch
  28. NO_OLD_SETTINGS["deadline"] = 5000
  29. SLOW_SETTINGS = {}
  30. if "--fast" in sys.argv: # pragma: no cover
  31. SLOW_SETTINGS["max_examples"] = 2
  32. else:
  33. SLOW_SETTINGS["max_examples"] = 10
  34. class TestJacobi(unittest.TestCase):
  35. def test___init__(self):
  36. curve = object()
  37. x = 2
  38. y = 3
  39. z = 1
  40. order = 4
  41. pj = PointJacobi(curve, x, y, z, order)
  42. self.assertEqual(pj.order(), order)
  43. self.assertIs(pj.curve(), curve)
  44. self.assertEqual(pj.x(), x)
  45. self.assertEqual(pj.y(), y)
  46. def test_add_with_different_curves(self):
  47. p_a = PointJacobi.from_affine(generator_256)
  48. p_b = PointJacobi.from_affine(generator_224)
  49. with self.assertRaises(ValueError): # pragma: no branch
  50. p_a + p_b
  51. def test_compare_different_curves(self):
  52. self.assertNotEqual(generator_256, generator_224)
  53. def test_equality_with_non_point(self):
  54. pj = PointJacobi.from_affine(generator_256)
  55. self.assertNotEqual(pj, "value")
  56. def test_conversion(self):
  57. pj = PointJacobi.from_affine(generator_256)
  58. pw = pj.to_affine()
  59. self.assertEqual(generator_256, pw)
  60. def test_single_double(self):
  61. pj = PointJacobi.from_affine(generator_256)
  62. pw = generator_256.double()
  63. pj = pj.double()
  64. self.assertEqual(pj.x(), pw.x())
  65. self.assertEqual(pj.y(), pw.y())
  66. def test_double_with_zero_point(self):
  67. pj = PointJacobi(curve_256, 0, 0, 1)
  68. pj = pj.double()
  69. self.assertIs(pj, INFINITY)
  70. def test_double_with_zero_equivalent_point(self):
  71. pj = PointJacobi(curve_256, 0, 0, 0)
  72. pj = pj.double()
  73. self.assertIs(pj, INFINITY)
  74. def test_double_with_zero_equivalent_point_non_zero_z_non_zero_y(self):
  75. pj = PointJacobi(curve_256, 0, 1, curve_256.p())
  76. pj = pj.double()
  77. self.assertIs(pj, INFINITY)
  78. def test_double_with_zero_equivalent_point_non_zero_z(self):
  79. pj = PointJacobi(curve_256, 0, 0, curve_256.p())
  80. pj = pj.double()
  81. self.assertIs(pj, INFINITY)
  82. def test_compare_with_affine_point(self):
  83. pj = PointJacobi.from_affine(generator_256)
  84. pa = pj.to_affine()
  85. self.assertEqual(pj, pa)
  86. self.assertEqual(pa, pj)
  87. def test_to_affine_with_zero_point(self):
  88. pj = PointJacobi(curve_256, 0, 0, 0)
  89. pa = pj.to_affine()
  90. self.assertIs(pa, INFINITY)
  91. def test_add_with_affine_point(self):
  92. pj = PointJacobi.from_affine(generator_256)
  93. pa = pj.to_affine()
  94. s = pj + pa
  95. self.assertEqual(s, pj.double())
  96. def test_radd_with_affine_point(self):
  97. pj = PointJacobi.from_affine(generator_256)
  98. pa = pj.to_affine()
  99. s = pa + pj
  100. self.assertEqual(s, pj.double())
  101. def test_add_with_infinity(self):
  102. pj = PointJacobi.from_affine(generator_256)
  103. s = pj + INFINITY
  104. self.assertEqual(s, pj)
  105. def test_add_zero_point_to_affine(self):
  106. pa = PointJacobi.from_affine(generator_256).to_affine()
  107. pj = PointJacobi(curve_256, 0, 0, 0)
  108. s = pj + pa
  109. self.assertIs(s, pa)
  110. def test_multiply_by_zero(self):
  111. pj = PointJacobi.from_affine(generator_256)
  112. pj = pj * 0
  113. self.assertIs(pj, INFINITY)
  114. def test_zero_point_multiply_by_one(self):
  115. pj = PointJacobi(curve_256, 0, 0, 1)
  116. pj = pj * 1
  117. self.assertIs(pj, INFINITY)
  118. def test_multiply_by_one(self):
  119. pj = PointJacobi.from_affine(generator_256)
  120. pw = generator_256 * 1
  121. pj = pj * 1
  122. self.assertEqual(pj.x(), pw.x())
  123. self.assertEqual(pj.y(), pw.y())
  124. def test_multiply_by_two(self):
  125. pj = PointJacobi.from_affine(generator_256)
  126. pw = generator_256 * 2
  127. pj = pj * 2
  128. self.assertEqual(pj.x(), pw.x())
  129. self.assertEqual(pj.y(), pw.y())
  130. def test_rmul_by_two(self):
  131. pj = PointJacobi.from_affine(generator_256)
  132. pw = generator_256 * 2
  133. pj = 2 * pj
  134. self.assertEqual(pj, pw)
  135. def test_compare_non_zero_with_infinity(self):
  136. pj = PointJacobi.from_affine(generator_256)
  137. self.assertNotEqual(pj, INFINITY)
  138. def test_compare_non_zero_bad_scale_with_infinity(self):
  139. pj = PointJacobi(curve_256, 1, 1, 0)
  140. self.assertEqual(pj, INFINITY)
  141. def test_eq_x_0_on_curve_with_infinity(self):
  142. c_23 = CurveFp(23, 1, 1)
  143. pj = PointJacobi(c_23, 0, 1, 1)
  144. self.assertTrue(c_23.contains_point(0, 1))
  145. self.assertNotEqual(pj, INFINITY)
  146. def test_eq_y_0_on_curve_with_infinity(self):
  147. c_23 = CurveFp(23, 1, 1)
  148. pj = PointJacobi(c_23, 4, 0, 1)
  149. self.assertTrue(c_23.contains_point(4, 0))
  150. self.assertNotEqual(pj, INFINITY)
  151. def test_eq_with_same_x_different_y(self):
  152. c_23 = CurveFp(23, 1, 1)
  153. p_a = PointJacobi(c_23, 0, 22, 1)
  154. p_b = PointJacobi(c_23, 0, 1, 1)
  155. self.assertNotEqual(p_a, p_b)
  156. def test_compare_zero_point_with_infinity(self):
  157. pj = PointJacobi(curve_256, 0, 0, 0)
  158. self.assertEqual(pj, INFINITY)
  159. def test_compare_double_with_multiply(self):
  160. pj = PointJacobi.from_affine(generator_256)
  161. dbl = pj.double()
  162. mlpl = pj * 2
  163. self.assertEqual(dbl, mlpl)
  164. @settings(**SLOW_SETTINGS)
  165. @given(
  166. st.integers(
  167. min_value=0, max_value=int(generator_brainpoolp160r1.order() - 1)
  168. )
  169. )
  170. def test_multiplications(self, mul):
  171. pj = PointJacobi.from_affine(generator_brainpoolp160r1)
  172. pw = pj.to_affine() * mul
  173. pj = pj * mul
  174. self.assertEqual((pj.x(), pj.y()), (pw.x(), pw.y()))
  175. self.assertEqual(pj, pw)
  176. @settings(**SLOW_SETTINGS)
  177. @given(
  178. st.integers(
  179. min_value=0, max_value=int(generator_brainpoolp160r1.order() - 1)
  180. )
  181. )
  182. @example(0)
  183. @example(int(generator_brainpoolp160r1.order()))
  184. def test_precompute(self, mul):
  185. precomp = generator_brainpoolp160r1
  186. self.assertTrue(precomp._PointJacobi__precompute)
  187. pj = PointJacobi.from_affine(generator_brainpoolp160r1)
  188. a = precomp * mul
  189. b = pj * mul
  190. self.assertEqual(a, b)
  191. @settings(**SLOW_SETTINGS)
  192. @given(
  193. st.integers(
  194. min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1)
  195. ),
  196. st.integers(
  197. min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1)
  198. ),
  199. )
  200. @example(3, 3)
  201. def test_add_scaled_points(self, a_mul, b_mul):
  202. j_g = PointJacobi.from_affine(generator_brainpoolp160r1)
  203. a = PointJacobi.from_affine(j_g * a_mul)
  204. b = PointJacobi.from_affine(j_g * b_mul)
  205. c = a + b
  206. self.assertEqual(c, j_g * (a_mul + b_mul))
  207. @settings(**SLOW_SETTINGS)
  208. @given(
  209. st.integers(
  210. min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1)
  211. ),
  212. st.integers(
  213. min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1)
  214. ),
  215. st.integers(min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)),
  216. )
  217. def test_add_one_scaled_point(self, a_mul, b_mul, new_z):
  218. j_g = PointJacobi.from_affine(generator_brainpoolp160r1)
  219. a = PointJacobi.from_affine(j_g * a_mul)
  220. b = PointJacobi.from_affine(j_g * b_mul)
  221. p = curve_brainpoolp160r1.p()
  222. assume(inverse_mod(new_z, p))
  223. new_zz = new_z * new_z % p
  224. b = PointJacobi(
  225. curve_brainpoolp160r1,
  226. b.x() * new_zz % p,
  227. b.y() * new_zz * new_z % p,
  228. new_z,
  229. )
  230. c = a + b
  231. self.assertEqual(c, j_g * (a_mul + b_mul))
  232. @pytest.mark.slow
  233. @settings(**SLOW_SETTINGS)
  234. @given(
  235. st.integers(
  236. min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1)
  237. ),
  238. st.integers(
  239. min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1)
  240. ),
  241. st.integers(min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)),
  242. )
  243. @example(1, 1, 1)
  244. @example(3, 3, 3)
  245. @example(2, int(generator_brainpoolp160r1.order() - 2), 1)
  246. @example(2, int(generator_brainpoolp160r1.order() - 2), 3)
  247. def test_add_same_scale_points(self, a_mul, b_mul, new_z):
  248. j_g = PointJacobi.from_affine(generator_brainpoolp160r1)
  249. a = PointJacobi.from_affine(j_g * a_mul)
  250. b = PointJacobi.from_affine(j_g * b_mul)
  251. p = curve_brainpoolp160r1.p()
  252. assume(inverse_mod(new_z, p))
  253. new_zz = new_z * new_z % p
  254. a = PointJacobi(
  255. curve_brainpoolp160r1,
  256. a.x() * new_zz % p,
  257. a.y() * new_zz * new_z % p,
  258. new_z,
  259. )
  260. b = PointJacobi(
  261. curve_brainpoolp160r1,
  262. b.x() * new_zz % p,
  263. b.y() * new_zz * new_z % p,
  264. new_z,
  265. )
  266. c = a + b
  267. self.assertEqual(c, j_g * (a_mul + b_mul))
  268. def test_add_same_scale_points_static(self):
  269. j_g = generator_brainpoolp160r1
  270. p = curve_brainpoolp160r1.p()
  271. a = j_g * 11
  272. a.scale()
  273. z1 = 13
  274. x = PointJacobi(
  275. curve_brainpoolp160r1,
  276. a.x() * z1**2 % p,
  277. a.y() * z1**3 % p,
  278. z1,
  279. )
  280. y = PointJacobi(
  281. curve_brainpoolp160r1,
  282. a.x() * z1**2 % p,
  283. a.y() * z1**3 % p,
  284. z1,
  285. )
  286. c = a + a
  287. self.assertEqual(c, x + y)
  288. @pytest.mark.slow
  289. @settings(**SLOW_SETTINGS)
  290. @given(
  291. st.integers(
  292. min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1)
  293. ),
  294. st.integers(
  295. min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1)
  296. ),
  297. st.lists(
  298. st.integers(
  299. min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)
  300. ),
  301. min_size=2,
  302. max_size=2,
  303. unique=True,
  304. ),
  305. )
  306. @example(2, 2, [2, 1])
  307. @example(2, 2, [2, 3])
  308. @example(2, int(generator_brainpoolp160r1.order() - 2), [2, 3])
  309. @example(2, int(generator_brainpoolp160r1.order() - 2), [2, 1])
  310. def test_add_different_scale_points(self, a_mul, b_mul, new_z):
  311. j_g = PointJacobi.from_affine(generator_brainpoolp160r1)
  312. a = PointJacobi.from_affine(j_g * a_mul)
  313. b = PointJacobi.from_affine(j_g * b_mul)
  314. p = curve_brainpoolp160r1.p()
  315. assume(inverse_mod(new_z[0], p))
  316. assume(inverse_mod(new_z[1], p))
  317. new_zz0 = new_z[0] * new_z[0] % p
  318. new_zz1 = new_z[1] * new_z[1] % p
  319. a = PointJacobi(
  320. curve_brainpoolp160r1,
  321. a.x() * new_zz0 % p,
  322. a.y() * new_zz0 * new_z[0] % p,
  323. new_z[0],
  324. )
  325. b = PointJacobi(
  326. curve_brainpoolp160r1,
  327. b.x() * new_zz1 % p,
  328. b.y() * new_zz1 * new_z[1] % p,
  329. new_z[1],
  330. )
  331. c = a + b
  332. self.assertEqual(c, j_g * (a_mul + b_mul))
  333. def test_add_different_scale_points_static(self):
  334. j_g = generator_brainpoolp160r1
  335. p = curve_brainpoolp160r1.p()
  336. a = j_g * 11
  337. a.scale()
  338. z1 = 13
  339. x = PointJacobi(
  340. curve_brainpoolp160r1,
  341. a.x() * z1**2 % p,
  342. a.y() * z1**3 % p,
  343. z1,
  344. )
  345. z2 = 29
  346. y = PointJacobi(
  347. curve_brainpoolp160r1,
  348. a.x() * z2**2 % p,
  349. a.y() * z2**3 % p,
  350. z2,
  351. )
  352. c = a + a
  353. self.assertEqual(c, x + y)
  354. def test_add_different_points_same_scale_static(self):
  355. j_g = generator_brainpoolp160r1
  356. p = curve_brainpoolp160r1.p()
  357. a = j_g * 11
  358. a.scale()
  359. b = j_g * 12
  360. z = 13
  361. x = PointJacobi(
  362. curve_brainpoolp160r1,
  363. a.x() * z**2 % p,
  364. a.y() * z**3 % p,
  365. z,
  366. )
  367. y = PointJacobi(
  368. curve_brainpoolp160r1,
  369. b.x() * z**2 % p,
  370. b.y() * z**3 % p,
  371. z,
  372. )
  373. c = a + b
  374. self.assertEqual(c, x + y)
  375. def test_add_same_point_different_scale_second_z_1_static(self):
  376. j_g = generator_112r2
  377. p = curve_112r2.p()
  378. z = 11
  379. a = j_g * z
  380. a.scale()
  381. x = PointJacobi(
  382. curve_112r2,
  383. a.x() * z**2 % p,
  384. a.y() * z**3 % p,
  385. z,
  386. )
  387. y = PointJacobi(
  388. curve_112r2,
  389. a.x(),
  390. a.y(),
  391. 1,
  392. )
  393. c = a + a
  394. self.assertEqual(c, x + y)
  395. def test_add_to_infinity_static(self):
  396. j_g = generator_112r2
  397. z = 11
  398. a = j_g * z
  399. a.scale()
  400. b = -a
  401. x = PointJacobi(
  402. curve_112r2,
  403. a.x(),
  404. a.y(),
  405. 1,
  406. )
  407. y = PointJacobi(
  408. curve_112r2,
  409. b.x(),
  410. b.y(),
  411. 1,
  412. )
  413. self.assertEqual(INFINITY, x + y)
  414. def test_add_point_3_times(self):
  415. j_g = PointJacobi.from_affine(generator_256)
  416. self.assertEqual(j_g * 3, j_g + j_g + j_g)
  417. def test_mul_without_order(self):
  418. j_g = PointJacobi(curve_256, generator_256.x(), generator_256.y(), 1)
  419. self.assertEqual(j_g * generator_256.order(), INFINITY)
  420. def test_mul_add_inf(self):
  421. j_g = PointJacobi.from_affine(generator_256)
  422. self.assertEqual(j_g, j_g.mul_add(1, INFINITY, 1))
  423. def test_mul_add_same(self):
  424. j_g = PointJacobi.from_affine(generator_256)
  425. self.assertEqual(j_g * 2, j_g.mul_add(1, j_g, 1))
  426. def test_mul_add_precompute(self):
  427. j_g = PointJacobi.from_affine(generator_brainpoolp160r1, True)
  428. b = PointJacobi.from_affine(j_g * 255, True)
  429. self.assertEqual(j_g * 256, j_g + b)
  430. self.assertEqual(j_g * (5 + 255 * 7), j_g * 5 + b * 7)
  431. self.assertEqual(j_g * (5 + 255 * 7), j_g.mul_add(5, b, 7))
  432. def test_mul_add_precompute_large(self):
  433. j_g = PointJacobi.from_affine(generator_brainpoolp160r1, True)
  434. b = PointJacobi.from_affine(j_g * 255, True)
  435. self.assertEqual(j_g * 256, j_g + b)
  436. self.assertEqual(
  437. j_g * (0xFF00 + 255 * 0xF0F0), j_g * 0xFF00 + b * 0xF0F0
  438. )
  439. self.assertEqual(
  440. j_g * (0xFF00 + 255 * 0xF0F0), j_g.mul_add(0xFF00, b, 0xF0F0)
  441. )
  442. def test_mul_add_to_mul(self):
  443. j_g = PointJacobi.from_affine(generator_256)
  444. a = j_g * 3
  445. b = j_g.mul_add(2, j_g, 1)
  446. self.assertEqual(a, b)
  447. def test_mul_add_differnt(self):
  448. j_g = PointJacobi.from_affine(generator_256)
  449. w_a = j_g * 2
  450. self.assertEqual(j_g.mul_add(1, w_a, 1), j_g * 3)
  451. def test_mul_add_slightly_different(self):
  452. j_g = PointJacobi.from_affine(generator_256)
  453. w_a = j_g * 2
  454. w_b = j_g * 3
  455. self.assertEqual(w_a.mul_add(1, w_b, 3), w_a * 1 + w_b * 3)
  456. def test_mul_add(self):
  457. j_g = PointJacobi.from_affine(generator_256)
  458. w_a = generator_256 * 255
  459. w_b = generator_256 * (0xA8 * 0xF0)
  460. j_b = j_g * 0xA8
  461. ret = j_g.mul_add(255, j_b, 0xF0)
  462. self.assertEqual(ret.to_affine(), w_a + w_b)
  463. def test_mul_add_zero(self):
  464. j_g = PointJacobi.from_affine(generator_256)
  465. w_a = generator_256 * 255
  466. w_b = generator_256 * (0 * 0xA8)
  467. j_b = j_g * 0xA8
  468. ret = j_g.mul_add(255, j_b, 0)
  469. self.assertEqual(ret.to_affine(), w_a + w_b)
  470. def test_mul_add_large(self):
  471. j_g = PointJacobi.from_affine(generator_256)
  472. b = PointJacobi.from_affine(j_g * 255)
  473. self.assertEqual(j_g * 256, j_g + b)
  474. self.assertEqual(
  475. j_g * (0xFF00 + 255 * 0xF0F0), j_g * 0xFF00 + b * 0xF0F0
  476. )
  477. self.assertEqual(
  478. j_g * (0xFF00 + 255 * 0xF0F0), j_g.mul_add(0xFF00, b, 0xF0F0)
  479. )
  480. def test_mul_add_with_infinity_as_result(self):
  481. j_g = PointJacobi.from_affine(generator_256)
  482. order = generator_256.order()
  483. b = PointJacobi.from_affine(generator_256 * 256)
  484. self.assertEqual(j_g.mul_add(order % 256, b, order // 256), INFINITY)
  485. def test_mul_add_without_order(self):
  486. j_g = PointJacobi(curve_256, generator_256.x(), generator_256.y(), 1)
  487. order = generator_256.order()
  488. w_b = generator_256 * 34
  489. w_b.scale()
  490. b = PointJacobi(curve_256, w_b.x(), w_b.y(), 1)
  491. self.assertEqual(j_g.mul_add(order % 34, b, order // 34), INFINITY)
  492. def test_mul_add_with_doubled_negation_of_itself(self):
  493. j_g = PointJacobi.from_affine(generator_256 * 17)
  494. dbl_neg = 2 * (-j_g)
  495. self.assertEqual(j_g.mul_add(4, dbl_neg, 2), INFINITY)
  496. @given(
  497. st.integers(min_value=0, max_value=int(generator_112r2.order() - 1)),
  498. st.integers(min_value=0, max_value=int(generator_112r2.order() - 1)),
  499. st.integers(min_value=0, max_value=int(generator_112r2.order() - 1)),
  500. )
  501. @example(693, 2, 3293) # values that will hit all the conditions for NAF
  502. def test_mul_add_random(self, mul1, mul2, mul3):
  503. p_a = PointJacobi.from_affine(generator_112r2)
  504. p_b = generator_112r2 * mul2
  505. res = p_a.mul_add(mul1, p_b, mul3)
  506. self.assertEqual(res, p_a * mul1 + p_b * mul3)
  507. def test_equality(self):
  508. pj1 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1)
  509. pj2 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1)
  510. self.assertEqual(pj1, pj2)
  511. def test_equality_with_invalid_object(self):
  512. j_g = PointJacobi.from_affine(generator_256)
  513. self.assertNotEqual(j_g, 12)
  514. def test_equality_with_wrong_curves(self):
  515. p_a = PointJacobi.from_affine(generator_256)
  516. p_b = PointJacobi.from_affine(generator_224)
  517. self.assertNotEqual(p_a, p_b)
  518. def test_add_with_point_at_infinity(self):
  519. pj1 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1)
  520. x, y, z = pj1._add(2, 3, 1, 5, 5, 0, 23)
  521. self.assertEqual((x, y, z), (2, 3, 1))
  522. def test_double_to_infinity(self):
  523. c_23 = CurveFp(23, 1, 1)
  524. p = PointJacobi(c_23, 11, 20, 1)
  525. p2 = p.double()
  526. self.assertEqual((p2.x(), p2.y()), (4, 0))
  527. self.assertNotEqual(p2, INFINITY)
  528. p3 = p2.double()
  529. self.assertEqual(p3, INFINITY)
  530. self.assertIs(p3, INFINITY)
  531. def test_double_to_x_0(self):
  532. c_23_2 = CurveFp(23, 1, 2)
  533. p = PointJacobi(c_23_2, 9, 2, 1)
  534. p2 = p.double()
  535. self.assertEqual((p2.x(), p2.y()), (0, 18))
  536. def test_mul_to_infinity(self):
  537. c_23 = CurveFp(23, 1, 1)
  538. p = PointJacobi(c_23, 11, 20, 1)
  539. p2 = p * 2
  540. self.assertEqual((p2.x(), p2.y()), (4, 0))
  541. self.assertNotEqual(p2, INFINITY)
  542. p3 = p2 * 2
  543. self.assertEqual(p3, INFINITY)
  544. self.assertIs(p3, INFINITY)
  545. def test_add_to_infinity(self):
  546. c_23 = CurveFp(23, 1, 1)
  547. p = PointJacobi(c_23, 11, 20, 1)
  548. p2 = p + p
  549. self.assertEqual((p2.x(), p2.y()), (4, 0))
  550. self.assertNotEqual(p2, INFINITY)
  551. p3 = p2 + p2
  552. self.assertEqual(p3, INFINITY)
  553. self.assertIs(p3, INFINITY)
  554. def test_mul_to_x_0(self):
  555. c_23 = CurveFp(23, 1, 1)
  556. p = PointJacobi(c_23, 9, 7, 1)
  557. p2 = p * 13
  558. self.assertEqual((p2.x(), p2.y()), (0, 22))
  559. def test_mul_to_y_0(self):
  560. c_23 = CurveFp(23, 1, 1)
  561. p = PointJacobi(c_23, 9, 7, 1)
  562. p2 = p * 14
  563. self.assertEqual((p2.x(), p2.y()), (4, 0))
  564. def test_add_to_x_0(self):
  565. c_23 = CurveFp(23, 1, 1)
  566. p = PointJacobi(c_23, 9, 7, 1)
  567. p2 = p * 12 + p
  568. self.assertEqual((p2.x(), p2.y()), (0, 22))
  569. def test_add_to_y_0(self):
  570. c_23 = CurveFp(23, 1, 1)
  571. p = PointJacobi(c_23, 9, 7, 1)
  572. p2 = p * 13 + p
  573. self.assertEqual((p2.x(), p2.y()), (4, 0))
  574. def test_add_diff_z_to_infinity(self):
  575. c_23 = CurveFp(23, 1, 1)
  576. p = PointJacobi(c_23, 9, 7, 1)
  577. c = p * 20 + p * 8
  578. self.assertIs(c, INFINITY)
  579. def test_pickle(self):
  580. pj = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1)
  581. self.assertEqual(pickle.loads(pickle.dumps(pj)), pj)
  582. @pytest.mark.slow
  583. @settings(**NO_OLD_SETTINGS)
  584. @pytest.mark.skipif(
  585. platform.python_implementation() == "PyPy",
  586. reason="threading on PyPy breaks coverage",
  587. )
  588. @given(st.integers(min_value=1, max_value=10))
  589. def test_multithreading(self, thread_num): # pragma: no cover
  590. # ensure that generator's precomputation table is filled
  591. generator_112r2 * 2
  592. # create a fresh point that doesn't have a filled precomputation table
  593. gen = generator_112r2
  594. gen = PointJacobi(gen.curve(), gen.x(), gen.y(), 1, gen.order(), True)
  595. self.assertEqual(gen._PointJacobi__precompute, [])
  596. def runner(generator):
  597. order = generator.order()
  598. for _ in range(10):
  599. generator * randrange(order)
  600. threads = []
  601. for _ in range(thread_num):
  602. threads.append(threading.Thread(target=runner, args=(gen,)))
  603. for t in threads:
  604. t.start()
  605. runner(gen)
  606. for t in threads:
  607. t.join()
  608. self.assertEqual(
  609. gen._PointJacobi__precompute,
  610. generator_112r2._PointJacobi__precompute,
  611. )
  612. @pytest.mark.slow
  613. @pytest.mark.skipif(
  614. platform.system() == "Windows"
  615. or platform.python_implementation() == "PyPy",
  616. reason="there are no signals on Windows, and threading breaks coverage"
  617. " on PyPy",
  618. )
  619. def test_multithreading_with_interrupts(self): # pragma: no cover
  620. thread_num = 10
  621. # ensure that generator's precomputation table is filled
  622. generator_112r2 * 2
  623. # create a fresh point that doesn't have a filled precomputation table
  624. gen = generator_112r2
  625. gen = PointJacobi(gen.curve(), gen.x(), gen.y(), 1, gen.order(), True)
  626. self.assertEqual(gen._PointJacobi__precompute, [])
  627. def runner(generator):
  628. order = generator.order()
  629. for _ in range(50):
  630. generator * randrange(order)
  631. def interrupter(barrier_start, barrier_end, lock_exit):
  632. # wait until MainThread can handle KeyboardInterrupt
  633. barrier_start.release()
  634. barrier_end.acquire()
  635. os.kill(os.getpid(), signal.SIGINT)
  636. lock_exit.release()
  637. threads = []
  638. for _ in range(thread_num):
  639. threads.append(threading.Thread(target=runner, args=(gen,)))
  640. barrier_start = threading.Lock()
  641. barrier_start.acquire()
  642. barrier_end = threading.Lock()
  643. barrier_end.acquire()
  644. lock_exit = threading.Lock()
  645. lock_exit.acquire()
  646. threads.append(
  647. threading.Thread(
  648. target=interrupter,
  649. args=(barrier_start, barrier_end, lock_exit),
  650. )
  651. )
  652. for t in threads:
  653. t.start()
  654. with self.assertRaises(KeyboardInterrupt):
  655. # signal to interrupter that we can now handle the signal
  656. barrier_start.acquire()
  657. barrier_end.release()
  658. runner(gen)
  659. # use the lock to ensure we never go past the scope of
  660. # assertRaises before the os.kill is called
  661. lock_exit.acquire()
  662. for t in threads:
  663. t.join()
  664. self.assertEqual(
  665. gen._PointJacobi__precompute,
  666. generator_112r2._PointJacobi__precompute,
  667. )
  668. class TestZeroCurve(unittest.TestCase):
  669. """Tests with curve that has (0, 0) on the curve."""
  670. def setUp(self):
  671. self.curve = CurveFp(23, 1, 0)
  672. def test_zero_point_on_curve(self):
  673. self.assertTrue(self.curve.contains_point(0, 0))
  674. def test_double_to_0_0_point(self):
  675. p = PointJacobi(self.curve, 1, 18, 1)
  676. d = p.double()
  677. self.assertNotEqual(d, INFINITY)
  678. self.assertEqual((0, 0), (d.x(), d.y()))
  679. def test_double_to_0_0_point_with_non_one_z(self):
  680. z = 2
  681. p = PointJacobi(self.curve, 1 * z**2, 18 * z**3, z)
  682. d = p.double()
  683. self.assertNotEqual(d, INFINITY)
  684. self.assertEqual((0, 0), (d.x(), d.y()))
  685. def test_mul_to_0_0_point(self):
  686. p = PointJacobi(self.curve, 11, 13, 1)
  687. d = p * 12
  688. self.assertNotEqual(d, INFINITY)
  689. self.assertEqual((0, 0), (d.x(), d.y()))
  690. def test_double_of_0_0_point(self):
  691. p = PointJacobi(self.curve, 0, 0, 1)
  692. d = p.double()
  693. self.assertIs(d, INFINITY)
  694. def test_compare_to_old_implementation(self):
  695. p = PointJacobi(self.curve, 11, 13, 1)
  696. p_c = Point(self.curve, 11, 13)
  697. for i in range(24):
  698. self.assertEqual(p * i, p_c * i)