From b3a1b565381db654f18b514328af77585c1075d3 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 1 Jul 2019 17:36:40 +0300 Subject: [PATCH 1/3] Added documentation and some review comments for selected classes focused mostly on the OT implementation and dependencies. --- CompactMPC/BitArray.cs | 2 + CompactMPC/Buffers/BufferBuilder.cs | 3 ++ .../IGeneralizedObliviousTransfer.cs | 27 +++++++++++ .../ObliviousTransfer/IObliviousTransfer.cs | 27 +++++++++++ .../InsecureObliviousTransfer.cs | 9 +++- .../NaorPinkasObliviousTransfer.cs | 46 ++++++++++++++++++- CompactMPC/ObliviousTransfer/RandomOracle.cs | 32 +++++++++++++ SampleCircuits/SecureSetIntersection.cs | 12 +++++ 8 files changed, 155 insertions(+), 3 deletions(-) diff --git a/CompactMPC/BitArray.cs b/CompactMPC/BitArray.cs index 03b9a0c..0052ee5 100644 --- a/CompactMPC/BitArray.cs +++ b/CompactMPC/BitArray.cs @@ -29,6 +29,8 @@ public static int RequiredBytes(int numberOfBits) return RequiredBytes(numberOfBits, ElementsPerByte); } + // note(lumip): it seems to me like all these would be nicer if they would return the result + // instead of inplace manipulation. Is there a specific design reason for the current way? public void Or(BitArray other) { if (other.Length != Length) diff --git a/CompactMPC/Buffers/BufferBuilder.cs b/CompactMPC/Buffers/BufferBuilder.cs index dcba491..14d288f 100644 --- a/CompactMPC/Buffers/BufferBuilder.cs +++ b/CompactMPC/Buffers/BufferBuilder.cs @@ -6,6 +6,9 @@ namespace CompactMPC.Buffers { + /// + /// Allows to build a byte buffer by composing existing buffers and integer values. + /// public class BufferBuilder { private MessageComposer _composer; diff --git a/CompactMPC/ObliviousTransfer/IGeneralizedObliviousTransfer.cs b/CompactMPC/ObliviousTransfer/IGeneralizedObliviousTransfer.cs index 6b8d69d..a0ea354 100644 --- a/CompactMPC/ObliviousTransfer/IGeneralizedObliviousTransfer.cs +++ b/CompactMPC/ObliviousTransfer/IGeneralizedObliviousTransfer.cs @@ -10,9 +10,36 @@ namespace CompactMPC.ObliviousTransfer { + /// + /// Common interface for 1-out-of-4 bit oblivious transfer implementations. + /// + /// + /// For single bit for messages/options, see . public interface IGeneralizedObliviousTransfer { + /// + /// Supplies the four options from the sender to the oblivious transfer. + /// + /// + /// To increase efficiency, several invocations of OT can be batched into one transmission. + /// + /// The network message channel to the receiver. + /// Array containing the four options supplied to 1-out-of-4 OT by the sender for each invocation. + /// The number of OT invocations in the transmission. + /// An asynchronous task which performs the server side of the oblivious transfer. Task SendAsync(IMessageChannel channel, Quadruple[] options, int numberOfInvocations, int numberOfMessageBytes); + + /// + /// Supplies the selection index from the client side to the oblivious transfer and returns the corresponding option from the server. + /// + /// + /// To increase efficiency, several invocations of OT can be batched into one transmission + /// + /// The network message channel to the sender. + /// Array containing the selection index supplied to 1-out-of-4 OT by the client for each invocation. + /// The number of OT invocations in the transmission. + /// An asynchronous task performing the client side of the oblivious transfer and returning the array containing + /// the options as selected by the client retrieved from the server. Task ReceiveAsync(IMessageChannel channel, QuadrupleIndexArray selectionIndices, int numberOfInvocations, int numberOfMessageBytes); } } diff --git a/CompactMPC/ObliviousTransfer/IObliviousTransfer.cs b/CompactMPC/ObliviousTransfer/IObliviousTransfer.cs index dfe3eea..6eef4e4 100644 --- a/CompactMPC/ObliviousTransfer/IObliviousTransfer.cs +++ b/CompactMPC/ObliviousTransfer/IObliviousTransfer.cs @@ -10,9 +10,36 @@ namespace CompactMPC.ObliviousTransfer { + /// + /// Common interface for 1-out-of-4 single bit oblivious transfer implementations. + /// + /// + /// For a variant with arbitrary bit length for messages/options, see . public interface IObliviousTransfer { + /// + /// Supplies the four options from the sender to the oblivious transfer. + /// + /// + /// To increase efficiency, several invocations of OT can be batched into one transmission. + /// + /// The network message channel to the receiver. + /// Array containing the four options supplied to 1-out-of-4 OT by the sender for each invocation. + /// The number of OT invocations in the transmission. + /// An asynchronous task which performs the server side of the oblivious transfer. Task SendAsync(IMessageChannel channel, BitQuadrupleArray options, int numberOfInvocations); + + /// + /// Supplies the selection index from the client side to the oblivious transfer and returns the corresponding option from the server. + /// + /// + /// To increase efficiency, several invocations of OT can be batched into one transmission + /// + /// The network message channel to the sender. + /// Array containing the selection index supplied to 1-out-of-4 OT by the client for each invocation. + /// The number of OT invocations in the transmission. + /// An asynchronous task performing the client side of the oblivious transfer and returning the array containing + /// the options as selected by the client retrieved from the server. Task ReceiveAsync(IMessageChannel channel, QuadrupleIndexArray selectionIndices, int numberOfInvocations); } } diff --git a/CompactMPC/ObliviousTransfer/InsecureObliviousTransfer.cs b/CompactMPC/ObliviousTransfer/InsecureObliviousTransfer.cs index 8f69ba3..3f3506d 100644 --- a/CompactMPC/ObliviousTransfer/InsecureObliviousTransfer.cs +++ b/CompactMPC/ObliviousTransfer/InsecureObliviousTransfer.cs @@ -9,14 +9,21 @@ namespace CompactMPC.ObliviousTransfer { + /// + /// Insecure (non-oblivious) implementation of the oblivious transfer interface. + /// + /// + /// Caution! This class is intended for testing and debugging purposes and does not provide any security. + /// Hence, it should not be used with any sensitive or in production deployments. All options are SENT IN THE PLAIN. public class InsecureObliviousTransfer : GeneralizedObliviousTransfer { public override Task SendAsync(IMessageChannel channel, Quadruple[] options, int numberOfInvocations, int numberOfMessageBytes) { + // note(lumip): common argument verification code.. wrap into a common method in a base class? if (options.Length != numberOfInvocations) throw new ArgumentException("Provided options must match the specified number of invocations.", nameof(options)); - for (int i = 0; i < options.Length; ++i) + for (int i = 0; i < numberOfInvocations; ++i) { foreach (byte[] message in options[i]) { diff --git a/CompactMPC/ObliviousTransfer/NaorPinkasObliviousTransfer.cs b/CompactMPC/ObliviousTransfer/NaorPinkasObliviousTransfer.cs index 3f59dca..1e41a4f 100644 --- a/CompactMPC/ObliviousTransfer/NaorPinkasObliviousTransfer.cs +++ b/CompactMPC/ObliviousTransfer/NaorPinkasObliviousTransfer.cs @@ -14,6 +14,11 @@ namespace CompactMPC.ObliviousTransfer { + // note(lumip): the implementation does not seem to actually follow any construction given in + // [Moni Naor and Benny Pinkas: Computationally Secure Oblivious Transfer. 2005.] + // so what is the exact reference here? + // looks like + // [Moni Naor and Benny Pinkas: Efficient oblivious transfer protocols 2001.] public class NaorPinkasObliviousTransfer : GeneralizedObliviousTransfer { private SecurityParameters _parameters; @@ -37,6 +42,7 @@ public NaorPinkasObliviousTransfer(SecurityParameters parameters, CryptoContext public override async Task SendAsync(IMessageChannel channel, Quadruple[] options, int numberOfInvocations, int numberOfMessageBytes) { + // note(lumip): common argument verification code.. wrap into a common method in a base class? if (options.Length != numberOfInvocations) throw new ArgumentException("Provided options must match the specified number of invocations.", nameof(options)); @@ -64,6 +70,8 @@ public override async Task SendAsync(IMessageChannel channel, Quadruple[ }); BigInteger alpha = listOfExponents[0]; + // note(lumip): sender should probably verify that the all generated elements are different! + // otherwise the receiver could recover two or more of the sent values #if DEBUG stopwatch.Stop(); @@ -175,6 +183,11 @@ public override async Task ReceiveAsync(IMessageChannel channel, Quadr return selectedOptions; } + /// + /// Returns a random element from the group as well as the corresponding exponent for the group generator. + /// + /// The exponent with which the returned group element can be obtained from the group generator. + /// A random group element. private BigInteger GenerateGroupElement(out BigInteger exponent) { do @@ -186,11 +199,22 @@ private BigInteger GenerateGroupElement(out BigInteger exponent) return BigInteger.ModPow(_parameters.G, exponent, _parameters.P); } + /// + /// Multiplicatively inverts a group element. + /// + /// The group element to be inverted. + /// The multiplicative inverse of the argument in the group. private BigInteger Invert(BigInteger groupElement) { return BigInteger.ModPow(groupElement, _parameters.Q - 1, _parameters.P); } + /// + /// Asynchronously writes a list of group elements (BigInteger) to a message channel. + /// + /// The network message channel. + /// The list of group elements to write/send. + /// private Task WriteGroupElements(IMessageChannel channel, IReadOnlyList groupElements) { MessageComposer message = new MessageComposer(2 * groupElements.Count); @@ -204,6 +228,12 @@ private Task WriteGroupElements(IMessageChannel channel, IReadOnlyList + /// Asynchronously reads a specified number of group elements from a message channel. + /// + /// The network message channel. + /// Number of group elements to read/receive. + /// private async Task ReadGroupElements(IMessageChannel channel, int numberOfGroupElements) { MessageDecomposer message = new MessageDecomposer(await channel.ReadMessageAsync()); @@ -246,10 +276,22 @@ private async Task[]> ReadOptions(IMessageChannel channel, int return options; } - private byte[] MaskOption(byte[] message, BigInteger groupElement, int invocationIndex, int optionIndex) + /// + /// Masks an option (i.e., a sender input message). + /// + /// + /// The option is XOR-masked with the output of a random oracle queried with the + /// concatentation of the binary representations of the given groupElement, invocationIndex and optionIndex. + /// + /// The sender input/option to be masked. + /// The group element that contributes receiver choice to the query. + /// The index of the OT invocation this options belongs to. + /// The index of the option. + /// + private byte[] MaskOption(byte[] option, BigInteger groupElement, int invocationIndex, int optionIndex) { byte[] query = BufferBuilder.From(groupElement.ToByteArray()).With(invocationIndex).With(optionIndex).Create(); - return _randomOracle.Mask(message, query); + return _randomOracle.Mask(option, query); } } } diff --git a/CompactMPC/ObliviousTransfer/RandomOracle.cs b/CompactMPC/ObliviousTransfer/RandomOracle.cs index 0e7de44..f949484 100644 --- a/CompactMPC/ObliviousTransfer/RandomOracle.cs +++ b/CompactMPC/ObliviousTransfer/RandomOracle.cs @@ -6,10 +6,42 @@ namespace CompactMPC.ObliviousTransfer { + /// + /// A random oracle as canonically defined. + /// + /// + /// As per the canonical definition of the random oracle, it produces a random but deterministic output + /// for each unique query it is invoked on, i.e., the output is unpredictably random over different queries + /// but providing the same query will always yield the same output sequence. + /// + /// The RandomOracle class also provides a Mask message that masks a given message with the output of the + /// random oracle for a given query. In that case the query can be seen as a shared key that allows for + /// masking and unmasking (encryption/decryption) of a message. + /// + /// Naturally, a true random oracle cannot be implemented so the outputs of all implementations of + /// RandomOracle will not be perfectly random but computationally indistinguishable from true randomness + /// by the usual cryptographic standards. public abstract class RandomOracle { + /// + /// Supplies the response of the random oracle to the given query. + /// + /// + /// As per the canonical definition of the random oracle, it produces a random but deterministic output + /// for each unique query, i.e., the output is unpredictably random over different queries but + /// providing the same query will always yield the same output sequence. + /// + /// The query for the random oracle. + /// public abstract IEnumerable Invoke(byte[] query); + /// + /// Masks a given message by applying bitwise XOR with the random oracle output stream. + /// + /// The message to be masked with the random oracle output. + /// The query for the random oracle. + /// Byte array containing the masked message. + /// Thrown when the random oracle does not provide enough data to mask the given message. public byte[] Mask(byte[] message, byte[] query) { byte[] result = new byte[message.Length]; diff --git a/SampleCircuits/SecureSetIntersection.cs b/SampleCircuits/SecureSetIntersection.cs index 34908b8..20a2188 100644 --- a/SampleCircuits/SecureSetIntersection.cs +++ b/SampleCircuits/SecureSetIntersection.cs @@ -9,6 +9,12 @@ namespace CompactMPC.SampleCircuits { + /// + /// Circuit which computes the intersection of sets given in a binary word representation. + /// + /// + /// In addition to the intersection result, a counter giving the cardinality of the intersection + /// is also calculated. public class SecureSetIntersection { private SecureWord _intersection; @@ -25,6 +31,9 @@ public SecureSetIntersection(SecureWord[] inputs, int numberOfCounterBits) _counter = counter.OfFixedLength(numberOfCounterBits); } + /// + /// The binary encoding of the intersection set. + /// public SecureWord Intersection { get @@ -33,6 +42,9 @@ public SecureWord Intersection } } + /// + /// The number of elements in the intersection set. + /// public SecureInteger Counter { get From 445873b3966887f7bacc4d45d6c913dec759a273 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Thu, 4 Jul 2019 20:39:00 +0300 Subject: [PATCH 2/3] note about the necessity of parameters in the I[Generalized]ObliviousTransfer interfaces. --- CompactMPC/ObliviousTransfer/IGeneralizedObliviousTransfer.cs | 2 ++ CompactMPC/ObliviousTransfer/IObliviousTransfer.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CompactMPC/ObliviousTransfer/IGeneralizedObliviousTransfer.cs b/CompactMPC/ObliviousTransfer/IGeneralizedObliviousTransfer.cs index a0ea354..79e9140 100644 --- a/CompactMPC/ObliviousTransfer/IGeneralizedObliviousTransfer.cs +++ b/CompactMPC/ObliviousTransfer/IGeneralizedObliviousTransfer.cs @@ -17,6 +17,7 @@ namespace CompactMPC.ObliviousTransfer /// For single bit for messages/options, see . public interface IGeneralizedObliviousTransfer { + // note(lumip): why have numberOfInvocations as an argument when it could be derived from options.Length? /// /// Supplies the four options from the sender to the oblivious transfer. /// @@ -29,6 +30,7 @@ public interface IGeneralizedObliviousTransfer /// An asynchronous task which performs the server side of the oblivious transfer. Task SendAsync(IMessageChannel channel, Quadruple[] options, int numberOfInvocations, int numberOfMessageBytes); + // note(lumip): why have numberOfInvocations as an argument when it could be derived from selectionIndices.Length? /// /// Supplies the selection index from the client side to the oblivious transfer and returns the corresponding option from the server. /// diff --git a/CompactMPC/ObliviousTransfer/IObliviousTransfer.cs b/CompactMPC/ObliviousTransfer/IObliviousTransfer.cs index 6eef4e4..97413fb 100644 --- a/CompactMPC/ObliviousTransfer/IObliviousTransfer.cs +++ b/CompactMPC/ObliviousTransfer/IObliviousTransfer.cs @@ -17,6 +17,7 @@ namespace CompactMPC.ObliviousTransfer /// For a variant with arbitrary bit length for messages/options, see . public interface IObliviousTransfer { + // note(lumip): why have numberOfInvocations as an argument when it could be derived from options.Length? /// /// Supplies the four options from the sender to the oblivious transfer. /// @@ -29,6 +30,7 @@ public interface IObliviousTransfer /// An asynchronous task which performs the server side of the oblivious transfer. Task SendAsync(IMessageChannel channel, BitQuadrupleArray options, int numberOfInvocations); + // note(lumip): why have numberOfInvocations as an argument when it could be derived from selectionIndices.Length? /// /// Supplies the selection index from the client side to the oblivious transfer and returns the corresponding option from the server. /// From 0a3e45214f721487efe27f9c1d480c50faf5e909 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Wed, 10 Jul 2019 20:16:23 +0300 Subject: [PATCH 3/3] Clarified a comment. --- CompactMPC/ObliviousTransfer/NaorPinkasObliviousTransfer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CompactMPC/ObliviousTransfer/NaorPinkasObliviousTransfer.cs b/CompactMPC/ObliviousTransfer/NaorPinkasObliviousTransfer.cs index aebbb2d..8f57d6c 100644 --- a/CompactMPC/ObliviousTransfer/NaorPinkasObliviousTransfer.cs +++ b/CompactMPC/ObliviousTransfer/NaorPinkasObliviousTransfer.cs @@ -56,11 +56,11 @@ protected override async Task GeneralizedSendAsync(IMessageChannel channel, Quad listOfCs[i] = GenerateGroupElement(out exponent); listOfExponents[i] = exponent; }); + // note(lumip): we discussed a possible vulnerability arising when two or more group elements + // are similar but decided against checking for that since the probability of it occuring is + // negligible small for the relevant group sizes. BigInteger alpha = listOfExponents[0]; - // note(lumip): we discussed a possible vulnerability of two or more group elements would be similar but - // decided against checking for that since the probability of that occuring is negligible small for - // the relevant group sizes. #if DEBUG stopwatch.Stop();