public async Task <BitArray> EvaluateAsync(IBatchEvaluableCircuit evaluable, InputPartyMapping inputMapping, OutputPartyMapping outputMapping, BitArray localInputValues) { if (inputMapping.NumberOfInputs != evaluable.Context.NumberOfInputGates) { throw new ArgumentException( "The number of inputs in input mapping does not match the number of declared inputs in the circuit.", nameof(inputMapping) ); } if (outputMapping.NumberOfOutputs != evaluable.Context.NumberOfOutputGates) { throw new ArgumentException( "The number of outputs in output mapping does not match the number of declared outputs in the circuit.", nameof(outputMapping) ); } SecretSharingBooleanCircuitEvaluator evaluator = new SecretSharingBooleanCircuitEvaluator(MultiPartySession, _multiplicativeSharing); BitArray maskedInputs = await MaskInputs(inputMapping, localInputValues); Task <Bit>[] inputTasks = maskedInputs.Select(Task.FromResult).ToArray(); Task <Bit>[] outputTasks = evaluable.Evaluate(evaluator, inputTasks); BitArray maskedOutputs = new BitArray(await Task.WhenAll(outputTasks)); return(await UnmaskOutputs(outputMapping, maskedOutputs)); }
private async Task <BitArray> MaskInputs(InputPartyMapping inputMapping, BitArray localInputValues) { List <int>[] inputIds = new List <int> [MultiPartySession.NumberOfParties]; for (int partyId = 0; partyId < inputIds.Length; ++partyId) { inputIds[partyId] = new List <int>(); } for (int inputId = 0; inputId < inputMapping.NumberOfInputs; ++inputId) { int partyId = inputMapping.GetAssignedParty(inputId); if (partyId < 0 || partyId >= MultiPartySession.NumberOfParties) { throw new ArgumentException("Input mapping assigns inputs to party not participating in current session.", nameof(inputMapping)); } inputIds[partyId].Add(inputId); } List <int> localInputIds = inputIds[MultiPartySession.LocalParty.Id]; if (localInputValues.Length != localInputIds.Count) { throw new ArgumentException( "Number of provided inputs does not match the number of declared inputs in the circuit for the local party.", nameof(localInputValues) ); } BitArray localSharesOfInput = new BitArray(inputMapping.NumberOfInputs); // --- Share local inputs and send via network --- if (localInputIds.Count > 0) { BitArray localSharesOfLocalInput = localInputValues.Clone(); foreach (ITwoPartyNetworkSession session in MultiPartySession.RemotePartySessions) { BitArray remoteSharesOfLocalInput = _cryptoContext.RandomNumberGenerator.GetBits(localInputIds.Count); localSharesOfLocalInput.Xor(remoteSharesOfLocalInput); await session.Channel.WriteMessageAsync(remoteSharesOfLocalInput.ToBytes()); } for (int localInputId = 0; localInputId < localInputIds.Count; ++localInputId) { localSharesOfInput[localInputIds[localInputId]] = localSharesOfLocalInput[localInputId]; } } // --- Receive shares of remote inputs via network --- foreach (ITwoPartyNetworkSession session in MultiPartySession.RemotePartySessions) { List <int> remoteInputIds = inputIds[session.RemoteParty.Id]; if (remoteInputIds.Count > 0) { BitArray localSharesOfRemoteInput = BitArray.FromBytes(await session.Channel.ReadMessageAsync(), remoteInputIds.Count); if (localSharesOfRemoteInput.Length != remoteInputIds.Count) { throw new ProtocolException("Number of input shares received from remote party does not match number of declared inputs in the circuit."); } for (int remoteInputId = 0; remoteInputId < remoteInputIds.Count; ++remoteInputId) { localSharesOfInput[remoteInputIds[remoteInputId]] = localSharesOfRemoteInput[remoteInputId]; } } } return(localSharesOfInput); }