Example #1
0
def test_mult():
    for ec in low_card_curves.values():
        for q in range(ec.n):
            Q = _mult_aff(q, ec.G, ec)
            QJ = _mult_jac(q, ec.GJ, ec)
            assert Q == ec._aff_from_jac(QJ)
        assert INF == _mult_aff(q, INF, ec)
        assert INFJ == _mult_jac(q, INFJ, ec)
Example #2
0
 def test_mult(self):
     for ec in low_card_curves.values():
         for q in range(ec.n):
             Q = _mult_aff(q, ec.G, ec)
             QJ = _mult_jac(q, ec.GJ, ec)
             Q2 = ec._aff_from_jac(QJ)
             self.assertEqual(Q, Q2)
     # with last curve
     self.assertEqual(INF, _mult_aff(3, INF, ec))
     self.assertEqual(INFJ, _mult_jac(3, INFJ, ec))
Example #3
0
 def test_mult(self):
     for ec in low_card_curves:
         for q in range(ec.n):
             Q = _mult_aff(ec, q, ec.G)
             Qjac = _mult_jac(ec, q, ec.GJ)
             Q2 = ec._aff_from_jac(Qjac)
             self.assertEqual(Q, Q2)
     # with last curve
     self.assertEqual(Inf, _mult_aff(ec, 3, Inf))
     self.assertEqual(InfJ, _mult_jac(ec, 3, InfJ))
Example #4
0
def test_mult_aff_curves():
    for ec in all_curves.values():
        assert _mult_aff(0, ec.G, ec) == INF
        assert _mult_aff(0, INF, ec) == INF

        assert _mult_aff(1, INF, ec) == INF
        assert _mult_aff(1, ec.G, ec) == ec.G

        P = ec._add_aff(ec.G, ec.G)
        assert P == _mult_aff(2, ec.G, ec)

        P = _mult_aff(ec.n - 1, ec.G, ec)
        assert ec.negate(ec.G) == P

        assert _mult_aff(ec.n - 1, INF, ec) == INF
        assert ec._add_aff(P, ec.G) == INF
        assert _mult_aff(ec.n, ec.G, ec) == INF

        with pytest.raises(ValueError, match="negative m: -0x"):
            _mult_aff(-1, ec.G, ec)
Example #5
0
def test_jac():

    ec = Curve(13, 0, 2, (1, 9), 19, 1, False)
    assert ec._jac_equality(ec.GJ, _jac_from_aff(ec.G))

    # q in [2, n-1]
    q = 2 + secrets.randbelow(ec.n - 2)
    Q = _mult_aff(q, ec.G, ec)
    QJ = _mult_jac(q, ec.GJ, ec)
    assert ec._jac_equality(QJ, _jac_from_aff(Q))
    assert not ec._jac_equality(QJ, ec.negate(QJ))
    assert not ec._jac_equality(QJ, ec.GJ)
Example #6
0
    def test_ecf(self):
        ec = CurveGroup(9739, 497, 1768)

        # challenge = 'Point Negation'
        P = (8045, 6936)
        S = ec.negate(P)
        S_exp = (8045, 2803)
        self.assertEqual(S, S_exp)

        # challenge = 'Point Addition'
        X = (5274, 2841)
        Y = (8669, 740)
        assert ec.add(X, Y) == (1024, 4440)
        assert ec.add(X, X) == (7284, 2107)
        P = (493, 5564)
        Q = (1539, 4742)
        R = (4403, 5202)
        S = ec.add(ec.add(ec.add(P, P), Q), R)
        ec.require_on_curve(S)
        S_exp = (4215, 2162)
        self.assertEqual(S, S_exp)

        # challenge = 'Scalar Multiplication'
        X = (5323, 5438)
        assert _mult_aff(1337, X, ec) == (1089, 6931)
        P = (2339, 2213)
        S = _mult_aff(7863, P, ec)
        ec.require_on_curve(S)
        S_exp = (9467, 2742)
        self.assertEqual(S, S_exp)

        # challenge = 'Curves and Logs'
        all_points = find_all_points(ec)
        self.assertEqual(len(all_points), 9735)
        G = (1804, 5368)
        points = find_subgroup_points(ec, G)
        self.assertEqual(len(points), 9735)
Example #7
0
def test_is_on_curve():
    for ec in all_curves.values():

        P = "not a point"
        with pytest.raises(ValueError, match="point must be a tuple"):
            ec.is_on_curve(P)

        with pytest.raises(ValueError, match="x-coordinate not in 0..p-1: "):
            ec.y(ec.p)

        # just a random point, not INF
        q = 1 + secrets.randbelow(ec.n - 1)
        Q = _mult_aff(q, ec.G, ec)
        with pytest.raises(ValueError, match="y-coordinate not in 1..p-1: "):
            ec.is_on_curve((Q[0], ec.p))
