Hello all,
As you are discussing implementing the algorithm from ICITS07, I have
improved on that to get a very effective algorithm. For p = 2^l - 1 and
using psaudorandom secret sharing. The comparison can be done in 5
rounds and 5l multiplications. The algorithm has never been published,
but attached is a java implementation of the algorithm. (There might be
an error in the faun in algorithm as that is not tested).
Unfortunately I do not have a phyton implementation of it, as I am bad
at programming in phyton, on the other hand I am working on a java
implementation of MPC, which should be ready in a month. If anyone else
want to try to implement it in phyton I will be more than happy to help.
To understand the code please start with the function
public Share comparisonRestricted(Share a, Share b)
and please observe that many small functions on the top are just
returning values instead of shares, this is for test purposes.
Tord
Martin Geisler wrote:
[EMAIL PROTECTED] writes:
I talked with Rune Thorbek yesterday, and he asked why we have not
implemented your comparison protocol from your PhD thesis:
http://www.daimi.au.dk/~tomas/publications/dissertation.pdf
Is there any good reason why we haven't done that? Is the constants
much worse than the ones implemented?
Short answer: Yes.
Longer Answer: You need to do lots of tricks to go to
constant-rounds. The logarithmic solutions do not give (much) worse
round complexity, but require notably fewer multiplications.
Okay.
The best one published that I know of is Tord's and mine from
ICITS07. This is reasonable to implement (complexity-wise), but
trust me, you don't want to :-)
Hmm... Rune says that I should consider this a challange... :-)
I wont really have time before I return from Switzerland in September
(I leave in a week), but can I find the article online? I found the
conference webpage, but it does not link to your article, and neither
does your own publication list.
/*
* Testclass.java
*
* Created on 11. juni 2007, 01:30
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package multiparty;
/**
*
* @author item
*/
import java.math.BigInteger;
import java.util.Stack;
import multiparty.Field;
//import org.lsmp.djep.groupJep.groups.Zn;
public class Testclass {
// private class Share extends multiparty.Field {
// public Share(long l) {super(l);}
// public Share(BigInteger v) {super(v);}
// }
/** Creates a new instance of Testclass */
public Testclass() {
}
static BigInteger BIG2 = BigInteger.valueOf(2);
static java.util.Random random = new java.util.Random();
public Share generateRandom() {
return new Share(Field.random());
}
public Share generateBit() {
// Not propper way to do it.
if (random == null)
random = new java.util.Random();
boolean r = random.nextBoolean();
if (true == r)
return new Share(BigInteger.ONE);
else
return new Share(BigInteger.ZERO);
}
public Field[] splitP() {
// Splits the fieldsize p into bits
// to reconstruct the value compute bits[i]*2^i
return splitNum(Field.getBaseField());
}
public Field[] splitNum(BigInteger a) {
Field [] bits = new Field[Field.getBaseField().bitLength()];
for (int i=0; i<bits.length; i++) {
if (a.testBit(i))
bits[i] = new Field(BigInteger.ONE);
else
bits[i] = new Field(BigInteger.ZERO);
}
return bits;
// To print with biggest to the left use
// for (int i=a.length-1; i>-1; i--)
}
public int initialBitsSetInP() {
BigInteger a = Field.getBaseField();
int numBits = 0;
for (int i=a.bitLength()-1; i>-1; i--) {
if (a.testBit(i)) {
numBits = numBits + 1;
} else
break;
}
return numBits;
}
public BigInteger convertFromBitsToValueB(Share[] a) {
BigInteger temp = BigInteger.ZERO;
BigInteger exp;
for (int i=0; i<a.length; i++) {
exp = BIG2.pow(i);
BigInteger temp2 = a[i].getvalue();
temp = temp.add(temp2.multiply(exp));
}
return temp;
}
public Share convertFromBitsToValueS(Share[] a) {
return new Share(convertFromBitsToValueB(a));
}
public Share[] Faunin(Share[] a, boolean reverse) {
if (true == reverse) {
Share [] b = new Share[a.length];
for (int i=0; i<a.length; i++)
b[a.length-1-i] = a[i];
Share [] c = Faunin(b);
for (int i=0; i<a.length; i++)
b[a.length-1-i] = c[i];
return b;
}
else
return Faunin(a);
}
public Share[] Faunin(Share[] a) {
// Computes a faun-in multiplication of the shares given in the array a
// Setting u_(-1) = 1 to save multiplications
// Revaling [u_(i-1)][a][r_i]/[u_i][r_i] = [u_(i-1)][a][u_i^(-1)]
// Final multiplication is with [u_i]
//Set reverse if the a
Share [] u = new Share[a.length];
Share [] r = new Share[a.length];
Share [] temp1 = new Share[a.length];
Field [] temp2 = new Share[a.length];
Field [] revealed = new Field[a.length];
for (int i=0; i<a.length; i++) {
u[i] = generateRandom();
r[i] = generateRandom();
}
temp1[0] = r[0];
for (int i=0; i<a.length; i++) {
if (i != 0)
temp1[i] = r[i].mpcmult(u[i-1]); // u_(i-1) r
temp2[i] = r[i].mpcmult(u[i]).reveal().inverse(); // (u_i r)^(-1)
}
for (int i=0; i<a.length; i++) {
revealed[i] = temp1[i].mpcmult(a[i]).reveal(); // u_(i-1) r a
revealed[i] = revealed[i].multf(temp2[i]); // u_(i-1) a u_i^(-1)
}
for (int i=1; i<a.length; i++) {
revealed[i] = revealed[i].multf(revealed[i-1]);
}
//The following step can be modified if not all the values are needed
for (int i=0; i<a.length; i++) {
r[i] = u[i].mpcmult(revealed[i].getvalue());
}
return r;
}
public Share[] generateRandomBitwiseSharedValue() {
Field[] Psplit = splitP();
Share[] Rand = new Share[Psplit.length];
boolean Finished = false;
while (!Finished) {
Finished = true;
for (int i=0; i<Psplit.length; i++) {
Rand[i] = generateBit();
}
// If the two highest order bits of P are 1 and 0, then the failure
// rate can be as high as 50%, this is reduced by 25% by checking
// that the two highest order bits multipled together do not produce
// a 1.
if (1 == initialBitsSetInP()) {
Share tempIni =
Rand[Rand.length-1].mpcmult(Rand[Rand.length-2]);
Field tempIni2 = tempIni.reveal();
//System.out.println("Rand[max-1]="+Rand[Rand.length-1]+ "
Rand[max-2]="+Rand[Rand.length-2]+" tempIni2="+tempIni2);
while (tempIni2.compareToONE()) {
Rand[Rand.length-1] = generateBit();
Rand[Rand.length-2] = generateBit();
tempIni = Rand[Rand.length-1].mpcmult(Rand[Rand.length-2]);
tempIni2 = tempIni.reveal();
//System.out.println("Rand[max-1]="+Rand[Rand.length-1]+ "
Rand[max-2]="+Rand[Rand.length-2]+ " tempIni2="+tempIni2);
}
}
//BigInteger tt = BigInteger.ZERO;
BigInteger tt = convertFromBitsToValueB(Rand);
//System.out.print("Random in bi ");
//for (int i=Psplit.length-1; i>-1; i--) {
// System.out.print(Rand[i]);
//}
//System.out.println("");
//for (int i=Psplit.length-1; i>-1; i--) {
// BigInteger tt2 = BIG2.pow(i);
// tt2 = tt2.multiply(Rand[i].getvalue());
// tt = tt.add(tt2);
//System.out.println("TT2 is " +tt2+" TT is "+tt);
//}
//System.out.println("TT is " + tt);
// Testing if Rand > P, there is no need to test for any bit where
// p_i = 1. p_i xor r_i is either r_i if p_i=0 or 1-r_i if p_i=1.
// There is a separate test for the last bit.
// Testing if (1-r_i+p_i) + \sum (r_j xor p_j)
// For last bit testing (p_0-r_0) + \sum (r_j xor p_j)
for (int i=Psplit.length-1; i>-1; i--) {
// Only check if p_i=0 or if last bit
if (Psplit[i].compareToZERO() || (0 == i)) {
Share temp = new Share(BigInteger.ONE);
temp = temp.mpcsub(Rand[i]);
//System.out.println("Start " + i + " with " + temp);
for (int j=Psplit.length-1; j>i; j--) {
// If p_i=0 add r_i to temp, if p_i=1 add 1-r_i to temp
if (Psplit[j].compareToZERO()) {
temp = temp.mpcadd(Rand[j]);
//System.out.println(j+" Add 0+"+Rand[j]+" gir
"+temp);
} else {
temp = temp.mpcadd(BigInteger.ONE);
temp = temp.mpcsub(Rand[j]);
//System.out.println(j+" Add 1-"+Rand[j]+" gir
"+temp);
}
}
//System.out.println("Test " + i + " gir " + temp);
//Multiply by a random value and reveal
Share random_mult = generateRandom();
while (random_mult.compareToZERO()) {
//Cheat to remove finding zeros for small values
//System.out.println("Zero as random number");
random_mult = generateRandom();
}
temp = temp.mpcmult(random_mult);
Field temp2 = temp.reveal();
if (temp2.compareToZERO()) {
Finished = false;
//if (! random_mult.compareToZERO())
//if (-1 == tt.compareTo(temp2.getBaseField())) {
// System.out.println("Error1 when tt is "+tt);
//}
//System.out.println("Restart at bit "+i);
Finished = true;
break; //Breaks the for loop
}
} // compareToZERO
} //for
} //while (!Finished)
BigInteger tt = convertFromBitsToValueB(Rand);
//if (-1 != tt.compareTo(Rand[0].getBaseField()))
// System.out.println("Error2 when tt is "+tt);
//else
//System.out.println("Ok when tt is "+tt);
return Rand;
}
public Share comparisonRestricted(Share a, Share b) {
//Comparing a > b, where a,b are shares and a,b < p/2
//Starting restating the comparison to p/2 > b-a > 0
//If this is true then 2(b-a)_0 is 0, otherwise 2(b-a)_0 is 1
//The least significant bit of 2(b-a), 2(b-a)_0 is equal to
//2(b-a)_0 = c_0 xor r_0 xor (r > c)
//Where c is revealed, r is bitwise secret shared value and
// c = 2(b-a) + r
Share temp = new Share(2L);
temp = temp.mpcmult(b.mpcsub(a));
Share[] Random = generateRandomBitwiseSharedValue();
Share tempRandom = convertFromBitsToValueS(Random);
temp = temp.mpcadd(tempRandom);
Field c = temp.reveal();
Field[] c_ar = splitNum(c.getvalue());
Share comp = CompareBitwiseRandomKnown(Random,c_ar);
int c0 = c.mod(BIG2).intValue();
Share r0comp = Random[0].mpcmult(comp);
// Return c0 xor Random[0] xor comp
if (0 == c0)
return comp.mpcxor(Random[0]);
else {
Share temp3 = new Share(BigInteger.ONE);
return temp3.mpcxor(comp.mpcxor(Random[0]));
} }
public Share CompareBitwiseRandomKnown(Share[] rand, Field[] c_ar) {
//First generate the value x from the shared values such that
// x = \sum r_i(1-c_i) \prod r_i xor c_i on two bits at a time
// x < 2^(l/2+1)
// Find the last bit of x by setting x' = x + r
// Then reveal x' and either use the last bit of x' or x' - 2^(l-1)
// As one of these values corresponds to a value of r with the first
bit not set.
Share x = CompareBitwiseRandomKnownReturnValueX (rand, c_ar);
Share[] Random = generateRandomBitwiseSharedValue();
Share temp = convertFromBitsToValueS(Random);
temp = x.mpcadd(temp);
Field c = temp.reveal();
Field [] cartemp = splitNum(c.getvalue());
Field c0Low = cartemp[0];
int highestbit = Field.getBaseField().bitLength();
BigInteger SetHighbit = BigInteger.ZERO;
SetHighbit.flipBit(highestbit);
Field highBitSet = new Field(SetHighbit);
c = c.subtractf(highBitSet);
cartemp = splitNum(c.getvalue());
Field c0High = cartemp[0];
temp = rand[highestbit-1].mpcmult(BigInteger.valueOf(-1)); // -r_h
temp = temp.mpcadd(BigInteger.ONE); // 1 - r_h
temp = temp.mpcmult(c0Low); // (1-r_h)c0Low
Share RetVal = rand[highestbit-1].mpcmult(c0High); // r_h c0High
RetVal = RetVal.mpcadd(temp); // r_h c0High + (1-r_h) c0Low
return RetVal;
}
public Share CompareBitwiseRandomKnownReturnValueX (Share[] rand, Field[]
c_ar) {
//Generating a new share where r > c is given by the last bit
//As the number x is even if c <= r otherwise x is odd.
//If rand and c_ar are l bit long then x < 2^(l/2 + log(l))
// x = \sum r_i(1-c_i) \prod r_i xor c_i on two bits at a time
if (rand.length != Field.getBaseField().bitLength())
System.out.println("Wrong size of the random");
if (c_ar.length != Field.getBaseField().bitLength())
System.out.println("Wrong size of c");
//Comparing 2 and 2 bits, special test for bit if it is alone
int halvedLen = rand.length/2; //rounded down
int oddNum = rand.length%2;
Share[] xor = new Share[halvedLen+oddNum];
Share[] rnotc = new Share[halvedLen+oddNum];
Field two = new Field(2L);
Field one = new Field(1L);
if (1 == oddNum) {
Field tempF = c_ar[0].multf(two); // 2c_0
Share tempS = rand[0].mpcmult(tempF); // 2r_0 c_0
xor[0] = rand[0].mpcadd(c_ar[0]).mpcadd(tempS); // r_0 + c_0 - 2
r_0 c_0
tempF = c_ar[0].inverse(); // -c_0
tempF = tempF.addf(one); // 1 - c_0
rnotc[0] = rand[0].mpcmult(tempF); // (1 - c_0)r_0
}
for (int i=0; i<halvedLen; i++) {
long c_double = c_ar[2*i+oddNum].getvalue().longValue() +
2* c_ar[2*i+oddNum+1].getvalue().longValue();
Share high = rand[2*i+oddNum+1];
Share low = rand[2*i+oddNum];
Share randN = high.mpcmult(low); //r_i r_(i+1)
Share notrandN = randN.mpcmult(BigInteger.valueOf(-1)); //-r_i
r_(i+1)
switch ((int)c_double) {
//This switch statment will look at two bits at a time:
//Returns a share xor which is 0 if r = c for the two bits
//otherwise returns xor with the value 1
//Returns a share rnotc which is 1 if r>c for the two bits
//otherwise returns rnotc with the value 0
case 0:
xor[i+oddNum] = notrandN.mpcadd(low).mpcadd(high); // low +
high - randN
rnotc[i+oddNum] = xor[i+oddNum];
break;
case 1:
xor[i+oddNum] = randN.mpcsub(low).mpcadd(one); // 1 - low +
randN
rnotc[i+oddNum] = high; // high
break;
case 2:
xor[i+oddNum] = randN.mpcsub(high).mpcadd(one); // 1 - high
+ randN
rnotc[i+oddNum] = randN; //randN
break;
case 3:
xor[i+oddNum] = notrandN.mpcadd(one); // 1 - randN
rnotc[i+oddNum] = new Share(0L);
break;
default: //Should never be reached
System.out.println("Case statement reaches wrong end");
break;
}
// Turning the xor values from the set {0,1} to the set {1,2}
xor[i+oddNum] = xor[i+oddNum].mpcadd(one);
} //xor and rnotc are now set
xor = Faunin (xor, true); //reversed Faun-in on xor
Share Returnval = new Share(0L);
for (int i=0; i<halvedLen+oddNum; i++) {
Share temp = xor[i].mpcmult(rnotc[i]);
Returnval = Returnval.mpcadd(temp);
}
return Returnval;
}
public void runtest() {
runtest3();
}
public void runtest2() {
// A test of generateing random bitwise shared numbers
int field_size = 31;
BigInteger field2 = BigInteger.valueOf((long)field_size);
//BigInteger field2 = BigInteger.valueOf(8191L);
Field.setBaseField(field2);
//System.out.println("Number of bits in P is " +
Field.getBaseField().bitLength());
//System.out.println("Number of bits set is " + initialBitsSetInP());
System.out.println("P is " + Field.getBaseField());
Field[] Psplit = splitP();
System.out.print("P is in bits ");
for (int i=Psplit.length-1; i>-1; i--) {
if (Psplit[i].compareToONE())
System.out.print("1");
else
System.out.print("0");
}
System.out.println("");
int[] eq_cont = new int[field_size+1];
for (int i=0; i<eq_cont.length; i++)
eq_cont[i] = 0;
Share[] Rand;
Field.writeWithPlussMinus = false;
for (int j=0; j<10000; j++) {
Rand = generateRandomBitwiseSharedValue();
BigInteger test = convertFromBitsToValueB(Rand);
int val = test.intValue();
eq_cont[val]++;
//System.out.println("i "+i);
}
for (int i=0; i<eq_cont.length; i++) {
System.out.println("Val "+i+ " happens "+eq_cont[i]+" times.");
}
}
public void runtest3() {
}
}
_______________________________________________
viff-devel mailing list (http://viff.dk/)
[email protected]
http://lists.viff.dk/listinfo.cgi/viff-devel-viff.dk