def _ecdsa_pubkey_recovery(ec: EC, e: int, sig: ECDS) -> List[Point]:
    """Private function provided for testing purposes only."""
    # ECDSA public key recovery operation according to SEC 1
    # http://www.secg.org/sec1-v2.pdf
    # See SEC 1 v.2 section 4.1.6

    r, s = to_dsasig(ec, sig)

    # precomputations
    r1 = mod_inv(r, ec.n)
    r1s = r1 * s
    r1e = -r1 * e
    keys = []
    for j in range(ec.h):  # 1
        x = r + j * ec.n  # 1.1
        try:
            R = (x % ec._p, ec.yOdd(x, 1))  # 1.2, 1.3, and 1.4
            # 1.5 already taken care outside this for loop
            Q = DblScalarMult(ec, r1s, R, r1e, ec.G)  # 1.6.1
            if Q[1] != 0 and _ecdsa_verhlp(ec, e, Q, sig):  # 1.6.2
                keys.append(Q)
            R = ec.opposite(R)  # 1.6.3
            Q = DblScalarMult(ec, r1s, R, r1e, ec.G)
            if Q[1] != 0 and _ecdsa_verhlp(ec, e, Q, sig):  # 1.6.2
                keys.append(Q)  # 1.6.2
        except Exception:  # R is not a curve point
            pass
    return keys
def borromean_sign(
        msg: bytes, k: List[int], sign_key_idx: List[int],
        sign_keys: List[int],
        pubk_rings: Dict[int,
                         List[Point]]) -> Tuple[bytes, Dict[int, List[int]]]:
    """ Borromean ring signature - signing algorithm

    inputs:
    - msg: msg to be signed (bytes)
    - sign_key_idx: list of indexes representing each signing key per ring
    - sign_keys: list containing the whole set of signing keys (one per ring)
    - pubk_rings: dictionary of lists where internal lists represent single rings of pubkeys
    """
    s: Dict[int, List[int]] = defaultdict(list)
    e: Dict[int, List[int]] = defaultdict(list)
    m = get_msg_format(msg, pubk_rings)
    e0bytes = m
    ring_size = len(pubk_rings)
    # step 1
    for i in range(ring_size):
        keys_size = len(pubk_rings[i])
        s[i] = [0] * keys_size
        e[i] = [0] * keys_size
        j_star = sign_key_idx[i]
        start_idx = (j_star + 1) % keys_size
        R = point2octets(ec, pointMult(ec, k[i], ec.G), True)
        if start_idx != 0:
            for j in range(start_idx, keys_size):
                s[i][j] = random.getrandbits(256)
                temp = borromean_hash(m, R, i, j)
                e[i][j] = bits2int(ec, temp)
                assert e[i][j] != 0 and e[i][j] < ec.n, "sign fail"
                T = DblScalarMult(ec, s[i][j], ec.G, -e[i][j],
                                  pubk_rings[i][j])
                R = point2octets(ec, T, True)
        e0bytes += R
    e0 = sha256(e0bytes).digest()
    # step 2
    for i in range(ring_size):
        temp = borromean_hash(m, e0, i, 0)
        e[i][0] = bits2int(ec, temp)
        assert e[i][0] != 0 and e[i][0] < ec.n, "sign fail"
        j_star = sign_key_idx[i]
        for j in range(1, j_star + 1):
            s[i][j - 1] = random.getrandbits(256)
            T = DblScalarMult(ec, s[i][j - 1], ec.G, -e[i][j - 1],
                              pubk_rings[i][j - 1])
            R = point2octets(ec, T, True)
            e[i][j] = bits2int(ec, borromean_hash(m, R, i, j))
            assert e[i][j] != 0 and e[i][j] < ec.n, "sign fail"
        s[i][j_star] = k[i] + sign_keys[i] * e[i][j_star]
    return e0, s