Example #8
0
def test_add():
    for ec in all_curves.values():

        # just a random point, not INF
        q = 1 + secrets.randbelow(ec.n - 1)
        Q = _mult_aff(q, ec.G, ec)
        QJ = _jac_from_aff(Q)

        # add Q and G
        R = ec._add_aff(Q, ec.G)
        RJ = ec._add_jac(QJ, ec.GJ)
        assert R == ec._aff_from_jac(RJ)

        # double Q
        R = ec._add_aff(Q, Q)
        RJ = ec._add_jac(QJ, QJ)
        assert R == ec._aff_from_jac(RJ)
Example #9
0
def test_aff_jac_conversions():
    for ec in all_curves.values():

        # just a random point, not INF
        q = 1 + secrets.randbelow(ec.n - 1)
        Q = _mult_aff(q, ec.G, ec)
        QJ = _jac_from_aff(Q)
        assert Q == ec._aff_from_jac(QJ)
        x_Q = ec._x_aff_from_jac(QJ)
        assert Q[0] == x_Q

        assert INF == ec._aff_from_jac(_jac_from_aff(INF))

        # relevant for BIP340-Schnorr signature verification
        assert not ec.has_square_y(INF)
        with pytest.raises(ValueError,
                           match="infinity point has no x-coordinate"):
            ec._x_aff_from_jac(INFJ)
        with pytest.raises(TypeError, match="not a point"):
            ec.has_square_y("notapoint")
Example #10
0
def test_negate():
    for ec in all_curves.values():

        # just a random point, not INF
        q = 1 + secrets.randbelow(ec.n - 1)
        Q = _mult_aff(q, ec.G, ec)
        minus_Q = ec.negate(Q)
        assert ec.add(Q, minus_Q) == INF

        # Jacobian coordinates
        QJ = _jac_from_aff(Q)
        minus_QJ = ec.negate(QJ)
        assert ec._add_jac(QJ, minus_QJ) == INFJ

        # negate of INF is INF
        minus_INF = ec.negate(INF)
        assert minus_INF == INF

        # negate of INFJ is INFJ
        minus_INFJ = ec.negate(INFJ)
        assert minus_INFJ == INFJ

    with pytest.raises(TypeError, match="not a point"):
        ec.negate("notapoint")
Example #11
0
def test_octets2point():
    for ec in all_curves.values():

        Gbytes = bytes_from_point(ec.G, ec)
        G2 = point_from_octets(Gbytes, ec)
        assert ec.G == G2

        Gbytes = bytes_from_point(ec.G, ec, False)
        G2 = point_from_octets(Gbytes, ec)
        assert ec.G == G2

        # just a random point, not INF
        q = 1 + secrets.randbelow(ec.n - 1)
        Q = _mult_aff(q, ec.G, ec)

        Q_bytes = b"\x03" if Q[1] & 1 else b"\x02"
        Q_bytes += Q[0].to_bytes(ec.psize, byteorder="big")
        R = point_from_octets(Q_bytes, ec)
        assert R == Q
        assert bytes_from_point(R, ec) == Q_bytes

        Q_hex_str = Q_bytes.hex()
        R = point_from_octets(Q_hex_str, ec)
        assert R == Q

        Q_bytes = b"\x04" + Q[0].to_bytes(ec.psize, byteorder="big")
        Q_bytes += Q[1].to_bytes(ec.psize, byteorder="big")
        R = point_from_octets(Q_bytes, ec)
        assert R == Q
        assert bytes_from_point(R, ec, False) == Q_bytes

        Q_hex_str = Q_bytes.hex()
        R = point_from_octets(Q_hex_str, ec)
        assert R == Q

        t = tuple()
        err_msg = "'<' not supported between instances of 'tuple' and 'int'"
        with pytest.raises(TypeError, match=err_msg):
            _mult_aff(t, ec.G, ec)

        Q_bytes = b"\x01" + b"\x01" * ec.psize
        with pytest.raises(ValueError, match="not a point: "):
            point_from_octets(Q_bytes, ec)

        Q_bytes = b"\x01" + b"\x01" * 2 * ec.psize
        with pytest.raises(ValueError, match="not a point: "):
            point_from_octets(Q_bytes, ec)

        Q_bytes = b"\x04" + b"\x01" * ec.psize
        with pytest.raises(ValueError,
                           match="invalid size for uncompressed point: "):
            point_from_octets(Q_bytes, ec)

        Q_bytes = b"\x02" + b"\x01" * 2 * ec.psize
        with pytest.raises(ValueError,
                           match="invalid size for compressed point: "):
            point_from_octets(Q_bytes, ec)

        Q_bytes = b"\x03" + b"\x01" * 2 * ec.psize
        with pytest.raises(ValueError,
                           match="invalid size for compressed point: "):
            point_from_octets(Q_bytes, ec)

    # invalid x_Q coordinate
    ec = CURVES["secp256k1"]
    x_Q = 0xEEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34
    xstr = format(x_Q, "32X")
    with pytest.raises(ValueError, match="invalid x-coordinate: "):
        point_from_octets("03" + xstr, ec)
    with pytest.raises(ValueError, match="point not on curve: "):
        point_from_octets("04" + 2 * xstr, ec)
    with pytest.raises(ValueError, match="point not on curve"):
        bytes_from_point((x_Q, x_Q), ec)
    with pytest.raises(ValueError, match="point not on curve"):
        bytes_from_point((x_Q, x_Q), ec, False)
