@Override public void send(int partyId, byte[] data) { this.delegate.send(partyId, data); }
/** * Flushes the internal buffers and sends the (remaining) pieces over the wire. */ public void flush() { for (int i = 1; i <= noOfParties; i++) { if (output.containsKey(i)) { ByteArrayOutputStream byteArrayOutputStream = output.get(i); byte[] data = byteArrayOutputStream.toByteArray(); network.send(i, data); } output.remove(i); } input.clear(); } }
/** * Queues up a value to be send to all parties (yourself included). * * @param data The value to send to all parties */ default void sendToAll(byte[] data) { for (int i = 1; i <= getNoOfParties(); i++) { send(i, data); } }
/** * Sends a list of StrictBitVectors to the default (0) channel. * * @param list * List to send, where all elements are required to have the same * length. */ private void sendList(List<StrictBitVector> list) { // Find the amount of bytes needed for each bitvector in the list int elementLength = list.get(0).getSize() / 8; // Allocate space for all elements in the list. byte[] toSend = new byte[(list.get(0).getSize() / 8) * list.size()]; for (int i = 0; i < list.size(); i++) { System.arraycopy(list.get(i).toByteArray(), 0, toSend, i * elementLength, elementLength); } network.send(resources.getOtherId(), toSend); } }
/** * Completes the sender's part of the Naor-Pinkas OT in order to send two random messages of the * length of hash digest. * * @return The two random messages sent by the sender. */ private Pair<byte[], byte[]> sendRandomOt() { BigInteger c = randNum.nextBigInteger(dhModulus); network.send(otherId, c.toByteArray()); BigInteger publicKeyZero = new BigInteger(network.receive(otherId)); BigInteger publicKeyOne = publicKeyZero.modInverse(dhModulus).multiply(c); Pair<BigInteger, byte[]> zeroChoiceData = encryptRandomMessage(publicKeyZero); Pair<BigInteger, byte[]> oneChoiceData = encryptRandomMessage(publicKeyOne); network.send(otherId, zeroChoiceData.getFirst().toByteArray()); network.send(otherId, oneChoiceData.getFirst().toByteArray()); return new Pair<>(zeroChoiceData.getSecond(), oneChoiceData.getSecond()); }
/** * Compute and send a bit indicating whether the sender should switch the zero * and one message around. * * @param choiceBit * The actual choice bit of the receiver */ private void sendSwitchBit(boolean choiceBit) { // Since we can only send a byte array we use 0x00 to indicate a 0-choice // and 0x01 to indicate a 1-choice byte[] switchBit = new byte[] { 0x00 }; // Set the choice to 0x01 if the sender should switch the 0 and 1 messages if (choiceBit ^ choices.getBit(offset, false) == true) { switchBit[0] = 0x01; } network.send(resources.getOtherId(), switchBit); } }
/** * Computes shares of products of this party's input elements and other party's mac key share. * * @param inputElements input field elements * @return shares of products of mac key share and input elements */ public List<FieldElement> extend(List<FieldElement> inputElements) { // use seeds to generate mask pairs List<Pair<FieldElement, FieldElement>> maskPairs = generateMaskPairs(inputElements.size()); // compute t0 - t1 + x for each input x for each mask pair List<FieldElement> diffs = helper.computeDiffs(maskPairs, inputElements); // send diffs network.send(otherId, resourcePool.getFieldDefinition().serialize(diffs)); // get zero index masks List<FieldElement> feZeroSeeds = maskPairs.parallelStream().map(Pair::getFirst).collect(Collectors.toList()); // compute product shares return helper.computeProductShares(feZeroSeeds, inputElements.size()); }
/** * Computes additive (unauthenticated) shares of values and distributes the shares across * parties. */ private List<FieldElement> secretShare(List<FieldElement> values, int numShares) { List<List<FieldElement>> allShares = values.stream().map(value -> sharer.share(value, numShares)).collect(Collectors.toList()); List<List<FieldElement>> byParty = TransposeUtils.transpose(allShares); for (int partyId = 1; partyId <= resourcePool.getNoOfParties(); partyId++) { // send shares to everyone but self if (partyId != resourcePool.getMyId()) { List<FieldElement> shares = byParty.get(partyId - 1); network.send(partyId, resourcePool.getFieldDefinition().serialize(shares)); } } // return own shares return byParty.get(resourcePool.getMyId() - 1); }
/** * Completes the receiver's part of the Naor-Pinkas OT in order to receive a random message of the * length of hash digest. * * @return The random message received */ private byte[] receiveRandomOt(boolean choiceBit) { BigInteger c = new BigInteger(network.receive(otherId)); BigInteger privateKey = randNum.nextBigInteger(dhModulus); BigInteger publicKeySigma = dhGenerator.modPow(privateKey, dhModulus); BigInteger publicKeyNotSigma = publicKeySigma.modInverse(dhModulus).multiply(c); if (choiceBit == false) { network.send(otherId, publicKeySigma.toByteArray()); } else { network.send(otherId, publicKeyNotSigma.toByteArray()); } BigInteger encZero = new BigInteger(network.receive(otherId)); BigInteger encOne = new BigInteger(network.receive(otherId)); byte[] message; if (choiceBit == false) { message = decryptRandomMessage(encZero, privateKey); } else { message = decryptRandomMessage(encOne, privateKey); } return message; }
@Override public void send(StrictBitVector messageZero, StrictBitVector messageOne) { int maxBitLength = Math.max(messageZero.getSize(), messageOne.getSize()); Pair<byte[], byte[]> seedMessages = sendRandomOt(); byte[] encryptedZeroMessage = PseudoOtp.encrypt(messageZero.toByteArray(), seedMessages.getFirst(), maxBitLength / Byte.SIZE); byte[] encryptedOneMessage = PseudoOtp.encrypt(messageOne.toByteArray(), seedMessages.getSecond(), maxBitLength / Byte.SIZE); network.send(otherId, encryptedZeroMessage); network.send(otherId, encryptedOneMessage); }
/** * Runs a batch of the entry wise product protocol with a given of right hand vector. * * <p> * For right vector <i><b>b</b>= b<sub>0</sub>, b<sub>1</sub>, ...)</i> and left vector of the * other party <i><b>a</b> = (a<sub>0</sub>, a<sub>1</sub>, ...)</i>, the protocol computes secret * shares of entry wise product <i>(a<sub>0</sub>b<sub>0</sub>, a<sub>1</sub>b<sub>1</sub>, ... * </i>). * </p> * * @param rightFactors this party's vector <i>b<sub>0</sub>, b<sub>1</sub> ...</i> * @return shares of the products <i>a<sub>0</sub>b<sub>0</sub>, a<sub>1</sub>b<sub>1</sub> ... * </i> */ public List<FieldElement> multiply(List<FieldElement> rightFactors) { List<Pair<StrictBitVector, StrictBitVector>> seedPairs = multiplyRightHelper.generateSeeds(rightFactors.size(), resourcePool.getModBitLength()); // convert seeds pairs to field elements so we can compute on them List<Pair<FieldElement, FieldElement>> feSeedPairs = seedsToFieldElements(seedPairs); // compute q0 - q1 + b for each seed pair List<FieldElement> diffs = multiplyRightHelper.computeDiffs(feSeedPairs, rightFactors); // send diffs over to other party network.send(otherId, resourcePool.getFieldDefinition().serialize(diffs)); // get zero index seeds List<FieldElement> feZeroSeeds = feSeedPairs.parallelStream().map(Pair::getFirst).collect(Collectors.toList()); // compute product shares return multiplyRightHelper.computeProductShares(feZeroSeeds, rightFactors.size()); }
/** * Exchange the seed with the other party using a commitment protocol. * * @param seed * The current party's seed * @param network * The network instance * @return The other party's seed */ private byte[] exchangeSeeds(byte[] seed, Network network) { // Let the party with the smallest id be the party receiving a commitment if (myId < otherId) { byte[] serializedComm = network.receive(otherId); HashBasedCommitment comm = serializer.deserialize(serializedComm); network.send(otherId, seed.clone()); byte[] opening = network.receive(otherId); return comm.open(opening); } else { HashBasedCommitment comm = new HashBasedCommitment(); byte[] openInfo = comm.commit(rand, seed); network.send(otherId, serializer.serialize(comm)); byte[] otherSeed = network.receive(otherId); network.send(otherId, openInfo); return otherSeed; } } }
/** * Adjust the random, preprocessed message, to fit the specific messages to send. * * @param messageZero The actual zero message to send * @param messageOne The actual one message to send */ private void doActualSend(byte[] messageZero, byte[] messageOne) { // Find the correct preprocessed random OT messages StrictBitVector randomZero = randomMessages.getFirst().get(offset); StrictBitVector randomOne = randomMessages.getSecond().get(offset); int maxLength = Math.max(messageZero.length, messageOne.length); // Receive a bit from the receiver indicating whether the zero and one // messages should be switched around byte[] switchBit = network.receive(resources.getOtherId()); // If false (indicated by byte 0x00), then don't switch around if (switchBit[0] == 0x00) { network.send(resources.getOtherId(), PseudoOtp.encrypt(messageZero, randomZero.toByteArray(), maxLength)); network.send(resources.getOtherId(), PseudoOtp.encrypt(messageOne, randomOne.toByteArray(), maxLength)); } else { network.send(resources.getOtherId(), PseudoOtp.encrypt(messageOne, randomZero.toByteArray(), maxLength)); network.send(resources.getOtherId(), PseudoOtp.encrypt(messageZero, randomOne.toByteArray(), maxLength)); } } }
@Override public List<StrictBitVector> extend(StrictBitVector choices) { // The underlying scheme requires computational security parameter plus lambda security // parameter extra OTs int minOts = choices.getSize() + resources.getComputationalSecurityParameter() + resources .getLambdaSecurityParam(); // Round up to nearest two-power, which is required by the underlying scheme int ellPrime = (int) Math.pow(2, Math.ceil(Math.log(minOts) / Math.log(2))); // Extend the choices with random choices for padding StrictBitVector paddingChoices = new StrictBitVector(ellPrime - choices.getSize(), resources .getRandomGenerator()); StrictBitVector extendedChoices = StrictBitVector.concat(choices, paddingChoices); // Use the choices along with the random padding uses for correlated OT with // errors List<StrictBitVector> tlist = receiver.extend(extendedChoices); // Agree on challenges for linear combination test List<StrictBitVector> chiList = getChallenges(ellPrime); StrictBitVector xvec = computeBitLinearCombination(extendedChoices, chiList); network.send(resources.getOtherId(), xvec.toByteArray()); StrictBitVector tvec = computeInnerProduct(chiList, tlist); network.send(resources.getOtherId(), tvec.toByteArray()); // Remove the correlation of the OTs by hashing List<StrictBitVector> vvec = hashBitVector(tlist, choices.getSize()); return vvec; }