Skip to content

Commit 1c5b393

Browse files
committed
base KALES19 NR-OPRF implementation.
1 parent ebf4a10 commit 1c5b393

File tree

7 files changed

+226
-6
lines changed

7 files changed

+226
-6
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
A Java library for the OPRF functions I programmed during my PhD.
33

44
[![Project Status: Active](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
5-
[![Coverage](https://badgen.net/badge/coverage/95%25/green)](https://badgen.net/badge/coverage/95%25/green)
5+
[![Coverage](https://badgen.net/badge/coverage/98%25/green)](https://badgen.net/badge/coverage/98%25/green)
66

77
***
88

@@ -13,7 +13,8 @@ We use <a href="https://github.com/pvriel/oprf4j/packages/">GitHub packages</a>.
1313
***
1414

1515
## Implemented OPRF protocols
16-
Currently, only the <a href="https://www.semanticscholar.org/paper/Private-Set-Intersection-for-Unequal-Set-Sizes-with-Kiss-Liu/ef148d510ce6fd445b73584a238f6244660efbe6">KISS17 NR-OPRF</a> is implemented.
16+
Currently, only the <a href="https://www.semanticscholar.org/paper/Private-Set-Intersection-for-Unequal-Set-Sizes-with-Kiss-Liu/ef148d510ce6fd445b73584a238f6244660efbe6">KISS17 NR-OPRF</a> is implemented,
17+
as well as the <a href="https://eprint.iacr.org/2019/517">KALES19 variant</a>.
1718

1819
***
1920

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66
group 'com.github.pvriel'
7-
version '1.1.0'
7+
version '1.2.0'
88

99
repositories {
1010
mavenLocal()

src/main/java/com/github/pvriel/oprf4j/nroprf/NROPRFProvider.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public abstract class NROPRFProvider implements OPRFProvider {
2626
* @param a0
2727
* The (not-null) array of keys that are used for the active bits.
2828
* @param a1
29-
* The (not-null) array of keys that are used for the inactive bits.
29+
* The array of keys that are used for the inactive bits.
3030
* @param p
3131
* The (not-null) prime number that is used for the group (the result of applying the PRF is always part of F_{p}).
3232
* @param q
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.github.pvriel.oprf4j.nroprf.semihonest.KALES19;
2+
3+
import com.github.pvriel.mpcutils4j.array.ArrayUtils;
4+
import com.github.pvriel.mpcutils4j.stream.StreamUtils;
5+
import com.github.pvriel.oblivioustransfer4j.rrot.RandomObliviousTransferReceiver;
6+
import com.github.pvriel.oprf4j.nroprf.NROPRFEvaluator;
7+
import com.github.pvriel.oprf4j.precomputed.PrecomputedOPRFEvaluator;
8+
import org.apache.commons.lang3.tuple.Pair;
9+
10+
import java.io.IOException;
11+
import java.io.InputStream;
12+
import java.io.OutputStream;
13+
import java.math.BigInteger;
14+
15+
/**
16+
* Implementation of the {@link NROPRFEvaluator} class that uses the <a href="https://eprint.iacr.org/2019/517">KALES19 variant</a>.
17+
*/
18+
public class KALES19NROPRFEvaluator extends NROPRFEvaluator implements PrecomputedOPRFEvaluator<Pair<boolean[], BigInteger[]>> {
19+
20+
private final RandomObliviousTransferReceiver ROTReceiver;
21+
private final int bitLengthRandomValues;
22+
23+
/**
24+
* Constructor for the {@link NROPRFEvaluator} class.
25+
*
26+
* @param p The (not-null) prime number that is used for the group (the result of applying the PRF is always part of F_{p}).
27+
* @param q The (not-null) prime number, for which q | p - 1 holds. This prime number is used to apply mod operations with the exponents.
28+
* @param ROTReceiver The (not-null) {@link RandomObliviousTransferReceiver} that is used to receive the random values.
29+
* @param bitLengthRandomValues The bit length of the random values that are used to apply the PRF.
30+
*/
31+
protected KALES19NROPRFEvaluator(BigInteger p, BigInteger q, RandomObliviousTransferReceiver ROTReceiver, int bitLengthRandomValues) {
32+
super(p, q);
33+
this.ROTReceiver = ROTReceiver;
34+
this.bitLengthRandomValues = bitLengthRandomValues;
35+
}
36+
37+
@Override
38+
public Pair<boolean[], BigInteger[]> executeOfflinePhase(BigInteger[] elements, int bitLength, InputStream inputStream, OutputStream outputStream) throws IOException {
39+
return ROTReceiver.execute(elements.length * bitLength, bitLengthRandomValues, inputStream, outputStream);
40+
}
41+
42+
@Override
43+
public BigInteger[] executeOnlinePhase(Pair<boolean[], BigInteger[]> resultOfflinePhase, BigInteger[] elements, int bitLength, InputStream inputStream, OutputStream outputStream) throws IOException {
44+
boolean[] choices = resultOfflinePhase.getLeft();
45+
boolean[] b = new boolean[elements.length * bitLength];
46+
for (int i = 0; i < elements.length; i ++) {
47+
BigInteger element = elements[i];
48+
for (int j = 0; j < bitLength; j ++) b[i * bitLength + j] = (choices[i * bitLength + j] != element.testBit(j));
49+
}
50+
BigInteger bAsBigInteger = ArrayUtils.convertToBigInteger(b);
51+
StreamUtils.writeBigIntegerToOutputStream(bAsBigInteger, outputStream);
52+
outputStream.flush();
53+
54+
BigInteger[] r_i_j_c_i_j = resultOfflinePhase.getRight();
55+
BigInteger[] R = new BigInteger[elements.length * bitLength];
56+
for (int i = 0; i < elements.length; i ++) {
57+
BigInteger element = elements[i];
58+
for (int j = 0; j < bitLength; j ++) R[i * bitLength + j] = r_i_j_c_i_j[i * bitLength + j].xor((element.testBit(j) ? BigInteger.ONE : BigInteger.ZERO).multiply(StreamUtils.readBigIntegerFromInputStream(inputStream)));
59+
}
60+
61+
BigInteger[] C_i = new BigInteger[elements.length];
62+
for (int i = 0; i < elements.length; i ++) {
63+
BigInteger exponent = BigInteger.ONE;
64+
for (int j = 0; j < bitLength; j ++) exponent = exponent.multiply(R[i * bitLength + j]);
65+
C_i[i] = exponent.mod(getQ());
66+
}
67+
68+
BigInteger[] returnValue = new BigInteger[elements.length];
69+
for (int i = 0; i < returnValue.length; i ++) {
70+
BigInteger g_modded = StreamUtils.readBigIntegerFromInputStream(inputStream);
71+
returnValue[i] = g_modded.modPow(C_i[i], getP());
72+
}
73+
return returnValue;
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.github.pvriel.oprf4j.nroprf.semihonest.KALES19;
2+
3+
import com.github.pvriel.mpcutils4j.array.ArrayUtils;
4+
import com.github.pvriel.mpcutils4j.stream.StreamUtils;
5+
import com.github.pvriel.oblivioustransfer4j.srot.RandomObliviousTransferSender;
6+
import com.github.pvriel.oprf4j.nroprf.NROPRFProvider;
7+
import com.github.pvriel.oprf4j.precomputed.PrecomputedOPRFProvider;
8+
9+
import java.io.IOException;
10+
import java.io.InputStream;
11+
import java.io.OutputStream;
12+
import java.math.BigInteger;
13+
import java.util.stream.IntStream;
14+
15+
/**
16+
* Implementation of the {@link NROPRFProvider} class that uses the <a href="https://eprint.iacr.org/2019/517">KALES19 variant</a>.
17+
*/
18+
public class KALES19NROPRFProvider extends NROPRFProvider implements PrecomputedOPRFProvider<BigInteger[][]> {
19+
20+
private final RandomObliviousTransferSender ROTSender;
21+
private final int bitLengthRandomValues;
22+
23+
/**
24+
* Constructor for the {@link NROPRFProvider} class.
25+
*
26+
* @param initialKey The (not-null) key that is always used as exponent for the generator, no matter the element that is being applied for the OPRF.
27+
* @param a0 The (not-null) array of keys that are used for the active bits.
28+
* @param a1 The (not-null) array of keys that are used for the inactive bits.
29+
* However, this value is never used.
30+
* @param p The (not-null) prime number that is used for the group (the result of applying the PRF is always part of F_{p}).
31+
* @param q The (not-null) prime number, for which q | p - 1 holds. This prime number is used to apply mod operations with the exponents.
32+
* @param g The (not-null) generator of the group F_{p}.
33+
* @param ROTSender The (not-null) {@link RandomObliviousTransferSender} that is used to execute the random oblivious transfer protocol with.
34+
* @param bitLengthRandomValues The (not-null) bit length of the random values that are used in the random oblivious transfer protocol.
35+
*/
36+
protected KALES19NROPRFProvider(BigInteger initialKey, BigInteger[] a0, BigInteger[] a1, BigInteger p, BigInteger q,
37+
BigInteger g, RandomObliviousTransferSender ROTSender, int bitLengthRandomValues) {
38+
super(initialKey, a0, null, p, q, g);
39+
this.ROTSender = ROTSender;
40+
this.bitLengthRandomValues = bitLengthRandomValues;
41+
}
42+
43+
@Override
44+
public BigInteger[][] executeOfflinePhase(int amountOfValues, int bitLength, InputStream inputStream, OutputStream outputStream) throws IOException {
45+
return ROTSender.execute(amountOfValues * bitLength, bitLengthRandomValues, inputStream, outputStream);
46+
}
47+
48+
@Override
49+
public void executeOnlinePhase(BigInteger[][] resultOfflinePhase, int amountOfValues, int bitLength, InputStream inputStream, OutputStream outputStream) throws IOException {
50+
BigInteger bAsBigInteger = StreamUtils.readBigIntegerFromInputStream(inputStream);
51+
boolean[] b = ArrayUtils.convertFromBigInteger(bAsBigInteger, amountOfValues * bitLength);
52+
53+
BigInteger[] xor_product = new BigInteger[amountOfValues * bitLength];
54+
BigInteger[] r_i_j = new BigInteger[amountOfValues * bitLength];
55+
IntStream.range(0, amountOfValues).parallel().forEach(i -> {
56+
for (int j = 0; j < bitLength; j ++) {
57+
int selection = b[i * bitLength + j]? 1 : 0;
58+
BigInteger selectedRValue = resultOfflinePhase[i * bitLength + j][selection];
59+
r_i_j[i * bitLength + j] = selectedRValue;
60+
BigInteger notSelectedRValue = resultOfflinePhase[i * bitLength + j][1 - selection];
61+
xor_product[i * bitLength + j] = notSelectedRValue.xor(selectedRValue.multiply(getA0()[j]));
62+
}
63+
});
64+
for (int i = 0; i < xor_product.length; i ++) StreamUtils.writeBigIntegerToOutputStream(xor_product[i], outputStream);
65+
outputStream.flush();
66+
67+
// TODO: performance optimization.
68+
for (int i = 0; i < amountOfValues; i++) {
69+
BigInteger r_inv = BigInteger.ONE;
70+
for (int j = 0; j < bitLength; j++) r_inv = r_inv.multiply(r_i_j[i * bitLength + j]);
71+
r_inv = r_inv.modInverse(getQ());
72+
73+
BigInteger g_i = getG().modPow(getInitialKey().multiply(r_inv), getP());
74+
StreamUtils.writeBigIntegerToOutputStream(g_i, outputStream);
75+
}
76+
outputStream.flush();
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.github.pvriel.oprf4j.nroprf.semihonest.KALES19;
2+
3+
import com.github.pvriel.mpcutils4j.math.MultiplicativeGroup;
4+
import com.github.pvriel.oblivioustransfer4j.ot.semihonest.alsz13.ALSZ13ObliviousTransferReceiver;
5+
import com.github.pvriel.oblivioustransfer4j.ot.semihonest.alsz13.ALSZ13ObliviousTransferSender;
6+
import com.github.pvriel.oblivioustransfer4j.ote.semihonest.alsz13.ALSZ13ObliviousTransferExtensionReceiver;
7+
import com.github.pvriel.oblivioustransfer4j.ote.semihonest.alsz13.ALSZ13ObliviousTransferExtensionSender;
8+
import com.github.pvriel.oblivioustransfer4j.precomputed.semihonest.bea95.BEA95PrecomputedObliviousTransferReceiver;
9+
import com.github.pvriel.oblivioustransfer4j.precomputed.semihonest.bea95.BEA95PrecomputedObliviousTransferSender;
10+
import com.github.pvriel.oblivioustransfer4j.rot.semihonest.asharov17.ASHAROV17RandomObliviousTransferReceiver;
11+
import com.github.pvriel.oblivioustransfer4j.rot.semihonest.asharov17.ASHAROV17RandomObliviousTransferSender;
12+
import com.github.pvriel.oblivioustransfer4j.rrot.RandomObliviousTransferReceiver;
13+
import com.github.pvriel.oblivioustransfer4j.srot.RandomObliviousTransferSender;
14+
import com.github.pvriel.oprf4j.AbstractOPRFTest;
15+
import com.github.pvriel.oprf4j.nroprf.semihonest.KISS17.KISS17NROPRFEvaluator;
16+
import com.github.pvriel.oprf4j.nroprf.semihonest.KISS17.KISS17NROPRFProvider;
17+
import com.github.pvriel.oprf4j.oprf.OPRFEvaluator;
18+
import com.github.pvriel.oprf4j.oprf.OPRFProvider;
19+
import com.github.pvriel.prf4j.PRF;
20+
import com.github.pvriel.prf4j.naorreingold.NaorReingoldPRF;
21+
import org.apache.commons.lang3.tuple.Pair;
22+
import org.apache.commons.lang3.tuple.Triple;
23+
24+
import java.math.BigInteger;
25+
import java.util.Arrays;
26+
import java.util.Random;
27+
28+
import static com.github.pvriel.ot.semihonest.KISS17.KISS17ObliviousTransferDefaultValues.p;
29+
import static com.github.pvriel.ot.semihonest.KISS17.KISS17ObliviousTransferDefaultValues.q;
30+
31+
class KALES19NROPRFTest extends AbstractOPRFTest {
32+
33+
private final static int BIT_LENGTH_TEST_CASES = 128;
34+
private final static int AMOUNT_OF_TEST_CASES = 1000;
35+
private final static Random random = new Random();
36+
37+
@Override
38+
protected Triple<Integer, Pair<BigInteger[], BigInteger[]>, Pair<OPRFProvider, OPRFEvaluator>> setup() {
39+
BigInteger g = new MultiplicativeGroup(p.getValue()).getElementOfOrder(q.getValue());
40+
MultiplicativeGroup multiplicativeGroupQ = new MultiplicativeGroup(q.getValue());
41+
BigInteger a0[] = multiplicativeGroupQ.getRandomElements(BIT_LENGTH_TEST_CASES);
42+
BigInteger a1[] = new BigInteger[BIT_LENGTH_TEST_CASES];
43+
BigInteger initialKey = BigInteger.ONE;
44+
Arrays.fill(a1, BigInteger.ONE);
45+
System.out.println("Generating test cases...");
46+
47+
ALSZ13ObliviousTransferSender baseOTSender = new ALSZ13ObliviousTransferSender(p.getValue(), q.getValue(), g);
48+
ALSZ13ObliviousTransferReceiver baseOTReceiver = new ALSZ13ObliviousTransferReceiver(p.getValue(), q.getValue(), g);
49+
ALSZ13ObliviousTransferExtensionSender OTeSender = new ALSZ13ObliviousTransferExtensionSender(10, baseOTReceiver);
50+
ALSZ13ObliviousTransferExtensionReceiver OTeReceiver = new ALSZ13ObliviousTransferExtensionReceiver(10, baseOTSender);
51+
ASHAROV17RandomObliviousTransferSender ROTSender = new ASHAROV17RandomObliviousTransferSender(10, OTeReceiver);
52+
ASHAROV17RandomObliviousTransferReceiver ROTReceiver = new ASHAROV17RandomObliviousTransferReceiver(10, OTeSender);
53+
KALES19NROPRFProvider provider = new KALES19NROPRFProvider(initialKey, a0, null, p.getValue(), q.getValue(), g, ROTSender, q.getValue().bitLength());
54+
KALES19NROPRFEvaluator evaluator = new KALES19NROPRFEvaluator(p.getValue(), q.getValue(), ROTReceiver, q.getValue().bitLength());
55+
56+
BigInteger inputs[] = new BigInteger[AMOUNT_OF_TEST_CASES];
57+
PRF prf = new NaorReingoldPRF(initialKey, a0, a1, p.getValue(), q.getValue(), g);
58+
for (int i = 0; i < AMOUNT_OF_TEST_CASES; i++) {
59+
// if (i % (Math.max(1, AMOUNT_OF_TEST_CASES / 10)) == 1) System.out.println("Generating test case " + i + " of " + AMOUNT_OF_TEST_CASES);
60+
inputs[i] = new BigInteger(BIT_LENGTH_TEST_CASES, random);
61+
}
62+
BigInteger expectedOutputs[] = prf.compute(inputs);
63+
64+
return Triple.of(BIT_LENGTH_TEST_CASES, Pair.of(inputs, expectedOutputs), Pair.of(provider, evaluator));
65+
}
66+
}

src/test/java/com/github/pvriel/oprf4j/nroprf/semihonest/KISS17/KISS17NROPRFTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ protected Triple<Integer, Pair<BigInteger[], BigInteger[]>, Pair<OPRFProvider, O
4141
ALSZ13ObliviousTransferExtensionReceiver OTeReceiver = new ALSZ13ObliviousTransferExtensionReceiver(10, baseOTSender);
4242
BEA95PrecomputedObliviousTransferReceiver precomputedObliviousTransferReceiver = new BEA95PrecomputedObliviousTransferReceiver(OTeReceiver);
4343
BEA95PrecomputedObliviousTransferSender precomputedObliviousTransferSender = new BEA95PrecomputedObliviousTransferSender(OTeSender);
44-
KISS17NROPRFProvider provider = new KISS17NROPRFProvider(BIT_LENGTH_TEST_CASES, precomputedObliviousTransferSender, a0, a1, p.getValue(), q.getValue(), g);
45-
KISS17NROPRFEvaluator evaluator = new KISS17NROPRFEvaluator(BIT_LENGTH_TEST_CASES, precomputedObliviousTransferReceiver, p.getValue(), q.getValue());
44+
KISS17NROPRFProvider provider = new KISS17NROPRFProvider(q.getValue().bitLength(), precomputedObliviousTransferSender, a0, a1, p.getValue(), q.getValue(), g);
45+
KISS17NROPRFEvaluator evaluator = new KISS17NROPRFEvaluator(q.getValue().bitLength(), precomputedObliviousTransferReceiver, p.getValue(), q.getValue());
4646

4747
BigInteger inputs[] = new BigInteger[AMOUNT_OF_TEST_CASES];
4848
PRF prf = new NaorReingoldPRF(BigInteger.ONE, a1, a0, p.getValue(), q.getValue(), g);

0 commit comments

Comments
 (0)