async def test_butterfly_network(): n, t, k, delta = 3, 1, 32, -9999 pp_elements = PreProcessedElements() pp_elements.generate_rands(1000, n, t) pp_elements.generate_one_minus_ones(1000, n, t) pp_elements.generate_triples(1500, n, t) async def verify_output(ctx, **kwargs): k, delta = kwargs["k"], kwargs["delta"] inputs = [ctx.preproc.get_rand(ctx) for _ in range(k)] sorted_input = sorted(await ctx.ShareArray(inputs).open(), key=lambda x: x.value) share_arr = await butterfly.butterfly_network_helper(ctx, k=k, delta=delta, inputs=inputs) outputs = await share_arr.open() assert len(sorted_input) == len(outputs) sorted_output = sorted(outputs, key=lambda x: x.value) for i, j in zip(sorted_input, sorted_output): assert i == j program_runner = TaskProgramRunner( n, t, {MixinConstants.MultiplyShareArray: BeaverMultiplyArrays()}) program_runner.add(verify_output, k=k, delta=delta) await program_runner.join()
async def _run(peers, n, t, my_id): from honeybadgermpc.ipc import ProcessProgramRunner from honeybadgermpc.progs.mixins.share_arithmetic import ( MixinConstants, BeaverMultiplyArrays, ) mpc_config = {MixinConstants.MultiplyShareArray: BeaverMultiplyArrays()} async with ProcessProgramRunner(peers, n, t, my_id, mpc_config) as runner: runner.execute("0", butterfly_network_helper, k=k)
from honeybadgermpc.elliptic_curve import Jubjub, Point from honeybadgermpc.progs.jubjub import SharedPoint, share_mul from honeybadgermpc.progs.mixins.share_arithmetic import ( BeaverMultiply, BeaverMultiplyArrays, DivideShareArrays, DivideShares, Equality, InvertShare, InvertShareArray, ) MIXINS = [ BeaverMultiply(), BeaverMultiplyArrays(), InvertShare(), InvertShareArray(), DivideShares(), DivideShareArrays(), Equality(), ] TEST_PREPROCESSING = ["rands", "triples", "bits"] TEST_CURVE = Jubjub() TEST_POINT = Point( 5, 6846412461894745224441235558443359243034138132682534265960483512729196124138, TEST_CURVE, ) # noqa: E501
""" import asyncio from honeybadgermpc.mpc import TaskProgramRunner from honeybadgermpc.progs.mixins.dataflow import Share from honeybadgermpc.preprocessing import ( PreProcessedElements as FakePreProcessedElements, ) from honeybadgermpc.utils.typecheck import TypeCheck from honeybadgermpc.progs.mixins.share_arithmetic import ( MixinConstants, BeaverMultiply, BeaverMultiplyArrays, ) config = { MixinConstants.MultiplyShareArray: BeaverMultiplyArrays(), MixinConstants.MultiplyShare: BeaverMultiply(), } @TypeCheck() async def beaver_multiply(ctx, x: Share, y: Share): """The hello world of MPC: beaver multiplication - Linear operations on Share objects are easy - Shares of random values are available from preprocessing - Opening a Share returns a GFElementFuture """ a, b, ab = ctx.preproc.get_triples(ctx) D = await (x - a).open() E = await (y - b).open()
from random import randint from honeybadgermpc.elliptic_curve import Jubjub from honeybadgermpc.progs.mimc import mimc_mpc_batch from honeybadgermpc.progs.mixins.share_arithmetic import ( BeaverMultiply, BeaverMultiplyArrays, InvertShare, InvertShareArray, DivideShares, DivideShareArrays, Equality, ) CONFIG = { BeaverMultiply.name: BeaverMultiply(), BeaverMultiplyArrays.name: BeaverMultiplyArrays(), InvertShare.name: InvertShare(), InvertShareArray.name: InvertShareArray(), DivideShares.name: DivideShares(), DivideShareArrays.name: DivideShareArrays(), Equality.name: Equality(), } PREPROCESSING = ["rands", "triples", "zeros", "cubes", "bits"] n, t = 4, 1 k = 300000 TEST_CURVE = Jubjub() TEST_FIELD = Jubjub.Field TEST_KEY = TEST_FIELD(randint(0, TEST_FIELD.modulus))
async def _mixing_loop(self): # Task 3. Participating in mixing epochs contract_concise = ConciseContract(self.contract) pp_elements = PreProcessedElements() n = contract_concise.n() t = contract_concise.t() K = contract_concise.K() # noqa: N806 PER_MIX_TRIPLES = contract_concise.PER_MIX_TRIPLES() # noqa: N806 PER_MIX_BITS = contract_concise.PER_MIX_BITS() # noqa: N806 epoch = 0 while True: # 3.a. Wait for the next mix to be initiated while True: epochs_initiated = contract_concise.epochs_initiated() if epochs_initiated > epoch: break await asyncio.sleep(5) # 3.b. Collect the inputs inputs = [] for idx in range(epoch * K, (epoch + 1) * K): # Get the public input masked_input, inputmask_idx = contract_concise.input_queue(idx) masked_input = field(int.from_bytes(masked_input, "big")) # Get the input masks inputmask = self._inputmasks[inputmask_idx] m_share = masked_input - inputmask inputs.append(m_share) # 3.c. Collect the preprocessing triples = self._triples[ (epoch + 0) * PER_MIX_TRIPLES : (epoch + 1) * PER_MIX_TRIPLES ] bits = self._bits[(epoch + 0) * PER_MIX_BITS : (epoch + 1) * PER_MIX_BITS] # Hack explanation... the relevant mixins are in triples key = (self.myid, n, t) for mixin in (pp_elements._triples, pp_elements._one_minus_ones): if key in mixin.cache: del mixin.cache[key] del mixin.count[key] # 3.d. Call the MPC program 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 send, recv = self.get_send_recv(f"mpc:{epoch}") logging.info(f"[{self.myid}] MPC initiated:{epoch}") # Config just has to specify mixins used by switching_network config = {MixinConstants.MultiplyShareArray: BeaverMultiplyArrays()} ctx = Mpc(f"mpc:{epoch}", n, t, self.myid, send, recv, prog, config) result = await ctx._run() logging.info(f"[{self.myid}] MPC complete {result}") # 3.e. Output the published messages to contract result = ",".join(result) tx_hash = self.contract.functions.propose_output(epoch, result).transact( {"from": self.w3.eth.accounts[self.myid]} ) tx_receipt = await wait_for_receipt(self.w3, tx_hash) rich_logs = self.contract.events.MixOutput().processReceipt(tx_receipt) if rich_logs: epoch = rich_logs[0]["args"]["epoch"] output = rich_logs[0]["args"]["output"] logging.info(f"[{self.myid}] MIX OUTPUT[{epoch}] {output}") else: pass epoch += 1 pass