diff --git a/core/src/main/java/dk/alexandra/fresco/commitment/.gitignore b/core/src/main/java/dk/alexandra/fresco/commitment/.gitignore new file mode 100644 index 000000000..4f2b47ed3 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/commitment/.gitignore @@ -0,0 +1 @@ +/Commitment.java diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/AdvancedNumeric.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/AdvancedNumeric.java index 0ef0acc1e..709d1fef0 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/AdvancedNumeric.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/AdvancedNumeric.java @@ -3,7 +3,10 @@ import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.builder.ComputationDirectory; import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.lib.math.integer.binary.RandomBitMask; + import java.math.BigInteger; import java.util.List; @@ -16,16 +19,27 @@ public interface AdvancedNumeric extends ComputationDirectory { * Calculates the sum of all elements in the list. * * @param elements the elements to sum - * @return A deferred result computing the sum of the elements + * @return A deferred result computing the sum of the elements inputs should be wrapped in {@link + * DRes}, use {@link #sum(DRes)} instead */ + @Deprecated DRes sum(List> elements); + /** + * Calculates the sum of all elements in the list. + * + * @param elements the elements to sum + * @return A deferred result computing the sum of the elements + */ + DRes sum(DRes>> elements); + /** * Calculates the product of all elements in the list. * * @param elements the elements to sum * @return A deferred result computing the product of the elements */ + @Deprecated DRes product(List> elements); /** @@ -67,7 +81,7 @@ public interface AdvancedNumeric extends ComputationDirectory { DRes> toBits(DRes in, int maxInputLength); /** - * Computes the exponentiation of x^e. + * Computes the exponentiation of x^e * * @param x The base * @param e The exponent @@ -77,7 +91,7 @@ public interface AdvancedNumeric extends ComputationDirectory { DRes exp(DRes x, DRes e, int maxExponentLength); /** - * Computes the exponentiation of x^e. + * Computes the exponentiation of x^e * * @param x The base * @param e The exponent @@ -96,8 +110,6 @@ public interface AdvancedNumeric extends ComputationDirectory { DRes exp(DRes x, BigInteger e); /** - * Calculating the square root of a given input. - * * @param input The input. * @param maxInputLength An upper bound for log2(input). * @return A deferred result computing an approximation of the square root of the input. @@ -119,7 +131,9 @@ public interface AdvancedNumeric extends ComputationDirectory { * @param vectorA The first vector * @param vectorB The second vector * @return A deferred result computing the inner product of the two given vectors + * @deprecated inputs should be wrapped in {@link DRes} */ + @Deprecated DRes innerProduct(List> vectorA, List> vectorB); /** @@ -128,28 +142,81 @@ public interface AdvancedNumeric extends ComputationDirectory { * @param vectorA The public vector * @param vectorB The secret vector * @return A deferred result computing the inner product of the two given vectors + * @deprecated inputs should be wrapped in {@link DRes}, use {@link #innerProductWithPublicPart(DRes, + * DRes)} instead */ + @Deprecated() DRes innerProductWithPublicPart(List vectorA, List> vectorB); + /** + * Computes the inner product between a public vector and a secret vector. + * + * @param vectorA The public vector + * @param vectorB The secret vector + * @return A deferred result computing the inner product of the two given vectors + */ + DRes innerProductWithPublicPart(DRes> vectorA, + DRes>> vectorB); + /** * Creates a string of random bits. * * @param noOfBits The amount of bits to create - i.e. the bit string length. * @return A container holding the bit string once evaluated. + * @deprecated use {@link #randomBitMask(int)} instead */ + @Deprecated DRes additiveMask(int noOfBits); /** - * Calculating the result of right shifting of the input by one. + * Creates a random bit mask [b0, ..., bn] along with an {@link SInt} representing the recombined + * bits, i.e., sum(2^{i} * bi). + * + * @param noOfBits The amount of bits + * @return A container holding the bit string once evaluated. + */ + DRes randomBitMask(int noOfBits); + + /** + * Takes a list of random bits [b0, ..., bn] and generates a random bit mask along with a {@link + * SInt} representing the recombined bits, i.e., sum(2^{i} * bi). * + * @param randomBits The bits to use for the bit mask + * @return A container holding the bit mask + */ + DRes randomBitMask(DRes>> randomBits); + + /** + * Right-shifts input by {@code shifts}.

Note that this is a probabilistic method which may + * produce an error in the least-significant bit.

+ * + * @param input secret value to right shift + * @param shifts number of shifts + * @param useTruncationPairs indicates whether truncation pairs are available as part of + * pre-processing material (this allows for a faster protocol) + * @return shifted result + */ + DRes truncate(DRes input, int shifts, boolean useTruncationPairs); + + default DRes truncate(DRes input, int shifts) { + return truncate(input, shifts, true); + } + + /** + * Creates truncation pair ({@link TruncationPair}).

This method may rely on pre-processed + * material in which case it should be overridden by backend suits.

+ * + * @param d number of shifts in truncation pair + */ + DRes generateTruncationPair(int d); + + /** * @param input input. * @return A deferred result computing input >> 1 */ DRes rightShift(DRes input); /** - * Calculating the result of right shifting of the input by a given amount. - * * @param input input. * @param shifts Number of shifts * @return A deferred result computing input >> shifts @@ -157,26 +224,19 @@ public interface AdvancedNumeric extends ComputationDirectory { DRes rightShift(DRes input, int shifts); /** - * Calculating the result of right shifting of the input by one, including the remainder. - * * @param input input - * @return A deferred result computing
- * result: input >> 1
- * remainder: The shifts least significant bits of the input with the least - * significant having index 0. + * @return A deferred result computing
result: input >> 1
remainder: The + * shifts least significant bits of the input with the least significant having index + * 0. */ DRes rightShiftWithRemainder(DRes input); /** - * Calculating the result of right shifting of the input by a given amount, including the - * remainder. - * * @param input input * @param shifts Number of shifts - * @return A deferred result computing
- * result: input >> shifts
- * remainder: The shifts least significant bits of the input with the least - * significant having index 0. + * @return A deferred result computing
result: input >> shifts
remainder: The + * shifts least significant bits of the input with the least significant having index + * 0. */ DRes rightShiftWithRemainder(DRes input, int shifts); @@ -185,13 +245,13 @@ public interface AdvancedNumeric extends ComputationDirectory { * * @param input The number to know the bit length of * @param maxBitLength The maximum bit length this number can have (if unknown, set this to the - * modulus bit size) + * modulus bit size) * @return A deferred result computing the bit length of the input number. */ DRes bitLength(DRes input, int maxBitLength); /** - * Compute the inverse of x within the field of operation. + * Compute the inverse of x within the field of operation * * @param x The element to take the inverse of * @return A deferred result computing x^-1 mod p where p is the modulus of the field. @@ -202,7 +262,7 @@ public interface AdvancedNumeric extends ComputationDirectory { * Selects left or right based on condition. * * @param condition the Computation holding the condition on which to select. Must be either 0 or - * 1. + * 1. * @param left the Computation holding the left argument. * @param right the Computation holding the right argument. * @return a computation holding either left or right depending on the condition. @@ -217,7 +277,7 @@ public interface AdvancedNumeric extends ComputationDirectory { * @param left The left argument * @param right The right argument * @return A deferred result computing a pair containing [left, right] if the condition is 0 and - * [right, left] if condition is 1. + * [right, left] if condition is 1. */ DRes, DRes>> swapIf(DRes condition, DRes left, DRes right); @@ -246,7 +306,10 @@ public SInt getRemainder() { /** * Container holding a random bitvector and its SInt representation. + * + * @deprecated values should be wrapped in DRes, use {@link RandomBitMask} instead */ + @Deprecated class RandomAdditiveMask { public final List> bits; @@ -257,4 +320,32 @@ public RandomAdditiveMask(List> bits, SInt random) { this.random = random; } } + + /** + * Generic representation of a truncation pair.

A truncation pair is pre-processing material + * used for probabilistic truncation. A truncation pair consists of a value r and r^{prime} such + * that r^{prime} is a random element and r = r^{prime} / 2^{d}, i.e., r right-shifted by d.

+ */ + class TruncationPair { + + private final DRes rPrime; + private final DRes r; + + public TruncationPair( + DRes rPrime, + DRes r) { + this.rPrime = rPrime; + this.r = r; + } + + public DRes getRPrime() { + return rPrime; + } + + public DRes getR() { + return r; + } + + } + } diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/BuilderFactoryNumeric.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/BuilderFactoryNumeric.java index 2ba99fae6..174dd3918 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/BuilderFactoryNumeric.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/BuilderFactoryNumeric.java @@ -2,6 +2,8 @@ import dk.alexandra.fresco.framework.BuilderFactory; import dk.alexandra.fresco.framework.builder.ComputationDirectory; +import dk.alexandra.fresco.framework.value.OIntArithmetic; +import dk.alexandra.fresco.framework.value.OIntFactory; import dk.alexandra.fresco.lib.compare.MiscBigIntegerGenerators; import dk.alexandra.fresco.lib.field.integer.BasicNumericContext; import dk.alexandra.fresco.lib.real.AdvancedRealNumeric; @@ -9,19 +11,15 @@ import dk.alexandra.fresco.lib.real.RealNumeric; import dk.alexandra.fresco.lib.real.RealNumericContext; import dk.alexandra.fresco.lib.real.fixed.AdvancedFixedNumeric; +import dk.alexandra.fresco.lib.real.fixed.DefaultFixedNumeric; import dk.alexandra.fresco.lib.real.fixed.FixedLinearAlgebra; -import dk.alexandra.fresco.lib.real.fixed.FixedNumeric; /** - * The core factory to implement when creating a numeric protocol. Every - * {@link ComputationDirectory} found in this factory will - * append the produced protocols to the supplied builder. Implementors must provide - * a {@link Numeric} - being directory for - *
    - *
  • simple, numeric operations (+, -, *)
  • - *
  • Open operations for opening a small subset of values used in the control flow (is a - *
  • Factories for producing secret shared values
  • - *
+ * The core factory to implement when creating a numeric protocol. Every {@link + * ComputationDirectory} found in this factory will append the produced protocols to the supplied + * builder. Implementors must provide a {@link Numeric} - being directory for
  • simple, + * numeric operations (+, -, *)
  • Open operations for opening a small subset of values used + * in the control flow (is a
  • Factories for producing secret shared values
* The other directories have defaults, based on the raw methods, but can be overridden if the * particular protocol suite has a more efficient way of e.g. comparing two numbers than a generic * approach would have. @@ -31,11 +29,24 @@ public interface BuilderFactoryNumeric extends BuilderFactory> DRes>> swapNeighborsIf( DRes> conditions, DRes> mat); + /** + * Obliviously selects a value from list according to selection bits.

Selection bits are + * assumed to be all zero except for the bit at the index of desired element.

+ */ + DRes select(DRes>> selectionBits, DRes>> values); + // Permutations /** @@ -133,7 +139,7 @@ > DRes>> swapNeighborsIf( * @param idxPerm encodes the desired permutation by supplying for each index a new index * @return permuted rows */ - DRes>> permute(DRes>> values, int[] idxPerm); + DRes>> permute(DRes>> values, int[] idxPerm); /** * Permutes the rows of values according to idxPerm.
To be called @@ -158,8 +164,8 @@ > DRes>> swapNeighborsIf( /** * Performs a SQL-like group-by sum operation. Groups rows by column groupColIdx and * sums values in resulting groups in column aggColIdx.
NOTE: this particular - * implementation leaks equality of values in column - * groupColIdx and the size of the result. + * implementation leaks equality of values in column groupColIdx and the size of the + * result. * * @param values rows to be aggregated * @param groupColIdx column to group by diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Comparison.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Comparison.java index 452ed3df5..20ef51884 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Comparison.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Comparison.java @@ -2,7 +2,11 @@ import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.builder.ComputationDirectory; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; +import java.util.List; /** * Interface for comparing numeric values. @@ -10,48 +14,98 @@ public interface Comparison extends ComputationDirectory { /** - * Compares two values and return x == y - * @param bitLength The maximum bit-length of the numbers to compare. - * @param x The first number - * @param y The second number - * @return A deferred result computing x == y + * The different algorithms supported by Fresco. The enum is used to decide of whether an + * algorithm running in constant rounds or logarithmic rounds should be used. In general the + * logarithmic round choice is the fastest. */ - DRes equals(int bitLength, DRes x, DRes y); - + enum Algorithm { + LOG_ROUNDS, CONST_ROUNDS + } + /** * Computes x == y. * - * @param x input - * @param y input - * @return A deferred result computing x == y. Result will be either [1] (true) or [0] (false). + * @param x the first input + * @param y the second input + * @param bitlength the amount of bits to do the equality test on. Must be less than or equal to + * the max bitlength allowed + * @param algorithm the algorithm to use + * @return A deferred result computing x' == y'. Where x' and y' represent the {@code bitlength} + * least significant bits of x, respectively y. Result will be either [1] (true) or [0] (false). + */ + DRes equals(DRes x, DRes y, int bitlength, Algorithm algorithm); + + /** + * Call to {@link #equals(DRes, DRes, int, Algorithm)} with default comparison algorithm. + */ + default DRes equals(DRes x, DRes y, int bitlength) { + return equals(x, y, bitlength, Algorithm.LOG_ROUNDS); + } + + /** + * Call to {@link #equals(DRes, DRes, int, Algorithm)} with default comparison algorithm, checking + * equality of all bits. */ DRes equals(DRes x, DRes y); - + + /** + * Computes if x <= y. + * + * @param x the first input + * @param y the second input + * @return A deferred result computing x <= y. Result will be either [1] (true) or [0] (false). + */ + DRes compareLEQ(DRes x, DRes y); + + /** + * Computes if x < y. + * + * @param x the first input + * @param y the second input + * @param algorithm the algorithm to use + * @return A deferred result computing x <= y. Result will be either [1] (true) or [0] (false). + */ + DRes compareLT(DRes x, DRes y, Algorithm algorithm); + /** - * Computes if x1 <= x2. - * @param x1 input - * @param x2 input - * @return A deferred result computing x1 <= x2. Result will be either [1] (true) or [0] (false). + * Call to {@link #compareLT(DRes, DRes, Algorithm)} with default comparison algorithm. */ - DRes compareLEQ(DRes x1, DRes x2); + default DRes compareLT(DRes x, DRes y) { + return compareLT(x, y, Algorithm.LOG_ROUNDS); + } /** - * Compares if x1 <= x2, but with twice the possible bit-length. - * Requires that the maximum bit length is set to something that can handle - * this scenario. It has to be at least less than half the modulus bit size. - * - * @param x1 input - * @param x2 input - * @return A deferred result computing x1 <= x2. Result will be either [1] (true) or [0] (false). + * Computes if the bit decomposition of an open value is less than the bit decomposition of a + * secret value. + * + * @param openValue open value which will be decomposed into bits and compared to secretBits + * @param secretBits secret value decomposed into bits + */ + DRes compareLTBits(DRes openValue, DRes>> secretBits); + + /** + * Method used internally in less-than protocol.

This is only here since we need a way to plug + * in a backend specific native protocol for it.

+ */ + DRes> carry(List bitPairs); + + /** + * Compares if x <= y, but with twice the possible bit-length. Requires that the maximum bit + * length is set to something that can handle this scenario. It has to be at least less than half + * the modulus bit size. + * + * @param x the first input + * @param y the second input + * @return A deferred result computing x <= y. Result will be either [1] (true) or [0] (false). */ - DRes compareLEQLong(DRes x1, DRes x2); + DRes compareLEQLong(DRes x, DRes y); /** * Computes the sign of the value (positive or negative) - * + * * @param x The value to compute the sign off * @return A deferred result computing the sign. Result will be 1 if the value is positive - * (including 0) and -1 if negative. + * (including 0) and -1 if negative. */ DRes sign(DRes x); @@ -59,8 +113,26 @@ public interface Comparison extends ComputationDirectory { * Test for equality with zero for a bitLength-bit number (positive or negative) * * @param x the value to test against zero - * @param bitLength bitlength - * @return A deferred result computing x == 0. Result will be either [1] (true) or [0] (false) + * @param bitlength the amount of bits to do the zero-test on. Must be less than or equal to the + * modulus bitlength + * @param algorithm the algorithm to use for zero-equality test + * @return A deferred result computing x' == 0 where x' is the {@code bitlength} least significant + * bits of x. Result will be either [1] (true) or [0] (false) + */ + DRes compareZero(DRes x, int bitlength, Algorithm algorithm); + + /** + * Computes the index of the minimum element in a list and the element itself.

The index is + * expressed as a list of bits where all bits are 0 except for the bit at the index of the minimum + * element, which is set to 1.

*/ - DRes compareZero(DRes x, int bitLength); + DRes>, SInt>> argMin(List> xs); + + /** + * Call to {@link #compareZero(DRes, int, Algorithm)} with default comparison algorithm. + */ + default DRes compareZero(DRes x, int bitlength) { + return compareZero(x, bitlength, Algorithm.LOG_ROUNDS); + } + } diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Conversion.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Conversion.java new file mode 100644 index 000000000..5b8685266 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Conversion.java @@ -0,0 +1,36 @@ +package dk.alexandra.fresco.framework.builder.numeric; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.ComputationDirectory; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.List; + +/** + * Operators for converting between different representations of secret values (for instance between + * an arithmetic representation and boolean representation).

NOTE: this is only experimental and + * will change in the feature. Furthermore, this is currently only supported by Spdz2k, not + * Spdz.

+ */ +public interface Conversion extends ComputationDirectory { + + /** + * Convert from arithmetic representation to boolean representation. + */ + DRes toBoolean(DRes arithmeticValue); + + /** + * Convert from boolean representation to arithmetic representation. + */ + DRes toArithmetic(DRes booleanValue); + + /** + * Convert multiple values from arithmetic to boolean. + */ + DRes>> toBooleanBatch(DRes>> arithmeticBatch); + + /** + * Convert multiple values from boolean to arithmetic. + */ + DRes>> toArithmeticBatch(DRes>> booleanBatch); + +} diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultAdvancedNumeric.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultAdvancedNumeric.java index 8cd82454b..d47f0bfad 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultAdvancedNumeric.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultAdvancedNumeric.java @@ -2,6 +2,7 @@ import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.lib.conditional.ConditionalSelect; import dk.alexandra.fresco.lib.conditional.SwapIf; @@ -9,6 +10,8 @@ import dk.alexandra.fresco.lib.math.integer.ProductSIntList; import dk.alexandra.fresco.lib.math.integer.SumSIntList; import dk.alexandra.fresco.lib.math.integer.binary.BitLength; +import dk.alexandra.fresco.lib.math.integer.binary.GenerateRandomBitMask; +import dk.alexandra.fresco.lib.math.integer.binary.RandomBitMask; import dk.alexandra.fresco.lib.math.integer.binary.RightShift; import dk.alexandra.fresco.lib.math.integer.division.KnownDivisor; import dk.alexandra.fresco.lib.math.integer.division.KnownDivisorRemainder; @@ -19,8 +22,11 @@ import dk.alexandra.fresco.lib.math.integer.inv.Inversion; import dk.alexandra.fresco.lib.math.integer.linalg.InnerProduct; import dk.alexandra.fresco.lib.math.integer.linalg.InnerProductOpen; +import dk.alexandra.fresco.lib.math.integer.linalg.InnerProductWithOInt; import dk.alexandra.fresco.lib.math.integer.log.Logarithm; import dk.alexandra.fresco.lib.math.integer.sqrt.SquareRoot; +import dk.alexandra.fresco.lib.real.fixed.utils.Truncate; +import dk.alexandra.fresco.lib.real.fixed.utils.TruncateFromPairs; import java.math.BigInteger; import java.util.List; @@ -31,8 +37,8 @@ */ public class DefaultAdvancedNumeric implements AdvancedNumeric { - private final BuilderFactoryNumeric factoryNumeric; - private final ProtocolBuilderNumeric builder; + protected final BuilderFactoryNumeric factoryNumeric; + protected final ProtocolBuilderNumeric builder; protected DefaultAdvancedNumeric(BuilderFactoryNumeric factoryNumeric, ProtocolBuilderNumeric builder) { @@ -45,6 +51,11 @@ public DRes sum(List> inputs) { return builder.seq(new SumSIntList(inputs)); } + @Override + public DRes sum(DRes>> elements) { + return builder.seq(new SumSIntList(elements)); + } + @Override public DRes product(List> elements) { return builder.seq(new ProductSIntList(elements)); @@ -105,11 +116,42 @@ public DRes innerProductWithPublicPart(List vectorA, List innerProductWithPublicPart(DRes> vectorA, + DRes>> vectorB) { + return builder.seq(new InnerProductWithOInt(vectorA, vectorB)); + } + @Override public DRes additiveMask(int noOfBits) { return builder.seq(new dk.alexandra.fresco.lib.compare.RandomAdditiveMask(noOfBits)); } + @Override + public DRes randomBitMask(int numBits) { + return builder.seq(new GenerateRandomBitMask(numBits)); + } + + @Override + public DRes randomBitMask(DRes>> randomBits) { + return builder.seq(new GenerateRandomBitMask(randomBits)); + } + + @Override + public DRes truncate(DRes input, int shifts, boolean useTruncationPairs) { + if (useTruncationPairs) { + return builder.seq(new TruncateFromPairs(input, shifts)); + } else { + return builder.seq(new Truncate(input, shifts)); + } + } + + @Override + public DRes generateTruncationPair(int d) { + throw new UnsupportedOperationException( + "Online truncation pair generation currently not supported"); + } + @Override public DRes rightShift(DRes input) { DRes rightShiftResult = builder.seq( diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultCollections.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultCollections.java index 6c854cccf..95eecbfd9 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultCollections.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultCollections.java @@ -41,7 +41,11 @@ public DRes> openRowPair(DRes>> closeList(List openList, int inputParty) { - return builder.par(new CloseList(openList, inputParty)); + if (builder.getBasicNumericContext().getMyId() == inputParty) { + return builder.par(new CloseList(openList, inputParty)); + } else { + return builder.par(new CloseList(openList.size(), inputParty)); + } } @Override @@ -90,6 +94,13 @@ public > DRes>> swapNeighborsIf(DRes(conditions, rows)); } + @Override + public DRes select(DRes>> selectionBits, + DRes>> values) { + return builder + .seq(seq -> seq.advancedNumeric().innerProduct(selectionBits.out(), values.out())); + } + @Override public DRes>> permute(DRes>> values, int[] idxPerm) { return builder diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultComparison.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultComparison.java index 7f84b44c1..9ea68153e 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultComparison.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultComparison.java @@ -1,11 +1,20 @@ package dk.alexandra.fresco.framework.builder.numeric; import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; -import dk.alexandra.fresco.lib.compare.eq.Equality; -import dk.alexandra.fresco.lib.compare.gt.LessThanOrEquals; -import dk.alexandra.fresco.lib.compare.zerotest.ZeroTest; +import dk.alexandra.fresco.lib.compare.lt.BitLessThanOpen; +import dk.alexandra.fresco.lib.compare.lt.Carry; +import dk.alexandra.fresco.lib.compare.lt.LessThanOrEquals; +import dk.alexandra.fresco.lib.compare.lt.LessThanZero; +import dk.alexandra.fresco.lib.compare.zerotest.ZeroTestConstRounds; +import dk.alexandra.fresco.lib.compare.zerotest.ZeroTestLogRounds; + +import dk.alexandra.fresco.lib.math.integer.min.ArgMin; import java.math.BigInteger; +import java.util.List; /** * Default way of producing the protocols within the interface. This default class can be @@ -14,10 +23,8 @@ */ public class DefaultComparison implements Comparison { - // Security parameter used by protocols using rightshifts and/or additive masks. - private final int magicSecureNumber = 60; - private final BuilderFactoryNumeric factoryNumeric; - private final ProtocolBuilderNumeric builder; + protected final BuilderFactoryNumeric factoryNumeric; + protected final ProtocolBuilderNumeric builder; public DefaultComparison(BuilderFactoryNumeric factoryNumeric, ProtocolBuilderNumeric builder) { @@ -28,28 +35,40 @@ public DefaultComparison(BuilderFactoryNumeric factoryNumeric, @Override public DRes compareLEQLong(DRes x, DRes y) { int bitLength = factoryNumeric.getBasicNumericContext().getMaxBitLength() * 2; - LessThanOrEquals leqProtocol = new LessThanOrEquals( - bitLength, magicSecureNumber, x, y); + LessThanOrEquals leqProtocol = new LessThanOrEquals(bitLength, x, y); return builder.seq(leqProtocol); + } + @Override + public DRes compareLEQ(DRes x, DRes y) { + int bitLength = factoryNumeric.getBasicNumericContext().getMaxBitLength(); + return builder.seq(new LessThanOrEquals(bitLength, x, y)); } @Override - public DRes equals(DRes x, DRes y) { - int maxBitLength = builder.getBasicNumericContext().getMaxBitLength(); - return equals(maxBitLength, x, y); + public DRes compareLT(DRes x, DRes y, Algorithm algorithm) { + if (algorithm == Algorithm.LOG_ROUNDS) { + if (factoryNumeric.getBasicNumericContext().getStatisticalSecurityParam() + factoryNumeric + .getBasicNumericContext().getMaxBitLength() > factoryNumeric.getBasicNumericContext() + .getModulus().bitLength()) { + throw new IllegalArgumentException( + "The max bitlength plus the statistical security parameter overflows the size of the modulus."); + } + DRes difference = builder.numeric().sub(x, y); + return builder.seq(new LessThanZero(difference)); + } else { + throw new UnsupportedOperationException("Not implemented yet"); + } } @Override - public DRes equals(int bitLength, DRes x, DRes y) { - return builder.seq(new Equality(bitLength, x, y)); + public DRes compareLTBits(DRes openValue, DRes>> secretBits) { + return builder.seq(new BitLessThanOpen(openValue, secretBits)); } @Override - public DRes compareLEQ(DRes x, DRes y) { - int bitLength = factoryNumeric.getBasicNumericContext().getMaxBitLength(); - return builder.seq( - new LessThanOrEquals(bitLength, magicSecureNumber, x, y)); + public DRes> carry(List bitPairs) { + return builder.seq(new Carry(bitPairs)); } @Override @@ -65,8 +84,40 @@ public DRes sign(DRes x) { } @Override - public DRes compareZero(DRes x, int bitLength) { - return builder.seq(new ZeroTest(bitLength, x, magicSecureNumber)); + public DRes equals(DRes x, DRes y, int bitlength, Algorithm algorithm) { + DRes diff = builder.numeric().sub(x, y); + return compareZero(diff, bitlength, algorithm); + } + + @Override + public DRes equals(DRes x, DRes y) { + int bitLength = factoryNumeric.getBasicNumericContext().getMaxBitLength(); + return equals(x, y, bitLength); + } + + @Override + public DRes compareZero(DRes x, int bitlength, Algorithm algorithm) { + if (bitlength > factoryNumeric.getBasicNumericContext().getMaxBitLength()) { + throw new IllegalArgumentException("The bitlength is more than allowed for elements."); + } + if (factoryNumeric.getBasicNumericContext().getStatisticalSecurityParam() + + bitlength > factoryNumeric.getBasicNumericContext().getModulus().bitLength()) { + throw new IllegalArgumentException( + "The max bitlength plus the statistical security parameter overflows the size of the modulus."); + } + switch (algorithm) { + case CONST_ROUNDS: + return builder.seq(new ZeroTestConstRounds(x, bitlength)); + case LOG_ROUNDS: + return builder.seq(new ZeroTestLogRounds(x, bitlength)); + default: + throw new UnsupportedOperationException("Not implemented yet"); + } + } + + @Override + public DRes>, SInt>> argMin(List> xs) { + return builder.seq(new ArgMin(xs)); } } diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultLogical.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultLogical.java new file mode 100644 index 000000000..c2f49c4b4 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/DefaultLogical.java @@ -0,0 +1,218 @@ +package dk.alexandra.fresco.framework.builder.numeric; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +/** + * Default implementation of {@link Logical}, expressing logical operations via arithmetic. + */ +public class DefaultLogical implements Logical { + + protected final ProtocolBuilderNumeric builder; + + protected DefaultLogical(ProtocolBuilderNumeric builder) { + this.builder = builder; + } + + @Override + public DRes and(DRes bitA, DRes bitB) { + return builder.seq(seq -> seq.numeric().mult(bitA, bitB)); + } + + @Override + public DRes or(DRes bitA, DRes bitB) { + // bitA + bitB - bitA * bitB + return builder.seq(seq -> { + // mult and add could be in parallel + DRes sum = seq.numeric().add(bitA, bitB); + DRes prod = seq.numeric().mult(bitA, bitB); + return seq.numeric().sub(sum, prod); + }); + } + + @Override + public DRes halfOr(DRes bitA, DRes bitB) { + return builder.numeric().add(bitA, bitB); + } + + @Override + public DRes xor(DRes bitA, DRes bitB) { + // knownBit + secretBit - 2 * knownBit * secretBit + return builder.seq(seq -> { + // mult and add could be in parallel + OInt two = seq.getOIntFactory().two(); + DRes sum = seq.numeric().add(bitA, bitB); + DRes prod = seq.numeric() + .multByOpen(two, seq.numeric().mult(bitA, bitB)); + return seq.numeric().sub(sum, prod); + }); + } + + @Override + public DRes andKnown(DRes knownBit, DRes secretBit) { + return builder.seq(seq -> seq.numeric().multByOpen(knownBit, secretBit)); + } + + @Override + public DRes xorKnown(DRes knownBit, DRes secretBit) { + // knownBit + secretBit - 2 * knownBit * secretBit + return builder.seq(seq -> { + // mult and add could be in parallel + OInt two = seq.getOIntFactory().two(); + DRes sum = seq.numeric().addOpen(knownBit, secretBit); + DRes prod = seq.numeric() + .multByOpen(two, seq.numeric().multByOpen(knownBit, secretBit)); + return seq.numeric().sub(sum, prod); + }); + } + + @Override + public DRes not(DRes secretBit) { + // 1 - secretBit + return builder.seq(seq -> { + OInt one = seq.getOIntFactory().one(); + return seq.numeric().subFromOpen(one, secretBit); + }); + } + + @Override + public DRes openAsBit(DRes secretBit) { + return builder.numeric().openAsOInt(secretBit); + } + + @Override + public DRes>> openAsBits(DRes>> secretBits) { + return builder.par(par -> { + List> openList = + secretBits.out().stream().map(closed -> par.logical().openAsBit(closed)) + .collect(Collectors.toList()); + return () -> openList; + }); + } + + @Override + public DRes>> batchedNot(DRes>> bits) { + return builder.par(par -> { + List> negated = + bits.out().stream().map(closed -> par.logical().not(closed)) + .collect(Collectors.toList()); + return () -> negated; + }); + } + + private DRes>> pairWise( + DRes>> bitsA, + DRes>> bitsB, + BiFunction, DRes, DRes> op) { + List> leftOut = bitsB.out(); + List> rightOut = bitsA.out(); + List> resultBits = new ArrayList<>(leftOut.size()); + for (int i = 0; i < leftOut.size(); i++) { + DRes leftBit = leftOut.get(i); + DRes rightBit = rightOut.get(i); + DRes resultBit = op.apply(leftBit, rightBit); + resultBits.add(resultBit); + } + return () -> resultBits; + } + + private DRes>> pairWiseKnown( + DRes> knownBits, + DRes>> secretBits, + BiFunction, DRes, DRes> op) { + List knownOut = knownBits.out(); + List> secretOut = secretBits.out(); + List> resultBits = new ArrayList<>(secretOut.size()); + for (int i = 0; i < secretOut.size(); i++) { + DRes secretBit = secretOut.get(i); + DRes knownBit = knownOut.get(i); + DRes resultBit = op.apply(knownBit, secretBit); + resultBits.add(resultBit); + } + return () -> resultBits; + } + + @Override + public DRes>> pairWiseXorKnown(DRes> knownBits, + DRes>> secretBits) { + return builder.par(par -> { + BiFunction, DRes, DRes> f = (left, right) -> par.logical() + .xorKnown(left, right); + return pairWiseKnown(knownBits, secretBits, f); + }); + } + + @Override + public DRes>> pairWiseAndKnown(DRes> knownBits, + DRes>> secretBits) { + return builder.par(par -> { + BiFunction, DRes, DRes> f = (left, right) -> par.logical() + .andKnown(left, right); + return pairWiseKnown(knownBits, secretBits, f); + }); + } + + @Override + public DRes>> pairWiseAnd(DRes>> bitsA, + DRes>> bitsB) { + return builder.par(par -> { + BiFunction, DRes, DRes> f = (left, right) -> par.logical() + .and(left, right); + return pairWise(bitsA, bitsB, f); + }); + } + + @Override + public DRes>> pairWiseOr(DRes>> bitsA, + DRes>> bitsB) { + return builder.par(par -> { + BiFunction, DRes, DRes> f = (left, right) -> par.logical() + .or(left, right); + return pairWise(bitsA, bitsB, f); + }); + } + + @Override + public DRes>> pairWiseXor(DRes>> bitsA, + DRes>> bitsB) { + return builder.par(par -> { + BiFunction, DRes, DRes> f = (left, right) -> par.logical() + .xor(left, right); + return pairWise(bitsA, bitsB, f); + }); + } + + @Override + public DRes orOfList(DRes>> bits) { + return builder.seq(seq -> bits) + .whileLoop((inputs) -> inputs.size() > 1, + (prevSeq, inputs) -> prevSeq.logical().orNeighbors(inputs)) + // end while + .seq((builder, out) -> out.get(0)); + } + + @Override + public DRes>> orNeighbors(List> bits) { + return builder.par(par -> { + List> out = new ArrayList<>(); + DRes left = null; + for (DRes currentInput : bits) { + if (left == null) { + left = currentInput; + } else { + out.add(par.logical().or(left, currentInput)); + left = null; + } + } + if (left != null) { + out.add(left); + } + return () -> out; + }); + } +} diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Logical.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Logical.java new file mode 100644 index 000000000..775fecdbf --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Logical.java @@ -0,0 +1,116 @@ +package dk.alexandra.fresco.framework.builder.numeric; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.ComputationDirectory; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.List; + +/** + * Logical operators on secret arithmetic representations of boolean values.

NOTE: all inputs are + * assumed to represent 0 or 1 values only. The result is undefined if other values are passed + * in.

+ */ +public interface Logical extends ComputationDirectory { + // TODO: this is starting to look a lot like the Binary computation directory... + + /** + * Computes logical AND of inputs.

NOTE: Inputs must represent 0 or 1 values only.

+ */ + DRes and(DRes bitA, DRes bitB); + + /** + * Computes logical OR of inputs.

NOTE: Inputs must represent 0 or 1 values only.

+ */ + DRes or(DRes bitA, DRes bitB); + + /** + * Computes logical OR of inputs but is only safe to use when at least one of the bits is 0. + *

This allows to express and or as a linear operation and therefore far more efficient.

+ */ + DRes halfOr(DRes bitA, DRes bitB); + + /** + * Computes logical XOR of inputs.

NOTE: Inputs must represent 0 or 1 values only.

+ */ + DRes xor(DRes bitA, DRes bitB); + + /** + * Computes logical AND of inputs.

NOTE: Inputs must represent 0 or 1 values only.

+ */ + DRes andKnown(DRes knownBit, DRes secretBit); + + /** + * Computes logical XOR of inputs.

NOTE: Inputs must represent 0 or 1 values only.

+ */ + DRes xorKnown(DRes knownBit, DRes secretBit); + + /** + * Computes logical NOT of input.

NOTE: Input must represent 0 or 1 values only.

+ */ + DRes not(DRes secretBit); + + /** + * Opens secret bits, possibly performing conversion before producing final open value.

NOTE: + * Input must represent 0 or 1 values only.

+ */ + DRes openAsBit(DRes secretBit); + + /** + * Batch opening of bits. + */ + DRes>> openAsBits(DRes>> secretBits); + + /** + * Negates all given bits. + */ + DRes>> batchedNot(DRes>> bits); + + /** + * Computes pairwise logical AND of input bits.

NOTE: Inputs must represent 0 or 1 values + * only.

+ */ + DRes>> pairWiseAndKnown(DRes> knownBits, + DRes>> secretBits); + + /** + * Computes pairwise logical AND of input bits.

NOTE: Inputs must represent 0 or 1 values + * only.

+ */ + DRes>> pairWiseAnd(DRes>> bitsA, + DRes>> bitsB); + + /** + * Computes pairwise logical OR of input bits.

NOTE: Inputs must represent 0 or 1 values + * only.

+ */ + DRes>> pairWiseOr(DRes>> bitsA, + DRes>> bitsB); + + /** + * Computes pairwise logical XOR of input bits.

NOTE: Inputs must represent 0 or 1 values + * only.

+ */ + DRes>> pairWiseXor(DRes>> bitsA, + DRes>> bitsB); + + /** + * Computes pairwise logical XOR of input bits.

NOTE: Inputs must represent 0 or 1 values + * only.

+ */ + DRes>> pairWiseXorKnown(DRes> knownBits, + DRes>> secretBits); + + /** + * Computes logical OR of all input bits.

NOTE: Inputs must represent 0 or 1 values only. + *

+ */ + DRes orOfList(DRes>> bits); + + /** + * Given a list of bits, computes or of each neighbor pair of bits, i.e., given b1, b2, b3, b4, + * will output b1 OR b2, b3 OR b4.

Also handles uneven number of elements.

+ */ + DRes>> orNeighbors(List> bits); + +} diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Numeric.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Numeric.java index ecd008da3..65649659e 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Numeric.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/Numeric.java @@ -2,8 +2,11 @@ import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.builder.ComputationDirectory; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; /** * Basic interface for numeric applications. This is the interface which an arithmetic protocol @@ -29,6 +32,14 @@ public interface Numeric extends ComputationDirectory { */ DRes add(BigInteger a, DRes b); + /** + * Adds a secret value with a public value and returns the result. + * @param a Public value + * @param b Secret value + * @return A deferred result computing a+b + */ + DRes addOpen(DRes a, DRes b); + /** * Subtracts two secret values and returns the result. * @param a Secret value 1 @@ -45,6 +56,22 @@ public interface Numeric extends ComputationDirectory { */ DRes sub(BigInteger a, DRes b); + /** + * Subtracts a public value and a secret value and returns the result. + * @param a Public value + * @param b Secret value + * @return A deferred result computing a-b + */ + DRes subFromOpen(DRes a, DRes b); + + /** + * Subtracts a secret value and a public value and returns the result. + * @param a Secret value + * @param b Public value + * @return A deferred result computing a-b + */ + DRes subOpen(DRes a, DRes b); + /** * Subtracts a secret value and a public value and returns the result. * @param a Secret value @@ -69,6 +96,14 @@ public interface Numeric extends ComputationDirectory { */ DRes mult(BigInteger a, DRes b); + /** + * Multiplies a public value onto a secret value and returns the result. + * @param a Public value + * @param b Secret value + * @return A deferred result computing a*b + */ + DRes multByOpen(DRes a, DRes b); + /** * Returns a deferred result which creates a secret shared random bit. (This should be computed * beforehand to increase the speed of the application) @@ -111,6 +146,16 @@ public interface Numeric extends ComputationDirectory { */ DRes open(DRes secretShare); + /** + * Opens a value to all MPC parties. + */ + DRes openAsOInt(DRes secretShare); + + /** + * Opens a value to all MPC parties. + */ + DRes openAsOInt(DRes secretShare, int outputParty); + /** * Opens a value to a single given party. * @param secretShare The value to open. @@ -118,4 +163,24 @@ public interface Numeric extends ComputationDirectory { * @return The opened value if you are the outputParty, or null otherwise. */ DRes open(DRes secretShare, int outputParty); + + /** + * Helper methods for inputting multiple known values at once. + */ + default List> known(List values) { + List> secret = new ArrayList<>(values.size()); + for (BigInteger value : values) { + secret.add(known(value)); + } + return secret; + } + + default DRes>> knownAsDRes(List values) { + List> secret = new ArrayList<>(values.size()); + for (BigInteger value : values) { + secret.add(known(value)); + } + return () -> secret; + } + } diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/NumericResourcePool.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/NumericResourcePool.java index b50039a79..225d64aa7 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/NumericResourcePool.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/NumericResourcePool.java @@ -6,10 +6,8 @@ import java.math.BigInteger; /** - * Every resource pool must have a set of properties available, primarily - * the modulus and a BigInteger serialization. - *

- * This is paired with the {@link ProtocolSuiteNumeric}. + * Every resource pool must have a set of properties available, primarily the modulus and a + * BigInteger serialization.

This is paired with the {@link ProtocolSuiteNumeric}. */ public interface NumericResourcePool extends ResourcePool { @@ -42,4 +40,5 @@ default BigInteger convertRepresentation(BigInteger bigInteger) { } return actual; } + } diff --git a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/ProtocolBuilderNumeric.java b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/ProtocolBuilderNumeric.java index 71bc47c17..962cdf218 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/ProtocolBuilderNumeric.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/builder/numeric/ProtocolBuilderNumeric.java @@ -1,6 +1,8 @@ package dk.alexandra.fresco.framework.builder.numeric; import dk.alexandra.fresco.framework.builder.ProtocolBuilderImpl; +import dk.alexandra.fresco.framework.value.OIntArithmetic; +import dk.alexandra.fresco.framework.value.OIntFactory; import dk.alexandra.fresco.lib.compare.MiscBigIntegerGenerators; import dk.alexandra.fresco.lib.field.integer.BasicNumericContext; import dk.alexandra.fresco.lib.real.AdvancedRealNumeric; @@ -26,6 +28,9 @@ public class ProtocolBuilderNumeric extends ProtocolBuilderImplWARNING: Do not use in * production code as most methods within this builder reveals values to all parties. - * + * * @return The debug computation directory. */ public Debug debug() { @@ -133,13 +171,25 @@ public Debug debug() { /** * Mostly for use within internal FRESCO protocols. Contains methods helpful for working with the * BigInteger class. - * + * * @return The {@link MiscBigIntegerGenerators} used within the builder. */ public MiscBigIntegerGenerators getBigIntegerHelper() { return factory.getBigIntegerHelper(); } + /** + * Returns the backend-specific implementation of {@link OIntFactory}, for converting between + * backend-suite representations of open values and native data types. + */ + public OIntFactory getOIntFactory() { + return factory.getOIntFactory(); + } + + public OIntArithmetic getOIntArithmetic() { + return factory.getOIntArithmetic(); + } + /** * Creates a {@link RealNumeric} computation directory for this instance - i.e. this intended * producer. Contains basic arithmetic operations on fixed point numbers. diff --git a/core/src/main/java/dk/alexandra/fresco/framework/network/socket/Connector.java b/core/src/main/java/dk/alexandra/fresco/framework/network/socket/Connector.java index 31a723d9f..850d12afa 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/network/socket/Connector.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/network/socket/Connector.java @@ -32,11 +32,11 @@ public class Connector implements NetworkConnector { private final SocketFactory socketFactory; private final ServerSocketFactory serverFactory; - Connector(NetworkConfiguration conf, Duration timeout) { + public Connector(NetworkConfiguration conf, Duration timeout) { this(conf, timeout, SocketFactory.getDefault(), ServerSocketFactory.getDefault()); } - Connector(NetworkConfiguration conf, Duration timeout, SocketFactory socketFactory, + public Connector(NetworkConfiguration conf, Duration timeout, SocketFactory socketFactory, ServerSocketFactory serverFactory) { this.socketFactory = socketFactory; this.serverFactory = serverFactory; diff --git a/core/src/main/java/dk/alexandra/fresco/framework/sce/evaluator/NetworkBatchDecorator.java b/core/src/main/java/dk/alexandra/fresco/framework/sce/evaluator/NetworkBatchDecorator.java index b74a4e160..bcaa6e96f 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/sce/evaluator/NetworkBatchDecorator.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/sce/evaluator/NetworkBatchDecorator.java @@ -1,18 +1,18 @@ package dk.alexandra.fresco.framework.sce.evaluator; import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.util.ByteAndBitConverter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.math.BigInteger; import java.util.HashMap; import java.util.Map; /** - * Default network for the evaluators, this interface bridges the raw network4 - * with the fresco default evaluators. This class makes the - * communication on the network batched and hence throttled so evaluators behave nice - * on the network. - *
- * It is important to call flush to empty all buffers after sending and before receiving data + * Default network for the evaluators, this interface bridges the raw network4 with the fresco + * default evaluators. This class makes the communication on the network batched and hence throttled + * so evaluators behave nice on the network.
It is important to call flush to empty all + * buffers after sending and before receiving data */ public class NetworkBatchDecorator implements Network { @@ -38,9 +38,20 @@ public byte[] receive(int id) { } int count = byteInputStream.read(); - byte[] bytes = new byte[count]; - byteInputStream.read(bytes, 0, count); - return bytes; + boolean isLargePacket = (count & 0x80) == 0x80; + if (!isLargePacket) { + byte[] bytes = new byte[count]; + byteInputStream.read(bytes, 0, count); + return bytes; + } else { + byte[] lengthBytes = new byte[4]; + lengthBytes[0] = (byte) (count & 0x7f); // zero out indicator bit + byteInputStream.read(lengthBytes, 1, 3); + int numBytes = ByteAndBitConverter.toInt(lengthBytes, 0); + byte[] bytes = new byte[numBytes]; + byteInputStream.read(bytes, 0, numBytes); + return bytes; + } } @Override @@ -52,12 +63,27 @@ public int getNoOfParties() { public void send(int id, byte[] data) { ByteArrayOutputStream buffer = this.output .computeIfAbsent(id, (i) -> new ByteArrayOutputStream()); - if (data.length > Byte.MAX_VALUE) { - throw new IllegalStateException( - "Current implementation only supports small packages, data.length=" + data.length); + final int packetLength = data.length; + // we need the top bit to be free because we use it as an indicator for the packet type + if (packetLength <= 0x7f) { + // small packet case + // set msb in byte to 0 to indicate small packet + byte packetLengthAsByte = (byte) (packetLength & 0x7f); + buffer.write(packetLengthAsByte); + buffer.write(data, 0, packetLengthAsByte); + } else { + // large packet case + // we need the top bit to be free because we use it as an indicator for the packet type + if (packetLength >= 0x7fffffff) { + throw new IllegalStateException( + "Current implementation only supports small packages, data.length=" + packetLength); + } + // set top bit to 1 to indicate large packet + int withSetBit = packetLength | 0x80000000; + final byte[] b = ByteAndBitConverter.toByteArray(withSetBit); + buffer.write(b, 0, 4); + buffer.write(data, 0, packetLength); } - buffer.write(data.length); - buffer.write(data, 0, data.length); } /** diff --git a/core/src/main/java/dk/alexandra/fresco/framework/util/ArithmeticDummyDataSupplier.java b/core/src/main/java/dk/alexandra/fresco/framework/util/ArithmeticDummyDataSupplier.java index 30c0a2bd9..fd7f32dbb 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/util/ArithmeticDummyDataSupplier.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/util/ArithmeticDummyDataSupplier.java @@ -17,24 +17,35 @@ public class ArithmeticDummyDataSupplier { private final int myId; private final int noOfParties; private final BigInteger modulus; + private final BigInteger maxOpenValue; private final int modBitLength; private final Random random; private final SecretSharer sharer; - public ArithmeticDummyDataSupplier(int myId, int noOfParties, BigInteger modulus) { + public ArithmeticDummyDataSupplier(int myId, int noOfParties, BigInteger modulus, + BigInteger maxOpenValue) { + if (maxOpenValue.compareTo(modulus) > 0) { + throw new IllegalArgumentException( + "Max open value " + maxOpenValue + " must be less than " + modulus); + } this.myId = myId; this.noOfParties = noOfParties; this.modulus = modulus; + this.maxOpenValue = maxOpenValue; this.modBitLength = modulus.bitLength(); random = new Random(42); sharer = new DummyBigIntegerSharer(modulus, random); } + public ArithmeticDummyDataSupplier(int myId, int noOfParties, BigInteger modulus) { + this(myId, noOfParties, modulus, modulus); + } + /** * Computes the next random element and this party's share. */ public Pair getRandomElementShare() { - BigInteger element = sampleRandomBigInteger(); + BigInteger element = sampleRandomBigInteger(maxOpenValue); return new Pair<>(element, sharer.share(element, noOfParties).get(myId - 1)); } @@ -50,8 +61,8 @@ public Pair getRandomBitShare() { * Computes the next random multiplication triple and this party's shares. */ public MultiplicationTripleShares getMultiplicationTripleShares() { - BigInteger left = sampleRandomBigInteger(); - BigInteger right = sampleRandomBigInteger(); + BigInteger left = sampleRandomBigInteger(maxOpenValue); + BigInteger right = sampleRandomBigInteger(maxOpenValue); BigInteger product = left.multiply(right).mod(modulus); return new MultiplicationTripleShares( new Pair<>(left, sharer.share(left, noOfParties).get(myId - 1)), @@ -60,6 +71,30 @@ public MultiplicationTripleShares getMultiplicationTripleShares() { ); } + public MultiplicationTripleShares getMultiplicationBitTripleShares() { + BigInteger left = getNextBit(); + BigInteger right = getNextBit(); + BigInteger product = left.multiply(right).mod(BigInteger.valueOf(2)); + return new MultiplicationTripleShares( + new Pair<>(left, sharer.share(left, noOfParties).get(myId - 1)), + new Pair<>(right, sharer.share(right, noOfParties).get(myId - 1)), + new Pair<>(product, sharer.share(product, noOfParties).get(myId - 1)) + ); + } + + /** + * Computes pair of values r and r^{prime} such that r^{prime} is a random element and r = + * r^{prime} / 2^{d}, i.e., r right-shifted by d. + */ + public TruncationPairShares getTruncationPairShares(int d) { + BigInteger rPrime = sampleRandomBigInteger(maxOpenValue); + BigInteger r = rPrime.shiftRight(d); + return new TruncationPairShares( + new Pair<>(rPrime, sharer.share(rPrime, noOfParties).get(myId - 1)), + new Pair<>(r, sharer.share(r, noOfParties).get(myId - 1)) + ); + } + /** * Constructs an exponentiation pipe.

An exponentiation pipe is a list of numbers in the * following format: r^{-1}, r, r^{2}, r^{3}, ..., r^{expPipeLength}, where r is a random element @@ -72,13 +107,29 @@ public List> getExpPipe(int expPipeLength) { .collect(Collectors.toList()); } + /** + * Returns this party's share of given secret. + * + * @param value secret to share + * @return this party's secret share + */ + public BigInteger secretShare(BigInteger value) { + return sharer.share(value, noOfParties).get(myId - 1); + } + private BigInteger sampleRandomBigInteger() { - return new BigInteger(modBitLength, random).mod(modulus); + return sampleRandomBigInteger(modulus); + } + + private BigInteger sampleRandomBigInteger(BigInteger limit) { + BigInteger randomElement = new BigInteger(modBitLength, random); + // this is a biased distribution but we're not in secure-land anyways + return randomElement.mod(limit); } private List getOpenExpPipe(int expPipeLength) { List openExpPipe = new ArrayList<>(expPipeLength); - BigInteger first = sampleRandomBigInteger(); + BigInteger first = sampleRandomBigInteger(maxOpenValue); BigInteger inverse = first.modInverse(modulus); openExpPipe.add(inverse); openExpPipe.add(first); diff --git a/core/src/main/java/dk/alexandra/fresco/framework/util/ByteAndBitConverter.java b/core/src/main/java/dk/alexandra/fresco/framework/util/ByteAndBitConverter.java index ed9d9b03b..0deca178b 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/util/ByteAndBitConverter.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/util/ByteAndBitConverter.java @@ -104,6 +104,32 @@ public static String toHex(boolean[] bits) { return hex.toString(); } + /** + * Given a larger, pre-allocated byte array, reads out a long starting at start index. + */ + public static long toLong(byte[] bytes, int start) { + int flipped = bytes.length - start - 1; + return (bytes[flipped] & 0xFFL) + | (bytes[flipped - 1] & 0xFFL) << 8 + | (bytes[flipped - 2] & 0xFFL) << 16 + | (bytes[flipped - 3] & 0xFFL) << 24 + | (bytes[flipped - 4] & 0xFFL) << 32 + | (bytes[flipped - 5] & 0xFFL) << 40 + | (bytes[flipped - 6] & 0xFFL) << 48 + | (bytes[flipped - 7] & 0xFFL) << 56; + } + + /** + * Same as {@link #toLong(byte[], int)} but for an int. + */ + public static int toInt(byte[] bytes, int start) { + int flipped = bytes.length - start - 1; + return (bytes[flipped] & 0xFF) + | (bytes[flipped - 1] & 0xFF) << 8 + | (bytes[flipped - 2] & 0xFF) << 16 + | (bytes[flipped - 3] & 0xFF) << 24; + } + public static String toHex(List bits) { Boolean[] bitArray = bits.toArray(new Boolean[1]); return toHex(convertArray(bitArray)); diff --git a/core/src/main/java/dk/alexandra/fresco/framework/util/MathUtils.java b/core/src/main/java/dk/alexandra/fresco/framework/util/MathUtils.java index 35682ff17..c88487196 100644 --- a/core/src/main/java/dk/alexandra/fresco/framework/util/MathUtils.java +++ b/core/src/main/java/dk/alexandra/fresco/framework/util/MathUtils.java @@ -1,6 +1,9 @@ package dk.alexandra.fresco.framework.util; +import dk.alexandra.fresco.framework.DRes; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class MathUtils { @@ -82,6 +85,34 @@ public static BigInteger sum(List summands, BigInteger modulus) { .mod(modulus); } + /** + * Turns input value into bits in big-endian order.

If the actual bit length of the value is + * smaller than numBits, the result is padded with 0s. If the bit length is larger only the first + * numBits bits are used.

+ */ + public static List toBits(BigInteger value, int numBits) { + List bits = new ArrayList<>(numBits); + for (int b = 0; b < numBits; b++) { + boolean boolBit = value.testBit(b); + bits.add(boolBit ? BigInteger.ONE : BigInteger.ZERO); + } + Collections.reverse(bits); + return bits; + } + + /** + * Same as {@link #toBits(BigInteger, int)}, but wraps result bits in DRes. + */ + public static List> toBitsAsDRes(BigInteger value, int numBits) { + List> bits = new ArrayList<>(numBits); + for (int b = 0; b < numBits; b++) { + boolean boolBit = value.testBit(b); + bits.add(boolBit ? () -> BigInteger.ONE : () -> BigInteger.ZERO); + } + Collections.reverse(bits); + return bits; + } + /** * Find non-quadratic residue for field. * diff --git a/core/src/main/java/dk/alexandra/fresco/framework/util/SIntPair.java b/core/src/main/java/dk/alexandra/fresco/framework/util/SIntPair.java new file mode 100644 index 000000000..d09f56161 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/util/SIntPair.java @@ -0,0 +1,13 @@ +package dk.alexandra.fresco.framework.util; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.value.SInt; + +public class SIntPair extends Pair, DRes> { + + public SIntPair(DRes first, + DRes second) { + super(first, second); + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/framework/util/TruncationPairShares.java b/core/src/main/java/dk/alexandra/fresco/framework/util/TruncationPairShares.java new file mode 100644 index 000000000..a413aa205 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/util/TruncationPairShares.java @@ -0,0 +1,29 @@ +package dk.alexandra.fresco.framework.util; + +import java.math.BigInteger; + +/** + * Generic representation of a truncation pair.

A truncation pair is pre-processing material + * used for probabilistic truncation. A truncation pair consists of a value r and r^{prime} such + * that r^{prime} is a random element and r = r^{prime} / 2^{d}, i.e., r right-shifted by d.

+ */ +public class TruncationPairShares { + + private final Pair rPrime; + private final Pair r; + + public TruncationPairShares(Pair rPrime, + Pair r) { + this.rPrime = rPrime; + this.r = r; + } + + public Pair getR() { + return r; + } + + public Pair getRPrime() { + return rPrime; + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/framework/value/BigIntegerOInt.java b/core/src/main/java/dk/alexandra/fresco/framework/value/BigIntegerOInt.java new file mode 100644 index 000000000..5219bc172 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/value/BigIntegerOInt.java @@ -0,0 +1,32 @@ +package dk.alexandra.fresco.framework.value; + +import java.math.BigInteger; + +/** + * An open value wrapper for {@link BigInteger}. + */ +public class BigIntegerOInt implements OInt { + + private final BigInteger value; + + public BigIntegerOInt(BigInteger value) { + this.value = value; + } + + public BigInteger getValue() { + return value; + } + + @Override + public OInt out() { + return this; + } + + @Override + public String toString() { + return "BigIntegerOInt{" + + "value=" + value + + '}'; + } +} + diff --git a/core/src/main/java/dk/alexandra/fresco/framework/value/BigIntegerOIntArithmetic.java b/core/src/main/java/dk/alexandra/fresco/framework/value/BigIntegerOIntArithmetic.java new file mode 100644 index 000000000..9f976db97 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/value/BigIntegerOIntArithmetic.java @@ -0,0 +1,94 @@ +package dk.alexandra.fresco.framework.value; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Implementation of {@link OIntArithmetic} for the case when open values are represented directly + * via {@link BigInteger}. + */ +public class BigIntegerOIntArithmetic implements OIntArithmetic { + + private static final BigInteger TWO = new BigInteger("2"); + private List twoPowersList; + private final List cachedTwoPowersList; + private final OIntFactory factory; + + public BigIntegerOIntArithmetic(OIntFactory factory) { + this.factory = factory; + twoPowersList = new ArrayList<>(1); + twoPowersList.add(new BigIntegerOInt(BigInteger.ONE)); + cachedTwoPowersList = Collections + .unmodifiableList(getPowersOfTwo(2 * factory.getMaxBitLength())); + } + + @Override + public boolean isZero(OInt openValue) { + return factory.toBigInteger(openValue).equals(BigInteger.ZERO); + } + + @Override + public boolean isOne(OInt openValue) { + return factory.toBigInteger(openValue).equals(BigInteger.ONE); + } + + @Override + public OInt one() { + return factory.one(); + } + + @Override + public List toBits(OInt openValue, int numBits) { + BigInteger value = factory.toBigInteger(openValue); + List bits = new ArrayList<>(numBits); + for (int b = 0; b < numBits; b++) { + boolean boolBit = value.testBit(b); + OInt bit = boolBit ? factory.one() : factory.zero(); + bits.add(bit); + } + Collections.reverse(bits); + return bits; + } + + @Override + public List getPowersOfTwo(int numPowers) { + // TODO do we need modular reduction in here? + // TODO taken from MiscBigIntegerGenerators, clean up + int currentLength = twoPowersList.size(); + if (numPowers > currentLength) { + ArrayList newTwoPowersList = new ArrayList<>(numPowers); + newTwoPowersList.addAll(twoPowersList); + BigInteger currentValue = ((BigIntegerOInt) newTwoPowersList.get(currentLength - 1).out()) + .getValue(); + while (numPowers > newTwoPowersList.size()) { + currentValue = currentValue.shiftLeft(1); + newTwoPowersList.add(new BigIntegerOInt(currentValue)); + } + twoPowersList = Collections.unmodifiableList(newTwoPowersList); + } + return twoPowersList.subList(0, numPowers); + } + + @Override + public OInt twoTo(int power) { + if (power < cachedTwoPowersList.size()) { + return cachedTwoPowersList.get(power); + } else { + System.out.println("Not cached!"); + return factory.fromBigInteger(TWO.pow(power)); + } + } + + @Override + public OInt modTwoTo(OInt input, int power) { + OInt pow = twoTo(power); + return factory.fromBigInteger(factory.toBigInteger(input).mod(factory.toBigInteger(pow))); + } + + @Override + public OInt shiftRight(OInt input, int n) { + return factory.fromBigInteger(factory.toBigInteger(input).shiftRight(n)); + } +} diff --git a/core/src/main/java/dk/alexandra/fresco/framework/value/BigIntegerOIntFactory.java b/core/src/main/java/dk/alexandra/fresco/framework/value/BigIntegerOIntFactory.java new file mode 100644 index 000000000..a597a9015 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/value/BigIntegerOIntFactory.java @@ -0,0 +1,50 @@ +package dk.alexandra.fresco.framework.value; + +import java.math.BigInteger; + +/** + * A generic {@link OIntFactory} implementation for arithmetic backend suites that use the {@link + * BigInteger} directly as the underlying open value data type. + */ +public class BigIntegerOIntFactory implements OIntFactory { + + private static final OInt ZERO = new BigIntegerOInt(BigInteger.ZERO); + private static final OInt ONE = new BigIntegerOInt(BigInteger.ONE); + private static final OInt TWO = new BigIntegerOInt(BigInteger.valueOf(2)); + private final int maxBitLength; + + public BigIntegerOIntFactory(int maxBitLength) { + this.maxBitLength = maxBitLength; + } + + @Override + public BigInteger toBigInteger(OInt value) { + return ((BigIntegerOInt) value).getValue(); + } + + @Override + public OInt fromBigInteger(BigInteger value) { + return new BigIntegerOInt(value); + } + + @Override + public OInt zero() { + return ZERO; + } + + @Override + public OInt one() { + return ONE; + } + + @Override + public OInt two() { + return TWO; + } + + @Override + public int getMaxBitLength() { + return maxBitLength; + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/framework/value/OInt.java b/core/src/main/java/dk/alexandra/fresco/framework/value/OInt.java new file mode 100644 index 000000000..04bf81d8c --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/value/OInt.java @@ -0,0 +1,12 @@ +package dk.alexandra.fresco.framework.value; + +import dk.alexandra.fresco.framework.DRes; + +/** + * Generic interface representing open (public) values.

Arithmetic suites must implement this + * interface. In some cases this can just be a wrapper around a {@link java.math.BigInteger}, + * however, other suites may choose to rely on more efficient implementations.

+ */ +public interface OInt extends DRes { + +} diff --git a/core/src/main/java/dk/alexandra/fresco/framework/value/OIntArithmetic.java b/core/src/main/java/dk/alexandra/fresco/framework/value/OIntArithmetic.java new file mode 100644 index 000000000..5757444ee --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/value/OIntArithmetic.java @@ -0,0 +1,57 @@ +package dk.alexandra.fresco.framework.value; + +import java.util.List; + +/** + * Helper class for implementing various arithmetic operations on open values. + */ +public interface OIntArithmetic { + + /** + * Checks if value is equal to 0. + */ + boolean isZero(OInt openValue); + + /** + * Checks if value is equal to 1. + */ + boolean isOne(OInt openValue); + + /** + * Returns the number one as a deferred opened int. + */ + OInt one(); + + /** + * Turns input value into bits in big-endian order.

If the actual bit length of the value is + * smaller than numBits, the result is padded with 0s. If the bit length is larger only the first + * numBits bits are used.

+ */ + List toBits(OInt openValue, int numBits); + + /** + * Returns a list of powers of two in ascending order, up to numPowers - 1 ([2^0, 2^1, ..., + * 2^{numPowers - 1}]). + */ + List getPowersOfTwo(int numPowers); + + /** + * Computes 2^{power}. + */ + OInt twoTo(int power); + + /** + * Reduces {@code input} modulo 2^{power}. + * + * @param input the input to reduce + * @param power the two-power to reduce against + * @return the reduced input modulo the two-power + */ + OInt modTwoTo(OInt input, int power); + + /** + * Right-shifts input by n.

This is an unsigned shift.

+ */ + OInt shiftRight(OInt input, int n); + +} diff --git a/core/src/main/java/dk/alexandra/fresco/framework/value/OIntFactory.java b/core/src/main/java/dk/alexandra/fresco/framework/value/OIntFactory.java new file mode 100644 index 000000000..58f9b2ea5 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/framework/value/OIntFactory.java @@ -0,0 +1,52 @@ +package dk.alexandra.fresco.framework.value; + +import java.math.BigInteger; +import java.util.List; +import java.util.stream.Collectors; + +/** + * A factory for creating instances of {@link OInt} from native java data types such as {@link + * java.math.BigInteger} and vice versa.

Arithmetic backend suites must implement this. A basic + * implementation for open values wrapping {@link BigInteger} instances is provided by {@link + * BigIntegerOIntFactory}.

+ */ +public interface OIntFactory { + + /** + * Convert open value to {@link BigInteger}. + */ + BigInteger toBigInteger(OInt value); + + /** + * Convert {@link BigInteger} to {@link OInt}. + */ + OInt fromBigInteger(BigInteger value); + + /** + * Default method for converting multiple instances of {@link BigInteger}. + */ + default List fromBigInteger(List values) { + return values.stream().map(this::fromBigInteger).collect(Collectors.toList()); + } + + /** + * Returns representation of the value 0. + */ + OInt zero(); + + /** + * Returns representation of the value 1. + */ + OInt one(); + + /** + * Returns representation of the value 2. + */ + OInt two(); + + /** + * Returns the bit length of the max. representable value. + */ + int getMaxBitLength(); + +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/MiscBigIntegerGenerators.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/MiscBigIntegerGenerators.java index 0526fe28c..428291e40 100644 --- a/core/src/main/java/dk/alexandra/fresco/lib/compare/MiscBigIntegerGenerators.java +++ b/core/src/main/java/dk/alexandra/fresco/lib/compare/MiscBigIntegerGenerators.java @@ -10,22 +10,33 @@ /** * Misc computation on BigIntegers -- results are cached. - * */ public class MiscBigIntegerGenerators { private Map coefficientsOfPolynomiums; private List twoPowersList; private BigInteger modulus; + private Map invertedPowersOfTwo; public MiscBigIntegerGenerators(BigInteger modulus) { coefficientsOfPolynomiums = new HashMap<>(); - + invertedPowersOfTwo = new HashMap<>(); this.modulus = modulus; twoPowersList = new ArrayList<>(1); twoPowersList.add(BigInteger.ONE); } + /** + * Computes 2^{-exponent} % modulus. + */ + public BigInteger invertPowerOfTwo(int exponent) { + if (!invertedPowersOfTwo.containsKey(exponent)) { + invertedPowersOfTwo.put( + exponent, + BigInteger.ONE.shiftLeft(exponent).modInverse(modulus)); + } + return invertedPowersOfTwo.get(exponent); + } /** * Generate a degree l polynomium P such that P(1) = 1 and P(i) = 0 for i in {2,3,...,l+1} @@ -52,38 +63,38 @@ public BigInteger[] getPoly(int l) { } /** - * Returns the coefficients of a polynomial of degree l such that - * f(1) = 1 and f(n) = 0 for 1 ≤ n ≤ l+1 and n - * ≠ 1 in Zp. The first element in the array is the - * coefficient of the term with the highest degree, eg. degree l. + * Returns the coefficients of a polynomial of degree l such that f(1) = 1 and + * f(n) = 0 for 1 ≤ n ≤ l+1 and n ≠ 1 in Zp. The + * first element in the array is the coefficient of the term with the highest degree, eg. degree + * l. * * @param l The desired degree of f */ private BigInteger[] constructPolynomial(int l) { - /* + /* * Let f_i be the polynoimial which is the product of the first i of - * (x-1), (x-2), ..., (x), (x-2), ..., (x-(l+1)). Then f_0 = 1 - * and f_i = (x-k) f_{i-1} where k = i if i < 1 and k = i+1 if i >= 1. - * Note that we are interested in calculating f(x) = f_l(x) / f_l(1). - * - * If we let f_ij denote the j'th coefficient of f_i we have the - * recurrence relations: - * - * f_i0 = 1 for all i (highest degree coefficient) - * - * f_ij = f_{i-1, j} - f_{i-1, j-1} * k for j = 1,...,i - * - * f_ij = 0 for j > i - */ + * (x-1), (x-2), ..., (x), (x-2), ..., (x-(l+1)). Then f_0 = 1 + * and f_i = (x-k) f_{i-1} where k = i if i < 1 and k = i+1 if i >= 1. + * Note that we are interested in calculating f(x) = f_l(x) / f_l(1). + * + * If we let f_ij denote the j'th coefficient of f_i we have the + * recurrence relations: + * + * f_i0 = 1 for all i (highest degree coefficient) + * + * f_ij = f_{i-1, j} - f_{i-1, j-1} * k for j = 1,...,i + * + * f_ij = 0 for j > i + */ BigInteger[] f = new BigInteger[l + 1]; // Initial value: f_0 = 1 f[0] = BigInteger.valueOf(1); - /* + /* * We also calculate f_i(m) in order to be able to normalize f such that - * f(m) = 1. Note that f_i(m) = f_{i-1}(m)(m - k) with the above notation. - */ + * f(m) = 1. Note that f_i(m) = f_{i-1}(m)(m - k) with the above notation. + */ BigInteger fm = BigInteger.ONE; for (int i = 1; i <= l; i++) { @@ -110,8 +121,6 @@ private BigInteger[] constructPolynomial(int l) { /** * Generates a list of [2^0, 2^1, ..., 2^length] - * @param length - * @return */ public List getTwoPowersList(int length) { int currentLength = twoPowersList.size(); @@ -130,7 +139,7 @@ public List getTwoPowersList(int length) { /** * Generates the sequence: [value, value^2, value^3, ..., value^maxBitSize-1] - * + * * @param value The base of the exponentiation sequence * @param maxBitSize The length of the sequence * @return [value, value^2, value^3, ..., value^maxBitSize-1] diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/eq/Equality.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/eq/Equality.java deleted file mode 100644 index 5d327bff8..000000000 --- a/core/src/main/java/dk/alexandra/fresco/lib/compare/eq/Equality.java +++ /dev/null @@ -1,39 +0,0 @@ -package dk.alexandra.fresco.lib.compare.eq; - -import dk.alexandra.fresco.framework.DRes; -import dk.alexandra.fresco.framework.builder.Computation; -import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; -import dk.alexandra.fresco.framework.value.SInt; - -/** - * Implements an equality protocol -- given inputs x, y set output to x==y. - * - */ -public class Equality implements Computation { - - // params - private final int bitLength; - private final DRes left; - private final DRes right; - - /** - * Constructs an instance of the Equality computation. - * - * @param bitLength The maximum bit length of the inputs. - * @param left The first element to compare. - * @param right The second element to compare. - */ - public Equality( - int bitLength, DRes left, DRes right) { - super(); - this.bitLength = bitLength; - this.left = left; - this.right = right; - } - - @Override - public DRes buildComputation(ProtocolBuilderNumeric builder) { - DRes diff = builder.numeric().sub(left, right); - return builder.comparison().compareZero(diff, bitLength); - } -} \ No newline at end of file diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/BitLessThanOpen.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/BitLessThanOpen.java new file mode 100644 index 000000000..4e4633fba --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/BitLessThanOpen.java @@ -0,0 +1,37 @@ +package dk.alexandra.fresco.lib.compare.lt; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntFactory; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.List; + +/** + * Given known value a and secret value b represented as bits, computes a { + + private final DRes openValueDef; + private final DRes>> secretBitsDef; + + public BitLessThanOpen(DRes openValue, DRes>> secretBits) { + this.openValueDef = openValue; + this.secretBitsDef = secretBits; + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + OIntFactory oIntFactory = builder.getOIntFactory(); + List> secretBits = secretBitsDef.out(); + OInt openValueA = openValueDef.out(); + int numBits = secretBits.size(); + List openBits = builder.getOIntArithmetic().toBits(openValueA, numBits); + DRes>> secretBitsNegated = builder.logical().batchedNot(secretBitsDef); + DRes gt = builder + .seq(new CarryOut(() -> openBits, secretBitsNegated, oIntFactory.one(), true)); + return builder.logical().not(gt); + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/Carry.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/Carry.java new file mode 100644 index 000000000..6c8284110 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/Carry.java @@ -0,0 +1,78 @@ +package dk.alexandra.fresco.lib.compare.lt; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.ComputationParallel; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.ArrayList; +import java.util.List; + +public class Carry implements Computation, ProtocolBuilderNumeric> { + + private final List pairs; + + public Carry(List pairs) { + this.pairs = pairs; + } + + @Override + public DRes> buildComputation(ProtocolBuilderNumeric builder) { + if (pairs.size() == 1) { + return () -> pairs; + } + final boolean isOdd = pairs.size() % 2 != 0; + final int lastFullPairIdx = pairs.size() / 2; + return (builder.par(par -> { + // TODO pre-initialize to correct size + List> pFactorsLeft = new ArrayList<>(); + List> pFactorsRight = new ArrayList<>(); + List> qFactorsLeft = new ArrayList<>(); + List> qFactorsRight = new ArrayList<>(); + + for (int i = 0; i < lastFullPairIdx; i++) { + SIntPair left = pairs.get(2 * i + 1); + SIntPair right = pairs.get(2 * i); + DRes p1 = left.getFirst(); + DRes g1 = left.getSecond(); + DRes p2 = right.getFirst(); + + pFactorsLeft.add(p1); + pFactorsRight.add(p2); + + qFactorsLeft.add(p2); + qFactorsRight.add(g1); + } + + DRes>> ps = par.logical().pairWiseAnd( + () -> pFactorsLeft, + () -> pFactorsRight + ); + DRes>> qs = par.logical().pairWiseAnd( + () -> qFactorsLeft, + () -> qFactorsRight + ); + Pair>>, DRes>>> resPair = new Pair<>(ps, qs); + return () -> resPair; + })).par((par, res) -> { + List nextRoundInner = new ArrayList<>(pairs.size() / 2); + List> ps = res.getFirst().out(); + List> qs = res.getSecond().out(); + for (int i = 0; i < lastFullPairIdx; i++) { + DRes oldQ = qs.get(i); + DRes g2 = pairs.get(2 * i) + .getSecond(); + DRes q = par.logical().halfOr(oldQ, g2); + nextRoundInner.add(new SIntPair(ps.get(i), q)); + } + if (isOdd) { + nextRoundInner.add(pairs.get(pairs.size() - 1)); + } + return () -> nextRoundInner; + }); + + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/CarryOut.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/CarryOut.java new file mode 100644 index 000000000..64f34c430 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/CarryOut.java @@ -0,0 +1,86 @@ +package dk.alexandra.fresco.lib.compare.lt; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Given values a and b represented as bits, computes if a + b overflows, i.e., if the addition + * results in a carry. + */ +public class CarryOut implements Computation { + + private final DRes> openBitsDef; + private final DRes>> secretBitsDef; + private final DRes carryIn; + private final boolean reverseSecretBits; + + /** + * Constructs new {@link CarryOut}. + * + * @param clearBits clear bits + * @param secretBits secret bits + * @param carryIn an additional carry-in bit which we add to the least-significant bits of the + * inputs + * @param reverseSecretBits indicates whether secret bits need to be reverse (to account for + * endianness) + */ + public CarryOut(DRes> clearBits, DRes>> secretBits, + DRes carryIn, boolean reverseSecretBits) { + this.secretBitsDef = secretBits; + this.openBitsDef = clearBits; + this.carryIn = carryIn; + this.reverseSecretBits = reverseSecretBits; + } + + public CarryOut(DRes> clearBits, DRes>> secretBits, + DRes carryIn) { + this(clearBits, secretBits, carryIn, false); + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + List> secretBits = secretBitsDef.out(); + if (reverseSecretBits) { + Collections.reverse(secretBits); + } + List openBits = openBitsDef.out(); + if (secretBits.size() != openBits.size()) { + throw new IllegalArgumentException("Number of bits must be the same"); + } + return builder.par(par -> { + DRes>> xored = par.logical().pairWiseXorKnown(openBitsDef, secretBitsDef); + DRes>> anded = par.logical().pairWiseAndKnown(openBitsDef, secretBitsDef); + final Pair>>, DRes>>> pair = new Pair<>(xored, + anded); + return () -> pair; + }).par((par, pair) -> { + List> xoredBits = pair.getFirst().out(); + List> andedBits = pair.getSecond().out(); + List pairs = new ArrayList<>(andedBits.size()); + for (int i = 0; i < secretBits.size(); i++) { + DRes xoredBit = xoredBits.get(i); + DRes andedBit = andedBits.get(i); + pairs.add(new SIntPair(xoredBit, andedBit)); + } + return () -> pairs; + }).seq((seq, pairs) -> { + // need to account for carry-in bit + int lastIdx = pairs.size() - 1; + SIntPair lastPair = pairs.get(lastIdx); + DRes lastCarryPropagator = seq.logical().halfOr( + lastPair.getSecond(), + seq.logical().andKnown(carryIn, lastPair.getFirst())); + pairs.set(lastIdx, new SIntPair(lastPair.getFirst(), lastCarryPropagator)); + return seq.seq(new PreCarryBits(pairs)); + }); + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/gt/LessThanOrEquals.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/LessThanOrEquals.java similarity index 86% rename from core/src/main/java/dk/alexandra/fresco/lib/compare/gt/LessThanOrEquals.java rename to core/src/main/java/dk/alexandra/fresco/lib/compare/lt/LessThanOrEquals.java index 724d8f4ed..885d75bef 100644 --- a/core/src/main/java/dk/alexandra/fresco/lib/compare/gt/LessThanOrEquals.java +++ b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/LessThanOrEquals.java @@ -1,8 +1,9 @@ -package dk.alexandra.fresco.lib.compare.gt; +package dk.alexandra.fresco.lib.compare.lt; import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.builder.Computation; import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric; +import dk.alexandra.fresco.framework.builder.numeric.Comparison.Algorithm; import dk.alexandra.fresco.framework.builder.numeric.Numeric; import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; import dk.alexandra.fresco.framework.util.Pair; @@ -13,41 +14,41 @@ public class LessThanOrEquals implements Computation { - public LessThanOrEquals(int bitLength, int securityParameter, DRes x, DRes y) { - this.bitLength = bitLength; - this.securityParameter = securityParameter; - this.x = x; - this.y = y; - } - // params etc private final int bitLength; - private final int securityParameter; private final DRes x; private final DRes y; + public LessThanOrEquals(int bitLength, DRes x, DRes y) { + this.bitLength = bitLength; + this.x = x; + this.y = y; + } + @SuppressWarnings("unchecked") @Override public DRes buildComputation(ProtocolBuilderNumeric builder) { + final int statisticalSecurity = builder.getBasicNumericContext().getStatisticalSecurityParam(); final BigInteger modulus = builder.getBasicNumericContext().getModulus(); final int bitLengthBottom = bitLength / 2; final int bitLengthTop = bitLength - bitLengthBottom; - final BigInteger twoToBitLength = BigInteger.ONE.shiftLeft(this.bitLength); + final BigInteger twoToBitLength = BigInteger.ONE.shiftLeft(bitLength); final BigInteger twoToBitLengthBottom = BigInteger.ONE.shiftLeft(bitLengthBottom); final BigInteger twoToNegBitLength = twoToBitLength.modInverse(modulus); final BigInteger one = BigInteger.ONE; return builder.seq((seq) -> seq.advancedNumeric() - .additiveMask(bitLength + securityParameter)) + .additiveMask(bitLength + statisticalSecurity)) .pairInPar((seq, mask) -> { List> bits = mask.bits.subList(0, bitLength); List> rBottomBits = bits.subList(0, bitLengthBottom); List twoPowsBottom = seq.getBigIntegerHelper().getTwoPowersList(bitLengthBottom); - return Pair.lazy(mask.random, seq.advancedNumeric().innerProductWithPublicPart(twoPowsBottom, rBottomBits)); + return Pair.lazy(mask.random, + seq.advancedNumeric().innerProductWithPublicPart(twoPowsBottom, rBottomBits)); }, (seq, mask) -> { List> rTopBits = mask.bits.subList(bitLengthBottom, bitLengthBottom + bitLengthTop); @@ -77,7 +78,7 @@ public DRes buildComputation(ProtocolBuilderNumeric builder) { DRes mS = numeric.add(z, () -> r); DRes mO = seq.numeric().open(mS); - return () -> new Object[] {mO, rBottom, rTop, rBar, z}; + return () -> new Object[]{mO, rBottom, rTop, rBar, z}; }).seq((ProtocolBuilderNumeric seq, Object[] input) -> { BigInteger mO = ((DRes) input[0]).out(); DRes rBottom = (DRes) input[1]; @@ -96,8 +97,9 @@ public DRes buildComputation(ProtocolBuilderNumeric builder) { DRes dif = numeric.sub(mTop, rTop); // eqResult <- execute eq.test - DRes eqResult = seq.comparison().compareZero(dif, bitLengthTop); - return () -> new Object[] {eqResult, rBottom, rTop, mBot, mTop, mBar, rBar, z}; + DRes eqResult = seq.comparison() + .compareZero(dif, bitLengthTop, Algorithm.CONST_ROUNDS); + return () -> new Object[]{eqResult, rBottom, rTop, mBot, mTop, mBar, rBar, z}; }).seq((ProtocolBuilderNumeric seq, Object[] input) -> { DRes eqResult = (DRes) input[0]; DRes rBottom = (DRes) input[1]; @@ -132,9 +134,9 @@ public DRes buildComputation(ProtocolBuilderNumeric builder) { // compare the half-length inputs int nextBitLength = (bitLength + 1) / 2; subComparisonResult = - seq.seq(new LessThanOrEquals(nextBitLength, securityParameter, rPrime, mPrime)); + seq.seq(new LessThanOrEquals(nextBitLength, rPrime, mPrime)); } - return () -> new Object[] {subComparisonResult, mBar, rBar, z}; + return () -> new Object[]{subComparisonResult, mBar, rBar, z}; }).seq((ProtocolBuilderNumeric seq, Object[] input) -> { DRes subComparisonResult = (DRes) input[0]; BigInteger mBar = (BigInteger) input[1]; diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/LessThanZero.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/LessThanZero.java new file mode 100644 index 000000000..b7f3c30d5 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/LessThanZero.java @@ -0,0 +1,40 @@ +package dk.alexandra.fresco.lib.compare.lt; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.Numeric; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.lib.math.integer.mod.Mod2m; +import java.math.BigInteger; + +/** + * Given secret value a, computes a { + // TODO add reference to protocol description + + private final DRes input; + + /** + * Constructs new {@link LessThanZero}. + * + * @param input input to compare to 0 + */ + public LessThanZero(DRes input) { + this.input = input; + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + final int maxBitlength = builder.getBasicNumericContext().getMaxBitLength(); + final int statisticalSecurity = builder.getBasicNumericContext().getStatisticalSecurityParam(); + DRes inputMod2m = builder.seq(new Mod2m(input, maxBitlength - 1, maxBitlength, + statisticalSecurity)); + Numeric numeric = builder.numeric(); + DRes difference = numeric.sub(input, inputMod2m); + BigInteger twoToMinusM = builder.getBigIntegerHelper().invertPowerOfTwo(maxBitlength - 1); + return numeric.sub(BigInteger.ZERO, numeric.mult(twoToMinusM, difference)); + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/PreCarryBits.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/PreCarryBits.java new file mode 100644 index 000000000..2d4974014 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/compare/lt/PreCarryBits.java @@ -0,0 +1,26 @@ +package dk.alexandra.fresco.lib.compare.lt; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.List; + +public class PreCarryBits implements Computation { + + private final List pairsDef; + + PreCarryBits(List pairs) { + this.pairsDef = pairs; + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + return builder.seq(seq -> () -> pairsDef) + .whileLoop((pairs) -> pairs.size() > 1, + (prevScope, pairs) -> prevScope.par(par -> par.comparison().carry(pairs))) + .seq((seq, out) -> out.get(0).getSecond()); + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/zerotest/ZeroTest.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/zerotest/ZeroTestConstRounds.java similarity index 51% rename from core/src/main/java/dk/alexandra/fresco/lib/compare/zerotest/ZeroTest.java rename to core/src/main/java/dk/alexandra/fresco/lib/compare/zerotest/ZeroTestConstRounds.java index 65fe3acc6..c6d2d3034 100644 --- a/core/src/main/java/dk/alexandra/fresco/lib/compare/zerotest/ZeroTest.java +++ b/core/src/main/java/dk/alexandra/fresco/lib/compare/zerotest/ZeroTestConstRounds.java @@ -9,21 +9,20 @@ * testing for equality with zero for a bitLength-bit number (positive or negative). * */ -public class ZeroTest implements Computation { +public class ZeroTestConstRounds implements Computation { - private final int securityParameter; - private final int bitLength; private final DRes input; + private final int maxBitlength; - public ZeroTest(int bitLength, DRes input, int securityParameter) { - this.bitLength = bitLength; + public ZeroTestConstRounds(DRes input, int maxBitlength) { this.input = input; - this.securityParameter = securityParameter; + this.maxBitlength = maxBitlength; } @Override public DRes buildComputation(ProtocolBuilderNumeric builder) { - DRes reduced = builder.seq(new ZeroTestReducer(bitLength, input, securityParameter)); - return builder.seq(new ZeroTestBruteforce(bitLength, reduced)); + final int statisticalSecurity = builder.getBasicNumericContext().getStatisticalSecurityParam(); + DRes reduced = builder.seq(new ZeroTestReducer(maxBitlength, input, statisticalSecurity)); + return builder.seq(new ZeroTestBruteforce(maxBitlength, reduced)); } } diff --git a/core/src/main/java/dk/alexandra/fresco/lib/compare/zerotest/ZeroTestLogRounds.java b/core/src/main/java/dk/alexandra/fresco/lib/compare/zerotest/ZeroTestLogRounds.java new file mode 100644 index 000000000..a9546e30d --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/compare/zerotest/ZeroTestLogRounds.java @@ -0,0 +1,50 @@ +package dk.alexandra.fresco.lib.compare.zerotest; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; + +public class ZeroTestLogRounds implements Computation { + + // TODO add paper reference + private final DRes input; + private final int maxBitlength; + + public ZeroTestLogRounds(DRes input, int maxBitlength) { + this.input = input; + this.maxBitlength = maxBitlength; + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + final int statisticalSecurity = builder.getBasicNumericContext().getStatisticalSecurityParam(); + return builder.seq(seq -> seq.advancedNumeric().randomBitMask(maxBitlength + + statisticalSecurity)).seq((seq, r) -> { + // Use the integer interpretation of r to compute c = 2^maxLength+(input + r) + DRes c = seq.numeric().openAsOInt(seq.numeric().addOpen(seq + .getOIntArithmetic().twoTo(maxBitlength), seq.numeric().add( + input, r.getValue()))); + final Pair>>, DRes> bitsAndC = new Pair<>(r.getBits(), c); + return () -> bitsAndC; + }).seq((seq, pair) -> { + List cbits = seq.getOIntArithmetic().toBits(pair.getSecond().out(), maxBitlength); + // Reverse the bits of c as they are stored in big endian whereas the + // composed r values from random bit mask will be in little endian as + // it is based on a list of bits + Collections.reverse(cbits); + List> secretBits = pair.getFirst().out().subList(0, maxBitlength); + DRes>> d = seq + .par(par -> par.logical().pairWiseXorKnown(() -> cbits, () -> secretBits)); + // return 1 - OR-list(d) + return seq.numeric().subFromOpen(seq.getOIntArithmetic().one(), seq + .logical().orOfList(d)); + }); + } +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/field/integer/BasicNumericContext.java b/core/src/main/java/dk/alexandra/fresco/lib/field/integer/BasicNumericContext.java index 4b50d6b66..024bda4c6 100644 --- a/core/src/main/java/dk/alexandra/fresco/lib/field/integer/BasicNumericContext.java +++ b/core/src/main/java/dk/alexandra/fresco/lib/field/integer/BasicNumericContext.java @@ -6,27 +6,57 @@ * Holds the most crucial properties about the finite field we are working within. */ public class BasicNumericContext { + // TODO temporary hardcoded statistical security parameter + private static final int DEFAULT_STATISTICAL_SECURITY = 40; + private final int statisticalSecurityParam; private final int maxBitLength; private final BigInteger modulus; private final int myId; private final int noOfParties; - /** - * @param maxBitLength The maximum length in bits that the numbers in the application will - * have. - * @param modulus the modules used in the application - * @param myId my party id - * @param noOfParties number of parties in computation + * @param maxBitLength + * The maximum length in bits that the numbers in the application will have. + * @param modulus + * the modules used in the application + * @param myId + * my party id + * @param noOfParties + * number of parties in computation */ public BasicNumericContext(int maxBitLength, BigInteger modulus, int myId, int noOfParties) { + this(maxBitLength, modulus, myId, noOfParties, DEFAULT_STATISTICAL_SECURITY); + } + + /** + * @param maxBitLength + * The maximum length in bits that the numbers in the application will have. + * @param modulus + * the modules used in the application + * @param myId + * my party id + * @param noOfParties + * number of parties in computation + * @param statisticalSecurityParam + * the statistical security parameter + */ + public BasicNumericContext(int maxBitLength, BigInteger modulus, int myId, int noOfParties, + int statisticalSecurityParam) { + this.statisticalSecurityParam = statisticalSecurityParam; this.maxBitLength = maxBitLength; this.modulus = modulus; this.myId = myId; this.noOfParties = noOfParties; } + /** + * Returns the statistical security parameter. + */ + public int getStatisticalSecurityParam() { + return this.statisticalSecurityParam; + } + /** * Returns the maximum number of bits a number in the field can contain. */ @@ -34,7 +64,6 @@ public int getMaxBitLength() { return this.maxBitLength; } - /** * Returns the modulus used in the underlying arithmetic protocol suite. * @@ -58,4 +87,5 @@ public int getMyId() { public int getNoOfParties() { return noOfParties; } + } diff --git a/core/src/main/java/dk/alexandra/fresco/lib/lp/BlandEnteringVariable.java b/core/src/main/java/dk/alexandra/fresco/lib/lp/BlandEnteringVariable.java index d68438c51..607405484 100644 --- a/core/src/main/java/dk/alexandra/fresco/lib/lp/BlandEnteringVariable.java +++ b/core/src/main/java/dk/alexandra/fresco/lib/lp/BlandEnteringVariable.java @@ -77,7 +77,7 @@ public DRes>, SInt>> buildComputation( int bitlength = (int) Math.log(pairwiseSums.size()) * 2 + 1; Comparison comparison = par.comparison(); for (int i = 0; i < updatedF.size(); i++) { - enteringIndex.add(comparison.equals(bitlength, pairwiseSums.get(i), one)); + enteringIndex.add(comparison.equals(pairwiseSums.get(i), one, bitlength)); } return () -> enteringIndex; })).seq((seq, enteringIndex) -> { diff --git a/core/src/main/java/dk/alexandra/fresco/lib/math/integer/SumSIntList.java b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/SumSIntList.java index 9a4f71235..3e0213bbb 100644 --- a/core/src/main/java/dk/alexandra/fresco/lib/math/integer/SumSIntList.java +++ b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/SumSIntList.java @@ -13,7 +13,7 @@ */ public class SumSIntList implements Computation { - private final List> input; + private final DRes>> inputDef; /** * Creates a new SumSIntList. @@ -21,11 +21,16 @@ public class SumSIntList implements Computation { * @param list the list to sum */ public SumSIntList(List> list) { - input = list; + this(() -> list); + } + + public SumSIntList(DRes>> list) { + inputDef = list; } @Override public DRes buildComputation(ProtocolBuilderNumeric iterationBuilder) { + List> input = inputDef.out(); return iterationBuilder.seq(seq -> () -> input ).whileLoop( diff --git a/core/src/main/java/dk/alexandra/fresco/lib/math/integer/binary/GenerateRandomBitMask.java b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/binary/GenerateRandomBitMask.java new file mode 100644 index 000000000..9efae14d2 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/binary/GenerateRandomBitMask.java @@ -0,0 +1,48 @@ +package dk.alexandra.fresco.lib.math.integer.binary; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.ArrayList; +import java.util.List; + +/** + * See {@link dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric#randomBitMask(int)}. + */ +public class GenerateRandomBitMask implements Computation { + + private final int numBits; + private DRes>> randomBits; + + public GenerateRandomBitMask(int numBits) { + this.numBits = numBits; + } + + public GenerateRandomBitMask(DRes>> randomBits) { + this.randomBits = randomBits; + this.numBits = this.randomBits.out().size(); + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + if (randomBits == null) { + randomBits = builder.par(par -> { + List> innerRandomBits = new ArrayList<>(numBits); + for (int i = 0; i < numBits; i++) { + innerRandomBits.add(par.numeric().randomBit()); + } + return () -> innerRandomBits; + }); + } + + List powersOfTwo = builder.getOIntArithmetic().getPowersOfTwo( + numBits); + DRes recombined = builder.advancedNumeric() + .innerProductWithPublicPart(() -> powersOfTwo, randomBits); + final RandomBitMask randomBitMask = new RandomBitMask(randomBits, recombined); + return () -> randomBitMask; + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/math/integer/binary/RandomBitMask.java b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/binary/RandomBitMask.java new file mode 100644 index 000000000..af94aae19 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/binary/RandomBitMask.java @@ -0,0 +1,28 @@ +package dk.alexandra.fresco.lib.math.integer.binary; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.List; + +/** + * Represents a random element and its bit decomposition. + */ +public class RandomBitMask { + + private final DRes>> bits; + private final DRes value; + + RandomBitMask(DRes>> bits, DRes value) { + this.bits = bits; + this.value = value; + } + + public DRes>> getBits() { + return bits; + } + + public DRes getValue() { + return value; + } + +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/math/integer/linalg/InnerProductWithOInt.java b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/linalg/InnerProductWithOInt.java new file mode 100644 index 000000000..78c60aab5 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/linalg/InnerProductWithOInt.java @@ -0,0 +1,44 @@ +package dk.alexandra.fresco.lib.math.integer.linalg; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.Numeric; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import java.util.ArrayList; +import java.util.List; + +/** + * Computes the inner product - i.e. Sum(a[0]*b[1], ..., a[n]*b[n]) by first computing + * all the multiplications in parallel, then summing up. + */ +public class InnerProductWithOInt implements Computation { + + private final DRes> vectorADef; + private final DRes>> vectorBDef; + + public InnerProductWithOInt( + DRes> vectorA, + DRes>> vectorB) { + this.vectorADef = vectorA; + this.vectorBDef = vectorB; + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + List vectorA = vectorADef.out(); + List> vectorB = vectorBDef.out(); + DRes>> product = builder.par(parallel -> { + List> result = new ArrayList<>(vectorA.size()); + Numeric numericBuilder = parallel.numeric(); + for (int i = 0; i < vectorA.size(); i++) { + DRes nextA = vectorA.get(i); + DRes nextB = vectorB.get(i); + result.add(numericBuilder.multByOpen(nextA, nextB)); + } + return () -> result; + }); + return builder.advancedNumeric().sum(product); + } +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/math/integer/min/ArgMin.java b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/min/ArgMin.java new file mode 100644 index 000000000..4a2007be9 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/min/ArgMin.java @@ -0,0 +1,111 @@ +package dk.alexandra.fresco.lib.math.integer.min; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.Comparison; +import dk.alexandra.fresco.framework.builder.numeric.Numeric; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.lib.conditional.ConditionalSelect; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Computes the index of the minimum element in a list and the element itself.

The index is + * expressed as a list of bits where all bits are 0 except for the bit at the index of the minimum + * element, which is set to 1.

+ */ +public class ArgMin implements + Computation>, SInt>, ProtocolBuilderNumeric> { + + private final List> xs; + private final int size; + + public ArgMin(List> xs) { + this.size = xs.size(); + if (this.size < 2) { + throw new IllegalArgumentException("Minimum protocol. Size should never be less than 2."); + } + this.xs = xs; + } + + + @Override + public DRes>, SInt>> buildComputation( + ProtocolBuilderNumeric builder) { + if (this.size == 2) { + Comparison comparison = builder.comparison(); + Numeric numeric = builder.numeric(); + DRes firstValue = this.xs.get(0); + DRes secondValue = this.xs.get(1); + DRes firstCompare = comparison.compareLT(firstValue, secondValue); + DRes minimum = builder + .seq(new ConditionalSelect(firstCompare, firstValue, secondValue)); + DRes secondCompare = numeric + .subFromOpen(builder.getOIntFactory().one(), firstCompare); + return () -> new Pair<>( + Arrays.asList(firstCompare, secondCompare), + minimum.out()); + } else if (this.size == 3) { + Comparison comparison = builder.comparison(); + Numeric numeric = builder.numeric(); + DRes firstValue = this.xs.get(0); + DRes secondValue = this.xs.get(1); + DRes thirdValue = this.xs.get(2); + DRes c1Prime = comparison.compareLT(firstValue, secondValue); + + DRes m1 = builder.seq(new ConditionalSelect(c1Prime, firstValue, secondValue)); + + DRes c2Prime = comparison.compareLT(m1, thirdValue); + + DRes m2 = builder.seq(new ConditionalSelect(c2Prime, m1, thirdValue)); + + DRes firstComparison = numeric.mult(c1Prime, c2Prime); + DRes secondComparison = numeric.sub(c2Prime, firstComparison); + DRes tmp = numeric.subFromOpen(builder.getOIntFactory().one(), firstComparison); + DRes thirdComparison = numeric.sub(tmp, secondComparison); + return () -> new Pair<>( + Arrays.asList(firstComparison, secondComparison, thirdComparison), + m2.out()); + } else { + return builder.seq((seq) -> { + int k1 = size / 2; + List> x1 = xs.subList(0, k1); + List> x2 = xs.subList(k1, size); + return Pair.lazy(x1, x2); + }).pairInPar( + (seq, pair) -> seq.seq(new ArgMin(pair.getFirst())), + (seq, pair) -> seq.seq(new ArgMin(pair.getSecond())) + ).seq((seq, pair) -> { + Comparison comparison = seq.comparison(); + Numeric numeric = seq.numeric(); + Pair>, SInt> minimum1 = pair.getFirst(); + Pair>, SInt> minimum2 = pair.getSecond(); + SInt m1 = minimum1.getSecond(); + SInt m2 = minimum2.getSecond(); + + DRes compare = comparison.compareLT(() -> m1, () -> m2); + DRes oneMinusCompare = numeric.subFromOpen(seq.getOIntFactory().one(), compare); + DRes m = seq.seq(new ConditionalSelect(compare, () -> m1, () -> m2)); + DRes>> enteringIndexes = seq.par((par) -> { + Numeric parNumeric = par.numeric(); + List> cs = new ArrayList<>(size); + for (DRes c : minimum1.getFirst()) { + cs.add(parNumeric.mult(c, compare)); + } + for (DRes c : minimum2.getFirst()) { + cs.add(parNumeric.mult(c, oneMinusCompare)); + } + return () -> cs; + }); + return () -> { + List> out = enteringIndexes.out(); + SInt out1 = m.out(); + return new Pair<>(out, out1); + }; + }); + } + } +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/math/integer/mod/Mod2m.java b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/mod/Mod2m.java new file mode 100644 index 000000000..05f4dce02 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/math/integer/mod/Mod2m.java @@ -0,0 +1,63 @@ +package dk.alexandra.fresco.lib.math.integer.mod; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.lib.math.integer.binary.RandomBitMask; +import java.util.List; + +/** + * Computes modular reduction of value mod 2^m. + */ +public class Mod2m implements Computation { + + private final DRes input; + private final int m; + private final int k; + private final int kappa; + + /** + * Constructs new {@link Mod2m}. + * + * @param input value to reduce + * @param m exponent (2^{m}) + * @param k bitlength of the input + * @param kappa Computational security parameter + */ + public Mod2m(DRes input, int m, int k, int kappa) { + this.input = input; + this.m = m; + this.k = k; + this.kappa = kappa; + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + if (m >= k) { + return input; + } + final DRes r = builder.advancedNumeric().randomBitMask(k + kappa); + return builder.seq(seq -> { + // Construct a new RandomBitMask consisting of the first m bits of r + final List> rBits = r.out().getBits().out().subList(0, m); + DRes rPrime = seq.advancedNumeric().randomBitMask(() -> rBits); + // Use the integer interpretation of r to compute c = 2^{k-1}+(input + r) + DRes c = seq.numeric().openAsOInt(seq.numeric().addOpen(seq + .getOIntArithmetic().twoTo(k - 1), seq.numeric().add(input, r.out().getValue()))); + Pair, DRes> pair = new Pair<>(rPrime, c); + return () -> pair; + }).seq((seq, pair) -> { + DRes rPrime = pair.getFirst(); + DRes c = pair.getSecond(); + DRes cPrime = seq.getOIntArithmetic().modTwoTo(c.out(), m); + DRes u = seq.comparison().compareLTBits(cPrime, rPrime.out().getBits()); + // Return cPrime - 2^m * u + return seq.numeric().add(seq.numeric().multByOpen(seq.getOIntArithmetic() + .twoTo(m), u), + seq.numeric().subFromOpen(cPrime, rPrime.out().getValue())); + }); + } +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/real/OReal.java b/core/src/main/java/dk/alexandra/fresco/lib/real/OReal.java new file mode 100644 index 000000000..9c903e484 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/real/OReal.java @@ -0,0 +1,13 @@ +package dk.alexandra.fresco.lib.real; + +import dk.alexandra.fresco.framework.DRes; + +/** + * Generic interface representing open (public) real values.

Arithmetic suites supporting + * arithmetic over reals must implement this interface. In some case this can just be a wrapper + * around a {@link java.math.BigDecimal}, however, other suites may choose to rely on more efficient + * implementations.

+ */ +public interface OReal extends DRes { + +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/real/RealNumeric.java b/core/src/main/java/dk/alexandra/fresco/lib/real/RealNumeric.java index 7ad8bff04..d49c841a3 100644 --- a/core/src/main/java/dk/alexandra/fresco/lib/real/RealNumeric.java +++ b/core/src/main/java/dk/alexandra/fresco/lib/real/RealNumeric.java @@ -4,6 +4,7 @@ import dk.alexandra.fresco.framework.builder.ComputationDirectory; import dk.alexandra.fresco.framework.value.SInt; import java.math.BigDecimal; +import java.math.BigInteger; /** * Basic interface for numeric applications on real numbers. @@ -100,9 +101,16 @@ public interface RealNumeric extends ComputationDirectory { */ DRes known(BigDecimal value); + /** + * Creates a known secret value from a public value (which has been scaled).

This is primarily + * a helper function in order to use public values within the FRESCO functions. Note that the + * value is interpreted as already scaled, which avoids various rounding artifacts.

+ */ + DRes fromScaled(BigInteger value); + /** * Create a secret real value from a secret integer value representing the same value. - * + * * @param value A secret integer. * @return A secret real with the same value as the input */ @@ -126,6 +134,14 @@ public interface RealNumeric extends ComputationDirectory { */ DRes open(DRes secretShare); + /** + * Opens a value to all MPC parties without converting to BigDecimal. + * + * @param secretShare The value to open. + * @return The opened value represented by the closed value (without conversion). + */ + DRes openRaw(DRes secretShare); + /** * Opens a value to a single given party. * diff --git a/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/DefaultFixedNumeric.java b/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/DefaultFixedNumeric.java new file mode 100644 index 000000000..2264d7e30 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/DefaultFixedNumeric.java @@ -0,0 +1,204 @@ +package dk.alexandra.fresco.lib.real.fixed; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.lib.real.RealNumeric; +import dk.alexandra.fresco.lib.real.SReal; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; + +/** + * An implementation of the {@link RealNumeric} ComputationDirectory based on a fixed point + * representation of real numbers. + */ +public class DefaultFixedNumeric implements RealNumeric { + + protected final ProtocolBuilderNumeric builder; + // TODO these should be cached static fields + private final int precision; + private final BigInteger scalingFactor; + private final BigDecimal scalingFactorDecimal; + + public DefaultFixedNumeric(ProtocolBuilderNumeric builder, int precision) { + this.builder = builder; + this.precision = precision; + this.scalingFactor = BigInteger.ONE.shiftLeft(precision); + this.scalingFactorDecimal = new BigDecimal(scalingFactor); + } + + public DefaultFixedNumeric(ProtocolBuilderNumeric builder) { + this(builder, builder.getRealNumericContext().getPrecision()); + } + + private BigInteger unscaled(BigDecimal value) { + return value.multiply(scalingFactorDecimal).setScale(0, RoundingMode.HALF_UP) + .toBigIntegerExact(); + } + + private BigDecimal scaled(BigInteger value) { + return new BigDecimal(value).setScale(precision).divide(scalingFactorDecimal, + RoundingMode.HALF_UP); + } + + @Override + public DRes add(DRes a, DRes b) { + return builder.seq(seq -> { + SFixed floatA = (SFixed) a.out(); + SFixed floatB = (SFixed) b.out(); + return new SFixed(seq.numeric().add(floatA.getSInt(), floatB.getSInt()), precision); + }); + } + + @Override + public DRes add(BigDecimal a, DRes b) { + return builder.seq(seq -> { + BigInteger unscaled = unscaled(a); + SFixed floatB = (SFixed) b.out(); + return new SFixed(seq.numeric().add(unscaled, floatB.getSInt()), precision); + }); + } + + @Override + public DRes sub(DRes a, DRes b) { + return builder.seq(seq -> { + SFixed floatA = (SFixed) a.out(); + SFixed floatB = (SFixed) b.out(); + return new SFixed(seq.numeric().sub(floatA.getSInt(), floatB.getSInt()), precision); + }); + } + + @Override + public DRes sub(BigDecimal a, DRes b) { + return builder.seq(seq -> { + BigInteger unscaled = unscaled(a); + SFixed floatB = (SFixed) b.out(); + return new SFixed(seq.numeric().sub(unscaled, floatB.getSInt()), precision); + }); + } + + @Override + public DRes sub(DRes a, BigDecimal b) { + return builder.seq(seq -> { + BigInteger unscaled = unscaled(b); + SFixed floatA = (SFixed) a.out(); + return new SFixed(seq.numeric().sub(floatA.getSInt(), unscaled), precision); + }); + } + + @Override + public DRes mult(DRes a, DRes b) { + return builder.seq(seq -> { + SFixed floatA = (SFixed) a.out(); + SFixed floatB = (SFixed) b.out(); + DRes unscaled = seq.numeric().mult(floatA.getSInt(), floatB.getSInt()); + DRes truncated = seq.advancedNumeric().truncate(unscaled, precision); + return new SFixed(truncated, precision); + }); + } + + @Override + public DRes mult(BigDecimal a, DRes b) { + return builder.seq(seq -> { + BigInteger unscaled = unscaled(a); + SFixed floatB = (SFixed) b.out(); + DRes overflowedProduct = seq.numeric().mult(unscaled, floatB.getSInt()); + DRes truncated = seq.advancedNumeric().truncate(overflowedProduct, precision); + return new SFixed(truncated, precision); + }); + } + + @Override + public DRes div(DRes a, DRes b) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public DRes div(DRes a, BigDecimal b) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public DRes known(BigDecimal value) { + return builder.seq(seq -> { + DRes input = seq.numeric().known(unscaled(value)); + return new SFixed(input, precision); + }); + } + + @Override + public DRes fromScaled(BigInteger value) { + return builder.seq(seq -> { + DRes input = seq.numeric().known(value); + return new SFixed(input, precision); + }); + } + + @Override + public DRes fromSInt(DRes value) { + return builder.seq(seq -> { + DRes scaled = seq.numeric().mult(scalingFactor, value); + return new SFixed(scaled, precision); + }); + } + + @Override + public DRes input(BigDecimal value, int inputParty) { + return builder.seq(seq -> { + BigInteger unscaled = (value != null) ? unscaled(value) : null; + DRes input = seq.numeric().input(unscaled, inputParty); + return new SFixed(input, precision); + }); + } + + @Override + public DRes open(DRes secretShare) { + return builder.seq(seq -> { + SFixed floatX = (SFixed) secretShare.out(); + DRes unscaled = floatX.getSInt(); + return seq.numeric().open(unscaled); + }).seq((seq, unscaled) -> { + // new scope to avoid scaling in lambda (since that would be recalculated every time value.out + // is called) + BigDecimal scaled = scaled(unscaled); + return () -> scaled; + }); + } + + @Override + public DRes openRaw(DRes secretShare) { + return builder.seq(seq -> { + SFixed floatX = (SFixed) secretShare.out(); + DRes unscaled = floatX.getSInt(); + return seq.numeric().open(unscaled); + }); + } + + @Override + public DRes open(DRes secretShare, int outputParty) { + return builder.seq(seq -> { + SFixed floatX = (SFixed) secretShare.out(); + DRes unscaled = floatX.getSInt(); + return seq.numeric().open(unscaled, outputParty); + }).seq((seq, unscaled) -> { + // new scope to avoid scaling in lambda (since that would be recalculated every time value.out + // is called) + if (unscaled != null) { + BigDecimal scaled = scaled(unscaled); + return () -> scaled; + } else { + return null; + } + }); + } + + @Override + public DRes leq(DRes x, DRes y) { + return builder.seq(seq -> { + SFixed floatX = (SFixed) x.out(); + SFixed floatY = (SFixed) y.out(); + return seq.comparison().compareLEQ(floatX.getSInt(), floatY.getSInt()); + }); + } +} diff --git a/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/FixedNumeric.java b/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/SemiFixedNumeric.java similarity index 95% rename from core/src/main/java/dk/alexandra/fresco/lib/real/fixed/FixedNumeric.java rename to core/src/main/java/dk/alexandra/fresco/lib/real/fixed/SemiFixedNumeric.java index eb96df02e..612c21a49 100644 --- a/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/FixedNumeric.java +++ b/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/SemiFixedNumeric.java @@ -13,9 +13,9 @@ /** * An implementation of the {@link RealNumeric} ComputationDirectory based on a fixed point - * representation of real numbers. + * representation of real numbers.

This class uses a semi-floating precision point.

*/ -public class FixedNumeric implements RealNumeric { +public class SemiFixedNumeric implements RealNumeric { private static final BigInteger BASE = BigInteger.valueOf(2); private final int defaultPrecision; @@ -30,7 +30,7 @@ public class FixedNumeric implements RealNumeric { * @param precision the precision used for the fixed point numbers. The precision must be in the * range 0 ... builder.getMaxBitLength / 4. */ - public FixedNumeric(ProtocolBuilderNumeric builder, int precision) { + public SemiFixedNumeric(ProtocolBuilderNumeric builder, int precision) { this.builder = builder; this.defaultPrecision = precision; /* @@ -45,7 +45,7 @@ public FixedNumeric(ProtocolBuilderNumeric builder, int precision) { } } - public FixedNumeric(ProtocolBuilderNumeric builder) { + public SemiFixedNumeric(ProtocolBuilderNumeric builder) { this(builder, builder.getRealNumericContext().getPrecision()); } @@ -219,6 +219,11 @@ public DRes known(BigDecimal value) { }); } + @Override + public DRes fromScaled(BigInteger value) { + return null; + } + @Override public DRes fromSInt(DRes value) { return builder.seq(seq -> new SFixed(value.out(), 0)); @@ -243,6 +248,11 @@ public DRes open(DRes x) { }); } + @Override + public DRes openRaw(DRes secretShare) { + return null; + } + @Override public DRes open(DRes x, int outputParty) { return builder.seq(seq -> { diff --git a/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/utils/Truncate.java b/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/utils/Truncate.java index 1aa731b9c..b07ceb904 100644 --- a/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/utils/Truncate.java +++ b/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/utils/Truncate.java @@ -15,7 +15,7 @@ * result will be one larger than the exact result with some non-negligible propability. If you need * the exact result you need to use {@link RightShift} instead, but this will be at a significant * performance cost. - * + * * The protocol is similar to protocol 3.1 in Catrina O., Saxena A. (2010) Secure Computation with * Fixed-Point Numbers. In: Sion R. (eds) Financial Cryptography and Data Security. FC 2010. Lecture * Notes in Computer Science, vol 6052. Springer, Berlin, Heidelberg. @@ -33,6 +33,8 @@ public Truncate(DRes input, int shifts) { @Override public DRes buildComputation(ProtocolBuilderNumeric sequential) { + // TODO double-check that this is secure. + // shouldn't we be generating maxBitLength + statistical security param number of bits? return sequential.seq((builder) -> { /* * Generate random additive mask of the same length as the input + some extra to avoid @@ -56,6 +58,7 @@ public DRes buildComputation(ProtocolBuilderNumeric sequential) { final DRes rBottom = seq.advancedNumeric().innerProductWithPublicPart( seq.getBigIntegerHelper().getTwoPowersList(shifts), mask.bits); + // TODO this should be cached BigInteger inverse = BigInteger.ONE.shiftLeft(shifts).modInverse(seq.getBasicNumericContext().getModulus()); DRes rTop = seq.numeric().sub(mask.random, rBottom); diff --git a/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/utils/TruncateFromPairs.java b/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/utils/TruncateFromPairs.java new file mode 100644 index 000000000..f90d70058 --- /dev/null +++ b/core/src/main/java/dk/alexandra/fresco/lib/real/fixed/utils/TruncateFromPairs.java @@ -0,0 +1,39 @@ +package dk.alexandra.fresco.lib.real.fixed.utils; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.TruncationPair; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; + +/** + * Probabilistic truncation protocol.

Described by Mohassel and Rindal in + * https://eprint.iacr.org/2018/403.pdf (Figure 3).

+ */ +public class TruncateFromPairs implements Computation { + + private final DRes input; + private final int shifts; + + public TruncateFromPairs(DRes input, int shifts) { + this.input = input; + this.shifts = shifts; + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + DRes truncationPairD = builder.advancedNumeric().generateTruncationPair(shifts); + return builder.seq(seq -> { + TruncationPair truncationPair = truncationPairD.out(); + // TODO look into making fixed-point arithmetic tests pass when we subtract here (to be + // consistent with original protocol) + DRes masked = seq.numeric().add(input, truncationPair.getRPrime()); + return seq.numeric().openAsOInt(masked); + }).seq((seq, opened) -> { + OInt shifted = seq.getOIntArithmetic().shiftRight(opened, shifts); + DRes r = truncationPairD.out().getR(); + return seq.numeric().subFromOpen(shifted, r); + }); + } +} diff --git a/core/src/main/java/dk/alexandra/fresco/logging/NumericSuiteLogging.java b/core/src/main/java/dk/alexandra/fresco/logging/NumericSuiteLogging.java index 8b2ac0d26..44f7b21a2 100644 --- a/core/src/main/java/dk/alexandra/fresco/logging/NumericSuiteLogging.java +++ b/core/src/main/java/dk/alexandra/fresco/logging/NumericSuiteLogging.java @@ -2,10 +2,13 @@ import dk.alexandra.fresco.framework.builder.numeric.BuilderFactoryNumeric; import dk.alexandra.fresco.framework.builder.numeric.Comparison; +import dk.alexandra.fresco.framework.builder.numeric.Conversion; import dk.alexandra.fresco.framework.builder.numeric.Numeric; import dk.alexandra.fresco.framework.builder.numeric.NumericResourcePool; import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.OIntArithmetic; +import dk.alexandra.fresco.framework.value.OIntFactory; import dk.alexandra.fresco.lib.compare.MiscBigIntegerGenerators; import dk.alexandra.fresco.lib.field.integer.BasicNumericContext; import dk.alexandra.fresco.lib.real.RealNumericContext; @@ -54,11 +57,26 @@ public Numeric createNumeric(ProtocolBuilderNumeric builder) { return numericLoggingDecorator; } + @Override + public Conversion createConversion(ProtocolBuilderNumeric builder) { + return delegateFactory.createConversion(builder); + } + @Override public MiscBigIntegerGenerators getBigIntegerHelper() { return delegateFactory.getBigIntegerHelper(); } + @Override + public OIntFactory getOIntFactory() { + return delegateFactory.getOIntFactory(); + } + + @Override + public OIntArithmetic getOIntArithmetic() { + return delegateFactory.getOIntArithmetic(); + } + @Override public Comparison createComparison(ProtocolBuilderNumeric builder) { ComparisonLoggerDecorator comparisonLoggerDecorator = diff --git a/core/src/main/java/dk/alexandra/fresco/logging/arithmetic/ComparisonLoggerDecorator.java b/core/src/main/java/dk/alexandra/fresco/logging/arithmetic/ComparisonLoggerDecorator.java index 1e41034d8..23d6a6f3c 100644 --- a/core/src/main/java/dk/alexandra/fresco/logging/arithmetic/ComparisonLoggerDecorator.java +++ b/core/src/main/java/dk/alexandra/fresco/logging/arithmetic/ComparisonLoggerDecorator.java @@ -2,9 +2,13 @@ import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.builder.numeric.Comparison; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.logging.PerformanceLogger; import java.util.HashMap; +import java.util.List; import java.util.Map; public class ComparisonLoggerDecorator implements Comparison, PerformanceLogger { @@ -17,22 +21,30 @@ public class ComparisonLoggerDecorator implements Comparison, PerformanceLogger private Comparison delegate; private long eqCount; private long leqCount; + private long ltCount; + private long ltBitsCount; private long signCount; private long comp0Count; - + public ComparisonLoggerDecorator(Comparison delegate) { super(); this.delegate = delegate; } @Override - public DRes equals(DRes x, DRes y) { + public DRes equals(DRes x, DRes y, int bitlength, Algorithm algorithm) { eqCount++; - return this.delegate.equals(x, y); + return this.delegate.equals(x, y, bitlength, algorithm); + } + + @Override + public DRes equals(DRes x, DRes y, int bitlength) { + eqCount++; + return this.delegate.equals(x, y, bitlength); } - + @Override - public DRes equals(int bitLength, DRes x, DRes y) { + public DRes equals(DRes x, DRes y) { eqCount++; return this.delegate.equals(x, y); } @@ -43,6 +55,23 @@ public DRes compareLEQ(DRes x1, DRes x2) { return this.delegate.compareLEQ(x1, x2); } + @Override + public DRes compareLT(DRes x1, DRes x2, Algorithm algorithm) { + ltCount++; + return this.delegate.compareLT(x1, x2, algorithm); + } + + @Override + public DRes compareLTBits(DRes openValue, DRes>> secretBits) { + ltBitsCount++; + return this.delegate.compareLTBits(openValue, secretBits); + } + + @Override + public DRes> carry(List bitPairs) { + throw new UnsupportedOperationException("Not implemented"); + } + @Override public DRes compareLEQLong(DRes x1, DRes x2) { leqCount++; @@ -56,21 +85,33 @@ public DRes sign(DRes x) { } @Override - public DRes compareZero(DRes x, int bitLength) { + public DRes compareZero(DRes x, int bitlength) { + return this.compareZero(x, bitlength, Algorithm.LOG_ROUNDS); + } + + @Override + public DRes compareZero(DRes x, int bitlength, Algorithm algorithm) { comp0Count++; - return this.delegate.compareZero(x, bitLength); + return this.delegate.compareZero(x, bitlength, algorithm); + } + + @Override + public DRes>, SInt>> argMin(List> xs) { + throw new UnsupportedOperationException("not implemented"); } @Override public void reset() { eqCount = 0; leqCount = 0; + ltCount = 0; signCount = 0; comp0Count = 0; } @Override public Map getLoggedValues() { + // TODO add ltCount Map values = new HashMap<>(); values.put(ARITHMETIC_COMPARISON_EQ, this.eqCount); values.put(ARITHMETIC_COMPARISON_LEQ, this.leqCount); diff --git a/core/src/main/java/dk/alexandra/fresco/logging/arithmetic/NumericLoggingDecorator.java b/core/src/main/java/dk/alexandra/fresco/logging/arithmetic/NumericLoggingDecorator.java index 8bc18af99..5b2cb393a 100644 --- a/core/src/main/java/dk/alexandra/fresco/logging/arithmetic/NumericLoggingDecorator.java +++ b/core/src/main/java/dk/alexandra/fresco/logging/arithmetic/NumericLoggingDecorator.java @@ -2,6 +2,7 @@ import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.builder.numeric.Numeric; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.logging.PerformanceLogger; import java.math.BigInteger; @@ -38,6 +39,11 @@ public DRes add(BigInteger a, DRes b) { return this.delegate.add(a, b); } + @Override + public DRes addOpen(DRes a, DRes b) { + return delegate.addOpen(a, b); + } + @Override public DRes sub(DRes a, DRes b) { subCount++; @@ -49,6 +55,16 @@ public DRes sub(BigInteger a, DRes b) { return this.delegate.sub(a, b); } + @Override + public DRes subFromOpen(DRes a, DRes b) { + return delegate.subFromOpen(a, b); + } + + @Override + public DRes subOpen(DRes a, DRes b) { + return delegate.subOpen(a, b); + } + @Override public DRes sub(DRes a, BigInteger b) { return this.delegate.sub(a, b); @@ -65,6 +81,11 @@ public DRes mult(BigInteger a, DRes b) { return this.delegate.mult(a, b); } + @Override + public DRes multByOpen(DRes a, DRes b) { + return delegate.multByOpen(a, b); + } + @Override public DRes randomBit() { this.bitCount++; @@ -92,6 +113,16 @@ public DRes open(DRes secretShare) { return this.delegate.open(secretShare); } + @Override + public DRes openAsOInt(DRes secretShare) { + return delegate.openAsOInt(secretShare); + } + + @Override + public DRes openAsOInt(DRes secretShare, int outputParty) { + return delegate.openAsOInt(secretShare, outputParty); + } + @Override public DRes open(DRes secretShare, int outputParty) { return this.delegate.open(secretShare, outputParty); diff --git a/core/src/main/java/dk/alexandra/fresco/suite/dummy/arithmetic/DummyArithmeticBuilderFactory.java b/core/src/main/java/dk/alexandra/fresco/suite/dummy/arithmetic/DummyArithmeticBuilderFactory.java index a465ba0ac..f639f0cb5 100644 --- a/core/src/main/java/dk/alexandra/fresco/suite/dummy/arithmetic/DummyArithmeticBuilderFactory.java +++ b/core/src/main/java/dk/alexandra/fresco/suite/dummy/arithmetic/DummyArithmeticBuilderFactory.java @@ -1,10 +1,18 @@ package dk.alexandra.fresco.suite.dummy.arithmetic; import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric; import dk.alexandra.fresco.framework.builder.numeric.BuilderFactoryNumeric; +import dk.alexandra.fresco.framework.builder.numeric.Conversion; +import dk.alexandra.fresco.framework.builder.numeric.DefaultAdvancedNumeric; import dk.alexandra.fresco.framework.builder.numeric.Numeric; import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.BigIntegerOIntArithmetic; +import dk.alexandra.fresco.framework.value.BigIntegerOIntFactory; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntArithmetic; +import dk.alexandra.fresco.framework.value.OIntFactory; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.lib.compare.MiscBigIntegerGenerators; import dk.alexandra.fresco.lib.field.integer.BasicNumericContext; @@ -22,12 +30,12 @@ public class DummyArithmeticBuilderFactory implements BuilderFactoryNumeric { private BasicNumericContext basicNumericContext; private RealNumericContext realNumericContext; private MiscBigIntegerGenerators mog; + private final OIntFactory oIntFactory; + private final OIntArithmetic oIntArithmetic; private Random rand; /** * Creates a dummy arithmetic builder factory which creates basic numeric operations - * - * @param factory The numeric context we work within. */ public DummyArithmeticBuilderFactory(BasicNumericContext basicNumericContext, RealNumericContext realNumericContext) { @@ -35,9 +43,10 @@ public DummyArithmeticBuilderFactory(BasicNumericContext basicNumericContext, this.basicNumericContext = basicNumericContext; this.realNumericContext = realNumericContext; this.rand = new Random(0); + this.oIntFactory = new BigIntegerOIntFactory(basicNumericContext.getMaxBitLength()); + this.oIntArithmetic = new BigIntegerOIntArithmetic(oIntFactory); } - @Override public BasicNumericContext getBasicNumericContext() { return basicNumericContext; @@ -47,7 +56,12 @@ public BasicNumericContext getBasicNumericContext() { public RealNumericContext getRealNumericContext() { return realNumericContext; } - + + @Override + public AdvancedNumeric createAdvancedNumeric(ProtocolBuilderNumeric builder) { + return new DummyAdvancedNumeric(this, builder, rand); + } + @Override public Numeric createNumeric(ProtocolBuilderNumeric builder) { return new Numeric() { @@ -66,6 +80,22 @@ public DRes sub(BigInteger a, DRes b) { return builder.append(c); } + @Override + public DRes subFromOpen(DRes a, DRes b) { + DummyArithmeticSubtractProtocol c = + new DummyArithmeticSubtractProtocol( + () -> new DummyArithmeticSInt(builder.getOIntFactory().toBigInteger(a.out())), b); + return builder.append(c); + } + + @Override + public DRes subOpen(DRes a, DRes b) { + DummyArithmeticNativeProtocol c = + new DummyArithmeticSubtractProtocol(a, + () -> new DummyArithmeticSInt(builder.getOIntFactory().toBigInteger(b.out()))); + return builder.append(c); + } + @Override public DRes sub(DRes a, DRes b) { DummyArithmeticSubtractProtocol c = new DummyArithmeticSubtractProtocol(a, b); @@ -124,6 +154,25 @@ public DRes open(DRes secretShare) { return builder.append(c); } + @Override + public DRes openAsOInt(DRes secretShare) { + DRes value = open(secretShare); + return () -> oIntFactory.fromBigInteger(value.out()); + } + + @Override + public DRes openAsOInt(DRes secretShare, int outputParty) { + DRes out = open(secretShare, outputParty); + return () -> { + BigInteger res = out.out(); + if (res == null) { + return null; + } else { + return oIntFactory.fromBigInteger(res); + } + }; + } + @Override public DRes open(DRes secretShare, int outputParty) { DummyArithmeticOpenProtocol c = new DummyArithmeticOpenProtocol(secretShare, outputParty); @@ -137,6 +186,14 @@ public DRes mult(BigInteger a, DRes b) { return builder.append(c); } + @Override + public DRes multByOpen(DRes a, DRes b) { + DummyArithmeticMultProtocol c = + new DummyArithmeticMultProtocol( + () -> new DummyArithmeticSInt(builder.getOIntFactory().toBigInteger(a.out())), b); + return builder.append(c); + } + @Override public DRes mult(DRes a, DRes b) { DummyArithmeticMultProtocol c = new DummyArithmeticMultProtocol(a, b); @@ -178,6 +235,14 @@ public DRes add(BigInteger a, DRes b) { return builder.append(c); } + @Override + public DRes addOpen(DRes a, DRes b) { + DummyArithmeticAddProtocol c = + new DummyArithmeticAddProtocol( + () -> new DummyArithmeticSInt(builder.getOIntFactory().toBigInteger(a.out())), b); + return builder.append(c); + } + @Override public DRes add(DRes a, DRes b) { DummyArithmeticAddProtocol c = new DummyArithmeticAddProtocol(a, b); @@ -186,6 +251,12 @@ public DRes add(DRes a, DRes b) { }; } + @Override + public Conversion createConversion(ProtocolBuilderNumeric builder) { + throw new UnsupportedOperationException( + "This protocol suite does not currently support conversion"); + } + @Override public MiscBigIntegerGenerators getBigIntegerHelper() { if (mog == null) { @@ -194,4 +265,41 @@ public MiscBigIntegerGenerators getBigIntegerHelper() { return mog; } + @Override + public OIntFactory getOIntFactory() { + return oIntFactory; + } + + @Override + public OIntArithmetic getOIntArithmetic() { + return oIntArithmetic; + } + + class DummyAdvancedNumeric extends DefaultAdvancedNumeric { + + private final Random rand; + + DummyAdvancedNumeric( + BuilderFactoryNumeric factoryNumeric, + ProtocolBuilderNumeric builder, + Random rand) { + super(factoryNumeric, builder); + this.rand = rand; + } + + @Override + public DRes generateTruncationPair(int d) { + return builder.seq(seq -> { + // TODO check if random value should be from bigger space + BigInteger rPrimeOpen = new BigInteger( + builder.getBasicNumericContext().getMaxBitLength(), + rand); + BigInteger rOpen = rPrimeOpen.shiftRight(d); + DRes rPrime = seq.numeric().input(rPrimeOpen, 1); + DRes r = seq.numeric().input(rOpen, 1); + return () -> new TruncationPair(rPrime, r); + }); + } + } + } diff --git a/core/src/test/java/dk/alexandra/fresco/framework/network/NetworkBatchDecoratorTest.java b/core/src/test/java/dk/alexandra/fresco/framework/network/NetworkBatchDecoratorTest.java index e80598aa8..58b441b1f 100644 --- a/core/src/test/java/dk/alexandra/fresco/framework/network/NetworkBatchDecoratorTest.java +++ b/core/src/test/java/dk/alexandra/fresco/framework/network/NetworkBatchDecoratorTest.java @@ -14,13 +14,13 @@ public class NetworkBatchDecoratorTest { private Map transmissions = new HashMap<>(); @Before - public void setUp() throws Exception { + public void setUp() { DummyNetwork network = new DummyNetwork(); networkBatchDecorator = new NetworkBatchDecorator(3, network); } @Test - public void receive() throws Exception { + public void receive() { transmissions.put(1, new byte[]{4, 2, 2, 23, 3, 3, 22, 0, 0}); transmissions.put(2, new byte[]{0}); Assert.assertArrayEquals(new byte[]{2, 2, 23, 3}, networkBatchDecorator.receive(1)); @@ -29,7 +29,7 @@ public void receive() throws Exception { } @Test - public void receiveFromAll() throws Exception { + public void receiveFromAll() { transmissions.put(1, new byte[]{4, 2, 2, 23, 3, 42}); transmissions.put(2, new byte[]{4, 2, 2, 23, 3, 42}); transmissions.put(3, new byte[]{4, 2, 2, 23, 3, 42}); @@ -40,14 +40,14 @@ public void receiveFromAll() throws Exception { } @Test(expected = NullPointerException.class) - public void receiveFromAllNoData() throws Exception { + public void receiveFromAllNoData() { transmissions.put(1, new byte[]{4, 2, 2, 23, 3, 42}); transmissions.put(2, new byte[]{4, 2, 2, 23, 3, 42}); networkBatchDecorator.receiveFromAll(); } @Test - public void send() throws Exception { + public void send() { networkBatchDecorator.send(1, new byte[]{123}); Assert.assertTrue(transmissions.isEmpty()); networkBatchDecorator.flush(); @@ -56,7 +56,7 @@ public void send() throws Exception { } @Test - public void sendToAll() throws Exception { + public void sendToAll() { networkBatchDecorator.sendToAll(new byte[]{123}); networkBatchDecorator.flush(); Assert.assertEquals(3, transmissions.size()); @@ -65,25 +65,47 @@ public void sendToAll() throws Exception { Assert.assertArrayEquals(new byte[]{1, 123}, transmissions.get(3)); } - @Test(expected = RuntimeException.class) - public void errorOnBigPackets() throws Exception { - networkBatchDecorator.sendToAll( - new byte[]{ - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - }); - + @Test + public void handleBigPackets() { + final byte[] payload = { + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123 + }; + networkBatchDecorator.sendToAll(payload); + byte[] expected = new byte[]{ + -128, 0, 0, -116, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123 + }; + networkBatchDecorator.flush(); + Assert.assertEquals(3, transmissions.size()); + Assert.assertArrayEquals(expected, transmissions.get(1)); + Assert.assertArrayEquals(expected, transmissions.get(2)); + Assert.assertArrayEquals(expected, transmissions.get(3)); } private class DummyNetwork implements Network { @@ -104,4 +126,4 @@ public int getNoOfParties() { return 3; } } -} \ No newline at end of file +} diff --git a/core/src/test/java/dk/alexandra/fresco/framework/util/TestArithmeticDummyDataSupplier.java b/core/src/test/java/dk/alexandra/fresco/framework/util/TestArithmeticDummyDataSupplier.java index 22102f8b9..08efddf3d 100644 --- a/core/src/test/java/dk/alexandra/fresco/framework/util/TestArithmeticDummyDataSupplier.java +++ b/core/src/test/java/dk/alexandra/fresco/framework/util/TestArithmeticDummyDataSupplier.java @@ -123,6 +123,24 @@ private void testGetExpPipe(int noOfParties) { } } + private void testGetTruncationPairShares(int noOfParties, BigInteger modulus) { + List suppliers = new ArrayList<>(noOfParties); + for (int i = 0; i < noOfParties; i++) { + suppliers.add(new ArithmeticDummyDataSupplier(i + 1, noOfParties, modulus)); + } + List actual = new ArrayList<>(); + for (ArithmeticDummyDataSupplier supplier : suppliers) { + actual.add(supplier.getTruncationPairShares(modulus.bitLength() / 2)); + } + assertTruncationPairValid(actual, modulus, modulus.bitLength() / 2); + } + + private void testGetTruncationPairShares(int noOfParties) { + for (BigInteger modulus : moduli) { + testGetTruncationPairShares(noOfParties, modulus); + } + } + @Test public void testGetRandomElementShareTwoParties() { testGetRandomElementShare(2); @@ -175,6 +193,13 @@ public void testGetExpPipes() { testGetExpPipe(5); } + @Test + public void testGetTruncationPairShares() { + testGetTruncationPairShares(2); + testGetTruncationPairShares(3); + testGetTruncationPairShares(5); + } + @Test public void testBitsNotAllSame() { int noOfParties = 2; @@ -280,4 +305,33 @@ private void assertMultiplicationTriplesValid(List t assertAllDifferent(productShares); } + private void assertTruncationPairValid(List pairs, + BigInteger modulus, int d) { + List pPrimeValues = new ArrayList<>(pairs.size()); + List rPrimeShares = new ArrayList<>(pairs.size()); + List rValues = new ArrayList<>(pairs.size()); + List rShares = new ArrayList<>(pairs.size()); + for (TruncationPairShares pair : pairs) { + Pair rPrime = pair.getRPrime(); + Pair r = pair.getR(); + pPrimeValues.add(rPrime.getFirst()); + rPrimeShares.add(rPrime.getSecond()); + rValues.add(r.getFirst()); + rShares.add(r.getSecond()); + } + // sizes are the same + assertEquals(rValues.size(), pPrimeValues.size()); + // r = r^{prime} >> d + for (int i = 0; i < pPrimeValues.size(); i++) { + assertEquals(rValues.get(i), pPrimeValues.get(i).shiftRight(d)); + } + // all left values the same; left = recombine([left]); all left shares different + pPrimeValues.add(MathUtils.sum(rPrimeShares, modulus)); + assertAllEqual(pPrimeValues); + assertAllDifferent(rPrimeShares); + rValues.add(MathUtils.sum(rShares, modulus)); + assertAllEqual(rValues); + assertAllDifferent(rShares); + } + } diff --git a/core/src/test/java/dk/alexandra/fresco/lib/compare/CompareTests.java b/core/src/test/java/dk/alexandra/fresco/lib/compare/CompareTests.java index 3fb9a399d..e0b7a7b73 100644 --- a/core/src/test/java/dk/alexandra/fresco/lib/compare/CompareTests.java +++ b/core/src/test/java/dk/alexandra/fresco/lib/compare/CompareTests.java @@ -10,7 +10,6 @@ import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; import dk.alexandra.fresco.framework.sce.resources.ResourcePool; import dk.alexandra.fresco.framework.util.ByteAndBitConverter; -import dk.alexandra.fresco.framework.util.Pair; import dk.alexandra.fresco.framework.value.SBool; import dk.alexandra.fresco.framework.value.SInt; import java.math.BigInteger; @@ -110,8 +109,40 @@ public void test() throws Exception { } } + public static class TestCompareEQSimple + extends TestThreadFactory { + + @Override + public TestThread next() { + return new TestThread() { + + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = builder -> { + Numeric input = builder.numeric(); + // Pair 1 + DRes x1 = input.known(BigInteger.valueOf(3)); + DRes y1 = input.known(BigInteger.valueOf(5)); + + Comparison comparison = builder.comparison(); + + DRes compResult1 = comparison.equals(x1, x1); + DRes compResult2 = comparison.equals(x1, y1); + Numeric open = builder.numeric(); + DRes res1 = open.open(compResult1); + DRes res2 = open.open(compResult2); + return () -> Arrays.asList(res1.out(), res2.out()); + }; + List output = runApplication(app); + Assert.assertEquals(BigInteger.ONE, output.get(0)); + Assert.assertEquals(BigInteger.ZERO, output.get(1)); + } + }; + } + } + /** - * Compares the two numbers 3 and 5 and checks that 3 == 3. Also checks that 3 != 5 + * Compares the two numbers x and y and checks that x == x. Also checks that x != y */ public static class TestCompareEQ extends TestThreadFactory { @@ -122,21 +153,94 @@ public TestThread next() { @Override public void test() throws Exception { - Application, ProtocolBuilderNumeric> app = builder -> { + Application, ProtocolBuilderNumeric> app = builder -> { Numeric input = builder.numeric(); - DRes x = input.known(BigInteger.valueOf(3)); - DRes y = input.known(BigInteger.valueOf(5)); + // Pair 1 + DRes x1 = input.known(BigInteger.valueOf(3)); + DRes y1 = input.known(BigInteger.valueOf(5)); + // Pair 2 + DRes x2 = input.known(BigInteger.valueOf(11833)); + DRes y2 = input.known(BigInteger.valueOf(-583)); + // Pair 3 + // Minimum legal case + DRes x3 = input.known(BigInteger.valueOf(2).pow(62).subtract( + BigInteger.ONE).negate()); + DRes y3 = input.known(BigInteger.valueOf(2).pow(62).subtract( + BigInteger.valueOf(2)).negate()); + Comparison comparison = builder.comparison(); - DRes compResult1 = comparison.equals(x, x); - DRes compResult2 = comparison.equals(x, y); + + DRes compResult1 = comparison.equals(x1, x1); + DRes compResult2 = comparison.equals(x1, y1); + DRes compResult3 = comparison.equals(x2, x2); + DRes compResult4 = comparison.equals(x2, y2); + DRes compResult5 = comparison.equals(x3, x3); + DRes compResult6 = comparison.equals(x3, y3); Numeric open = builder.numeric(); DRes res1 = open.open(compResult1); DRes res2 = open.open(compResult2); - return () -> new Pair<>(res1.out(), res2.out()); + DRes res3 = open.open(compResult3); + DRes res4 = open.open(compResult4); + DRes res5 = open.open(compResult5); + DRes res6 = open.open(compResult6); + return () -> Arrays.asList(res1.out(), res2.out(), res3.out(), res4 + .out(), res5.out(), res6.out()); }; - Pair output = runApplication(app); - Assert.assertEquals(BigInteger.ONE, output.getFirst()); - Assert.assertEquals(BigInteger.ZERO, output.getSecond()); + List output = runApplication(app); + Assert.assertEquals(BigInteger.ONE, output.get(0)); + Assert.assertEquals(BigInteger.ZERO, output.get(1)); + Assert.assertEquals(BigInteger.ONE, output.get(2)); + Assert.assertEquals(BigInteger.ZERO, output.get(3)); + Assert.assertEquals(BigInteger.ONE, output.get(4)); + Assert.assertEquals(BigInteger.ZERO, output.get(5)); + } + }; + } + } + + public static class TestCompareEQZero + extends TestThreadFactory { + + private int bitLength; + + public TestCompareEQZero(int bitLength) { + this.bitLength = bitLength; + } + + @Override + public TestThread next() { + return new TestThread() { + + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = builder -> { + Numeric input = builder.numeric(); + DRes w = input.known(BigInteger.valueOf(-1)); + DRes x = input.known(BigInteger.valueOf(0)); + // Max positive value + DRes y = input.known(BigInteger.valueOf(2).pow(bitLength - 1).subtract( + BigInteger.ONE)); + // Min negative value + DRes z = input.known(BigInteger.valueOf(2).pow(bitLength - 1).negate()); + Comparison comparison = builder.comparison(); + DRes compResult1 = comparison.compareZero(w, bitLength); + DRes compResult2 = comparison.compareZero(x, bitLength); + DRes compResult3 = comparison.compareZero(y, bitLength); + DRes compResult4 = comparison.compareZero(z, bitLength); + Numeric open = builder.numeric(); + DRes res1 = open.open(compResult1); + DRes res2 = open.open(compResult2); + DRes res3 = open.open(compResult3); + DRes res4 = open.open(compResult4); + return () -> Arrays.asList(res1.out(), res2.out(), res3.out(), res4 + .out()); + }; + List output = runApplication(app); + Assert.assertEquals(BigInteger.ZERO, output.get(0)); + Assert.assertEquals(BigInteger.ONE, output.get(1)); + Assert.assertEquals(BigInteger.ZERO, output.get(2)); + Assert.assertEquals(BigInteger.ZERO, output.get(3)); } }; } @@ -272,4 +376,84 @@ public void test() throws Exception { } } + public static class TestLessThanLogRounds + extends TestThreadFactory { + + private final List openLeft; + private final List openRight; + private final List expected; + + public TestLessThanLogRounds(int maxBitLength) { + BigInteger two = BigInteger.valueOf(2); + this.openLeft = Arrays.asList( + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ONE, + BigInteger.valueOf(-1), + BigInteger.valueOf(-111111), + BigInteger.valueOf(-111), + BigInteger.valueOf(-110), + BigInteger.ONE, + two.pow(maxBitLength - 1).subtract(BigInteger.ONE), + two.pow(maxBitLength - 1).subtract(two), + BigInteger.TEN, + two.pow(maxBitLength - 1).subtract(BigInteger.ONE), + two.pow(maxBitLength - 1).subtract(two) + ); + this.openRight = Arrays.asList( + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.valueOf(-1), + BigInteger.valueOf(-111112), + BigInteger.valueOf(-110), + BigInteger.valueOf(10), + BigInteger.valueOf(5), + two.pow(maxBitLength - 1).subtract(two), + two.pow(maxBitLength - 1).subtract(BigInteger.ONE), + BigInteger.valueOf(-1), + BigInteger.ONE, + BigInteger.valueOf(-1) + ); + this.expected = computeExpected(openLeft, openRight); + } + + private static List computeExpected(List openLeft, + List openRight) { + if (openLeft.size() != openRight.size()) { + throw new IllegalStateException("Incorrect test spec!"); + } + List expected = new ArrayList<>(openLeft.size()); + for (int i = 0; i < openLeft.size(); i++) { + boolean lessThan = openLeft.get(i).compareTo(openRight.get(i)) < 0; + expected.add(lessThan ? BigInteger.ONE : BigInteger.ZERO); + } + return expected; + } + + @Override + public TestThread next() { + return new TestThread() { + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = builder -> { + Numeric numeric = builder.numeric(); + List> left = numeric.known(openLeft); + List> right = numeric.known(openRight); + List> actualInner = new ArrayList<>(left.size()); + for (int i = 0; i < left.size(); i++) { + actualInner.add(builder.comparison().compareLT(left.get(i), right.get(i), + Comparison.Algorithm.LOG_ROUNDS)); + } + DRes>> opened = builder.collections().openList(() -> actualInner); + return () -> opened.out().stream().map(DRes::out).collect(Collectors.toList()); + }; + List actual = runApplication(app); + Assert.assertEquals(expected, actual); + } + }; + } + } + } diff --git a/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/BitLessThanOpenTests.java b/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/BitLessThanOpenTests.java new file mode 100644 index 000000000..bda82dca7 --- /dev/null +++ b/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/BitLessThanOpenTests.java @@ -0,0 +1,102 @@ +package dk.alexandra.fresco.lib.compare.lt; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.NumericResourcePool; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.MathUtils; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; +import org.junit.Assert; + +public class BitLessThanOpenTests { + + public static class TestBitLessThanOpen + extends TestThreadFactory { + + private List left; + private List right; + + @Override + public TestThread next() { + + return new TestThread() { + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + int numBits = 32; + setupInputs(conf.getResourcePool().getModulus(), numBits); + List> results = new ArrayList<>(left.size()); + for (int i = 0; i < left.size(); i++) { + int finalI = i; + DRes leftValue = () -> root.getOIntFactory() + .fromBigInteger(left.get(finalI)); + DRes>> rightValue = toSecretBits(root, right.get(finalI), + numBits); + results.add( + root.numeric().open(root.seq(new BitLessThanOpen(leftValue, rightValue))) + ); + } + return () -> results.stream().map(DRes::out).collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = new ArrayList<>(left.size()); + for (int i = 0; i < left.size(); i++) { + boolean leq = left.get(i).compareTo(right.get(i)) < 0; + expected.add(leq ? BigInteger.ONE : BigInteger.ZERO); + } + Assert.assertEquals(expected, actual); + } + }; + } + + private void setupInputs(BigInteger modulus, int numBits) { + Random random = new Random(42); + this.left = Arrays.asList( + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.valueOf(5), + BigInteger.valueOf(111), + BigInteger.valueOf(111), + modulus.subtract(BigInteger.ONE), + modulus.subtract(BigInteger.ONE), + BigInteger.valueOf(2055014152), + new BigInteger(numBits, random).mod(modulus) + ); + this.right = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.valueOf(4), + BigInteger.valueOf(111), + BigInteger.valueOf(112), + modulus.subtract(BigInteger.ONE), + modulus.subtract(BigInteger.valueOf(2)), + BigInteger.valueOf(2055014153), + new BigInteger(numBits, random).mod(modulus) + ); + } + + } + + private static DRes>> toSecretBits(ProtocolBuilderNumeric root, + BigInteger value, + int numBits) { + List openList = MathUtils.toBits(value, numBits); + Collections.reverse(openList); + return root.collections().closeList(openList, 1); + } + +} diff --git a/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/CarryOutTests.java b/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/CarryOutTests.java new file mode 100644 index 000000000..f6b012fe1 --- /dev/null +++ b/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/CarryOutTests.java @@ -0,0 +1,73 @@ +package dk.alexandra.fresco.lib.compare.lt; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.value.OIntFactory; +import dk.alexandra.fresco.framework.value.SInt; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.junit.Assert; + +public class CarryOutTests { + + public static class TestCarryOut + extends TestThreadFactory { + + private final List left; + private final List right; + private final BigInteger expected; + + public TestCarryOut(int l, int r) { + expected = carry(l, r); + left = intToBits(l); + right = new ArrayList<>(left.size()); + right.addAll(intToBits(r)); + } + + @Override + public TestThread next() { + + return new TestThread() { + + @Override + public void test() { + Application app = + root -> { + List> leftClosed = root.numeric().known(right); + OIntFactory oIntFactory = root.getOIntFactory(); + DRes carry = root + .seq(new CarryOut(() -> oIntFactory.fromBigInteger(right), () -> leftClosed, + oIntFactory.zero())); + return root.numeric().open(carry); + }; + BigInteger actual = runApplication(app); + Assert.assertEquals(expected, actual); + } + }; + } + } + + private static BigInteger carry(int a, int b) { + long res = Integer.toUnsignedLong(a) + Integer.toUnsignedLong(b); + int carry = (int) ((res & (1L << 32)) >> 32); + return BigInteger.valueOf(carry); + } + + private static List intToBits(int value) { + int numBits = Integer.SIZE; + List bits = new ArrayList<>(numBits); + for (int i = 0; i < numBits; i++) { + int bit = (value & (1 << i)) >>> i; + bits.add(BigInteger.valueOf(bit)); + } + Collections.reverse(bits); + return bits; + } + +} diff --git a/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/LessThanZeroTests.java b/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/LessThanZeroTests.java new file mode 100644 index 000000000..03aad6d13 --- /dev/null +++ b/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/LessThanZeroTests.java @@ -0,0 +1,70 @@ +package dk.alexandra.fresco.lib.compare.lt; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.Numeric; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.value.SInt; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.Assert; + +public class LessThanZeroTests { + + public static class TestLessThanZero + extends TestThreadFactory { + + private final List openInputs; + private final List expected; + + public TestLessThanZero(BigInteger modulus) { + this.openInputs = Arrays.asList( + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.valueOf(-1), + BigInteger.valueOf(-111111), + BigInteger.valueOf(-123123), + modulus + ); + this.expected = computeExpected(openInputs); + } + + private static List computeExpected(List inputs) { + List expected = new ArrayList<>(inputs.size()); + for (BigInteger input : inputs) { + boolean lessThanZero = input.compareTo(BigInteger.ZERO) < 0; + expected.add(lessThanZero ? BigInteger.ONE : BigInteger.ZERO); + } + return expected; + } + + @Override + public TestThread next() { + return new TestThread() { + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = builder -> { + Numeric numeric = builder.numeric(); + List> inputs = numeric.known(openInputs); + List> actualInner = new ArrayList<>(inputs.size()); + for (DRes input : inputs) { + actualInner.add(builder.seq(new LessThanZero(input))); + } + DRes>> opened = builder.collections().openList(() -> actualInner); + return () -> opened.out().stream().map(DRes::out).collect(Collectors.toList()); + }; + List actual = runApplication(app); + Assert.assertEquals(expected, actual); + } + }; + } + } + +} diff --git a/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/PreCarryTests.java b/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/PreCarryTests.java new file mode 100644 index 000000000..242819eba --- /dev/null +++ b/core/src/test/java/dk/alexandra/fresco/lib/compare/lt/PreCarryTests.java @@ -0,0 +1,47 @@ +package dk.alexandra.fresco.lib.compare.lt; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.Numeric; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.framework.value.SInt; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import org.junit.Assert; + +public class PreCarryTests { + + public static class TestPreCarryBits + extends TestThreadFactory { + + @Override + public TestThread next() { + return new TestThread() { + + @Override + public void test() { + Application app = builder -> { + Numeric numeric = builder.numeric(); + DRes p1 = numeric.known(BigInteger.ONE); + DRes g1 = numeric.known(BigInteger.ZERO); + DRes p2 = numeric.known(BigInteger.ONE); + DRes g2 = numeric.known(BigInteger.ONE); + SIntPair pairOne = new SIntPair(p1, g1); + SIntPair pairTwo = new SIntPair(p2, g2); + List pairs = Arrays.asList(pairOne, pairTwo); + DRes carried = builder.seq(new PreCarryBits(pairs)); + return builder.numeric().open(carried); + }; + BigInteger actual = runApplication(app); + Assert.assertEquals(BigInteger.ONE, actual); + } + }; + } + } + +} diff --git a/core/src/test/java/dk/alexandra/fresco/lib/math/integer/binary/BinaryOperationsTests.java b/core/src/test/java/dk/alexandra/fresco/lib/math/integer/binary/BinaryOperationsTests.java index 2fc9e1e80..f8bdb317e 100644 --- a/core/src/test/java/dk/alexandra/fresco/lib/math/integer/binary/BinaryOperationsTests.java +++ b/core/src/test/java/dk/alexandra/fresco/lib/math/integer/binary/BinaryOperationsTests.java @@ -6,8 +6,10 @@ import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric; import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.RightShiftResult; +import dk.alexandra.fresco.framework.builder.numeric.NumericResourcePool; import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.util.Pair; import dk.alexandra.fresco.framework.value.SInt; import java.math.BigInteger; import java.util.Arrays; @@ -17,11 +19,8 @@ /** - * Generic test cases for basic finite field operations. - *

- * Can be reused by a test case for any protocol suite that implements the basic field protocol - * factory. - *

+ * Generic test cases for basic finite field operations.

Can be reused by a test case for any + * protocol suite that implements the basic field protocol factory.

*/ public class BinaryOperationsTests { @@ -39,7 +38,7 @@ public TestThread next() { private final int shifts = 3; @Override - public void test() throws Exception { + public void test() { Application, ProtocolBuilderNumeric> app = (ProtocolBuilderNumeric builder) -> { AdvancedNumeric rightShift = builder.advancedNumeric(); @@ -52,7 +51,7 @@ public void test() throws Exception { builder.numeric().open(() -> shiftedRight.out().getRemainder()); return () -> Arrays.asList(openResult.out(), openRemainder.out()); }; - List output = runApplication(app); + List output = runApplication(app); Assert.assertEquals(input.shiftRight(shifts), output.get(0)); Assert.assertEquals(input.mod(BigInteger.ONE.shiftLeft(shifts)), output.get(1)); @@ -75,7 +74,7 @@ public TestThread next() { private final BigInteger input = BigInteger.valueOf(5); @Override - public void test() throws Exception { + public void test() { Application app = builder -> { DRes sharedInput = builder.numeric().known(input); AdvancedNumeric bitLengthBuilder = builder.advancedNumeric(); @@ -104,7 +103,7 @@ public TestThread next() { private final int max = 16; @Override - public void test() throws Exception { + public void test() { Application, ProtocolBuilderNumeric> app = producer -> producer.seq(builder -> { DRes sharedInput = builder.numeric().known(input); @@ -123,4 +122,50 @@ public void test() throws Exception { }; } } + + public static class TestGenerateRandomBitMask + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + + private int numBits = -1; + private BigInteger modulus; + + private BigInteger recombine(List bits) { + BigInteger result = BigInteger.ZERO; + for (int i = 0; i < bits.size(); i++) { + result = result.add(BigInteger.ONE.shiftLeft(i).multiply(bits.get(i)).mod(modulus)); + } + return result.mod(modulus); + } + + @Override + public void test() { + Application, List>>, ProtocolBuilderNumeric> app = + root -> { + numBits = root.getBasicNumericContext().getMaxBitLength() - 1; + modulus = root.getBasicNumericContext().getModulus(); + return root.seq(seq -> seq.advancedNumeric().randomBitMask(numBits)) + .seq((seq, mask) -> { + DRes rec = seq.numeric().open(mask.getValue()); + DRes>> bits = seq.collections() + .openList(mask.getBits()); + return () -> new Pair<>(rec, bits.out()); + }); + }; + Pair, List>> actual = runApplication(app); + BigInteger recombined = actual.getFirst().out(); + List bits = actual.getSecond().stream() + .map(DRes::out) + .collect(Collectors.toList()); + Assert.assertEquals(numBits, bits.size()); + Assert.assertEquals(recombine(bits), recombined); + } + }; + } + } + } diff --git a/core/src/test/java/dk/alexandra/fresco/lib/math/integer/logical/LogicalOperationsTests.java b/core/src/test/java/dk/alexandra/fresco/lib/math/integer/logical/LogicalOperationsTests.java new file mode 100644 index 000000000..167ac6c8e --- /dev/null +++ b/core/src/test/java/dk/alexandra/fresco/lib/math/integer/logical/LogicalOperationsTests.java @@ -0,0 +1,290 @@ +package dk.alexandra.fresco.lib.math.integer.logical; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.Assert; + +public class LogicalOperationsTests { + + public static class TestXorKnown + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO); + private final List right = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO); + + @Override + public void test() { + Application>, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.numeric().knownAsDRes(left); + List rightOInts = root.getOIntFactory().fromBigInteger(right); + DRes>> xored = root.logical() + .pairWiseXorKnown(() -> rightOInts, leftClosed); + return root.collections().openList(xored); + }; + List actual = runApplication(app).stream().map(DRes::out) + .collect(Collectors.toList()); + List expected = Arrays.asList( + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestAndKnown + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO); + private final List right = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO); + + @Override + public void test() { + Application>, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.numeric().knownAsDRes(left); + List rightOInts = root.getOIntFactory().fromBigInteger(right); + DRes>> anded = root.logical() + .pairWiseAndKnown(() -> rightOInts, leftClosed); + return root.collections().openList(anded); + }; + List actual = runApplication(app).stream().map(DRes::out) + .collect(Collectors.toList()); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestAnd + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO); + private final List right = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO); + + @Override + public void test() { + Application>, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.numeric().knownAsDRes(left); + DRes>> rightClosed = root.numeric().knownAsDRes(right); + DRes>> anded = root.logical() + .pairWiseAnd(leftClosed, rightClosed); + return root.collections().openList(anded); + }; + List actual = runApplication(app).stream().map(DRes::out) + .collect(Collectors.toList()); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestOr + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO); + private final List right = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO); + + @Override + public void test() { + Application>, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.numeric().knownAsDRes(left); + DRes>> rightClosed = root.numeric().knownAsDRes(right); + DRes>> anded = root.logical().pairWiseOr(leftClosed, rightClosed); + return root.collections().openList(anded); + }; + List actual = runApplication(app).stream().map(DRes::out) + .collect(Collectors.toList()); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestOrNeighbors + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List list = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO); + + @Override + public void test() { + Application>, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.numeric().knownAsDRes(list); + return root.seq(seq -> { + DRes>> orred = seq.logical().orNeighbors(leftClosed.out()); + return seq.collections().openList(orred); + }); + }; + List actual = runApplication(app).stream().map(DRes::out) + .collect(Collectors.toList()); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestOrList extends + TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List input1 = Arrays.asList(BigInteger.ZERO, + BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, BigInteger.ONE); + private final List input2 = Arrays.asList(BigInteger.ZERO, + BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO); + private final List input3 = Arrays.asList(BigInteger.ZERO, + BigInteger.ZERO, BigInteger.ONE, BigInteger.ZERO, BigInteger.ZERO); + private final List input4 = Arrays.asList(BigInteger.ZERO, + BigInteger.ZERO, BigInteger.ONE, BigInteger.ZERO, BigInteger.ONE); + + @Override + public void test() { + List> inputLists = Arrays.asList(input1, input2, + input3, input4); + List expectedOutput = Arrays.asList(BigInteger.ONE, + BigInteger.ZERO, BigInteger.ONE, BigInteger.ONE); + + Application, ProtocolBuilderNumeric> app = root -> { + List> results = inputLists.stream().map( + current -> root.numeric().open(root.logical().orOfList(root.numeric().knownAsDRes( + current)))).collect(Collectors.toList()); + return () -> results.stream().map(DRes::out).collect(Collectors + .toList()); + }; + List actual = runApplication(app); + Assert.assertArrayEquals(expectedOutput.toArray(), actual.toArray()); + } + }; + } + } + + public static class TestNot + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + + @Override + public void test() { + Application>, ProtocolBuilderNumeric> app = + root -> { + DRes>> bits = root.numeric().knownAsDRes( + Arrays.asList(BigInteger.ONE, BigInteger.ZERO) + ); + DRes>> notted = root.logical().batchedNot(bits); + return root.collections().openList(notted); + }; + List actual = runApplication(app).stream().map(DRes::out) + .collect(Collectors.toList()); + List expected = Arrays.asList( + BigInteger.ZERO, + BigInteger.ONE + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + +} diff --git a/core/src/test/java/dk/alexandra/fresco/lib/math/integer/mod/Mod2mTests.java b/core/src/test/java/dk/alexandra/fresco/lib/math/integer/mod/Mod2mTests.java new file mode 100644 index 000000000..81ee37333 --- /dev/null +++ b/core/src/test/java/dk/alexandra/fresco/lib/math/integer/mod/Mod2mTests.java @@ -0,0 +1,83 @@ +package dk.alexandra.fresco.lib.math.integer.mod; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.SInt; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.Assert; + +public class Mod2mTests { + + public static class TestMod2mBaseCase + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + + private Pair, List> getExpecteds(int m, int k) { + BigInteger two = new BigInteger("2"); + List inputs = new ArrayList<>(); + inputs.add(BigInteger.ONE); + inputs.add(two.pow(m + 3)); + inputs.add(two.pow(k - 2).add(new BigInteger("3"))); + inputs.add(new BigInteger("3573894")); + inputs.add(new BigInteger("-1")); + inputs.add(two.pow(m).subtract(BigInteger.ONE).multiply( + new BigInteger("-1"))); + inputs.add(two.pow(m + 4).multiply(new BigInteger("-1"))); + inputs.add(two.pow(m + 5).add(new BigInteger("23493892").multiply( + new BigInteger("-1")))); + + List outputs = new ArrayList<>(); + outputs.add(BigInteger.ONE); + outputs.add(BigInteger.ZERO); + outputs.add(new BigInteger("3")); + outputs.add(new BigInteger("3573894")); + outputs.add(two.pow(m).add(new BigInteger("-1"))); + outputs.add(BigInteger.ONE); + outputs.add(BigInteger.ZERO); + outputs.add(two.pow(m).subtract(new BigInteger("23493892"))); + return new Pair, List>( + inputs, outputs); + } + + private void runTest(int m, int k, int kappa) { + Pair, List> expecteds = getExpecteds( + m, k); + Application, ProtocolBuilderNumeric> app = builder -> { + // Make input list into list of differed, known, shared integers + List> inputs = expecteds.getFirst().stream().map( + input -> builder.numeric().known( + input)).collect(Collectors.toList()); + // Apply mod2m to each of the inputs, open the result + List> results = inputs.stream().map( + input -> builder.numeric().open(builder.seq( + new Mod2m(input, m, k, kappa)))).collect(Collectors.toList()); + return () -> results.stream().map(DRes::out).collect(Collectors + .toList()); + }; + List actuals = runApplication(app); + Assert.assertArrayEquals(expecteds.getSecond().toArray(), actuals + .toArray()); + } + + @Override + public void test() { + runTest(32, 64, 40); + runTest(64, 128, 80); + } + }; + } + } + +} diff --git a/core/src/test/java/dk/alexandra/fresco/lib/real/BasicFixedPointTests.java b/core/src/test/java/dk/alexandra/fresco/lib/real/BasicFixedPointTests.java index 800e87c37..2e7ea1df7 100644 --- a/core/src/test/java/dk/alexandra/fresco/lib/real/BasicFixedPointTests.java +++ b/core/src/test/java/dk/alexandra/fresco/lib/real/BasicFixedPointTests.java @@ -21,10 +21,8 @@ import org.junit.Assert; /** - * Basic tests of computation with fixed point numbers. - *

- * NOTE: these tests all assume a precision of {@link BasicFixedPointTests.DEFAULT_PRECISION}. - *

+ * Basic tests of computation with fixed point numbers.

NOTE: these tests all assume a precision + * of {@code DEFAULT_PRECISION}.

*/ public class BasicFixedPointTests { @@ -32,6 +30,8 @@ public class BasicFixedPointTests { * The precision assumed in all tests. */ public static final int DEFAULT_PRECISION = 16; + public static final BigDecimal SCALING_FACTOR = new BigDecimal( + BigInteger.ONE.shiftLeft(DEFAULT_PRECISION)); public static class TestInput extends TestThreadFactory { @@ -83,7 +83,7 @@ public void test() throws Exception { List output = runApplication(app); RealTestUtils.assertEqual( value.stream().map(BigDecimal::new).collect(Collectors.toList()), output, - DEFAULT_PRECISION + 1); + DEFAULT_PRECISION); } }; } @@ -261,9 +261,9 @@ public void test() throws Exception { openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); List> opened = Stream.concat( IntStream.range(0, closed.size()) - .mapToObj(i -> producer.realNumeric().sub(closed.get(i), openInputs2.get(i))), + .mapToObj(i -> producer.realNumeric().sub(closed.get(i), openInputs2.get(i))), IntStream.range(0, closed.size()) - .mapToObj(i -> producer.realNumeric().sub(openInputs2.get(i), closed.get(i)))) + .mapToObj(i -> producer.realNumeric().sub(openInputs2.get(i), closed.get(i)))) .map(producer.realNumeric()::open) .collect(Collectors.toList()); return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); @@ -285,7 +285,7 @@ public void test() throws Exception { BigDecimal b = openInputs2.get(idx - openInputs.size()); RealTestUtils.assertEqual(b.subtract(a), output.get(idx), DEFAULT_PRECISION); }); - } + } }; } } @@ -296,10 +296,10 @@ public static class TestMultKnown @Override public TestThread next() { List openInputs = - Stream.of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.0007, 0.1298, 9.99) + Stream.of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.1298, 9.99, 64.0) .map(BigDecimal::valueOf).collect(Collectors.toList()); List openInputs2 = - Stream.of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 0.0005, 10.0012, 999.0101) + Stream.of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 10.0012, 999.0101, 1 / 64.0) .map(BigDecimal::valueOf).collect(Collectors.toList()); return new TestThread() { @Override @@ -325,9 +325,10 @@ public void test() throws Exception { BigDecimal a = openInputs.get(idx); BigDecimal b = openInputs2.get(idx); // There should be no truncation after just one multiplication + int precisionLoss = Math + .max(0, Math.max(RealTestUtils.floorLog2(a), RealTestUtils.floorLog2(b))); RealTestUtils.assertEqual(a.multiply(b), openOutput, - DEFAULT_PRECISION - - Math.max(RealTestUtils.floorLog2(a), RealTestUtils.floorLog2(b))); + DEFAULT_PRECISION - 1 - precisionLoss); } } }; @@ -431,12 +432,12 @@ public static class TestMult @Override public TestThread next() { List openInputs = Stream - .of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.0007, 0.1298, - 1.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.1298, 64.0, + 5.0 * Math.pow(2.0, -DEFAULT_PRECISION)) .map(BigDecimal::valueOf).collect(Collectors.toList()); List openInputs2 = Stream - .of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 0.0005, 10.0012, - 3.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 10.0012, 1 / 64.0, + 3.0 * Math.pow(2.0, -DEFAULT_PRECISION)) .map(BigDecimal::valueOf).collect(Collectors.toList()); return new TestThread() { @Override @@ -460,12 +461,63 @@ public void test() throws Exception { for (BigDecimal openOutput : output) { int idx = output.indexOf(openOutput); - BigDecimal a = openInputs.get(idx); BigDecimal b = openInputs2.get(idx); - + int precisionLoss = Math.max( + Math.max(RealTestUtils.floorLog2(a), RealTestUtils.floorLog2(b)), + 0 + ); RealTestUtils.assertEqual(a.multiply(b), openOutput, - DEFAULT_PRECISION - 1 - Math.max(RealTestUtils.floorLog2(a), RealTestUtils.floorLog2(b))); + DEFAULT_PRECISION - 1 - precisionLoss); + } + } + }; + } + } + + public static class TestMultIsolated + extends TestThreadFactory { + + private BigInteger modulus; + + @Override + public TestThread next() { + List openInputs = Stream + .of(0x0001L, 0x8000L, 0x0800L, 0x8800L, 0x88008800L) + .map(BigInteger::valueOf).collect(Collectors.toList()); + List openInputs2 = Stream + .of(0x0001L, 0x8000L, 0x8000L, 0x8000L, 0x8800L) + .map(BigInteger::valueOf).collect(Collectors.toList()); + return new TestThread() { + + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + modulus = producer.getBasicNumericContext().getModulus(); + List> closed1 = + openInputs.stream().map(producer.realNumeric()::fromScaled) + .collect(Collectors.toList()); + List> closed2 = openInputs2.stream().map(producer.realNumeric()::fromScaled) + .collect(Collectors.toList()); + + List> result = new ArrayList<>(); + for (DRes inputX : closed1) { + result.add(producer.realNumeric().mult(inputX, closed2.get(closed1.indexOf(inputX)))); + } + + List> opened = + result.stream().map(producer.realNumeric()::openRaw).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + + for (BigInteger openOutput : output) { + int idx = output.indexOf(openOutput); + BigInteger a = openInputs.get(idx); + BigInteger b = openInputs2.get(idx); + Assert.assertEquals( + a.multiply(b).mod(modulus).shiftRight(DEFAULT_PRECISION), + openOutput); } } }; diff --git a/core/src/test/java/dk/alexandra/fresco/lib/real/BasicSemiFloatingPointTests.java b/core/src/test/java/dk/alexandra/fresco/lib/real/BasicSemiFloatingPointTests.java new file mode 100644 index 000000000..33f2714f0 --- /dev/null +++ b/core/src/test/java/dk/alexandra/fresco/lib/real/BasicSemiFloatingPointTests.java @@ -0,0 +1,657 @@ +package dk.alexandra.fresco.lib.real; + +import static org.junit.Assert.assertEquals; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.value.SInt; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.junit.Assert; + +/** + * Basic tests of computation with fixed point numbers. + *

+ * NOTE: these tests all assume a precision of {@code DEFAULT_PRECISION}. + *

+ */ +public class BasicSemiFloatingPointTests { + + /** + * The precision assumed in all tests. + */ + public static final int DEFAULT_PRECISION = 16; + + public static class TestInput + extends TestThreadFactory { + + @Override + public TestThread next() { + List value = Arrays.asList(10.000001, 5.9, 11.0, 0.0001, + 100000.0001, 1.5 * Math.pow(2.0, -DEFAULT_PRECISION + 2)) + .stream().map(BigDecimal::valueOf).collect(Collectors.toList()); + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> inputs = value.stream().map(x -> producer.realNumeric().input(x, 1)) + .collect(Collectors.toList()); + List> opened = + inputs.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + RealTestUtils.assertEqual(value, output, DEFAULT_PRECISION); + } + }; + } + } + + public static class TestUseSInt + extends TestThreadFactory { + + @Override + public TestThread next() { + + List value = Arrays.asList(BigInteger.ONE, BigInteger.ONE.negate(), + BigInteger.ONE.shiftLeft(200).negate()); + + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> sints = + value.stream().map(producer.numeric()::known).collect(Collectors.toList()); + List> inputs = + sints.stream().map(producer.realNumeric()::fromSInt).collect(Collectors.toList()); + List> opened = + inputs.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + RealTestUtils.assertEqual( + value.stream().map(BigDecimal::new).collect(Collectors.toList()), output, + DEFAULT_PRECISION); + } + }; + } + } + + public static class TestOpenToParty + extends TestThreadFactory { + + @Override + public TestThread next() { + + BigDecimal value = BigDecimal.ONE; + + return new TestThread() { + @Override + public void test() throws Exception { + Application app = producer -> { + DRes input = producer.realNumeric().input(value, 1); + return producer.realNumeric().open(input, 1); + }; + BigDecimal output = runApplication(app); + + if (conf.getMyId() == 1) { + RealTestUtils.assertEqual(value, output, DEFAULT_PRECISION + 1); + } else { + Assert.assertNull(output); + } + + } + }; + } + } + + public static class TestKnown + extends TestThreadFactory { + + @Override + public TestThread next() { + + List value = Arrays + .asList(10.000001, 5.9, 11.0, 0.0001, 100000000.0001, + 0.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .stream().map(BigDecimal::valueOf).collect(Collectors.toList()); + + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> inputs = + value.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + List> opened = + inputs.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + RealTestUtils.assertEqual(value, output, DEFAULT_PRECISION + 1); + } + }; + } + } + + public static class TestAddKnown + extends TestThreadFactory { + + @Override + public TestThread next() { + + List openInputs = Stream + .of(1.0001, 0.000_000_001, -1_000_000_000_000.000_100_000_000_1, + 0.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + List openInputs2 = Stream + .of(-1.0001, 1_000_000_000.0, -1_000_000_000_000.000_100_000_000_1, + 0.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> closed1 = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + + List> result = new ArrayList<>(); + for (DRes inputX : closed1) { + result.add( + producer.realNumeric().add(openInputs2.get(closed1.indexOf(inputX)), inputX)); + } + + List> opened = + result.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + + for (BigDecimal openOutput : output) { + int idx = output.indexOf(openOutput); + + BigDecimal a = openInputs.get(idx); + BigDecimal b = openInputs2.get(idx); + RealTestUtils.assertEqual(a.add(b), openOutput, DEFAULT_PRECISION); + } + } + }; + } + } + + public static class TestSubtractSecret + extends TestThreadFactory { + + @Override + public TestThread next() { + + List openInputs = Stream + .of(1.000_2, 0.000_000_001, -1_000_000_000_000.000_100_000_000_1, + 2.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + List openInputs2 = Stream + .of(1.000_1, 1_000_000_000.0, -1_000_000_000_000.000_100_000_000_1, + Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> closed1 = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + List> closed2 = openInputs2.stream().map(producer.realNumeric()::known) + .collect(Collectors.toList()); + + List> results = new ArrayList<>(); + for (DRes inputX : closed1) { + results.add(producer.realNumeric().sub(inputX, closed2.get(closed1.indexOf(inputX)))); + } + + List> opened = + results.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + + for (BigDecimal openOutput : output) { + int idx = output.indexOf(openOutput); + + BigDecimal a = openInputs.get(idx); + BigDecimal b = openInputs2.get(idx); + RealTestUtils.assertEqual(a.subtract(b), openOutput, DEFAULT_PRECISION); + } + } + }; + } + } + + public static class TestSubKnown + extends TestThreadFactory { + + @Override + public TestThread next() { + + List openInputs = Stream + .of(1.000_2, 0.000_000_001, -1_000_000_000_000.000_100_000_000_1, + 2.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + List openInputs2 = Stream + .of(1.000_1, 1_000_000_000.0, -1_000_000_000_000.000_100_000_000_1, + Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> closed = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + List> opened = Stream.concat( + IntStream.range(0, closed.size()) + .mapToObj(i -> producer.realNumeric().sub(closed.get(i), openInputs2.get(i))), + IntStream.range(0, closed.size()) + .mapToObj(i -> producer.realNumeric().sub(openInputs2.get(i), closed.get(i)))) + .map(producer.realNumeric()::open) + .collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + assertEquals(output.size(), openInputs.size() * 2); + IntStream.range(0, openInputs.size()) + .forEach( + idx -> { + BigDecimal a = openInputs.get(idx); + BigDecimal b = openInputs2.get(idx); + RealTestUtils.assertEqual(a.subtract(b), output.get(idx), DEFAULT_PRECISION); + }); + + IntStream.range(openInputs.size(), output.size()) + .forEach( + idx -> { + BigDecimal a = openInputs.get(idx - openInputs.size()); + BigDecimal b = openInputs2.get(idx - openInputs.size()); + RealTestUtils.assertEqual(b.subtract(a), output.get(idx), DEFAULT_PRECISION); + }); + } + }; + } + } + + public static class TestMultKnown + extends TestThreadFactory { + + @Override + public TestThread next() { + List openInputs = + Stream.of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.0007, 0.1298, 9.99) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + List openInputs2 = + Stream.of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 0.0005, 10.0012, 999.0101) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + + List> closed1 = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + + List> result = new ArrayList<>(); + for (DRes inputX : closed1) { + result.add( + producer.realNumeric().mult(openInputs2.get(closed1.indexOf(inputX)), inputX)); + } + + List> opened = + result.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + for (BigDecimal openOutput : output) { + int idx = output.indexOf(openOutput); + BigDecimal a = openInputs.get(idx); + BigDecimal b = openInputs2.get(idx); + // There should be no truncation after just one multiplication + RealTestUtils.assertEqual(a.multiply(b), openOutput, + DEFAULT_PRECISION + - Math.max(RealTestUtils.floorLog2(a), RealTestUtils.floorLog2(b))); + } + } + }; + } + } + + + public static class TestRepeatedMultiplication + extends TestThreadFactory { + + @Override + public TestThread next() { + List openInputs = + Stream.of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.0007, 0.1298) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + return new TestThread() { + @Override + public void test() throws Exception { + Application app = producer -> { + List> closed1 = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + + DRes result = producer.realNumeric().known(BigDecimal.ONE); + for (DRes inputX : closed1) { + result = producer.realNumeric().mult(result, inputX); + } + + DRes opened = producer.realNumeric().open(result); + return opened; + }; + BigDecimal output = runApplication(app); + + BigDecimal expected = BigDecimal.ONE.setScale(DEFAULT_PRECISION / 2); + for (BigDecimal openOutput : openInputs) { + expected = expected.multiply(openOutput); + } + // We lose precision for each multiplication. + RealTestUtils.assertEqual(output, expected, DEFAULT_PRECISION - 8); + } + }; + } + } + + public static class TestDivisionKnownDivisor + extends TestThreadFactory { + + @Override + public TestThread next() { + + BigDecimal value = BigDecimal.valueOf(10.00100); + BigDecimal value2 = BigDecimal.valueOf(0.2); + + return new TestThread() { + @Override + public void test() throws Exception { + Application app = producer -> { + + DRes input = producer.realNumeric().input(value, 1); + DRes product = producer.realNumeric().div(input, value2); + + return producer.realNumeric().open(product); + }; + BigDecimal output = runApplication(app); + RealTestUtils.assertEqual(value.divide(value2), output, DEFAULT_PRECISION - 2 + - Math.max(0, RealTestUtils.floorLog2(value) - RealTestUtils.floorLog2(value2))); + } + }; + } + } + + public static class TestDivisionKnownNegativeDivisor + extends TestThreadFactory { + + @Override + public TestThread next() { + + BigDecimal value = BigDecimal.valueOf(10.00100); + BigDecimal value2 = BigDecimal.valueOf(-1); + + return new TestThread() { + @Override + public void test() throws Exception { + Application app = producer -> { + + DRes input = producer.realNumeric().input(value, 1); + DRes product = producer.realNumeric().div(input, value2); + + return producer.realNumeric().open(product); + }; + BigDecimal output = runApplication(app); + RealTestUtils.assertEqual(value.divide(value2), output, DEFAULT_PRECISION - 2 + - Math.max(0, RealTestUtils.floorLog2(value) - RealTestUtils.floorLog2(value2))); + } + }; + } + } + + public static class TestMult + extends TestThreadFactory { + + @Override + public TestThread next() { + // TODO not clear if this test makes sense + List openInputs = Stream + .of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.1298) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + List openInputs2 = Stream + .of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 10.0012) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> closed1 = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + List> closed2 = openInputs2.stream().map(producer.realNumeric()::known) + .collect(Collectors.toList()); + + List> result = new ArrayList<>(); + for (DRes inputX : closed1) { + result.add(producer.realNumeric().mult(inputX, closed2.get(closed1.indexOf(inputX)))); + } + + List> opened = + result.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + + for (BigDecimal openOutput : output) { + int idx = output.indexOf(openOutput); + BigDecimal a = openInputs.get(idx); + BigDecimal b = openInputs2.get(idx); + RealTestUtils.assertEqual(a.multiply(b), openOutput, + DEFAULT_PRECISION - 1 - + Math.max(RealTestUtils.floorLog2(a), RealTestUtils.floorLog2(b))) ; + } + } + }; + } + } + + public static class TestMultSemiFloating + extends TestThreadFactory { + + @Override + public TestThread next() { + List openInputs = Stream + .of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.0007, 0.1298, + 1.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + List openInputs2 = Stream + .of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 0.0005, 10.0012, + 3.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> closed1 = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + List> closed2 = openInputs2.stream().map(producer.realNumeric()::known) + .collect(Collectors.toList()); + + List> result = new ArrayList<>(); + for (DRes inputX : closed1) { + result.add(producer.realNumeric().mult(inputX, closed2.get(closed1.indexOf(inputX)))); + } + + List> opened = + result.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + + for (BigDecimal openOutput : output) { + int idx = output.indexOf(openOutput); + + BigDecimal a = openInputs.get(idx); + BigDecimal b = openInputs2.get(idx); + + RealTestUtils.assertEqual(a.multiply(b), openOutput, + DEFAULT_PRECISION - 1 - Math.max(RealTestUtils.floorLog2(a), RealTestUtils.floorLog2(b))); + } + } + }; + } + } + + public static class TestAdd + extends TestThreadFactory { + + @Override + public TestThread next() { + + List openInputs = Stream + .of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.0007, 0.121998, + 0.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + List openInputs2 = Stream + .of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 0.0005, 10.00112, + 0.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> closed1 = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + List> closed2 = openInputs2.stream().map(producer.realNumeric()::known) + .collect(Collectors.toList()); + + List> result = new ArrayList<>(); + for (DRes inputX : closed1) { + result.add(producer.realNumeric().add(inputX, closed2.get(closed1.indexOf(inputX)))); + } + + List> opened = + result.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + + for (BigDecimal openOutput : output) { + int idx = output.indexOf(openOutput); + + BigDecimal a = openInputs.get(idx); + BigDecimal b = openInputs2.get(idx); + RealTestUtils.assertEqual(a.add(b), openOutput, DEFAULT_PRECISION); + } + } + }; + } + } + + public static class TestDiv + extends TestThreadFactory { + + @Override + public TestThread next() { + + List openInputs = Stream + .of(2.0, Math.pow(2.0, DEFAULT_PRECISION - 1), -4.0, + 2.5 * Math.pow(2.0, -DEFAULT_PRECISION)) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + List openInputs2 = + Stream.of(-1.0, 2.2, -2.1, 2.0).map(BigDecimal::valueOf).collect(Collectors.toList()); + + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + List> closed1 = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + List> closed2 = openInputs2.stream().map(producer.realNumeric()::known) + .collect(Collectors.toList()); + List> result = new ArrayList<>(); + for (DRes inputX : closed1) { + result.add(producer.realNumeric().div(inputX, closed2.get(closed1.indexOf(inputX)))); + } + List> opened = + result.stream().map(producer.realNumeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + for (BigDecimal openOutput : output) { + int idx = output.indexOf(openOutput); + BigDecimal a = openInputs.get(idx).setScale(DEFAULT_PRECISION, RoundingMode.HALF_UP); + BigDecimal b = openInputs2.get(idx).setScale(DEFAULT_PRECISION, RoundingMode.HALF_UP); + BigDecimal expected = a.divide(b, RoundingMode.HALF_UP); + // It's hard to approximate error after division since it depends on the input sizes. We + // use 4 for now. + RealTestUtils.assertEqual(expected, openOutput, 4); + } + } + }; + } + } + + public static class TestLeq + extends TestThreadFactory { + + @Override + public TestThread next() { + List openInputs = Stream.of(1.1 * Math.pow(2.0, -DEFAULT_PRECISION + 1), + Math.pow(2.0, DEFAULT_PRECISION - 1), -1.0).map(BigDecimal::valueOf) + .collect(Collectors.toList()); + List openInputs2 = Stream + .of(1.2 * Math.pow(2.0, -DEFAULT_PRECISION + 1), + Math.pow(2.0, DEFAULT_PRECISION - 1) - 1.0, 1.0) + .map(BigDecimal::valueOf).collect(Collectors.toList()); + + return new TestThread() { + @Override + public void test() throws Exception { + Application, ProtocolBuilderNumeric> app = producer -> { + + List> closed1 = + openInputs.stream().map(producer.realNumeric()::known).collect(Collectors.toList()); + List> closed2 = openInputs2.stream().map(producer.realNumeric()::known) + .collect(Collectors.toList()); + + List> result = new ArrayList<>(); + for (DRes inputX : closed1) { + result.add(producer.realNumeric().leq(inputX, closed2.get(closed1.indexOf(inputX)))); + } + + List> opened = + result.stream().map(producer.numeric()::open).collect(Collectors.toList()); + return () -> opened.stream().map(DRes::out).collect(Collectors.toList()); + }; + List output = runApplication(app); + + for (int i = 0; i < output.size(); i++) { + BigDecimal a = openInputs.get(i); + BigDecimal b = openInputs2.get(i); + int expected = (a.compareTo(b) != 1) ? 1 : 0; + int result = output.get(i).intValue(); + Assert.assertEquals(expected, result); + } + } + }; + } + } +} diff --git a/core/src/test/java/dk/alexandra/fresco/lib/real/fixed/TestFixedNumeric.java b/core/src/test/java/dk/alexandra/fresco/lib/real/fixed/TestFixedNumeric.java index de909a80f..a376e4b1c 100644 --- a/core/src/test/java/dk/alexandra/fresco/lib/real/fixed/TestFixedNumeric.java +++ b/core/src/test/java/dk/alexandra/fresco/lib/real/fixed/TestFixedNumeric.java @@ -14,7 +14,7 @@ public void testFixedNumericLegalPrecision() { BuilderFactoryNumeric bfn = new DummyArithmeticBuilderFactory( new BasicNumericContext(16, BigInteger.TEN, 1, 1), new RealNumericContext(0)); - new FixedNumeric(bfn.createSequential(), 4); + new SemiFixedNumeric(bfn.createSequential(), 4); } @Test(expected = IllegalArgumentException.class) @@ -22,7 +22,7 @@ public void testFixedNumericPrecisionTooLarge() { BuilderFactoryNumeric bfn = new DummyArithmeticBuilderFactory( new BasicNumericContext(16, BigInteger.TEN, 1, 1), new RealNumericContext(0)); - new FixedNumeric(bfn.createSequential(), 5); + new SemiFixedNumeric(bfn.createSequential(), 5); } @Test(expected = IllegalArgumentException.class) @@ -30,12 +30,12 @@ public void testFixedNumericPrecisionTooLow() { BuilderFactoryNumeric bfn = new DummyArithmeticBuilderFactory( new BasicNumericContext(16, BigInteger.TEN, 1, 1), new RealNumericContext(0)); - new FixedNumeric(bfn.createSequential(), -1); + new SemiFixedNumeric(bfn.createSequential(), -1); } @Test(expected = NullPointerException.class) public void testFixedNumericNullBuilder() { - new FixedNumeric(null, -1); + new SemiFixedNumeric(null, -1); } } diff --git a/core/src/test/java/dk/alexandra/fresco/logging/TestNumericSuiteLoggingDecorators.java b/core/src/test/java/dk/alexandra/fresco/logging/TestNumericSuiteLoggingDecorators.java index 1fada7c17..3c676de05 100644 --- a/core/src/test/java/dk/alexandra/fresco/logging/TestNumericSuiteLoggingDecorators.java +++ b/core/src/test/java/dk/alexandra/fresco/logging/TestNumericSuiteLoggingDecorators.java @@ -134,7 +134,6 @@ public void testComparisonLoggingDecorator() { SecureComputationEngine sce = new SecureComputationEngineImpl<>(ps, evaluator); - Drbg drbg = new HmacDrbg(); TestThreadRunner.TestThreadConfiguration ttc = new TestThreadRunner.TestThreadConfiguration<>(sce, () -> new DummyArithmeticResourcePoolImpl(playerId, @@ -150,13 +149,13 @@ public void testComparisonLoggingDecorator() { Map loggedValues = logger.getLoggedValues(); assertThat(loggedValues.get(ComparisonLoggerDecorator.ARITHMETIC_COMPARISON_EQ), - is((long) 2)); + is((long) 6)); assertThat(loggedValues.get(ComparisonLoggerDecorator.ARITHMETIC_COMPARISON_LEQ), is((long) 0)); assertThat(loggedValues.get(ComparisonLoggerDecorator.ARITHMETIC_COMPARISON_SIGN), is((long) 0)); assertThat(loggedValues.get(ComparisonLoggerDecorator.ARITHMETIC_COMPARISON_COMP0), - is((long) 2)); + is((long) 0)); logger.reset(); loggedValues = logger.getLoggedValues(); diff --git a/core/src/test/java/dk/alexandra/fresco/suite/dummy/arithmetic/AbstractDummyArithmeticTest.java b/core/src/test/java/dk/alexandra/fresco/suite/dummy/arithmetic/AbstractDummyArithmeticTest.java index 16e178802..ba1e344bd 100644 --- a/core/src/test/java/dk/alexandra/fresco/suite/dummy/arithmetic/AbstractDummyArithmeticTest.java +++ b/core/src/test/java/dk/alexandra/fresco/suite/dummy/arithmetic/AbstractDummyArithmeticTest.java @@ -162,8 +162,8 @@ public TestParameters maxBitLength(int maxBitLength) { return this; } - public TestParameters fixedPointPrecesion(int fixedPointPrecesion) { - this.fixedPointPrecesion = fixedPointPrecesion; + public TestParameters fixedPointPrecision(int fixedPointPrecision) { + this.fixedPointPrecesion = fixedPointPrecision; return this; } diff --git a/core/src/test/java/dk/alexandra/fresco/suite/dummy/arithmetic/TestDummyArithmeticProtocolSuite.java b/core/src/test/java/dk/alexandra/fresco/suite/dummy/arithmetic/TestDummyArithmeticProtocolSuite.java index 393e8c637..f38cea851 100644 --- a/core/src/test/java/dk/alexandra/fresco/suite/dummy/arithmetic/TestDummyArithmeticProtocolSuite.java +++ b/core/src/test/java/dk/alexandra/fresco/suite/dummy/arithmetic/TestDummyArithmeticProtocolSuite.java @@ -22,6 +22,11 @@ import dk.alexandra.fresco.lib.collections.relational.LeakyAggregationTests; import dk.alexandra.fresco.lib.collections.shuffle.ShuffleRowsTests; import dk.alexandra.fresco.lib.compare.CompareTests; +import dk.alexandra.fresco.lib.compare.CompareTests.TestLessThanLogRounds; +import dk.alexandra.fresco.lib.compare.lt.BitLessThanOpenTests.TestBitLessThanOpen; +import dk.alexandra.fresco.lib.compare.lt.CarryOutTests.TestCarryOut; +import dk.alexandra.fresco.lib.compare.lt.LessThanZeroTests.TestLessThanZero; +import dk.alexandra.fresco.lib.compare.lt.PreCarryTests.TestPreCarryBits; import dk.alexandra.fresco.lib.conditional.ConditionalSelectTests; import dk.alexandra.fresco.lib.conditional.ConditionalSwapNeighborsTests; import dk.alexandra.fresco.lib.conditional.ConditionalSwapRowsTests; @@ -31,15 +36,25 @@ import dk.alexandra.fresco.lib.lp.LPSolver; import dk.alexandra.fresco.lib.lp.LpBuildingBlockTests; import dk.alexandra.fresco.lib.math.integer.binary.BinaryOperationsTests; +import dk.alexandra.fresco.lib.math.integer.binary.BinaryOperationsTests.TestGenerateRandomBitMask; import dk.alexandra.fresco.lib.math.integer.division.DivisionTests; import dk.alexandra.fresco.lib.math.integer.exp.ExponentiationTests; import dk.alexandra.fresco.lib.math.integer.linalg.LinAlgTests; import dk.alexandra.fresco.lib.math.integer.log.LogTests; +import dk.alexandra.fresco.lib.math.integer.logical.LogicalOperationsTests.TestAnd; +import dk.alexandra.fresco.lib.math.integer.logical.LogicalOperationsTests.TestAndKnown; +import dk.alexandra.fresco.lib.math.integer.logical.LogicalOperationsTests.TestNot; +import dk.alexandra.fresco.lib.math.integer.logical.LogicalOperationsTests.TestOr; +import dk.alexandra.fresco.lib.math.integer.logical.LogicalOperationsTests.TestOrList; +import dk.alexandra.fresco.lib.math.integer.logical.LogicalOperationsTests.TestXorKnown; import dk.alexandra.fresco.lib.math.integer.min.MinTests; +import dk.alexandra.fresco.lib.math.integer.mod.Mod2mTests.TestMod2mBaseCase; import dk.alexandra.fresco.lib.math.integer.sqrt.SqrtTests; import dk.alexandra.fresco.lib.math.integer.stat.StatisticsTests; import dk.alexandra.fresco.lib.math.polynomial.PolynomialTests; import dk.alexandra.fresco.lib.real.BasicFixedPointTests; +import dk.alexandra.fresco.lib.real.BasicFixedPointTests.TestMult; +import dk.alexandra.fresco.lib.real.BasicFixedPointTests.TestMultIsolated; import dk.alexandra.fresco.lib.real.LinearAlgebraTests; import dk.alexandra.fresco.lib.real.MathTests; import dk.alexandra.fresco.lib.real.TruncationTests; @@ -51,8 +66,10 @@ import dk.alexandra.fresco.logging.NetworkLoggingDecorator; import dk.alexandra.fresco.logging.arithmetic.ComparisonLoggerDecorator; import dk.alexandra.fresco.logging.arithmetic.NumericLoggingDecorator; +import java.math.BigInteger; import java.util.ArrayList; import java.util.Random; +import org.junit.Ignore; import org.junit.Test; public class TestDummyArithmeticProtocolSuite extends AbstractDummyArithmeticTest { @@ -429,7 +446,7 @@ public void test_LpSolverDanzigSmallerMod() { .numParties(2) .modulus(ModulusFinder.findSuitableModulus(128)) .maxBitLength(30) - .fixedPointPrecesion(8) + .fixedPointPrecision(8) .performanceLogging(false)); } @@ -653,7 +670,12 @@ public void test_Real_Mult_Known() { @Test public void test_Real_Mults() { - runTest(new BasicFixedPointTests.TestMult<>(), new TestParameters().numParties(2)); + runTest(new TestMult<>(), new TestParameters().numParties(2)); + } + + @Test + public void test_Real_Mults_Isolated() { + runTest(new TestMultIsolated<>(), new TestParameters().numParties(2)); } @Test @@ -662,17 +684,20 @@ public void test_Real_Repeated_Multiplication() { new TestParameters().numParties(2)); } + @Ignore @Test public void test_Real_Division_Secret_Divisor() { runTest(new BasicFixedPointTests.TestDiv<>(), new TestParameters().numParties(2)); } + @Ignore @Test public void test_Real_Division_Known_Divisor() { runTest(new BasicFixedPointTests.TestDivisionKnownDivisor<>(), new TestParameters().numParties(2)); } + @Ignore @Test public void test_Real_Division_Known_Negative_Divisor() { runTest(new BasicFixedPointTests.TestDivisionKnownNegativeDivisor<>(), @@ -733,12 +758,14 @@ public void test_Real_Matrix_Addition_Unmatched() { new TestParameters()); } + @Ignore @Test public void test_Real_Matrix_Transpose() { runTest(new LinearAlgebraTests.TestTransposeMatrix<>(), new TestParameters()); } + @Ignore @Test public void test_Real_Exp() { runTest(new MathTests.TestExp<>(), new TestParameters().numParties(2)); @@ -754,11 +781,13 @@ public void test_Real_Leq() { runTest(new BasicFixedPointTests.TestLeq<>(), new TestParameters().numParties(2)); } + @Ignore @Test public void test_Real_Log() { runTest(new MathTests.TestLog<>(), new TestParameters().numParties(2)); } + @Ignore @Test public void test_Real_Sqrt() { runTest(new MathTests.TestSqrt<>(), new TestParameters().numParties(2)); @@ -789,11 +818,12 @@ public void test_inner_product_known_part_unmatched() { runTest(new MathTests.TestInnerProductPublicPartUnmatched<>(), new TestParameters()); } + @Ignore @Test public void test_Real_Sqrt_Uneven_Precision() { runTest(new MathTests.TestSqrt<>(), new TestParameters() - .fixedPointPrecesion(BasicFixedPointTests.DEFAULT_PRECISION + 1)); + .fixedPointPrecision(BasicFixedPointTests.DEFAULT_PRECISION + 1)); } @Test @@ -801,4 +831,111 @@ public void test_trunctation() { runTest(new TruncationTests.TestTruncation<>(), new TestParameters().numParties(2)); } + @Test + public void testAndKnown() { + runTest(new TestAndKnown<>(), new TestParameters()); + } + + @Test + public void testAnd() { + runTest(new TestAnd<>(), new TestParameters()); + } + + @Test + public void testOr() { + runTest(new TestOr<>(), new TestParameters()); + } + + @Test + public void testOrList() { + runTest(new TestOrList<>(), new TestParameters()); + } + + @Test + public void testNot() { + runTest(new TestNot<>(), new TestParameters()); + } + + @Test + public void testXorKnown() { + runTest(new TestXorKnown<>(), new TestParameters()); + } + + @Test + public void testMod2mBaseCase() { + TestParameters params = new TestParameters() + .modulus(ModulusFinder.findSuitableModulus(256)) + .numParties(2); + runTest(new TestMod2mBaseCase<>(), params); + } + + @Test + public void testPreCarryBits() { + runTest(new TestPreCarryBits<>(), new TestParameters()); + } + + @Test + public void testCarryOutZero() { + runTest(new TestCarryOut<>(0x00000000, 0x00000000), new TestParameters().numParties(2)); + } + + @Test + public void testCarryOutOne() { + runTest(new TestCarryOut<>(0x80000000, 0x80000000), new TestParameters().numParties(2)); + } + + @Test + public void testCarryOutAllOnes() { + runTest(new TestCarryOut<>(0xffffffff, 0xffffffff), new TestParameters().numParties(2)); + } + + @Test + public void testCarryOutOneFromCarry() { + runTest(new TestCarryOut<>(0x40000000, 0xc0000000), new TestParameters().numParties(2)); + } + + @Test + public void testCarryOutRandom() { + runTest(new TestCarryOut<>(new Random(42).nextInt(), new Random(1).nextInt()), + new TestParameters().numParties(2)); + } + + @Test + public void testBitLessThanOpen() { + BigInteger modulus = ModulusFinder.findSuitableModulus(128); + TestParameters parameters = new TestParameters().numParties(2).modulus(modulus); + runTest(new TestBitLessThanOpen<>(), parameters); + } + + @Test + public void testLessThanZero() { + BigInteger modulus = ModulusFinder.findSuitableModulus(128); + int maxBitLength = 64; + TestParameters parameters = new TestParameters().numParties(2).modulus(modulus).maxBitLength( + maxBitLength); + runTest(new TestLessThanZero<>(modulus), parameters); + } + + @Test + public void testLessThanLogRounds() { + BigInteger modulus = ModulusFinder.findSuitableModulus(128); + int maxBitLength = 64; + TestParameters parameters = new TestParameters() + .numParties(2) + .modulus(modulus) + .maxBitLength(maxBitLength); + runTest(new TestLessThanLogRounds<>(maxBitLength), parameters); + } + + @Test + public void testGenerateRandomBitMask() { + BigInteger modulus = ModulusFinder.findSuitableModulus(128); + int maxBitLength = 64; + TestParameters parameters = new TestParameters() + .numParties(2) + .modulus(modulus) + .maxBitLength(maxBitLength); + runTest(new TestGenerateRandomBitMask<>(), parameters); + } + } diff --git a/demos/common/pom.xml b/demos/common/pom.xml index 26595bff6..d751b7182 100644 --- a/demos/common/pom.xml +++ b/demos/common/pom.xml @@ -24,5 +24,11 @@ test-jar test + + dk.alexandra.fresco + spdz2k + 1.1.4-SNAPSHOT + compile + diff --git a/demos/common/src/main/java/dk/alexandra/fresco/demo/cli/CmdLineProtocolSuite.java b/demos/common/src/main/java/dk/alexandra/fresco/demo/cli/CmdLineProtocolSuite.java index 3fa82590e..31e87838f 100644 --- a/demos/common/src/main/java/dk/alexandra/fresco/demo/cli/CmdLineProtocolSuite.java +++ b/demos/common/src/main/java/dk/alexandra/fresco/demo/cli/CmdLineProtocolSuite.java @@ -1,5 +1,7 @@ package dk.alexandra.fresco.demo.cli; +import dk.alexandra.fresco.framework.configuration.NetworkConfiguration; +import dk.alexandra.fresco.framework.network.AsyncNetwork; import dk.alexandra.fresco.framework.sce.resources.ResourcePool; import dk.alexandra.fresco.framework.sce.resources.ResourcePoolImpl; import dk.alexandra.fresco.framework.sce.resources.storage.FilebasedStreamedStorageImpl; @@ -18,6 +20,18 @@ import dk.alexandra.fresco.suite.spdz.storage.SpdzDummyDataSupplier; import dk.alexandra.fresco.suite.spdz.storage.SpdzOpenedValueStoreImpl; import dk.alexandra.fresco.suite.spdz.storage.SpdzStorageDataSupplier; +import dk.alexandra.fresco.suite.spdz2k.Spdz2kProtocolSuite128; +import dk.alexandra.fresco.suite.spdz2k.Spdz2kProtocolSuite64; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128Factory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt64; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt64Factory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePoolImpl; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDataSupplier; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDummyDataSupplier; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kOpenedValueStoreImpl; import dk.alexandra.fresco.suite.tinytables.online.TinyTablesProtocolSuite; import dk.alexandra.fresco.suite.tinytables.ot.TinyTablesNaorPinkasOt; import dk.alexandra.fresco.suite.tinytables.ot.TinyTablesOt; @@ -44,14 +58,13 @@ public class CmdLineProtocolSuite { private final ResourcePool resourcePool; static String getSupportedProtocolSuites() { - String[] strings = {"dummybool", "dummyarithmetic", "spdz", "tinytables", "tinytablesprepro"}; + String[] strings = {"dummybool", "dummyarithmetic", "spdz", "spdz2k32", "spdz2k64", "tinytables", "tinytablesprepro"}; return Arrays.toString(strings); } - CmdLineProtocolSuite(String protocolSuiteName, Properties properties, int myId, - int noOfPlayers) throws ParseException, NoSuchAlgorithmException { - this.myId = myId; - this.noOfPlayers = noOfPlayers; + CmdLineProtocolSuite(String protocolSuiteName, Properties properties, NetworkConfiguration conf) throws ParseException, NoSuchAlgorithmException { + this.myId = conf.getMyId(); + this.noOfPlayers = conf.noOfParties(); if (protocolSuiteName.equals("dummybool")) { this.protocolSuite = new DummyBooleanProtocolSuite(); this.resourcePool = @@ -67,6 +80,14 @@ static String getSupportedProtocolSuites() { this.protocolSuite = getSpdzProtocolSuite(properties); this.resourcePool = createSpdzResourcePool(properties); + } else if (protocolSuiteName.equals("spdz2k32")) { + this.protocolSuite = getSpdz2kProtocolSuite(properties, false); + this.resourcePool = + createSpdz2kResourcePool(properties, false, conf); + } else if (protocolSuiteName.equals("spdz2k64")) { + this.protocolSuite = getSpdz2kProtocolSuite(properties, true); + this.resourcePool = + createSpdz2kResourcePool(properties, true, conf); } else if (protocolSuiteName.equals("tinytablesprepro")) { String tinytablesFileOption = "tinytables.file"; String tinyTablesFilePath = properties.getProperty(tinytablesFileOption, "tinytables"); @@ -113,6 +134,11 @@ public ResourcePool getResourcePool() { return new SpdzProtocolSuite(maxBitLength); } + private ProtocolSuite getSpdz2kProtocolSuite(Properties properties, boolean large) { + Properties p = getProperties(properties); + return large ? new Spdz2kProtocolSuite128(true) : new Spdz2kProtocolSuite64(true); + } + private Properties getProperties(Properties properties) { return properties; } @@ -137,6 +163,43 @@ private SpdzResourcePool createSpdzResourcePool(Properties properties) { new AesCtrDrbg(new byte[32])); } + private Spdz2kResourcePool createSpdz2kResourcePool(Properties properties, boolean large, NetworkConfiguration conf) { + String strat = properties.getProperty("spdz2k.preprocessingStrategy"); + final PreprocessingStrategy strategy = PreprocessingStrategy.valueOf(strat); + Spdz2kDataSupplier supplier = null; + if (strategy == PreprocessingStrategy.DUMMY) { + if (large) { + CompUIntFactory factory = new CompUInt128Factory(); + CompUInt128 keyShare = factory.createRandom(); + Spdz2kResourcePool resourcePool = + new Spdz2kResourcePoolImpl<>( + myId, + noOfPlayers, new AesCtrDrbg(new byte[32]), + new Spdz2kOpenedValueStoreImpl<>(), + new Spdz2kDummyDataSupplier<>(myId, noOfPlayers, keyShare, factory), + factory); + resourcePool.initializeJointRandomness(() -> new AsyncNetwork(conf), AesCtrDrbg::new, 32); + return resourcePool; + } else { + CompUIntFactory factory = new CompUInt64Factory(); + CompUInt64 keyShare = factory.createRandom(); + Spdz2kResourcePool resourcePool = + new Spdz2kResourcePoolImpl<>( + myId, + noOfPlayers, new AesCtrDrbg(new byte[32]), + new Spdz2kOpenedValueStoreImpl<>(), + new Spdz2kDummyDataSupplier<>(myId, noOfPlayers, keyShare, factory), + factory); + resourcePool.initializeJointRandomness(() -> new AsyncNetwork(conf), AesCtrDrbg::new, 32); + return resourcePool; + } + } + if (strategy == PreprocessingStrategy.STATIC) { + throw new UnsupportedOperationException("Real SPDZ2k supplier from commandline not implemented yet"); + } + throw new UnsupportedOperationException("Unknown SPDZ2k supplier"); + } + private ProtocolSuite tinyTablesPreProFromCmdLine(Properties properties) { return new TinyTablesPreproProtocolSuite(); } diff --git a/demos/common/src/main/java/dk/alexandra/fresco/demo/cli/CmdLineUtil.java b/demos/common/src/main/java/dk/alexandra/fresco/demo/cli/CmdLineUtil.java index 072dc428e..ba9e9186d 100644 --- a/demos/common/src/main/java/dk/alexandra/fresco/demo/cli/CmdLineUtil.java +++ b/demos/common/src/main/java/dk/alexandra/fresco/demo/cli/CmdLineUtil.java @@ -245,8 +245,7 @@ public CommandLine parse(String[] args) { parseAndSetupNetwork(); CmdLineProtocolSuite protocolSuiteParser = new CmdLineProtocolSuite(protocolSuiteName, - cmd.getOptionProperties("D"), this.networkConfiguration.getMyId(), - this.networkConfiguration.noOfParties()); + cmd.getOptionProperties("D"), this.networkConfiguration); protocolSuite = (ProtocolSuite) protocolSuiteParser.getProtocolSuite(); resourcePool = (ResourcePoolT) protocolSuiteParser.getResourcePool(); diff --git a/demos/pom.xml b/demos/pom.xml index 13cafe259..9c0a50407 100644 --- a/demos/pom.xml +++ b/demos/pom.xml @@ -16,6 +16,11 @@ spdz ${project.version} + + dk.alexandra.fresco + spdz2k + ${project.version} + dk.alexandra.fresco tinytables diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzBuilder.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzBuilder.java index a43029c09..9349eb338 100644 --- a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzBuilder.java +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzBuilder.java @@ -1,27 +1,51 @@ package dk.alexandra.fresco.suite.spdz; import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric; import dk.alexandra.fresco.framework.builder.numeric.BuilderFactoryNumeric; +import dk.alexandra.fresco.framework.builder.numeric.Comparison; +import dk.alexandra.fresco.framework.builder.numeric.Conversion; +import dk.alexandra.fresco.framework.builder.numeric.DefaultAdvancedNumeric; +import dk.alexandra.fresco.framework.builder.numeric.DefaultComparison; +import dk.alexandra.fresco.framework.builder.numeric.DefaultLogical; +import dk.alexandra.fresco.framework.builder.numeric.Logical; import dk.alexandra.fresco.framework.builder.numeric.Numeric; import dk.alexandra.fresco.framework.builder.numeric.PreprocessedValues; import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.framework.value.BigIntegerOIntArithmetic; +import dk.alexandra.fresco.framework.value.BigIntegerOIntFactory; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntArithmetic; +import dk.alexandra.fresco.framework.value.OIntFactory; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.lib.compare.MiscBigIntegerGenerators; import dk.alexandra.fresco.lib.field.integer.BasicNumericContext; import dk.alexandra.fresco.lib.real.RealNumericContext; import dk.alexandra.fresco.suite.spdz.gates.SpdzAddProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzAddProtocolKnownLeft; +import dk.alexandra.fresco.suite.spdz.gates.SpdzAndBatchedProtocol; +import dk.alexandra.fresco.suite.spdz.gates.SpdzAndKnownBatchedProtocol; +import dk.alexandra.fresco.suite.spdz.gates.SpdzCarryProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzInputProtocol; +import dk.alexandra.fresco.suite.spdz.gates.SpdzInputTwoPartyProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzKnownSIntProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzMultProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzMultProtocolKnownLeft; +import dk.alexandra.fresco.suite.spdz.gates.SpdzNotBatchedProtocol; +import dk.alexandra.fresco.suite.spdz.gates.SpdzOrBatchedProtocol; +import dk.alexandra.fresco.suite.spdz.gates.SpdzOrOfListProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzOutputSingleProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzOutputToAllProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzRandomProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzSubtractProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzSubtractProtocolKnownLeft; import dk.alexandra.fresco.suite.spdz.gates.SpdzSubtractProtocolKnownRight; +import dk.alexandra.fresco.suite.spdz.gates.SpdzTruncationPairProtocol; +import dk.alexandra.fresco.suite.spdz.gates.SpdzXorKnownBatchedProtocol; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; /** * Basic native builder for the SPDZ protocol suite. @@ -31,10 +55,14 @@ class SpdzBuilder implements BuilderFactoryNumeric { private BasicNumericContext basicNumericContext; private MiscBigIntegerGenerators miscOIntGenerators; private RealNumericContext realNumericContext; + private final OIntFactory oIntFactory; + private final OIntArithmetic oIntArithmetic; SpdzBuilder(BasicNumericContext basicNumericContext, RealNumericContext realNumericContext) { this.basicNumericContext = basicNumericContext; this.realNumericContext = realNumericContext; + this.oIntFactory = new BigIntegerOIntFactory(basicNumericContext.getMaxBitLength()); + this.oIntArithmetic = new BigIntegerOIntArithmetic(oIntFactory); } @Override @@ -46,7 +74,7 @@ public BasicNumericContext getBasicNumericContext() { public RealNumericContext getRealNumericContext() { return realNumericContext; } - + @Override public PreprocessedValues createPreprocessedValues(ProtocolBuilderNumeric protocolBuilder) { return pipeLength -> { @@ -56,6 +84,21 @@ public PreprocessedValues createPreprocessedValues(ProtocolBuilderNumeric protoc }; } + @Override + public Comparison createComparison(ProtocolBuilderNumeric builder) { + return new SpdzComparison(this, builder); + } + + @Override + public AdvancedNumeric createAdvancedNumeric(ProtocolBuilderNumeric builder) { + return new SpdzAdvancedNumeric(this, builder); + } + + @Override + public Logical createLogical(ProtocolBuilderNumeric builder) { + return new SpdzLogical(builder); + } + @Override public Numeric createNumeric(ProtocolBuilderNumeric protocolBuilder) { return new Numeric() { @@ -65,13 +108,16 @@ public DRes add(DRes a, DRes b) { return protocolBuilder.append(spdzAddProtocol); } - @Override public DRes add(BigInteger a, DRes b) { SpdzAddProtocolKnownLeft spdzAddProtocolKnownLeft = new SpdzAddProtocolKnownLeft(a, b); return protocolBuilder.append(spdzAddProtocolKnownLeft); } + @Override + public DRes addOpen(DRes a, DRes b) { + return add(protocolBuilder.getOIntFactory().toBigInteger(a.out()), b); + } @Override public DRes sub(DRes a, DRes b) { @@ -86,6 +132,16 @@ public DRes sub(BigInteger a, DRes b) { return protocolBuilder.append(spdzSubtractProtocolKnownLeft); } + @Override + public DRes subFromOpen(DRes a, DRes b) { + return sub(protocolBuilder.getOIntFactory().toBigInteger(a.out()), b); + } + + @Override + public DRes subOpen(DRes a, DRes b) { + return sub(a, protocolBuilder.getOIntFactory().toBigInteger(b.out())); + } + @Override public DRes sub(DRes a, BigInteger b) { SpdzSubtractProtocolKnownRight spdzSubtractProtocolKnownRight = @@ -106,6 +162,11 @@ public DRes mult(BigInteger a, DRes b) { } + @Override + public DRes multByOpen(DRes a, DRes b) { + return mult(protocolBuilder.getOIntFactory().toBigInteger(a.out()), b); + } + @Override public DRes randomBit() { return protocolBuilder.append(new SpdzRandomBitProtocol()); @@ -123,8 +184,11 @@ public DRes known(BigInteger value) { @Override public DRes input(BigInteger value, int inputParty) { - SpdzInputProtocol protocol = new SpdzInputProtocol(value, inputParty); - return protocolBuilder.append(protocol); + if (protocolBuilder.getBasicNumericContext().getNoOfParties() == 2) { + return protocolBuilder.append(new SpdzInputTwoPartyProtocol(value, inputParty)); + } else { + return protocolBuilder.append(new SpdzInputProtocol(value, inputParty)); + } } @Override @@ -139,9 +203,35 @@ public DRes open(DRes secretShare, int outputParty) { outputParty); return protocolBuilder.append(openProtocol); } + + @Override + public DRes openAsOInt(DRes secretShare) { + DRes value = open(secretShare); + return () -> oIntFactory.fromBigInteger(value.out()); + } + + @Override + public DRes openAsOInt(DRes secretShare, int outputParty) { + DRes out = open(secretShare, outputParty); + return () -> { + BigInteger res = out.out(); + if (res == null) { + return null; + } else { + return oIntFactory.fromBigInteger(res); + } + }; + } + }; } + @Override + public Conversion createConversion(ProtocolBuilderNumeric builder) { + throw new UnsupportedOperationException( + "This protocol suite does not currently support conversion"); + } + @Override public MiscBigIntegerGenerators getBigIntegerHelper() { if (miscOIntGenerators == null) { @@ -150,4 +240,100 @@ public MiscBigIntegerGenerators getBigIntegerHelper() { return miscOIntGenerators; } + @Override + public OIntFactory getOIntFactory() { + return oIntFactory; + } + + @Override + public OIntArithmetic getOIntArithmetic() { + return oIntArithmetic; + } + + class SpdzComparison extends DefaultComparison { + + public SpdzComparison( + BuilderFactoryNumeric factoryNumeric, + ProtocolBuilderNumeric builder) { + super(factoryNumeric, builder); + } + + @Override + public DRes> carry(List bitPairs) { + return builder.append(new SpdzCarryProtocol(bitPairs)); + } + } + + class SpdzLogical extends DefaultLogical { + + protected SpdzLogical( + ProtocolBuilderNumeric builder) { + super(builder); + } + + @Override + public DRes>> pairWiseOr(DRes>> bitsA, + DRes>> bitsB) { + return builder.append(new SpdzOrBatchedProtocol(bitsA, bitsB)); + } + + @Override + public DRes>> pairWiseAnd(DRes>> bitsA, + DRes>> bitsB) { + return builder.append(new SpdzAndBatchedProtocol(bitsA, bitsB)); + } + + @Override + public DRes>> batchedNot(DRes>> bits) { + return builder.append(new SpdzNotBatchedProtocol(bits)); + } + + @Override + public DRes>> pairWiseXorKnown(DRes> knownBits, + DRes>> secretBits) { + return builder.append(new SpdzXorKnownBatchedProtocol(knownBits, secretBits)); + } + + @Override + public DRes>> pairWiseAndKnown(DRes> knownBits, + DRes>> secretBits) { + return builder.append(new SpdzAndKnownBatchedProtocol(knownBits, secretBits)); + } + + @Override + public DRes orOfList(DRes>> bits) { + return builder.append(new SpdzOrOfListProtocol(bits)); + } + + @Override + public DRes>> orNeighbors(List> bits) { + // TODO same as SPDZ2k version + List> leftBits = new ArrayList<>(bits.size() / 2); + List> rightBits = new ArrayList<>(bits.size() / 2); + for (int i = 0; i < bits.size() - 1; i += 2) { + leftBits.add(bits.get(i)); + rightBits.add(bits.get(i + 1)); + } + final boolean isOdd = bits.size() % 2 != 0; + return builder.append(new SpdzOrBatchedProtocol( + () -> leftBits, + () -> rightBits, + isOdd ? bits.get(bits.size() - 1) : null)); + } + } + + class SpdzAdvancedNumeric extends DefaultAdvancedNumeric { + + protected SpdzAdvancedNumeric( + BuilderFactoryNumeric factoryNumeric, + ProtocolBuilderNumeric builder) { + super(factoryNumeric, builder); + } + + @Override + public DRes generateTruncationPair(int d) { + return builder.append(new SpdzTruncationPairProtocol(d)); + } + } + } diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzProtocolSuite.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzProtocolSuite.java index 8b2d2b1a8..930473abc 100644 --- a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzProtocolSuite.java +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzProtocolSuite.java @@ -8,18 +8,22 @@ public class SpdzProtocolSuite implements ProtocolSuiteNumeric { + private static final int DEFAULT_STATISTICAL_SECURITY = 40; private final int maxBitLength; private final int fixedPointPrecision; + private final int statisticalSecurityParam; - public SpdzProtocolSuite(int maxBitLength, int fixedPointPrecision) { + public SpdzProtocolSuite(int maxBitLength, int fixedPointPrecision, + int statisticalSecurityParam) { this.maxBitLength = maxBitLength; this.fixedPointPrecision = fixedPointPrecision; + this.statisticalSecurityParam = statisticalSecurityParam; } public SpdzProtocolSuite(int maxBitLength) { - this(maxBitLength, maxBitLength / 8); + this(maxBitLength, maxBitLength / 8, DEFAULT_STATISTICAL_SECURITY); } - + @Override public BuilderFactoryNumeric init(SpdzResourcePool resourcePool, Network network) { BasicNumericContext numericContext = createNumericContext(resourcePool); @@ -29,9 +33,9 @@ public BuilderFactoryNumeric init(SpdzResourcePool resourcePool, Network network BasicNumericContext createNumericContext(SpdzResourcePool resourcePool) { return new BasicNumericContext(maxBitLength, resourcePool.getModulus(), - resourcePool.getMyId(), resourcePool.getNoOfParties()); + resourcePool.getMyId(), resourcePool.getNoOfParties(), statisticalSecurityParam); } - + RealNumericContext createRealNumericContext() { return new RealNumericContext(fixedPointPrecision); } diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzRoundSynchronization.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzRoundSynchronization.java index 946b3ee1a..5cf6e78c6 100644 --- a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzRoundSynchronization.java +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/SpdzRoundSynchronization.java @@ -7,12 +7,14 @@ import dk.alexandra.fresco.framework.sce.evaluator.BatchedProtocolEvaluator; import dk.alexandra.fresco.framework.sce.evaluator.BatchedStrategy; import dk.alexandra.fresco.framework.util.OpenedValueStore; +import dk.alexandra.fresco.framework.util.Pair; import dk.alexandra.fresco.suite.ProtocolSuite.RoundSynchronization; import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; import dk.alexandra.fresco.suite.spdz.gates.SpdzMacCheckProtocol; import dk.alexandra.fresco.suite.spdz.gates.SpdzOutputProtocol; import java.math.BigInteger; import java.security.SecureRandom; +import java.util.List; import java.util.stream.StreamSupport; /** @@ -21,12 +23,12 @@ */ public class SpdzRoundSynchronization implements RoundSynchronization { - private static final int DEFAULT_VALUE_THRESHOLD = 1000000; + private static final int DEFAULT_VALUE_THRESHOLD = 300000; private static final int DEFAULT_BATCH_SIZE = 128; private final int openValueThreshold; private final SpdzProtocolSuite spdzProtocolSuite; private final SecureRandom secRand; - private boolean isCheckRequired = false; + private boolean isCheckRequired; private final int batchSize; /** @@ -45,6 +47,7 @@ public SpdzRoundSynchronization(SpdzProtocolSuite spdzProtocolSuite, int openVal this.secRand = new SecureRandom(); this.openValueThreshold = openValueThreshold; this.batchSize = batchSize; + this.isCheckRequired = false; } public SpdzRoundSynchronization(SpdzProtocolSuite spdzProtocolSuite) { @@ -52,6 +55,9 @@ public SpdzRoundSynchronization(SpdzProtocolSuite spdzProtocolSuite) { } protected void doMacCheck(SpdzResourcePool resourcePool, Network network) { +// Pair, List> bar = resourcePool.getOpenedValueStore().popValues(); +// bar.getFirst().clear(); +// bar.getSecond().clear(); SpdzBuilder spdzBuilder = new SpdzBuilder( spdzProtocolSuite.createNumericContext(resourcePool), spdzProtocolSuite.createRealNumericContext()); @@ -74,9 +80,11 @@ protected void doMacCheck(SpdzResourcePool resourcePool, Network network) { public void finishedBatch(int gatesEvaluated, SpdzResourcePool resourcePool, Network network) { OpenedValueStore store = resourcePool.getOpenedValueStore(); if (isCheckRequired) { +// System.out.println("Because required finished batch"); doMacCheck(resourcePool, network); isCheckRequired = false; } else if (store.exceedsThreshold(openValueThreshold)) { +// System.out.println("Because exceeds "); doMacCheck(resourcePool, network); isCheckRequired = false; } @@ -86,6 +94,7 @@ public void finishedBatch(int gatesEvaluated, SpdzResourcePool resourcePool, Net public void finishedEval(SpdzResourcePool resourcePool, Network network) { OpenedValueStore store = resourcePool.getOpenedValueStore(); if (store.hasPendingValues()) { +// System.out.println("Because eval finished"); doMacCheck(resourcePool, network); } } @@ -94,10 +103,13 @@ public void finishedEval(SpdzResourcePool resourcePool, Network network) { public void beforeBatch( ProtocolCollection protocols, SpdzResourcePool resourcePool, Network network) { - isCheckRequired = StreamSupport.stream(protocols.spliterator(), false) + final boolean outputFound = StreamSupport.stream(protocols.spliterator(), false) .anyMatch(p -> p instanceof SpdzOutputProtocol); +// System.out.println(outputFound); + this.isCheckRequired = outputFound; OpenedValueStore store = resourcePool.getOpenedValueStore(); - if (store.hasPendingValues() && isCheckRequired) { + if (store.hasPendingValues() && this.isCheckRequired) { +// System.out.println("Because of output"); doMacCheck(resourcePool, network); } } diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzAndBatchedProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzAndBatchedProtocol.java new file mode 100644 index 000000000..d506bf9c6 --- /dev/null +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzAndBatchedProtocol.java @@ -0,0 +1,136 @@ +package dk.alexandra.fresco.suite.spdz.gates; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz.SpdzResourcePool; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzTriple; +import dk.alexandra.fresco.suite.spdz.storage.SpdzDataSupplier; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class SpdzAndBatchedProtocol extends SpdzNativeProtocol>> { + + private final DRes>> leftDef; + private final DRes>> rightDef; + private List triples; + private List epsilons; + private List deltas; + private List openEpsilons; + private List openDeltas; + private List> products; + + public SpdzAndBatchedProtocol(DRes>> left, DRes>> right) { + this.leftDef = left; + this.rightDef = right; + } + + @Override + public EvaluationStatus evaluate(int round, SpdzResourcePool spdzResourcePool, + Network network) { + SpdzDataSupplier dataSupplier = spdzResourcePool.getDataSupplier(); + int noOfPlayers = spdzResourcePool.getNoOfParties(); + ByteSerializer serializer = spdzResourcePool.getSerializer(); + final List> leftFactors = leftDef.out(); + final List> rightFactors = rightDef.out(); + if (leftFactors.size() != rightFactors.size()) { + throw new IllegalArgumentException("Lists must be same size"); + } + if (round == 0) { + triples = new ArrayList<>(leftFactors.size()); + epsilons = new ArrayList<>(leftFactors.size()); + deltas = new ArrayList<>(leftFactors.size()); + openEpsilons = new ArrayList<>(leftFactors.size()); + openDeltas = new ArrayList<>(leftFactors.size()); + products = new ArrayList<>(leftFactors.size()); + + for (int i = 0; i < leftFactors.size(); i++) { + SpdzTriple triple = dataSupplier.getNextTriple(); + triples.add(triple); + + SpdzSInt left = (SpdzSInt) leftFactors.get(i).out(); + SpdzSInt right = (SpdzSInt) rightFactors.get(i).out(); + + SpdzSInt epsilon = left.subtract(triple.getA()); + SpdzSInt delta = right.subtract(triple.getB()); + epsilons.add(epsilon); + deltas.add(delta); + } + + serializeAndSend(network, serializer); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + BigInteger modulus = spdzResourcePool.getModulus(); + receiveAndReconstruct(network, serializer, noOfPlayers, modulus); + for (int i = 0; i < leftFactors.size(); i++) { + BigInteger e = openEpsilons.get(i); + BigInteger d = openDeltas.get(i); + + SpdzSInt product = computeProduct(spdzResourcePool.getMyId(), + e, d, modulus, triples.get(i), dataSupplier.getSecretSharedKey()); + products.add(product); + // Set the opened and closed value. + spdzResourcePool.getOpenedValueStore().pushOpenedValue(epsilons.get(i), e); + spdzResourcePool.getOpenedValueStore().pushOpenedValue(deltas.get(i), d); + } + return EvaluationStatus.IS_DONE; + } + } + + static SpdzSInt computeProduct(int myId, BigInteger e, BigInteger d, BigInteger modulus, + SpdzTriple triple, BigInteger key) { + BigInteger product = e.multiply(d).mod(modulus); + SpdzSInt ed = new SpdzSInt( + product, + key.multiply(product).mod(modulus), + modulus); + SpdzSInt res = triple.getC(); + return res.add(triple.getB().multiply(e)) + .add(triple.getA().multiply(d)) + .add(ed, myId); + } + + private void serializeAndSend(Network network, ByteSerializer serializer) { + byte[] epsilonBytes = serializer.serialize( + epsilons.stream().map(SpdzSInt::getShare).collect(Collectors.toList())); + byte[] deltaBytes = serializer.serialize( + deltas.stream().map(SpdzSInt::getShare).collect(Collectors.toList())); + network.sendToAll(epsilonBytes); + network.sendToAll(deltaBytes); + } + + private void receiveAndReconstruct(Network network, ByteSerializer serializer, + int noOfParties, BigInteger modulus) { + byte[] rawEpsilons = network.receive(1); + byte[] rawDeltas = network.receive(1); + openEpsilons = serializer.deserializeList(rawEpsilons); + openDeltas = serializer.deserializeList(rawDeltas); + + for (int i = 2; i <= noOfParties; i++) { + rawEpsilons = network.receive(i); + rawDeltas = network.receive(i); + + List innerEpsilons = serializer.deserializeList(rawEpsilons); + List innerDeltas = serializer.deserializeList(rawDeltas); + for (int j = 0; j < epsilons.size(); j++) { + openEpsilons.set(j, openEpsilons.get(j).add(innerEpsilons.get(j))); + openDeltas.set(j, openDeltas.get(j).add(innerDeltas.get(j))); + } + } + + for (int j = 0; j < epsilons.size(); j++) { + openEpsilons.set(j, openEpsilons.get(j).mod(modulus)); + openDeltas.set(j, openDeltas.get(j).mod(modulus)); + } + } + + @Override + public List> out() { + return products; + } + +} diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzAndKnownBatchedProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzAndKnownBatchedProtocol.java new file mode 100644 index 000000000..7fe93b764 --- /dev/null +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzAndKnownBatchedProtocol.java @@ -0,0 +1,46 @@ +package dk.alexandra.fresco.suite.spdz.gates; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.BigIntegerOInt; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz.SpdzResourcePool; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class SpdzAndKnownBatchedProtocol extends SpdzNativeProtocol>> { + + private final DRes> left; + private final DRes>> right; + private List> result; + + public SpdzAndKnownBatchedProtocol( + DRes> left, DRes>> right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, SpdzResourcePool resourcePool, Network network) { + List leftOut = left.out(); + List> rightOut = right.out(); + if (leftOut.size() != rightOut.size()) { + throw new IllegalArgumentException("Lists must be same size"); + } + this.result = new ArrayList<>(leftOut.size()); + for (int i = 0; i < leftOut.size(); i++) { + BigInteger leftEl = ((BigIntegerOInt) leftOut.get(i)).getValue(); + SpdzSInt rightEl = (SpdzSInt) rightOut.get(i).out(); + result.add(rightEl.multiply(leftEl)); + } + return EvaluationStatus.IS_DONE; + } + + @Override + public List> out() { + return result; + } +} diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzCarryProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzCarryProtocol.java new file mode 100644 index 000000000..43747577d --- /dev/null +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzCarryProtocol.java @@ -0,0 +1,146 @@ +package dk.alexandra.fresco.suite.spdz.gates; + +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; +import dk.alexandra.fresco.framework.util.OpenedValueStore; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.suite.spdz.SpdzResourcePool; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzTriple; +import dk.alexandra.fresco.suite.spdz.storage.SpdzDataSupplier; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class SpdzCarryProtocol extends SpdzNativeProtocol> { + + private final List bits; + private List triples; + private List epsilons; + private List deltas; + private List openEpsilons; + private List openDeltas; + private List carried; + + public SpdzCarryProtocol(List bits) { + this.bits = bits; + } + + @Override + public EvaluationStatus evaluate(int round, SpdzResourcePool spdzResourcePool, Network network) { + SpdzDataSupplier dataSupplier = spdzResourcePool.getDataSupplier(); + int noOfPlayers = spdzResourcePool.getNoOfParties(); + ByteSerializer serializer = spdzResourcePool.getSerializer(); + if (round == 0) { + triples = new ArrayList<>(bits.size()); + epsilons = new ArrayList<>(bits.size()); + deltas = new ArrayList<>(bits.size()); + openEpsilons = new ArrayList<>(bits.size()); + openDeltas = new ArrayList<>(bits.size()); + carried = new ArrayList<>(bits.size() / 2); + + for (int i = 0; i < bits.size() / 2; i++) { + // two multiplications + triples.add(spdzResourcePool.getDataSupplier().getNextTriple()); + triples.add(spdzResourcePool.getDataSupplier().getNextTriple()); + + SIntPair left = bits.get(2 * i + 1); + SIntPair right = bits.get(2 * i); + + SpdzTriple p1p2Triple = triples.get(2 * i + 1); + SpdzTriple p2g1Triple = triples.get(2 * i); + + SpdzSInt p1 = (SpdzSInt) left.getFirst().out(); + SpdzSInt g1 = (SpdzSInt) left.getSecond().out(); + SpdzSInt p2 = (SpdzSInt) right.getFirst().out(); + + // p2 * g1 + final SpdzSInt epsilonP2G1 = p2.subtract(p2g1Triple.getA()); + epsilons.add(epsilonP2G1); + final SpdzSInt deltaP2G1 = g1.subtract(p2g1Triple.getB()); + deltas.add(deltaP2G1); + + // p1 * p2 + final SpdzSInt epsilonP1P2 = p1.subtract(p1p2Triple.getA()); + epsilons.add(epsilonP1P2); + final SpdzSInt deltaP1P2 = p2.subtract(p1p2Triple.getB()); + deltas.add(deltaP1P2); + } + serializeAndSend(network, serializer); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + OpenedValueStore openedValueStore = spdzResourcePool + .getOpenedValueStore(); + receiveAndReconstruct(network, serializer, noOfPlayers, spdzResourcePool.getModulus()); + for (int i = 0; i < bits.size() / 2; i++) { + SpdzTriple p1p2Triple = triples.get(2 * i + 1); + SpdzTriple p2g1Triple = triples.get(2 * i); + + BigInteger p1p2E = openEpsilons.get(2 * i + 1); + openedValueStore.pushOpenedValue(epsilons.get(2 * i + 1), p1p2E); + BigInteger p2g1E = openEpsilons.get(2 * i); + openedValueStore.pushOpenedValue(epsilons.get(2 * i), p2g1E); + + BigInteger p1p2D = openDeltas.get(2 * i + 1); + openedValueStore.pushOpenedValue(deltas.get(2 * i + 1), p1p2D); + BigInteger p2g1D = openDeltas.get(2 * i); + openedValueStore.pushOpenedValue(deltas.get(2 * i), p2g1D); + + SpdzSInt p = SpdzAndBatchedProtocol.computeProduct(spdzResourcePool.getMyId(), p1p2E, p1p2D, + spdzResourcePool.getModulus(), p1p2Triple, dataSupplier.getSecretSharedKey()); + + SpdzSInt g2 = (SpdzSInt) bits.get(2 * i).getSecond().out(); + + SpdzSInt g = SpdzAndBatchedProtocol.computeProduct(spdzResourcePool.getMyId(), p2g1E, p2g1D, + spdzResourcePool.getModulus(), p2g1Triple, dataSupplier.getSecretSharedKey()) + .add(g2); + carried.add(new SIntPair(p, g)); + } + // if we have an odd number of elements the last pair can just be taken directly from the input + if (bits.size() % 2 != 0) { + carried.add(bits.get(bits.size() - 1)); + } + return EvaluationStatus.IS_DONE; + } + } + + private void serializeAndSend(Network network, ByteSerializer serializer) { + byte[] epsilonBytes = serializer.serialize( + epsilons.stream().map(SpdzSInt::getShare).collect(Collectors.toList())); + byte[] deltaBytes = serializer.serialize( + deltas.stream().map(SpdzSInt::getShare).collect(Collectors.toList())); + network.sendToAll(epsilonBytes); + network.sendToAll(deltaBytes); + } + + private void receiveAndReconstruct(Network network, ByteSerializer serializer, + int noOfParties, BigInteger modulus) { + byte[] rawEpsilons = network.receive(1); + byte[] rawDeltas = network.receive(1); + openEpsilons = serializer.deserializeList(rawEpsilons); + openDeltas = serializer.deserializeList(rawDeltas); + + for (int i = 2; i <= noOfParties; i++) { + rawEpsilons = network.receive(i); + rawDeltas = network.receive(i); + + List innerEpsilons = serializer.deserializeList(rawEpsilons); + List innerDeltas = serializer.deserializeList(rawDeltas); + for (int j = 0; j < epsilons.size(); j++) { + openEpsilons.set(j, openEpsilons.get(j).add(innerEpsilons.get(j))); + openDeltas.set(j, openDeltas.get(j).add(innerDeltas.get(j))); + } + } + + for (int j = 0; j < epsilons.size(); j++) { + openEpsilons.set(j, openEpsilons.get(j).mod(modulus)); + openDeltas.set(j, openDeltas.get(j).mod(modulus)); + } + } + + @Override + public List out() { + return carried; + } +} diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzInputProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzInputProtocol.java index 8229d81c5..73c6c6997 100644 --- a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzInputProtocol.java +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzInputProtocol.java @@ -12,11 +12,11 @@ public class SpdzInputProtocol extends SpdzNativeProtocol { - private SpdzInputMask inputMask; // is opened by this gate. + SpdzInputMask inputMask; // is opened by this gate. protected BigInteger input; - private BigInteger valueMasked; + BigInteger valueMasked; protected SpdzSInt out; - private int inputter; + int inputter; private byte[] digest; public SpdzInputProtocol(BigInteger input, int inputter) { diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzInputTwoPartyProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzInputTwoPartyProtocol.java new file mode 100644 index 000000000..9eda3776c --- /dev/null +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzInputTwoPartyProtocol.java @@ -0,0 +1,48 @@ +package dk.alexandra.fresco.suite.spdz.gates; + +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; +import dk.alexandra.fresco.suite.spdz.SpdzResourcePool; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; +import dk.alexandra.fresco.suite.spdz.storage.SpdzDataSupplier; +import java.math.BigInteger; + +public class SpdzInputTwoPartyProtocol extends SpdzInputProtocol { + + public SpdzInputTwoPartyProtocol(BigInteger input, int inputter) { + super(input, inputter); + } + + @Override + public EvaluationStatus evaluate(int round, SpdzResourcePool spdzResourcePool, + Network network) { + int myId = spdzResourcePool.getMyId(); + BigInteger modulus = spdzResourcePool.getModulus(); + SpdzDataSupplier dataSupplier = spdzResourcePool.getDataSupplier(); + ByteSerializer serializer = spdzResourcePool.getSerializer(); + if (round == 0) { + this.inputMask = dataSupplier.getNextInputMask(this.inputter); + if (myId == this.inputter) { + BigInteger bcValue = this.input.subtract(this.inputMask.getRealValue()); + bcValue = bcValue.mod(modulus); + network.sendToAll(serializer.serialize(bcValue)); + } + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + this.valueMasked = serializer.deserialize(network.receive(inputter)); + SpdzSInt valueMaskedElement = + new SpdzSInt( + valueMasked, + dataSupplier.getSecretSharedKey().multiply(valueMasked).mod(modulus), + modulus); + this.out = this.inputMask.getMask().add(valueMaskedElement, myId); + return EvaluationStatus.IS_DONE; + } + } + + @Override + public SpdzSInt out() { + return out; + } + +} diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzMacCheckProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzMacCheckProtocol.java index ec6a2c84f..2485fc436 100644 --- a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzMacCheckProtocol.java +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzMacCheckProtocol.java @@ -19,6 +19,7 @@ */ public class SpdzMacCheckProtocol implements Computation { + private static int COUNT = 0; private final SecureRandom rand; private final MessageDigest digest; private final BigInteger modulus; @@ -53,6 +54,8 @@ public SpdzMacCheckProtocol( @Override public DRes buildComputation(ProtocolBuilderNumeric builder) { +// System.out.println("SPDZ Mac Check: " + COUNT++ + " " + openedValues.size()); +// System.out.println("SPDZ Mac Check " + COUNT++ + " " + openedValues.size()); return builder .seq(seq -> { BigInteger[] rs = sampleRandomCoefficients(openedValues.size(), jointDrbg, modulus); diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzNotBatchedProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzNotBatchedProtocol.java new file mode 100644 index 000000000..1efd776e3 --- /dev/null +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzNotBatchedProtocol.java @@ -0,0 +1,39 @@ +package dk.alexandra.fresco.suite.spdz.gates; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz.SpdzResourcePool; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class SpdzNotBatchedProtocol extends SpdzNativeProtocol>> { + + private final DRes>> bits; + private List> result; + + public SpdzNotBatchedProtocol( + DRes>> bits) { + this.bits = bits; + } + + @Override + public EvaluationStatus evaluate(int round, SpdzResourcePool resourcePool, Network network) { + List> bitsOut = bits.out(); + this.result = new ArrayList<>(bitsOut.size()); + for (DRes secretBit : bitsOut) { + SpdzSInt left = + SpdzKnownSIntProtocol.createKnownSpdzElement(resourcePool, BigInteger.ONE); + SpdzSInt right = (SpdzSInt) secretBit.out(); + result.add(left.subtract(right)); + } + return EvaluationStatus.IS_DONE; + } + + @Override + public List> out() { + return result; + } +} diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzOrBatchedProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzOrBatchedProtocol.java new file mode 100644 index 000000000..ec0266c16 --- /dev/null +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzOrBatchedProtocol.java @@ -0,0 +1,137 @@ +package dk.alexandra.fresco.suite.spdz.gates; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz.SpdzResourcePool; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzTriple; +import dk.alexandra.fresco.suite.spdz.storage.SpdzDataSupplier; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class SpdzOrBatchedProtocol extends SpdzNativeProtocol>> { + + private final DRes>> leftDef; + private final DRes>> rightDef; + private List triples; + private List epsilons; + private List deltas; + private List openEpsilons; + private List openDeltas; + private List> disjunctions; + private final DRes extraBit; + + public SpdzOrBatchedProtocol(DRes>> left, DRes>> right, + DRes extraBit) { + this.leftDef = left; + this.rightDef = right; + this.extraBit = extraBit; + } + + public SpdzOrBatchedProtocol(DRes>> left, DRes>> right) { + this(left, right, null); + } + + @Override + public EvaluationStatus evaluate(int round, SpdzResourcePool spdzResourcePool, + Network network) { + SpdzDataSupplier dataSupplier = spdzResourcePool.getDataSupplier(); + int noOfPlayers = spdzResourcePool.getNoOfParties(); + ByteSerializer serializer = spdzResourcePool.getSerializer(); + final List> leftFactors = leftDef.out(); + final List> rightFactors = rightDef.out(); + if (leftFactors.size() != rightFactors.size()) { + throw new IllegalArgumentException("Lists must be same size"); + } + if (round == 0) { + triples = new ArrayList<>(leftFactors.size()); + epsilons = new ArrayList<>(leftFactors.size()); + deltas = new ArrayList<>(leftFactors.size()); + openEpsilons = new ArrayList<>(leftFactors.size()); + openDeltas = new ArrayList<>(leftFactors.size()); + disjunctions = new ArrayList<>(leftFactors.size()); + + for (int i = 0; i < leftFactors.size(); i++) { + SpdzTriple triple = dataSupplier.getNextTriple(); + triples.add(triple); + + SpdzSInt left = (SpdzSInt) leftFactors.get(i).out(); + SpdzSInt right = (SpdzSInt) rightFactors.get(i).out(); + + SpdzSInt epsilon = left.subtract(triple.getA()); + SpdzSInt delta = right.subtract(triple.getB()); + epsilons.add(epsilon); + deltas.add(delta); + } + serializeAndSend(network, serializer); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + BigInteger modulus = spdzResourcePool.getModulus(); + receiveAndReconstruct(network, serializer, noOfPlayers, modulus); + for (int i = 0; i < leftFactors.size(); i++) { + BigInteger e = openEpsilons.get(i); + BigInteger d = openDeltas.get(i); + + SpdzSInt product = SpdzAndBatchedProtocol.computeProduct(spdzResourcePool.getMyId(), + e, d, modulus, triples.get(i), dataSupplier.getSecretSharedKey()); + + SpdzSInt left = (SpdzSInt) leftFactors.get(i).out(); + SpdzSInt right = (SpdzSInt) rightFactors.get(i).out(); + // bitA + bitB - bitA * bitB + SpdzSInt disjunction = left.add(right).subtract(product); + disjunctions.add(disjunction); + // Set the opened and closed value. + spdzResourcePool.getOpenedValueStore().pushOpenedValue(epsilons.get(i), e); + spdzResourcePool.getOpenedValueStore().pushOpenedValue(deltas.get(i), d); + } + if (extraBit != null) { + disjunctions.add(extraBit); + } + return EvaluationStatus.IS_DONE; + } + } + + private void serializeAndSend(Network network, ByteSerializer serializer) { + byte[] epsilonBytes = serializer.serialize( + epsilons.stream().map(SpdzSInt::getShare).collect(Collectors.toList())); + byte[] deltaBytes = serializer.serialize( + deltas.stream().map(SpdzSInt::getShare).collect(Collectors.toList())); + network.sendToAll(epsilonBytes); + network.sendToAll(deltaBytes); + } + + private void receiveAndReconstruct(Network network, ByteSerializer serializer, + int noOfParties, BigInteger modulus) { + byte[] rawEpsilons = network.receive(1); + byte[] rawDeltas = network.receive(1); + openEpsilons = serializer.deserializeList(rawEpsilons); + openDeltas = serializer.deserializeList(rawDeltas); + + for (int i = 2; i <= noOfParties; i++) { + rawEpsilons = network.receive(i); + rawDeltas = network.receive(i); + + List innerEpsilons = serializer.deserializeList(rawEpsilons); + List innerDeltas = serializer.deserializeList(rawDeltas); + for (int j = 0; j < epsilons.size(); j++) { + openEpsilons.set(j, openEpsilons.get(j).add(innerEpsilons.get(j))); + openDeltas.set(j, openDeltas.get(j).add(innerDeltas.get(j))); + } + } + + for (int j = 0; j < epsilons.size(); j++) { + openEpsilons.set(j, openEpsilons.get(j).mod(modulus)); + openDeltas.set(j, openDeltas.get(j).mod(modulus)); + } + } + + @Override + public List> out() { + return disjunctions; + } + +} diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzOrOfListProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzOrOfListProtocol.java new file mode 100644 index 000000000..b6270c809 --- /dev/null +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzOrOfListProtocol.java @@ -0,0 +1,150 @@ +package dk.alexandra.fresco.suite.spdz.gates; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz.SpdzResourcePool; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzTriple; +import dk.alexandra.fresco.suite.spdz.storage.SpdzDataSupplier; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class SpdzOrOfListProtocol extends SpdzNativeProtocol { + + private final DRes>> bitsDef; + private SInt res; + private List> nextRound; + private List> bitsA; + private List> bitsB; + private List triples; + private List epsilons; + private List deltas; + private List openEpsilons; + private List openDeltas; + private SInt extraBit; + + public SpdzOrOfListProtocol(DRes>> left) { + this.bitsDef = left; + } + + @Override + public EvaluationStatus evaluate(int round, SpdzResourcePool spdzResourcePool, + Network network) { + SpdzDataSupplier dataSupplier = spdzResourcePool.getDataSupplier(); + int noOfPlayers = spdzResourcePool.getNoOfParties(); + ByteSerializer serializer = spdzResourcePool.getSerializer(); + +// System.out.println("Running round " + round); + if (round % 2 == 0) { + if (nextRound == null) { + nextRound = bitsDef.out(); + } + final int nextRoundSize = nextRound.size(); + if (nextRoundSize == 1) { + res = nextRound.get(0).out(); + return EvaluationStatus.IS_DONE; + } + + bitsA = new ArrayList<>(nextRoundSize / 2); + bitsB = new ArrayList<>(nextRoundSize / 2); + for (int i = 0; i < nextRoundSize - 1; i += 2) { + bitsA.add(nextRound.get(i)); + bitsB.add(nextRound.get(i + 1)); + } + triples = new ArrayList<>(nextRoundSize / 2); + epsilons = new ArrayList<>(nextRoundSize / 2); + deltas = new ArrayList<>(nextRoundSize / 2); + openEpsilons = new ArrayList<>(nextRoundSize / 2); + openDeltas = new ArrayList<>(nextRoundSize / 2); + // reset next round + final boolean isOdd = nextRoundSize % 2 != 0; + if (isOdd) { + extraBit = nextRound.get(nextRoundSize - 1).out(); + } else { + extraBit = null; + } + nextRound = new ArrayList<>(nextRoundSize / 2); + for (int i = 0; i < bitsA.size(); i++) { + SpdzTriple triple = dataSupplier.getNextTriple(); + triples.add(triple); + + SpdzSInt left = (SpdzSInt) bitsA.get(i).out(); + SpdzSInt right = (SpdzSInt) bitsB.get(i).out(); + + SpdzSInt epsilon = left.subtract(triple.getA()); + SpdzSInt delta = right.subtract(triple.getB()); + epsilons.add(epsilon); + deltas.add(delta); + } + serializeAndSend(network, serializer); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + BigInteger modulus = spdzResourcePool.getModulus(); + receiveAndReconstruct(network, serializer, noOfPlayers, modulus); + for (int i = 0; i < bitsA.size(); i++) { + BigInteger e = openEpsilons.get(i); + BigInteger d = openDeltas.get(i); + + SpdzSInt product = SpdzAndBatchedProtocol.computeProduct(spdzResourcePool.getMyId(), + e, d, modulus, triples.get(i), dataSupplier.getSecretSharedKey()); + + SpdzSInt left = (SpdzSInt) bitsA.get(i).out(); + SpdzSInt right = (SpdzSInt) bitsB.get(i).out(); + // bitA + bitB - bitA * bitB + SpdzSInt disjunction = left.add(right).subtract(product); + nextRound.add(disjunction); + // Set the opened and closed value. + spdzResourcePool.getOpenedValueStore().pushOpenedValue(epsilons.get(i), e); + spdzResourcePool.getOpenedValueStore().pushOpenedValue(deltas.get(i), d); + } + if (extraBit != null) { + nextRound.add(extraBit); + } + return EvaluationStatus.HAS_MORE_ROUNDS; + } + } + + private void serializeAndSend(Network network, ByteSerializer serializer) { + byte[] epsilonBytes = serializer.serialize( + epsilons.stream().map(SpdzSInt::getShare).collect(Collectors.toList())); + byte[] deltaBytes = serializer.serialize( + deltas.stream().map(SpdzSInt::getShare).collect(Collectors.toList())); + network.sendToAll(epsilonBytes); + network.sendToAll(deltaBytes); + } + + private void receiveAndReconstruct(Network network, ByteSerializer serializer, + int noOfParties, BigInteger modulus) { + byte[] rawEpsilons = network.receive(1); + byte[] rawDeltas = network.receive(1); + openEpsilons = serializer.deserializeList(rawEpsilons); + openDeltas = serializer.deserializeList(rawDeltas); + + for (int i = 2; i <= noOfParties; i++) { + rawEpsilons = network.receive(i); + rawDeltas = network.receive(i); + + List innerEpsilons = serializer.deserializeList(rawEpsilons); + List innerDeltas = serializer.deserializeList(rawDeltas); + for (int j = 0; j < epsilons.size(); j++) { + openEpsilons.set(j, openEpsilons.get(j).add(innerEpsilons.get(j))); + openDeltas.set(j, openDeltas.get(j).add(innerDeltas.get(j))); + } + } + + for (int j = 0; j < epsilons.size(); j++) { + openEpsilons.set(j, openEpsilons.get(j).mod(modulus)); + openDeltas.set(j, openDeltas.get(j).mod(modulus)); + } + } + + @Override + public SInt out() { + return res; + } + +} diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzTruncationPairProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzTruncationPairProtocol.java new file mode 100644 index 000000000..bc18f4058 --- /dev/null +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzTruncationPairProtocol.java @@ -0,0 +1,29 @@ +package dk.alexandra.fresco.suite.spdz.gates; + +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.TruncationPair; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.suite.spdz.SpdzResourcePool; + +public class SpdzTruncationPairProtocol extends + SpdzNativeProtocol { + + private TruncationPair pair; + private final int d; + + public SpdzTruncationPairProtocol(int d) { + this.d = d; + } + + @Override + public EvaluationStatus evaluate(int round, SpdzResourcePool resourcePool, + Network network) { + pair = resourcePool.getDataSupplier().getNextTruncationPair(d); + return EvaluationStatus.IS_DONE; + } + + @Override + public TruncationPair out() { + return pair; + } + +} diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzXorKnownBatchedProtocol.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzXorKnownBatchedProtocol.java new file mode 100644 index 000000000..c8e2587c6 --- /dev/null +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/gates/SpdzXorKnownBatchedProtocol.java @@ -0,0 +1,50 @@ +package dk.alexandra.fresco.suite.spdz.gates; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.BigIntegerOInt; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz.SpdzResourcePool; +import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class SpdzXorKnownBatchedProtocol extends SpdzNativeProtocol>> { + + private static final BigInteger TWO = BigInteger.valueOf(2); + private final DRes> left; + private final DRes>> right; + private List> result; + + public SpdzXorKnownBatchedProtocol( + DRes> left, DRes>> right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, SpdzResourcePool resourcePool, Network network) { + List leftOut = left.out(); + List> rightOut = right.out(); + if (leftOut.size() != rightOut.size()) { + throw new IllegalArgumentException("Lists must be same size"); + } + this.result = new ArrayList<>(leftOut.size()); + for (int i = 0; i < leftOut.size(); i++) { + BigInteger leftEl = ((BigIntegerOInt) leftOut.get(i)).getValue(); + SpdzSInt rightEl = (SpdzSInt) rightOut.get(i).out(); + SpdzSInt prod = rightEl.multiply(leftEl.multiply(TWO)); + SpdzSInt sum = rightEl.add( + SpdzKnownSIntProtocol.createKnownSpdzElement(resourcePool, leftEl)); + result.add(sum.subtract(prod)); + } + return EvaluationStatus.IS_DONE; + } + + @Override + public List> out() { + return result; + } +} diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzDataSupplier.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzDataSupplier.java index e57e23786..1023cceb5 100644 --- a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzDataSupplier.java +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzDataSupplier.java @@ -1,5 +1,6 @@ package dk.alexandra.fresco.suite.spdz.storage; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.TruncationPair; import dk.alexandra.fresco.lib.compare.zerotest.ZeroTestBruteforce; import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; import dk.alexandra.fresco.suite.spdz.datatypes.SpdzInputMask; @@ -62,4 +63,11 @@ public interface SpdzDataSupplier { */ SpdzSInt getNextRandomFieldElement(); + /** + * Supplies the next truncation pair (r^{prime}, r) where r = r^{prime} / 2^{d}. + * + * @param d number of shifts + */ + TruncationPair getNextTruncationPair(int d); + } diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzDummyDataSupplier.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzDummyDataSupplier.java index a8289badd..f05736778 100644 --- a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzDummyDataSupplier.java +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzDummyDataSupplier.java @@ -1,9 +1,11 @@ package dk.alexandra.fresco.suite.spdz.storage; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.TruncationPair; import dk.alexandra.fresco.framework.util.ArithmeticDummyDataSupplier; import dk.alexandra.fresco.framework.util.ModulusFinder; import dk.alexandra.fresco.framework.util.MultiplicationTripleShares; import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.util.TruncationPairShares; import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; import dk.alexandra.fresco.suite.spdz.datatypes.SpdzInputMask; import dk.alexandra.fresco.suite.spdz.datatypes.SpdzTriple; @@ -13,10 +15,13 @@ public class SpdzDummyDataSupplier implements SpdzDataSupplier { + private static int DEFAULT_MAX_BIT_LENGTH = 512; + private final int myId; private final ArithmeticDummyDataSupplier supplier; private final BigInteger modulus; - private final BigInteger secretSharedKey; + private final BigInteger wholeKey; + private final BigInteger myKeyShare; private final int expPipeLength; public SpdzDummyDataSupplier(int myId, int noOfPlayers) { @@ -31,17 +36,24 @@ public SpdzDummyDataSupplier(int myId, int noOfPlayers, BigInteger modulus) { } public SpdzDummyDataSupplier(int myId, int noOfPlayers, BigInteger modulus, - BigInteger secretSharedKey) { - this(myId, noOfPlayers, modulus, secretSharedKey, 200); + BigInteger macKey) { + this(myId, noOfPlayers, modulus, macKey, 200); } public SpdzDummyDataSupplier(int myId, int noOfPlayers, BigInteger modulus, BigInteger secretSharedKey, int expPipeLength) { + this(myId, noOfPlayers, modulus, secretSharedKey, expPipeLength, modulus.bitLength() - 1); + } + + public SpdzDummyDataSupplier(int myId, int noOfPlayers, BigInteger modulus, + BigInteger macKey, int expPipeLength, int maxBitLength) { this.myId = myId; this.modulus = modulus; - this.secretSharedKey = secretSharedKey; this.expPipeLength = expPipeLength; - this.supplier = new ArithmeticDummyDataSupplier(myId, noOfPlayers, modulus); + this.supplier = new ArithmeticDummyDataSupplier(myId, noOfPlayers, modulus, + BigInteger.ONE.shiftLeft(maxBitLength - 1)); + this.wholeKey = macKey; + this.myKeyShare = supplier.secretShare(wholeKey); } @Override @@ -55,7 +67,7 @@ public SpdzTriple getNextTriple() { @Override public SpdzSInt[] getNextExpPipe() { - List> rawExpPipe = supplier.getExpPipe(expPipeLength); + List> rawExpPipe = supplier.getExpPipe(expPipeLength); return rawExpPipe.stream() .map(this::toSpdzSInt) .toArray(SpdzSInt[]::new); @@ -63,7 +75,7 @@ public SpdzSInt[] getNextExpPipe() { @Override public SpdzInputMask getNextInputMask(int towardPlayerId) { - Pair raw = supplier.getRandomElementShare(); + Pair raw = supplier.getRandomElementShare(); if (myId == towardPlayerId) { return new SpdzInputMask(toSpdzSInt(raw), raw.getFirst()); } else { @@ -83,7 +95,7 @@ public BigInteger getModulus() { @Override public BigInteger getSecretSharedKey() { - return secretSharedKey; + return myKeyShare; } @Override @@ -91,16 +103,22 @@ public SpdzSInt getNextRandomFieldElement() { return toSpdzSInt(supplier.getRandomElementShare()); } + @Override + public TruncationPair getNextTruncationPair(int d) { + TruncationPairShares pair = supplier.getTruncationPairShares(d); + return new TruncationPair(toSpdzSInt(pair.getRPrime()), toSpdzSInt(pair.getR())); + } + private SpdzSInt toSpdzSInt(Pair raw) { return new SpdzSInt( raw.getSecond(), - raw.getFirst().multiply(secretSharedKey).mod(modulus), + raw.getSecond().multiply(wholeKey).mod(modulus), modulus ); } static private BigInteger getSsk(BigInteger modulus) { - return new BigInteger(modulus.bitLength(), new Random()).mod(modulus); + return new BigInteger(modulus.bitLength(), new Random(1)).mod(modulus); } } diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzMascotDataSupplier.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzMascotDataSupplier.java index 27775e826..e11c05d99 100644 --- a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzMascotDataSupplier.java +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzMascotDataSupplier.java @@ -1,5 +1,6 @@ package dk.alexandra.fresco.suite.spdz.storage; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.TruncationPair; import dk.alexandra.fresco.framework.network.Network; import dk.alexandra.fresco.framework.util.Drbg; import dk.alexandra.fresco.framework.util.StrictBitVector; @@ -170,6 +171,11 @@ public SpdzSInt getNextBit() { return MascotFormatConverter.toSpdzSInt(randomBits.pop()); } + @Override + public TruncationPair getNextTruncationPair(int d) { + throw new UnsupportedOperationException("Not implemented"); + } + @Override public BigInteger getModulus() { return modulus; diff --git a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzStorageDataSupplier.java b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzStorageDataSupplier.java index 8a8623f2b..738224040 100644 --- a/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzStorageDataSupplier.java +++ b/suite/spdz/src/main/java/dk/alexandra/fresco/suite/spdz/storage/SpdzStorageDataSupplier.java @@ -1,5 +1,6 @@ package dk.alexandra.fresco.suite.spdz.storage; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.TruncationPair; import dk.alexandra.fresco.framework.sce.resources.storage.StreamedStorage; import dk.alexandra.fresco.framework.sce.resources.storage.exceptions.NoMoreElementsException; import dk.alexandra.fresco.suite.spdz.datatypes.SpdzSInt; @@ -62,6 +63,11 @@ public SpdzStorageDataSupplier(StreamedStorage storage, String storageName, this.inputMaskCounters = new int[noOfParties]; } + @Override + public TruncationPair getNextTruncationPair(int d) { + throw new UnsupportedOperationException("Not implemented"); + } + @Override public SpdzTriple getNextTriple() { SpdzTriple trip; diff --git a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/MaliciousSpdzBuilder.java b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/MaliciousSpdzBuilder.java index 102645ae2..c699ba6f1 100644 --- a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/MaliciousSpdzBuilder.java +++ b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/MaliciousSpdzBuilder.java @@ -3,6 +3,7 @@ import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.builder.numeric.Numeric; import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.lib.field.integer.BasicNumericContext; import dk.alexandra.fresco.lib.real.RealNumericContext; @@ -41,6 +42,11 @@ public DRes add(BigInteger a, DRes b) { return protocolBuilder.append(spdzAddProtocolKnownLeft); } + @Override + public DRes addOpen(DRes a, DRes b) { + throw new UnsupportedOperationException(); + } + @Override public DRes sub(DRes a, DRes b) { @@ -55,6 +61,16 @@ public DRes sub(BigInteger a, DRes b) { return protocolBuilder.append(spdzSubtractProtocolKnownLeft); } + @Override + public DRes subFromOpen(DRes a, DRes b) { + throw new UnsupportedOperationException(); + } + + @Override + public DRes subOpen(DRes a, DRes b) { + throw new UnsupportedOperationException(); + } + @Override public DRes sub(DRes a, BigInteger b) { SpdzSubtractProtocolKnownRight spdzSubtractProtocolKnownRight = @@ -72,7 +88,11 @@ public DRes mult(DRes a, DRes b) { public DRes mult(BigInteger a, DRes b) { SpdzMultProtocolKnownLeft spdzMultProtocol4 = new SpdzMultProtocolKnownLeft(a, b); return protocolBuilder.append(spdzMultProtocol4); + } + @Override + public DRes multByOpen(DRes a, DRes b) { + throw new UnsupportedOperationException(); } @Override @@ -101,6 +121,16 @@ public DRes open(DRes secretShare) { return protocolBuilder.append(openProtocol); } + @Override + public DRes openAsOInt(DRes secretShare) { + throw new UnsupportedOperationException(); + } + + @Override + public DRes openAsOInt(DRes secretShare, int outputParty) { + throw new UnsupportedOperationException(); + } + @Override public DRes open(DRes secretShare, int outputParty) { SpdzOutputSingleProtocol openProtocol = diff --git a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzBasicArithmetic2Parties.java b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzBasicArithmetic2Parties.java index 69a78e5a2..e00bf5bdd 100644 --- a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzBasicArithmetic2Parties.java +++ b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzBasicArithmetic2Parties.java @@ -117,6 +117,12 @@ public void test_Lots_Of_Mults_Sequential_Batched_Different_Modulus() { PreprocessingStrategy.DUMMY, 2, 256, 128, 16); } + @Test + public void test_Lots_() { + runTest(new BasicArithmeticTests.TestLotsMult<>(), + PreprocessingStrategy.DUMMY, 2, 64, 32, 16); + } + @Test public void testOpenWithConversionMascot() { runTest(new BasicArithmeticTests.TestOpenWithConversion<>(), EvaluationStrategy.SEQUENTIAL_BATCHED, diff --git a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzComparison.java b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzComparison.java index 806b39022..3eef31fbf 100644 --- a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzComparison.java +++ b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzComparison.java @@ -4,9 +4,15 @@ import dk.alexandra.fresco.framework.sce.resources.storage.FilebasedStreamedStorageImpl; import dk.alexandra.fresco.framework.sce.resources.storage.InMemoryStorage; import dk.alexandra.fresco.lib.compare.CompareTests; +import dk.alexandra.fresco.lib.compare.CompareTests.TestLessThanLogRounds; +import dk.alexandra.fresco.lib.compare.lt.CarryOutTests; +import dk.alexandra.fresco.lib.compare.lt.CarryOutTests.TestCarryOut; +import dk.alexandra.fresco.lib.compare.lt.PreCarryTests.TestPreCarryBits; import dk.alexandra.fresco.lib.list.EliminateDuplicatesTests.TestFindDuplicatesOne; +import dk.alexandra.fresco.suite.dummy.arithmetic.AbstractDummyArithmeticTest.TestParameters; import dk.alexandra.fresco.suite.spdz.configuration.PreprocessingStrategy; import dk.alexandra.fresco.suite.spdz.storage.InitializeStorage; +import java.util.Random; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; @@ -25,6 +31,38 @@ public void test_compareLTEdge_Sequential() { PreprocessingStrategy.DUMMY, 2); } + @Test + public void testPreCarry() { + runTest(new TestPreCarryBits<>(), + PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testCarryOutZero() { + runTest(new TestCarryOut<>(0x00000000, 0x00000000), PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testCarryOutOne() { + runTest(new TestCarryOut<>(0x80000000, 0x80000000), PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testCarryOutAllOnes() { + runTest(new TestCarryOut<>(0xffffffff, 0xffffffff), PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testCarryOutOneFromCarry() { + runTest(new TestCarryOut<>(0x40000000, 0xc0000000), PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testCarryOutRandom() { + runTest(new TestCarryOut<>(new Random(42).nextInt(), new Random(1).nextInt()), + PreprocessingStrategy.DUMMY, 2); + } + @Test @Ignore("This is not tested on windows and does not work here") public void test_compareLT_Sequential_static() throws Exception { @@ -67,14 +105,17 @@ public void testCompareLTBatchedMascot() { } @Test - public void testCompareEQSequentialBatchedMascot() { - runTest(new CompareTests.TestCompareEQ<>(), EvaluationStrategy.SEQUENTIAL_BATCHED, - PreprocessingStrategy.MASCOT, 2, 64, 2, 1); + public void testLessThanLogRounds() { + int maxBitLength = 64; + runTest(new TestLessThanLogRounds<>(maxBitLength), + EvaluationStrategy.SEQUENTIAL_BATCHED, + PreprocessingStrategy.DUMMY, + 2, 128, 64, 32); } @Test - public void testCompareEQEdgeCasesBatchedMascot() { - runTest(new CompareTests.TestCompareEQEdgeCases<>(), EvaluationStrategy.SEQUENTIAL_BATCHED, + public void testCompareEQSequentialBatchedMascot() { + runTest(new CompareTests.TestCompareEQSimple<>(), EvaluationStrategy.SEQUENTIAL_BATCHED, PreprocessingStrategy.MASCOT, 2, 64, 2, 1); } diff --git a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzDEASolver2Parties.java b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzDEASolver2Parties.java index 64870d65e..71949445a 100644 --- a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzDEASolver2Parties.java +++ b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzDEASolver2Parties.java @@ -7,12 +7,14 @@ import dk.alexandra.fresco.lib.statistics.DeaSolverTests.TestDeaFixed2; import dk.alexandra.fresco.suite.spdz.configuration.PreprocessingStrategy; import java.util.Random; +import org.junit.Ignore; import org.junit.Test; /** * Tests for the DEASolver. */ +@Ignore public class TestSpdzDEASolver2Parties extends AbstractSpdzTest { @Test diff --git a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzLogical.java b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzLogical.java new file mode 100644 index 000000000..604de8a65 --- /dev/null +++ b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzLogical.java @@ -0,0 +1,51 @@ +package dk.alexandra.fresco.suite.spdz; + +import dk.alexandra.fresco.lib.math.integer.logical.LogicalOperationsTests; +import dk.alexandra.fresco.suite.spdz.configuration.PreprocessingStrategy; +import org.junit.Test; + +public class TestSpdzLogical extends AbstractSpdzTest { + + @Test + public void testXorKnown() { + runTest(new LogicalOperationsTests.TestXorKnown<>(), + PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testAndKnown() { + runTest(new LogicalOperationsTests.TestAndKnown<>(), + PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testAnd() { + runTest(new LogicalOperationsTests.TestAnd<>(), + PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testOr() { + runTest(new LogicalOperationsTests.TestOr<>(), + PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testOrOfList() { + runTest(new LogicalOperationsTests.TestOrList<>(), + PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testOrNeighbors() { + runTest(new LogicalOperationsTests.TestOrNeighbors<>(), + PreprocessingStrategy.DUMMY, 2); + } + + @Test + public void testNot() { + runTest(new LogicalOperationsTests.TestNot<>(), + PreprocessingStrategy.DUMMY, 2); + } + +} diff --git a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzRoundSynchronization.java b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzRoundSynchronization.java index e3cbb0ef6..57d8b7e87 100644 --- a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzRoundSynchronization.java +++ b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/TestSpdzRoundSynchronization.java @@ -33,7 +33,7 @@ protected SpdzProtocolSuite createProtocolSuite(int maxBitLength) { private class LowThresholdSpdzSuite extends SpdzProtocolSuite { public LowThresholdSpdzSuite(int maxBitLength, int fixedPointPrecision) { - super(maxBitLength, fixedPointPrecision); + super(maxBitLength, fixedPointPrecision, 40); } @Override diff --git a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/storage/TestSpdzDummyDataSupplier.java b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/storage/TestSpdzDummyDataSupplier.java index 3bfe7000e..18233061d 100644 --- a/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/storage/TestSpdzDummyDataSupplier.java +++ b/suite/spdz/src/test/java/dk/alexandra/fresco/suite/spdz/storage/TestSpdzDummyDataSupplier.java @@ -34,9 +34,9 @@ private List setupSuppliers(int noOfParties, BigInteger modulus, int expPipeLength) { List suppliers = new ArrayList<>(noOfParties); Random random = new Random(); + BigInteger macKey = new BigInteger(modulus.bitLength(), random).mod(modulus); for (int i = 0; i < noOfParties; i++) { - BigInteger macKeyShare = new BigInteger(modulus.bitLength(), random).mod(modulus); - suppliers.add(new SpdzDummyDataSupplier(i + 1, noOfParties, modulus, macKeyShare, + suppliers.add(new SpdzDummyDataSupplier(i + 1, noOfParties, modulus, macKey, expPipeLength)); } return suppliers; @@ -202,10 +202,14 @@ public void testGetNextRandomFieldElement() { @Test public void testGetters() { - SpdzDummyDataSupplier supplier = new SpdzDummyDataSupplier(1, 2, moduli.get(0), + final BigInteger mod = moduli.get(0); + SpdzDummyDataSupplier supplier = new SpdzDummyDataSupplier(1, 2, mod, BigInteger.ONE); - assertEquals(moduli.get(0), supplier.getModulus()); - assertEquals(BigInteger.ONE, supplier.getSecretSharedKey()); + SpdzDummyDataSupplier supplierTwo = new SpdzDummyDataSupplier(2, 2, mod, + BigInteger.ONE); + assertEquals(mod, supplier.getModulus()); + assertEquals(BigInteger.ONE, + supplier.getSecretSharedKey().add(supplierTwo.getSecretSharedKey()).mod(mod)); } private SpdzSInt recombine(List shares) { diff --git a/suite/spdz2k/pom.xml b/suite/spdz2k/pom.xml index 4ad786f5f..8294d6052 100644 --- a/suite/spdz2k/pom.xml +++ b/suite/spdz2k/pom.xml @@ -30,6 +30,24 @@ test-jar test + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + test-jar + + + + + + + diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kAdvancedNumeric.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kAdvancedNumeric.java new file mode 100644 index 000000000..d143bfa74 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kAdvancedNumeric.java @@ -0,0 +1,25 @@ +package dk.alexandra.fresco.suite.spdz2k; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.numeric.BuilderFactoryNumeric; +import dk.alexandra.fresco.framework.builder.numeric.DefaultAdvancedNumeric; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kTruncationPairProtocol; + +/** + * Spdz2k-specific advanced numeric functionality. + */ +public class Spdz2kAdvancedNumeric extends DefaultAdvancedNumeric { + + Spdz2kAdvancedNumeric( + BuilderFactoryNumeric factoryNumeric, + ProtocolBuilderNumeric builder) { + super(factoryNumeric, builder); + } + + @Override + public DRes generateTruncationPair(int d) { + return builder.seq(seq -> seq.append(new Spdz2kTruncationPairProtocol<>(d))); + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kBuilder.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kBuilder.java index 8a71409c5..e4105bb60 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kBuilder.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kBuilder.java @@ -1,27 +1,38 @@ package dk.alexandra.fresco.suite.spdz2k; import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric; import dk.alexandra.fresco.framework.builder.numeric.BuilderFactoryNumeric; +import dk.alexandra.fresco.framework.builder.numeric.Comparison; +import dk.alexandra.fresco.framework.builder.numeric.Conversion; +import dk.alexandra.fresco.framework.builder.numeric.DefaultLogical; +import dk.alexandra.fresco.framework.builder.numeric.Logical; import dk.alexandra.fresco.framework.builder.numeric.Numeric; import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntArithmetic; +import dk.alexandra.fresco.framework.value.OIntFactory; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.lib.compare.MiscBigIntegerGenerators; import dk.alexandra.fresco.lib.field.integer.BasicNumericContext; import dk.alexandra.fresco.lib.real.RealNumericContext; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; -import dk.alexandra.fresco.suite.spdz2k.protocols.computations.Spdz2kInputComputation; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.InputComputationSpdz2k; import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kAddKnownProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kAddProtocol; import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kKnownSIntProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kMultKnownProtocol; import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kMultiplyProtocol; import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kOutputSinglePartyProtocol; -import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kOutputToAllProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kOutputToAll; import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kRandomBitProtocol; import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kRandomElementProtocol; import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kSubtractFromKnownProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kSubtractProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kTwoPartyInputProtocol; import java.math.BigInteger; -import java.util.Objects; /** * Basic native builder for the SPDZ2k protocol suite. @@ -33,10 +44,19 @@ public class Spdz2kBuilder> implements private final CompUIntFactory factory; private final BasicNumericContext numericContext; - - public Spdz2kBuilder(CompUIntFactory factory, BasicNumericContext numericContext) { + private final RealNumericContext realNumericContext; + private final boolean useBooleanMode; + private final CompUIntArithmetic uIntArithmetic; + + public Spdz2kBuilder(CompUIntFactory factory, + BasicNumericContext numericContext, + RealNumericContext realNumericContext, + boolean useBooleanMode) { this.factory = factory; + this.uIntArithmetic = new CompUIntArithmetic<>(factory); this.numericContext = numericContext; + this.realNumericContext = realNumericContext; + this.useBooleanMode = useBooleanMode; } @Override @@ -44,12 +64,36 @@ public BasicNumericContext getBasicNumericContext() { return numericContext; } + @Override + public Comparison createComparison(ProtocolBuilderNumeric builder) { + if (!useBooleanMode) { + throw new IllegalStateException( + "Need to enable boolean mode to perform comparisons in spdz2k"); + } else { + return new Spdz2kComparison<>(this, builder, factory); + } + } + + @Override + public Logical createLogical(ProtocolBuilderNumeric builder) { + if (useBooleanMode) { + return new Spdz2kLogicalBooleanMode<>(builder, factory); + } else { + return new Spdz2kLogical(builder); + } + } + + @Override + public AdvancedNumeric createAdvancedNumeric(ProtocolBuilderNumeric builder) { + return new Spdz2kAdvancedNumeric(this, builder); + } + @Override public Numeric createNumeric(ProtocolBuilderNumeric builder) { return new Numeric() { @Override public DRes add(DRes a, DRes b) { - return () -> toSpdz2kSInt(a).add(toSpdz2kSInt(b)); + return builder.append(new Spdz2kAddProtocol<>(a, b)); } @Override @@ -57,9 +101,14 @@ public DRes add(BigInteger a, DRes b) { return builder.append(new Spdz2kAddKnownProtocol<>(factory.createFromBigInteger(a), b)); } + @Override + public DRes addOpen(DRes a, DRes b) { + return builder.append(new Spdz2kAddKnownProtocol<>(factory.fromOInt(a), b)); + } + @Override public DRes sub(DRes a, DRes b) { - return () -> (toSpdz2kSInt(a)).subtract(toSpdz2kSInt(b)); + return builder.append(new Spdz2kSubtractProtocol<>(a, b)); } @Override @@ -68,6 +117,17 @@ public DRes sub(BigInteger a, DRes b) { new Spdz2kSubtractFromKnownProtocol<>(factory.createFromBigInteger(a), b)); } + @Override + public DRes subFromOpen(DRes a, DRes b) { + return builder.append(new Spdz2kSubtractFromKnownProtocol<>(a, b)); + } + + @Override + public DRes subOpen(DRes a, DRes b) { + return builder.append( + new Spdz2kAddKnownProtocol<>(factory.fromOInt(b).negate(), a)); + } + @Override public DRes sub(DRes a, BigInteger b) { return builder.append( @@ -81,7 +141,12 @@ public DRes mult(DRes a, DRes b) { @Override public DRes mult(BigInteger a, DRes b) { - return () -> toSpdz2kSInt(b).multiply(factory.createFromBigInteger(a)); + return multByOpen(factory.createFromBigInteger(a), b); + } + + @Override + public DRes multByOpen(DRes a, DRes b) { + return builder.append(new Spdz2kMultKnownProtocol<>(a, b)); } @Override @@ -96,44 +161,82 @@ public DRes randomElement() { @Override public DRes known(BigInteger value) { - return builder.append(new Spdz2kKnownSIntProtocol<>(factory.createFromBigInteger(value))); + return builder.append(new Spdz2kKnownSIntProtocol<>( + (value != null) ? factory.fromLong(value.longValue()) : null)); } @Override public DRes input(BigInteger value, int inputParty) { - return builder.seq( - new Spdz2kInputComputation<>(factory.createFromBigInteger(value), inputParty) - ); + PlainT val = (value != null) ? factory.fromLong(value.longValue()) : null; + if (builder.getBasicNumericContext().getNoOfParties() <= 2) { + return builder.append(new Spdz2kTwoPartyInputProtocol<>(val, inputParty)); + } else { + return builder.seq(new InputComputationSpdz2k<>(val, inputParty)); + } + } + + @Override + public DRes openAsOInt(DRes secretShare) { + return builder.append(new Spdz2kOutputToAll<>(secretShare)); } @Override public DRes open(DRes secretShare) { - return builder.append(new Spdz2kOutputToAllProtocol<>(secretShare)); + DRes out = openAsOInt(secretShare); + return () -> factory.fromOInt(out).toBigInteger(); } @Override - public DRes open(DRes secretShare, int outputParty) { + public DRes openAsOInt(DRes secretShare, int outputParty) { return builder.append(new Spdz2kOutputSinglePartyProtocol<>(secretShare, outputParty)); } + + @Override + public DRes open(DRes secretShare, int outputParty) { + DRes out = openAsOInt(secretShare, outputParty); + return () -> { + OInt res = out.out(); + if (res == null) { + return null; + } else { + return factory.fromOInt(out).toBigInteger(); + } + }; + } }; } + @Override + public Conversion createConversion(ProtocolBuilderNumeric builder) { + return new Spdz2kConversion(builder); + } + @Override public MiscBigIntegerGenerators getBigIntegerHelper() { throw new UnsupportedOperationException(); } - /** - * Get result from deferred and downcast result to {@link Spdz2kSInt}. - */ - private Spdz2kSInt toSpdz2kSInt(DRes value) { - return Objects.requireNonNull((Spdz2kSInt) value.out()); + @Override + public OIntFactory getOIntFactory() { + return factory; + } + + @Override + public OIntArithmetic getOIntArithmetic() { + return uIntArithmetic; } @Override public RealNumericContext getRealNumericContext() { - // TODO Auto-generated method stub - return null; + return realNumericContext; + } + + class Spdz2kLogical extends DefaultLogical { + + Spdz2kLogical( + ProtocolBuilderNumeric builder) { + super(builder); + } } } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kComparison.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kComparison.java new file mode 100644 index 000000000..186b4de74 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kComparison.java @@ -0,0 +1,76 @@ +package dk.alexandra.fresco.suite.spdz2k; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.numeric.BuilderFactoryNumeric; +import dk.alexandra.fresco.framework.builder.numeric.DefaultComparison; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.eq.ZeroTestSpdz2k; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.lt.MostSignBitSpdz2k; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kCarryProtocol; +import java.util.List; + +/** + * Spdz2k optimized protocols for comparison. + */ +public class Spdz2kComparison> extends DefaultComparison { + + private final CompUIntFactory factory; + + protected Spdz2kComparison( + BuilderFactoryNumeric factoryNumeric, + ProtocolBuilderNumeric builder, CompUIntFactory factory) { + super(factoryNumeric, builder); + this.factory = factory; + } + + @Override + public DRes compareLT(DRes x1, DRes x2, Algorithm algorithm) { + if (algorithm == Algorithm.CONST_ROUNDS) { + throw new UnsupportedOperationException( + "No constant round comparison protocol implemented for Spdz2k"); + } else { + DRes diff = builder.numeric().sub(x1, x2); + return builder.seq(new MostSignBitSpdz2k<>(diff, factory)); + } + } + + @Override + public DRes compareLTBits(DRes openValue, DRes>> secretBits) { + DRes>> converted = builder.conversion().toBooleanBatch(secretBits); + return super.compareLTBits(openValue, converted); + } + + @Override + public DRes compareZero(DRes x, int bitLength, Algorithm algorithm) { + if (bitLength > factory.getLowBitLength()) { + throw new IllegalArgumentException( + "Only support bit lengths up to " + factory.getLowBitLength()); + } + if (algorithm == Algorithm.CONST_ROUNDS) { + throw new UnsupportedOperationException( + "No constant round zero test protocol implemented for Spdz2k"); + } else { + return builder.seq(new ZeroTestSpdz2k<>(x, factory)); + } + } + + @Override + public DRes equals(DRes x, DRes y, int bitlength, Algorithm algorithm) { + return compareZero(builder.numeric().sub(x, y), bitlength, algorithm); + } + + @Override + public DRes> carry(List bitPairs) { + return builder.append(new Spdz2kCarryProtocol<>(bitPairs)); + } + + protected CompUIntFactory getFactory() { + return factory; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kConversion.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kConversion.java new file mode 100644 index 000000000..4bf9ad3c9 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kConversion.java @@ -0,0 +1,57 @@ +package dk.alexandra.fresco.suite.spdz2k; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.numeric.Conversion; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kArithmeticToBooleanProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kBooleanToArithmeticProtocol; +import java.util.ArrayList; +import java.util.List; + +/** + * Spdz2k optimized protocols for converting between arithmetic and boolean representations. + */ +public class Spdz2kConversion implements Conversion { + + private final ProtocolBuilderNumeric builder; + + public Spdz2kConversion(ProtocolBuilderNumeric builder) { + this.builder = builder; + } + + @Override + public DRes toBoolean(DRes arithmeticValue) { + return builder.append(new Spdz2kArithmeticToBooleanProtocol<>(arithmeticValue)); + } + + @Override + public DRes toArithmetic(DRes booleanValue) { + return builder.append(new Spdz2kBooleanToArithmeticProtocol<>(booleanValue)); + } + + @Override + public DRes>> toBooleanBatch(DRes>> arithmeticBatch) { + return builder.par(par -> { + List> inner = arithmeticBatch.out(); + List> converted = new ArrayList<>(inner.size()); + for (DRes anInner : inner) { + converted.add(par.conversion().toBoolean(anInner)); + } + return () -> converted; + }); + } + + @Override + public DRes>> toArithmeticBatch(DRes>> booleanBatch) { + return builder.par(par -> { + List> inner = booleanBatch.out(); + List> converted = new ArrayList<>(inner.size()); + for (DRes anInner : inner) { + converted.add(par.conversion().toArithmetic(anInner)); + } + return () -> converted; + }); + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kLogicalBooleanMode.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kLogicalBooleanMode.java new file mode 100644 index 000000000..06c422d26 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kLogicalBooleanMode.java @@ -0,0 +1,129 @@ +package dk.alexandra.fresco.suite.spdz2k; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.numeric.DefaultLogical; +import dk.alexandra.fresco.framework.builder.numeric.Logical; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.OrNeighborsComputationSpdz2k; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kAndBatchedProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kAndKnownBatchedProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kAndKnownProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kAndProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kNotBatchedProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kOrBatchedProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kOrOfListProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kOrProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kOutputToAll; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kXorKnownBatchedProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kXorKnownProtocol; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kXorProtocol; +import java.util.List; + +/** + * Logical operators for Spdz2k on boolean shares.

NOTE: requires that inputs have previously + * been converted to boolean shares!

+ */ +public class Spdz2kLogicalBooleanMode> extends + DefaultLogical implements Logical { + + private final CompUIntFactory factory; + + protected Spdz2kLogicalBooleanMode( + ProtocolBuilderNumeric builder, CompUIntFactory factory) { + super(builder); + this.factory = factory; + } + + @Override + public DRes and(DRes bitA, DRes bitB) { + return builder.append(new Spdz2kAndProtocol<>(bitA, bitB)); + } + + @Override + public DRes or(DRes bitA, DRes bitB) { + return builder.append(new Spdz2kOrProtocol<>(bitA, bitB)); + } + + @Override + public DRes xor(DRes bitA, DRes bitB) { + return builder.append(new Spdz2kXorProtocol<>(bitA, bitB)); + } + + @Override + public DRes halfOr(DRes bitA, DRes bitB) { + return xor(bitA, bitB); + } + + @Override + public DRes andKnown(DRes knownBit, DRes secretBit) { + return builder.append(new Spdz2kAndKnownProtocol<>(knownBit, secretBit)); + } + + @Override + public DRes>> pairWiseAndKnown(DRes> knownBits, + DRes>> secretBits) { + return builder.append(new Spdz2kAndKnownBatchedProtocol<>(knownBits, secretBits)); + } + + @Override + public DRes>> pairWiseAnd(DRes>> bitsA, + DRes>> bitsB) { + return builder.append(new Spdz2kAndBatchedProtocol<>(bitsA, bitsB)); + } + + @Override + public DRes>> batchedNot(DRes>> bits) { + return builder.append(new Spdz2kNotBatchedProtocol<>(bits)); + } + + @Override + public DRes>> pairWiseXorKnown(DRes> knownBits, + DRes>> secretBits) { + return builder.append(new Spdz2kXorKnownBatchedProtocol<>(knownBits, secretBits)); + } + + @Override + public DRes xorKnown(DRes knownBit, DRes secretBit) { + return builder.append(new Spdz2kXorKnownProtocol<>(knownBit, secretBit)); + } + + @Override + public DRes not(DRes secretBit) { + return xorKnown(builder.getOIntFactory().one(), secretBit); + } + + @Override + public DRes>> pairWiseOr(DRes>> bitsA, + DRes>> bitsB) { + return builder.append(new Spdz2kOrBatchedProtocol<>(bitsA, bitsB)); + } + + @Override + public DRes orOfList(DRes>> bits) { + return builder.append(new Spdz2kOrOfListProtocol<>(bits)); + } + + @Override + public DRes>> orNeighbors(List> bits) { + return builder.seq(new OrNeighborsComputationSpdz2k(bits)); + } + + @Override + public DRes openAsBit(DRes secretBit) { + // quite heavy machinery... + return builder.seq(seq -> { + Spdz2kSIntBoolean bit = factory.toSpdz2kSIntBoolean(secretBit); + return seq.append(new Spdz2kOutputToAll<>(bit.asArithmetic())); + }).seq((seq, opened) -> { + PlainT openBit = factory.fromOInt(opened); + // TODO clean up + return openBit.testBit(factory.getLowBitLength() - 1) ? factory.one() : factory.zero(); + }); + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite.java index 6a5904e56..60b1b273b 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite.java @@ -3,6 +3,7 @@ import dk.alexandra.fresco.framework.builder.numeric.BuilderFactoryNumeric; import dk.alexandra.fresco.framework.network.Network; import dk.alexandra.fresco.lib.field.integer.BasicNumericContext; +import dk.alexandra.fresco.lib.real.RealNumericContext; import dk.alexandra.fresco.suite.ProtocolSuiteNumeric; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntConverter; @@ -29,7 +30,11 @@ public abstract class Spdz2kProtocolSuite< PlainT extends CompUInt> implements ProtocolSuiteNumeric> { + private static final int DEFAULT_FIXED_POINT_PRECISION = 16; + private final CompUIntConverter converter; + private final boolean useBooleanMode; + private final int fixedPointPrecision; /** * Constructs new {@link Spdz2kProtocolSuite}. @@ -37,14 +42,34 @@ public abstract class Spdz2kProtocolSuite< * @param converter helper which allows converting {@link HighT}, and {@link LowT} instances to * {@link PlainT}. This is necessary for the mac-check protocol where we perform arithmetic * between these different types. + * @param useBooleanMode flag for switching to boolean shares for logical operations */ - Spdz2kProtocolSuite(CompUIntConverter converter) { + Spdz2kProtocolSuite(CompUIntConverter converter, + boolean useBooleanMode, + int fixedPointPrecision) { this.converter = converter; + this.useBooleanMode = useBooleanMode; + this.fixedPointPrecision = fixedPointPrecision; + } + + Spdz2kProtocolSuite(CompUIntConverter converter, int fixedPointPrecision) { + this(converter, false, fixedPointPrecision); + } + + Spdz2kProtocolSuite(CompUIntConverter converter, boolean useBooleanMode) { + this(converter, useBooleanMode, DEFAULT_FIXED_POINT_PRECISION); + } + + Spdz2kProtocolSuite(CompUIntConverter converter) { + this(converter, false, DEFAULT_FIXED_POINT_PRECISION); } @Override public BuilderFactoryNumeric init(Spdz2kResourcePool resourcePool, Network network) { - return new Spdz2kBuilder<>(resourcePool.getFactory(), createBasicNumericContext(resourcePool)); + return new Spdz2kBuilder<>(resourcePool.getFactory(), + createBasicNumericContext(resourcePool), + createRealNumericContext(), + useBooleanMode); } @Override @@ -58,4 +83,8 @@ public BasicNumericContext createBasicNumericContext(Spdz2kResourcePool resourcePool.getNoOfParties()); } + public RealNumericContext createRealNumericContext() { + return new RealNumericContext(fixedPointPrecision); + } + } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite128.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite128.java index fa33f4376..93d9a2b0b 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite128.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite128.java @@ -9,8 +9,12 @@ */ public class Spdz2kProtocolSuite128 extends Spdz2kProtocolSuite { + public Spdz2kProtocolSuite128(boolean useBooleanMode) { + super(new CompUIntConverter128(), useBooleanMode); + } + public Spdz2kProtocolSuite128() { - super(new CompUIntConverter128()); + this(false); } } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite64.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite64.java new file mode 100644 index 000000000..f7904e7ba --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite64.java @@ -0,0 +1,20 @@ +package dk.alexandra.fresco.suite.spdz2k; + +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt64; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntConverter64; +import dk.alexandra.fresco.suite.spdz2k.datatypes.UInt32; + +/** + * Protocol suite using {@link CompUInt64} as the underlying plain-value type. + */ +public class Spdz2kProtocolSuite64 extends Spdz2kProtocolSuite { + + public Spdz2kProtocolSuite64(boolean useBooleanMode) { + super(new CompUIntConverter64(), useBooleanMode); + } + + public Spdz2kProtocolSuite64() { + this(false); + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite96.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite96.java deleted file mode 100644 index d4adc0d6c..000000000 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuite96.java +++ /dev/null @@ -1,17 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k; - -import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt96; -import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntConverter96; -import dk.alexandra.fresco.suite.spdz2k.datatypes.UInt32; -import dk.alexandra.fresco.suite.spdz2k.datatypes.UInt64; - -/** - * Protocol suite using {@link CompUInt96} as the underlying plain-value type. - */ -public class Spdz2kProtocolSuite96 extends Spdz2kProtocolSuite { - - Spdz2kProtocolSuite96() { - super(new CompUIntConverter96()); - } - -} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuiteGeneric.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuiteGeneric.java deleted file mode 100644 index 009167ada..000000000 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kProtocolSuiteGeneric.java +++ /dev/null @@ -1,16 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k; - -import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntConverterGeneric; -import dk.alexandra.fresco.suite.spdz2k.datatypes.GenericCompUInt; - -/** - * Protocol suite using {@link GenericCompUInt} as the underlying plain-value type. - */ -public class Spdz2kProtocolSuiteGeneric extends - Spdz2kProtocolSuite { - - Spdz2kProtocolSuiteGeneric(int highBitLength, int lowBitLength) { - super(new CompUIntConverterGeneric(highBitLength, lowBitLength)); - } - -} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt.java index 93baf009b..4423e5c7c 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt.java @@ -1,5 +1,7 @@ package dk.alexandra.fresco.suite.spdz2k.datatypes; +import dk.alexandra.fresco.framework.value.OInt; + /** * An unsigned integer conceptually composed of two other unsigned integers.

Composite integers * have a bit length of t = s + k, where the s most significant bits can be viewed as a s-bit @@ -9,7 +11,7 @@ public interface CompUInt< HighT extends UInt, LowT extends UInt, - CompT extends UInt> extends UInt { + CompT extends UInt> extends UInt, OInt { /** * Get the s most significant bits as an unsigned integer of type {@link HighT}. @@ -26,11 +28,66 @@ public interface CompUInt< */ HighT getLeastSignificantAsHigh(); + /** + * Left shift by n bits where n < k.

Result of a shift by n >= k is undefined. A shift for n <= + * 0 returns this, unchanged.

+ */ + CompT shiftLeftSmall(int n); + + /** + * Unsigned right shift by n bits where n < k.

Result of a shift by n >= k is undefined. A + * shift for n <= 0 returns this, unchanged.

+ */ + CompT shiftRightSmall(int n); + + /** + * Unsigned right shift by n bits where n < k in the least significant bits only. + */ + CompT shiftRightLowOnly(int n); + /** * Left-shift the k least significant bits by k. */ CompT shiftLowIntoHigh(); + /** + * Clears all bits above bitPos, i.e., (k + s) - bitPos most significant bits.

Analogous to + * computing this mod 2^{bitPos}.

+ */ + CompT clearAboveBitAt(int bitPos); + + /** + * Sets s most significant bits to 0. + */ + CompT clearHighBits(); + + /** + * Converts this to bit representation. + */ + CompT toBitRep(); + + /** + * Converts this to arithmetic representation. + */ + CompT toArithmeticRep(); + + /** + * Computes product of this and value. + */ + CompT multiplyByBit(int value); + + /** + * Returns result of {@link #testBit(int)} as UInt. + */ + CompT testBitAsUInt(int bit); + + /** + * Returns bit value of this as integer. + */ + default int bitValue() { + throw new IllegalStateException("Only supported by bit representations"); + } + /** * Get length of least significant bit segment, i.e., k. */ @@ -53,6 +110,10 @@ default int getBitLength() { return getCompositeBitLength(); } + default byte[] serializeLeastSignificant() { + return getLeastSignificant().toByteArray(); + } + /** * Util for padding a byte array up to the required bit length.

Since we are working with * unsigned ints, the first byte of the passed in array is discarded if it's a zero byte.

diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128.java index 93db9ec63..a7e08c839 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128.java @@ -1,5 +1,7 @@ package dk.alexandra.fresco.suite.spdz2k.datatypes; +import dk.alexandra.fresco.framework.util.ByteAndBitConverter; +import dk.alexandra.fresco.framework.value.OInt; import java.math.BigInteger; /** @@ -10,9 +12,10 @@ public class CompUInt128 implements CompUInt { private static final CompUInt128 ONE = new CompUInt128(1); - private final long high; - private final int mid; - private final int low; + private static final CompUInt128 ZERO = new CompUInt128(0); + protected final long high; + protected final int mid; + final int low; /** * Creates new {@link CompUInt128}.

Do not pad bytes by default.

@@ -34,12 +37,12 @@ public CompUInt128(byte[] bytes, boolean requiresPadding) { if (padded.length == 8) { // we are instantiating from the least significant bits only this.high = 0L; - this.mid = toInt(padded, 4); - this.low = toInt(padded, 0); + this.mid = ByteAndBitConverter.toInt(padded, 4); + this.low = ByteAndBitConverter.toInt(padded, 0); } else { - this.high = toLong(padded, 8); - this.mid = toInt(padded, 4); - this.low = toInt(padded, 0); + this.high = ByteAndBitConverter.toLong(padded, 8); + this.mid = ByteAndBitConverter.toInt(padded, 4); + this.low = ByteAndBitConverter.toInt(padded, 0); } } @@ -47,7 +50,11 @@ public CompUInt128(byte[] bytes, boolean requiresPadding) { * Creates new {@link CompUInt128} from {@link BigInteger}. */ public CompUInt128(BigInteger value) { - this(value.toByteArray(), true); + this(value.shiftRight(64).longValue(), value.shiftRight(32).intValue(), value.intValue()); + } + + public CompUInt128(BigInteger value, boolean lowOnly) { + this(value.longValue()); } CompUInt128(long high, int mid, int low) { @@ -124,6 +131,14 @@ public CompUInt128 multiply(CompUInt128 other) { @Override public CompUInt128 subtract(CompUInt128 other) { +// long newLow = Integer.toUnsignedLong(this.low) - Integer.toUnsignedLong(other.low); +// long lowOverflow = newLow >>> 32; +// long newMid = Integer.toUnsignedLong(this.mid) +// - Integer.toUnsignedLong(other.mid) +// - lowOverflow; +// long midOverflow = newMid >>> 32; +// long newHigh = this.high - other.high - midOverflow; +// return new CompUInt128(newHigh, (int) newMid, (int) newLow); return this.add(other.negate()); } @@ -137,6 +152,11 @@ public boolean isZero() { return low == 0 && mid == 0 && high == 0; } + @Override + public boolean isOne() { + return low == 1 && mid == 0 && high == 0; + } + @Override public BigInteger toBigInteger() { return new BigInteger(1, toByteArray()); @@ -157,6 +177,51 @@ public UInt64 getLeastSignificantAsHigh() { return getLeastSignificant(); } + @Override + public CompUInt128 shiftLeftSmall(int n) { + if (n >= Long.SIZE) { + throw new IllegalArgumentException( + "Shift step must be less than " + Long.SIZE + " but was " + n); + } + if (n <= 0) { + return this; + } + int nInv = (Long.SIZE - n); + long midAndLow = (UInt.toUnLong(mid) << 32) | UInt.toUnLong(low); + long newHigh = (high << n) | (midAndLow >>> nInv); + long midAndLowShifted = midAndLow << n; + return new CompUInt128(newHigh, (int) (midAndLowShifted >>> 32), (int) midAndLowShifted); + } + + @Override + public CompUInt128 shiftRightSmall(int n) { + if (n >= Long.SIZE) { + throw new IllegalArgumentException( + "Shift step must be less than " + Long.SIZE + " but was " + n); + } + if (n <= 0) { + return this; + } + int nInv = (Long.SIZE - n); + long midAndLow = (UInt.toUnLong(mid) << 32) | UInt.toUnLong(low); + long newHigh = high >>> n; + long midAndLowShifted = (high << nInv) | (midAndLow >>> n); + return new CompUInt128(newHigh, (int) (midAndLowShifted >>> 32), (int) midAndLowShifted); + } + + @Override + public CompUInt128 shiftRightLowOnly(int n) { + if (n >= Long.SIZE) { + throw new IllegalArgumentException( + "Shift step must be less than " + Long.SIZE + " but was " + n); + } + if (n <= 0) { + return this; + } + long midAndLow = ((UInt.toUnLong(mid) << 32) | UInt.toUnLong(low)) >>> n; + return new CompUInt128(high, (int) (midAndLow >>> 32), (int) midAndLow); + } + @Override public long toLong() { return (UInt.toUnLong(this.mid) << 32) + UInt.toUnLong(this.low); @@ -172,6 +237,48 @@ public CompUInt128 shiftLowIntoHigh() { return new CompUInt128(toLong(), 0, 0); } + @Override + public CompUInt128 clearAboveBitAt(int bitPos) { + if (bitPos < Integer.SIZE) { + int mask = ~(0x80000000 >> (31 - bitPos)); + return new CompUInt128(0L, 0, low & mask); + } else if (bitPos < Long.SIZE) { + int mask = ~(0x80000000 >> (63 - bitPos)); + return new CompUInt128(0L, mid & mask, low); + } else { + long mask = ~(0x8000000000000000L >> (127 - bitPos)); + return new CompUInt128(high & mask, mid, low); + } + } + + @Override + public int bitValue() { + return low & 1; // lowest bit + } + + @Override + public CompUInt128 multiplyByBit(int value) { + return multiply(new CompUInt128(0L, 0, value)); + } + + @Override + public CompUInt128 clearHighBits() { + return new CompUInt128(0, mid, low); + } + + @Override + public CompUInt128 toBitRep() { + return new CompUInt128Bit( + (high << 63) + (UInt.toUnLong(mid) << 31) + (UInt.toUnLong(low) >>> 1), + low << 31, + 0); + } + + @Override + public CompUInt128 toArithmeticRep() { + throw new IllegalStateException("Already arithmetic"); + } + @Override public int getLowBitLength() { return 64; @@ -196,6 +303,34 @@ public byte[] toByteArray() { return bytes; } + @Override + public boolean testBit(int bit) { + // TODO optimize if bottle-neck + long section; + int relative; + if (bit < Integer.SIZE) { + section = low; + relative = bit; + } else if (bit < Long.SIZE) { + section = mid; + relative = bit - Integer.SIZE; + } else { + section = high; + relative = bit - Long.SIZE; + } + return (((1L << relative) & section) >>> relative) == 1; + } + + @Override + public CompUInt128 testBitAsUInt(int bit) { + return testBit(bit) ? ONE : ZERO; + } + + @Override + public OInt out() { + return this; + } + private void toByteArrayLong(byte[] bytes, int start, long value) { int offset = bytes.length - start - 1; for (int i = 0; i < 8; i++) { @@ -212,24 +347,4 @@ private void toByteArray(byte[] bytes, int start, int value) { } } - private static long toLong(byte[] bytes, int start) { - int flipped = bytes.length - start - 1; - return (bytes[flipped] & 0xFFL) - | (bytes[flipped - 1] & 0xFFL) << 8 - | (bytes[flipped - 2] & 0xFFL) << 16 - | (bytes[flipped - 3] & 0xFFL) << 24 - | (bytes[flipped - 4] & 0xFFL) << 32 - | (bytes[flipped - 5] & 0xFFL) << 40 - | (bytes[flipped - 6] & 0xFFL) << 48 - | (bytes[flipped - 7] & 0xFFL) << 56; - } - - private static int toInt(byte[] bytes, int start) { - int flipped = bytes.length - start - 1; - return (bytes[flipped] & 0xFF) - | (bytes[flipped - 1] & 0xFF) << 8 - | (bytes[flipped - 2] & 0xFF) << 16 - | (bytes[flipped - 3] & 0xFF) << 24; - } - } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128Bit.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128Bit.java new file mode 100644 index 000000000..183a947bc --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128Bit.java @@ -0,0 +1,74 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +public class CompUInt128Bit extends CompUInt128 { + + public CompUInt128Bit(long high, int mid, int low) { + super(high, mid, low); + } + + public CompUInt128Bit(long high, int bit) { + super(high, bit << 31, 0); + } + + @Override + public CompUInt128 multiply(CompUInt128 other) { + int bit = mid >>> 31; + int otherBit = other.mid >>> 31; + return new CompUInt128Bit( + ((high * other.high) << 1) + (high * otherBit) + (other.high * bit), + mid & other.mid, + 0); + } + + @Override + public CompUInt128 add(CompUInt128 other) { + int carry = ((mid >>> 31) + (other.mid >>> 31)) >> 1; + return new CompUInt128Bit(high + other.high + carry, mid ^ other.mid, 0); + } + + @Override + public CompUInt128 subtract(CompUInt128 other) { + throw new UnsupportedOperationException("Subtraction not supported by bit representation"); + } + + @Override + public CompUInt128 negate() { + throw new UnsupportedOperationException("Negation not supported by bit representation"); + } + + @Override + public CompUInt128 toBitRep() { + throw new IllegalStateException("Already in bit form"); + } + + @Override + public CompUInt128 toArithmeticRep() { + return new CompUInt128(high, mid, low); + } + + @Override + public String toString() { + return toBigInteger().toString() + "B"; + } + + @Override + public byte[] serializeLeastSignificant() { + return new byte[]{(byte) (mid >>> 31)}; + } + + @Override + public CompUInt128 clearHighBits() { + return new CompUInt128Bit(0L, mid, 0); + } + + @Override + public int bitValue() { + return (mid & 0x80000000) >>> 31; + } + + @Override + public CompUInt128 multiplyByBit(int value) { + return multiply(new CompUInt128Bit(0L, value)); + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128Factory.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128Factory.java index 9c7da10ea..d0acc8f62 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128Factory.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt128Factory.java @@ -8,6 +8,8 @@ public class CompUInt128Factory implements CompUIntFactory { private static final CompUInt128 ZERO = new CompUInt128(new byte[16]); + private static final CompUInt128 ONE = new CompUInt128(1); + private static final CompUInt128 TWO = new CompUInt128(2); private final SecureRandom random = new SecureRandom(); @Override @@ -22,6 +24,11 @@ public CompUInt128 createRandom() { return createFromBytes(bytes); } + @Override + public CompUInt128 fromBit(int bit) { + return new CompUInt128Bit(0L, bit); + } + @Override public ByteSerializer createSerializer() { return new UIntSerializer<>(this); @@ -39,7 +46,12 @@ public int getHighBitLength() { @Override public CompUInt128 createFromBigInteger(BigInteger value) { - return value == null ? null : new CompUInt128(value.toByteArray(), true); + return value == null ? null : new CompUInt128(value); + } + + @Override + public CompUInt128 fromLong(long value) { + return new CompUInt128(value); } @Override @@ -47,4 +59,14 @@ public CompUInt128 zero() { return ZERO; } + @Override + public CompUInt128 one() { + return ONE; + } + + @Override + public CompUInt128 two() { + return TWO; + } + } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt64.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt64.java new file mode 100644 index 000000000..543529fac --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt64.java @@ -0,0 +1,187 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +import dk.alexandra.fresco.framework.util.ByteAndBitConverter; +import dk.alexandra.fresco.framework.value.OInt; +import java.math.BigInteger; + +public class CompUInt64 implements CompUInt { + + private static final CompUInt64 ZERO = new CompUInt64(0); + private static final CompUInt64 ONE = new CompUInt64(1); + + protected final long value; + + public CompUInt64(byte[] bytes) { + this(bytes, false); + } + + public CompUInt64(byte[] bytes, boolean requiresPadding) { + byte[] padded = requiresPadding ? CompUInt.pad(bytes, 64) : bytes; + if (padded.length == 4) { + // we are instantiating from the least significant bits only + this.value = UInt.toUnLong(ByteAndBitConverter.toInt(padded, 0)); + } else { + this.value = ByteAndBitConverter.toLong(padded, 0); + } + } + + public CompUInt64(long value) { + this.value = value; + } + + public CompUInt64(BigInteger value) { + this.value = value.longValue(); + } + + @Override + public UInt32 getMostSignificant() { + return new UInt32((int) (value >>> 32)); + } + + @Override + public UInt32 getLeastSignificant() { + return new UInt32((int) (value & 0xfffffffffL)); + } + + @Override + public UInt32 getLeastSignificantAsHigh() { + return new UInt32((int) (value & 0xfffffffffL)); + } + + @Override + public CompUInt64 shiftLeftSmall(int n) { + return new CompUInt64(value << n); + } + + @Override + public CompUInt64 shiftRightSmall(int n) { + return new CompUInt64(value >>> n); + } + + @Override + public CompUInt64 shiftRightLowOnly(int n) { + throw new UnsupportedOperationException(); + } + + @Override + public CompUInt64 shiftLowIntoHigh() { + return new CompUInt64(value << 32); + } + + @Override + public CompUInt64 clearAboveBitAt(int bitPos) { + long mask = ~(0x8000000000000000L >> (63 - bitPos)); + return new CompUInt64(value & mask); + } + + @Override + public CompUInt64 clearHighBits() { + return new CompUInt64((value & 0xffffffffL)); + } + + @Override + public CompUInt64 toBitRep() { + return new CompUInt64Bit(value); + } + + @Override + public CompUInt64 toArithmeticRep() { + throw new IllegalStateException("Already arithmetic"); + } + + @Override + public CompUInt64 multiplyByBit(int bit) { + return new CompUInt64(this.value * bit); + } + + @Override + public boolean testBit(int bitPos) { + return (((1L << bitPos) & value) >>> bitPos) == 1; + } + + @Override + public CompUInt64 testBitAsUInt(int bitPos) { + return testBit(bitPos) ? ONE : ZERO; + } + + @Override + public int getLowBitLength() { + return 32; + } + + @Override + public int getHighBitLength() { + return 32; + } + + @Override + public byte[] serializeLeastSignificant() { + return ByteAndBitConverter.toByteArray((int) (value)); + } + + @Override + public int bitValue() { + return (int) value & 1; // lowest bit + } + + @Override + public OInt out() { + return this; + } + + @Override + public CompUInt64 add(CompUInt64 other) { + return new CompUInt64(value + other.value); + } + + @Override + public CompUInt64 multiply(CompUInt64 other) { + return new CompUInt64(value * other.value); + } + + @Override + public CompUInt64 subtract(CompUInt64 other) { + return new CompUInt64(value - other.value); + } + + @Override + public CompUInt64 negate() { + return new CompUInt64(-value); + } + + @Override + public boolean isZero() { + return value == 0; + } + + @Override + public boolean isOne() { + return value == 1; + } + + @Override + public byte[] toByteArray() { + return ByteAndBitConverter.toByteArray(value); + } + + @Override + public BigInteger toBigInteger() { + return new BigInteger(1, toByteArray()); + } + + @Override + public long toLong() { + return value; + } + + @Override + public int toInt() { + return (int) (value & 0xffffffffL); + } + + @Override + public String toString() { + return toBigInteger().toString(); + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt64Bit.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt64Bit.java new file mode 100644 index 000000000..d4eade320 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt64Bit.java @@ -0,0 +1,70 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +import java.math.BigInteger; + +public class CompUInt64Bit extends CompUInt64 { + + public CompUInt64Bit(int high, int bit) { + super((UInt.toUnLong(high) << 1) | UInt.toUnLong(bit)); + } + + public CompUInt64Bit(long value) { + super(value); + } + + @Override + public CompUInt64 toBitRep() { + throw new IllegalStateException("Already in bit form."); + } + + @Override + public CompUInt64 toArithmeticRep() { + return new CompUInt64(value << 31); + } + + @Override + public BigInteger toBigInteger() { + return toArithmeticRep().toBigInteger(); + } + + @Override + public CompUInt64 multiply(CompUInt64 other) { + return new CompUInt64Bit(value * other.value); + } + + @Override + public CompUInt64 add(CompUInt64 other) { + return new CompUInt64Bit(value + other.value); + } + + @Override + public String toString() { + return toBigInteger().toString() + "B"; + } + + @Override + public CompUInt64 subtract(CompUInt64 other) { + throw new UnsupportedOperationException("Subtraction not supported by bit representation"); + } + + @Override + public CompUInt64 negate() { + throw new UnsupportedOperationException("Negation not supported by bit representation"); + } + + @Override + public int bitValue() { + return (int) (value & 1L); + } + + @Override + public byte[] serializeLeastSignificant() { + return new byte[]{(byte) bitValue()}; + } + + @Override + public CompUInt64 multiplyByBit(int bitValue) { + return new CompUInt64Bit(value * UInt.toUnLong(bitValue)); + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt64Factory.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt64Factory.java new file mode 100644 index 000000000..cf9c01aba --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt64Factory.java @@ -0,0 +1,72 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; +import dk.alexandra.fresco.suite.spdz2k.util.UIntSerializer; +import java.math.BigInteger; +import java.security.SecureRandom; + +public class CompUInt64Factory implements CompUIntFactory { + + private static final CompUInt64 ZERO = new CompUInt64(0); + private static final CompUInt64 ONE = new CompUInt64(1); + private static final CompUInt64 TWO = new CompUInt64(2); + private final SecureRandom random = new SecureRandom(); + + @Override + public CompUInt64 createFromBytes(byte[] bytes) { + return new CompUInt64(bytes); + } + + @Override + public CompUInt64 createRandom() { + byte[] bytes = new byte[8]; + this.random.nextBytes(bytes); + return createFromBytes(bytes); + } + + @Override + public CompUInt64 fromBit(int bit) { + return new CompUInt64Bit(0, (bit) & 1); + } + + @Override + public ByteSerializer createSerializer() { + return new UIntSerializer<>(this); + } + + @Override + public int getLowBitLength() { + return 32; + } + + @Override + public int getHighBitLength() { + return 32; + } + + @Override + public CompUInt64 createFromBigInteger(BigInteger value) { + return value == null ? null : new CompUInt64(value); + } + + @Override + public CompUInt64 fromLong(long value) { + return new CompUInt64(value & 0xffffffffL); + } + + @Override + public CompUInt64 zero() { + return ZERO; + } + + @Override + public CompUInt64 one() { + return ONE; + } + + @Override + public CompUInt64 two() { + return TWO; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt96.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt96.java deleted file mode 100644 index ae22a2ed4..000000000 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt96.java +++ /dev/null @@ -1,195 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k.datatypes; - -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -public class CompUInt96 implements CompUInt { - private static final CompUInt96 ONE = new CompUInt96((int) 1); - - private final int high; - private final int mid; - private final int low; - - /** - * Creates new {@link CompUInt96}. - * - * @param bytes bytes interpreted in big-endian order. - */ - public CompUInt96(byte[] bytes) { - byte[] padded = CompUInt.pad(bytes, 96); - ByteBuffer buffer = ByteBuffer.wrap(padded); - buffer.order(ByteOrder.BIG_ENDIAN); - this.high = buffer.getInt(); - this.mid = buffer.getInt(); - this.low = buffer.getInt(); - } - - CompUInt96(int high, int mid, int low) { - this.high = high; - this.mid = mid; - this.low = low; - } - - CompUInt96(BigInteger value) { - this(value.toByteArray()); - } - - CompUInt96(UInt64 value) { - this(value.toLong()); - } - - CompUInt96(UInt32 value) { - this(value.toInt()); - } - - CompUInt96(long value) { - this.high = 0; - this.mid = (int) (value >>> 32); - this.low = (int) value; - } - - CompUInt96(int value) { - this.high = 0; - this.mid = 0; - this.low = value; - } - - CompUInt96(CompUInt96 other) { - this.high = other.high; - this.mid = other.mid; - this.low = other.low; - } - - @Override - public CompUInt96 add(CompUInt96 other) { - long newLow = Integer.toUnsignedLong(this.low) + Integer.toUnsignedLong(other.low); - long lowOverflow = newLow >>> 32; - long newMid = Integer.toUnsignedLong(this.mid) - + Integer.toUnsignedLong(other.mid) - + lowOverflow; - long midOverflow = newMid >>> 32; - long newHigh = UInt.toUnLong(this.high) + UInt.toUnLong(other.high) + midOverflow; - return new CompUInt96((int) newHigh, (int) newMid, (int) newLow); - } - - @Override - public CompUInt96 multiply(CompUInt96 other) { - long thisLowAsLong = UInt.toUnLong(this.low); - long thisMidAsLong = UInt.toUnLong(this.mid); - long otherLowAsLong = UInt.toUnLong(other.low); - long otherMidAsLong = UInt.toUnLong(other.mid); - - // low - long t1 = thisLowAsLong * otherLowAsLong; - long t2 = thisLowAsLong * otherMidAsLong; - long t3 = thisLowAsLong * other.high; - - // mid - long t4 = thisMidAsLong * otherLowAsLong; - long t5 = thisMidAsLong * otherMidAsLong; - int t6 = this.mid * other.high; - - // high - long t7 = this.high * otherLowAsLong; - int t8 = this.high * other.mid; - // we don't need the product of this.high and other.high since those overflow 2^128 - - long m1 = (t1 >>> 32) + (t2 & 0xffffffffL); - int m2 = (int) m1; - long newMid = UInt.toUnLong(m2) + (t4 & 0xffffffffL); - - long newHigh = (t2 >>> 32) - + t3 - + (t4 >>> 32) - + t5 - + (UInt.toUnLong(t6) << 32) - + t7 - + (UInt.toUnLong(t8) << 32) - + (m1 >>> 32) - + (newMid >>> 32); - return new CompUInt96((int) newHigh, (int) newMid, (int) t1); - } - - @Override - public CompUInt96 subtract(CompUInt96 other) { - return this.add(other.negate()); - } - - @Override - public CompUInt96 negate() { - return new CompUInt96(~high, ~mid, ~low).add(ONE); - } - - @Override - public boolean isZero() { - return high == 0 && mid == 0 && low == 0; - } - - @Override - public BigInteger toBigInteger() { - return new BigInteger(1, toByteArray()); - } - - @Override - public UInt32 getLeastSignificant() { - return new UInt32(low); - } - - @Override - public UInt64 getMostSignificant() { - return new UInt64((UInt.toUnLong(high) << 32) + UInt.toUnLong(mid)); - } - - @Override - public UInt64 getLeastSignificantAsHigh() { - return new UInt64(toLong()); - } - - @Override - public long toLong() { - return (UInt.toUnLong(mid) << 32) + (UInt.toUnLong(this.low)); - } - - @Override - public int toInt() { - return low; - } - - @Override - public CompUInt96 shiftLowIntoHigh() { - return new CompUInt96(mid, low, 0); - } - - @Override - public int getLowBitLength() { - return 32; - } - - @Override - public int getHighBitLength() { - return 64; - } - - @Override - public String toString() { - return toBigInteger().toString(); - } - - @Override - public int getBitLength() { - return 96; - } - - @Override - public byte[] toByteArray() { - ByteBuffer buffer = ByteBuffer.allocate(getBitLength() / 8); - buffer.order(ByteOrder.BIG_ENDIAN); - buffer.putInt(high); - buffer.putInt(mid); - buffer.putInt(low); - buffer.flip(); - return buffer.array(); - } - -} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt96Factory.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt96Factory.java deleted file mode 100644 index 1ae2a2c40..000000000 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUInt96Factory.java +++ /dev/null @@ -1,38 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k.datatypes; - -import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; -import dk.alexandra.fresco.suite.spdz2k.util.UIntSerializer; -import java.security.SecureRandom; - -public class CompUInt96Factory implements CompUIntFactory { - - private final SecureRandom random = new SecureRandom(); - - @Override - public CompUInt96 createFromBytes(byte[] bytes) { - return new CompUInt96(bytes); - } - - @Override - public CompUInt96 createRandom() { - byte[] bytes = new byte[12]; - this.random.nextBytes(bytes); - return createFromBytes(bytes); - } - - @Override - public ByteSerializer createSerializer() { - return new UIntSerializer<>(this); - } - - @Override - public int getLowBitLength() { - return 32; - } - - @Override - public int getHighBitLength() { - return 64; - } - -} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntArithmetic.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntArithmetic.java new file mode 100644 index 000000000..1f457181d --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntArithmetic.java @@ -0,0 +1,93 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntArithmetic; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Implementation of {@link OIntArithmetic} for {@link CompT}. + */ +public class CompUIntArithmetic> implements OIntArithmetic { + + private final CompUIntFactory factory; + private final List powersOfTwo; + + public CompUIntArithmetic(CompUIntFactory factory) { + this.factory = factory; + this.powersOfTwo = initializePowersOfTwo(factory.getLowBitLength()); + } + + @Override + public boolean isZero(OInt openValue) { + return factory.fromOInt(openValue).isZero(); + } + + @Override + public boolean isOne(OInt openValue) { + return factory.fromOInt(openValue).isOne(); + } + + @Override + public OInt one() { + return factory.one(); + } + + @Override + public List toBits(OInt openValue, int numBits) { + CompT value = factory.fromOInt(openValue); + List bits = new ArrayList<>(numBits); + for (int b = 0; b < numBits; b++) { + bits.add(value.testBitAsUInt(b)); + } + Collections.reverse(bits); + return bits; + } + + @Override + public List getPowersOfTwo(int numPowers) { + if (numPowers > factory.getLowBitLength()) { + throw new UnsupportedOperationException(); + } else { + return powersOfTwo.subList(0, numPowers); + } + } + + @Override + public OInt twoTo(int power) { + if (power > factory.getLowBitLength()) { + throw new UnsupportedOperationException(); + } else { + return powersOfTwo.get(power); + } + } + + @Override + public OInt modTwoTo(OInt input, int power) { + if (power > factory.getLowBitLength()) { + throw new UnsupportedOperationException(); + } else { + return factory.fromOInt(input).clearAboveBitAt(power); + } + } + + private List initializePowersOfTwo(int numPowers) { + List powers = new ArrayList<>(numPowers); + CompT current = factory.one(); + final CompT tempOuter = current; + powers.add(tempOuter); + for (int i = 1; i < numPowers; i++) { + current = current.multiply(factory.two()); + final CompT temp = current; + powers.add(temp); + } + return powers; + } + + @Override + public OInt shiftRight(OInt input, int n) { + return factory.fromOInt(input).shiftRightLowOnly(n); + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntConverter64.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntConverter64.java new file mode 100644 index 000000000..f73ac5966 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntConverter64.java @@ -0,0 +1,17 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +public class CompUIntConverter64 implements CompUIntConverter { + + @Override + public CompUInt64 createFromHigh(UInt32 value) { + return new CompUInt64( + UInt.toUnLong(value.toInt()) + ); + } + + @Override + public CompUInt64 createFromLow(UInt32 value) { + return new CompUInt64(UInt.toUnLong(value.toInt())); + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntConverter96.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntConverter96.java deleted file mode 100644 index 81924e30b..000000000 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntConverter96.java +++ /dev/null @@ -1,15 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k.datatypes; - -public class CompUIntConverter96 implements CompUIntConverter { - - @Override - public CompUInt96 createFromHigh(UInt64 value) { - return new CompUInt96(value); - } - - @Override - public CompUInt96 createFromLow(UInt32 value) { - return new CompUInt96(value); - } - -} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntConverterGeneric.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntConverterGeneric.java deleted file mode 100644 index 7b9d0b050..000000000 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntConverterGeneric.java +++ /dev/null @@ -1,28 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k.datatypes; - -public class CompUIntConverterGeneric implements - CompUIntConverter { - - private final int highBitLength; - private final int lowBitLength; - - public CompUIntConverterGeneric(int highBitLength, int lowBitLength) { - this.highBitLength = highBitLength; - this.lowBitLength = lowBitLength; - } - - @Override - public GenericCompUInt createFromHigh(GenericCompUInt value) { - return new GenericCompUInt(value, getCompositeBitLength()); - } - - @Override - public GenericCompUInt createFromLow(GenericCompUInt value) { - return new GenericCompUInt(value, getCompositeBitLength()); - } - - private int getCompositeBitLength() { - return highBitLength + lowBitLength; - } - -} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntFactory.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntFactory.java index 1ae28d4a2..e859d4196 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntFactory.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/CompUIntFactory.java @@ -1,12 +1,53 @@ package dk.alexandra.fresco.suite.spdz2k.datatypes; +import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntFactory; +import dk.alexandra.fresco.framework.value.SInt; import java.math.BigInteger; +import java.util.Objects; /** * Factory for {@link CompT} instances. */ -public interface CompUIntFactory> { +public interface CompUIntFactory> extends OIntFactory { + + @Override + default BigInteger toBigInteger(OInt value) { + // TODO test + return ((CompUInt) value).toBigInteger(); + } + + @Override + default OInt fromBigInteger(BigInteger value) { + return createFromBigInteger(value); + } + + default CompT fromBit(int bit) { + throw new UnsupportedOperationException(); + } + + /** + * Get result from deferred and downcast result to {@link CompT}. + */ + default CompT fromOInt(DRes value) { + return Objects.requireNonNull((CompT) value.out()); + } + + /** + * Get result from deferred and downcast result to {@link Spdz2kSIntArithmetic }. + */ + default Spdz2kSIntArithmetic toSpdz2kSIntArithmetic(DRes value) { + return Objects.requireNonNull((Spdz2kSIntArithmetic) value.out()); + } + + /** + * Get result from deferred and downcast result to {@link Spdz2kSIntBoolean}. + */ + default Spdz2kSIntBoolean toSpdz2kSIntBoolean(DRes value) { + return Objects.requireNonNull((Spdz2kSIntBoolean) value.out()); + } /** * Creates new {@link CompT} from a raw array of bytes. @@ -33,6 +74,11 @@ public interface CompUIntFactory> { */ int getLowBitLength(); + @Override + default int getMaxBitLength() { + return getLowBitLength(); + } + /** * Get total bit length. */ @@ -47,11 +93,24 @@ default CompT createFromBigInteger(BigInteger value) { return (value == null) ? null : createFromBytes(value.toByteArray()); } + /** + * Creates new {@link CompT} from a {@link long}. + */ + CompT fromLong(long value); + /** * Creates element whose value is zero. */ default CompT zero() { - return createFromBytes(new byte[getCompositeBitLength() / Byte.SIZE]); + return createFromBigInteger(BigInteger.ZERO); + } + + default CompT one() { + return createFromBigInteger(BigInteger.ONE); } - + + default CompT two() { + return createFromBigInteger(BigInteger.valueOf(2)); + } + } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/GenericCompUInt.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/GenericCompUInt.java deleted file mode 100644 index ac6303390..000000000 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/GenericCompUInt.java +++ /dev/null @@ -1,210 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k.datatypes; - -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.IntBuffer; -import java.util.Arrays; - -/** - * Implementation of {@link CompUInt} that allows for any size least-significant and - * most-significant bit portion.

Note that this class is a lot slower than dedicated - * implementations such as {@link CompUInt128}.

- */ -public class GenericCompUInt implements - CompUInt { - - private final int lowBitLength; - private final int[] ints; - - GenericCompUInt(final int[] ints, int lowBitLength) { - this.lowBitLength = lowBitLength; - this.ints = ints; - } - - GenericCompUInt(int low, int requiredBitLength) { - this(initIntArray(low, requiredBitLength)); - } - - GenericCompUInt(final int[] ints) { - this(ints, ints.length / 2 * Integer.SIZE); - } - - GenericCompUInt(GenericCompUInt other, int requiredBitLength) { - this(pad(other.ints, requiredBitLength)); - } - - GenericCompUInt(byte[] bytes, int requiredBitLength) { - this(toIntArray(bytes, requiredBitLength)); - } - - GenericCompUInt(BigInteger value, int requiredBitLength) { - this(value.toByteArray(), requiredBitLength); - } - - @Override - public GenericCompUInt add(final GenericCompUInt other) { - final int[] resultInts = new int[ints.length]; - long carry = 0; - // big-endian, so reverse order - for (int l = ints.length - 1; l >= 0; l--) { - final long sum = UInt.toUnLong(ints[l]) + UInt.toUnLong(other.ints[l]) + carry; - resultInts[l] = (int) sum; - carry = sum >>> 32; - } - return new GenericCompUInt(resultInts); - } - - @Override - public GenericCompUInt multiply(final GenericCompUInt other) { - // note that we assume that other has the same bit-length as this - final int[] resultInts = new int[ints.length]; - for (int l = ints.length - 1; l >= 0; l--) { - long carry = 0; - int resIdxOffset = l; - for (int r = ints.length - 1; r >= 0 && resIdxOffset >= 0; r--, resIdxOffset--) { - final long product = UInt.toUnLong(ints[l]) * UInt.toUnLong(other.ints[r]) - + UInt.toUnLong(resultInts[resIdxOffset]) + carry; - carry = product >>> 32; - resultInts[resIdxOffset] = (int) product; - } - } - return new GenericCompUInt(resultInts); - } - - @Override - public GenericCompUInt subtract(GenericCompUInt other) { - return this.add(other.negate()); - } - - @Override - public GenericCompUInt negate() { - int[] reversed = new int[ints.length]; - for (int i = 0; i < reversed.length; i++) { - reversed[i] = ~ints[i]; - } - return new GenericCompUInt(reversed).add(one()); - } - - @Override - public boolean isZero() { - for (int val : ints) { - if (val != 0) { - return false; - } - } - return true; - } - - @Override - public int getBitLength() { - return ints.length * Integer.SIZE; - } - - @Override - public byte[] toByteArray() { - ByteBuffer buffer = ByteBuffer.allocate(getBitLength() / Byte.SIZE); - IntBuffer intBuffer = buffer.asIntBuffer(); - intBuffer.put(ints); - return buffer.array(); - } - - @Override - public BigInteger toBigInteger() { - return new BigInteger(1, toByteArray()); - } - - @Override - public GenericCompUInt getLeastSignificant() { - return getSubRange(0, getLowBitLength() / Integer.SIZE); - } - - @Override - public GenericCompUInt getLeastSignificantAsHigh() { - return getSubRange(0, getHighBitLength() / Integer.SIZE); - } - - @Override - public GenericCompUInt getMostSignificant() { - return getSubRange(getLowBitLength() / Integer.SIZE, getCompositeBitLength() / Integer.SIZE); - } - - @Override - public long toLong() { - return (UInt.toUnLong(ints[ints.length - 2]) << 32) + UInt.toUnLong(ints[ints.length - 1]); - } - - @Override - public int toInt() { - return ints[ints.length - 1]; - } - - @Override - public GenericCompUInt shiftLowIntoHigh() { - int[] shifted = new int[ints.length]; - int smallerByteLength = Integer.min(getLowBitLength(), getHighBitLength()) / Integer.SIZE; - int lowByteLength = getLowBitLength() / Integer.SIZE; - for (int i = 0; i < smallerByteLength; i++) { - shifted[shifted.length - (lowByteLength + i + 1)] = ints[shifted.length - i - 1]; - } - return new GenericCompUInt(shifted); - } - - @Override - public int getLowBitLength() { - return lowBitLength; - } - - @Override - public int getHighBitLength() { - return ints.length * Integer.SIZE - getLowBitLength(); - } - - @Override - public String toString() { - return toBigInteger().toString(); - } - - private GenericCompUInt one() { - // TODO cache this - int[] temp = new int[getCompositeBitLength() / Integer.SIZE]; - temp[temp.length - 1] = 1; - return new GenericCompUInt(temp); - } - - private GenericCompUInt getSubRange(int from, int to) { - return new GenericCompUInt(getIntSubRange(from, to)); - } - - private int[] getIntSubRange(int from, int to) { - // big-endian order so need to flip indexes - int fromFlipped = ints.length - from - (to - from); - int toFlipped = ints.length - from; - return Arrays.copyOfRange(ints, fromFlipped, toFlipped); - } - - private static int[] toIntArray(byte[] bytes, int requiredBitLength) { - IntBuffer intBuf = - ByteBuffer.wrap(CompUInt.pad(bytes, requiredBitLength)) - .order(ByteOrder.BIG_ENDIAN) - .asIntBuffer(); - int[] array = new int[intBuf.remaining()]; - intBuf.get(array); - return array; - } - - private static int[] pad(int[] ints, int requiredBitLength) { - int byteLength = requiredBitLength / Integer.SIZE; - int[] padded = new int[byteLength]; - // assuming ints is shorter than required length - System.arraycopy(ints, 0, padded, byteLength - ints.length, ints.length); - return padded; - } - - private static int[] initIntArray(int value, int requiredBitLength) { - int[] temp = new int[requiredBitLength / Integer.SIZE]; - temp[temp.length - 1] = value; - return temp; - } - -} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/GenericCompUIntFactory.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/GenericCompUIntFactory.java deleted file mode 100644 index b648fdb8a..000000000 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/GenericCompUIntFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k.datatypes; - -import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; -import dk.alexandra.fresco.suite.spdz2k.util.UIntSerializer; -import java.security.SecureRandom; - -public class GenericCompUIntFactory implements - CompUIntFactory { - - private final SecureRandom random = new SecureRandom(); - private final int highBitLength; - private final int lowBitLength; - - public GenericCompUIntFactory(int highBitLength, int lowBitLength) { - this.highBitLength = highBitLength; - this.lowBitLength = lowBitLength; - } - - @Override - public GenericCompUInt createFromBytes(byte[] bytes) { - return new GenericCompUInt(bytes, getCompositeBitLength()); - } - - @Override - public GenericCompUInt createRandom() { - byte[] bytes = new byte[getCompositeBitLength() / Byte.SIZE]; - this.random.nextBytes(bytes); - return createFromBytes(bytes); - } - - @Override - public ByteSerializer createSerializer() { - return new UIntSerializer<>(this); - } - - @Override - public int getLowBitLength() { - return lowBitLength; - } - - @Override - public int getHighBitLength() { - return highBitLength; - } - -} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kInputMask.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kInputMask.java index 0afaccbc5..e01c01912 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kInputMask.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kInputMask.java @@ -2,19 +2,19 @@ public class Spdz2kInputMask> { - private final Spdz2kSInt maskShare; + private final Spdz2kSIntArithmetic maskShare; private final PlainT openValue; - public Spdz2kInputMask(Spdz2kSInt maskShare) { + public Spdz2kInputMask(Spdz2kSIntArithmetic maskShare) { this(maskShare, null); } - public Spdz2kInputMask(Spdz2kSInt maskShare, PlainT openValue) { + public Spdz2kInputMask(Spdz2kSIntArithmetic maskShare, PlainT openValue) { this.maskShare = maskShare; this.openValue = openValue; } - public Spdz2kSInt getMaskShare() { + public Spdz2kSIntArithmetic getMaskShare() { return maskShare; } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSInt.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSInt.java index 22a56a11d..f2c0f47e0 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSInt.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSInt.java @@ -2,79 +2,16 @@ import dk.alexandra.fresco.framework.value.SInt; -/** - * Represents an authenticated, secret-share element. - * - * @param type of underlying plain value, i.e., the value type we use for arithmetic. - */ -public class Spdz2kSInt> implements SInt { +public abstract class Spdz2kSInt> implements SInt { - private final PlainT share; - private final PlainT macShare; + protected final PlainT share; + protected final PlainT macShare; - /** - * Creates a {@link Spdz2kSInt}. - */ public Spdz2kSInt(PlainT share, PlainT macShare) { this.share = share; this.macShare = macShare; } - /** - * Creates a {@link Spdz2kSInt} from a public value.

All parties compute the mac share of the - * value but only party one (by convention) stores the public value as the share, the others store - * 0.

- */ - public Spdz2kSInt(PlainT share, PlainT macKeyShare, PlainT zero, boolean isPartyOne) { - this(isPartyOne ? share : zero, share.multiply(macKeyShare)); - } - - /** - * Compute sum of this and other. - */ - public Spdz2kSInt add(Spdz2kSInt other) { - return new Spdz2kSInt<>(share.add(other.share), macShare.add(other.macShare)); - } - - /** - * Compute difference of this and other. - */ - public Spdz2kSInt subtract(Spdz2kSInt other) { - return new Spdz2kSInt<>(share.subtract(other.share), macShare.subtract(other.macShare)); - } - - /** - * Compute product of this and constant (open) value. - */ - public Spdz2kSInt multiply(PlainT other) { - return new Spdz2kSInt<>(share.multiply(other), macShare.multiply(other)); - } - - @Override - public String toString() { - return "Spdz2kSInt{" + - "share=" + share + - ", macShare=" + macShare + - '}'; - } - - /** - * Compute sum of this and constant (open) value.

All parties compute their mac share of the - * public value and add it to the mac share of the authenticated value, however only party 1 adds - * the public value to is value share.

- * - * @param other constant, open value - * @param macKeyShare mac key share for maccing open value - * @param zero zero value - * @param isPartyOne used to ensure that only one party adds value to share - * @return result of sum - */ - public Spdz2kSInt addConstant( - PlainT other, PlainT macKeyShare, PlainT zero, boolean isPartyOne) { - Spdz2kSInt wrapped = new Spdz2kSInt<>(other, macKeyShare, zero, isPartyOne); - return add(wrapped); - } - /** * Return share. */ @@ -89,6 +26,10 @@ public PlainT getMacShare() { return macShare; } + public byte[] serializeShareLow() { + return share.serializeLeastSignificant(); + } + @Override public SInt out() { return this; diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSIntArithmetic.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSIntArithmetic.java new file mode 100644 index 000000000..0256e2275 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSIntArithmetic.java @@ -0,0 +1,85 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +/** + * Represents an authenticated, secret-share element. + * + * @param type of underlying plain value, i.e., the value type we use for arithmetic. + */ +public class Spdz2kSIntArithmetic> extends + Spdz2kSInt { + + /** + * Creates a {@link Spdz2kSIntArithmetic}. + */ + public Spdz2kSIntArithmetic(PlainT share, PlainT macShare) { + super(share, macShare); + } + + /** + * Creates a {@link Spdz2kSIntArithmetic} from a public value.

All parties compute the mac + * share of the value but only party one (by convention) stores the public value as the share, the + * others store 0.

+ */ + public Spdz2kSIntArithmetic(PlainT share, PlainT macKeyShare, PlainT zero, boolean isPartyOne) { + this(isPartyOne ? share : zero, share.multiply(macKeyShare)); + } + + /** + * Compute sum of this and other. + */ + public Spdz2kSIntArithmetic add(Spdz2kSIntArithmetic other) { + return new Spdz2kSIntArithmetic<>(share.add(other.share), macShare.add(other.macShare)); + } + + /** + * Compute difference of this and other. + */ + public Spdz2kSIntArithmetic subtract(Spdz2kSIntArithmetic other) { + return new Spdz2kSIntArithmetic<>(share.subtract(other.share), + macShare.subtract(other.macShare)); + } + + /** + * Compute product of this and constant (open) value. + */ + public Spdz2kSIntArithmetic multiply(PlainT other) { + return new Spdz2kSIntArithmetic<>(share.multiply(other), macShare.multiply(other)); + } + + /** + * Compute sum of this and constant (open) value.

All parties compute their mac share of the + * public value and add it to the mac share of the authenticated value, however only party 1 adds + * the public value to is value share.

+ * + * @param other constant, open value + * @param macKeyShare mac key share for maccing open value + * @param zero zero value + * @param isPartyOne used to ensure that only one party adds value to share + * @return result of sum + */ + public Spdz2kSIntArithmetic addConstant( + PlainT other, PlainT macKeyShare, PlainT zero, boolean isPartyOne) { + Spdz2kSIntArithmetic wrapped = new Spdz2kSIntArithmetic<>(other, macKeyShare, zero, + isPartyOne); + return add(wrapped); + } + + /** + * Converts this to boolean representation ({@link Spdz2kSIntBoolean}). + */ + public Spdz2kSIntBoolean toBoolean() { + return new Spdz2kSIntBoolean<>( + share.toBitRep(), + macShare.shiftLeftSmall(macShare.getLowBitLength() - 1) + ); + } + + @Override + public String toString() { + return "Spdz2kSIntArithmetic{" + + "share=" + share + + ", macShare=" + macShare + + '}'; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSIntBoolean.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSIntBoolean.java new file mode 100644 index 000000000..ad90e93bb --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kSIntBoolean.java @@ -0,0 +1,77 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +/** + * Represents an authenticated, secret-share element. + * + * @param type of underlying plain value, i.e., the value type we use for arithmetic. + */ +public class Spdz2kSIntBoolean> extends + Spdz2kSInt { + + /** + * Creates a {@link Spdz2kSIntBoolean}. + */ + public Spdz2kSIntBoolean(PlainT share, PlainT macShare) { + super(share, macShare); + } + + /** + * Creates a {@link Spdz2kSIntBoolean} from a public value.

All parties compute the mac share + * of the value but only party one (by convention) stores the public value as the share, the + * others store 0.

+ */ + public Spdz2kSIntBoolean(PlainT share, PlainT macKeyShare, PlainT zero, boolean isPartyOne) { + this(isPartyOne ? share : zero, share.toArithmeticRep().multiply(macKeyShare)); + } + + /** + * Compute sum of this and other. + */ + public Spdz2kSIntBoolean xor(Spdz2kSIntBoolean other) { + return new Spdz2kSIntBoolean<>( + share.add(other.share), + macShare.add(other.macShare) + ); + } + + /** + * Compute product of this and constant (open) value. + */ + public Spdz2kSIntBoolean and(int otherBit) { + return new Spdz2kSIntBoolean<>( + share.multiplyByBit(otherBit), + macShare.multiplyByBit(otherBit) + ); + } + + /** + * Compute sum of this and constant (open) value.

All parties compute their mac share of the + * public value and add it to the mac share of the authenticated value, however only party 1 adds + * the public value to is value share.

+ * + * @param other constant, open value + * @param macKeyShare mac key share for maccing open value + * @param zero zero value + * @param isPartyOne used to ensure that only one party adds value to share + * @return result of sum + */ + public Spdz2kSIntBoolean xorOpen( + PlainT other, PlainT macKeyShare, PlainT zero, boolean isPartyOne) { + Spdz2kSIntBoolean wrapped = new Spdz2kSIntBoolean<>(other, macKeyShare, zero, + isPartyOne); + return xor(wrapped); + } + + public Spdz2kSIntArithmetic asArithmetic() { + return new Spdz2kSIntArithmetic<>(share.toArithmeticRep(), macShare); + } + + @Override + public String toString() { + return "Spdz2kSIntBoolean{" + + "share=" + share + + ", macShare=" + macShare + + '}'; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kTriple.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kTriple.java index f46456d40..3afb5a9ed 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kTriple.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/Spdz2kTriple.java @@ -1,28 +1,35 @@ package dk.alexandra.fresco.suite.spdz2k.datatypes; -public class Spdz2kTriple> { +public class Spdz2kTriple, SIntT extends Spdz2kSInt> { - private final Spdz2kSInt left; - private final Spdz2kSInt right; - private final Spdz2kSInt product; + private final SIntT left; + private final SIntT right; + private final SIntT product; - public Spdz2kTriple(Spdz2kSInt left, Spdz2kSInt right, - Spdz2kSInt product) { + public Spdz2kTriple(SIntT left, SIntT right, SIntT product) { this.left = left; this.right = right; this.product = product; } - public Spdz2kSInt getLeft() { + public SIntT getLeft() { return left; } - public Spdz2kSInt getRight() { + public SIntT getRight() { return right; } - public Spdz2kSInt getProduct() { + public SIntT getProduct() { return product; } + @Override + public String toString() { + return "Spdz2kTriple{" + + "left=" + left + + ", right=" + right + + ", product=" + product + + '}'; + } } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt.java index 2db729661..5d527c84d 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt.java @@ -35,6 +35,11 @@ public interface UInt { */ boolean isZero(); + /** + * Check if values is one. + */ + boolean isOne(); + /** * Return bit length. */ @@ -60,6 +65,13 @@ public interface UInt { */ int toInt(); + /** + * Returns if bit at position is set or not. + */ + default boolean testBit(int bit) { + return toBigInteger().testBit(bit); + } + /** * Compute sum of elements. */ diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt32.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt32.java index 077e91019..45e246d3c 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt32.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt32.java @@ -40,6 +40,11 @@ public boolean isZero() { return value == 0; } + @Override + public boolean isOne() { + return value == 1; + } + @Override public int getBitLength() { return 32; diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt64.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt64.java index 84999ea29..6d6d8adaa 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt64.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/datatypes/UInt64.java @@ -40,6 +40,11 @@ public boolean isZero() { return value == 0; } + @Override + public boolean isOne() { + return value == 1; + } + @Override public int getBitLength() { return 64; diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/BroadcastComputation.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/BroadcastComputation.java index 4c5a29982..ba42b6431 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/BroadcastComputation.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/BroadcastComputation.java @@ -17,13 +17,15 @@ public class BroadcastComputation Computation, BuilderT> { private final List input; + private final boolean doValidation; - BroadcastComputation(List input) { + BroadcastComputation(List input, boolean doValidation) { this.input = input; + this.doValidation = doValidation; } - BroadcastComputation(byte[] input) { - this(java.util.Collections.singletonList(input)); + BroadcastComputation(byte[] input, boolean doValidation) { + this(java.util.Collections.singletonList(input), doValidation); } @Override @@ -38,8 +40,12 @@ public DRes> buildComputation(BuilderT builder) { List toValidate = lst.stream() .flatMap(broadcast -> broadcast.out().stream()) .collect(Collectors.toList()); - seq.append(new BroadcastValidationProtocol<>(toValidate)); - return () -> toValidate; + if (doValidation) { + seq.append(new BroadcastValidationProtocol<>(toValidate)); + return () -> toValidate; + } else { + return () -> toValidate; + } }); } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/CoinTossingComputation.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/CoinTossingComputation.java index 0daea842c..b0bb7ddb0 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/CoinTossingComputation.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/CoinTossingComputation.java @@ -35,7 +35,7 @@ public CoinTossingComputation(int seedLength, ByteSerializer buildComputation(ProtocolBuilderNumeric builder) { - return builder.seq(new Spdz2kCommitmentComputation(serializer, ownSeed, noOfParties, localDrbg)) + return builder.seq(new CommitmentComputationSpdz2k(serializer, ownSeed, noOfParties, localDrbg)) .seq((seq, seeds) -> { byte[] jointSeed = new byte[ownSeed.length]; for (byte[] seed : seeds) { diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kCommitmentComputation.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/CommitmentComputationSpdz2k.java similarity index 89% rename from suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kCommitmentComputation.java rename to suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/CommitmentComputationSpdz2k.java index d263e79e8..b5fc9c576 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kCommitmentComputation.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/CommitmentComputationSpdz2k.java @@ -13,7 +13,7 @@ /** * Protocol for all parties to commit to a value and open it to the other parties. */ -public class Spdz2kCommitmentComputation implements +public class CommitmentComputationSpdz2k implements Computation, ProtocolBuilderNumeric> { private final ByteSerializer commitmentSerializer; @@ -21,7 +21,7 @@ public class Spdz2kCommitmentComputation implements private final int noOfParties; private final Drbg localDrbg; - public Spdz2kCommitmentComputation(ByteSerializer commitmentSerializer, + public CommitmentComputationSpdz2k(ByteSerializer commitmentSerializer, byte[] value, int noOfParties, Drbg localDrbg) { this.commitmentSerializer = commitmentSerializer; this.value = value; @@ -33,7 +33,8 @@ public Spdz2kCommitmentComputation(ByteSerializer commitmen public DRes> buildComputation(ProtocolBuilderNumeric builder) { HashBasedCommitment ownCommitment = new HashBasedCommitment(); byte[] ownOpening = ownCommitment.commit(localDrbg, value); - return builder.seq(new BroadcastComputation<>(commitmentSerializer.serialize(ownCommitment))) + return builder.seq(new BroadcastComputation<>( + commitmentSerializer.serialize(ownCommitment), noOfParties > 2)) .seq((seq, rawCommitments) -> { DRes> openingsDRes = seq.append(new InsecureBroadcastProtocol<>(ownOpening)); List commitments = commitmentSerializer diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kInputComputation.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/InputComputationSpdz2k.java similarity index 92% rename from suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kInputComputation.java rename to suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/InputComputationSpdz2k.java index 0f89672bc..743479ea2 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kInputComputation.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/InputComputationSpdz2k.java @@ -16,13 +16,13 @@ * validation of the bytes of the masked input (if more than two parties are carrying out the * computation).

*/ -public class Spdz2kInputComputation> implements +public class InputComputationSpdz2k> implements Computation { private final PlainT input; private final int inputPartyId; - public Spdz2kInputComputation(PlainT input, int inputPartyId) { + public InputComputationSpdz2k(PlainT input, int inputPartyId) { this.inputPartyId = inputPartyId; this.input = input; } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/OrNeighborsComputationSpdz2k.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/OrNeighborsComputationSpdz2k.java new file mode 100644 index 000000000..abebf144b --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/OrNeighborsComputationSpdz2k.java @@ -0,0 +1,34 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.computations; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kOrBatchedProtocol; +import java.util.ArrayList; +import java.util.List; + +public class OrNeighborsComputationSpdz2k implements + Computation>, ProtocolBuilderNumeric> { + + private final List> bits; + + public OrNeighborsComputationSpdz2k(List> bits) { + this.bits = bits; + } + + @Override + public DRes>> buildComputation(ProtocolBuilderNumeric builder) { + List> leftBits = new ArrayList<>(bits.size() / 2); + List> rightBits = new ArrayList<>(bits.size() / 2); + for (int i = 0; i < bits.size() - 1; i += 2) { + leftBits.add(bits.get(i)); + rightBits.add(bits.get(i + 1)); + } + final boolean isOdd = bits.size() % 2 != 0; + return builder.append(new Spdz2kOrBatchedProtocol<>( + () -> leftBits, + () -> rightBits, + isOdd ? bits.get(bits.size() - 1) : null)); + } +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kMacCheckComputation.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kMacCheckComputation.java index 364bab571..717110bfe 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kMacCheckComputation.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/Spdz2kMacCheckComputation.java @@ -11,7 +11,7 @@ import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntConverter; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.datatypes.UInt; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDataSupplier; @@ -28,10 +28,12 @@ public class Spdz2kMacCheckComputation< PlainT extends CompUInt> implements Computation { + private static int COUNT = 0; + private final CompUIntConverter converter; private final ByteSerializer serializer; private final Spdz2kDataSupplier supplier; - private final List> authenticatedElements; + private final List> authenticatedElements; private final List openValues; private final List randomCoefficients; private ByteSerializer commitmentSerializer; @@ -46,7 +48,7 @@ public class Spdz2kMacCheckComputation< * @param converter utility class for converting between {@link HighT} and {@link PlainT}, {@link * LowT} and {@link PlainT} */ - public Spdz2kMacCheckComputation(Pair>, List> toCheck, + public Spdz2kMacCheckComputation(Pair>, List> toCheck, Spdz2kResourcePool resourcePool, CompUIntConverter converter) { this.authenticatedElements = toCheck.getFirst(); @@ -67,24 +69,27 @@ public Spdz2kMacCheckComputation(Pair>, List> to public DRes buildComputation(ProtocolBuilderNumeric builder) { PlainT macKeyShare = supplier.getSecretSharedKey(); PlainT y = UInt.innerProduct(openValues, randomCoefficients); - Spdz2kSInt r = supplier.getNextRandomElementShare(); + Spdz2kSIntArithmetic r = supplier.getNextRandomElementShare(); +// System.out.println("SPDZ2k Mac Check " + COUNT++ + " "+ openValues.size()); return builder .seq(seq -> { if (noOfParties > 2) { List sharesLowBits = authenticatedElements.stream() .map(element -> element.getShare().getLeastSignificant().toByteArray()) .collect(Collectors.toList()); - return new BroadcastComputation(sharesLowBits) + return new BroadcastComputation(sharesLowBits, true) .buildComputation(seq); } else { - return () -> null; + return null; } }) .seq((seq, ignored) -> computePValues(seq, authenticatedElements, r)) .seq((seq, broadcastPjs) -> computeZValues(seq, authenticatedElements, macKeyShare, y, r, broadcastPjs)) .seq((seq, commitZjs) -> { - if (!UInt.sum(serializer.deserializeList(commitZjs)).isZero()) { + List elements = serializer.deserializeList(commitZjs); + PlainT sum = UInt.sum(elements); + if (!sum.isZero()) { throw new MaliciousException("Mac check failed"); } authenticatedElements.clear(); @@ -100,35 +105,37 @@ private HighT computePj(PlainT originalShare, PlainT randomCoefficient) { } private DRes> computePValues(ProtocolBuilderNumeric builder, - List> authenticatedElements, - Spdz2kSInt r) { + List> authenticatedElements, + Spdz2kSIntArithmetic r) { HighT pj = computePj(authenticatedElements.get(0).getShare(), randomCoefficients.get(0)); for (int i = 1; i < authenticatedElements.size(); i++) { PlainT share = authenticatedElements.get(i).getShare(); PlainT randomCoefficient = randomCoefficients.get(i); pj = pj.add(computePj(share, randomCoefficient)); } - byte[] pjBytes = pj.add(r.getShare().getLeastSignificantAsHigh()).toByteArray(); - return new BroadcastComputation(pjBytes).buildComputation(builder); + final HighT add = pj.add(r.getShare().getLeastSignificantAsHigh()); + byte[] pjBytes = add.toByteArray(); + return new BroadcastComputation(pjBytes, noOfParties > 2) + .buildComputation(builder); } private DRes> computeZValues(ProtocolBuilderNumeric builder, - List> authenticatedElements, - PlainT macKeyShare, PlainT y, Spdz2kSInt r, + List> authenticatedElements, + PlainT macKeyShare, PlainT y, Spdz2kSIntArithmetic r, List broadcastPjs) { List pjList = serializer.deserializeList(broadcastPjs); HighT pLow = UInt.sum( pjList.stream().map(PlainT::getLeastSignificantAsHigh).collect(Collectors.toList())); PlainT p = converter.createFromHigh(pLow); List macShares = authenticatedElements.stream() - .map(Spdz2kSInt::getMacShare) + .map(Spdz2kSIntArithmetic::getMacShare) .collect(Collectors.toList()); PlainT mj = UInt.innerProduct(macShares, randomCoefficients); PlainT zj = macKeyShare.multiply(y) .subtract(mj) .subtract(p.multiply(macKeyShare).shiftLowIntoHigh()) .add(r.getMacShare().shiftLowIntoHigh()); - return new Spdz2kCommitmentComputation(commitmentSerializer, serializer.serialize(zj), + return new CommitmentComputationSpdz2k(commitmentSerializer, serializer.serialize(zj), noOfParties, localDrbg).buildComputation(builder); } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/eq/ZeroTestSpdz2k.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/eq/ZeroTestSpdz2k.java new file mode 100644 index 000000000..ffa3c368e --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/eq/ZeroTestSpdz2k.java @@ -0,0 +1,65 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.computations.eq; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.Conversion; +import dk.alexandra.fresco.framework.builder.numeric.Logical; +import dk.alexandra.fresco.framework.builder.numeric.Numeric; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntArithmetic; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import java.util.Collections; +import java.util.List; + +/** + * Computes if given value equals 0 (result remains secret). + */ +public class ZeroTestSpdz2k> implements + Computation { + + private final DRes value; + private final CompUIntFactory factory; + private final int k; + + public ZeroTestSpdz2k(DRes value, CompUIntFactory factory) { + this.value = value; + this.factory = factory; + this.k = factory.getLowBitLength(); + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + OIntArithmetic arithmetic = builder.getOIntArithmetic(); + return builder.seq(seq -> seq.advancedNumeric().randomBitMask(k - 1)) + .seq((seq, mask) -> { + Numeric numeric = seq.numeric(); + PlainT twoTo2k1 = factory.fromOInt(arithmetic.twoTo(k - 1)).negate(); + DRes extraBit = numeric.randomBit(); + List> bits = mask.getBits().out(); + bits.add(extraBit); + Collections.reverse(bits); + DRes r = numeric.add( + mask.getValue(), + numeric.multByOpen(twoTo2k1, extraBit) + ); + DRes c = numeric.add(value, r); + DRes cOpen = numeric.openAsOInt(c); + Pair>, DRes> res = new Pair<>(bits, cOpen); + return () -> res; + }).seq((seq, pair) -> { + Logical logical = seq.logical(); + Conversion conversion = seq.conversion(); + List> rBits = pair.getFirst(); + List cBits = arithmetic.toBits(pair.getSecond().out(), k); + DRes>> rBitsBoolean = conversion.toBooleanBatch(() -> rBits); + DRes>> xored = logical.pairWiseXorKnown(() -> cBits, rBitsBoolean); + final long then = System.currentTimeMillis(); + DRes or = logical.orOfList(xored); + return conversion.toArithmetic(logical.not(or)); + }); + } +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/lt/MostSignBitSpdz2k.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/lt/MostSignBitSpdz2k.java new file mode 100644 index 000000000..fdefad32a --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/lt/MostSignBitSpdz2k.java @@ -0,0 +1,74 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.computations.lt; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.builder.Computation; +import dk.alexandra.fresco.framework.builder.numeric.Numeric; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntArithmetic; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.lib.math.integer.binary.RandomBitMask; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; + +/** + * Extract the value of the most significant bit of value. + */ +public class MostSignBitSpdz2k> implements + Computation { + + private final DRes value; + private final CompUIntFactory factory; + private final int k; + + public MostSignBitSpdz2k(DRes value, CompUIntFactory factory) { + this.value = value; + this.factory = factory; + this.k = factory.getLowBitLength(); + } + + @Override + public DRes buildComputation(ProtocolBuilderNumeric builder) { + OIntArithmetic arithmetic = builder.getOIntArithmetic(); + DRes twoTo2k1 = arithmetic.twoTo(k - 1); + return builder.seq(seq -> seq.advancedNumeric().randomBitMask(k - 1)) + .seq((seq, mask) -> { + Numeric numeric = seq.numeric(); + DRes rPrime = mask.getValue(); + DRes kthBit = numeric.randomBit(); + DRes r = numeric.add(rPrime, numeric.multByOpen(twoTo2k1, kthBit)); + DRes c = numeric.add(value, r); + DRes cOpen = numeric.openAsOInt(c); + final Pair, RandomBitMask> resPair = new Pair<>(cOpen, mask); + return () -> resPair; + }).seq((seq, pair) -> { + Numeric nb = seq.numeric(); + PlainT cOpen = factory.fromOInt(pair.getFirst()); + PlainT cPrime = cOpen.clearAboveBitAt(k - 1); + RandomBitMask mask = pair.getSecond(); + DRes rPrime = mask.getValue(); + DRes u = seq.comparison().compareLTBits(cPrime, mask.getBits()); + DRes aPrime = nb.add( + nb.subFromOpen(() -> cPrime, rPrime), + seq.seq(ignored -> factory.toSpdz2kSIntBoolean(u).asArithmetic().out()) + ); + DRes d = nb.sub(value, aPrime); + DRes b = nb.randomBit(); + DRes e = nb.add(d, nb.multByOpen(twoTo2k1, b)); + DRes eOpen = nb.openAsOInt(e); + final Pair, DRes> resPair = new Pair<>(eOpen, b); + return () -> resPair; + }).seq((seq, pair) -> { + Numeric nb = seq.numeric(); + PlainT eOpen = factory.fromOInt(pair.getFirst()); + DRes b = pair.getSecond(); + PlainT eMsb = eOpen.testBitAsUInt(k - 1); + PlainT eMsbByTwo = eMsb.multiply(factory.two()); + return nb.sub( + nb.addOpen(eMsb, b), + nb.multByOpen(eMsbByTwo, b) + ); + }); + } +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAddKnownProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAddKnownProtocol.java index 66abf9175..bb822cfec 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAddKnownProtocol.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAddKnownProtocol.java @@ -34,7 +34,7 @@ public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourceP Network network) { Spdz2kDataSupplier dataSupplier = resourcePool.getDataSupplier(); CompUIntFactory factory = resourcePool.getFactory(); - out = toSpdz2kSInt(right).addConstant(left, + out = factory.toSpdz2kSIntArithmetic(right).addConstant(left, dataSupplier.getSecretSharedKey(), factory.zero(), resourcePool.getMyId() == 1); diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAddProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAddProtocol.java new file mode 100644 index 000000000..2d8700907 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAddProtocol.java @@ -0,0 +1,39 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; + +public class Spdz2kAddProtocol> extends + Spdz2kNativeProtocol { + + private final DRes left; + private final DRes right; + private SInt result; + + public Spdz2kAddProtocol( + DRes left, + DRes right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + Spdz2kSIntArithmetic leftVal = resourcePool.getFactory().toSpdz2kSIntArithmetic(left); + Spdz2kSIntArithmetic rightVal = resourcePool.getFactory().toSpdz2kSIntArithmetic(right); + result = leftVal.add(rightVal); + return EvaluationStatus.IS_DONE; + } + + @Override + public SInt out() { + return result; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndBatchedProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndBatchedProtocol.java new file mode 100644 index 000000000..66162cfad --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndBatchedProtocol.java @@ -0,0 +1,188 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.util.OpenedValueStore; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.util.ArrayList; +import java.util.List; + +/** + * Native protocol for computing logical AND of two values in boolean form. + */ +public class Spdz2kAndBatchedProtocol> extends + Spdz2kNativeProtocol>, PlainT> { + + private DRes>> bitsADef; + private DRes>> bitsBDef; + // TODO final LinkedLists? + private List>> triples; + private List> epsilons; + private List> deltas; + private List openEpsilons; + private List openDeltas; + private List> products; + + public Spdz2kAndBatchedProtocol(DRes>> bitsA, + DRes>> bitsB) { + this.bitsADef = bitsA; + this.bitsBDef = bitsB; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + PlainT macKeyShare = resourcePool.getDataSupplier().getSecretSharedKey(); + CompUIntFactory factory = resourcePool.getFactory(); + List> bitsA = bitsADef.out(); + List> bitsB = bitsBDef.out(); + if (bitsA.size() != bitsB.size()) { + throw new IllegalArgumentException("Lists must be same size"); + } + if (round == 0) { + triples = new ArrayList<>(bitsA.size()); + epsilons = new ArrayList<>(bitsA.size()); + deltas = new ArrayList<>(bitsA.size()); + openEpsilons = new ArrayList<>(bitsA.size()); + openDeltas = new ArrayList<>(bitsA.size()); + products = new ArrayList<>(bitsA.size()); + + for (int i = 0; i < bitsA.size(); i++) { + Spdz2kTriple> triple = resourcePool + .getDataSupplier() + .getNextBitTripleShares(); + triples.add(triple); + + Spdz2kSIntBoolean left = factory.toSpdz2kSIntBoolean(bitsA.get(i)); + Spdz2kSIntBoolean right = factory.toSpdz2kSIntBoolean(bitsB.get(i)); + + epsilons.add(factory.toSpdz2kSIntBoolean(left).xor(triple.getLeft())); + deltas.add(factory.toSpdz2kSIntBoolean(right).xor(triple.getRight())); + } + + serializeAndSend(network, epsilons, deltas); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + receiveAndReconstruct(network, factory, resourcePool.getNoOfParties()); + + OpenedValueStore, PlainT> openedValueStore = resourcePool + .getOpenedValueStore(); + + for (int i = 0; i < bitsA.size(); i++) { + Spdz2kTriple> triple = triples.get(i); + + PlainT e = openEpsilons.get(i); + openedValueStore.pushOpenedValue(epsilons.get(i).asArithmetic(), e.toArithmeticRep()); + PlainT d = openDeltas.get(i); + openedValueStore.pushOpenedValue(deltas.get(i).asArithmetic(), d.toArithmeticRep()); + + Spdz2kSIntBoolean prod = andAfterReceive(e, d, triple, macKeyShare, factory, + resourcePool.getMyId()); + + products.add(prod); + } + return EvaluationStatus.IS_DONE; + } + } + + private Spdz2kSIntBoolean andAfterReceive( + PlainT e, + PlainT d, + Spdz2kTriple> triple, + PlainT macKeyShare, + CompUIntFactory factory, + int myId) { + int eBit = e.bitValue(); + int dBit = d.bitValue(); + PlainT ed = e.multiply(d); + // compute [prod] = [c] XOR epsilon AND [b] XOR delta AND [a] XOR epsilon AND delta + Spdz2kSIntBoolean tripleLeft = triple.getLeft(); + Spdz2kSIntBoolean tripleRight = triple.getRight(); + Spdz2kSIntBoolean tripleProduct = triple.getProduct(); + return tripleProduct + .xor(tripleRight.and(eBit)) + .xor(tripleLeft.and(dBit)) + .xorOpen(ed, + macKeyShare, + factory.zero().toBitRep(), + myId == 1); + } + + /** + * Retrieves shares for epsilons and deltas and reconstructs each. + */ + private void receiveAndReconstruct(Network network, CompUIntFactory factory, + int noOfParties) { + byte[] rawEpsilons = network.receive(1); + byte[] rawDeltas = network.receive(1); + + for (int i = 0; i < epsilons.size(); i++) { + int currentByteIdx = i / Byte.SIZE; + int bitIndexWithinByte = i % Byte.SIZE; + PlainT e = factory.fromBit((rawEpsilons[currentByteIdx] >>> bitIndexWithinByte)); + openEpsilons.add(e); + PlainT d = factory.fromBit((rawDeltas[currentByteIdx] >>> bitIndexWithinByte)); + openDeltas.add(d); + } + + for (int i = 2; i <= noOfParties; i++) { + rawEpsilons = network.receive(i); + rawDeltas = network.receive(i); + + for (int j = 0; j < epsilons.size(); j++) { + int currentByteIdx = j / Byte.SIZE; + int bitIndexWithinByte = j % Byte.SIZE; + openEpsilons.set(j, openEpsilons.get(j).add( + factory.fromBit((rawEpsilons[currentByteIdx] >>> bitIndexWithinByte)) + )); + openDeltas.set(j, openDeltas.get(j).add( + factory.fromBit((rawDeltas[currentByteIdx] >>> bitIndexWithinByte)) + )); + } + } + } + + /** + * Serializes and sends epsilon and delta values. + */ + private void serializeAndSend(Network network, + List> epsilons, + List> deltas) { + int numBytes = epsilons.size() / Byte.SIZE; + if (epsilons.size() % 8 != 0) { + numBytes++; + } + byte[] epsilonBytes = new byte[numBytes]; + byte[] deltaBytes = new byte[numBytes]; + + for (int i = 0; i < epsilons.size(); i++) { + int currentByteIdx = i / Byte.SIZE; + int bitIndexWithinByte = i % Byte.SIZE; + + int serializedEpsilon = epsilons.get(i).getShare().bitValue(); + epsilonBytes[currentByteIdx] |= ((serializedEpsilon << bitIndexWithinByte) + & (1 << bitIndexWithinByte)); + + int serializedDelta = deltas + .get(i) + .getShare() + .bitValue(); + deltaBytes[currentByteIdx] |= ((serializedDelta << bitIndexWithinByte) + & (1 << bitIndexWithinByte)); + } + network.sendToAll(epsilonBytes); + network.sendToAll(deltaBytes); + } + + @Override + public List> out() { + return products; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndKnownBatchedProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndKnownBatchedProtocol.java new file mode 100644 index 000000000..f6316b973 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndKnownBatchedProtocol.java @@ -0,0 +1,53 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.util.ArrayList; +import java.util.List; + +public class Spdz2kAndKnownBatchedProtocol> extends + Spdz2kNativeProtocol>, PlainT> { + + private final DRes> left; + private final DRes>> right; + private List> result; + + public Spdz2kAndKnownBatchedProtocol( + DRes> left, + DRes>> right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + CompUIntFactory factory = resourcePool.getFactory(); + List leftOut = left.out(); + List> rightOut = right.out(); + if (leftOut.size() != rightOut.size()) { + throw new IllegalArgumentException("Lists must be same size"); + } + this.result = new ArrayList<>(leftOut.size()); + for (int i = 0; i < leftOut.size(); i++) { + PlainT knownBit = factory.fromOInt(leftOut.get(i)).toBitRep(); + DRes secretBit = rightOut.get(i); + Spdz2kSIntBoolean andedBit = factory.toSpdz2kSIntBoolean(secretBit) + .and(knownBit.bitValue()); + result.add(andedBit); + } + return EvaluationStatus.IS_DONE; + } + + @Override + public List> out() { + return result; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndKnownProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndKnownProtocol.java new file mode 100644 index 000000000..7cbe9ccd9 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndKnownProtocol.java @@ -0,0 +1,39 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; + +public class Spdz2kAndKnownProtocol> extends + Spdz2kNativeProtocol { + + private final DRes left; + private final DRes right; + private SInt result; + + public Spdz2kAndKnownProtocol( + DRes left, + DRes right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + CompUIntFactory factory = resourcePool.getFactory(); + int known = factory.fromOInt(left.out()).toInt(); + result = factory.toSpdz2kSIntBoolean(right).and(known); + return EvaluationStatus.IS_DONE; + } + + @Override + public SInt out() { + return result; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndProtocol.java new file mode 100644 index 000000000..28f502a4b --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kAndProtocol.java @@ -0,0 +1,105 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.util.Arrays; + +/** + * Native protocol for computing logical AND of two values in boolean form. + */ +public class Spdz2kAndProtocol> extends + Spdz2kNativeProtocol { + + private final DRes left; + private final DRes right; + private Spdz2kTriple> triple; + private Spdz2kSIntBoolean epsilon; + private Spdz2kSIntBoolean delta; + private SInt product; + + /** + * Creates new {@link dk.alexandra.fresco.suite.spdz2k.protocols.natives.Spdz2kMultiplyProtocol}. + * + * @param left left factor + * @param right right factor + */ + public Spdz2kAndProtocol(DRes left, DRes right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + PlainT macKeyShare = resourcePool.getDataSupplier().getSecretSharedKey(); + CompUIntFactory factory = resourcePool.getFactory(); + if (round == 0) { + triple = resourcePool.getDataSupplier().getNextBitTripleShares(); + epsilon = factory.toSpdz2kSIntBoolean(left).xor(triple.getLeft()); + delta = factory.toSpdz2kSIntBoolean(right).xor(triple.getRight()); + int packed = epsilon.serializeShareLow()[0] ^ (delta.serializeShareLow()[0] << 1); + final byte[] bytes = new byte[]{(byte) packed}; + network.sendToAll(bytes); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + Pair epsilonAndDelta = receiveAndReconstruct(network, + resourcePool.getNoOfParties(), + factory); + PlainT e = epsilonAndDelta.getFirst(); + PlainT d = epsilonAndDelta.getSecond(); + resourcePool.getOpenedValueStore().pushOpenedValues( + Arrays.asList( + epsilon.asArithmetic(), + delta.asArithmetic() + ), + Arrays.asList( + e.toArithmeticRep(), + d.toArithmeticRep() + ) + ); + int eBit = e.bitValue(); + int dBit = d.bitValue(); + PlainT ed = e.multiply(d); + // compute [prod] = [c] XOR epsilon AND [b] XOR delta AND [a] XOR epsilon AND delta + Spdz2kSIntBoolean tripleLeft = triple.getLeft(); + Spdz2kSIntBoolean tripleRight = triple.getRight(); + Spdz2kSIntBoolean tripleProduct = triple.getProduct(); + this.product = tripleProduct + .xor(tripleRight.and(eBit)) + .xor(tripleLeft.and(dBit)) + .xorOpen(ed, + macKeyShare, + factory.zero().toBitRep(), + resourcePool.getMyId() == 1); + return EvaluationStatus.IS_DONE; + } + } + + /** + * Retrieves shares for epsilon and delta and reconstructs each. + */ + private Pair receiveAndReconstruct(Network network, + int noOfParties, CompUIntFactory factory) { + int received = network.receive(1)[0]; + PlainT e = factory.fromBit(received & 1); // first bit + PlainT d = factory.fromBit((received & 2) >>> 1); // second bit + for (int i = 2; i <= noOfParties; i++) { + received = network.receive(i)[0]; + e = e.add(factory.fromBit(received & 1)); + d = d.add(factory.fromBit((received & 2) >>> 1)); + } + return new Pair<>(e, d); + } + + @Override + public SInt out() { + return product; + } +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kArithmeticToBooleanProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kArithmeticToBooleanProtocol.java new file mode 100644 index 000000000..590e4013c --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kArithmeticToBooleanProtocol.java @@ -0,0 +1,38 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; + +public class Spdz2kArithmeticToBooleanProtocol> extends + Spdz2kNativeProtocol { + + private final DRes arithmetic; + private SInt bool; + + public Spdz2kArithmeticToBooleanProtocol(DRes arithmetic) { + this.arithmetic = arithmetic; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + Spdz2kSIntArithmetic value = resourcePool.getFactory() + .toSpdz2kSIntArithmetic(arithmetic); + bool = new Spdz2kSIntBoolean<>( + value.getShare().toBitRep(), + value.getMacShare().toBitRep().toArithmeticRep() // results in shift + ); + return EvaluationStatus.IS_DONE; + } + + @Override + public SInt out() { + return bool; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kBooleanToArithmeticProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kBooleanToArithmeticProtocol.java new file mode 100644 index 000000000..91919b738 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kBooleanToArithmeticProtocol.java @@ -0,0 +1,73 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; + +/** + * Native protocol for converting boolean shares to arithmetic shares. + */ +public class Spdz2kBooleanToArithmeticProtocol> extends + Spdz2kNativeProtocol { + + private final DRes bool; + private SInt arithmetic; + private Spdz2kSIntArithmetic arithmeticR; + private Spdz2kSIntBoolean c; + + public Spdz2kBooleanToArithmeticProtocol(DRes bool) { + this.bool = bool; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + CompUIntFactory factory = resourcePool.getFactory(); + if (round == 0) { + arithmeticR = resourcePool.getDataSupplier().getNextBitShare(); + Spdz2kSIntBoolean booleanR = arithmeticR.toBoolean(); + c = factory.toSpdz2kSIntBoolean(bool).xor(booleanR); + network.sendToAll(c.serializeShareLow()); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + PlainT openC = receiveAndReconstruct(network, resourcePool.getNoOfParties(), factory); + resourcePool.getOpenedValueStore().pushOpenedValue( + c.asArithmetic(), + openC.toArithmeticRep() + ); + // TODO + PlainT openCBit = openC.bitValue() == 1 ? factory.one() : factory.zero(); + PlainT macKeyShare = resourcePool.getDataSupplier().getSecretSharedKey(); + boolean isPartyOne = resourcePool.getMyId() == 1; + arithmetic = arithmeticR.addConstant(openCBit, macKeyShare, factory.zero(), + isPartyOne).subtract(arithmeticR.multiply(factory.two().multiplyByBit(openC.bitValue()))); + return EvaluationStatus.IS_DONE; + } + } + + /** + * Receive shares of value and reconstruct.

Note that this includes overflow into top s + * bits.

+ */ + private PlainT receiveAndReconstruct(Network network, int noOfParties, + CompUIntFactory factory) { + int received = network.receive(1)[0]; + PlainT opened = factory.fromBit(received); + for (int i = 2; i <= noOfParties; i++) { + received = network.receive(i)[0]; + opened = opened.add(factory.fromBit(received)); + } + return opened; + } + + @Override + public SInt out() { + return arithmetic; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kCarryProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kCarryProtocol.java new file mode 100644 index 000000000..713b7d657 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kCarryProtocol.java @@ -0,0 +1,213 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.util.OpenedValueStore; +import dk.alexandra.fresco.framework.util.SIntPair; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.util.ArrayList; +import java.util.List; + +public class Spdz2kCarryProtocol> extends + Spdz2kNativeProtocol, PlainT> { + + private final List bits; + private List>> triples; + private List> epsilons; + private List> deltas; + private List openEpsilons; + private List openDeltas; + private List carried; + + public Spdz2kCarryProtocol(List bits) { + this.bits = bits; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + PlainT macKeyShare = resourcePool.getDataSupplier().getSecretSharedKey(); + CompUIntFactory factory = resourcePool.getFactory(); + if (round == 0) { + triples = new ArrayList<>(bits.size()); + epsilons = new ArrayList<>(bits.size()); + deltas = new ArrayList<>(bits.size()); + openEpsilons = new ArrayList<>(bits.size()); + openDeltas = new ArrayList<>(bits.size()); + carried = new ArrayList<>(bits.size() / 2); + + for (int i = 0; i < bits.size() / 2; i++) { + // two multiplications + triples.add(resourcePool.getDataSupplier().getNextBitTripleShares()); + triples.add(resourcePool.getDataSupplier().getNextBitTripleShares()); + + SIntPair left = bits.get(2 * i + 1); + SIntPair right = bits.get(2 * i); + + Spdz2kTriple> p1p2Triple = triples.get(2 * i + 1); + Spdz2kTriple> p2g1Triple = triples.get(2 * i); + + Spdz2kSIntBoolean p1 = factory.toSpdz2kSIntBoolean(left.getFirst()); + Spdz2kSIntBoolean g1 = factory.toSpdz2kSIntBoolean(left.getSecond()); + Spdz2kSIntBoolean p2 = factory.toSpdz2kSIntBoolean(right.getFirst()); + + // p2 * g1 + epsilons.add(factory.toSpdz2kSIntBoolean(p2).xor(p2g1Triple.getLeft())); + deltas.add(factory.toSpdz2kSIntBoolean(g1).xor(p2g1Triple.getRight())); + + // p1 * p2 + epsilons.add(factory.toSpdz2kSIntBoolean(p1).xor(p1p2Triple.getLeft())); + deltas.add(factory.toSpdz2kSIntBoolean(p2).xor(p1p2Triple.getRight())); + } + + serializeAndSend(network, epsilons, deltas); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + receiveAndReconstruct(network, factory, resourcePool.getNoOfParties()); + + OpenedValueStore, PlainT> openedValueStore = resourcePool + .getOpenedValueStore(); + + for (int i = 0; i < bits.size() / 2; i++) { + Spdz2kTriple> p1p2Triple = triples.get(2 * i + 1); + Spdz2kTriple> p2g1Triple = triples.get(2 * i); + + PlainT p1p2E = openEpsilons.get(2 * i + 1); + openedValueStore.pushOpenedValue( + epsilons.get(2 * i + 1).asArithmetic(), + p1p2E.toArithmeticRep() + ); + PlainT p2g1E = openEpsilons.get(2 * i); + openedValueStore.pushOpenedValue( + epsilons.get(2 * i).asArithmetic(), + p2g1E.toArithmeticRep() + ); + + PlainT p1p2D = openDeltas.get(2 * i + 1); + openedValueStore.pushOpenedValue( + deltas.get(2 * i + 1).asArithmetic(), + p1p2D.toArithmeticRep() + ); + PlainT p2g1D = openDeltas.get(2 * i); + openedValueStore.pushOpenedValue( + deltas.get(2 * i).asArithmetic(), + p2g1D.toArithmeticRep() + ); + Spdz2kSIntBoolean p = andAfterReceive(p1p2E, p1p2D, p1p2Triple, macKeyShare, + factory, + resourcePool.getMyId()); + + Spdz2kSIntBoolean g2 = factory.toSpdz2kSIntBoolean(bits.get(2 * i).getSecond()); + + Spdz2kSIntBoolean g = andAfterReceive(p2g1E, p2g1D, p2g1Triple, macKeyShare, + factory, + resourcePool.getMyId()).xor(g2); + carried.add(new SIntPair(p, g)); + } + // if we have an odd number of elements the last pair can just be taken directly from the input + if (bits.size() % 2 != 0) { + carried.add(bits.get(bits.size() - 1)); + } + return EvaluationStatus.IS_DONE; + } + } + + private Spdz2kSIntBoolean andAfterReceive( + PlainT e, + PlainT d, + Spdz2kTriple> triple, + PlainT macKeyShare, + CompUIntFactory factory, + int myId) { + int eBit = e.bitValue(); + int dBit = d.bitValue(); + PlainT ed = e.multiply(d); + // compute [prod] = [c] XOR epsilon AND [b] XOR delta AND [a] XOR epsilon AND delta + Spdz2kSIntBoolean tripleLeft = triple.getLeft(); + Spdz2kSIntBoolean tripleRight = triple.getRight(); + Spdz2kSIntBoolean tripleProduct = triple.getProduct(); + return tripleProduct + .xor(tripleRight.and(eBit)) + .xor(tripleLeft.and(dBit)) + .xorOpen(ed, + macKeyShare, + factory.zero().toBitRep(), + myId == 1); + } + + /** + * Retrieves shares for epsilons and deltas and reconstructs each. + */ + private void receiveAndReconstruct(Network network, CompUIntFactory factory, + int noOfParties) { + byte[] rawEpsilons = network.receive(1); + byte[] rawDeltas = network.receive(1); + + for (int i = 0; i < epsilons.size(); i++) { + int currentByteIdx = i / Byte.SIZE; + int bitIndexWithinByte = i % Byte.SIZE; + PlainT e = factory.fromBit((rawEpsilons[currentByteIdx] >>> bitIndexWithinByte)); + openEpsilons.add(e); + PlainT d = factory.fromBit((rawDeltas[currentByteIdx] >>> bitIndexWithinByte)); + openDeltas.add(d); + } + + for (int i = 2; i <= noOfParties; i++) { + rawEpsilons = network.receive(i); + rawDeltas = network.receive(i); + + for (int j = 0; j < epsilons.size(); j++) { + int currentByteIdx = j / Byte.SIZE; + int bitIndexWithinByte = j % Byte.SIZE; + openEpsilons.set(j, openEpsilons.get(j).add( + factory.fromBit((rawEpsilons[currentByteIdx] >>> bitIndexWithinByte)) + )); + openDeltas.set(j, openDeltas.get(j).add( + factory.fromBit((rawDeltas[currentByteIdx] >>> bitIndexWithinByte)) + )); + } + } + } + + /** + * Serializes and sends epsilon and delta values. + */ + private void serializeAndSend(Network network, + List> epsilons, + List> deltas) { + int numBytes = epsilons.size() / Byte.SIZE; + if (epsilons.size() % 8 != 0) { + numBytes++; + } + byte[] epsilonBytes = new byte[numBytes]; + byte[] deltaBytes = new byte[numBytes]; + + for (int i = 0; i < epsilons.size(); i++) { + int currentByteIdx = i / Byte.SIZE; + int bitIndexWithinByte = i % Byte.SIZE; + + int serializedEpsilon = epsilons.get(i).getShare().bitValue(); + epsilonBytes[currentByteIdx] |= ((serializedEpsilon << bitIndexWithinByte) + & (1 << bitIndexWithinByte)); + + int serializedDelta = deltas + .get(i) + .getShare() + .bitValue(); + deltaBytes[currentByteIdx] |= ((serializedDelta << bitIndexWithinByte) + & (1 << bitIndexWithinByte)); + } + network.sendToAll(epsilonBytes); + network.sendToAll(deltaBytes); + } + + @Override + public List out() { + return carried; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kInputOnlyProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kInputOnlyProtocol.java index 11a59a8bb..441a1892d 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kInputOnlyProtocol.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kInputOnlyProtocol.java @@ -8,13 +8,14 @@ import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kInputMask; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.InputComputationSpdz2k; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDataSupplier; /** * Native protocol for inputting data.

This is used by native computation {@link - * dk.alexandra.fresco.suite.spdz2k.protocols.computations.Spdz2kInputComputation}. The result of + * InputComputationSpdz2k}. The result of * this protocol is this party's share of the input, as well as the bytes of the masked input which * are later used in a broadcast validation.

*/ @@ -54,8 +55,8 @@ public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourceP } else { byte[] inputMaskBytes = network.receive(inputPartyId); PlainT macKeyShare = dataSupplier.getSecretSharedKey(); - Spdz2kSInt maskShare = inputMask.getMaskShare(); - Spdz2kSInt out = maskShare.addConstant( + Spdz2kSIntArithmetic maskShare = inputMask.getMaskShare(); + Spdz2kSIntArithmetic out = maskShare.addConstant( serializer.deserialize(inputMaskBytes), macKeyShare, factory.zero(), diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kKnownSIntProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kKnownSIntProtocol.java index 607b7fa86..f6efc5aac 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kKnownSIntProtocol.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kKnownSIntProtocol.java @@ -4,7 +4,7 @@ import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDataSupplier; @@ -32,7 +32,7 @@ public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourceP CompUIntFactory factory = resourcePool.getFactory(); Spdz2kDataSupplier dataSupplier = resourcePool.getDataSupplier(); boolean isPartyOne = (resourcePool.getMyId() == 1); - out = new Spdz2kSInt<>(input, dataSupplier.getSecretSharedKey(), factory.zero(), isPartyOne); + out = new Spdz2kSIntArithmetic<>(input, dataSupplier.getSecretSharedKey(), factory.zero(), isPartyOne); return EvaluationStatus.IS_DONE; } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kMultKnownProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kMultKnownProtocol.java new file mode 100644 index 000000000..092a6a167 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kMultKnownProtocol.java @@ -0,0 +1,45 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; + +/** + * Native protocol from computing the product of a secret value and a public constant. + */ +public class Spdz2kMultKnownProtocol> + extends Spdz2kNativeProtocol { + + private final DRes left; + private final DRes right; + private SInt out; + + /** + * Creates new {@link Spdz2kMultKnownProtocol}. + * + * @param left public factor + * @param right secret factor + */ + public Spdz2kMultKnownProtocol(DRes left, DRes right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + CompUIntFactory factory = resourcePool.getFactory(); + out = factory.toSpdz2kSIntArithmetic(right).multiply(factory.fromOInt(left)); + return EvaluationStatus.IS_DONE; + } + + @Override + public SInt out() { + return out; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kMultiplyProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kMultiplyProtocol.java index 493642e34..348fe5bb2 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kMultiplyProtocol.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kMultiplyProtocol.java @@ -7,7 +7,7 @@ import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; import java.util.Arrays; @@ -20,9 +20,9 @@ public class Spdz2kMultiplyProtocol> exten private final DRes left; private final DRes right; - private Spdz2kTriple triple; - private Spdz2kSInt epsilon; - private Spdz2kSInt delta; + private Spdz2kTriple> triple; + private Spdz2kSIntArithmetic epsilon; + private Spdz2kSIntArithmetic delta; private SInt product; /** @@ -41,26 +41,26 @@ public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourceP Network network) { final PlainT macKeyShare = resourcePool.getDataSupplier().getSecretSharedKey(); ByteSerializer serializer = resourcePool.getPlainSerializer(); + CompUIntFactory factory = resourcePool.getFactory(); if (round == 0) { - triple = resourcePool.getDataSupplier().getNextTripleShares(); - epsilon = toSpdz2kSInt(left).subtract(triple.getLeft()); - delta = toSpdz2kSInt(right).subtract(triple.getRight()); - network.sendToAll(epsilon.getShare().getLeastSignificant().toByteArray()); - network.sendToAll(delta.getShare().getLeastSignificant().toByteArray()); + triple = resourcePool.getDataSupplier().getNextTripleSharesFull(); + epsilon = factory.toSpdz2kSIntArithmetic(left).subtract(triple.getLeft()); + delta = factory.toSpdz2kSIntArithmetic(right).subtract(triple.getRight()); + network.sendToAll(epsilon.serializeShareLow()); + network.sendToAll(delta.serializeShareLow()); return EvaluationStatus.HAS_MORE_ROUNDS; } else { Pair epsilonAndDelta = receiveAndReconstruct(network, - resourcePool.getFactory(), + factory, resourcePool.getNoOfParties(), serializer); // compute [prod] = [c] + epsilon * [b] + delta * [a] + epsilon * delta PlainT e = epsilonAndDelta.getFirst(); PlainT d = epsilonAndDelta.getSecond(); PlainT ed = e.multiply(d); - Spdz2kSInt tripleRight = triple.getRight(); - Spdz2kSInt tripleLeft = triple.getLeft(); - Spdz2kSInt tripleProduct = triple.getProduct(); - CompUIntFactory factory = resourcePool.getFactory(); + Spdz2kSIntArithmetic tripleRight = triple.getRight(); + Spdz2kSIntArithmetic tripleLeft = triple.getLeft(); + Spdz2kSIntArithmetic tripleProduct = triple.getProduct(); this.product = tripleProduct .add(tripleRight.multiply(e)) .add(tripleLeft.multiply(d)) diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kNativeProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kNativeProtocol.java index 5a222e471..abca9d49d 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kNativeProtocol.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kNativeProtocol.java @@ -1,12 +1,8 @@ package dk.alexandra.fresco.suite.spdz2k.protocols.natives; -import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.NativeProtocol; -import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; -import java.util.Objects; /** * Generic native Spdz2k protocol. @@ -16,11 +12,4 @@ public abstract class Spdz2kNativeProtocol< PlainT extends CompUInt> implements NativeProtocol> { - /** - * Get result from deferred and downcast result to {@link Spdz2kSInt}. - */ - Spdz2kSInt toSpdz2kSInt(DRes value) { - return Objects.requireNonNull((Spdz2kSInt) value.out()); - } - } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kNotBatchedProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kNotBatchedProtocol.java new file mode 100644 index 000000000..ef68480b1 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kNotBatchedProtocol.java @@ -0,0 +1,44 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.util.ArrayList; +import java.util.List; + +public class Spdz2kNotBatchedProtocol> extends + Spdz2kNativeProtocol>, PlainT> { + + private final DRes>> bits; + private List> result; + + public Spdz2kNotBatchedProtocol(DRes>> bits) { + this.bits = bits; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + CompUIntFactory factory = resourcePool.getFactory(); + PlainT secretSharedKey = resourcePool.getDataSupplier().getSecretSharedKey(); + List> bitsOut = bits.out(); + this.result = new ArrayList<>(bitsOut.size()); + for (DRes secretBit : bitsOut) { + Spdz2kSIntBoolean notBit = factory.toSpdz2kSIntBoolean(secretBit) + .xorOpen(factory.one().toBitRep(), secretSharedKey, factory.zero().toBitRep(), + resourcePool.getMyId() == 1); + result.add(notBit); + } + return EvaluationStatus.IS_DONE; + } + + @Override + public List> out() { + return result; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOrBatchedProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOrBatchedProtocol.java new file mode 100644 index 000000000..577f52930 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOrBatchedProtocol.java @@ -0,0 +1,199 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.util.OpenedValueStore; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.util.ArrayList; +import java.util.List; + +/** + * Native protocol for computing logical OR of twos lists of values. + */ +public class Spdz2kOrBatchedProtocol> extends + Spdz2kNativeProtocol>, PlainT> { + + private DRes>> bitsADef; + private DRes>> bitsBDef; + private List>> triples; + private List> epsilons; + private List> deltas; + private List openEpsilons; + private List openDeltas; + private final DRes extraBit; + private List> products; + + public Spdz2kOrBatchedProtocol(DRes>> bitsA, + DRes>> bitsB, DRes extraBit) { + this.bitsADef = bitsA; + this.bitsBDef = bitsB; + this.extraBit = extraBit; + } + + public Spdz2kOrBatchedProtocol(DRes>> bitsA, + DRes>> bitsB) { + this(bitsA, bitsB, null); + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + PlainT macKeyShare = resourcePool.getDataSupplier().getSecretSharedKey(); + CompUIntFactory factory = resourcePool.getFactory(); + List> bitsA = bitsADef.out(); + List> bitsB = bitsBDef.out(); + if (bitsA.size() != bitsB.size()) { + throw new IllegalArgumentException("Lists must be same size"); + } + if (round == 0) { + triples = new ArrayList<>(bitsA.size()); + epsilons = new ArrayList<>(bitsA.size()); + deltas = new ArrayList<>(bitsA.size()); + openEpsilons = new ArrayList<>(bitsA.size()); + openDeltas = new ArrayList<>(bitsA.size()); + products = new ArrayList<>(bitsA.size()); + + for (int i = 0; i < bitsA.size(); i++) { + Spdz2kTriple> triple = resourcePool + .getDataSupplier() + .getNextBitTripleShares(); + triples.add(triple); + + Spdz2kSIntBoolean left = factory.toSpdz2kSIntBoolean(bitsA.get(i)); + Spdz2kSIntBoolean right = factory.toSpdz2kSIntBoolean(bitsB.get(i)); + + epsilons.add(factory.toSpdz2kSIntBoolean(left).xor(triple.getLeft())); + deltas.add(factory.toSpdz2kSIntBoolean(right).xor(triple.getRight())); + } + + serializeAndSend(network, epsilons, deltas); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + receiveAndReconstruct(network, factory, resourcePool.getNoOfParties()); + + OpenedValueStore, PlainT> openedValueStore = resourcePool + .getOpenedValueStore(); + + for (int i = 0; i < bitsA.size(); i++) { + Spdz2kTriple> triple = triples.get(i); + + PlainT e = openEpsilons.get(i); + openedValueStore.pushOpenedValue(epsilons.get(i).asArithmetic(), e.toArithmeticRep()); + PlainT d = openDeltas.get(i); + openedValueStore.pushOpenedValue(deltas.get(i).asArithmetic(), d.toArithmeticRep()); + + Spdz2kSIntBoolean prod = andAfterReceive(e, d, triple, macKeyShare, factory, + resourcePool.getMyId()); + Spdz2kSIntBoolean xored = factory.toSpdz2kSIntBoolean(bitsA.get(i)) + .xor(factory.toSpdz2kSIntBoolean(bitsB.get(i))); + + products.add(prod.xor(xored)); + } + if (extraBit != null) { + products.add(extraBit); + } + return EvaluationStatus.IS_DONE; + } + } + + private Spdz2kSIntBoolean andAfterReceive( + PlainT e, + PlainT d, + Spdz2kTriple> triple, + PlainT macKeyShare, + CompUIntFactory factory, + int myId) { + int eBit = e.bitValue(); + int dBit = d.bitValue(); + PlainT ed = e.multiply(d); + // compute [prod] = [c] XOR epsilon AND [b] XOR delta AND [a] XOR epsilon AND delta + Spdz2kSIntBoolean tripleLeft = triple.getLeft(); + Spdz2kSIntBoolean tripleRight = triple.getRight(); + Spdz2kSIntBoolean tripleProduct = triple.getProduct(); + return tripleProduct + .xor(tripleRight.and(eBit)) + .xor(tripleLeft.and(dBit)) + .xorOpen(ed, + macKeyShare, + factory.zero().toBitRep(), + myId == 1); + } + + /** + * Retrieves shares for epsilons and deltas and reconstructs each. + */ + private void receiveAndReconstruct(Network network, CompUIntFactory factory, + int noOfParties) { + byte[] rawEpsilons = network.receive(1); + byte[] rawDeltas = network.receive(1); + + for (int i = 0; i < epsilons.size(); i++) { + int currentByteIdx = i / Byte.SIZE; + int bitIndexWithinByte = i % Byte.SIZE; + PlainT e = factory.fromBit((rawEpsilons[currentByteIdx] >>> bitIndexWithinByte)); + openEpsilons.add(e); + PlainT d = factory.fromBit((rawDeltas[currentByteIdx] >>> bitIndexWithinByte)); + openDeltas.add(d); + } + + for (int i = 2; i <= noOfParties; i++) { + rawEpsilons = network.receive(i); + rawDeltas = network.receive(i); + + for (int j = 0; j < epsilons.size(); j++) { + int currentByteIdx = j / Byte.SIZE; + int bitIndexWithinByte = j % Byte.SIZE; + openEpsilons.set(j, openEpsilons.get(j).add( + factory.fromBit((rawEpsilons[currentByteIdx] >>> bitIndexWithinByte)) + )); + openDeltas.set(j, openDeltas.get(j).add( + factory.fromBit((rawDeltas[currentByteIdx] >>> bitIndexWithinByte)) + )); + } + } + } + + /** + * Serializes and sends epsilon and delta values. + */ + private void serializeAndSend(Network network, + List> epsilons, + List> deltas) { + int numBytes = epsilons.size() / Byte.SIZE; + if (epsilons.size() % 8 != 0) { + numBytes++; + } + byte[] epsilonBytes = new byte[numBytes]; + byte[] deltaBytes = new byte[numBytes]; + + for (int i = 0; i < epsilons.size(); i++) { + int currentByteIdx = i / Byte.SIZE; + int bitIndexWithinByte = i % Byte.SIZE; + + int serializedEpsilon = epsilons.get(i).getShare().bitValue(); + epsilonBytes[currentByteIdx] |= ((serializedEpsilon << bitIndexWithinByte) + & (1 << bitIndexWithinByte)); + + int serializedDelta = deltas + .get(i) + .getShare() + .bitValue(); + deltaBytes[currentByteIdx] |= ((serializedDelta << bitIndexWithinByte) + & (1 << bitIndexWithinByte)); + } + network.sendToAll(epsilonBytes); + network.sendToAll(deltaBytes); + } + + @Override + public List> out() { + return products; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOrOfListProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOrOfListProtocol.java new file mode 100644 index 000000000..59be6d4b6 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOrOfListProtocol.java @@ -0,0 +1,207 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.util.OpenedValueStore; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.util.ArrayList; +import java.util.List; + +public class Spdz2kOrOfListProtocol> extends + Spdz2kNativeProtocol { + + private final DRes>> bitsDef; + private SInt res; + private List> nextRound; + private List> bitsA; + private List> bitsB; + private List>> triples; + private List> epsilons; + private List> deltas; + private List openEpsilons; + private List openDeltas; + private SInt extraBit; + + public Spdz2kOrOfListProtocol(DRes>> bits) { + this.bitsDef = bits; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + PlainT macKeyShare = resourcePool.getDataSupplier().getSecretSharedKey(); + CompUIntFactory factory = resourcePool.getFactory(); +// System.out.println("Running round " + round); + + if (round % 2 == 0) { + if (nextRound == null) { + nextRound = bitsDef.out(); + } + final int nextRoundSize = nextRound.size(); + if (nextRoundSize == 1) { + res = nextRound.get(0).out(); + return EvaluationStatus.IS_DONE; + } + + bitsA = new ArrayList<>(nextRoundSize / 2); + bitsB = new ArrayList<>(nextRoundSize / 2); + for (int i = 0; i < nextRoundSize - 1; i += 2) { + bitsA.add(nextRound.get(i)); + bitsB.add(nextRound.get(i + 1)); + } + triples = new ArrayList<>(nextRoundSize / 2); + epsilons = new ArrayList<>(nextRoundSize / 2); + deltas = new ArrayList<>(nextRoundSize / 2); + openEpsilons = new ArrayList<>(nextRoundSize / 2); + openDeltas = new ArrayList<>(nextRoundSize / 2); + // reset next round + final boolean isOdd = nextRoundSize % 2 != 0; + if (isOdd) { + extraBit = nextRound.get(nextRoundSize - 1).out(); + } else { + extraBit = null; + } + nextRound = new ArrayList<>(nextRoundSize / 2); + for (int i = 0; i < bitsA.size(); i++) { + Spdz2kTriple> triple = resourcePool + .getDataSupplier() + .getNextBitTripleShares(); + triples.add(triple); + + Spdz2kSIntBoolean left = factory.toSpdz2kSIntBoolean(bitsA.get(i)); + Spdz2kSIntBoolean right = factory.toSpdz2kSIntBoolean(bitsB.get(i)); + + epsilons.add(factory.toSpdz2kSIntBoolean(left).xor(triple.getLeft())); + deltas.add(factory.toSpdz2kSIntBoolean(right).xor(triple.getRight())); + } + serializeAndSend(network, epsilons, deltas); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + receiveAndReconstruct(network, factory, resourcePool.getNoOfParties()); + + OpenedValueStore, PlainT> openedValueStore = resourcePool + .getOpenedValueStore(); + + for (int i = 0; i < bitsA.size(); i++) { + Spdz2kTriple> triple = triples.get(i); + + PlainT e = openEpsilons.get(i); + openedValueStore.pushOpenedValue(epsilons.get(i).asArithmetic(), e.toArithmeticRep()); + PlainT d = openDeltas.get(i); + openedValueStore.pushOpenedValue(deltas.get(i).asArithmetic(), d.toArithmeticRep()); + + Spdz2kSIntBoolean prod = andAfterReceive(e, d, triple, macKeyShare, factory, + resourcePool.getMyId()); + Spdz2kSIntBoolean xored = factory.toSpdz2kSIntBoolean(bitsA.get(i)) + .xor(factory.toSpdz2kSIntBoolean(bitsB.get(i))); + + nextRound.add(prod.xor(xored)); + } + if (extraBit != null) { + nextRound.add(extraBit); + } + return EvaluationStatus.HAS_MORE_ROUNDS; + } + } + + private Spdz2kSIntBoolean andAfterReceive( + PlainT e, + PlainT d, + Spdz2kTriple> triple, + PlainT macKeyShare, + CompUIntFactory factory, + int myId) { + int eBit = e.bitValue(); + int dBit = d.bitValue(); + PlainT ed = e.multiply(d); + // compute [prod] = [c] XOR epsilon AND [b] XOR delta AND [a] XOR epsilon AND delta + Spdz2kSIntBoolean tripleLeft = triple.getLeft(); + Spdz2kSIntBoolean tripleRight = triple.getRight(); + Spdz2kSIntBoolean tripleProduct = triple.getProduct(); + return tripleProduct + .xor(tripleRight.and(eBit)) + .xor(tripleLeft.and(dBit)) + .xorOpen(ed, + macKeyShare, + factory.zero().toBitRep(), + myId == 1); + } + + /** + * Retrieves shares for epsilons and deltas and reconstructs each. + */ + private void receiveAndReconstruct(Network network, CompUIntFactory factory, + int noOfParties) { + byte[] rawEpsilons = network.receive(1); + byte[] rawDeltas = network.receive(1); + + for (int i = 0; i < epsilons.size(); i++) { + int currentByteIdx = i / Byte.SIZE; + int bitIndexWithinByte = i % Byte.SIZE; + PlainT e = factory.fromBit((rawEpsilons[currentByteIdx] >>> bitIndexWithinByte)); + openEpsilons.add(e); + PlainT d = factory.fromBit((rawDeltas[currentByteIdx] >>> bitIndexWithinByte)); + openDeltas.add(d); + } + + for (int i = 2; i <= noOfParties; i++) { + rawEpsilons = network.receive(i); + rawDeltas = network.receive(i); + + for (int j = 0; j < epsilons.size(); j++) { + int currentByteIdx = j / Byte.SIZE; + int bitIndexWithinByte = j % Byte.SIZE; + openEpsilons.set(j, openEpsilons.get(j).add( + factory.fromBit((rawEpsilons[currentByteIdx] >>> bitIndexWithinByte)) + )); + openDeltas.set(j, openDeltas.get(j).add( + factory.fromBit((rawDeltas[currentByteIdx] >>> bitIndexWithinByte)) + )); + } + } + } + + /** + * Serializes and sends epsilon and delta values. + */ + private void serializeAndSend(Network network, + List> epsilons, + List> deltas) { + int numBytes = epsilons.size() / Byte.SIZE; + if (epsilons.size() % 8 != 0) { + numBytes++; + } + byte[] epsilonBytes = new byte[numBytes]; + byte[] deltaBytes = new byte[numBytes]; + + for (int i = 0; i < epsilons.size(); i++) { + int currentByteIdx = i / Byte.SIZE; + int bitIndexWithinByte = i % Byte.SIZE; + + int serializedEpsilon = epsilons.get(i).getShare().bitValue(); + epsilonBytes[currentByteIdx] |= ((serializedEpsilon << bitIndexWithinByte) + & (1 << bitIndexWithinByte)); + + int serializedDelta = deltas + .get(i) + .getShare() + .bitValue(); + deltaBytes[currentByteIdx] |= ((serializedDelta << bitIndexWithinByte) + & (1 << bitIndexWithinByte)); + } + network.sendToAll(epsilonBytes); + network.sendToAll(deltaBytes); + } + + @Override + public SInt out() { + return res; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOrProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOrProtocol.java new file mode 100644 index 000000000..d85c04b02 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOrProtocol.java @@ -0,0 +1,108 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.util.Arrays; + +/** + * Native protocol for computing logical OR of two values in boolean form. + */ +public class Spdz2kOrProtocol> extends + Spdz2kNativeProtocol { + + private final DRes left; + private final DRes right; + private Spdz2kTriple> triple; + private Spdz2kSIntBoolean epsilon; + private Spdz2kSIntBoolean delta; + private SInt result; + + /** + * Creates new {@link Spdz2kMultiplyProtocol}. + * + * @param left left factor + * @param right right factor + */ + public Spdz2kOrProtocol(DRes left, DRes right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + PlainT macKeyShare = resourcePool.getDataSupplier().getSecretSharedKey(); + CompUIntFactory factory = resourcePool.getFactory(); + if (round == 0) { + triple = resourcePool.getDataSupplier().getNextBitTripleShares(); + epsilon = factory.toSpdz2kSIntBoolean(left).xor(triple.getLeft()); + delta = factory.toSpdz2kSIntBoolean(right).xor(triple.getRight()); + int packed = epsilon.serializeShareLow()[0] ^ (delta.serializeShareLow()[0] << 1); + final byte[] bytes = new byte[]{(byte) packed}; + network.sendToAll(bytes); + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + Pair epsilonAndDelta = receiveAndReconstruct(network, + resourcePool.getNoOfParties(), + factory); + PlainT e = epsilonAndDelta.getFirst(); + PlainT d = epsilonAndDelta.getSecond(); + resourcePool.getOpenedValueStore().pushOpenedValues( + Arrays.asList( + epsilon.asArithmetic(), + delta.asArithmetic() + ), + Arrays.asList( + e.toArithmeticRep(), + d.toArithmeticRep() + ) + ); + int eBit = e.bitValue(); + int dBit = d.bitValue(); + PlainT ed = e.multiply(d); + // compute [prod] = [c] XOR epsilon AND [b] XOR delta AND [a] XOR epsilon AND delta + Spdz2kSIntBoolean tripleLeft = triple.getLeft(); + Spdz2kSIntBoolean tripleRight = triple.getRight(); + Spdz2kSIntBoolean tripleProduct = triple.getProduct(); + Spdz2kSIntBoolean anded = tripleProduct + .xor(tripleRight.and(eBit)) + .xor(tripleLeft.and(dBit)) + .xorOpen(ed, + macKeyShare, + factory.zero().toBitRep(), + resourcePool.getMyId() == 1); + Spdz2kSIntBoolean xored = factory.toSpdz2kSIntBoolean(left) + .xor(factory.toSpdz2kSIntBoolean(right)); + result = anded.xor(xored); + return EvaluationStatus.IS_DONE; + } + } + + /** + * Retrieves shares for epsilon and delta and reconstructs each. + */ + private Pair receiveAndReconstruct(Network network, + int noOfParties, CompUIntFactory factory) { + int received = network.receive(1)[0]; + PlainT e = factory.fromBit(received & 1); // first bit + PlainT d = factory.fromBit((received & 2) >>> 1); // second bit + for (int i = 2; i <= noOfParties; i++) { + received = network.receive(i)[0]; + e = e.add(factory.fromBit(received & 1)); + d = d.add(factory.fromBit((received & 2) >>> 1)); + } + return new Pair<>(e, d); + } + + @Override + public SInt out() { + return result; + } +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputSinglePartyProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputSinglePartyProtocol.java index 3ba3dd1fa..d17576b33 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputSinglePartyProtocol.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputSinglePartyProtocol.java @@ -3,28 +3,29 @@ import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.network.Network; import dk.alexandra.fresco.framework.util.OpenedValueStore; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kInputMask; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.datatypes.UInt; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDataSupplier; -import java.math.BigInteger; import java.util.List; /** * Native protocol for opening a secret value to a single party. */ public class Spdz2kOutputSinglePartyProtocol> - extends Spdz2kNativeProtocol + extends Spdz2kNativeProtocol implements RequiresMacCheck { private final DRes share; private final int outputParty; - private BigInteger opened; + private PlainT opened; private Spdz2kInputMask inputMask; - private Spdz2kSInt inMinusMask; + private Spdz2kSIntArithmetic inMinusMask; /** * Creates new {@link Spdz2kOutputSinglePartyProtocol}. @@ -40,13 +41,14 @@ public Spdz2kOutputSinglePartyProtocol(DRes share, int outputParty) { @Override public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, Network network) { - OpenedValueStore, PlainT> openedValueStore = resourcePool + OpenedValueStore, PlainT> openedValueStore = resourcePool .getOpenedValueStore(); Spdz2kDataSupplier supplier = resourcePool.getDataSupplier(); + CompUIntFactory factory = resourcePool.getFactory(); if (round == 0) { this.inputMask = supplier.getNextInputMask(outputParty); - inMinusMask = toSpdz2kSInt(share).subtract(this.inputMask.getMaskShare()); - network.sendToAll(inMinusMask.getShare().getLeastSignificant().toByteArray()); + inMinusMask = factory.toSpdz2kSIntArithmetic(share).subtract(this.inputMask.getMaskShare()); + network.sendToAll(inMinusMask.serializeShareLow()); return EvaluationStatus.HAS_MORE_ROUNDS; } else { List shares = resourcePool.getPlainSerializer() @@ -54,14 +56,14 @@ public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourceP PlainT recombined = UInt.sum(shares); openedValueStore.pushOpenedValue(inMinusMask, recombined); if (outputParty == resourcePool.getMyId()) { - this.opened = resourcePool.convertRepresentation(recombined.add(inputMask.getOpenValue())); + this.opened = recombined.add(inputMask.getOpenValue()).clearHighBits(); } return EvaluationStatus.IS_DONE; } } @Override - public BigInteger out() { + public OInt out() { return opened; } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputToAllProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputToAll.java similarity index 61% rename from suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputToAllProtocol.java rename to suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputToAll.java index cb32fe672..72aeefd58 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputToAllProtocol.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kOutputToAll.java @@ -4,55 +4,57 @@ import dk.alexandra.fresco.framework.network.Network; import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; import dk.alexandra.fresco.framework.util.OpenedValueStore; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.datatypes.UInt; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; -import java.math.BigInteger; import java.util.List; /** * Native protocol for opening a secret value to all parties. */ -public class Spdz2kOutputToAllProtocol> - extends Spdz2kNativeProtocol +public class Spdz2kOutputToAll> + extends Spdz2kNativeProtocol implements RequiresMacCheck { private final DRes share; - private BigInteger opened; - private Spdz2kSInt authenticatedElement; + private PlainT opened; + private Spdz2kSIntArithmetic authenticatedElement; /** - * Creates new {@link Spdz2kOutputToAllProtocol}. + * Creates new {@link Spdz2kOutputToAll}. * * @param share value to open */ - public Spdz2kOutputToAllProtocol(DRes share) { + public Spdz2kOutputToAll(DRes share) { this.share = share; } @Override public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, Network network) { - OpenedValueStore, PlainT> openedValueStore = resourcePool + OpenedValueStore, PlainT> openedValueStore = resourcePool .getOpenedValueStore(); + CompUIntFactory factory = resourcePool.getFactory(); if (round == 0) { - authenticatedElement = toSpdz2kSInt(share); - network.sendToAll(authenticatedElement.getShare().getLeastSignificant().toByteArray()); + authenticatedElement = factory.toSpdz2kSIntArithmetic(share); + network.sendToAll(authenticatedElement.serializeShareLow()); return EvaluationStatus.HAS_MORE_ROUNDS; } else { ByteSerializer serializer = resourcePool.getPlainSerializer(); List shares = serializer.deserializeList(network.receiveFromAll()); PlainT recombined = UInt.sum(shares); openedValueStore.pushOpenedValue(authenticatedElement, recombined); - this.opened = resourcePool.convertRepresentation(recombined); + this.opened = recombined.clearHighBits(); return EvaluationStatus.IS_DONE; } } @Override - public BigInteger out() { + public OInt out() { return opened; } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kSubtractFromKnownProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kSubtractFromKnownProtocol.java index 72deb5194..e6512a42b 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kSubtractFromKnownProtocol.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kSubtractFromKnownProtocol.java @@ -2,19 +2,21 @@ import dk.alexandra.fresco.framework.DRes; import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.OInt; import dk.alexandra.fresco.framework.value.SInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; /** - * Native protocol for subtracting a secret value from a known public values.

Note that the - * result is a secret value.

+ * Native protocol for subtracting a secret value from a known public value.

Note that the result + * is a secret value.

*/ public class Spdz2kSubtractFromKnownProtocol> extends Spdz2kNativeProtocol { - private final PlainT left; + private final DRes left; private final DRes right; private SInt difference; @@ -24,7 +26,7 @@ public class Spdz2kSubtractFromKnownProtocol right) { + public Spdz2kSubtractFromKnownProtocol(DRes left, DRes right) { this.left = left; this.right = right; } @@ -34,9 +36,11 @@ public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourceP Network network) { PlainT secretSharedKey = resourcePool.getDataSupplier().getSecretSharedKey(); PlainT zero = resourcePool.getFactory().zero(); - Spdz2kSInt leftSInt = new Spdz2kSInt<>(left, secretSharedKey, zero, + CompUIntFactory factory = resourcePool.getFactory(); + Spdz2kSIntArithmetic leftSInt = new Spdz2kSIntArithmetic<>(factory.fromOInt(left), + secretSharedKey, zero, resourcePool.getMyId() == 1); - difference = leftSInt.subtract(toSpdz2kSInt(right)); + difference = leftSInt.subtract(factory.toSpdz2kSIntArithmetic(right)); return EvaluationStatus.IS_DONE; } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kSubtractProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kSubtractProtocol.java new file mode 100644 index 000000000..e3c0815c5 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kSubtractProtocol.java @@ -0,0 +1,38 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; + +public class Spdz2kSubtractProtocol> extends + Spdz2kNativeProtocol { + + private final DRes left; + private final DRes right; + private SInt result; + + public Spdz2kSubtractProtocol( + DRes left, + DRes right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + Spdz2kSIntArithmetic leftVal = resourcePool.getFactory().toSpdz2kSIntArithmetic(left); + Spdz2kSIntArithmetic rightVal = resourcePool.getFactory().toSpdz2kSIntArithmetic(right); + result = leftVal.subtract(rightVal); + return EvaluationStatus.IS_DONE; + } + + @Override + public SInt out() { + return result; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kTruncationPairProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kTruncationPairProtocol.java new file mode 100644 index 000000000..f80fbcc13 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kTruncationPairProtocol.java @@ -0,0 +1,29 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.TruncationPair; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; + +public class Spdz2kTruncationPairProtocol> extends + Spdz2kNativeProtocol { + + private TruncationPair pair; + private final int d; + + public Spdz2kTruncationPairProtocol(int d) { + this.d = d; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + pair = resourcePool.getDataSupplier().getNextTruncationPair(d); + return EvaluationStatus.IS_DONE; + } + + @Override + public TruncationPair out() { + return pair; + } +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kTwoPartyInputProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kTwoPartyInputProtocol.java new file mode 100644 index 000000000..3ed6bf7a7 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kTwoPartyInputProtocol.java @@ -0,0 +1,68 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kInputMask; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDataSupplier; + +/** + * Native protocol for inputting data. + */ +public class Spdz2kTwoPartyInputProtocol> + extends Spdz2kNativeProtocol { + + private final PlainT input; + private final int inputPartyId; + private Spdz2kInputMask inputMask; + private SInt share; + + /** + * Creates new {@link Spdz2kTwoPartyInputProtocol}. + * + * @param input value to secret-share + * @param inputPartyId id of input party + */ + public Spdz2kTwoPartyInputProtocol(PlainT input, int inputPartyId) { + this.input = input; + this.inputPartyId = inputPartyId; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + CompUIntFactory factory = resourcePool.getFactory(); + int myId = resourcePool.getMyId(); + ByteSerializer serializer = resourcePool.getPlainSerializer(); + Spdz2kDataSupplier dataSupplier = resourcePool.getDataSupplier(); + if (round == 0) { + inputMask = dataSupplier.getNextInputMask(inputPartyId); + if (myId == inputPartyId) { + PlainT bcValue = this.input.subtract(inputMask.getOpenValue()); + network.sendToAll(serializer.serialize(bcValue)); + } + return EvaluationStatus.HAS_MORE_ROUNDS; + } else { + byte[] inputMaskBytes = network.receive(inputPartyId); + PlainT macKeyShare = dataSupplier.getSecretSharedKey(); + Spdz2kSIntArithmetic maskShare = inputMask.getMaskShare(); + Spdz2kSIntArithmetic out = maskShare.addConstant( + serializer.deserialize(inputMaskBytes), + macKeyShare, + factory.zero(), + myId == 1); + this.share = out; + return EvaluationStatus.IS_DONE; + } + } + + @Override + public SInt out() { + return share; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kXorKnownBatchedProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kXorKnownBatchedProtocol.java new file mode 100644 index 000000000..fdf19c2b9 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kXorKnownBatchedProtocol.java @@ -0,0 +1,55 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.util.ArrayList; +import java.util.List; + +public class Spdz2kXorKnownBatchedProtocol> extends + Spdz2kNativeProtocol>, PlainT> { + + private final DRes> left; + private final DRes>> right; + private List> result; + + public Spdz2kXorKnownBatchedProtocol( + DRes> left, + DRes>> right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + CompUIntFactory factory = resourcePool.getFactory(); + PlainT secretSharedKey = resourcePool.getDataSupplier().getSecretSharedKey(); + List leftOut = left.out(); + List> rightOut = right.out(); + if (leftOut.size() != rightOut.size()) { + throw new IllegalArgumentException("Lists must be same size"); + } + this.result = new ArrayList<>(leftOut.size()); + for (int i = 0; i < leftOut.size(); i++) { + PlainT knownBit = factory.fromOInt(leftOut.get(i)).toBitRep(); + DRes secretBit = rightOut.get(i); + Spdz2kSIntBoolean xoredBit = factory.toSpdz2kSIntBoolean(secretBit) + .xorOpen(knownBit, secretSharedKey, factory.zero().toBitRep(), + resourcePool.getMyId() == 1); + result.add(xoredBit); + } + return EvaluationStatus.IS_DONE; + } + + @Override + public List> out() { + return result; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kXorKnownProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kXorKnownProtocol.java new file mode 100644 index 000000000..845772c99 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kXorKnownProtocol.java @@ -0,0 +1,41 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; + +public class Spdz2kXorKnownProtocol> extends + Spdz2kNativeProtocol { + + private final DRes left; + private final DRes right; + private SInt result; + + public Spdz2kXorKnownProtocol( + DRes left, + DRes right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + CompUIntFactory factory = resourcePool.getFactory(); + PlainT known = factory.fromOInt(left.out()).toBitRep(); + PlainT secretSharedKey = resourcePool.getDataSupplier().getSecretSharedKey(); + result = factory.toSpdz2kSIntBoolean(right).xorOpen(known, + secretSharedKey, factory.zero().toBitRep(), resourcePool.getMyId() == 1); + return EvaluationStatus.IS_DONE; + } + + @Override + public SInt out() { + return result; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kXorProtocol.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kXorProtocol.java new file mode 100644 index 000000000..8a890d297 --- /dev/null +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/protocols/natives/Spdz2kXorProtocol.java @@ -0,0 +1,38 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.natives; + +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; + +public class Spdz2kXorProtocol> extends + Spdz2kNativeProtocol { + + private final DRes left; + private final DRes right; + private SInt result; + + public Spdz2kXorProtocol( + DRes left, + DRes right) { + this.left = left; + this.right = right; + } + + @Override + public EvaluationStatus evaluate(int round, Spdz2kResourcePool resourcePool, + Network network) { + Spdz2kSIntBoolean leftBit = resourcePool.getFactory().toSpdz2kSIntBoolean(left); + Spdz2kSIntBoolean rightBit = resourcePool.getFactory().toSpdz2kSIntBoolean(right); + result = leftBit.xor(rightBit); + return EvaluationStatus.IS_DONE; + } + + @Override + public SInt out() { + return result; + } + +} diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/Spdz2kResourcePool.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/Spdz2kResourcePool.java index 551bea63f..c25138d3c 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/Spdz2kResourcePool.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/Spdz2kResourcePool.java @@ -10,7 +10,7 @@ import dk.alexandra.fresco.suite.spdz2k.Spdz2kProtocolSuite; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDataSupplier; import java.math.BigInteger; import java.util.function.Function; @@ -28,7 +28,7 @@ public interface Spdz2kResourcePool> /** * Returns instance of {@link OpenedValueStore} which tracks all opened, unchecked values. */ - OpenedValueStore, PlainT> getOpenedValueStore(); + OpenedValueStore, PlainT> getOpenedValueStore(); /** * Returns instance of {@link Spdz2kDataSupplier} which provides pre-processed material such as diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/Spdz2kResourcePoolImpl.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/Spdz2kResourcePoolImpl.java index 0e3542956..bcfb18d04 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/Spdz2kResourcePoolImpl.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/Spdz2kResourcePoolImpl.java @@ -20,7 +20,7 @@ import dk.alexandra.fresco.suite.spdz2k.Spdz2kBuilder; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.protocols.computations.CoinTossingComputation; import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDataSupplier; import java.io.Closeable; @@ -40,7 +40,7 @@ public class Spdz2kResourcePoolImpl> private final int effectiveBitLength; private final BigInteger modulus; - private final OpenedValueStore, PlainT> storage; + private final OpenedValueStore, PlainT> storage; private final Spdz2kDataSupplier supplier; private final CompUIntFactory factory; private final ByteSerializer rawSerializer; @@ -51,7 +51,7 @@ public class Spdz2kResourcePoolImpl> * Creates new {@link Spdz2kResourcePoolImpl}. */ public Spdz2kResourcePoolImpl(int myId, int noOfPlayers, Drbg drbg, - OpenedValueStore, PlainT> storage, + OpenedValueStore, PlainT> storage, Spdz2kDataSupplier supplier, CompUIntFactory factory) { super(myId, noOfPlayers); Objects.requireNonNull(storage); @@ -73,7 +73,7 @@ public int getMaxBitLength() { } @Override - public OpenedValueStore, PlainT> getOpenedValueStore() { + public OpenedValueStore, PlainT> getOpenedValueStore() { return storage; } @@ -141,7 +141,7 @@ private byte[] runCoinTossing(Computation coinTo network); BuilderFactoryNumeric builderFactory = new Spdz2kBuilder<>(factory, new BasicNumericContext(effectiveBitLength, modulus, - getMyId(), getNoOfParties())); + getMyId(), getNoOfParties()), null,false); ProtocolBuilderNumeric root = builderFactory.createSequential(); DRes jointSeed = coinTossing .buildComputation(root); diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kDataSupplier.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kDataSupplier.java index 7091a0f04..f390f4796 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kDataSupplier.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kDataSupplier.java @@ -1,8 +1,10 @@ package dk.alexandra.fresco.suite.spdz2k.resource.storage; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.TruncationPair; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kInputMask; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; /** @@ -12,11 +14,18 @@ public interface Spdz2kDataSupplier> { /** - * Supplies the next triple. + * Supplies the next full multiplication triple. * * @return the next new triple */ - Spdz2kTriple getNextTripleShares(); + Spdz2kTriple> getNextTripleSharesFull(); + + /** + * Supplies the next boolean multiplication triple. + * + * @return the next new triple + */ + Spdz2kTriple> getNextBitTripleShares(); /** * Supplies the next inputmask for a given input player. @@ -29,7 +38,7 @@ public interface Spdz2kDataSupplier> { /** * Supplies the next bit (SInt representing value in {0, 1}). */ - Spdz2kSInt getNextBitShare(); + Spdz2kSIntArithmetic getNextBitShare(); /** * Returns the player's share of the mac key. @@ -37,8 +46,15 @@ public interface Spdz2kDataSupplier> { T getSecretSharedKey(); /** - * Returns the next random field element. + * Supplies the next random field element. + */ + Spdz2kSIntArithmetic getNextRandomElementShare(); + + /** + * Supplies the next truncation pair (r^{prime}, r) where r = r^{prime} / 2^{d}. + * + * @param d number of shifts */ - Spdz2kSInt getNextRandomElementShare(); + TruncationPair getNextTruncationPair(int d); } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kDummyDataSupplier.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kDummyDataSupplier.java index 1ee9a9139..b4f468ba0 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kDummyDataSupplier.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kDummyDataSupplier.java @@ -1,12 +1,15 @@ package dk.alexandra.fresco.suite.spdz2k.resource.storage; +import dk.alexandra.fresco.framework.builder.numeric.AdvancedNumeric.TruncationPair; import dk.alexandra.fresco.framework.util.ArithmeticDummyDataSupplier; import dk.alexandra.fresco.framework.util.MultiplicationTripleShares; import dk.alexandra.fresco.framework.util.Pair; +import dk.alexandra.fresco.framework.util.TruncationPairShares; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kInputMask; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntBoolean; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; import java.math.BigInteger; @@ -21,19 +24,25 @@ public class Spdz2kDummyDataSupplier< private final int myId; private final ArithmeticDummyDataSupplier supplier; private final PlainT secretSharedKey; + private final PlainT myKeyShare; private final CompUIntFactory factory; public Spdz2kDummyDataSupplier(int myId, int noOfParties, PlainT secretSharedKey, CompUIntFactory factory) { this.myId = myId; - this.secretSharedKey = secretSharedKey; this.factory = factory; - this.supplier = new ArithmeticDummyDataSupplier(myId, noOfParties, - BigInteger.ONE.shiftLeft(factory.getCompositeBitLength())); + this.supplier = new ArithmeticDummyDataSupplier( + myId, + noOfParties, + BigInteger.ONE.shiftLeft(factory.getCompositeBitLength()), + BigInteger.ONE.shiftLeft(factory.getLowBitLength() - 1)); + final Pair keyPair = supplier.getRandomElementShare(); + this.secretSharedKey = factory.createFromBigInteger(keyPair.getFirst()); + this.myKeyShare = factory.createFromBigInteger(keyPair.getSecond()); } @Override - public Spdz2kTriple getNextTripleShares() { + public Spdz2kTriple> getNextTripleSharesFull() { MultiplicationTripleShares rawTriple = supplier.getMultiplicationTripleShares(); return new Spdz2kTriple<>( toSpdz2kSInt(rawTriple.getLeft()), @@ -41,6 +50,15 @@ public Spdz2kTriple getNextTripleShares() { toSpdz2kSInt(rawTriple.getProduct())); } + @Override + public Spdz2kTriple> getNextBitTripleShares() { + MultiplicationTripleShares rawTriple = supplier.getMultiplicationBitTripleShares(); + return new Spdz2kTriple<>( + toSpdz2kSIntBool(rawTriple.getLeft()), + toSpdz2kSIntBool(rawTriple.getRight()), + toSpdz2kSIntBool(rawTriple.getProduct())); + } + @Override public Spdz2kInputMask getNextInputMask(int towardPlayerId) { Pair raw = supplier.getRandomElementShare(); @@ -53,25 +71,38 @@ public Spdz2kInputMask getNextInputMask(int towardPlayerId) { } @Override - public Spdz2kSInt getNextBitShare() { + public Spdz2kSIntArithmetic getNextBitShare() { return toSpdz2kSInt(supplier.getRandomBitShare()); } @Override public PlainT getSecretSharedKey() { - return secretSharedKey; + return myKeyShare; } @Override - public Spdz2kSInt getNextRandomElementShare() { + public Spdz2kSIntArithmetic getNextRandomElementShare() { return toSpdz2kSInt(supplier.getRandomElementShare()); } - private Spdz2kSInt toSpdz2kSInt(Pair raw) { + @Override + public TruncationPair getNextTruncationPair(int d) { + TruncationPairShares pair = supplier.getTruncationPairShares(d); + return new TruncationPair(toSpdz2kSInt(pair.getRPrime()), toSpdz2kSInt(pair.getR())); + } + + private Spdz2kSIntArithmetic toSpdz2kSInt(Pair raw) { PlainT openValue = factory.createFromBigInteger(raw.getFirst()); PlainT share = factory.createFromBigInteger(raw.getSecond()); - PlainT macShare = openValue.multiply(secretSharedKey); - return new Spdz2kSInt<>(share, macShare); + PlainT macShare = share.multiply(secretSharedKey); + return new Spdz2kSIntArithmetic<>(share, macShare); + } + + private Spdz2kSIntBoolean toSpdz2kSIntBool(Pair raw) { + PlainT openValue = factory.createFromBigInteger(raw.getFirst()).toBitRep(); + PlainT share = factory.createFromBigInteger(raw.getSecond()).toBitRep(); + PlainT macShare = share.toArithmeticRep().multiply(secretSharedKey); + return new Spdz2kSIntBoolean<>(share, macShare); } } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kOpenedValueStoreImpl.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kOpenedValueStoreImpl.java index dbce73e9f..c0dc18a6d 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kOpenedValueStoreImpl.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/Spdz2kOpenedValueStoreImpl.java @@ -3,12 +3,12 @@ import dk.alexandra.fresco.framework.util.OpenedValueStore; import dk.alexandra.fresco.framework.util.OpenedValueStoreImpl; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; /** * Spdz2k-specific instantiation of {@link OpenedValueStore}. */ public class Spdz2kOpenedValueStoreImpl> - extends OpenedValueStoreImpl, PlainT> { + extends OpenedValueStoreImpl, PlainT> { } diff --git a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/synchronization/Spdz2kRoundSynchronization.java b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/synchronization/Spdz2kRoundSynchronization.java index 2260965e3..3b97c5afc 100644 --- a/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/synchronization/Spdz2kRoundSynchronization.java +++ b/suite/spdz2k/src/main/java/dk/alexandra/fresco/suite/spdz2k/synchronization/Spdz2kRoundSynchronization.java @@ -7,16 +7,20 @@ import dk.alexandra.fresco.framework.sce.evaluator.BatchedProtocolEvaluator; import dk.alexandra.fresco.framework.sce.evaluator.BatchedStrategy; import dk.alexandra.fresco.framework.util.OpenedValueStore; +import dk.alexandra.fresco.framework.util.Pair; import dk.alexandra.fresco.suite.ProtocolSuite.RoundSynchronization; import dk.alexandra.fresco.suite.spdz2k.Spdz2kBuilder; import dk.alexandra.fresco.suite.spdz2k.Spdz2kProtocolSuite; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntConverter; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.datatypes.UInt; import dk.alexandra.fresco.suite.spdz2k.protocols.computations.Spdz2kMacCheckComputation; import dk.alexandra.fresco.suite.spdz2k.protocols.natives.RequiresMacCheck; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import java.math.BigInteger; +import java.util.List; import java.util.stream.StreamSupport; /** @@ -29,6 +33,7 @@ public class Spdz2kRoundSynchronization< PlainT extends CompUInt> implements RoundSynchronization> { + private static final int OPEN_VALUE_THRESHOLD = 300000; private final int openValueThreshold; private final int batchSize; private boolean isCheckRequired; @@ -37,7 +42,7 @@ public class Spdz2kRoundSynchronization< public Spdz2kRoundSynchronization(Spdz2kProtocolSuite protocolSuite, CompUIntConverter converter) { - this(protocolSuite, converter, 1000000, 128); + this(protocolSuite, converter, OPEN_VALUE_THRESHOLD, 128); } public Spdz2kRoundSynchronization(Spdz2kProtocolSuite protocolSuite, @@ -52,14 +57,19 @@ public Spdz2kRoundSynchronization(Spdz2kProtocolSuite proto } private void doMacCheck(Spdz2kResourcePool resourcePool, Network network) { +// Pair>, List> bar = resourcePool.getOpenedValueStore().popValues(); +// bar.getFirst().clear(); +// bar.getSecond().clear(); Spdz2kBuilder builder = new Spdz2kBuilder<>(resourcePool.getFactory(), - protocolSuite.createBasicNumericContext(resourcePool)); + protocolSuite.createBasicNumericContext(resourcePool), + protocolSuite.createRealNumericContext(), + false); BatchEvaluationStrategy> batchStrategy = new BatchedStrategy<>(); BatchedProtocolEvaluator> evaluator = new BatchedProtocolEvaluator<>( batchStrategy, protocolSuite, batchSize); - OpenedValueStore, PlainT> store = resourcePool.getOpenedValueStore(); + OpenedValueStore, PlainT> store = resourcePool.getOpenedValueStore(); Spdz2kMacCheckComputation macCheck = new Spdz2kMacCheckComputation<>( store.popValues(), resourcePool, converter); @@ -71,8 +81,13 @@ private void doMacCheck(Spdz2kResourcePool resourcePool, Network network @Override public void finishedBatch(int gatesEvaluated, Spdz2kResourcePool resourcePool, Network network) { - OpenedValueStore, PlainT> store = resourcePool.getOpenedValueStore(); - if (isCheckRequired || store.exceedsThreshold(openValueThreshold)) { + OpenedValueStore, PlainT> store = resourcePool.getOpenedValueStore(); + if (isCheckRequired) { +// System.out.println("Because required finished batch"); + doMacCheck(resourcePool, network); + isCheckRequired = false; + } else if (store.exceedsThreshold(openValueThreshold)) { +// System.out.println("Because exceeds "); doMacCheck(resourcePool, network); isCheckRequired = false; } @@ -80,8 +95,9 @@ public void finishedBatch(int gatesEvaluated, Spdz2kResourcePool resourc @Override public void finishedEval(Spdz2kResourcePool resourcePool, Network network) { - OpenedValueStore, PlainT> store = resourcePool.getOpenedValueStore(); + OpenedValueStore, PlainT> store = resourcePool.getOpenedValueStore(); if (store.hasPendingValues()) { +// System.out.println("Because eval finished"); doMacCheck(resourcePool, network); } } @@ -90,10 +106,13 @@ public void finishedEval(Spdz2kResourcePool resourcePool, Network networ public void beforeBatch( ProtocolCollection> nativeProtocols, Spdz2kResourcePool resourcePool, Network network) { - isCheckRequired = StreamSupport.stream(nativeProtocols.spliterator(), false) + final boolean outputFound = StreamSupport.stream(nativeProtocols.spliterator(), false) .anyMatch(p -> p instanceof RequiresMacCheck); - OpenedValueStore, PlainT> store = resourcePool.getOpenedValueStore(); - if (store.hasPendingValues() && isCheckRequired) { +// System.out.println(outputFound); + this.isCheckRequired = outputFound; + OpenedValueStore, PlainT> store = resourcePool.getOpenedValueStore(); + if (store.hasPendingValues() && this.isCheckRequired) { +// System.out.println("Because of output"); doMacCheck(resourcePool, network); } } diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/AbstractSpdz2kTest.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/AbstractSpdz2kTest.java index 1dab16737..378dfaeae 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/AbstractSpdz2kTest.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/AbstractSpdz2kTest.java @@ -25,7 +25,7 @@ public abstract class AbstractSpdz2kTest partyNumbers = Arrays.asList(2, 3); - void runTest( + protected void runTest( TestThreadRunner.TestThreadFactory f, EvaluationStrategy evalStrategy) { for (Integer numberOfParties : partyNumbers) { diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kTestSuite.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kTestSuite.java index 214e60aaf..71ed7ddb5 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kTestSuite.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/Spdz2kTestSuite.java @@ -3,6 +3,21 @@ import dk.alexandra.fresco.framework.sce.evaluator.EvaluationStrategy; import dk.alexandra.fresco.lib.arithmetic.BasicArithmeticTests; import dk.alexandra.fresco.lib.collections.io.CloseListTests.TestCloseAndOpenList; +import dk.alexandra.fresco.lib.compare.CompareTests.TestCompareEQ; +import dk.alexandra.fresco.lib.compare.CompareTests.TestCompareEQEdgeCases; +import dk.alexandra.fresco.lib.compare.CompareTests.TestCompareEQZero; +import dk.alexandra.fresco.lib.compare.CompareTests.TestLessThanLogRounds; +import dk.alexandra.fresco.lib.math.integer.binary.BinaryOperationsTests.TestGenerateRandomBitMask; +import dk.alexandra.fresco.lib.real.BasicFixedPointTests; +import dk.alexandra.fresco.lib.real.BasicFixedPointTests.TestMult; +import dk.alexandra.fresco.lib.real.BasicFixedPointTests.TestMultIsolated; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.TestComparisonSpdz2k.TestBitLessThanOpenSpdz2k; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.TestLogicalOperationsSpdz2k.TestAndKnownSpdz2k; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.TestLogicalOperationsSpdz2k.TestAndSpdz2k; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.TestLogicalOperationsSpdz2k.TestNotSpdz2k; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.TestLogicalOperationsSpdz2k.TestOrListSpdz2k; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.TestLogicalOperationsSpdz2k.TestOrSpdz2k; +import dk.alexandra.fresco.suite.spdz2k.protocols.computations.TestLogicalOperationsSpdz2k.TestXorKnownSpdz2k; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; import org.junit.Test; @@ -126,4 +141,102 @@ public void testRandomElement() { EvaluationStrategy.SEQUENTIAL_BATCHED); } + @Test + public void testBitLessThanOpen() { + runTest(new TestBitLessThanOpenSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testGenerateRandomBitMask() { + runTest(new TestGenerateRandomBitMask<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testLessThanLogRounds() { + runTest(new TestLessThanLogRounds<>(getMaxBitLength()), + EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testAndKnown() { + runTest(new TestAndKnownSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testAnd() { + runTest(new TestAndSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testOrOfList() { + runTest(new TestOrListSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testOr() { + runTest(new TestOrSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testNot() { + runTest(new TestNotSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testXorKnown() { + runTest(new TestXorKnownSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testCompareZeroLogRounds() { + runTest(new TestCompareEQZero<>(getMaxBitLength()), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testEqualsLogRounds() { + runTest(new TestCompareEQ<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testEqualsEdgeCasesLogRounds() { + runTest(new TestCompareEQEdgeCases<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testRealInput() { + runTest(new BasicFixedPointTests.TestInput<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testRealOpenToParty() { + runTest(new BasicFixedPointTests.TestOpenToParty<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testRealKnown() { + runTest(new BasicFixedPointTests.TestKnown<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void test_Real_Add_Secret() { + runTest(new BasicFixedPointTests.TestAdd<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void test_Real_Mult_Known() { + runTest(new BasicFixedPointTests.TestMultKnown<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void test_Real_Mults() { + runTest(new TestMult<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void test_Real_Mults_Isolated() { + runTest(new TestMultIsolated<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + protected abstract int getMaxBitLength(); + } diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBasicArithmetic128.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2k128.java similarity index 84% rename from suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBasicArithmetic128.java rename to suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2k128.java index 2cda4ebca..0b1d8a300 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBasicArithmetic128.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2k128.java @@ -12,18 +12,19 @@ import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kOpenedValueStoreImpl; import java.util.function.Supplier; -public class TestSpdz2kBasicArithmetic128 extends Spdz2kTestSuite> { +public class TestSpdz2k128 extends Spdz2kTestSuite> { @Override protected Spdz2kResourcePool createResourcePool(int playerId, int noOfParties, Supplier networkSupplier) { CompUIntFactory factory = new CompUInt128Factory(); + final CompUInt128 key = factory.createRandom(); Spdz2kResourcePool resourcePool = new Spdz2kResourcePoolImpl<>( playerId, noOfParties, null, new Spdz2kOpenedValueStoreImpl<>(), - new Spdz2kDummyDataSupplier<>(playerId, noOfParties, factory.createRandom(), factory), + new Spdz2kDummyDataSupplier<>(playerId, noOfParties, key, factory), factory); resourcePool.initializeJointRandomness(networkSupplier, AesCtrDrbg::new, 32); return resourcePool; @@ -31,7 +32,12 @@ protected Spdz2kResourcePool createResourcePool(int playerId, int n @Override protected ProtocolSuiteNumeric> createProtocolSuite() { - return new Spdz2kProtocolSuite128(); + return new Spdz2kProtocolSuite128(true); + } + + @Override + protected int getMaxBitLength() { + return 64; } } diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBasicArithmetic96.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2k64.java similarity index 53% rename from suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBasicArithmetic96.java rename to suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2k64.java index 6e90e0c6a..67b0642e7 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBasicArithmetic96.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2k64.java @@ -3,8 +3,8 @@ import dk.alexandra.fresco.framework.network.Network; import dk.alexandra.fresco.framework.util.AesCtrDrbg; import dk.alexandra.fresco.suite.ProtocolSuiteNumeric; -import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt96; -import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt96Factory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt64; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt64Factory; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePoolImpl; @@ -12,13 +12,13 @@ import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kOpenedValueStoreImpl; import java.util.function.Supplier; -public class TestSpdz2kBasicArithmetic96 extends Spdz2kTestSuite> { +public class TestSpdz2k64 extends Spdz2kTestSuite> { @Override - protected Spdz2kResourcePool createResourcePool(int playerId, int noOfParties, + protected Spdz2kResourcePool createResourcePool(int playerId, int noOfParties, Supplier networkSupplier) { - CompUIntFactory factory = new CompUInt96Factory(); - Spdz2kResourcePool resourcePool = + CompUIntFactory factory = new CompUInt64Factory(); + Spdz2kResourcePool resourcePool = new Spdz2kResourcePoolImpl<>( playerId, noOfParties, null, @@ -30,8 +30,43 @@ protected Spdz2kResourcePool createResourcePool(int playerId, int no } @Override - protected ProtocolSuiteNumeric> createProtocolSuite() { - return new Spdz2kProtocolSuite96(); + protected ProtocolSuiteNumeric> createProtocolSuite() { + return new Spdz2kProtocolSuite64(true); + } + + // TODO implement fixed-point arithmetic + + @Override + public void testRealInput() { + } + + @Override + public void testRealOpenToParty() { + } + + @Override + public void testRealKnown() { + } + + @Override + public void test_Real_Add_Secret() { + } + + @Override + public void test_Real_Mult_Known() { + } + + @Override + public void test_Real_Mults() { + } + + @Override + public void test_Real_Mults_Isolated() { + } + + @Override + protected int getMaxBitLength() { + return 32; } } diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBasicArithmeticGeneric.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBasicArithmeticGeneric.java deleted file mode 100644 index 6bb9a5381..000000000 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBasicArithmeticGeneric.java +++ /dev/null @@ -1,38 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k; - -import dk.alexandra.fresco.framework.network.Network; -import dk.alexandra.fresco.framework.util.AesCtrDrbg; -import dk.alexandra.fresco.suite.ProtocolSuiteNumeric; -import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.GenericCompUInt; -import dk.alexandra.fresco.suite.spdz2k.datatypes.GenericCompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; -import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePoolImpl; -import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDummyDataSupplier; -import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kOpenedValueStoreImpl; -import java.util.function.Supplier; - -public class TestSpdz2kBasicArithmeticGeneric extends - Spdz2kTestSuite> { - - @Override - protected Spdz2kResourcePool createResourcePool(int playerId, int noOfParties, - Supplier networkSupplier) { - CompUIntFactory factory = new GenericCompUIntFactory(32, 32); - Spdz2kResourcePool resourcePool = - new Spdz2kResourcePoolImpl<>( - playerId, - noOfParties, null, - new Spdz2kOpenedValueStoreImpl<>(), - new Spdz2kDummyDataSupplier<>(playerId, noOfParties, factory.createRandom(), factory), - factory); - resourcePool.initializeJointRandomness(networkSupplier, AesCtrDrbg::new, 32); - return resourcePool; - } - - @Override - protected ProtocolSuiteNumeric> createProtocolSuite() { - return new Spdz2kProtocolSuiteGeneric(32, 32); - } - -} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBuilder.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBuilder.java index ec8dd5231..128293f13 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBuilder.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/TestSpdz2kBuilder.java @@ -1,13 +1,13 @@ package dk.alexandra.fresco.suite.spdz2k; -import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128Factory; import org.junit.Test; public class TestSpdz2kBuilder { @Test(expected = UnsupportedOperationException.class) public void getBigIntegerHelper() { - new Spdz2kBuilder(null, null).getBigIntegerHelper(); + new Spdz2kBuilder<>(new CompUInt128Factory(), null, null, false).getBigIntegerHelper(); } } diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt128.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt128.java index 6e390a2f8..b0f6f4312 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt128.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt128.java @@ -58,6 +58,18 @@ public void testConstruct() { twoTo128.subtract(BigInteger.ONE), new CompUInt128(twoTo128.subtract(BigInteger.ONE)).toBigInteger() ); + assertEquals( + BigInteger.valueOf(-1).mod(twoTo128), + new CompUInt128(BigInteger.valueOf(-1)).toBigInteger() + ); + assertEquals( + BigInteger.valueOf(-2).mod(twoTo128), + new CompUInt128(BigInteger.valueOf(-2)).toBigInteger() + ); + assertEquals( + twoTo128.subtract(BigInteger.ONE).negate().mod(twoTo128), + new CompUInt128(twoTo128.subtract(BigInteger.ONE).negate()).toBigInteger() + ); } @Test @@ -208,6 +220,13 @@ public void testSubtract() { new CompUInt128(BigInteger.ONE).subtract(new CompUInt128(two)) .toBigInteger() ); + assertEquals( + new BigInteger("1121381238012").subtract(new BigInteger("10261555690727498232")) + .mod(twoTo128), + new CompUInt128(new BigInteger("1121381238012")) + .subtract(new CompUInt128(new BigInteger("10261555690727498232"))) + .toBigInteger() + ); } @Test @@ -268,10 +287,102 @@ public void testPadIllegal() { @Test public void testIsZero() { - assertTrue(new CompUInt128(0, 0,0).isZero()); - assertFalse(new CompUInt128(0, 0,1).isZero()); - assertFalse(new CompUInt128(0, 1,0).isZero()); - assertFalse(new CompUInt128(1, 0,0).isZero()); + assertTrue(new CompUInt128(0, 0, 0).isZero()); + assertFalse(new CompUInt128(0, 0, 1).isZero()); + assertFalse(new CompUInt128(0, 1, 0).isZero()); + assertFalse(new CompUInt128(1, 0, 0).isZero()); + } + + @Test + public void testTestBit() { + assertTrue(new CompUInt128(0, 0, 1).testBit(0)); + assertFalse(new CompUInt128(0, 0, 0).testBit(0)); + assertTrue(new CompUInt128(0, 1, 0).testBit(32)); + assertFalse(new CompUInt128(0, 0, 1).testBit(32)); + assertTrue(new CompUInt128(1, 0, 0).testBit(64)); + assertFalse(new CompUInt128(0, 1, 1).testBit(64)); + assertTrue(new CompUInt128(0, 0, 1 << 14).testBit(14)); + assertTrue(new CompUInt128(0, 1 << 10, 0).testBit(32 + 10)); + assertTrue(new CompUInt128(1 << 2, 0, 0).testBit(64 + 2)); + assertTrue(new CompUInt128(1L << 62, 0, 0).testBit(64 + 62)); + assertTrue(new CompUInt128(0x8000000000000000L, 0, 0).testBit(64 + 63)); + } + + @Test + public void testClearAboveBitAt() { + assertEquals(new CompUInt128(0, 0, 0).toBigInteger(), + new CompUInt128(0, 0, 0).clearAboveBitAt(63).toBigInteger()); + assertEquals(new CompUInt128(0, 0, 123123).toBigInteger(), + new CompUInt128(0, 0, 123123).clearAboveBitAt(63).toBigInteger()); + assertEquals(new CompUInt128(0, 0, 123123).toBigInteger(), + new CompUInt128(1, 0, 123123).clearAboveBitAt(63).toBigInteger()); + assertEquals(new CompUInt128(0, 0x70001001, 123123).toBigInteger(), + new CompUInt128(1, 0xf0001001, 123123).clearAboveBitAt(63).toBigInteger()); + assertEquals(new CompUInt128(0, 0x00000021, 123123).toBigInteger(), + new CompUInt128(1, 0xf0001021, 123123).clearAboveBitAt(44).toBigInteger()); + assertEquals(new CompUInt128(0x7000100100000000L, 0x70001001, 123123).toBigInteger(), + new CompUInt128(0xf000100100000000L, 0x70001001, 123123).clearAboveBitAt(127) + .toBigInteger()); + assertEquals(new CompUInt128(0, 0, 0x00000001).toBigInteger(), + new CompUInt128(1, 1, 0xff001021).clearAboveBitAt(5).toBigInteger()); + } + + @Test + public void testShiftLeftSmall() { + byte[] bytes = new byte[16]; + new Random(1).nextBytes(bytes); + CompUInt128 r = new CompUInt128(bytes); + for (int i = 0; i < 64; i++) { + assertEquals("Number of shifts " + i, r.toBigInteger().shiftLeft(i).mod(twoTo128).toString(2), + r.shiftLeftSmall(i).toBigInteger().toString(2)); + } + assertEquals(new BigInteger("1").shiftLeft(63), + new CompUInt128(new BigInteger("1")).shiftLeftSmall(63).toBigInteger()); + assertEquals(new BigInteger("12312").shiftLeft(12), + new CompUInt128(new BigInteger("12312")).shiftLeftSmall(12).toBigInteger()); + assertEquals(new BigInteger("12312"), + new CompUInt128(new BigInteger("12312")).shiftLeftSmall(0).toBigInteger()); + assertEquals(new BigInteger("12312"), + new CompUInt128(new BigInteger("12312")).shiftLeftSmall(-1).toBigInteger()); + } + + @Test + public void testShiftRightSmall() { + byte[] bytes = new byte[16]; + new Random(2).nextBytes(bytes); + CompUInt128 r = new CompUInt128(bytes); + for (int i = 0; i < 64; i++) { + assertEquals("Number of shifts " + i, + r.toBigInteger().shiftRight(i).mod(twoTo128).toString(2), + r.shiftRightSmall(i).toBigInteger().toString(2)); + } + for (int i = 0; i < 64; i++) { + CompUInt128 element = new CompUInt128(1L << i); + assertEquals("Number of shifts " + i, BigInteger.ONE, + element.shiftRightSmall(i).toBigInteger()); + } + assertEquals(new BigInteger("12312"), + new CompUInt128(new BigInteger("12312")).shiftRightSmall(0).toBigInteger()); + assertEquals(new BigInteger("12312"), + new CompUInt128(new BigInteger("12312")).shiftRightSmall(-1).toBigInteger()); + } + + @Test + public void testShiftRightLowOnly() { + assertEquals(BigInteger.ZERO, new CompUInt128(0).shiftRightLowOnly(16).toBigInteger()); + assertEquals(BigInteger.ZERO, new CompUInt128(1).shiftRightLowOnly(16).toBigInteger()); + for (int i = 0; i < 64; i++) { + CompUInt128 element = new CompUInt128(1L << i); + assertEquals("Number of shifts " + i, BigInteger.ONE, + element.shiftRightLowOnly(i).toBigInteger()); + } + } + + @Test + public void testToBit() { + assertEquals(BigInteger.ZERO, new CompUInt128(0).toBitRep().toBigInteger()); + assertEquals(twoTo64.shiftRight(1), new CompUInt128(1).toBitRep().toBigInteger()); + assertEquals(twoTo64.shiftLeft(63), new CompUInt128(twoTo64).toBitRep().toBigInteger()); } } diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt128Bit.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt128Bit.java new file mode 100644 index 000000000..8385ef198 --- /dev/null +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt128Bit.java @@ -0,0 +1,110 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +import java.math.BigInteger; +import java.util.Random; +import org.junit.Assert; +import org.junit.Test; + +public class TestCompUInt128Bit { + + private static final BigInteger twoTo128 = BigInteger.ONE.shiftLeft(128); + + private static long rand(int seed) { + return new Random(seed).nextLong(); + } + + private static BigInteger bigInt128(BigInteger value65) { + return value65.shiftLeft(63).mod(twoTo128); + } + + private static BigInteger bigInt65(long high, int bit) { + return BigInteger.valueOf(high).shiftLeft(1) + .add(BigInteger.valueOf(bit)) + .mod(twoTo128); + } + + @Test + public void testConstruct() { + Assert.assertEquals(BigInteger.valueOf(111).shiftLeft(64), + new CompUInt128Bit(111, 0).toBigInteger()); + Assert.assertEquals(BigInteger.valueOf(rand(1)).shiftLeft(64).mod(twoTo128), + new CompUInt128Bit(rand(1), 0).toBigInteger()); + Assert.assertEquals( + BigInteger.valueOf(rand(2)).shiftLeft(64).add(BigInteger.valueOf(1L).shiftLeft(63)) + .mod(twoTo128), + new CompUInt128Bit(rand(2), 1).toBigInteger()); + } + + @Test + public void testBitValue() { + Assert.assertEquals( + 0, + new CompUInt128Bit(111, 0).bitValue()); + Assert.assertEquals( + 0, + new CompUInt128Bit(rand(1), 0).bitValue()); + Assert.assertEquals( + 1, + new CompUInt128Bit(rand(2), 1).bitValue()); + Assert.assertEquals( + 1, + new CompUInt128Bit(0, 1).bitValue()); + Assert.assertEquals( + 0, + new CompUInt128Bit(0, 0).bitValue()); + } + + @Test + public void testMultiply() { + Assert.assertEquals( + bigInt128(bigInt65(rand(3), 0).multiply(bigInt65(rand(4), 0))), + new CompUInt128Bit(rand(3), 0).multiply(new CompUInt128Bit(rand(4), 0)).toBigInteger() + ); + Assert.assertEquals( + bigInt128(bigInt65(rand(3), 1).multiply(bigInt65(rand(4), 0))), + new CompUInt128Bit(rand(3), 1).multiply(new CompUInt128Bit(rand(4), 0)).toBigInteger() + ); + Assert.assertEquals( + bigInt128(bigInt65(1, 1).multiply(bigInt65(1, 1))), + new CompUInt128Bit(1, 1).multiply(new CompUInt128Bit(1, 1)).toBigInteger() + ); + Assert.assertEquals( + bigInt128(bigInt65(rand(3), 1).multiply(bigInt65(rand(4), 1))), + new CompUInt128Bit(rand(3), 1).multiply(new CompUInt128Bit(rand(4), 1)).toBigInteger() + ); + } + + @Test + public void testAdd() { + Assert.assertEquals( + bigInt128(bigInt65(rand(3), 0).add(bigInt65(rand(4), 0))), + new CompUInt128Bit(rand(3), 0).add(new CompUInt128Bit(rand(4), 0)).toBigInteger() + ); + Assert.assertEquals( + bigInt128(bigInt65(rand(3), 1).add(bigInt65(rand(4), 0))).toString(2), + new CompUInt128Bit(rand(3), 1).add(new CompUInt128Bit(rand(4), 0)).toBigInteger() + .toString(2) + ); + Assert.assertEquals( + bigInt128(bigInt65(1, 1).add(bigInt65(1, 1))), + new CompUInt128Bit(1, 1).add(new CompUInt128Bit(1, 1)).toBigInteger() + ); + Assert.assertEquals( + bigInt128(bigInt65(rand(3), 1).add(bigInt65(rand(4), 1))), + new CompUInt128Bit(rand(3), 1).add(new CompUInt128Bit(rand(4), 1)).toBigInteger() + ); + } + + @Test + public void testSerializeLeastSignificant() { + Assert.assertArrayEquals( + new byte[]{0}, + new CompUInt128Bit(rand(42), 0).serializeLeastSignificant() + ); + Assert.assertArrayEquals( + new byte[]{1}, + new CompUInt128Bit(rand(42), 1).serializeLeastSignificant() + ); + } + +} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt64.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt64.java new file mode 100644 index 000000000..15e169b42 --- /dev/null +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt64.java @@ -0,0 +1,69 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +import dk.alexandra.fresco.framework.util.ByteAndBitConverter; +import java.math.BigInteger; +import org.junit.Assert; +import org.junit.Test; + +public class TestCompUInt64 { + + private static BigInteger twoTo32 = BigInteger.ONE.shiftLeft(32); + + @Test + public void clearAboveBitAt() { + for (int i = 0; i < Long.SIZE - 2; i++) { + BigInteger input = BigInteger.ONE.shiftLeft(i + 1).add(BigInteger.ONE); + final BigInteger actual = new CompUInt64(input).clearAboveBitAt(i + 1).toBigInteger(); + Assert.assertEquals("Failed at " + i + " expected 1 but was " + actual, + BigInteger.ONE, + actual); + } + } + + @Test + public void clearHighBits() { + Assert.assertEquals( + new CompUInt64(1234L).toBigInteger(), + new CompUInt64((12L << 34) + 1234L).clearHighBits().toBigInteger()); + } + + @Test + public void toBitRep() { + } + + @Test + public void testBit() { + Assert.assertEquals( + true, new CompUInt64(BigInteger.ONE.shiftLeft(30).longValue()).testBit(30)); + Assert.assertEquals( + false, new CompUInt64(BigInteger.ONE.shiftLeft(30).longValue()).testBit(29)); + Assert.assertEquals( + true, new CompUInt64(BigInteger.ONE.longValue()).testBit(0)); + Assert.assertEquals( + false, new CompUInt64(BigInteger.ONE.longValue()).testBit(1)); + } + + @Test + public void serializeLeastSignificant() { + long input = 1231139128938112323L; + Assert.assertArrayEquals( + ByteAndBitConverter.toByteArray((int) input), + new CompUInt64(input).serializeLeastSignificant()); + } + + @Test + public void toByteArray() { + long input = 1231139128938112323L; + Assert.assertArrayEquals( + ByteAndBitConverter.toByteArray(input), + new CompUInt64(input).toByteArray()); + } + + @Test + public void testToBit() { + Assert.assertEquals(BigInteger.ZERO, new CompUInt64(0).toBitRep().toBigInteger()); + Assert.assertEquals(twoTo32.shiftRight(1), new CompUInt64(1).toBitRep().toBigInteger()); + Assert.assertEquals(twoTo32.shiftLeft(31), new CompUInt64(twoTo32).toBitRep().toBigInteger()); + } + +} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt64Bit.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt64Bit.java new file mode 100644 index 000000000..c5b257d45 --- /dev/null +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt64Bit.java @@ -0,0 +1,110 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +import java.math.BigInteger; +import java.util.Random; +import org.junit.Assert; +import org.junit.Test; + +public class TestCompUInt64Bit { + + private static final BigInteger twoTo64 = BigInteger.ONE.shiftLeft(64); + + private static int rand(int seed) { + return new Random(seed).nextInt(); + } + + private static BigInteger bigInt64(BigInteger value33) { + return value33.shiftLeft(31).mod(twoTo64); + } + + private static BigInteger bigInt33(int high, int bit) { + return BigInteger.valueOf(high).shiftLeft(1) + .add(BigInteger.valueOf(bit)) + .mod(twoTo64); + } + + @Test + public void testConstruct() { + Assert.assertEquals(BigInteger.valueOf(111).shiftLeft(32), + new CompUInt64Bit(111, 0).toBigInteger()); + Assert.assertEquals(BigInteger.valueOf(rand(1)).shiftLeft(32).mod(twoTo64), + new CompUInt64Bit(rand(1), 0).toBigInteger()); + Assert.assertEquals( + BigInteger.valueOf(rand(2)).shiftLeft(32).add(BigInteger.valueOf(1L).shiftLeft(31)) + .mod(twoTo64), + new CompUInt64Bit(rand(2), 1).toBigInteger()); + } + + @Test + public void testBitValue() { + Assert.assertEquals( + 0, + new CompUInt64Bit(111, 0).bitValue()); + Assert.assertEquals( + 0, + new CompUInt64Bit(rand(1), 0).bitValue()); + Assert.assertEquals( + 1, + new CompUInt64Bit(rand(2), 1).bitValue()); + Assert.assertEquals( + 1, + new CompUInt64Bit(0, 1).bitValue()); + Assert.assertEquals( + 0, + new CompUInt64Bit(0, 0).bitValue()); + } + + @Test + public void testMultiply() { + Assert.assertEquals( + bigInt64(bigInt33(rand(3), 0).multiply(bigInt33(rand(4), 0))), + new CompUInt64Bit(rand(3), 0).multiply(new CompUInt64Bit(rand(4), 0)).toBigInteger() + ); + Assert.assertEquals( + bigInt64(bigInt33(rand(3), 1).multiply(bigInt33(rand(4), 0))), + new CompUInt64Bit(rand(3), 1).multiply(new CompUInt64Bit(rand(4), 0)).toBigInteger() + ); + Assert.assertEquals( + bigInt64(bigInt33(1, 1).multiply(bigInt33(1, 1))), + new CompUInt64Bit(1, 1).multiply(new CompUInt64Bit(1, 1)).toBigInteger() + ); + Assert.assertEquals( + bigInt64(bigInt33(rand(3), 1).multiply(bigInt33(rand(4), 1))), + new CompUInt64Bit(rand(3), 1).multiply(new CompUInt64Bit(rand(4), 1)).toBigInteger() + ); + } + + @Test + public void testAdd() { + Assert.assertEquals( + bigInt64(bigInt33(rand(3), 0).add(bigInt33(rand(4), 0))), + new CompUInt64Bit(rand(3), 0).add(new CompUInt64Bit(rand(4), 0)).toBigInteger() + ); + Assert.assertEquals( + bigInt64(bigInt33(rand(3), 1).add(bigInt33(rand(4), 0))).toString(2), + new CompUInt64Bit(rand(3), 1).add(new CompUInt64Bit(rand(4), 0)).toBigInteger() + .toString(2) + ); + Assert.assertEquals( + bigInt64(bigInt33(1, 1).add(bigInt33(1, 1))), + new CompUInt64Bit(1, 1).add(new CompUInt64Bit(1, 1)).toBigInteger() + ); + Assert.assertEquals( + bigInt64(bigInt33(rand(3), 1).add(bigInt33(rand(4), 1))), + new CompUInt64Bit(rand(3), 1).add(new CompUInt64Bit(rand(4), 1)).toBigInteger() + ); + } + + @Test + public void testSerializeLeastSignificant() { + Assert.assertArrayEquals( + new byte[]{0}, + new CompUInt64Bit(rand(42), 0).serializeLeastSignificant() + ); + Assert.assertArrayEquals( + new byte[]{1}, + new CompUInt64Bit(rand(42), 1).serializeLeastSignificant() + ); + } + +} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt96.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt96.java deleted file mode 100644 index 9698c63d9..000000000 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestCompUInt96.java +++ /dev/null @@ -1,285 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k.datatypes; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.math.BigInteger; -import java.util.Random; -import org.junit.Test; - -public class TestCompUInt96 { - - private final BigInteger two = BigInteger.valueOf(2); - private final BigInteger twoTo32 = BigInteger.ONE.shiftLeft(32); - private final BigInteger twoTo64 = BigInteger.ONE.shiftLeft(64); - private final BigInteger twoTo96 = BigInteger.ONE.shiftLeft(96); - - @Test - public void testConstruct() { - assertEquals( - BigInteger.ZERO, - new CompUInt96(BigInteger.ZERO).toBigInteger() - ); - assertEquals( - BigInteger.ONE, - new CompUInt96(BigInteger.ONE).toBigInteger() - ); - assertEquals( - new BigInteger("42"), - new CompUInt96(new BigInteger("42")).toBigInteger() - ); - assertEquals( - twoTo32, - new CompUInt96(twoTo32).toBigInteger() - ); - assertEquals( - twoTo32.subtract(BigInteger.ONE), - new CompUInt96(twoTo32.subtract(BigInteger.ONE)).toBigInteger() - ); - assertEquals( - twoTo32.add(BigInteger.ONE), - new CompUInt96(twoTo32.add(BigInteger.ONE)).toBigInteger() - ); - assertEquals( - twoTo64.subtract(BigInteger.ONE), - new CompUInt96(twoTo64.subtract(BigInteger.ONE)).toBigInteger() - ); - assertEquals( - twoTo64, - new CompUInt96(twoTo64).toBigInteger() - ); - assertEquals( - twoTo64.add(BigInteger.ONE), - new CompUInt96(twoTo64.add(BigInteger.ONE)).toBigInteger() - ); - assertEquals( - twoTo96.subtract(BigInteger.ONE), - new CompUInt96(twoTo96.subtract(BigInteger.ONE)).toBigInteger() - ); - } - - @Test - public void testAdd() { - assertEquals( - BigInteger.ZERO, - new CompUInt96(0).add(new CompUInt96(0)).toBigInteger() - ); - assertEquals( - two, - new CompUInt96(1).add(new CompUInt96(1)).toBigInteger() - ); - assertEquals( - twoTo32, - new CompUInt96(twoTo32).add(new CompUInt96(0)).toBigInteger() - ); - assertEquals( - twoTo32.add(BigInteger.ONE), - new CompUInt96(twoTo32).add(new CompUInt96(1)).toBigInteger() - ); - assertEquals( - twoTo64, - new CompUInt96(twoTo64).add(new CompUInt96(0)).toBigInteger() - ); - assertEquals( - twoTo64.add(BigInteger.ONE), - new CompUInt96(twoTo64).add(new CompUInt96(1)).toBigInteger() - ); - assertEquals( - twoTo96.subtract(BigInteger.ONE), - new CompUInt96(twoTo96.subtract(BigInteger.ONE)).add(new CompUInt96(0)) - .toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new CompUInt96(twoTo96.subtract(BigInteger.ONE)) - .add(new CompUInt96(BigInteger.ONE)).toBigInteger() - ); - assertEquals( - twoTo96.subtract(new BigInteger("10000000")).add(twoTo32.add(twoTo64)).mod(twoTo96), - new CompUInt96(twoTo96.subtract(new BigInteger("10000000"))) - .add(new CompUInt96(twoTo32.add(twoTo64))).toBigInteger() - ); - assertEquals( - twoTo32.add(twoTo64).mod(twoTo96), - new CompUInt96(twoTo32).add(new CompUInt96(twoTo64)).toBigInteger() - ); - } - - @Test - public void testMultiply() { - assertEquals( - BigInteger.ZERO, - new CompUInt96(0).multiply(new CompUInt96(0)).toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new CompUInt96(1).multiply(new CompUInt96(0)).toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new CompUInt96(0).multiply(new CompUInt96(1)).toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new CompUInt96(1024).multiply(new CompUInt96(0)).toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new CompUInt96(twoTo96.subtract(BigInteger.ONE)).multiply(new CompUInt96(0)) - .toBigInteger() - ); - assertEquals( - BigInteger.ONE, - new CompUInt96(1).multiply(new CompUInt96(1)).toBigInteger() - ); - assertEquals( - twoTo96.subtract(BigInteger.ONE), - new CompUInt96(new CompUInt96(1)) - .multiply(new CompUInt96(twoTo96.subtract(BigInteger.ONE))) - .toBigInteger() - ); - assertEquals( - twoTo96.subtract(BigInteger.ONE), - new CompUInt96(twoTo96.subtract(BigInteger.ONE)).multiply(new CompUInt96(1)) - .toBigInteger() - ); - assertEquals( - new BigInteger("4294967306").multiply(new BigInteger("7415541639366192187")).mod(twoTo96), - new CompUInt96(new BigInteger("4294967306")) - .multiply(new CompUInt96(new BigInteger("7415541639366192187"))) - .toBigInteger() - ); - // multiply no overflow - assertEquals( - new BigInteger("42").multiply(new BigInteger("7")), - new CompUInt96(new BigInteger("42")).multiply(new CompUInt96(new BigInteger("7"))) - .toBigInteger() - ); - // multiply with overflow - assertEquals( - new BigInteger("42").multiply(twoTo96.subtract(BigInteger.ONE)).mod(twoTo96), - new CompUInt96(new BigInteger("42")) - .multiply(new CompUInt96(twoTo96.subtract(BigInteger.ONE))) - .toBigInteger() - ); - assertEquals( - twoTo64.multiply(twoTo64.add(BigInteger.TEN)).mod(twoTo96), - new CompUInt96(twoTo64) - .multiply(new CompUInt96(twoTo64.add(BigInteger.TEN))) - .toBigInteger() - ); - } - - @Test - public void testNegate() { - assertEquals( - BigInteger.ZERO, - new CompUInt96(BigInteger.ZERO).negate().toBigInteger() - ); - assertEquals( - BigInteger.ONE, - new CompUInt96(twoTo96.subtract(BigInteger.ONE)).negate().toBigInteger() - ); - assertEquals( - two, - new CompUInt96(twoTo96.subtract(two)).negate().toBigInteger() - ); - assertEquals( - twoTo96.subtract(two), - new CompUInt96(two).negate().toBigInteger() - ); - } - - @Test - public void testSubtract() { - assertEquals( - BigInteger.ZERO, - new CompUInt96(BigInteger.ZERO).subtract(new CompUInt96(BigInteger.ZERO)) - .toBigInteger() - ); - assertEquals( - BigInteger.ONE, - new CompUInt96(BigInteger.ONE).subtract(new CompUInt96(BigInteger.ZERO)) - .toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new CompUInt96(BigInteger.ONE).subtract(new CompUInt96(BigInteger.ONE)) - .toBigInteger() - ); - assertEquals( - twoTo96.subtract(BigInteger.ONE), - new CompUInt96(BigInteger.ONE).subtract(new CompUInt96(two)) - .toBigInteger() - ); - } - - @Test - public void testToByteArrayWithPadding() { - byte[] bytes = new byte[]{0x42}; - UInt uint = new CompUInt96(bytes); - byte[] expected = new byte[12]; - expected[expected.length - 1] = 0x42; - byte[] actual = uint.toByteArray(); - assertArrayEquals(expected, actual); - } - - @Test - public void testToByteArray() { - byte[] bytes = new byte[12]; - new Random(1).nextBytes(bytes); - UInt uint = new CompUInt96(bytes); - byte[] actual = uint.toByteArray(); - assertArrayEquals(bytes, actual); - } - - @Test - public void testToByteArrayMore() { - byte[] bytes = new byte[]{ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // high - 0x02, 0x02, 0x02, 0x02, // low - }; - UInt uint = new CompUInt96(bytes); - byte[] actual = uint.toByteArray(); - assertArrayEquals(bytes, actual); - } - - @Test - public void testToLong() { - assertEquals(Long.MAX_VALUE, new CompUInt96(Long.MAX_VALUE).toLong()); - assertEquals(0, new CompUInt96(0).toLong()); - assertEquals(1, new CompUInt96(1).toLong()); - assertEquals(twoTo64.longValue(), new CompUInt96(twoTo64).toLong()); - } - - @Test - public void testGetBitLength() { - CompUInt96 uint = new CompUInt96(1); - assertEquals(96, uint.getBitLength()); - assertEquals(64, uint.getHighBitLength()); - assertEquals(32, uint.getLowBitLength()); - } - - @Test - public void testToInt() { - UInt uint = new CompUInt96(1); - assertEquals(1, uint.toInt()); - } - - @Test - public void testToString() { - UInt uint = new CompUInt96(12135); - assertEquals("12135", uint.toString()); - } - - @Test - public void testIsZero() { - assertTrue(new CompUInt96(0, 0,0).isZero()); - assertFalse(new CompUInt96(0, 0,1).isZero()); - assertFalse(new CompUInt96(0, 1,0).isZero()); - assertFalse(new CompUInt96(1, 0,0).isZero()); - } - -} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestGenericCompUInt.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestGenericCompUInt.java deleted file mode 100644 index 1e036bc19..000000000 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestGenericCompUInt.java +++ /dev/null @@ -1,318 +0,0 @@ -package dk.alexandra.fresco.suite.spdz2k.datatypes; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.math.BigInteger; -import java.util.Random; -import org.junit.Test; - -public class TestGenericCompUInt { - - private final BigInteger two = BigInteger.valueOf(2); - private final BigInteger twoTo32 = BigInteger.ONE.shiftLeft(32); - private final BigInteger twoTo64 = BigInteger.ONE.shiftLeft(64); - private final BigInteger twoTo128 = BigInteger.ONE.shiftLeft(128); - - @Test - public void testConstruct() { - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(BigInteger.ZERO, 128).toBigInteger() - ); - assertEquals( - BigInteger.ONE, - new GenericCompUInt(BigInteger.ONE, 128).toBigInteger() - ); - assertEquals( - new BigInteger("42"), - new GenericCompUInt(new BigInteger("42"), 128).toBigInteger() - ); - assertEquals( - twoTo32, - new GenericCompUInt(twoTo32, 128).toBigInteger() - ); - assertEquals( - twoTo32.subtract(BigInteger.ONE), - new GenericCompUInt(twoTo32.subtract(BigInteger.ONE), 128).toBigInteger() - ); - assertEquals( - twoTo32.add(BigInteger.ONE), - new GenericCompUInt(twoTo32.add(BigInteger.ONE), 128).toBigInteger() - ); - assertEquals( - twoTo64.subtract(BigInteger.ONE), - new GenericCompUInt(twoTo64.subtract(BigInteger.ONE), 128).toBigInteger() - ); - assertEquals( - twoTo64, - new GenericCompUInt(twoTo64, 128).toBigInteger() - ); - assertEquals( - twoTo64.add(BigInteger.ONE), - new GenericCompUInt(twoTo64.add(BigInteger.ONE), 128).toBigInteger() - ); - assertEquals( - twoTo128.subtract(BigInteger.ONE), - new GenericCompUInt(twoTo128.subtract(BigInteger.ONE), 128).toBigInteger() - ); - } - - @Test - public void testAdd() { - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(0, 128).add(new GenericCompUInt(0, 128)).toBigInteger() - ); - assertEquals( - two, - new GenericCompUInt(1, 128).add(new GenericCompUInt(1, 128)).toBigInteger() - ); - assertEquals( - twoTo32, - new GenericCompUInt(twoTo32, 128).add(new GenericCompUInt(0, 128)).toBigInteger() - ); - assertEquals( - twoTo32.add(BigInteger.ONE), - new GenericCompUInt(twoTo32, 128).add(new GenericCompUInt(1, 128)).toBigInteger() - ); - assertEquals( - twoTo64, - new GenericCompUInt(twoTo64, 128).add(new GenericCompUInt(0, 128)).toBigInteger() - ); - assertEquals( - twoTo64.add(BigInteger.ONE), - new GenericCompUInt(twoTo64, 128).add(new GenericCompUInt(1, 128)).toBigInteger() - ); - assertEquals( - twoTo128.subtract(BigInteger.ONE), - new GenericCompUInt(twoTo128.subtract(BigInteger.ONE), 128).add(new GenericCompUInt(0, 128)) - .toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(twoTo128.subtract(BigInteger.ONE), 128) - .add(new GenericCompUInt(BigInteger.ONE, 128)).toBigInteger() - ); - assertEquals( - twoTo128.subtract(new BigInteger("10000000")).add(twoTo32.add(twoTo64)).mod(twoTo128), - new GenericCompUInt(twoTo128.subtract(new BigInteger("10000000")), 128) - .add(new GenericCompUInt(twoTo32.add(twoTo64), 128)).toBigInteger() - ); - assertEquals( - twoTo32.add(twoTo64).mod(twoTo128), - new GenericCompUInt(twoTo32, 128).add(new GenericCompUInt(twoTo64, 128)).toBigInteger() - ); - } - - @Test - public void testMultiply() { - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(0, 128).multiply(new GenericCompUInt(0, 128)).toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(1, 128).multiply(new GenericCompUInt(0, 128)).toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(0, 128).multiply(new GenericCompUInt(1, 128)).toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(1024, 128).multiply(new GenericCompUInt(0, 128)).toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(twoTo128.subtract(BigInteger.ONE), 128) - .multiply(new GenericCompUInt(0, 128)) - .toBigInteger() - ); - assertEquals( - BigInteger.ONE, - new GenericCompUInt(1, 128).multiply(new GenericCompUInt(1, 128)).toBigInteger() - ); - assertEquals( - twoTo128.subtract(BigInteger.ONE), - new GenericCompUInt(1, 128) - .multiply(new GenericCompUInt(twoTo128.subtract(BigInteger.ONE), 128)) - .toBigInteger() - ); - assertEquals( - twoTo128.subtract(BigInteger.ONE), - new GenericCompUInt(twoTo128.subtract(BigInteger.ONE), 128) - .multiply(new GenericCompUInt(1, 128)) - .toBigInteger() - ); - // multiply no overflow - assertEquals( - new BigInteger("42").multiply(new BigInteger("7")), - new GenericCompUInt(new BigInteger("42"), 128) - .multiply(new GenericCompUInt(new BigInteger("7"), 128)) - .toBigInteger() - ); - // multiply with overflow - assertEquals( - new BigInteger("42").multiply(twoTo128.subtract(BigInteger.ONE)).mod(twoTo128), - new GenericCompUInt(new BigInteger("42"), 128) - .multiply(new GenericCompUInt(twoTo128.subtract(BigInteger.ONE), 128)) - .toBigInteger() - ); - assertEquals( - twoTo64.multiply(twoTo64.add(BigInteger.TEN)).mod(twoTo128), - new GenericCompUInt(twoTo64, 128) - .multiply(new GenericCompUInt(twoTo64.add(BigInteger.TEN), 128)) - .toBigInteger() - ); - } - - @Test - public void testNegate() { - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(BigInteger.ZERO, 128).negate().toBigInteger() - ); - assertEquals( - BigInteger.ONE, - new GenericCompUInt(twoTo128.subtract(BigInteger.ONE), 128).negate().toBigInteger() - ); - assertEquals( - two, - new GenericCompUInt(twoTo128.subtract(two), 128).negate().toBigInteger() - ); - assertEquals( - twoTo128.subtract(two), - new GenericCompUInt(two, 128).negate().toBigInteger() - ); - } - - @Test - public void testSubtract() { - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(BigInteger.ZERO, 128) - .subtract(new GenericCompUInt(BigInteger.ZERO, 128)) - .toBigInteger() - ); - assertEquals( - BigInteger.ONE, - new GenericCompUInt(BigInteger.ONE, 128).subtract(new GenericCompUInt(BigInteger.ZERO, 128)) - .toBigInteger() - ); - assertEquals( - BigInteger.ZERO, - new GenericCompUInt(BigInteger.ONE, 128).subtract(new GenericCompUInt(BigInteger.ONE, 128)) - .toBigInteger() - ); - assertEquals( - twoTo128.subtract(BigInteger.ONE), - new GenericCompUInt(BigInteger.ONE, 128).subtract(new GenericCompUInt(two, 128)) - .toBigInteger() - ); - } - - @Test - public void testToByteArrayWithPadding() { - byte[] bytes = new byte[]{0x42}; - UInt uint = new GenericCompUInt(bytes, 128); - byte[] expected = new byte[16]; - expected[expected.length - 1] = 0x42; - byte[] actual = uint.toByteArray(); - assertArrayEquals(expected, actual); - } - - @Test - public void testToByteArray() { - byte[] bytes = new byte[16]; - new Random(1).nextBytes(bytes); - UInt uint = new GenericCompUInt(bytes, 128); - byte[] actual = uint.toByteArray(); - assertArrayEquals(bytes, actual); - } - - @Test - public void testToByteArrayMore() { - byte[] bytes = new byte[]{ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // high - 0x02, 0x02, 0x02, 0x02, // mid - 0x03, 0x03, 0x02, 0x03 // low - }; - UInt uint = new GenericCompUInt(bytes, 128); - byte[] actual = uint.toByteArray(); - assertArrayEquals(bytes, actual); - } - - @Test - public void testIsZero() { - assertTrue(new GenericCompUInt(0, 128).isZero()); - assertFalse(new GenericCompUInt(1, 128).isZero()); - } - - @Test - public void testGetSubRange() { - byte[] bytes = new byte[]{ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x02, 0x03 - }; - CompUInt uint = new GenericCompUInt(bytes, - 128); - GenericCompUInt subLow = uint.getLeastSignificant(); - byte[] expectedSubRangeBytesLow = new byte[]{ - 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x02, 0x03 - }; - assertArrayEquals(expectedSubRangeBytesLow, subLow.toByteArray()); - GenericCompUInt subHigh = uint.getMostSignificant(); - byte[] expectedSubRangeBytesHigh = new byte[]{ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 - }; - assertArrayEquals(expectedSubRangeBytesHigh, subHigh.toByteArray()); - } - - @Test - public void testGetBitLengths() { - GenericCompUInt uint3232 = new GenericCompUInt(new int[]{1, 0}); - assertEquals(32, uint3232.getHighBitLength()); - assertEquals(32, uint3232.getLowBitLength()); - assertEquals(64, uint3232.getCompositeBitLength()); - GenericCompUInt uint6432 = new GenericCompUInt(new int[]{2, 1, 0}, 32); - assertEquals(64, uint6432.getHighBitLength()); - assertEquals(32, uint6432.getLowBitLength()); - assertEquals(96, uint6432.getCompositeBitLength()); - } - - @Test - public void testShiftLowIntoHigh() { - GenericCompUInt uint3232 = new GenericCompUInt(new int[]{2, 1}); - assertEquals(new GenericCompUInt(new int[]{1, 0}).toBigInteger(), - uint3232.shiftLowIntoHigh().toBigInteger()); - GenericCompUInt uint6432 = new GenericCompUInt(new int[]{3, 2, 1}, 32); - assertEquals(new GenericCompUInt(new int[]{0, 1, 0}).toBigInteger(), - uint6432.shiftLowIntoHigh().toBigInteger()); - GenericCompUInt uint3264 = new GenericCompUInt(new int[]{3, 2, 1}, 64); - assertEquals(new GenericCompUInt(new int[]{1, 0, 0}).toBigInteger(), - uint3264.shiftLowIntoHigh().toBigInteger()); - } - - @Test - public void testToInt() { - GenericCompUInt uint3232 = new GenericCompUInt(new int[]{1111}); - assertEquals(1111, uint3232.toInt()); - } - - @Test - public void testToLong() { - GenericCompUInt uint3232 = new GenericCompUInt(new int[]{122, 1111}); - assertEquals(523986011223L, uint3232.toLong()); - } - - @Test - public void testToString() { - GenericCompUInt uint3232 = new GenericCompUInt(new int[]{122, 1111}); - assertEquals("523986011223", uint3232.toString()); - } - -} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestSpdz2kSInt.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestSpdz2kSIntArithmetic.java similarity index 56% rename from suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestSpdz2kSInt.java rename to suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestSpdz2kSIntArithmetic.java index c7858c61d..6ad9f19c1 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestSpdz2kSInt.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestSpdz2kSIntArithmetic.java @@ -4,13 +4,13 @@ import org.junit.Assert; import org.junit.Test; -public class TestSpdz2kSInt { +public class TestSpdz2kSIntArithmetic { @Test public void testToString() { - Spdz2kSInt sint = new Spdz2kSInt<>( + Spdz2kSIntArithmetic sint = new Spdz2kSIntArithmetic<>( new CompUInt128(BigInteger.ONE), new CompUInt128(BigInteger.ONE) ); - Assert.assertEquals("Spdz2kSInt{share=1, macShare=1}", sint.toString()); + Assert.assertEquals("Spdz2kSIntArithmetic{share=1, macShare=1}", sint.toString()); } } diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestSpdz2kSIntBoolean.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestSpdz2kSIntBoolean.java new file mode 100644 index 000000000..c9e89ac31 --- /dev/null +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/datatypes/TestSpdz2kSIntBoolean.java @@ -0,0 +1,44 @@ +package dk.alexandra.fresco.suite.spdz2k.datatypes; + +import org.junit.Test; + +public class TestSpdz2kSIntBoolean { + + @Test + public void test128() { + CompUInt128 alpha = new CompUInt128(11111L, (int) (1L << 31), 1); + + CompUInt128 valueA = new CompUInt128Bit(0L, 1); + CompUInt128 macA = valueA.toArithmeticRep().multiply(alpha); + + CompUInt128 valueB = new CompUInt128Bit(0L, 0); + CompUInt128 macB = valueB.toArithmeticRep().multiply(alpha); + + CompUInt128 sum = valueA.add(valueB); + CompUInt128 macSum = macA.add(macB); + + System.out.println("sum " + sum + " macSum " + macSum); + System.out.println("alpha * sum (regular arithmetic) " + sum.toArithmeticRep() + .multiply(alpha)); + System.out.println("alpha * sum (bool arithmetic) " + sum.multiply(alpha)); + } + +// @Test +// public void test64() { +// CompUInt64 alpha = new CompUInt64(11111L, (int) (1L << 31), 1); +// +// CompUInt128 valueA = new CompUInt128Bit(0L, 1); +// CompUInt128 macA = valueA.toArithmeticRep().multiply(alpha); +// +// CompUInt128 valueB = new CompUInt128Bit(0L, 0); +// CompUInt128 macB = valueB.toArithmeticRep().multiply(alpha); +// +// CompUInt128 sum = valueA.add(valueB); +// CompUInt128 macSum = macA.add(macB); +// +// System.out.println("sum " + sum + " macSum " + macSum); +// System.out.println("alpha * sum (regular arithmetic) " + sum.toArithmeticRep() +// .multiply(alpha)); +// System.out.println("alpha * sum (bool arithmetic) " + sum.multiply(alpha)); +// } +} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestSpdz2kBroadcastComputation.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestBroadcastComputationSpdz2k.java similarity index 95% rename from suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestSpdz2kBroadcastComputation.java rename to suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestBroadcastComputationSpdz2k.java index 0fbac54ca..0ada34d15 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestSpdz2kBroadcastComputation.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestBroadcastComputationSpdz2k.java @@ -35,7 +35,7 @@ import java.util.stream.Collectors; import org.junit.Test; -public class TestSpdz2kBroadcastComputation extends +public class TestBroadcastComputationSpdz2k extends AbstractSpdz2kTest> { @Test @@ -91,7 +91,8 @@ public void test() throws Exception { } Application, ProtocolBuilderNumeric> testApplication = root -> new BroadcastComputation( - inputs.get(root.getBasicNumericContext().getMyId() - 1)).buildComputation(root); + inputs.get(root.getBasicNumericContext().getMyId() - 1), (noParties > 2)) + .buildComputation(root); List actual = runApplication(testApplication); assertEquals(inputs.size(), actual.size()); for (int i = 0; i < actual.size(); i++) { @@ -122,10 +123,12 @@ public void test() throws Exception { Application, ProtocolBuilderNumeric> testApplication; if (partyId == 2) { testApplication = root -> new MaliciousBroadcastComputation( - inputs.get(root.getBasicNumericContext().getMyId() - 1)).buildComputation(root); + inputs.get(root.getBasicNumericContext().getMyId() - 1), noParties > 2) + .buildComputation(root); } else { testApplication = root -> new BroadcastComputation( - inputs.get(root.getBasicNumericContext().getMyId() - 1)).buildComputation(root); + inputs.get(root.getBasicNumericContext().getMyId() - 1), noParties > 2) + .buildComputation(root); } // we need that new test framework... try { @@ -143,8 +146,8 @@ private static class MaliciousBroadcastComputation extends private final List inputCopy; - MaliciousBroadcastComputation(byte[] input) { - super(input); + MaliciousBroadcastComputation(byte[] input, boolean doValidation) { + super(input, doValidation); this.inputCopy = Collections.singletonList(input); } diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestSpdz2kCommitmentComputation.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestCommitmentComputationSpdz2k.java similarity index 97% rename from suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestSpdz2kCommitmentComputation.java rename to suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestCommitmentComputationSpdz2k.java index b3e83b6a4..d7616a2fa 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestSpdz2kCommitmentComputation.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestCommitmentComputationSpdz2k.java @@ -26,7 +26,7 @@ import java.util.function.Supplier; import org.junit.Test; -public class TestSpdz2kCommitmentComputation extends +public class TestCommitmentComputationSpdz2k extends AbstractSpdz2kTest> { @Test @@ -76,7 +76,7 @@ public void test() { inputs.add(bytes); } Application, ProtocolBuilderNumeric> testApplication = - root -> new Spdz2kCommitmentComputation( + root -> new CommitmentComputationSpdz2k( conf.getResourcePool().getCommitmentSerializer(), inputs.get(root.getBasicNumericContext().getMyId() - 1), noParties, conf.getResourcePool().getLocalRandomGenerator()) diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestComparisonSpdz2k.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestComparisonSpdz2k.java new file mode 100644 index 000000000..f9d92af8d --- /dev/null +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestComparisonSpdz2k.java @@ -0,0 +1,246 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.computations; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.NumericResourcePool; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.sce.evaluator.EvaluationStrategy; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.util.AesCtrDrbg; +import dk.alexandra.fresco.framework.util.MathUtils; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntFactory; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.lib.compare.CompareTests.TestLessThanLogRounds; +import dk.alexandra.fresco.lib.compare.lt.CarryOut; +import dk.alexandra.fresco.suite.ProtocolSuiteNumeric; +import dk.alexandra.fresco.suite.spdz2k.AbstractSpdz2kTest; +import dk.alexandra.fresco.suite.spdz2k.Spdz2kProtocolSuite128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128Factory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePoolImpl; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDummyDataSupplier; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kOpenedValueStoreImpl; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import org.junit.Assert; +import org.junit.Test; + +public class TestComparisonSpdz2k extends + AbstractSpdz2kTest> { + + @Test + public void testCarryOutZero() { + runTest(new TestCarryOutSpdz2k<>(0x00000000, 0x00000000), EvaluationStrategy.SEQUENTIAL_BATCHED, + 2); + } + + @Test + public void testCarryOutOne() { + runTest(new TestCarryOutSpdz2k<>(0x80000000, 0x80000000), EvaluationStrategy.SEQUENTIAL_BATCHED, + 2); + } + + @Test + public void testCarryOutAllOnes() { + runTest(new TestCarryOutSpdz2k<>(0xffffffff, 0xffffffff), EvaluationStrategy.SEQUENTIAL_BATCHED, + 2); + } + + @Test + public void testCarryOutOneFromCarry() { + runTest(new TestCarryOutSpdz2k<>(0x40000000, 0xc0000000), EvaluationStrategy.SEQUENTIAL_BATCHED, + 2); + } + + @Test + public void testCarryOutRandom() { + Random random = new Random(1); + int l = random.nextInt(); + int r = random.nextInt(); + runTest(new TestCarryOutSpdz2k<>(l, r), + EvaluationStrategy.SEQUENTIAL_BATCHED, 2); + } + + @Test + public void testBitLessThan() { + runTest(new TestBitLessThanOpenSpdz2k<>(), + EvaluationStrategy.SEQUENTIAL_BATCHED, 2); + } + + @Test + public void testLessThanLogRounds() { + runTest(new TestLessThanLogRounds<>(64), + EvaluationStrategy.SEQUENTIAL_BATCHED, 2); + } + + @Override + protected Spdz2kResourcePool createResourcePool(int playerId, int noOfParties, + Supplier networkSupplier) { + CompUIntFactory factory = new CompUInt128Factory(); + CompUInt128 keyShare = factory.createRandom(); + Spdz2kResourcePool resourcePool = + new Spdz2kResourcePoolImpl<>( + playerId, + noOfParties, new AesCtrDrbg(new byte[32]), + new Spdz2kOpenedValueStoreImpl<>(), + new Spdz2kDummyDataSupplier<>(playerId, noOfParties, keyShare, factory), + factory); + resourcePool.initializeJointRandomness(networkSupplier, AesCtrDrbg::new, 32); + return resourcePool; + } + + @Override + protected ProtocolSuiteNumeric> createProtocolSuite() { + return new Spdz2kProtocolSuite128(true); + } + + public static class TestCarryOutSpdz2k + extends TestThreadFactory { + + private final List left; + private final List right; + private final BigInteger expected; + + TestCarryOutSpdz2k(int l, int r) { + expected = carry(l, r); + left = intToBits(l); + right = new ArrayList<>(left.size()); + right.addAll(intToBits(r)); + } + + @Override + public TestThread next() { + + return new TestThread() { + + @Override + public void test() { + Application app = + root -> { + DRes>> leftClosed = + root.conversion().toBooleanBatch(root.collections().closeList(right, 1)); + OIntFactory oIntFactory = root.getOIntFactory(); + DRes carry = root + .seq(new CarryOut(() -> oIntFactory.fromBigInteger(right), leftClosed, + oIntFactory.zero())); + DRes opened = root.logical().openAsBit(carry); + return () -> oIntFactory.toBigInteger(opened.out()); + }; + BigInteger actual = runApplication(app); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestBitLessThanOpenSpdz2k + extends TestThreadFactory { + + private List left; + private List right; + + @Override + public TestThread next() { + + return new TestThread() { + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + int numBits = 32; + OIntFactory oIntFactory = root.getOIntFactory(); + setupInputs(conf.getResourcePool().getModulus(), numBits); + List> results = new ArrayList<>(left.size()); + for (int i = 0; i < left.size(); i++) { + OInt leftValue = oIntFactory.fromBigInteger(left.get(i)); + DRes>> rightValue = toSecretBits(root, right.get(i), + numBits); + results.add( + root.logical().openAsBit( + root.comparison().compareLTBits(leftValue, rightValue) + ) + ); + } + return () -> results.stream().map(v -> oIntFactory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = new ArrayList<>(left.size()); + for (int i = 0; i < left.size(); i++) { + boolean leq = left.get(i).compareTo(right.get(i)) < 0; + expected.add(leq ? BigInteger.ONE : BigInteger.ZERO); + } + Assert.assertEquals(expected, actual); + } + }; + } + + private void setupInputs(BigInteger modulus, int numBits) { + Random random = new Random(42); + this.left = Arrays.asList( + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.valueOf(5), + BigInteger.valueOf(111), + BigInteger.valueOf(111), + modulus.subtract(BigInteger.ONE), + modulus.subtract(BigInteger.ONE), + BigInteger.valueOf(2055014152), + new BigInteger(numBits, random).mod(modulus) + ); + this.right = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.valueOf(4), + BigInteger.valueOf(111), + BigInteger.valueOf(112), + modulus.subtract(BigInteger.ONE), + modulus.subtract(BigInteger.valueOf(2)), + BigInteger.valueOf(2055014153), + new BigInteger(numBits, random).mod(modulus) + ); + } + + } + + private static DRes>> toSecretBits(ProtocolBuilderNumeric root, + BigInteger value, + int numBits) { + List openList = MathUtils.toBits(value, numBits); + Collections.reverse(openList); + return root.collections().closeList(openList, 1); + } + + private static BigInteger carry(int a, int b) { + long res = Integer.toUnsignedLong(a) + Integer.toUnsignedLong(b); + int carry = (int) ((res & (1L << 32)) >> 32); + return BigInteger.valueOf(carry); + } + + private static List intToBits(int value) { + int numBits = Integer.SIZE; + List bits = new ArrayList<>(numBits); + for (int i = 0; i < numBits; i++) { + int bit = (value & (1 << i)) >>> i; + bits.add(BigInteger.valueOf(bit)); + } + Collections.reverse(bits); + return bits; + } + +} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestConversionSpdz2k.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestConversionSpdz2k.java new file mode 100644 index 000000000..0320f34d0 --- /dev/null +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestConversionSpdz2k.java @@ -0,0 +1,138 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.computations; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.sce.evaluator.EvaluationStrategy; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.util.AesCtrDrbg; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntFactory; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.ProtocolSuiteNumeric; +import dk.alexandra.fresco.suite.spdz2k.AbstractSpdz2kTest; +import dk.alexandra.fresco.suite.spdz2k.Spdz2kProtocolSuite128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128Factory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePoolImpl; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDummyDataSupplier; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kOpenedValueStoreImpl; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import org.junit.Assert; +import org.junit.Test; + +public class TestConversionSpdz2k extends + AbstractSpdz2kTest> { + + @Test + public void testArithmeticToBool() { + runTest(new TestArithmeticToBool<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testBoolToArithmetic() { + runTest(new TestBoolToArithmetic<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Override + protected Spdz2kResourcePool createResourcePool(int playerId, int noOfParties, + Supplier networkSupplier) { + CompUIntFactory factory = new CompUInt128Factory(); + Spdz2kResourcePool resourcePool = + new Spdz2kResourcePoolImpl<>( + playerId, + noOfParties, null, + new Spdz2kOpenedValueStoreImpl<>(), + new Spdz2kDummyDataSupplier<>(playerId, noOfParties, factory.createRandom(), factory), + factory); + resourcePool.initializeJointRandomness(networkSupplier, AesCtrDrbg::new, 32); + return resourcePool; + } + + @Override + protected ProtocolSuiteNumeric> createProtocolSuite() { + return new Spdz2kProtocolSuite128(true); + } + + public static class TestArithmeticToBool + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + + private final List input = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO + ); + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + OIntFactory factory = root.getOIntFactory(); + DRes>> inputClosed = root.collections().closeList(input, 1); + DRes>> inputBool = root.conversion().toBooleanBatch(inputClosed); + DRes>> opened = root.logical().openAsBits(inputBool); + return () -> opened.out().stream().map(v -> factory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestBoolToArithmetic + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + + private final List input = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO + ); + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes>> inputClosed = root.collections().closeList(input, 1); + DRes>> inputBool = root.conversion().toBooleanBatch(inputClosed); + DRes>> inputArithmetic = root.conversion() + .toArithmeticBatch(inputBool); + DRes>> opened = root.collections().openList(inputArithmetic); + return () -> opened.out().stream().map(DRes::out) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + +} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestLogicalOperationsSpdz2k.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestLogicalOperationsSpdz2k.java new file mode 100644 index 000000000..f270c051a --- /dev/null +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestLogicalOperationsSpdz2k.java @@ -0,0 +1,693 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.computations; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.sce.evaluator.EvaluationStrategy; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.util.AesCtrDrbg; +import dk.alexandra.fresco.framework.value.OInt; +import dk.alexandra.fresco.framework.value.OIntFactory; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.ProtocolSuiteNumeric; +import dk.alexandra.fresco.suite.spdz2k.AbstractSpdz2kTest; +import dk.alexandra.fresco.suite.spdz2k.Spdz2kProtocolSuite128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128Factory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePoolImpl; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDummyDataSupplier; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kOpenedValueStoreImpl; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import org.junit.Assert; +import org.junit.Test; + +public class TestLogicalOperationsSpdz2k extends + AbstractSpdz2kTest> { + + @Test + public void testAnd() { + runTest(new TestAndSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testBatchedAnd() { + runTest(new TestBatchedAndSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testOr() { + runTest(new TestOrSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testOrList() { + runTest(new TestOrListSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testAndXorSequence() { + runTest(new TestAndXorSequence<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testSequentialAnd() { + runTest(new TestSequentialAndSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testXor() { + runTest(new TestXorSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testXorKnown() { + runTest(new TestXorKnownSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testSequentialXor() { + runTest(new TestSequentialXorSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testSequentialAndKnown() { + runTest(new TestAndKnownSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testXorRandom() { + runTest(new TestXorSpdz2kRandom<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testAndRandom() { + runTest(new TestAndSpdz2kRandom<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Test + public void testNot() { + runTest(new TestNotSpdz2k<>(), EvaluationStrategy.SEQUENTIAL_BATCHED); + } + + @Override + protected Spdz2kResourcePool createResourcePool(int playerId, int noOfParties, + Supplier networkSupplier) { + CompUIntFactory factory = new CompUInt128Factory(); + CompUInt128 keyShare = factory.createRandom(); + Spdz2kResourcePool resourcePool = + new Spdz2kResourcePoolImpl<>( + playerId, + noOfParties, new AesCtrDrbg(new byte[32]), + new Spdz2kOpenedValueStoreImpl<>(), + new Spdz2kDummyDataSupplier<>(playerId, noOfParties, keyShare, factory), + factory); + resourcePool.initializeJointRandomness(networkSupplier, AesCtrDrbg::new, 32); + return resourcePool; + } + + @Override + protected ProtocolSuiteNumeric> createProtocolSuite() { + return new Spdz2kProtocolSuite128(true); + } + + public static class TestOrListSpdz2k extends + TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List input1 = Arrays.asList(BigInteger.ZERO, + BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, BigInteger.ONE); + private final List input2 = Arrays.asList(BigInteger.ZERO, + BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO); + private final List input3 = Arrays.asList(BigInteger.ZERO, + BigInteger.ZERO, BigInteger.ONE, BigInteger.ZERO, BigInteger.ZERO); + private final List input4 = Arrays.asList(BigInteger.ZERO, + BigInteger.ZERO, BigInteger.ONE, BigInteger.ZERO, BigInteger.ONE); + + @Override + public void test() { + List> inputLists = Arrays.asList(input1, input2, + input3, input4); + List expectedOutput = Arrays.asList(BigInteger.ONE, + BigInteger.ZERO, BigInteger.ONE, BigInteger.ONE); + + Application, ProtocolBuilderNumeric> app = root -> { + OIntFactory factory = root.getOIntFactory(); + List> results = inputLists.stream().map( + current -> { + final DRes>> arithmeticBatch = root.numeric() + .knownAsDRes(current); + final DRes>> bits = root.conversion() + .toBooleanBatch(arithmeticBatch); + final DRes orred = root.logical().orOfList(bits); + return root.logical().openAsBit(orred); + }).collect(Collectors.toList()); + return () -> results.stream().map(d -> factory.toBigInteger(d.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + Assert.assertArrayEquals(expectedOutput.toArray(), actual.toArray()); + } + }; + } + } + + public static class TestNotSpdz2k + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes notOne = root.logical().not( + root.conversion().toBoolean(root.numeric().input(BigInteger.ONE, 1))); + DRes notZero = root.logical().not( + root.conversion().toBoolean(root.numeric().input(BigInteger.ZERO, 2))); + List> notted = Arrays.asList(notOne, notZero); + DRes>> opened = root.logical().openAsBits(() -> notted); + return () -> opened.out().stream() + .map(v -> root.getOIntFactory().toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = Arrays.asList( + BigInteger.ZERO, + BigInteger.ONE + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestXorKnownSpdz2k + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO); + private final List right = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO); + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.conversion() + .toBooleanBatch(root.collections().closeList(left, 1)); + OIntFactory oIntFactory = root.getOIntFactory(); + List rightOInts = oIntFactory.fromBigInteger(right); + DRes>> xored = root.logical() + .pairWiseXorKnown(() -> rightOInts, leftClosed); + DRes>> opened = root.logical().openAsBits(xored); + return () -> opened.out().stream().map(v -> oIntFactory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = Arrays.asList( + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestAndKnownSpdz2k + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO); + private final List right = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO); + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.conversion() + .toBooleanBatch(root.collections().closeList(left, 1)); + OIntFactory oIntFactory = root.getOIntFactory(); + List rightOInts = oIntFactory.fromBigInteger(right); + DRes>> anded = root.logical() + .pairWiseAndKnown(() -> rightOInts, leftClosed); + DRes>> opened = root.logical().openAsBits(anded); + return () -> opened.out().stream().map(v -> oIntFactory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestSequentialXorSpdz2k + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ONE + ); + + @Override + public void test() { + Application app = + root -> { + DRes bit = root.conversion().toBoolean(root.numeric().input(left.get(0), 1)); + for (int i = 1; i < left.size(); i++) { + bit = root.logical().xor(bit, + root.conversion().toBoolean(root.numeric().input(left.get(i), 1))); + } + DRes result = root.logical().openAsBit(bit); + return () -> root.getOIntFactory().toBigInteger(result.out()); + }; + BigInteger actual = runApplication(app); + Assert.assertEquals(BigInteger.ONE, actual); + } + }; + } + } + + public static class TestSequentialAndSpdz2k + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ONE + ); + + @Override + public void test() { + Application app = + root -> { + DRes bit = root.conversion().toBoolean(root.numeric().input(left.get(0), 1)); + for (int i = 1; i < left.size(); i++) { + bit = root.logical().and(bit, + root.conversion().toBoolean(root.numeric().input(left.get(i), 1))); + } + DRes result = root.logical().openAsBit(bit); + return () -> root.getOIntFactory().toBigInteger(result.out()); + }; + BigInteger actual = runApplication(app); + Assert.assertEquals(BigInteger.ZERO, actual); + } + }; + } + } + + public static class TestOrSpdz2k + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO + ); + private final List right = Arrays.asList( + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ONE + ); + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = + root.collections().closeList(left, 1); + DRes>> rightClosed = root.collections().closeList(right, 1); + DRes>> leftConverted = root.conversion() + .toBooleanBatch(leftClosed); + DRes>> rightConverted = root.conversion() + .toBooleanBatch(rightClosed); + DRes>> anded = root.logical().pairWiseOr( + leftConverted, + rightConverted + ); + DRes>> opened = root.logical().openAsBits(anded); + OIntFactory factory = root.getOIntFactory(); + return () -> opened.out().stream().map(v -> factory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ONE + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestXorSpdz2k + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO + ); + private final List right = Arrays.asList( + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ONE + ); + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = + root.collections().closeList(left, 1); + DRes>> rightClosed = root.collections().closeList(right, 1); + DRes>> leftConverted = root.conversion() + .toBooleanBatch(leftClosed); + DRes>> rightConverted = root.conversion() + .toBooleanBatch(rightClosed); + DRes>> anded = root.logical().pairWiseXor( + leftConverted, + rightConverted + ); + DRes>> opened = root.logical().openAsBits(anded); + OIntFactory factory = root.getOIntFactory(); + return () -> opened.out().stream().map(v -> factory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ONE + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + + public static class TestAndSpdz2k + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ONE, + BigInteger.ZERO + ); + private final List right = Arrays.asList( + BigInteger.ONE, + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO + ); + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.numeric().knownAsDRes(left); + DRes>> rightClosed = root.numeric().knownAsDRes(right); + DRes>> leftConverted = root.conversion() + .toBooleanBatch(leftClosed); + DRes>> rightConverted = root.conversion() + .toBooleanBatch(rightClosed); + DRes>> anded = root.logical().pairWiseAnd( + leftConverted, + rightConverted + ); + DRes>> opened = root.logical().openAsBits(anded); + OIntFactory factory = root.getOIntFactory(); + return () -> opened.out().stream().map(v -> factory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = Arrays.asList( + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ZERO + ); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestBatchedAndSpdz2k + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + BigInteger leftBit = BigInteger.ONE; + BigInteger rightBit = BigInteger.ZERO; + final int repetitions = 20000; + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes leftBitClosed = + root.conversion().toBoolean(root.numeric().input(leftBit, 1)); + DRes rightBitClosed = + root.conversion().toBoolean(root.numeric().input(rightBit, 1)); + List> leftBits = new ArrayList<>(repetitions); + List> rightBits = new ArrayList<>(repetitions); + for (int i = 0; i < repetitions; i++) { + leftBits.add(leftBitClosed); + rightBits.add(rightBitClosed); + } + DRes>> anded = root.logical().pairWiseAnd( + () ->leftBits, + () -> rightBits + ); + DRes>> opened = root.logical().openAsBits(anded); + OIntFactory factory = root.getOIntFactory(); + return () -> opened.out().stream().map(v -> factory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + Assert.assertEquals(repetitions, actual.size()); + for (BigInteger actualBit : actual) { + Assert.assertEquals(BigInteger.ZERO, actualBit); + } + } + }; + } + } + + public static class TestXorSpdz2kRandom + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = randomBits(100, 1); + private final List right = randomBits(100, 2); + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.numeric().knownAsDRes(left); + DRes>> rightClosed = root.numeric().knownAsDRes(right); + DRes>> leftConverted = root.conversion().toBooleanBatch(leftClosed); + DRes>> rightConverted = root.conversion() + .toBooleanBatch(rightClosed); + DRes>> anded = root.logical().pairWiseXor( + leftConverted, + rightConverted + ); + DRes>> opened = root.logical().openAsBits(anded); + OIntFactory factory = root.getOIntFactory(); + return () -> opened.out().stream().map(v -> factory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = xor(left, right); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestAndSpdz2kRandom + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + private final List left = randomBits(100, 1); + private final List right = randomBits(100, 2); + + @Override + public void test() { + Application, ProtocolBuilderNumeric> app = + root -> { + DRes>> leftClosed = root.numeric().knownAsDRes(left); + DRes>> rightClosed = root.numeric().knownAsDRes(right); + DRes>> leftConverted = root.conversion().toBooleanBatch(leftClosed); + DRes>> rightConverted = root.conversion() + .toBooleanBatch(rightClosed); + DRes>> anded = root.logical().pairWiseAnd( + leftConverted, + rightConverted + ); + DRes>> opened = root.logical().openAsBits(anded); + OIntFactory factory = root.getOIntFactory(); + return () -> opened.out().stream().map(v -> factory.toBigInteger(v.out())) + .collect(Collectors.toList()); + }; + List actual = runApplication(app); + List expected = and(left, right); + Assert.assertEquals(expected, actual); + } + }; + } + } + + public static class TestAndXorSequence + extends TestThreadFactory { + + @Override + public TestThread next() { + + return new TestThread() { + + @Override + public void test() { + Application app = + root -> { + DRes b = bit(root, 1); + b = root.logical().and(b, bit(root, 1)); + b = root.logical().and(b, bit(root, 0)); + b = root.logical().xor(b, bit(root, 0)); + b = root.logical().xor(b, bit(root, 1)); + b = root.logical().xor(b, bit(root, 1)); + b = root.logical().and(b, bit(root, 0)); + DRes opened = root.logical().openAsBit(b); + OIntFactory factory = root.getOIntFactory(); + return () -> factory.toBigInteger(opened.out()); + }; + BigInteger actual = runApplication(app); + Assert.assertEquals(BigInteger.ZERO, actual); + } + }; + } + } + + private static List randomBits(int num, int seed) { + Random random = new Random(seed); + List bits = new ArrayList<>(num); + for (int i = 0; i < num; i++) { + bits.add(random.nextBoolean() ? BigInteger.ONE : BigInteger.ZERO); + } + return bits; + } + + private static List and(List left, List right) { + List bits = new ArrayList<>(left.size()); + for (int i = 0; i < left.size(); i++) { + bits.add(left.get(i).multiply(right.get(i)).mod(BigInteger.valueOf(2))); + } + return bits; + } + + private static List xor(List left, List right) { + List bits = new ArrayList<>(left.size()); + for (int i = 0; i < left.size(); i++) { + bits.add(left.get(i).add(right.get(i)).mod(BigInteger.valueOf(2))); + } + return bits; + } + + private static DRes bit(ProtocolBuilderNumeric root, int bit) { + return root.conversion().toBoolean(root.numeric().input(BigInteger.valueOf(bit), 1)); + } + +} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestSpdz2kMacCheckComputation.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestMacCheckComputationSpdz2k.java similarity index 95% rename from suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestSpdz2kMacCheckComputation.java rename to suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestMacCheckComputationSpdz2k.java index c2faab9cc..2c617919e 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestSpdz2kMacCheckComputation.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestMacCheckComputationSpdz2k.java @@ -19,7 +19,7 @@ import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128Factory; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePoolImpl; import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDummyDataSupplier; @@ -28,7 +28,7 @@ import java.util.function.Supplier; import org.junit.Test; -public class TestSpdz2kMacCheckComputation extends +public class TestMacCheckComputationSpdz2k extends AbstractSpdz2kTest> { @Test @@ -89,7 +89,7 @@ public void test() { return producer.seq(seq -> { SInt value = input.out(); if (seq.getBasicNumericContext().getMyId() == cheatingPartyId) { - value = ((Spdz2kSInt) value).multiply( + value = ((Spdz2kSIntArithmetic) value).multiply( new CompUInt128(BigInteger.valueOf(2))); } final SInt finalSInt = value; diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestTruncateSpdz2k.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestTruncateSpdz2k.java new file mode 100644 index 000000000..c776fa106 --- /dev/null +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/protocols/computations/TestTruncateSpdz2k.java @@ -0,0 +1,113 @@ +package dk.alexandra.fresco.suite.spdz2k.protocols.computations; + +import dk.alexandra.fresco.framework.Application; +import dk.alexandra.fresco.framework.DRes; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThread; +import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory; +import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric; +import dk.alexandra.fresco.framework.network.Network; +import dk.alexandra.fresco.framework.sce.evaluator.EvaluationStrategy; +import dk.alexandra.fresco.framework.sce.resources.ResourcePool; +import dk.alexandra.fresco.framework.util.AesCtrDrbg; +import dk.alexandra.fresco.framework.value.SInt; +import dk.alexandra.fresco.suite.ProtocolSuiteNumeric; +import dk.alexandra.fresco.suite.spdz2k.AbstractSpdz2kTest; +import dk.alexandra.fresco.suite.spdz2k.Spdz2kProtocolSuite128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128Factory; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePool; +import dk.alexandra.fresco.suite.spdz2k.resource.Spdz2kResourcePoolImpl; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kDummyDataSupplier; +import dk.alexandra.fresco.suite.spdz2k.resource.storage.Spdz2kOpenedValueStoreImpl; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import org.junit.Assert; +import org.junit.Test; + +public class TestTruncateSpdz2k extends + AbstractSpdz2kTest> { + + @Override + protected Spdz2kResourcePool createResourcePool(int playerId, int noOfParties, + Supplier networkSupplier) { + CompUIntFactory factory = new CompUInt128Factory(); + CompUInt128 keyShare = factory.createRandom(); + Spdz2kResourcePool resourcePool = + new Spdz2kResourcePoolImpl<>( + playerId, + noOfParties, new AesCtrDrbg(new byte[32]), + new Spdz2kOpenedValueStoreImpl<>(), + new Spdz2kDummyDataSupplier<>(playerId, noOfParties, keyShare, factory), + factory); + resourcePool.initializeJointRandomness(networkSupplier, AesCtrDrbg::new, 32); + return resourcePool; + } + + @Override + protected ProtocolSuiteNumeric> createProtocolSuite() { + return new Spdz2kProtocolSuite128(true); + } + + @Test + public void testTruncate() { + runTest(new TestTruncate<>(), EvaluationStrategy.SEQUENTIAL_BATCHED, 2); + } + + public static class TestTruncate + extends TestThreadFactory { + + private int maxBitLength; + + @Override + public TestThread next() { + + return new TestThread() { + + @Override + public void test() { + List inputs = Arrays.asList( + BigInteger.valueOf(-1), + BigInteger.ONE, + BigInteger.ZERO, + BigInteger.valueOf(2723121121381238012L), + BigInteger.valueOf(121121381238012L) + ); + Application>, ProtocolBuilderNumeric> app = + root -> { + List> result = new ArrayList<>(inputs.size()); + for (BigInteger input : inputs) { + result.add( + root.advancedNumeric().truncate(root.numeric().input(input, 1), 16) + ); + } + maxBitLength = root.getBasicNumericContext().getMaxBitLength(); + return root.collections().openList(() -> result); + }; + List actuals = runApplication(app).stream().map(DRes::out) + .collect(Collectors.toList()); + BigInteger modulus = BigInteger.ONE.shiftLeft(maxBitLength); + for (int i = 0; i < inputs.size(); i++) { + BigInteger expected = inputs.get(i).shiftRight(16).mod(modulus); + BigInteger actual = actuals.get(i); + assertWithinOne(expected, actual, modulus); + } + } + }; + } + } + + private static void assertWithinOne(BigInteger expected, BigInteger actual, BigInteger modulus) { + BigInteger difference = expected.subtract(actual).mod(modulus); + String failureMessage = "Actual " + actual + " != " + expected + "+/-1"; + Assert.assertTrue(failureMessage, + difference.equals(BigInteger.ZERO) + || difference.equals(BigInteger.ONE) + || difference.equals(BigInteger.valueOf(-1).mod(modulus))); + } + +} diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/TestSpdz2kDummyDataSupplier.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/TestSpdz2kDummyDataSupplier.java index 4965502f5..7f2a98491 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/TestSpdz2kDummyDataSupplier.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/resource/storage/TestSpdz2kDummyDataSupplier.java @@ -5,12 +5,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128Factory; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSInt; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kInputMask; +import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kSIntArithmetic; import dk.alexandra.fresco.suite.spdz2k.datatypes.Spdz2kTriple; -import dk.alexandra.fresco.suite.spdz2k.datatypes.GenericCompUInt; -import dk.alexandra.fresco.suite.spdz2k.datatypes.GenericCompUIntFactory; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; @@ -20,26 +20,26 @@ public class TestSpdz2kDummyDataSupplier { private void testGetNextRandomElementShare(int noOfParties) { - List> suppliers = setupSuppliers(noOfParties); - GenericCompUInt macKey = getMacKeyFromSuppliers(suppliers); - List> shares = new ArrayList<>(noOfParties); - for (Spdz2kDataSupplier supplier : suppliers) { + List> suppliers = setupSuppliers(noOfParties); + CompUInt128 macKey = getMacKeyFromSuppliers(suppliers); + List> shares = new ArrayList<>(noOfParties); + for (Spdz2kDataSupplier supplier : suppliers) { shares.add(supplier.getNextRandomElementShare()); } - Spdz2kSInt recombined = recombine(shares); + Spdz2kSIntArithmetic recombined = recombine(shares); assertFalse("Random value was 0 ", recombined.getShare().toBigInteger().equals(BigInteger.ZERO)); assertMacCorrect(recombined, macKey); } private void testGetNextBitShare(int noOfParties) { - List> suppliers = setupSuppliers(noOfParties); - GenericCompUInt macKey = getMacKeyFromSuppliers(suppliers); - List> shares = new ArrayList<>(noOfParties); - for (Spdz2kDataSupplier supplier : suppliers) { + List> suppliers = setupSuppliers(noOfParties); + CompUInt128 macKey = getMacKeyFromSuppliers(suppliers); + List> shares = new ArrayList<>(noOfParties); + for (Spdz2kDataSupplier supplier : suppliers) { shares.add(supplier.getNextBitShare()); } - Spdz2kSInt recombined = recombine(shares); + Spdz2kSIntArithmetic recombined = recombine(shares); BigInteger asBitInt = recombined.getShare().toBigInteger(); assertTrue("Not a bit " + asBitInt, asBitInt.equals(BigInteger.ZERO) || asBitInt.equals(BigInteger.ONE)); @@ -47,16 +47,16 @@ private void testGetNextBitShare(int noOfParties) { } private void testGetInputMask(int noOfParties, int towardParty) { - List> suppliers = setupSuppliers(noOfParties); - GenericCompUInt macKey = getMacKeyFromSuppliers(suppliers); - List> masks = new ArrayList<>(noOfParties); - for (Spdz2kDataSupplier supplier : suppliers) { + List> suppliers = setupSuppliers(noOfParties); + CompUInt128 macKey = getMacKeyFromSuppliers(suppliers); + List> masks = new ArrayList<>(noOfParties); + for (Spdz2kDataSupplier supplier : suppliers) { masks.add(supplier.getNextInputMask(towardParty)); } - GenericCompUInt realValue = null; - List> shares = new ArrayList<>(noOfParties); + CompUInt128 realValue = null; + List> shares = new ArrayList<>(noOfParties); for (int i = 1; i <= noOfParties; i++) { - Spdz2kInputMask inputMask = masks.get(i - 1); + Spdz2kInputMask inputMask = masks.get(i - 1); if (i != towardParty) { assertTrue(null == inputMask.getOpenValue()); } else { @@ -64,19 +64,19 @@ private void testGetInputMask(int noOfParties, int towardParty) { } shares.add(inputMask.getMaskShare()); } - Spdz2kSInt recombined = recombine(shares); + Spdz2kSIntArithmetic recombined = recombine(shares); assertMacCorrect(recombined, macKey); assertEquals(realValue.toBigInteger(), recombined.getShare().toBigInteger()); } private void testGetNextTripleShares(int noOfParties) { - List> suppliers = setupSuppliers(noOfParties); - GenericCompUInt macKey = getMacKeyFromSuppliers(suppliers); - List> triples = new ArrayList<>(noOfParties); - for (Spdz2kDataSupplier supplier : suppliers) { - triples.add(supplier.getNextTripleShares()); + List> suppliers = setupSuppliers(noOfParties); + CompUInt128 macKey = getMacKeyFromSuppliers(suppliers); + List>> triples = new ArrayList<>(noOfParties); + for (Spdz2kDataSupplier supplier : suppliers) { + triples.add(supplier.getNextTripleSharesFull()); } - Spdz2kTriple recombined = recombineTriples(triples); + Spdz2kTriple> recombined = recombineTriples(triples); assertTripleValid(recombined, macKey); } @@ -111,45 +111,45 @@ public void testGetNextTripleShares() { testGetNextTripleShares(5); } - private Spdz2kSInt recombine( - List> shares) { - return shares.stream().reduce(Spdz2kSInt::add).get(); + private Spdz2kSIntArithmetic recombine( + List> shares) { + return shares.stream().reduce(Spdz2kSIntArithmetic::add).get(); } - private void assertMacCorrect(Spdz2kSInt recombined, - GenericCompUInt macKey) { + private void assertMacCorrect(Spdz2kSIntArithmetic recombined, + CompUInt128 macKey) { assertArrayEquals( macKey.multiply(recombined.getShare()).toByteArray(), recombined.getMacShare().toByteArray() ); } - private List> setupSuppliers( + private List> setupSuppliers( int noOfParties) { - List> suppliers = new ArrayList<>( + List> suppliers = new ArrayList<>( noOfParties); for (int i = 0; i < noOfParties; i++) { - CompUIntFactory factory = new GenericCompUIntFactory(64, 64); - GenericCompUInt macKeyShare = factory.createRandom(); + CompUIntFactory factory = new CompUInt128Factory(); + CompUInt128 macKeyShare = factory.createRandom(); suppliers.add(new Spdz2kDummyDataSupplier<>(i + 1, noOfParties, macKeyShare, factory)); } return suppliers; } - private GenericCompUInt getMacKeyFromSuppliers( - List> suppliers) { + private CompUInt128 getMacKeyFromSuppliers( + List> suppliers) { return suppliers.stream() .map(Spdz2kDataSupplier::getSecretSharedKey) - .reduce(GenericCompUInt::add).get(); + .reduce(CompUInt128::add).get(); } - private Spdz2kTriple recombineTriples( - List> triples) { - List> left = new ArrayList<>(triples.size()); - List> right = new ArrayList<>(triples.size()); - List> product = new ArrayList<>(triples.size()); - for (Spdz2kTriple triple : triples) { + private Spdz2kTriple> recombineTriples( + List>> triples) { + List> left = new ArrayList<>(triples.size()); + List> right = new ArrayList<>(triples.size()); + List> product = new ArrayList<>(triples.size()); + for (Spdz2kTriple> triple : triples) { left.add(triple.getLeft()); right.add(triple.getRight()); product.add(triple.getProduct()); @@ -157,10 +157,10 @@ private Spdz2kTriple recombineTriples( return new Spdz2kTriple<>(recombine(left), recombine(right), recombine(product)); } - private void assertTripleValid(Spdz2kTriple recombined, GenericCompUInt macKey) { + private void assertTripleValid(Spdz2kTriple> recombined, CompUInt128 macKey) { assertMacCorrect(recombined.getLeft(), macKey); assertMacCorrect(recombined.getRight(), macKey); - assertMacCorrect(recombined.getRight(), macKey); + assertMacCorrect(recombined.getProduct(), macKey); // check that a * b = c assertEquals(recombined.getProduct().getShare().toBigInteger(), recombined.getLeft().getShare().multiply(recombined.getRight().getShare()).toBigInteger()); diff --git a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/util/TestUIntSerializer.java b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/util/TestUIntSerializer.java index 60b582912..cab6ea0eb 100644 --- a/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/util/TestUIntSerializer.java +++ b/suite/spdz2k/src/test/java/dk/alexandra/fresco/suite/spdz2k/util/TestUIntSerializer.java @@ -4,9 +4,9 @@ import static org.junit.Assert.assertEquals; import dk.alexandra.fresco.framework.network.serializers.ByteSerializer; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128; +import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUInt128Factory; import dk.alexandra.fresco.suite.spdz2k.datatypes.CompUIntFactory; -import dk.alexandra.fresco.suite.spdz2k.datatypes.GenericCompUInt; -import dk.alexandra.fresco.suite.spdz2k.datatypes.GenericCompUIntFactory; import java.util.Arrays; import java.util.List; import java.util.Random; @@ -14,8 +14,8 @@ public class TestUIntSerializer { - private final CompUIntFactory factory = new GenericCompUIntFactory(64, 64); - private final ByteSerializer serializer = new UIntSerializer<>(factory); + private final CompUIntFactory factory = new CompUInt128Factory(); + private final ByteSerializer serializer = new UIntSerializer<>(factory); @Test public void testSerialize() { @@ -24,7 +24,7 @@ public void testSerialize() { rawBytes[1] = 0x02; rawBytes[2] = 0x03; rawBytes[15] = 0x16; - GenericCompUInt element = factory.createFromBytes(rawBytes); + CompUInt128 element = factory.createFromBytes(rawBytes); assertArrayEquals(rawBytes, serializer.serialize(element)); } @@ -33,7 +33,7 @@ public void testSerializeList() { Random random = new Random(42); byte[] rawBytes = new byte[32]; random.nextBytes(rawBytes); - List elements = Arrays.asList( + List elements = Arrays.asList( factory.createFromBytes(Arrays.copyOfRange(rawBytes, 0, 16)), factory.createFromBytes(Arrays.copyOfRange(rawBytes, 16, 32)) ); @@ -46,7 +46,7 @@ public void testDeserialize() { Random random = new Random(42); byte[] bytes = new byte[16]; random.nextBytes(bytes); - GenericCompUInt uint = serializer.deserialize(bytes); + CompUInt128 uint = serializer.deserialize(bytes); assertArrayEquals(bytes, uint.toByteArray()); } @@ -55,11 +55,11 @@ public void testDeserializeList() { Random random = new Random(42); byte[] rawBytes = new byte[32]; random.nextBytes(rawBytes); - List expected = Arrays.asList( + List expected = Arrays.asList( factory.createFromBytes(Arrays.copyOfRange(rawBytes, 0, 16)), factory.createFromBytes(Arrays.copyOfRange(rawBytes, 16, 32)) ); - List actual = serializer.deserializeList(rawBytes); + List actual = serializer.deserializeList(rawBytes); assertEquals(expected.size(), actual.size()); for (int i = 0; i < actual.size(); i++) { assertArrayEquals(expected.get(i).toByteArray(), actual.get(i).toByteArray()); @@ -68,7 +68,6 @@ public void testDeserializeList() { @Test(expected = IllegalArgumentException.class) public void testDeserializeListWrongLength() { - Random random = new Random(42); byte[] rawBytes = new byte[33]; serializer.deserializeList(rawBytes); }