async def prog(ctx): pp_elements._init_data_dir() # Overwrite triples and one_minus_ones for kind, elems in zip(("triples", "one_minus_one"), (triples, bits)): if kind == "triples": elems = flatten_lists(elems) elems = [e.value for e in elems] mixin = pp_elements.mixins[kind] mixin_filename = mixin.build_filename(ctx.N, ctx.t, ctx.myid) mixin._write_preprocessing_file( mixin_filename, ctx.t, ctx.myid, elems, append=False ) pp_elements._init_mixins() logging.info(f"[{ctx.myid}] Running permutation network") inps = list(map(ctx.Share, inputs)) assert len(inps) == K shuffled = await iterated_butterfly_network(ctx, inps, K) shuffled_shares = ctx.ShareArray(list(map(ctx.Share, shuffled))) opened_values = await shuffled_shares.open() msgs = [ m.value.to_bytes(32, "big").decode().strip("\x00") for m in opened_values ] return msgs
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))
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)]))