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))
def _batch_verify(ec: Curve, hf, ms: List[bytes], P: List[Point],
                  sig: List[ECSS]) -> bool:
    t = 0
    scalars: List(int) = list()
    points: List[Point] = list()
    for i in range(len(P)):
        _ensure_msg_size(hf, ms[i])
        ec.require_on_curve(P[i])
        r, s = _to_sig(ec, sig[i])
        e = _e(ec, hf, r, P[i], ms[i])
        y = ec.y(r)  # raises an error if y does not exist

        # deterministically generated using a CSPRNG seeded by a cryptographic
        # hash (e.g., SHA256) of all inputs of the algorithm, or randomly
        # generated independently for each run of the batch verification
        # algorithm  FIXME
        a = (1 if i == 0 else random.getrandbits(ec.nlen) % ec.n)
        scalars.append(a)
        points.append(_jac_from_aff((r, y)))
        scalars.append(a * e % ec.n)
        points.append(_jac_from_aff(P[i]))
        t += a * s % ec.n

    TJ = _mult_jac(ec, t, ec.GJ)
    RHSJ = _multi_mult(ec, scalars, points)

    # return T == RHS, checked in Jacobian coordinates
    RHSZ2 = RHSJ[2] * RHSJ[2]
    TZ2 = TJ[2] * TJ[2]
    if (TJ[0] * RHSZ2) % ec._p != (RHSJ[0] * TZ2) % ec._p:
        return False

    return (TJ[1] * RHSZ2 * RHSJ[2]) % ec._p == (RHSJ[1] * TZ2 * TJ[2]) % ec._p
Example #5
0
def _sign(ec: Curve, e: int, d: int, k: int) -> Tuple[int, int]:
    """Private function provided for testing purposes only."""
    # e is assumed to be valid
    # Steps numbering follows SEC 1 v.2 section 4.1.3

    # The secret key d: an integer in the range 1..n-1.
    # SEC 1 v.2 section 3.2.1
    if not 0 < d < ec.n:
        raise ValueError(f"private key {hex(d)} not in (0, n)")

    # Fail if k' = 0.
    if not 0 < k < ec.n:
        raise ValueError(f"ephemeral key {hex(k)} not in (0, n)")
    # Let R = k'G.
    RJ = _mult_jac(ec, k, ec.GJ)                      # 1

    Rx = (RJ[0]*mod_inv(RJ[2]*RJ[2], ec._p)) % ec._p
    r = Rx % ec.n                                     # 2, 3
    if r == 0:  # r≠0 required as it multiplies the public key
        raise ValueError("r = 0, failed to sign")

    s = mod_inv(k, ec.n) * (e + r*d) % ec.n           # 6
    if s == 0:  # s≠0 required as verify will need the inverse of s
        raise ValueError("s = 0, failed to sign")

    # bitcoin canonical 'low-s' encoding for ECDSA signatures
    # it removes signature malleability as cause of transaction malleability
    # see https://github.com/bitcoin/bitcoin/pull/6769
    if s > ec.n / 2:
        s = ec.n - s

    return r, s
