398 lines
11 KiB
Python
398 lines
11 KiB
Python
|
import pickle
|
||
|
|
||
|
try:
|
||
|
import unittest2 as unittest
|
||
|
except ImportError:
|
||
|
import unittest
|
||
|
|
||
|
import hypothesis.strategies as st
|
||
|
from hypothesis import given, assume, settings, example
|
||
|
|
||
|
from .ellipticcurve import CurveFp, Point, PointJacobi, INFINITY
|
||
|
from .ecdsa import generator_256, curve_256, generator_224
|
||
|
from .numbertheory import inverse_mod
|
||
|
|
||
|
|
||
|
class TestJacobi(unittest.TestCase):
|
||
|
def test___init__(self):
|
||
|
curve = object()
|
||
|
x = 2
|
||
|
y = 3
|
||
|
z = 1
|
||
|
order = 4
|
||
|
pj = PointJacobi(curve, x, y, z, order)
|
||
|
|
||
|
self.assertEqual(pj.order(), order)
|
||
|
self.assertIs(pj.curve(), curve)
|
||
|
self.assertEqual(pj.x(), x)
|
||
|
self.assertEqual(pj.y(), y)
|
||
|
|
||
|
def test_add_with_different_curves(self):
|
||
|
p_a = PointJacobi.from_affine(generator_256)
|
||
|
p_b = PointJacobi.from_affine(generator_224)
|
||
|
|
||
|
with self.assertRaises(ValueError):
|
||
|
p_a + p_b
|
||
|
|
||
|
def test_compare_different_curves(self):
|
||
|
self.assertNotEqual(generator_256, generator_224)
|
||
|
|
||
|
def test_equality_with_non_point(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
self.assertNotEqual(pj, "value")
|
||
|
|
||
|
def test_conversion(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
pw = pj.to_affine()
|
||
|
|
||
|
self.assertEqual(generator_256, pw)
|
||
|
|
||
|
def test_single_double(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
pw = generator_256.double()
|
||
|
|
||
|
pj = pj.double()
|
||
|
|
||
|
self.assertEqual(pj.x(), pw.x())
|
||
|
self.assertEqual(pj.y(), pw.y())
|
||
|
|
||
|
def test_double_with_zero_point(self):
|
||
|
pj = PointJacobi(curve_256, 0, 0, 1)
|
||
|
|
||
|
pj = pj.double()
|
||
|
|
||
|
self.assertIs(pj, INFINITY)
|
||
|
|
||
|
def test_double_with_zero_equivalent_point(self):
|
||
|
pj = PointJacobi(curve_256, 0, curve_256.p(), 1)
|
||
|
|
||
|
pj = pj.double()
|
||
|
|
||
|
self.assertIs(pj, INFINITY)
|
||
|
|
||
|
def test_double_with_zero_equivalent_point_non_1_z(self):
|
||
|
pj = PointJacobi(curve_256, 0, curve_256.p(), 2)
|
||
|
|
||
|
pj = pj.double()
|
||
|
|
||
|
self.assertIs(pj, INFINITY)
|
||
|
|
||
|
def test_compare_with_affine_point(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
pa = pj.to_affine()
|
||
|
|
||
|
self.assertEqual(pj, pa)
|
||
|
self.assertEqual(pa, pj)
|
||
|
|
||
|
def test_to_affine_with_zero_point(self):
|
||
|
pj = PointJacobi(curve_256, 0, 0, 1)
|
||
|
|
||
|
pa = pj.to_affine()
|
||
|
|
||
|
self.assertIs(pa, INFINITY)
|
||
|
|
||
|
def test_add_with_affine_point(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
pa = pj.to_affine()
|
||
|
|
||
|
s = pj + pa
|
||
|
|
||
|
self.assertEqual(s, pj.double())
|
||
|
|
||
|
def test_radd_with_affine_point(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
pa = pj.to_affine()
|
||
|
|
||
|
s = pa + pj
|
||
|
|
||
|
self.assertEqual(s, pj.double())
|
||
|
|
||
|
def test_add_with_infinity(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
s = pj + INFINITY
|
||
|
|
||
|
self.assertEqual(s, pj)
|
||
|
|
||
|
def test_add_zero_point_to_affine(self):
|
||
|
pa = PointJacobi.from_affine(generator_256).to_affine()
|
||
|
pj = PointJacobi(curve_256, 0, 0, 1)
|
||
|
|
||
|
s = pj + pa
|
||
|
|
||
|
self.assertIs(s, pa)
|
||
|
|
||
|
def test_multiply_by_zero(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
pj = pj * 0
|
||
|
|
||
|
self.assertIs(pj, INFINITY)
|
||
|
|
||
|
def test_zero_point_multiply_by_one(self):
|
||
|
pj = PointJacobi(curve_256, 0, 0, 1)
|
||
|
|
||
|
pj = pj * 1
|
||
|
|
||
|
self.assertIs(pj, INFINITY)
|
||
|
|
||
|
def test_multiply_by_one(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
pw = generator_256 * 1
|
||
|
|
||
|
pj = pj * 1
|
||
|
|
||
|
self.assertEqual(pj.x(), pw.x())
|
||
|
self.assertEqual(pj.y(), pw.y())
|
||
|
|
||
|
def test_multiply_by_two(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
pw = generator_256 * 2
|
||
|
|
||
|
pj = pj * 2
|
||
|
|
||
|
self.assertEqual(pj.x(), pw.x())
|
||
|
self.assertEqual(pj.y(), pw.y())
|
||
|
|
||
|
def test_rmul_by_two(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
pw = generator_256 * 2
|
||
|
|
||
|
pj = 2 * pj
|
||
|
|
||
|
self.assertEqual(pj, pw)
|
||
|
|
||
|
def test_compare_non_zero_with_infinity(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
self.assertNotEqual(pj, INFINITY)
|
||
|
|
||
|
def test_compare_zero_point_with_infinity(self):
|
||
|
pj = PointJacobi(curve_256, 0, 0, 1)
|
||
|
|
||
|
self.assertEqual(pj, INFINITY)
|
||
|
|
||
|
def test_compare_double_with_multiply(self):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
dbl = pj.double()
|
||
|
mlpl = pj * 2
|
||
|
|
||
|
self.assertEqual(dbl, mlpl)
|
||
|
|
||
|
@settings(max_examples=10)
|
||
|
@given(st.integers(min_value=0, max_value=int(generator_256.order())))
|
||
|
def test_multiplications(self, mul):
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
pw = pj.to_affine() * mul
|
||
|
|
||
|
pj = pj * mul
|
||
|
|
||
|
self.assertEqual((pj.x(), pj.y()), (pw.x(), pw.y()))
|
||
|
self.assertEqual(pj, pw)
|
||
|
|
||
|
@settings(max_examples=10)
|
||
|
@given(st.integers(min_value=0, max_value=int(generator_256.order())))
|
||
|
@example(0)
|
||
|
@example(int(generator_256.order()))
|
||
|
def test_precompute(self, mul):
|
||
|
precomp = PointJacobi.from_affine(generator_256, True)
|
||
|
pj = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
a = precomp * mul
|
||
|
b = pj * mul
|
||
|
|
||
|
self.assertEqual(a, b)
|
||
|
|
||
|
@settings(max_examples=10)
|
||
|
@given(
|
||
|
st.integers(min_value=1, max_value=int(generator_256.order())),
|
||
|
st.integers(min_value=1, max_value=int(generator_256.order())),
|
||
|
)
|
||
|
@example(3, 3)
|
||
|
def test_add_scaled_points(self, a_mul, b_mul):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
a = PointJacobi.from_affine(j_g * a_mul)
|
||
|
b = PointJacobi.from_affine(j_g * b_mul)
|
||
|
|
||
|
c = a + b
|
||
|
|
||
|
self.assertEqual(c, j_g * (a_mul + b_mul))
|
||
|
|
||
|
@settings(max_examples=10)
|
||
|
@given(
|
||
|
st.integers(min_value=1, max_value=int(generator_256.order())),
|
||
|
st.integers(min_value=1, max_value=int(generator_256.order())),
|
||
|
st.integers(min_value=1, max_value=int(curve_256.p() - 1)),
|
||
|
)
|
||
|
def test_add_one_scaled_point(self, a_mul, b_mul, new_z):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
a = PointJacobi.from_affine(j_g * a_mul)
|
||
|
b = PointJacobi.from_affine(j_g * b_mul)
|
||
|
|
||
|
p = curve_256.p()
|
||
|
|
||
|
assume(inverse_mod(new_z, p))
|
||
|
|
||
|
new_zz = new_z * new_z % p
|
||
|
|
||
|
b = PointJacobi(
|
||
|
curve_256, b.x() * new_zz % p, b.y() * new_zz * new_z % p, new_z
|
||
|
)
|
||
|
|
||
|
c = a + b
|
||
|
|
||
|
self.assertEqual(c, j_g * (a_mul + b_mul))
|
||
|
|
||
|
@settings(max_examples=10)
|
||
|
@given(
|
||
|
st.integers(min_value=1, max_value=int(generator_256.order())),
|
||
|
st.integers(min_value=1, max_value=int(generator_256.order())),
|
||
|
st.integers(min_value=1, max_value=int(curve_256.p() - 1)),
|
||
|
)
|
||
|
@example(1, 1, 1)
|
||
|
@example(3, 3, 3)
|
||
|
@example(2, int(generator_256.order() - 2), 1)
|
||
|
@example(2, int(generator_256.order() - 2), 3)
|
||
|
def test_add_same_scale_points(self, a_mul, b_mul, new_z):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
a = PointJacobi.from_affine(j_g * a_mul)
|
||
|
b = PointJacobi.from_affine(j_g * b_mul)
|
||
|
|
||
|
p = curve_256.p()
|
||
|
|
||
|
assume(inverse_mod(new_z, p))
|
||
|
|
||
|
new_zz = new_z * new_z % p
|
||
|
|
||
|
a = PointJacobi(
|
||
|
curve_256, a.x() * new_zz % p, a.y() * new_zz * new_z % p, new_z
|
||
|
)
|
||
|
b = PointJacobi(
|
||
|
curve_256, b.x() * new_zz % p, b.y() * new_zz * new_z % p, new_z
|
||
|
)
|
||
|
|
||
|
c = a + b
|
||
|
|
||
|
self.assertEqual(c, j_g * (a_mul + b_mul))
|
||
|
|
||
|
@settings(max_examples=14)
|
||
|
@given(
|
||
|
st.integers(min_value=1, max_value=int(generator_256.order())),
|
||
|
st.integers(min_value=1, max_value=int(generator_256.order())),
|
||
|
st.lists(
|
||
|
st.integers(min_value=1, max_value=int(curve_256.p() - 1)),
|
||
|
min_size=2,
|
||
|
max_size=2,
|
||
|
unique=True,
|
||
|
),
|
||
|
)
|
||
|
@example(2, 2, [2, 1])
|
||
|
@example(2, 2, [2, 3])
|
||
|
@example(2, int(generator_256.order() - 2), [2, 3])
|
||
|
@example(2, int(generator_256.order() - 2), [2, 1])
|
||
|
def test_add_different_scale_points(self, a_mul, b_mul, new_z):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
a = PointJacobi.from_affine(j_g * a_mul)
|
||
|
b = PointJacobi.from_affine(j_g * b_mul)
|
||
|
|
||
|
p = curve_256.p()
|
||
|
|
||
|
assume(inverse_mod(new_z[0], p))
|
||
|
assume(inverse_mod(new_z[1], p))
|
||
|
|
||
|
new_zz0 = new_z[0] * new_z[0] % p
|
||
|
new_zz1 = new_z[1] * new_z[1] % p
|
||
|
|
||
|
a = PointJacobi(
|
||
|
curve_256,
|
||
|
a.x() * new_zz0 % p,
|
||
|
a.y() * new_zz0 * new_z[0] % p,
|
||
|
new_z[0],
|
||
|
)
|
||
|
b = PointJacobi(
|
||
|
curve_256,
|
||
|
b.x() * new_zz1 % p,
|
||
|
b.y() * new_zz1 * new_z[1] % p,
|
||
|
new_z[1],
|
||
|
)
|
||
|
|
||
|
c = a + b
|
||
|
|
||
|
self.assertEqual(c, j_g * (a_mul + b_mul))
|
||
|
|
||
|
def test_add_point_3_times(self):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
self.assertEqual(j_g * 3, j_g + j_g + j_g)
|
||
|
|
||
|
def test_mul_add_inf(self):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
self.assertEqual(j_g, j_g.mul_add(1, INFINITY, 1))
|
||
|
|
||
|
def test_mul_add_same(self):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
self.assertEqual(j_g * 2, j_g.mul_add(1, j_g, 1))
|
||
|
|
||
|
def test_mul_add_precompute(self):
|
||
|
j_g = PointJacobi.from_affine(generator_256, True)
|
||
|
b = PointJacobi.from_affine(j_g * 255, True)
|
||
|
|
||
|
self.assertEqual(j_g * 256, j_g + b)
|
||
|
self.assertEqual(j_g * (5 + 255 * 7), j_g * 5 + b * 7)
|
||
|
self.assertEqual(j_g * (5 + 255 * 7), j_g.mul_add(5, b, 7))
|
||
|
|
||
|
def test_mul_add_precompute_large(self):
|
||
|
j_g = PointJacobi.from_affine(generator_256, True)
|
||
|
b = PointJacobi.from_affine(j_g * 255, True)
|
||
|
|
||
|
self.assertEqual(j_g * 256, j_g + b)
|
||
|
self.assertEqual(
|
||
|
j_g * (0xFF00 + 255 * 0xF0F0), j_g * 0xFF00 + b * 0xF0F0
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
j_g * (0xFF00 + 255 * 0xF0F0), j_g.mul_add(0xFF00, b, 0xF0F0)
|
||
|
)
|
||
|
|
||
|
def test_mul_add_to_mul(self):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
a = j_g * 3
|
||
|
b = j_g.mul_add(2, j_g, 1)
|
||
|
|
||
|
self.assertEqual(a, b)
|
||
|
|
||
|
def test_mul_add(self):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
|
||
|
w_a = generator_256 * 255
|
||
|
w_b = generator_256 * (0xA8 * 0xF0)
|
||
|
j_b = j_g * 0xA8
|
||
|
|
||
|
ret = j_g.mul_add(255, j_b, 0xF0)
|
||
|
|
||
|
self.assertEqual(ret.to_affine(), w_a + w_b)
|
||
|
|
||
|
def test_mul_add_large(self):
|
||
|
j_g = PointJacobi.from_affine(generator_256)
|
||
|
b = PointJacobi.from_affine(j_g * 255)
|
||
|
|
||
|
self.assertEqual(j_g * 256, j_g + b)
|
||
|
self.assertEqual(
|
||
|
j_g * (0xFF00 + 255 * 0xF0F0), j_g * 0xFF00 + b * 0xF0F0
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
j_g * (0xFF00 + 255 * 0xF0F0), j_g.mul_add(0xFF00, b, 0xF0F0)
|
||
|
)
|
||
|
|
||
|
def test_equality(self):
|
||
|
pj1 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1)
|
||
|
pj2 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1)
|
||
|
self.assertEqual(pj1, pj2)
|
||
|
|
||
|
def test_pickle(self):
|
||
|
pj = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1)
|
||
|
self.assertEqual(pickle.loads(pickle.dumps(pj)), pj)
|