Example #3
0
def _ecssa_pubkey_recovery(ec: EC, hf, e: int, sig: ECSS) -> Point:
    """Private function provided for testing purposes only."""

    r, s = to_ssasig(ec, sig)

    # could be obtained from to_ssasig...
    K = r, ec.yQuadraticResidue(r, True)

    if e == 0:
        raise ValueError("invalid (zero) challenge e")
    e1 = mod_inv(e, ec.n)
    P = DblScalarMult(ec, e1*s, ec.G, -e1, K)
    assert P[1] != 0, "how did you do that?!?"
    return P
Example #4
0
def _ecssa_verify(ec: EC, hf, m: bytes, P: Point, sig: ECSS) -> bool:
    """Private function provided for testing purposes only.
    
       It raises Errors, while verify should always return True or False

       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)

    # Let r = int(sig[ 0:32]); fail if r is not [0, p-1].
    # Let s = int(sig[32:64]); fail if s is not [0, n-1].
    r, s = to_ssasig(ec, sig)

    # The message m: a 32-byte array
    if len(m) != hf().digest_size:
        errmsg = f'message of wrong size: {len(m)}'
        errmsg += f' instead of {hf().digest_size}'
        raise ValueError(errmsg)

    # Let P = point(pk); fail if point(pk) fails.
    ec.requireOnCurve(P)
    if P[1] == 0:
        raise ValueError("public key is infinite")

    # Let e = int(hf(bytes(r) || bytes(P) || m)) mod n.
    e = _ecssa_e(ec, hf, r, P, m)

    # Let R = sG - eP.
    R = DblScalarMult(ec, s, ec.G, -e, P)

    # Fail if infinite(R).
    if R[1] == 0:
        raise ValueError("sG - eP is infinite")

    # Fail if jacobi(y(R)) ≠ 1.
    if legendre_symbol(R[1], ec._p) != 1:
        raise ValueError("y(sG - eP) is not a quadratic residue")

    # Fail if x(R) ≠ r.
    return R[0] == r
def _ecdsa_verhlp(ec: EC, e: int, P: Point, sig: ECDS) -> bool:
    """Private function provided for testing purposes only."""
    # Fail if r is not [1, n-1]
    # Fail if s is not [1, n-1]
    r, s = to_dsasig(ec, sig)  # 1

    # Let P = point(pk); fail if point(pk) fails.
    ec.requireOnCurve(P)
    if P[1] == 0:
        raise ValueError("public key is infinite")

    s1 = mod_inv(s, ec.n)
    u = e * s1
    v = r * s1  # 4
    # Let R = u*G + v*P.
    R = DblScalarMult(ec, u, ec.G, v, P)  # 5

    # Fail if infinite(R).
    assert R[1] != 0, "how did you do that?!?"  # 5

    v = R[0] % ec.n  # 6, 7
    # Fail if r ≠ x(R) %n.
    return r == v  # 8
def _borromean_verify(msg: bytes, e0: bytes, s: Dict[int, List[int]],
                      pubk_rings: Dict[int, List[Point]]) -> bool:

    ring_size = len(pubk_rings)
    m = get_msg_format(msg, pubk_rings)
    e: Dict[int, List[int]] = defaultdict(list)
    e0bytes = m
    for i in range(ring_size):
        keys_size = len(pubk_rings[i])
        e[i] = [0] * keys_size
        e[i][0] = bits2int(ec, borromean_hash(m, e0, i, 0))
        assert e[i][0] != 0, "how did you do that?!?"
        R = b'\0x00'
        for j in range(keys_size):
            T = DblScalarMult(ec, s[i][j], ec.G, -e[i][j], pubk_rings[i][j])
            R = point2octets(ec, T, True)
            if j != len(pubk_rings[i]) - 1:
                e[i][j + 1] = bits2int(ec, borromean_hash(m, R, i, j + 1))
                assert e[i][j + 1] != 0, "how did you do that?!?"
            else:
                e0bytes += R
    e0_prime = sha256(e0bytes).digest()
    return e0_prime == e0
def pedersen_commit(r: int, v: int, ec: EC, hf) -> Point:
    """Return rG + vH, with H being second (NUMS) generator of the curve"""
    H = secondGenerator(ec, hf)
    Q = DblScalarMult(ec, r, ec.G, v, H)
    assert Q[1] != 0, "how did you do that?!?"
    return Q