コード例 #1
0
 def get_degree_and_secret(shares):
     decoder = DecoderFactory.get(eval_point)
     polys = decoder.decode(list(range(n)),
                            transpose_lists(list(shares)))
     secrets = [p[0] for p in polys]
     degrees = [get_degree(p) for p in polys]
     return degrees, secrets
コード例 #2
0
async def randousha(n, t, k, my_id, _send, _recv, field):
    """
    Generates a batch of (n-2t)k secret sharings of random elements
    """
    poly = polynomials_over(field)
    eval_point = EvalPoint(field, n, use_omega_powers=False)
    big_t = n - (2 * t) - 1  # This is same as `T` in the HyperMPC paper.
    encoder = EncoderFactory.get(eval_point)

    # Pick k random elements
    def to_int(coeffs):
        return tuple(map(int, coeffs))

    my_randoms = [field.random() for _ in range(k)]

    # Generate t and 2t shares of the random element.
    coeffs_t = [to_int(poly.random(t, r).coeffs) for r in my_randoms]
    coeffs_2t = [to_int(poly.random(2 * t, r).coeffs) for r in my_randoms]
    unref_t = encoder.encode(coeffs_t)
    unref_2t = encoder.encode(coeffs_2t)

    subscribe_recv_task, subscribe = subscribe_recv(_recv)

    def _get_send_recv(tag):
        return wrap_send(tag, _send), subscribe(tag)

    # Start listening for my share of t and 2t shares from all parties.
    send, recv = _get_send_recv("H1")
    share_recv_task = asyncio.create_task(_recv_loop(n, recv))

    # Send each party their shares.
    to_send_t = transpose_lists(unref_t)
    to_send_2t = transpose_lists(unref_2t)
    for i in range(n):
        send(i, (to_send_t[i], to_send_2t[i]))

    # Wait until all shares are received.
    received_shares = await share_recv_task
    unrefined_t_shares, unrefined_2t_shares = zip(*received_shares)

    # Apply the hyper-invertible matrix.
    # Assume the unrefined shares to be coefficients of a polynomial
    # and then evaluate that polynomial at powers of omega.
    ref_t = encoder.encode(transpose_lists(list(unrefined_t_shares)))
    ref_2t = encoder.encode(transpose_lists(list(unrefined_2t_shares)))

    # Parties with id in [N-2t+1, N] need to start
    # listening for shares which they have to check.
    send, recv = _get_send_recv("H2")
    to_send_t = transpose_lists(ref_t)
    to_send_2t = transpose_lists(ref_2t)

    if my_id > big_t:
        share_chk_recv_task = asyncio.create_task(_recv_loop(n, recv))

    # Send shares of parties with id in [N-2t+1, N] to those parties.
    for i in range(big_t + 1, n):
        send(i, (to_send_t[i], to_send_2t[i]))

    # Parties with id in [N-2t+1, N] need to verify that the shares are in-fact correct.
    if my_id > big_t:
        shares_to_check = await share_chk_recv_task
        shares_t, shares_2t = zip(*shares_to_check)
        response = HyperInvMessageType.ABORT

        def get_degree(p):
            for i in range(len(p))[::-1]:
                if p[i] != 0:
                    return i
            return 0

        def get_degree_and_secret(shares):
            decoder = DecoderFactory.get(eval_point)
            polys = decoder.decode(list(range(n)),
                                   transpose_lists(list(shares)))
            secrets = [p[0] for p in polys]
            degrees = [get_degree(p) for p in polys]
            return degrees, secrets

        degree_t, secret_t = get_degree_and_secret(shares_t)
        degree_2t, secret_2t = get_degree_and_secret(shares_2t)

        # Verify that the shares are in-fact `t` and `2t` shared.
        # Verify that both `t` and `2t` shares of the same value.
        if (all(deg == t for deg in degree_t)
                and all(deg == 2 * t for deg in degree_2t)
                and secret_t == secret_2t):
            response = HyperInvMessageType.SUCCESS

        logging.debug(
            "[%d] Degree check: %s, Secret Check: %s",
            my_id,
            all(deg == t for deg in degree_t)
            and all(deg == 2 * t for deg in degree_2t),
            secret_t == secret_2t,
        )

    # Start listening for the verification response.
    send, recv = _get_send_recv("H3")
    response_recv_task = asyncio.create_task(
        _recv_loop(n - big_t - 1, recv, big_t + 1))

    # Send the verification response.
    if my_id > big_t:
        for i in range(n):
            send(i, response)

    responses = await response_recv_task
    subscribe_recv_task.cancel()

    # If any of [T+1, N] parties say that the shares are inconsistent then abort.
    if responses.count(HyperInvMessageType.SUCCESS) != n - big_t - 1:
        raise HoneyBadgerMPCError(
            "Aborting because the shares were inconsistent.")

    out_t = flatten_lists([s[:big_t + 1] for s in ref_t])
    out_2t = flatten_lists([s[:big_t + 1] for s in ref_2t])

    return tuple(zip(out_t, out_2t))
