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,
generator_brainpoolp160r1,
curve_brainpoolp160r1,
)
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_brainpoolp160r1.order())
)
)
def test_multiplications(self, mul):
pj = PointJacobi.from_affine(generator_brainpoolp160r1)
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_brainpoolp160r1.order())
)
)
@example(0)
@example(int(generator_brainpoolp160r1.order()))
def test_precompute(self, mul):
precomp = PointJacobi.from_affine(generator_brainpoolp160r1, True)
pj = PointJacobi.from_affine(generator_brainpoolp160r1)
a = precomp * mul
b = pj * mul
self.assertEqual(a, b)
@settings(max_examples=10)
@given(
st.integers(
min_value=1, max_value=int(generator_brainpoolp160r1.order())
),
st.integers(
min_value=1, max_value=int(generator_brainpoolp160r1.order())
),
)
@example(3, 3)
def test_add_scaled_points(self, a_mul, b_mul):
j_g = PointJacobi.from_affine(generator_brainpoolp160r1)
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_brainpoolp160r1.order())
),
st.integers(
min_value=1, max_value=int(generator_brainpoolp160r1.order())
),
st.integers(min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)),
)
def test_add_one_scaled_point(self, a_mul, b_mul, new_z):
j_g = PointJacobi.from_affine(generator_brainpoolp160r1)
a = PointJacobi.from_affine(j_g * a_mul)
b = PointJacobi.from_affine(j_g * b_mul)
p = curve_brainpoolp160r1.p()
assume(inverse_mod(new_z, p))
new_zz = new_z * new_z % p
b = PointJacobi(
curve_brainpoolp160r1,
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_brainpoolp160r1.order())
),
st.integers(
min_value=1, max_value=int(generator_brainpoolp160r1.order())
),
st.integers(min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)),
)
@example(1, 1, 1)
@example(3, 3, 3)
@example(2, int(generator_brainpoolp160r1.order() - 2), 1)
@example(2, int(generator_brainpoolp160r1.order() - 2), 3)
def test_add_same_scale_points(self, a_mul, b_mul, new_z):
j_g = PointJacobi.from_affine(generator_brainpoolp160r1)
a = PointJacobi.from_affine(j_g * a_mul)
b = PointJacobi.from_affine(j_g * b_mul)
p = curve_brainpoolp160r1.p()
assume(inverse_mod(new_z, p))
new_zz = new_z * new_z % p
a = PointJacobi(
curve_brainpoolp160r1,
a.x() * new_zz % p,
a.y() * new_zz * new_z % p,
new_z,
)
b = PointJacobi(
curve_brainpoolp160r1,
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_brainpoolp160r1.order())
),
st.integers(
min_value=1, max_value=int(generator_brainpoolp160r1.order())
),
st.lists(
st.integers(
min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)
),
min_size=2,
max_size=2,
unique=True,
),
)
@example(2, 2, [2, 1])
@example(2, 2, [2, 3])
@example(2, int(generator_brainpoolp160r1.order() - 2), [2, 3])
@example(2, int(generator_brainpoolp160r1.order() - 2), [2, 1])
def test_add_different_scale_points(self, a_mul, b_mul, new_z):
j_g = PointJacobi.from_affine(generator_brainpoolp160r1)
a = PointJacobi.from_affine(j_g * a_mul)
b = PointJacobi.from_affine(j_g * b_mul)
p = curve_brainpoolp160r1.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_brainpoolp160r1,
a.x() * new_zz0 % p,
a.y() * new_zz0 * new_z[0] % p,
new_z[0],
)
b = PointJacobi(
curve_brainpoolp160r1,
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)