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
def ecdsa_sign(ec: EC,
               hf,
               M: bytes,
               d: int,
               k: Optional[int] = None) -> Tuple[int, int]:
    """ECDSA signing operation according to SEC 1

       http://www.secg.org/sec1-v2.pdf
       Steps numbering follows SEC 1 v.2 section 4.1.3
    """

    # https://tools.ietf.org/html/rfc6979#section-3.2
    # The message M is first processed by hf, yielding the value hd(m),
    # a sequence of bits of length hlen.  Normally, hf is chosen such that
    # its output length hlen is roughly equal to nlen, since the overall
    # security of the signature scheme will depend on the smallest of hlen
    # and nlen; however, the (EC)DSA standard support all combinations of
    # hlen and nlen.
    hd = hf(M).digest()  # 4
    # H(m) is transformed into an integer modulo ec.n using bits2int:
    e = bits2int(ec, hd)  # 5

    if k is None:
        k = rfc6979(ec, hf, hd, d)  # 1

    # second part delegated to helper function used in testing
    return _ecdsa_sign(ec, e, d, k)
Exemplo n.º 3
0
def _ecssa_e(ec: EC, hf, r: int, P: Point, m: bytes) -> int:
    # Let e = int(hf(bytes(x(R)) || bytes(dG) || m)) mod n.
    ebytes = int2octets(r, ec.psize) # FIXME: hsize, nsize ?
    ebytes += point2octets(ec, P, True)
    ebytes += m
    ebytes = hf(ebytes).digest()
    e = bits2int(ec, ebytes)
    return e
def ecdsa_pubkey_recovery(ec: EC, hf, M: bytes, sig: ECDS) -> List[Point]:
    """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
    """

    # The message digest m: a 32-byte array
    hd = hf(M).digest()  # 1.5
    e = bits2int(ec, hd)  # 1.5

    return _ecdsa_pubkey_recovery(ec, e, sig)
Exemplo n.º 5
0
def ecssa_batch_validation(ec: EC,
                           hf,
                           ms: List[bytes],
                           P: List[Point],
                           a: List[int], 
                           sig: List[ECSS]) -> bool:
    # initialization
    mult = 0
    points = list()
    factors = list()

    u = len(P)
    for i in range(u):
        r, s = to_ssasig(ec, sig[i])
        ebytes = r.to_bytes(32, byteorder="big")
        ebytes += point2octets(ec, P[i], True)
        ebytes += ms[i]
        ebytes = hf(ebytes).digest()
        e = bits2int(ec, ebytes)

        y = ec.y(r)  # raises an error if y does not exist

        mult += a[i] * s % ec.n
        points.append(_jac_from_aff((r, y)))
        factors.append(a[i])
        points.append(_jac_from_aff(P[i]))
        factors.append(a[i] * e % ec.n)

    # Bos-coster's algorithm, source:
    # https://cr.yp.to/badbatch/boscoster2.py
    boscoster = list(zip([-n for n in factors], points))
    heapq.heapify(boscoster)
    while len(boscoster) > 1:
        aK1 = heapq.heappop(boscoster)
        aK2 = heapq.heappop(boscoster)
        a1, K1 = -aK1[0], aK1[1]
        a2, K2 = -aK2[0], aK2[1]
        K2 = ec._addJacobian(K1, K2)
        a1 -= a2
        if a1 > 0:
            heapq.heappush(boscoster, (-a1, K1))
        heapq.heappush(boscoster, (-a2, K2))
    aK = heapq.heappop(boscoster)

    RHSJ = _pointMultJacobian(ec, -aK[0], aK[1])
    TJ = _pointMultJacobian(ec, mult, _jac_from_aff(ec.G))
    RHS = ec._affine_from_jac(RHSJ)
    T = ec._affine_from_jac(TJ)

    return T == RHS
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 verify_commit(c: bytes, ec: EC, hf, receipt: Receipt) -> bool:
    w, R = receipt
    # w in [1..n-1] dsa
    # w in [1..p-1] ssa
    # different verify functions?

    # verify R is a good point?

    ch = hf(c).digest()
    e = hf(point2octets(ec, R, True) + ch).digest()
    e = bits2int(ec, e)
    W = ec.add(R, pointMult(ec, e, ec.G))
    # different verify functions?
    # return w == W[0] # ECSS
    return w == W[0] % ec.n  # ECDS
def _ecdsa_verify(ec: EC, hf, M: bytes, P: Point, sig: ECDS) -> bool:
    """Private function provided for testing purposes only.
    
       It raises Errors, while verify should always return True or False

       See SEC 1 v.2 section 4.1.4
       http://www.secg.org/sec1-v2.pdf
    """

    # The message digest m: a 32-byte array
    hd = hf(M).digest()  # 2
    e = bits2int(ec, hd)  # 3

    # Let P = point(pk); fail if point(pk) fails.
    # P on point will be checked below by DblScalarMult

    # second part delegated to helper function used in testing
    return _ecdsa_verhlp(ec, e, P, sig)
def secondGenerator(ec: EC, hf) -> Point:
    """Nothing-Up-My-Sleeve (NUMS) second generator H wrt ec.G 

       source: https://github.com/ElementsProject/secp256k1-zkp/blob/secp256k1-zkp/src/modules/rangeproof/main_impl.h
       idea: https://crypto.stackexchange.com/questions/25581/second-generator-for-secp256k1-curve
       Get the hash of G, then coerce it to a point (hx, hy).
       The resulting point could not be a curvepoint: in this case keep on
       incrementing hx until a valid curve point (hx, hy) is obtained.
    """
    G_bytes = point2octets(ec, ec.G, False)
    hd = hf(G_bytes).digest()
    hx = bits2int(ec, hd)
    isCurvePoint = False
    while not isCurvePoint:
        try:
            hy = ec.yOdd(hx, False)
            isCurvePoint = True
        except:
            hx += 1
    return hx, hy