コード例 #3
0
async def batch_reconstruct(
    secret_shares,
    p,
    t,
    n,
    myid,
    send,
    recv,
    config=None,
    use_omega_powers=False,
    debug=False,
    degree=None,
):
    """
    args:
      shared_secrets: an array of points representing shared secrets S1 - SB
      p: field modulus
      t: faults tolerated
      n: total number of nodes n >= 3t+1
      myid: id of the specific node running batch_reconstruction function
      degree: degree of polynomial to decode (defaults to t)

    output:
      the reconstructed array of B shares

    Communication takes place over two rounds,
      objects sent/received of the form('R1', shares) or ('R2', shares)
      up to one of each for each party

    Reconstruction takes places in chunks of t+1 values
    """
    bench_logger = logging.LoggerAdapter(logging.getLogger("benchmark_logger"),
                                         {"node_id": myid})

    if degree is None:
        degree = t

    secret_shares = [v.value for v in secret_shares]

    # (optional) Induce faults
    if config is not None and config.induce_faults:
        logging.debug("[FAULT][BatchReconstruction] Sending random shares.")
        secret_shares = [
            random.randint(0, p - 1) for _ in range(len(secret_shares))
        ]

    # Prepare recv loops for this batch reconstruction
    subscribe_task, subscribe = subscribe_recv(recv)
    del recv  # ILC enforces this in type system, no duplication of reads

    task_r1, recvs_r1 = recv_each_party(subscribe("R1"), n)
    data_r1 = [asyncio.create_task(recv()) for recv in recvs_r1]

    task_r2, recvs_r2 = recv_each_party(subscribe("R2"), n)
    data_r2 = [asyncio.create_task(recv()) for recv in recvs_r2]
    del subscribe  # ILC should determine we can garbage collect after this

    # Set up encoding and decoding algorithms
    fp = GF(p)
    decoding_algorithm = Algorithm.GAO if config is None else config.decoding_algorithm

    point = EvalPoint(fp, n, use_omega_powers=use_omega_powers)
    enc = EncoderFactory.get(
        point, Algorithm.FFT if use_omega_powers else Algorithm.VANDERMONDE)
    dec = DecoderFactory.get(
        point, Algorithm.FFT if use_omega_powers else Algorithm.VANDERMONDE)
    robust_dec = RobustDecoderFactory.get(t,
                                          point,
                                          algorithm=decoding_algorithm)

    # Prepare data for step 1
    round1_chunks = chunk_data(secret_shares, degree + 1)
    num_chunks = len(round1_chunks)

    # Step 1: Compute the polynomial P1, then send the elements
    start_time = time.time()

    encoded = enc.encode(round1_chunks)
    to_send = transpose_lists(encoded)
    for dest, message in enumerate(to_send):
        send(dest, ("R1", message))

    end_time = time.time()
    bench_logger.info(f"[BatchReconstruct] P1 Send: {end_time - start_time}")

    # Step 2: Attempt to reconstruct P1
    start_time = time.time()
    try:
        recons_r2 = await incremental_decode(data_r1, enc, dec, robust_dec,
                                             num_chunks, t, degree, n)
    except asyncio.CancelledError:
        # Cancel all created tasks
        for task in [task_r1, task_r2, subscribe_task, *data_r1, *data_r2]:
            task.cancel()

    if recons_r2 is None:
        logging.error("[BatchReconstruct] P1 reconstruction failed!")
        return None

    end_time = time.time()
    bench_logger.info(
        f"[BatchReconstruct] P1 Reconstruct: {end_time - start_time}")

    # Step 3: Send R2 points
    start_time = time.time()

    # Evaluate all chunks at x=0, then broadcast
    message = [chunk[0] for chunk in recons_r2]
    for dest in range(n):
        send(dest, ("R2", message))

    end_time = time.time()
    bench_logger.info(f"[BatchReconstruct] P2 Send: {end_time - start_time}")

    # Step 4: Attempt to reconstruct R2
    start_time = time.time()
    try:
        recons_p = await incremental_decode(data_r2, enc, dec, robust_dec,
                                            num_chunks, t, degree, n)
    except asyncio.CancelledError:
        # Cancel all created tasks
        for task in [task_r1, task_r2, subscribe_task, *data_r1, *data_r2]:
            task.cancel()

    if recons_p is None:
        logging.error("[BatchReconstruct] P2 reconstruction failed!")
        return None

    end_time = time.time()
    bench_logger.info(
        f"[BatchReconstruct] P2 Reconstruct: {end_time - start_time}")

    # Cancel all created tasks
    for task in [task_r1, task_r2, subscribe_task, *data_r1, *data_r2]:
        task.cancel()

    result = flatten_lists(recons_p)
    assert len(result) >= len(secret_shares)

    # Get back result as GFElement type
    return list(map(fp, result[:len(secret_shares)]))