Example #12
0
def test_symmetry():
    """Methods to break simmetry: quadratic residue, odd/even, low/high"""
    for ec in low_card_curves.values():

        # just a random point, not INF
        q = 1 + secrets.randbelow(ec.n - 1)
        Q = _mult_aff(q, ec.G, ec)
        x_Q = Q[0]

        y_odd = ec.y_odd(x_Q)
        assert y_odd % 2 == 1
        y_even = ec.y_odd(x_Q, False)
        assert y_even % 2 == 0
        assert y_even == ec.p - y_odd

        y_low = ec.y_low(x_Q)
        y_high = ec.y_low(x_Q, False)
        assert y_low < y_high
        assert y_high == ec.p - y_low

        # compute quadratic residues
        hasRoot = set()
        hasRoot.add(1)
        for i in range(2, ec.p):
            hasRoot.add(i * i % ec.p)

        if ec.p % 4 == 3:
            quad_res = ec.y_quadratic_residue(x_Q)
            not_quad_res = ec.y_quadratic_residue(x_Q, False)

            # in this case only quad_res is a quadratic residue
            assert quad_res in hasRoot
            root = mod_sqrt(quad_res, ec.p)
            assert quad_res == (root * root) % ec.p
            root = ec.p - root
            assert quad_res == (root * root) % ec.p

            assert not_quad_res == ec.p - quad_res
            assert not_quad_res not in hasRoot
            with pytest.raises(ValueError, match="no root for "):
                mod_sqrt(not_quad_res, ec.p)
        else:
            assert ec.p % 4 == 1
            # cannot use y_quadratic_residue in this case
            err_msg = "field prime is not equal to 3 mod 4: "
            with pytest.raises(ValueError, match=err_msg):
                ec.y_quadratic_residue(x_Q)
            with pytest.raises(ValueError, match=err_msg):
                ec.y_quadratic_residue(x_Q, False)

            # in this case neither or both y_Q are quadratic residues
            neither = y_odd not in hasRoot and y_even not in hasRoot
            both = y_odd in hasRoot and y_even in hasRoot
            assert neither or both
            if y_odd in hasRoot:  # both have roots
                root = mod_sqrt(y_odd, ec.p)
                assert y_odd == (root * root) % ec.p
                root = ec.p - root
                assert y_odd == (root * root) % ec.p
                root = mod_sqrt(y_even, ec.p)
                assert y_even == (root * root) % ec.p
                root = ec.p - root
                assert y_even == (root * root) % ec.p
            else:
                err_msg = "no root for "
                with pytest.raises(ValueError, match=err_msg):
                    mod_sqrt(y_odd, ec.p)
                with pytest.raises(ValueError, match=err_msg):
                    mod_sqrt(y_even, ec.p)

    # with the last curve
    with pytest.raises(ValueError, match="low1high0 must be bool or 1/0"):
        ec.y_low(x_Q, 2)
    with pytest.raises(ValueError, match="odd1even0 must be bool or 1/0"):
        ec.y_odd(x_Q, 2)
    with pytest.raises(ValueError, match="quad_res must be bool or 1/0"):
        ec.y_quadratic_residue(x_Q, 2)
Example #13
0
# or distributed except according to the terms contained in the LICENSE file.

import random
import time

from btclib.curve import _jac_from_aff, _mult_aff, _mult_jac
from btclib.curves import secp256k1

random.seed(42)

ec = secp256k1

# setup
qs = []
for _ in range(50):
    qs.append(random.getrandbits(ec.nlen) % ec.n)

start = time.time()
for q in qs:
    _mult_aff(ec, q, ec.G)
elapsed1 = time.time() - start

start = time.time()
for q in qs:
    # starts from affine coordinates, ends with affine coordinates
    GJ = _jac_from_aff(ec.G)
    ec._aff_from_jac(_mult_jac(ec, q, GJ))
elapsed2 = time.time() - start

print(elapsed2 / elapsed1)