Example #6
0
def test_assorted_mult():
    ec = ec23_31
    H = second_generator(ec)
    HJ = _jac_from_aff(H)
    for k1 in range(ec.n):
        K1J = _mult_jac(k1, ec.GJ, ec)
        for k2 in range(ec.n):
            K2J = _mult_jac(k2, HJ, ec)

            shamir = _double_mult(k1, ec.GJ, k2, ec.GJ, ec)
            assert ec._jac_equality(shamir, _mult_jac(k1 + k2, ec.GJ, ec))

            shamir = _double_mult(k1, INFJ, k2, HJ, ec)
            assert ec._jac_equality(shamir, K2J)
            shamir = _double_mult(k1, ec.GJ, k2, INFJ, ec)
            assert ec._jac_equality(shamir, K1J)

            shamir = _double_mult(k1, ec.GJ, k2, HJ, ec)
            K1JK2J = ec._add_jac(K1J, K2J)
            assert ec._jac_equality(K1JK2J, shamir)

            k3 = 1 + secrets.randbelow(ec.n - 1)
            K3J = _mult_jac(k3, ec.GJ, ec)
            K1JK2JK3J = ec._add_jac(K1JK2J, K3J)
            boscoster = _multi_mult([k1, k2, k3], [ec.GJ, HJ, ec.GJ], ec)
            assert ec._jac_equality(K1JK2JK3J, boscoster)

            k4 = 1 + secrets.randbelow(ec.n - 1)
            K4J = _mult_jac(k4, HJ, ec)
            K1JK2JK3JK4J = ec._add_jac(K1JK2JK3J, K4J)
            points = [ec.GJ, HJ, ec.GJ, HJ]
            boscoster = _multi_mult([k1, k2, k3, k4], points, ec)
            assert ec._jac_equality(K1JK2JK3JK4J, boscoster)
            assert ec._jac_equality(K1JK2JK3J, _multi_mult([k1, k2, k3, 0], points, ec))
            assert ec._jac_equality(K1JK2J, _multi_mult([k1, k2, 0, 0], points, ec))
            assert ec._jac_equality(K1J, _multi_mult([k1, 0, 0, 0], points, ec))
            assert ec._jac_equality(INFJ, _multi_mult([0, 0, 0, 0], points, ec))

    err_msg = "mismatch between number of scalars and points: "
    with pytest.raises(ValueError, match=err_msg):
        _multi_mult([k1, k2, k3, k4], [ec.GJ, HJ, ec.GJ], ec)

    with pytest.raises(ValueError, match="negative first coefficient: "):
        _double_mult(-5, HJ, 1, ec.GJ, ec)
    with pytest.raises(ValueError, match="negative second coefficient: "):
        _double_mult(1, HJ, -5, ec.GJ, ec)
Example #7
0
def _batch_verify(ec: Curve, hf: Callable[[Any], Any], ms: Sequence[bytes],
                  P: Sequence[Point], sig: Sequence[ECSS]) -> bool:

    # the bitcoin proposed standard is only valid for curves
    # whose prime p = 3 % 4
    if not ec.pIsThreeModFour:
        errmsg = 'curve prime p must be equal to 3 (mod 4)'
        raise ValueError(errmsg)

    batch_size = len(P)
    if len(ms) != batch_size:
        errMsg = f"mismatch between number of pubkeys ({batch_size}) "
        errMsg += f"and number of messages ({len(ms)})"
        raise ValueError(errMsg)
    if len(sig) != batch_size:
        errMsg = f"mismatch between number of pubkeys ({batch_size}) "
        errMsg += f"and number of signatures ({len(sig)})"
        raise ValueError(errMsg)

    if batch_size == 1:
        return _verify(ec, hf, ms[0], P[0], sig[0])

    t = 0
    scalars: Sequence(int) = list()
    points: Sequence[Point] = list()
    for i in range(batch_size):
        r, s = _to_sig(ec, sig[i])
        _ensure_msg_size(hf, ms[i])
        ec.require_on_curve(P[i])
        e = _e(ec, hf, r, P[i], ms[i])
        # raises an error if y does not exist
        # no need to check for quadratic residue
        y = ec.y(r)

        # a in [1, n-1]
        # deterministically generated using a CSPRNG seeded by a
        # cryptographic hash (e.g., SHA256) of all inputs of the
        # algorithm, or randomly generated independently for each
        # run of the batch verification algorithm
        a = (1 if i == 0 else (1 + random.getrandbits(ec.nlen)) % ec.n)
        scalars.append(a)
        points.append(_jac_from_aff((r, y)))
        scalars.append(a * e % ec.n)
        points.append(_jac_from_aff(P[i]))
        t += a * s

    TJ = _mult_jac(ec, t, ec.GJ)
    RHSJ = _multi_mult(ec, scalars, points)

    # return T == RHS, checked in Jacobian coordinates
    RHSZ2 = RHSJ[2] * RHSJ[2]
    TZ2 = TJ[2] * TJ[2]
    if (TJ[0] * RHSZ2) % ec._p != (RHSJ[0] * TZ2) % ec._p:
        return False

    return (TJ[1] * RHSZ2 * RHSJ[2]) % ec._p == (RHSJ[1] * TZ2 * TJ[2]) % ec._p
