protected override async Task <byte[][]> ReceiveMaskedOptionsAsync(BitArray selectionIndices, BitMatrix tTransposed, int numberOfInvocations, int numberOfMessageBytes)
        {
            Debug.Assert(selectionIndices.Length == numberOfInvocations);
            Debug.Assert(tTransposed.Rows == SecurityParameter);
            Debug.Assert(tTransposed.Cols == numberOfInvocations);

            // retrieve the masked options from the sender and unmask the one indicated by the
            //  corresponding selection indices
            byte[][][] maskedOptions = await CommunicationTools.ReadOptionsAsync(Channel, 1, numberOfInvocations, numberOfMessageBytes);

            Debug.Assert(maskedOptions.Length == numberOfInvocations);

            byte[][] results = new byte[numberOfInvocations][];
            Parallel.For(0, numberOfInvocations, i =>
            {
                Debug.Assert(maskedOptions[i].Length == 1);
                Debug.Assert(maskedOptions[i][0].Length == numberOfMessageBytes);

                RandomOracle randomOracle = RandomOracleProvider.Create();

                int s = Convert.ToInt32(selectionIndices[i].Value);

                byte[] query = tTransposed.GetColumn((uint)i).ToBytes();

                if (s == 0)
                {
                    results[i] = randomOracle.Invoke(query).Take(numberOfMessageBytes).ToArray();
                }
                else
                {
                    results[i] = randomOracle.Mask(maskedOptions[i][0], query);
                }
            });
            return(results);
        }
        public async Task <Pair <byte[]>[]> SendAsync(byte[][] correlationStrings, int numberOfInvocations, int numberOfMessageBytes)
        {
            if (correlationStrings.Length != numberOfInvocations)
            {
                throw new ArgumentException("Amount of provided correlation strings must match the specified number of invocations.", nameof(correlationStrings));
            }

            foreach (byte[] message in correlationStrings)
            {
                if (message.Length != numberOfMessageBytes)
                {
                    throw new ArgumentException("The length of of at least one correlation string does not match the specified message length.", nameof(correlationStrings));
                }
            }

            BitMatrix q = await ReceiveQMatrix(numberOfInvocations);

            Debug.Assert(q.Rows == numberOfInvocations);
            Debug.Assert(q.Cols == SecurityParameter);

            Pair <byte[]>[] options       = new Pair <byte[]> [numberOfInvocations];
            byte[][][]      maskedOptions = new byte[numberOfInvocations][][];
            Parallel.For(0, numberOfInvocations, i =>
            {
                Debug.Assert(correlationStrings[i].Length == numberOfMessageBytes);
                RandomOracle randomOracle = RandomOracleProvider.Create();

                options[i] = new Pair <byte[]>();

                BitArray qRow = q.GetRow((uint)i);

                byte[] query  = qRow.ToBytes();
                options[i][0] = randomOracle.Invoke(query).Take(numberOfMessageBytes).ToArray();

                options[i][1] = ByteBuffer.Xor(correlationStrings[i], options[i][0]);

                query = (qRow ^ SenderChoices).ToBytes();

                maskedOptions[i] = new[] { randomOracle.Mask(options[i][1], query) };
                Debug.Assert(maskedOptions[i][0].Length == numberOfMessageBytes);
            });

            await CommunicationTools.WriteOptionsAsync(Channel, maskedOptions, 1, numberOfInvocations, numberOfMessageBytes);

            return(options);
        }