Example #8
0
def test_mult_jac_curves():
    for ec in all_curves.values():
        assert _mult_jac(0, ec.GJ, ec) == INFJ
        assert _mult_jac(0, INFJ, ec) == INFJ

        assert _mult_jac(1, INFJ, ec) == INFJ
        assert _mult_jac(1, ec.GJ, ec) == ec.GJ

        PJ = ec._add_jac(ec.GJ, ec.GJ)
        assert PJ == _mult_jac(2, ec.GJ, ec)

        PJ = _mult_jac(ec.n - 1, ec.GJ, ec)
        assert ec._jac_equality(ec.negate(ec.GJ), PJ)

        assert _mult_jac(ec.n - 1, INFJ, ec) == INFJ
        assert ec._add_jac(PJ, ec.GJ) == INFJ
        assert _mult_jac(ec.n, ec.GJ, ec) == INFJ

        with pytest.raises(ValueError, match="negative m: -0x"):
            _mult_jac(-1, ec.GJ, ec)
Example #9
0
def sign(ec: Curve,
         hf: Callable[[Any], Any],
         mhd: bytes,
         d: int,
         k: Optional[int] = None) -> ECSS:
    """ ECSSA signing operation according to bip-schnorr

        This signature scheme supports 32-byte messages.
        Differently from ECDSA, the 32-byte message can be a
        digest of other messages, but it does not need to.

        https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki
    """

    # the bitcoin proposed standard is only valid for curves
    # whose prime p = 3 % 4
    if not ec.pIsThreeModFour:
        errmsg = 'curve prime p must be equal to 3 (mod 4)'
        raise ValueError(errmsg)

    # The message mhd: a 32-byte array
    _ensure_msg_size(hf, mhd)

    # The secret key d: an integer in the range 1..n-1.
    if not 0 < d < ec.n:
        raise ValueError(f"private key {hex(d)} not in [1, n-1]")
    P = mult(ec, d, ec.G)

    # Fail if k' = 0.
    if k is None:
        k = rfc6979(ec, hf, mhd, d)
    if not 0 < k < ec.n:
        raise ValueError(f"ephemeral key {hex(k)} not in [1, n-1]")

    # Let R = k'G.
    RJ = _mult_jac(ec, k, ec.GJ)

    # break the simmetry: any criteria might have been used,
    # jacobi is the proposed bitcoin standard
    # Let k = k' if jacobi(y(R)) = 1, otherwise let k = n - k'.
    if legendre_symbol(RJ[1] * RJ[2] % ec._p, ec._p) != 1:
        k = ec.n - k

    Z2 = RJ[2] * RJ[2]
    r = (RJ[0] * mod_inv(Z2, ec._p)) % ec._p

    # Let e = int(hf(bytes(x(R)) || bytes(dG) || mhd)) mod n.
    e = _e(ec, hf, r, P, mhd)

    s = (k +
         e * d) % ec.n  # s=0 is ok: in verification there is no inverse of s
    # The signature is bytes(x(R) || bytes((k + ed) mod n)).
    return r, s
Example #10
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 #11
0
def _sign(ec: Curve, c: int, q: int, k: int) -> ECDS:
    # Private function for test/dev purposes
    # it is assumed that q, k, and c are in [1, n-1]

    # Steps numbering follows SEC 1 v.2 section 4.1.3

    RJ = _mult_jac(ec, k, ec.GJ)  # 1

    Rx = (RJ[0] * mod_inv(RJ[2] * RJ[2], ec._p)) % ec._p
    r = Rx % ec.n  # 2, 3
    if r == 0:  # r≠0 required as it multiplies the public key
        raise ValueError("r = 0, failed to sign")

    s = mod_inv(k, ec.n) * (c + r * q) % ec.n  # 6
    if s == 0:  # s≠0 required as verify will need the inverse of s
        raise ValueError("s = 0, failed to sign")

    # bitcoin canonical 'low-s' encoding for ECDSA signatures
    # it removes signature malleability as cause of transaction malleability
    # see https://github.com/bitcoin/bitcoin/pull/6769
    if s > ec.n / 2:
        s = ec.n - s

    return r, s
Example #12
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)