Browse Source

Added modified ObliVMGC code where GC Evaluator's GTT receiving and evaluation are separated

Boyoung- 8 years ago
parent
commit
73a0b7da3e
92 changed files with 8160 additions and 1 deletions
  1. 3 0
      .classpath
  2. 175 0
      ObliVMGC/com/oblivm/backend/circuits/BitonicSortLib.java
  3. 291 0
      ObliVMGC/com/oblivm/backend/circuits/CircuitLib.java
  4. 37 0
      ObliVMGC/com/oblivm/backend/circuits/arithmetic/ArithmeticLib.java
  5. 207 0
      ObliVMGC/com/oblivm/backend/circuits/arithmetic/DenseMatrixLib.java
  6. 112 0
      ObliVMGC/com/oblivm/backend/circuits/arithmetic/FixedPointLib.java
  7. 235 0
      ObliVMGC/com/oblivm/backend/circuits/arithmetic/FloatLib.java
  8. 525 0
      ObliVMGC/com/oblivm/backend/circuits/arithmetic/IntegerLib.java
  9. 63 0
      ObliVMGC/com/oblivm/backend/circuits/arithmetic/VectorLib.java
  10. 97 0
      ObliVMGC/com/oblivm/backend/example/HammingDistance.java
  11. 62 0
      ObliVMGC/com/oblivm/backend/example/Millionaire.java
  12. 63 0
      ObliVMGC/com/oblivm/backend/example/Sort.java
  13. 44 0
      ObliVMGC/com/oblivm/backend/flexsc/BooleanCompEnv.java
  14. 98 0
      ObliVMGC/com/oblivm/backend/flexsc/CVCompEnv.java
  15. 147 0
      ObliVMGC/com/oblivm/backend/flexsc/CompEnv.java
  16. 5 0
      ObliVMGC/com/oblivm/backend/flexsc/Comparator.java
  17. 17 0
      ObliVMGC/com/oblivm/backend/flexsc/Flag.java
  18. 19 0
      ObliVMGC/com/oblivm/backend/flexsc/IWritable.java
  19. 32 0
      ObliVMGC/com/oblivm/backend/flexsc/Mode.java
  20. 142 0
      ObliVMGC/com/oblivm/backend/flexsc/PMCompEnv.java
  21. 8 0
      ObliVMGC/com/oblivm/backend/flexsc/Party.java
  22. 11 0
      ObliVMGC/com/oblivm/backend/gc/BadLabelException.java
  23. 39 0
      ObliVMGC/com/oblivm/backend/gc/DbgUtils.java
  24. 36 0
      ObliVMGC/com/oblivm/backend/gc/GCCompEnv.java
  25. 139 0
      ObliVMGC/com/oblivm/backend/gc/GCEvaComp.java
  26. 191 0
      ObliVMGC/com/oblivm/backend/gc/GCGenComp.java
  27. 115 0
      ObliVMGC/com/oblivm/backend/gc/GCSignal.java
  28. 58 0
      ObliVMGC/com/oblivm/backend/gc/halfANDs/GCEva.java
  29. 82 0
      ObliVMGC/com/oblivm/backend/gc/halfANDs/GCGen.java
  30. 27 0
      ObliVMGC/com/oblivm/backend/gc/halfANDs/Garbler.java
  31. 25 0
      ObliVMGC/com/oblivm/backend/gc/halfANDs/TestGarbler.java
  32. 46 0
      ObliVMGC/com/oblivm/backend/gc/offline/FileReader.java
  33. 61 0
      ObliVMGC/com/oblivm/backend/gc/offline/GCEva.java
  34. 131 0
      ObliVMGC/com/oblivm/backend/gc/offline/GCGen.java
  35. 36 0
      ObliVMGC/com/oblivm/backend/gc/offline/Garbler.java
  36. 34 0
      ObliVMGC/com/oblivm/backend/gc/offline/TestGarbler.java
  37. 88 0
      ObliVMGC/com/oblivm/backend/gc/regular/GCEva.java
  38. 99 0
      ObliVMGC/com/oblivm/backend/gc/regular/GCGen.java
  39. 37 0
      ObliVMGC/com/oblivm/backend/gc/regular/Garbler.java
  40. 28 0
      ObliVMGC/com/oblivm/backend/gc/regular/TestGarbler.java
  41. 35 0
      ObliVMGC/com/oblivm/backend/lang/inter/BoxedInt.java
  42. 56 0
      ObliVMGC/com/oblivm/backend/lang/inter/Cmd.java
  43. 8 0
      ObliVMGC/com/oblivm/backend/lang/inter/ISecureRunnable.java
  44. 14 0
      ObliVMGC/com/oblivm/backend/lang/inter/Input.java
  45. 138 0
      ObliVMGC/com/oblivm/backend/lang/inter/MainRunnable.java
  46. 65 0
      ObliVMGC/com/oblivm/backend/lang/inter/NullableType.java
  47. 36 0
      ObliVMGC/com/oblivm/backend/lang/inter/Util.java
  48. 72 0
      ObliVMGC/com/oblivm/backend/lang/inter/input/BitFileInput.java
  49. 53 0
      ObliVMGC/com/oblivm/backend/network/Client.java
  50. 47 0
      ObliVMGC/com/oblivm/backend/network/CustomizedConcurrentQueue.java
  51. 55 0
      ObliVMGC/com/oblivm/backend/network/CustomizedConcurrentQueue2.java
  52. 249 0
      ObliVMGC/com/oblivm/backend/network/Network.java
  53. 23 0
      ObliVMGC/com/oblivm/backend/network/Server.java
  54. 34 0
      ObliVMGC/com/oblivm/backend/network/ThreadedIO.java
  55. 27 0
      ObliVMGC/com/oblivm/backend/oram/Block.java
  56. 184 0
      ObliVMGC/com/oblivm/backend/oram/BucketLib.java
  57. 162 0
      ObliVMGC/com/oblivm/backend/oram/CircuitOram.java
  58. 199 0
      ObliVMGC/com/oblivm/backend/oram/CircuitOramLib.java
  59. 71 0
      ObliVMGC/com/oblivm/backend/oram/LinearScanOram.java
  60. 192 0
      ObliVMGC/com/oblivm/backend/oram/OramParty.java
  61. 37 0
      ObliVMGC/com/oblivm/backend/oram/PlainBlock.java
  62. 149 0
      ObliVMGC/com/oblivm/backend/oram/RecursiveCircuitOram.java
  63. 62 0
      ObliVMGC/com/oblivm/backend/oram/SecureArray.java
  64. 136 0
      ObliVMGC/com/oblivm/backend/oram/TreeBasedOramParty.java
  65. 95 0
      ObliVMGC/com/oblivm/backend/oram/TrivialPrivateOram.java
  66. 67 0
      ObliVMGC/com/oblivm/backend/ot/BitMatrix.java
  67. 97 0
      ObliVMGC/com/oblivm/backend/ot/Cipher.java
  68. 33 0
      ObliVMGC/com/oblivm/backend/ot/FakeOTReceiver.java
  69. 30 0
      ObliVMGC/com/oblivm/backend/ot/FakeOTSender.java
  70. 108 0
      ObliVMGC/com/oblivm/backend/ot/NPOTReceiver.java
  71. 160 0
      ObliVMGC/com/oblivm/backend/ot/NPOTSender.java
  72. 143 0
      ObliVMGC/com/oblivm/backend/ot/OTExtReceiver.java
  73. 155 0
      ObliVMGC/com/oblivm/backend/ot/OTExtSender.java
  74. 84 0
      ObliVMGC/com/oblivm/backend/ot/OTPreprocessReceiver.java
  75. 79 0
      ObliVMGC/com/oblivm/backend/ot/OTPreprocessSender.java
  76. 22 0
      ObliVMGC/com/oblivm/backend/ot/OTReceiver.java
  77. 23 0
      ObliVMGC/com/oblivm/backend/ot/OTSender.java
  78. 264 0
      ObliVMGC/com/oblivm/backend/rand/ISAACAlgorithm.java
  79. 183 0
      ObliVMGC/com/oblivm/backend/rand/ISAACEngine.java
  80. 26 0
      ObliVMGC/com/oblivm/backend/rand/ISAACProvider.java
  81. 7 0
      ObliVMGC/com/oblivm/backend/util/Constants.java
  82. 126 0
      ObliVMGC/com/oblivm/backend/util/EvaRunnable.java
  83. 116 0
      ObliVMGC/com/oblivm/backend/util/GenRunnable.java
  84. 31 0
      ObliVMGC/com/oblivm/backend/util/Reciever.java
  85. 34 0
      ObliVMGC/com/oblivm/backend/util/Sender.java
  86. 136 0
      ObliVMGC/com/oblivm/backend/util/StopWatch.java
  87. 360 0
      ObliVMGC/com/oblivm/backend/util/Utils.java
  88. 4 1
      build.xml
  89. 8 0
      config/Config.conf
  90. BIN
      lib/argparse4j-0.1.0.jar
  91. BIN
      lib/oblivm-flexsc-0.2.jar
  92. BIN
      lib/org.hamcrest.core_1.3.0.v201303031735.jar

+ 3 - 0
.classpath

@@ -3,12 +3,15 @@
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="test"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="src" path="ObliVMGC"/>
+	<classpathentry kind="lib" path="lib/argparse4j-0.1.0.jar"/>
 	<classpathentry kind="lib" path="lib/bcprov-jdk15on-151.jar"/>
 	<classpathentry kind="lib" path="lib/commons-cli-1.2.jar"/>
 	<classpathentry kind="lib" path="lib/commons-io-2.4.jar"/>
 	<classpathentry kind="lib" path="lib/commons-lang3-3.3.2.jar"/>
 	<classpathentry kind="lib" path="lib/jargs.jar"/>
 	<classpathentry kind="lib" path="lib/junit-4.10.jar"/>
+	<classpathentry kind="lib" path="lib/org.hamcrest.core_1.3.0.v201303031735.jar"/>
 	<classpathentry kind="lib" path="lib/snakeyaml-1.11.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>

+ 175 - 0
ObliVMGC/com/oblivm/backend/circuits/BitonicSortLib.java

@@ -0,0 +1,175 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.circuits;
+
+import com.oblivm.backend.circuits.arithmetic.IntegerLib;
+import com.oblivm.backend.flexsc.CompEnv;
+
+public class BitonicSortLib<T> extends IntegerLib<T> {
+	public BitonicSortLib(CompEnv<T> e) {
+		super(e);
+	}
+
+	public void sortWithPayload(T[][] a, T[][] data, T isAscending) {
+		bitonicSortWithPayload(a, data, 0, a.length, isAscending);
+	}
+
+	private void bitonicSortWithPayload(T[][] key, T[][] data, int lo, int n, T dir) {
+		if (n > 1) {
+			int m = n / 2;
+			bitonicSortWithPayload(key, data, lo, m, not(dir));
+			bitonicSortWithPayload(key, data, lo + m, n - m, dir);
+			bitonicMergeWithPayload(key, data, lo, n, dir);
+		}
+	}
+
+	protected void bitonicMergeWithPayload(T[][] key, T[][] data, int lo, int n, T dir) {
+		if (n > 1) {
+			int m = greatestPowerOfTwoLessThan(n);
+			for (int i = lo; i < lo + n - m; i++)
+				compareWithPayload(key, data, i, i + m, dir);
+			bitonicMergeWithPayload(key, data, lo, m, dir);
+			bitonicMergeWithPayload(key, data, lo + m, n - m, dir);
+		}
+	}
+
+	private void compareWithPayload(T[][] key, T[][] data, int i, int j, T dir) {
+		T greater = not(leq(key[i], key[j]));
+		T swap = eq(greater, dir);
+		T[] s = mux(key[j], key[i], swap);
+		s = xor(s, key[i]);
+		T[] ki = xor(key[j], s);
+		T[] kj = xor(key[i], s);
+		key[i] = ki;
+		key[j] = kj;
+
+		T[] s2 = mux(data[j], data[i], swap);
+		s2 = xor(s2, data[i]);
+		T[] di = xor(data[j], s2);
+		T[] dj = xor(data[i], s2);
+		data[i] = di;
+		data[j] = dj;
+	}
+
+	public void sort(T[][] a, T isAscending) {
+		bitonicSort(a, 0, a.length, isAscending);
+	}
+
+	private void bitonicSort(T[][] key, int lo, int n, T dir) {
+		if (n > 1) {
+			int m = n / 2;
+			bitonicSort(key, lo, m, not(dir));
+			bitonicSort(key, lo + m, n - m, dir);
+			bitonicMerge(key, lo, n, dir);
+		}
+	}
+
+	protected void bitonicMerge(T[][] key, int lo, int n, T dir) {
+		if (n > 1) {
+			int m = greatestPowerOfTwoLessThan(n);
+			for (int i = lo; i < lo + n - m; i++)
+				compare(key, i, i + m, dir);
+			bitonicMerge(key, lo, m, dir);
+			bitonicMerge(key, lo + m, n - m, dir);
+		}
+	}
+
+	private void compare(T[][] key, int i, int j, T dir) {
+		T swap = eq(not(leq(key[i], key[j])), dir);
+		T[] s = mux(key[j], key[i], swap);
+		s = xor(s, key[i]);
+		T[] ki = xor(key[j], s);
+		T[] kj = xor(key[i], s);
+		key[i] = ki;
+		key[j] = kj;
+	}
+
+	private int greatestPowerOfTwoLessThan(int n) {
+		int k = 1;
+		while (k < n)
+			k = k << 1;
+		return k >> 1;
+	}
+
+	public void sortWithPayload(T[] a, T[][] data, T isAscending) {
+		bitonicSortWithPayload(a, data, 0, a.length, isAscending);
+	}
+
+	private void bitonicSortWithPayload(T[] key, T[][] data, int lo, int n, T dir) {
+		if (n > 1) {
+			int m = n / 2;
+			bitonicSortWithPayload(key, data, lo, m, not(dir));
+			bitonicSortWithPayload(key, data, lo + m, n - m, dir);
+			bitonicMergeWithPayload(key, data, lo, n, dir);
+		}
+	}
+
+	private void bitonicMergeWithPayload(T[] key, T[][] data, int lo, int n, T dir) {
+		if (n > 1) {
+			int m = greatestPowerOfTwoLessThan(n);
+			for (int i = lo; i < lo + n - m; i++)
+				compareWithPayload(key, data, i, i + m, dir);
+			bitonicMergeWithPayload(key, data, lo, m, dir);
+			bitonicMergeWithPayload(key, data, lo + m, n - m, dir);
+		}
+	}
+
+	private void compareWithPayload(T[] key, T[][] data, int i, int j, T dir) {
+		T greater = and(key[i], not(key[j]));
+		T swap = eq(greater, dir);
+		T s = mux(key[j], key[i], swap);
+		s = xor(s, key[i]);
+		T ki = xor(key[j], s);
+		T kj = xor(key[i], s);
+		key[i] = ki;
+		key[j] = kj;
+
+		T[] s2 = mux(data[j], data[i], swap);
+		s2 = xor(s2, data[i]);
+		T[] di = xor(data[j], s2);
+		T[] dj = xor(data[i], s2);
+		data[i] = di;
+		data[j] = dj;
+	}
+
+	public void sortWithPayload(T[][] a, T[] data, T isAscending) {
+		bitonicSortWithPayload(a, data, 0, a.length, isAscending);
+	}
+
+	private void bitonicSortWithPayload(T[][] key, T[] data, int lo, int n, T dir) {
+		if (n > 1) {
+			int m = n / 2;
+			bitonicSortWithPayload(key, data, lo, m, not(dir));
+			bitonicSortWithPayload(key, data, lo + m, n - m, dir);
+			bitonicMergeWithPayload(key, data, lo, n, dir);
+		}
+	}
+
+	private void bitonicMergeWithPayload(T[][] key, T[] data, int lo, int n, T dir) {
+		if (n > 1) {
+			int m = greatestPowerOfTwoLessThan(n);
+			for (int i = lo; i < lo + n - m; i++)
+				compareWithPayload(key, data, i, i + m, dir);
+			bitonicMergeWithPayload(key, data, lo, m, dir);
+			bitonicMergeWithPayload(key, data, lo + m, n - m, dir);
+		}
+	}
+
+	private void compareWithPayload(T[][] key, T[] data, int i, int j, T dir) {
+		T greater = not(leq(key[i], key[j]));
+		T swap = eq(greater, dir);
+		T[] s = mux(key[j], key[i], swap);
+		s = xor(s, key[i]);
+		T[] ki = xor(key[j], s);
+		T[] kj = xor(key[i], s);
+		key[i] = ki;
+		key[j] = kj;
+
+		T s2 = mux(data[j], data[i], swap);
+		s2 = xor(s2, data[i]);
+		T di = xor(data[j], s2);
+		T dj = xor(data[i], s2);
+		data[i] = di;
+		data[j] = dj;
+	}
+
+}

+ 291 - 0
ObliVMGC/com/oblivm/backend/circuits/CircuitLib.java

@@ -0,0 +1,291 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.circuits;
+
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.flexsc.Party;
+import com.oblivm.backend.gc.GCSignal;
+
+public class CircuitLib<T> {
+	public CompEnv<T> env;
+	public final T SIGNAL_ZERO;
+	public final T SIGNAL_ONE;
+
+	public CircuitLib(CompEnv<T> e) {
+		env = e;
+		SIGNAL_ZERO = e.ZERO();
+		SIGNAL_ONE = e.ONE();
+	}
+
+	public T[] toSignals(long a, int width) {
+		T[] result = env.newTArray(width);
+		for (int i = 0; i < width; ++i) {
+			if ((a & 1) == 1)
+				result[i] = SIGNAL_ONE;
+			else
+				result[i] = SIGNAL_ZERO;
+			a >>= 1;
+		}
+		return result;
+
+	}
+
+	public T[] enforceBits(T[] a, int length) {
+		if (length > a.length)
+			return padSignal(a, length);
+		else
+			return Arrays.copyOfRange(a, 0, length);
+	}
+
+	public T enforceBits(T a) {
+		if (a == null)
+			return SIGNAL_ZERO;
+		else
+			return a;
+	}
+
+	public T[] enforceBits(T a, int length) {
+		T[] ret = env.newTArray(length);
+		if (a == null)
+			ret[0] = SIGNAL_ZERO;
+		else
+			ret[0] = a;
+		for (int i = 1; i < ret.length; ++i) {
+			ret[i] = SIGNAL_ZERO;
+		}
+		return ret;
+	}
+
+	public T[] randBools(int length) {
+		if (env.getMode() == Mode.COUNT) {
+			return zeros(length);
+		}
+		boolean[] res = new boolean[length];
+		for (int i = 0; i < length; ++i)
+			res[i] = CompEnv.rnd.nextBoolean();
+		T[] alice = env.inputOfAlice(res);
+		T[] bob = env.inputOfBob(res);
+		T[] resSC = xor(alice, bob);
+
+		return resSC;
+	}
+
+	public boolean[] declassifyToAlice(T[] x) {
+		return env.outputToAlice(x);
+	}
+
+	public boolean[] declassifyToBob(T[] x) {
+		return env.outputToBob(x);
+	}
+
+	public boolean[] declassifyToBoth2(T[] x) {
+
+		if (env.getMode() == Mode.COUNT) {
+			return new boolean[x.length];
+		}
+
+		boolean[] pos = env.outputToBob(x);
+
+		if (env.getParty() == Party.Bob) {
+			byte[] tmp = new byte[pos.length];
+			for (int i = 0; i < pos.length; ++i)
+				tmp[i] = (byte) (pos[i] ? 1 : 0);
+			env.channel.writeByte(tmp, tmp.length);
+			env.flush();
+		} else {
+			byte tmp[] = env.channel.readBytes(x.length);
+			pos = new boolean[x.length];
+			for (int k = 0; k < tmp.length; ++k) {
+				pos[k] = ((tmp[k] - 1) == 0);
+			}
+		}
+		return pos;
+	}
+
+	public boolean[] declassifyToBoth(T[] x) {
+		if (env.getMode() == Mode.COUNT) {
+			return new boolean[x.length];
+		} else if (env.getMode() == Mode.VERIFY) {
+			return com.oblivm.backend.util.Utils.tobooleanArray((Boolean[]) x);
+		} else {
+
+			GCSignal[] in = (GCSignal[]) x;
+
+			boolean[] pos = new boolean[x.length];
+			GCSignal tmp;
+			for (int i = 0; i < x.length; ++i) {
+				if (in[i].isPublic()) {
+					pos[i] = in[i].v;
+				} else {
+					in[i].send(env.channel);
+				}
+			}
+			env.channel.flush();
+			for (int i = 0; i < x.length; ++i) {
+				if (!in[i].isPublic()) {
+					tmp = GCSignal.receive(env.channel);
+					if (tmp.equals(in[i]))
+						pos[i] = false;
+					else
+						pos[i] = true;
+				}
+			}
+			return pos;
+		}
+	}
+
+	// Defaults to 32 bit constants.
+	public T[] toSignals(int value) {
+		return toSignals(value, 32);
+	}
+
+	public GCSignal[] toSignals(GCSignal[] value) {
+		return value;
+	}
+
+	public T[] zeros(int length) {
+		T[] result = env.newTArray(length);
+		for (int i = 0; i < length; ++i) {
+			result[i] = SIGNAL_ZERO;
+		}
+		return result;
+	}
+
+	public T[] ones(int length) {
+		T[] result = env.newTArray(length);
+		for (int i = 0; i < length; ++i) {
+			result[i] = SIGNAL_ONE;
+		}
+		return result;
+	}
+
+	/*
+	 * Basic logical operations on Signal and Signal[]
+	 */
+	public T and(T x, T y) {
+		assert (x != null && y != null) : "CircuitLib.and: bad inputs";
+
+		return env.and(x, y);
+	}
+
+	public T[] and(T[] x, T[] y) {
+		assert (x != null && y != null && x.length == y.length) : "CircuitLib.and[]: bad inputs";
+
+		T[] result = env.newTArray(x.length);
+		for (int i = 0; i < x.length; ++i) {
+			result[i] = and(x[i], y[i]);
+		}
+		return result;
+	}
+
+	public T xor(T x, T y) {
+		assert (x != null && y != null) : "CircuitLib.xor: bad inputs";
+
+		return env.xor(x, y);
+	}
+
+	public T[] xor(T[] x, T[] y) {
+		assert (x != null && y != null && x.length == y.length) : "CircuitLib.xor[]: bad inputs";
+
+		T[] result = env.newTArray(x.length);
+		for (int i = 0; i < x.length; ++i) {
+			result[i] = xor(x[i], y[i]);
+		}
+		return result;
+	}
+
+	public T not(T x) {
+		assert (x != null) : "CircuitLib.not: bad input";
+
+		return env.xor(x, SIGNAL_ONE);
+	}
+
+	public T[] not(T[] x) {
+		assert (x != null) : "CircuitLib.not[]: bad input";
+
+		T[] result = env.newTArray(x.length);
+		for (int i = 0; i < x.length; ++i) {
+			result[i] = not(x[i]);
+		}
+		return result;
+	}
+
+	public T or(T x, T y) {
+		assert (x != null && y != null) : "CircuitLib.or: bad inputs";
+
+		return xor(xor(x, y), and(x, y)); // http://stackoverflow.com/a/2443029
+	}
+
+	public T[] or(T[] x, T[] y) {
+		assert (x != null && y != null && x.length == y.length) : "CircuitLib.or[]: bad inputs";
+
+		T[] result = env.newTArray(x.length);
+		for (int i = 0; i < x.length; ++i) {
+			result[i] = or(x[i], y[i]);
+		}
+		return result;
+	}
+
+	/*
+	 * Output x when c == 0; Otherwise output y.
+	 */
+	public T mux(T x, T y, T c) {
+		assert (x != null && y != null && c != null) : "CircuitLib.mux: bad inputs";
+		T t = xor(x, y);
+		t = and(t, c);
+		T ret = xor(t, x);
+		return ret;
+	}
+
+	public T[] mux(T[] x, T[] y, T c) {
+		assert (x != null && y != null && x.length == y.length) : "CircuitLib.mux[]: bad inputs";
+
+		T[] ret = env.newTArray(x.length);
+		for (int i = 0; i < x.length; i++)
+			ret[i] = mux(x[i], y[i], c);
+
+		return ret;
+	}
+
+	public T[][] mux(T[][] x, T[][] y, T c) {
+		assert (x != null && y != null && x.length == y.length) : "CircuitLib.mux[][]: bad inputs";
+
+		T[][] ret = env.newTArray(x.length, 1);
+		for (int i = 0; i < x.length; i++)
+			ret[i] = mux(x[i], y[i], c);
+
+		return ret;
+	}
+
+	public T[][][] mux(T[][][] x, T[][][] y, T c) {
+		assert (x != null && y != null && x.length == y.length) : "CircuitLib.mux[]: bad inputs";
+
+		T[][][] ret = env.newTArray(x.length, 1, 1);
+		for (int i = 0; i < x.length; i++)
+			ret[i] = mux(x[i], y[i], c);
+
+		return ret;
+	}
+
+	public T[] padSignal(T[] a, int length) {
+		T[] res = zeros(length);
+		for (int i = 0; i < a.length && i < length; ++i)
+			res[i] = a[i];
+		return res;
+	}
+
+	public T[] padSignedSignal(T[] a, int length) {
+		T[] res = env.newTArray(length);
+		for (int i = 0; i < a.length && i < length; ++i)
+			res[i] = a[i];
+		for (int i = a.length; i < length; ++i)
+			res[i] = a[a.length - 1];
+		return res;
+	}
+
+	public T[] copy(T[] x) {
+		return Arrays.copyOf(x, x.length);
+	}
+}

+ 37 - 0
ObliVMGC/com/oblivm/backend/circuits/arithmetic/ArithmeticLib.java

@@ -0,0 +1,37 @@
+package com.oblivm.backend.circuits.arithmetic;
+
+import com.oblivm.backend.flexsc.CompEnv;
+
+public interface ArithmeticLib<T> {
+	CompEnv<T> getEnv();
+
+	T[] inputOfAlice(double d);
+
+	T[] inputOfBob(double d);
+
+	double outputToAlice(T[] a);
+
+	T[] add(T[] x, T[] y);
+
+	T[] multiply(T[] x, T[] y);
+
+	T[] div(T[] x, T[] y);
+
+	T[] sub(T[] x, T[] y);
+
+	T[] publicValue(double v);
+
+	T leq(T[] a, T[] b);
+
+	T eq(T[] a, T[] b);
+
+	T[] sqrt(T[] a);
+
+	T[] toSecureInt(T[] a, IntegerLib<T> lib);
+
+	T[] toSecureFloat(T[] a, FloatLib<T> lib);
+
+	T[] toSecureFixPoint(T[] a, FixedPointLib<T> lib);
+
+	int numBits();
+}

+ 207 - 0
ObliVMGC/com/oblivm/backend/circuits/arithmetic/DenseMatrixLib.java

@@ -0,0 +1,207 @@
+package com.oblivm.backend.circuits.arithmetic;
+
+import com.oblivm.backend.flexsc.CompEnv;
+
+public class DenseMatrixLib<T> {
+	public ArithmeticLib<T> lib;
+	VectorLib<T> veclib;
+	CompEnv<T> env;
+	IntegerLib<T> integerlib;
+
+	public DenseMatrixLib(CompEnv<T> e, ArithmeticLib<T> lib) {
+		env = e;
+		this.lib = lib;
+		integerlib = new IntegerLib<T>(e);
+		veclib = new VectorLib<T>(e, lib);
+	}
+
+	public T[][][] xor(T[][][] a, T[][][] b) {
+		T[][][] res = env.newTArray(a.length, a[0].length, 1);
+		for (int i = 0; i < a.length; ++i)
+			res[i] = veclib.xor(a[i], b[i]);
+		return res;
+	}
+
+	public T[][][] add(T[][][] a, T[][][] b) {
+		T[][][] res = env.newTArray(a.length, a[0].length, 1);
+		for (int i = 0; i < a.length; ++i)
+			res[i] = veclib.add(a[i], b[i]);
+		return res;
+	}
+
+	public T[][][] sub(T[][][] a, T[][][] b) {
+		T[][][] res = env.newTArray(a.length, a[0].length, 1);
+		for (int i = 0; i < a.length; ++i)
+			res[i] = veclib.sub(a[i], b[i]);
+		return res;
+	}
+
+	public T[][][] multiply(T[][][] a, T[][][] b) {
+		T[][][] res = env.newTArray(a.length, b[0].length, 1);
+		for (int i = 0; i < a.length; ++i)
+			for (int j = 0; j < b[0].length; ++j) {
+				res[i][j] = lib.multiply(a[i][0], b[0][j]);
+				for (int k = 1; k < a[0].length; ++k)
+					res[i][j] = lib.add(res[i][j], lib.multiply(a[i][k], b[k][j]));
+			}
+		return res;
+	}
+
+	public T[][][] transpose(T[][][] a) {
+		T[][][] res = env.newTArray(a[0].length, a.length, 1);
+		for (int i = 0; i < a.length; ++i)
+			for (int j = 0; j < a[0].length; ++j)
+				res[j][i] = a[i][j];
+		return res;
+	}
+
+	public T[][][] rref(T[][][] m) {
+		T[][][] result = env.newTArray(m.length, m[0].length, 1);
+		for (int r = 0; r < m.length; ++r)
+			for (int c = 0; c < m[r].length; ++c)
+				result[r][c] = m[r][c];
+
+		for (int p = 0; p < result.length; ++p) {
+			/* Make this pivot 1 */
+			T[] pv = result[p][p];
+			T pvZero = lib.eq(pv, lib.publicValue(0));
+			T[] pvInv = lib.div(lib.publicValue(1), pv);
+			for (int i = 0; i < result[p].length; ++i)
+				result[p][i] = integerlib.mux(lib.multiply(result[p][i], pvInv), result[p][i], pvZero);
+
+			/* Make other rows zero */
+			for (int r = 0; r < result.length; ++r) {
+				if (r != p) {
+					T[] f = result[r][p];
+					for (int i = 0; i < result[r].length; ++i)
+						result[r][i] = lib.sub(result[r][i], lib.multiply(f, result[p][i]));
+				}
+			}
+		}
+
+		return result;
+	}
+
+	public T[][][] fastInverse(T[][][] m) {
+		int dimension = m.length;
+		T[][][] extended = env.newTArray(dimension, dimension * 2, 1);
+		T[] zeroFloat = lib.publicValue(0);
+		T[] oneFloat = lib.publicValue(1);
+		for (int i = 0; i < dimension; ++i) {
+			for (int j = 0; j < dimension; ++j)
+				extended[i][j] = m[i][j];
+			for (int j = 0; j < dimension; ++j)
+				extended[i][dimension + j] = zeroFloat;
+			extended[i][dimension + i] = oneFloat;
+		}
+		extended = rref(extended);
+		T[][][] result = env.newTArray(dimension, dimension, 1);
+
+		for (int i = 0; i < dimension; ++i) {
+			for (int j = 0; j < dimension; ++j)
+				result[i][j] = extended[i][dimension + j];
+		}
+		return result;
+	}
+
+	public T[][] solve(T[][][] A, T[][] b) {
+		int dimension = A.length;
+		T[][][] extended = env.newTArray(dimension, dimension + 1, 1);
+		for (int i = 0; i < dimension; ++i) {
+			for (int j = 0; j < dimension; ++j)
+				extended[i][j] = A[i][j];
+			extended[i][dimension] = b[i];
+		}
+		extended = rref(extended);
+		T[][] result = env.newTArray(dimension, 1);
+		for (int i = 0; i < dimension; ++i) {
+			result[i] = extended[i][dimension];
+		}
+		return result;
+	}
+
+	public T[][] getColumn(T[][][] matrix, int col) {
+		T[][] res = env.newTArray(matrix[0].length, 1);
+		for (int i = 0; i < matrix[0].length; ++i)
+			res[i] = matrix[i][col];
+		return res;
+	}
+
+	public T[][] getRow(T[][][] matrix, int row) {
+		T[][] res = env.newTArray(matrix.length, 1);
+		for (int i = 0; i < matrix.length; ++i)
+			res[i] = matrix[row][i];
+		return res;
+	}
+
+	// using Gram-Schmidt process
+	public void QRDecomposition(T[][][] matrix, T[][][] res1, T[][][] res2) {
+		T[][][] u = env.newTArray(matrix[0].length, matrix.length, 1);
+		T[][][] e = env.newTArray(matrix[0].length, matrix.length, 1);
+		T[][][] a = transpose(matrix);
+		for (int i = 0; i < matrix[0].length; ++i) {
+			u[i] = a[i];
+			for (int j = 0; j < i; ++j) {
+				u[i] = veclib.sub(u[i], veclib.projection(a[i], e[j]));
+			}
+			e[i] = veclib.normalize(u[i]);
+		}
+		T[][][] r = env.newTArray(matrix.length, matrix[0].length, 1);
+		T[] zero = lib.publicValue(0);
+		for (int i = 0; i < r.length; ++i) {
+			for (int j = 0; j < r[0].length; ++j) {
+				if (i <= j)
+					r[i][j] = veclib.innerProduct(e[i], a[j]);
+				else
+					r[i][j] = zero;
+			}
+		}
+		res1 = transpose(e);
+		res2 = r;
+	}
+
+	public T[][][] eigenValues(T[][][] matrix, int numberOfIterations) {
+		T[][][] e1 = null, e2 = null;
+		QRDecomposition(matrix, e1, e2);
+		T[][][] newMatrix = null;
+		for (int i = 0; i < numberOfIterations; ++i) {
+			newMatrix = multiply(e1, e2);
+			QRDecomposition(newMatrix, e1, e2);
+		}
+		return newMatrix;
+	}
+
+	public static double[][] rref(double[][] mat) {
+		double[][] rref = new double[mat.length][mat[0].length];
+
+		/* Copy matrix */
+		for (int r = 0; r < rref.length; ++r) {
+			for (int c = 0; c < rref[r].length; ++c) {
+				rref[r][c] = mat[r][c];
+			}
+		}
+
+		for (int p = 0; p < rref.length; ++p) {
+			/* Make this pivot 1 */
+			double pv = rref[p][p];
+			if (pv != 0) {
+				double pvInv = 1.0 / pv;
+				for (int i = 0; i < rref[p].length; ++i) {
+					rref[p][i] *= pvInv;
+				}
+			}
+
+			/* Make other rows zero */
+			for (int r = 0; r < rref.length; ++r) {
+				if (r != p) {
+					double f = rref[r][p];
+					for (int i = 0; i < rref[0].length; ++i) {
+						rref[r][i] -= (f * rref[p][i]);
+					}
+				}
+			}
+		}
+
+		return rref;
+	}
+}

+ 112 - 0
ObliVMGC/com/oblivm/backend/circuits/arithmetic/FixedPointLib.java

@@ -0,0 +1,112 @@
+package com.oblivm.backend.circuits.arithmetic;
+
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.util.Utils;
+
+//http://x86asm.net/articles/fixed-point-arithmetic-and-tricks/
+public class FixedPointLib<T> implements ArithmeticLib<T> {
+
+	CompEnv<T> env;
+	IntegerLib<T> lib;
+	int offset;
+	int width;
+
+	public FixedPointLib(CompEnv<T> e, int width, int offset) {
+		assert (offset % 2 == 0);
+		this.env = e;
+		lib = new IntegerLib<>(e);
+		this.offset = offset;
+		this.width = width;
+	}
+
+	public T[] inputOfAlice(double d) {
+		return env.inputOfAlice(Utils.fromFixPoint(d, width, offset));
+	}
+
+	public T[] inputOfBob(double d) {
+		return env.inputOfBob(Utils.fromFixPoint(d, width, offset));
+	}
+
+	public T[] add(T[] x, T[] y) {
+		return lib.add(x, y);
+	}
+
+	public T[] sub(T[] x, T[] y) {
+		return lib.sub(x, y);
+	}
+
+	// http://dsp.stackexchange.com/questions/7906/fixed-point-multiplication-with-negative-numbers
+	public T[] multiply(T[] x, T[] y) {
+		T[] res = lib.karatsubaMultiply(lib.absolute(x), lib.absolute(y));
+		res = Arrays.copyOfRange(res, offset, offset + width);
+		return lib.addSign(res, lib.xor(x[x.length - 1], y[y.length - 1]));
+	}
+
+	public T[] div(T[] x, T[] y) {
+		T[] padX = lib.padSignedSignal(x, x.length + offset);
+		return Arrays.copyOf(lib.div(lib.leftPublicShift(padX, offset), y), width);
+	}
+
+	public T[] publicValue(double d) {
+		boolean[] a = Utils.fromFixPoint(d, width, offset);
+		T[] res = env.newTArray(width);
+		for (int i = 0; i < width; ++i)
+			res[i] = a[i] ? lib.SIGNAL_ONE : lib.SIGNAL_ZERO;
+		return res;
+	}
+
+	@Override
+	public T leq(T[] a, T[] b) {
+		return lib.leq(a, b);
+	}
+
+	@Override
+	public T eq(T[] a, T[] b) {
+		return lib.eq(a, b);
+	}
+
+	@Override
+	public T[] sqrt(T[] a) {
+		T[] res = lib.sqrt(a);
+		return lib.leftPublicShift(res, offset / 2);
+	}
+
+	@Override
+	public CompEnv<T> getEnv() {
+		return env;
+	}
+
+	@Override
+	public T[] toSecureInt(T[] a, IntegerLib<T> lib) {
+		T[] res = lib.env.newTArray(lib.width);
+		T[] intPart = Arrays.copyOfRange(a, offset, a.length);
+		if (res.length >= intPart.length)
+			System.arraycopy(intPart, 0, res, 0, intPart.length);
+		else
+			res = Arrays.copyOf(intPart, res.length);
+		return res;
+	}
+
+	@Override
+	public T[] toSecureFloat(T[] a, FloatLib<T> lib) {
+		return null;
+	}
+
+	@Override
+	public T[] toSecureFixPoint(T[] a, FixedPointLib<T> lib) {
+		// later may support case between different libs;
+		return a;
+	}
+
+	@Override
+	public double outputToAlice(T[] a) {
+		return Utils.toFixPoint(env.outputToAlice(a), offset);
+	}
+
+	@Override
+	public int numBits() {
+		return width;
+	}
+}

+ 235 - 0
ObliVMGC/com/oblivm/backend/circuits/arithmetic/FloatLib.java

@@ -0,0 +1,235 @@
+package com.oblivm.backend.circuits.arithmetic;
+
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.util.Utils;
+
+public class FloatLib<T> implements ArithmeticLib<T> {
+
+	CompEnv<T> env;
+	IntegerLib<T> lib;
+	public int VLength;
+	public int PLength;
+
+	public FloatLib(CompEnv<T> e, int VLength, int PLength) {
+		this.env = e;
+		lib = new IntegerLib<>(e);
+		this.VLength = VLength;
+		this.PLength = PLength;
+	}
+
+	public T[] inputOfAlice(double d) {
+		return env.inputOfAlice(Utils.fromFloat(d, VLength, PLength));
+	}
+
+	public T[] inputOfBob(double d) {
+		return env.inputOfBob(Utils.fromFloat(d, VLength, PLength));
+	}
+
+	public T[] pack(Representation<T> f) {
+		assert (f.v.length == VLength && f.p.length == PLength) : "pack: not compatiable";
+		T[] res = env.newTArray(1 + f.v.length + f.p.length);
+		res[0] = f.s;
+		System.arraycopy(f.v, 0, res, 1, f.v.length);
+		System.arraycopy(f.p, 0, res, 1 + f.v.length, f.p.length);
+		return res;
+	}
+
+	public Representation<T> unpack(T[] data) {
+		assert (data.length == VLength + PLength + 1) : "unpack: not compatiable";
+
+		T[] v = Arrays.copyOfRange(data, 1, 1 + VLength);
+		T[] p = Arrays.copyOfRange(data, 1 + VLength, data.length);
+		return new Representation<T>(data[0], v, p);
+	}
+
+	public static class Representation<T> {
+		public T s;
+		public T[] v;
+		public T[] p;
+
+		public Representation(T sign, T[] v, T[] p) {
+			this.s = sign;
+			this.p = p;
+			this.v = v;
+		}
+	}
+
+	public T[] multiply(T[] fa, T[] fb) {
+		Representation<T> a = unpack(fa);
+		Representation<T> b = unpack(fb);
+
+		T new_s = lib.xor(a.s, b.s);
+		T[] a_multi_b = lib.karatsubaMultiply(a.v, b.v);// length 2*v.length
+		T[] a_add_b = lib.add(a.p, b.p);
+
+		T toShift = lib.not(a_multi_b[a_multi_b.length - 1]);
+		T[] Shifted = lib.conditionalLeftPublicShift(a_multi_b, 1, toShift);
+
+		T[] new_v = Arrays.copyOfRange(Shifted, a.v.length, a.v.length * 2);
+		T[] new_p = lib.add(a_add_b, lib.toSignals(a.v.length, a_add_b.length));
+
+		T[] decrement = lib.zeros(new_p.length);
+		decrement[0] = toShift;
+		new_p = lib.sub(new_p, decrement);
+		Representation<T> res = new Representation<T>(new_s, new_v, new_p);
+		return pack(res);
+	}
+
+	public T[] div(T[] fa, T[] fb) {
+		Representation<T> a = unpack(fa);
+		Representation<T> b = unpack(fb);
+
+		T new_s = lib.xor(a.s, b.s);
+		int length = a.v.length;
+		int newLength = a.v.length * 2;
+		T[] padded_av = lib.padSignal(a.v, newLength);
+		T[] padded_bv = lib.padSignal(b.v, b.v.length + 1);
+		T[] shifted_av = lib.leftPublicShift(padded_av, newLength - length - 1);
+		// must be postive number div. so avoid div(shifted_av, padded_bv);
+		T[] a_div_b = Arrays.copyOf(lib.divInternal(shifted_av, padded_bv), shifted_av.length);
+		T[] leadingzero = lib.leadingZeros(a_div_b);
+
+		T[] sh = lib.leftPrivateShift(a_div_b, leadingzero);
+		sh = lib.rightPublicShift(sh, newLength - length);
+		T[] new_v = Arrays.copyOf(sh, length);
+		T[] new_p = lib.add(lib.sub(a.p, b.p), lib.toSignals(1, a.p.length));
+		new_p = lib.sub(lib.padSignal(new_p, leadingzero.length), leadingzero);
+		new_p = lib.padSignedSignal(new_p, a.p.length);
+
+		Representation<T> res = new Representation<T>(new_s, new_v, new_p);
+		return pack(res);
+	}
+
+	public T[] publicValue(double d) {
+		boolean[] b = Utils.fromFloat(d, VLength, PLength);
+		T[] res = env.newTArray(PLength + VLength + 1);
+		for (int i = 0; i < b.length; ++i)
+			res[i] = b[i] ? lib.SIGNAL_ONE : lib.SIGNAL_ZERO;
+		return res;
+	}
+
+	// assuming na = va*2^p, nb = vb*2^(p+pDiff)
+	private T[] addInternal(T sa, T sb, T[] va, T[] vb, T[] p, T[] pDiff) {
+		int temp_length = 2 * VLength + 1;
+		T[] signedVa = lib.padSignal(va, temp_length);
+		T[] signedVb = lib.padSignal(vb, temp_length);
+		signedVb = lib.leftPrivateShift(signedVb, pDiff);
+
+		signedVa = lib.addSign(signedVa, sa);
+		signedVb = lib.addSign(signedVb, sb);
+
+		T[] new_v = lib.add(signedVa, signedVb);
+
+		T new_s = new_v[new_v.length - 1];
+		new_v = lib.absolute(new_v);
+
+		T[] leadingzero = lib.leadingZeros(new_v);
+
+		T[] sh = lib.leftPrivateShift(new_v, leadingzero);
+		sh = lib.rightPublicShift(sh, temp_length - VLength);
+		new_v = Arrays.copyOf(sh, VLength);
+
+		T[] new_p = lib.sub(lib.padSignal(p, leadingzero.length), leadingzero);
+		new_p = lib.add(new_p, lib.toSignals(temp_length - VLength, new_p.length));
+		new_p = lib.padSignedSignal(new_p, PLength);
+
+		Representation<T> res = new Representation<T>(new_s, new_v, new_p);
+
+		return pack(res);
+	}
+
+	public T[] add(T[] fa, T[] fb) {
+		T[] va = Arrays.copyOfRange(fa, 1, 1 + VLength);
+		T[] vb = Arrays.copyOfRange(fb, 1, 1 + VLength);
+		T[] pa = Arrays.copyOfRange(fa, 1 + VLength, fa.length);
+		T[] pb = Arrays.copyOfRange(fb, 1 + VLength, fb.length);
+
+		T[] pDifference = lib.sub(pa, pb);
+		T[] pDiffAbs = lib.absolute(pDifference);
+
+		T paGreater = lib.not(pDifference[pDifference.length - 1]);
+		T[] pToUse = lib.mux(pa, pb, paGreater);
+		T[] normalCase = addInternal(lib.mux(fa[0], fb[0], paGreater), lib.mux(fb[0], fa[0], paGreater),
+				lib.mux(va, vb, paGreater), lib.mux(vb, va, paGreater), pToUse, pDiffAbs);
+		T underFlowHappen = lib.not(lib.leq(pDiffAbs, lib.toSignals(VLength, pDiffAbs.length)));
+		T[] underFlowResult = lib.mux(fb, fa, paGreater);
+		return lib.mux(normalCase, underFlowResult, underFlowHappen);
+	}
+
+	// (v*s^p)^(1/2) =
+	public T[] sqrt(T[] fa) {
+		int newLength = VLength + 2 + 1;
+		T[] va = Arrays.copyOfRange(fa, 1, 1 + VLength);
+		T[] pa = Arrays.copyOfRange(fa, 1 + VLength, fa.length);
+
+		va = lib.padSignal(va, newLength);
+		va = lib.leftPublicShift(va, 1);
+		pa = lib.sub(pa, lib.toSignals(1, PLength));
+
+		va = lib.conditionalLeftPublicShift(va, 1, pa[0]);
+
+		va = lib.sqrt(va);
+		pa = lib.rightPublicShift(pa, 1);
+		pa[pa.length - 1] = pa[pa.length - 2];
+
+		T[] leadingzero = lib.leadingZeros(va);
+		T[] sh = lib.leftPrivateShift(va, leadingzero);
+		sh = lib.rightPublicShift(sh, newLength - VLength);
+		T[] new_v = Arrays.copyOf(sh, VLength);
+
+		pa = lib.sub(pa, lib.padSignal(leadingzero, pa.length));
+		pa = lib.add(pa, lib.toSignals(newLength - VLength, PLength));
+
+		return pack(new Representation<T>(lib.SIGNAL_ZERO, new_v, pa));
+	}
+
+	public T[] sub(T[] a, T[] b) {
+		T[] negB = Arrays.copyOf(b, b.length);
+		negB[0] = lib.not(negB[0]);
+		return add(a, negB);
+	}
+
+	public T leq(T[] a, T[] b) {
+		T[] res = sub(a, b);
+		return lib.not(res[0]);
+	}
+
+	public T eq(T[] a, T[] b) {
+		return lib.eq(a, b);
+	}
+
+	@Override
+	public CompEnv<T> getEnv() {
+		return env;
+	}
+
+	@Override
+	public T[] toSecureInt(T[] a, IntegerLib<T> lib) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public T[] toSecureFloat(T[] a, FloatLib<T> lib) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public T[] toSecureFixPoint(T[] a, FixedPointLib<T> lib) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public double outputToAlice(T[] a) {
+		return Utils.toFloat(env.outputToAlice(a), VLength, PLength);
+	}
+
+	@Override
+	public int numBits() {
+		return VLength + PLength + 1;
+	}
+}

+ 525 - 0
ObliVMGC/com/oblivm/backend/circuits/arithmetic/IntegerLib.java

@@ -0,0 +1,525 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>, Yan Huang <yhuang@cs.umd.edu> and Kartik Nayak <kartik@cs.umd.edu>
+package com.oblivm.backend.circuits.arithmetic;
+
+import java.util.Arrays;
+
+import com.oblivm.backend.circuits.CircuitLib;
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.util.Utils;
+
+public class IntegerLib<T> extends CircuitLib<T> implements ArithmeticLib<T> {
+
+	public int width;
+
+	public IntegerLib(CompEnv<T> e) {
+		super(e);
+		width = 32;
+	}
+
+	public IntegerLib(CompEnv<T> e, int width) {
+		super(e);
+		this.width = width;
+	}
+
+	static final int S = 0;
+	static final int COUT = 1;
+
+	public T[] publicValue(double v) {
+		int intv = (int) v;
+		return toSignals(intv, width);
+	}
+
+	// full 1-bit adder
+	protected T[] add(T x, T y, T cin) {
+		T[] res = env.newTArray(2);
+
+		T t1 = xor(x, cin);
+		T t2 = xor(y, cin);
+		res[S] = xor(x, t2);
+		t1 = and(t1, t2);
+		res[COUT] = xor(cin, t1);
+
+		return res;
+	}
+
+	// full n-bit adder
+	public T[] addFull(T[] x, T[] y, boolean cin) {
+		assert (x != null && y != null && x.length == y.length) : "add: bad inputs.";
+
+		T[] res = env.newTArray(x.length + 1);
+		T[] t = add(x[0], y[0], env.newT(cin));
+		res[0] = t[S];
+		for (int i = 0; i < x.length - 1; i++) {
+			t = add(x[i + 1], y[i + 1], t[COUT]);
+			res[i + 1] = t[S];
+		}
+		res[res.length - 1] = t[COUT];
+		return res;
+	}
+
+	public T[] add(T[] x, T[] y, boolean cin) {
+		return Arrays.copyOf(addFull(x, y, cin), x.length);
+	}
+
+	public T[] add(T[] x, T[] y) {
+
+		return add(x, y, false);
+	}
+
+	public T[] sub(T x, T y) throws Exception {
+		T[] ax = env.newTArray(2);
+		ax[1] = SIGNAL_ZERO;
+		ax[0] = x;
+		T[] ay = env.newTArray(2);
+		ay[1] = SIGNAL_ZERO;
+		ay[0] = y;
+		return sub(x, y);
+	}
+
+	public T[] sub(T[] x, T[] y) {
+		assert (x != null && y != null && x.length == y.length) : "sub: bad inputs.";
+
+		return add(x, not(y), true);
+	}
+
+	public T[] incrementByOne(T[] x) {
+		T[] one = zeros(x.length);
+		one[0] = SIGNAL_ONE;
+		return add(x, one);
+	}
+
+	public T[] decrementByOne(T[] x) {
+		T[] one = zeros(x.length);
+		one[0] = SIGNAL_ONE;
+		return sub(x, one);
+	}
+
+	public T[] conditionalIncreament(T[] x, T flag) {
+		T[] one = zeros(x.length);
+		one[0] = mux(SIGNAL_ZERO, SIGNAL_ONE, flag);
+		return add(x, one);
+	}
+
+	public T[] conditionalDecrement(T[] x, T flag) {
+		T[] one = zeros(x.length);
+		one[0] = mux(SIGNAL_ZERO, SIGNAL_ONE, flag);
+		return sub(x, one);
+	}
+
+	public T geq(T[] x, T[] y) {
+		assert (x.length == y.length) : "bad input";
+
+		T[] result = sub(x, y);
+		return not(result[result.length - 1]);
+	}
+
+	public T leq(T[] x, T[] y) {
+		return geq(y, x);
+	}
+
+	public T[] multiply(T[] x, T[] y) {
+		return Arrays.copyOf(multiplyInternal(x, y), x.length);// res;
+	}
+
+	// This multiplication does not truncate the length of x and y
+	public T[] multiplyFull(T[] x, T[] y) {
+		return multiplyInternal(x, y);
+	}
+
+	private T[] multiplyInternal(T[] x, T[] y) {
+		// return karatsubaMultiply(x,y);
+		assert (x != null && y != null) : "multiply: bad inputs";
+		T[] res = zeros(x.length + y.length);
+		T[] zero = zeros(x.length);
+
+		T[] toAdd = mux(zero, x, y[0]);
+		System.arraycopy(toAdd, 0, res, 0, toAdd.length);
+
+		for (int i = 1; i < y.length; ++i) {
+			toAdd = Arrays.copyOfRange(res, i, i + x.length);
+			toAdd = add(toAdd, mux(zero, x, y[i]), false);
+			System.arraycopy(toAdd, 0, res, i, toAdd.length);
+		}
+		return res;
+	}
+
+	public T[] absolute(T[] x) {
+		T reachedOneSignal = SIGNAL_ZERO;
+		T[] result = zeros(x.length);
+		for (int i = 0; i < x.length; ++i) {
+			T comp = eq(SIGNAL_ONE, x[i]);
+			result[i] = xor(x[i], reachedOneSignal);
+			reachedOneSignal = or(reachedOneSignal, comp);
+		}
+		return mux(x, result, x[x.length - 1]);
+	}
+
+	public T[] div(T[] x, T[] y) {
+		T[] absoluteX = absolute(x);
+		T[] absoluteY = absolute(y);
+		T[] PA = divInternal(absoluteX, absoluteY);
+		return addSign(Arrays.copyOf(PA, x.length), xor(x[x.length - 1], y[y.length - 1]));
+
+	}
+
+	// Restoring Division Algorithm
+	public T[] divInternal(T[] x, T[] y) {
+		T[] PA = zeros(x.length + y.length);
+		T[] B = y;
+		System.arraycopy(x, 0, PA, 0, x.length);
+		for (int i = 0; i < x.length; ++i) {
+			PA = leftShift(PA);
+			T[] tempP = sub(Arrays.copyOfRange(PA, x.length, PA.length), B);
+			PA[0] = not(tempP[tempP.length - 1]);
+			System.arraycopy(mux(tempP, Arrays.copyOfRange(PA, x.length, PA.length), tempP[tempP.length - 1]), 0, PA,
+					x.length, y.length);
+		}
+		return PA;
+	}
+
+	public T[] mod(T[] x, T[] y) {
+		T Xneg = x[x.length - 1];
+		T[] absoluteX = absolute(x);
+		T[] absoluteY = absolute(y);
+		T[] PA = divInternal(absoluteX, absoluteY);
+		T[] res = Arrays.copyOfRange(PA, y.length, PA.length);
+		return mux(res, sub(toSignals(0, res.length), res), Xneg);
+	}
+
+	public T[] addSign(T[] x, T sign) {
+		T[] reachedOneSignal = zeros(x.length);
+		T[] result = env.newTArray(x.length);
+		for (int i = 0; i < x.length - 1; ++i) {
+			reachedOneSignal[i + 1] = or(reachedOneSignal[i], x[i]);
+			result[i] = xor(x[i], reachedOneSignal[i]);
+		}
+		result[x.length - 1] = xor(x[x.length - 1], reachedOneSignal[x.length - 1]);
+		return mux(x, result, sign);
+	}
+
+	public T[] commonPrefix(T[] x, T[] y) {
+		assert (x != null && y != null) : "multiply: bad inputs";
+		T[] result = xor(x, y);
+
+		for (int i = x.length - 2; i >= 0; --i) {
+			result[i] = or(result[i], result[i + 1]);
+		}
+		return result;
+	}
+
+	public T[] leadingZeros(T[] x) {
+		assert (x != null) : "leading zeros: bad inputs";
+
+		T[] result = Arrays.copyOf(x, x.length);
+		for (int i = result.length - 2; i >= 0; --i) {
+			result[i] = or(result[i], result[i + 1]);
+		}
+
+		return numberOfOnes(not(result));
+	}
+
+	public T[] lengthOfCommenPrefix(T[] x, T[] y) {
+		assert (x != null) : "lengthOfCommenPrefix : bad inputs";
+
+		return leadingZeros(xor(x, y));
+	}
+
+	/*
+	 * Integer manipulation
+	 */
+	public T[] leftShift(T[] x) {
+		assert (x != null) : "leftShift: bad inputs";
+		return leftPublicShift(x, 1);
+	}
+
+	public T[] rightShift(T[] x) {
+		assert (x != null) : "rightShift: bad inputs";
+		return rightPublicShift(x, 1);
+	}
+
+	public T[] leftPublicShift(T[] x, int s) {
+		assert (x != null && s < x.length) : "leftshift: bad inputs";
+
+		T res[] = env.newTArray(x.length);
+		System.arraycopy(zeros(s), 0, res, 0, s);
+		System.arraycopy(x, 0, res, s, x.length - s);
+
+		return res;
+	}
+
+	public T[] rightPublicShift(T[] x, int s) {
+		assert (x != null && s < x.length) : "rightshift: bad inputs";
+
+		T[] res = env.newTArray(x.length);
+		System.arraycopy(x, s, res, 0, x.length - s);
+		System.arraycopy(zeros(s), 0, res, x.length - s, s);
+
+		return res;
+	}
+
+	public T[] conditionalLeftPublicShift(T[] x, int s, T sign) {
+		assert (x != null && s < x.length) : "leftshift: bad inputs";
+
+		T[] res = env.newTArray(x.length);
+		System.arraycopy(mux(Arrays.copyOfRange(x, 0, s), zeros(s), sign), 0, res, 0, s);
+		System.arraycopy(mux(Arrays.copyOfRange(x, s, x.length), Arrays.copyOfRange(x, 0, x.length), sign), 0, res, s,
+				x.length - s);
+		return res;
+	}
+
+	public T[] conditionalRightPublicShift(T[] x, int s, T sign) {
+		assert (x != null && s < x.length) : "rightshift: bad inputs";
+
+		T res[] = env.newTArray(x.length);
+		System.arraycopy(mux(Arrays.copyOfRange(x, 0, x.length - s), Arrays.copyOfRange(x, s, x.length), sign), 0, res,
+				0, x.length - s);
+		System.arraycopy(mux(Arrays.copyOfRange(x, x.length - s, x.length), zeros(s), sign), 0, res, x.length - s, s);
+		return res;
+	}
+
+	public T[] leftPrivateShift(T[] x, T[] lengthToShift) {
+		T[] res = Arrays.copyOf(x, x.length);
+
+		for (int i = 0; ((1 << i) < x.length) && i < lengthToShift.length; ++i)
+			res = conditionalLeftPublicShift(res, (1 << i), lengthToShift[i]);
+		T clear = SIGNAL_ZERO;
+		for (int i = 0; i < lengthToShift.length; ++i) {
+			if ((1 << i) >= x.length)
+				clear = or(clear, lengthToShift[i]);
+		}
+
+		return mux(res, zeros(x.length), clear);
+	}
+
+	public T[] rightPrivateShift(T[] x, T[] lengthToShift) {
+		T[] res = Arrays.copyOf(x, x.length);
+
+		for (int i = 0; ((1 << i) < x.length) && i < lengthToShift.length; ++i)
+			res = conditionalRightPublicShift(res, (1 << i), lengthToShift[i]);
+		T clear = SIGNAL_ZERO;
+		for (int i = 0; i < lengthToShift.length; ++i) {
+			if ((1 << i) >= x.length)
+				clear = or(clear, lengthToShift[i]);
+		}
+
+		return mux(res, zeros(x.length), clear);
+	}
+
+	T compare(T x, T y, T cin) {
+		T t1 = xor(x, cin);
+		T t2 = xor(y, cin);
+		t1 = and(t1, t2);
+		return xor(x, t1);
+	}
+
+	public T compare(T[] x, T[] y) {
+		assert (x != null && y != null && x.length == y.length) : "compare: bad inputs.";
+
+		T t = env.newT(false);
+		for (int i = 0; i < x.length; i++) {
+			t = compare(x[i], y[i], t);
+		}
+
+		return t;
+	}
+
+	public T eq(T x, T y) {
+		assert (x != null && y != null) : "CircuitLib.eq: bad inputs";
+
+		return not(xor(x, y));
+	}
+
+	public T eq(T[] x, T[] y) {
+		assert (x != null && y != null && x.length == y.length) : "CircuitLib.eq[]: bad inputs.";
+
+		T res = env.newT(true);
+		for (int i = 0; i < x.length; i++) {
+			T t = eq(x[i], y[i]);
+			res = env.and(res, t);
+		}
+
+		return res;
+	}
+
+	public T[] twosComplement(T[] x) {
+		T reachOne = SIGNAL_ZERO;
+		T[] result = env.newTArray(x.length);
+		for (int i = 0; i < x.length; ++i) {
+			result[i] = xor(x[i], reachOne);
+			reachOne = or(reachOne, x[i]);
+		}
+		return result;
+	}
+
+	public T[] hammingDistance(T[] x, T[] y) {
+		T[] a = xor(x, y);
+		return numberOfOnes(a);
+	}
+
+	public T[] numberOfOnes(T[] t) {
+		if (t.length == 0) {
+			T[] res = env.newTArray(1);
+			res[0] = SIGNAL_ZERO;
+			return res;
+		}
+		if (t.length == 1) {
+			return t;
+		} else {
+			int length = 1;
+			int w = 1;
+			while (length <= t.length) {
+				length <<= 1;
+				w++;
+			}
+			length >>= 1;
+
+			T[] res1 = numberOfOnesN(Arrays.copyOfRange(t, 0, length));
+			T[] res2 = numberOfOnes(Arrays.copyOfRange(t, length, t.length));
+			return add(padSignal(res1, w), padSignal(res2, w));
+		}
+	}
+
+	public T[] numberOfOnesN(T[] res) {
+		if (res.length == 1)
+			return res;
+		T[] left = numberOfOnesN(Arrays.copyOfRange(res, 0, res.length / 2));
+		T[] right = numberOfOnesN(Arrays.copyOfRange(res, res.length / 2, res.length));
+		return unSignedAdd(left, right);
+	}
+
+	public T[] unSignedAdd(T[] x, T[] y) {
+		assert (x != null && y != null && x.length == y.length) : "add: bad inputs.";
+		T[] res = env.newTArray(x.length + 1);
+
+		T[] t = add(x[0], y[0], env.newT(false));
+		res[0] = t[S];
+		for (int i = 0; i < x.length - 1; i++) {
+			t = add(x[i + 1], y[i + 1], t[COUT]);
+			res[i + 1] = t[S];
+		}
+		res[res.length - 1] = t[COUT];
+		return res;
+	}
+
+	public T[] unSignedMultiply(T[] x, T[] y) {
+		assert (x != null && y != null) : "multiply: bad inputs";
+
+		T[] res = zeros(x.length + y.length);
+		T[] zero = zeros(x.length);
+
+		T[] toAdd = mux(zero, x, y[0]);
+		System.arraycopy(toAdd, 0, res, 0, toAdd.length);
+
+		for (int i = 1; i < y.length; ++i) {
+			toAdd = Arrays.copyOfRange(res, i, i + x.length);
+			toAdd = unSignedAdd(toAdd, mux(zero, x, y[i]));
+			System.arraycopy(toAdd, 0, res, i, toAdd.length);
+
+		}
+		return res;
+	}
+
+	public T[] karatsubaMultiply(T[] x, T[] y) {
+		if (x.length <= 18)
+			return unSignedMultiply(x, y);
+
+		int length = (x.length + y.length);
+
+		T[] xlo = Arrays.copyOfRange(x, 0, x.length / 2);
+		T[] xhi = Arrays.copyOfRange(x, x.length / 2, x.length);
+		T[] ylo = Arrays.copyOfRange(y, 0, y.length / 2);
+		T[] yhi = Arrays.copyOfRange(y, y.length / 2, y.length);
+
+		int nextlength = Math.max(x.length / 2, x.length - x.length / 2);
+		xlo = padSignal(xlo, nextlength);
+		xhi = padSignal(xhi, nextlength);
+		ylo = padSignal(ylo, nextlength);
+		yhi = padSignal(yhi, nextlength);
+
+		T[] z0 = karatsubaMultiply(xlo, ylo);
+		T[] z2 = karatsubaMultiply(xhi, yhi);
+
+		T[] z1 = sub(padSignal(karatsubaMultiply(unSignedAdd(xlo, xhi), unSignedAdd(ylo, yhi)), 2 * nextlength + 2),
+				padSignal(unSignedAdd(padSignal(z2, 2 * nextlength), padSignal(z0, 2 * nextlength)),
+						2 * nextlength + 2));
+		z1 = padSignal(z1, length);
+		z1 = leftPublicShift(z1, x.length / 2);
+
+		T[] z0Pad = padSignal(z0, length);
+		T[] z2Pad = padSignal(z2, length);
+		z2Pad = leftPublicShift(z2Pad, 2 * (x.length / 2));
+		return add(add(z0Pad, z1), z2Pad);
+	}
+
+	public T[] min(T[] x, T[] y) {
+		T leq = leq(x, y);
+		return mux(y, x, leq);
+	}
+
+	public T[] sqrt(T[] a) {
+		int newLength = a.length;
+		if (newLength % 2 == 1)
+			newLength++;
+		T[] x = padSignal(a, newLength);
+
+		T[] rem = zeros(x.length);
+		T[] root = zeros(x.length);
+		for (int i = 0; i < x.length / 2; i++) {
+			root = leftShift(root);
+			rem = add(leftPublicShift(rem, 2), rightPublicShift(x, x.length - 2));
+			x = leftPublicShift(x, 2);
+			T[] oldRoot = root;
+			root = copy(root);
+			root[0] = SIGNAL_ONE;
+			T[] remMinusRoot = sub(rem, root);
+			T isRootSmaller = not(remMinusRoot[remMinusRoot.length - 1]);
+			rem = mux(rem, remMinusRoot, isRootSmaller);
+			root = mux(oldRoot, incrementByOne(root), isRootSmaller);
+		}
+		return padSignal(rightShift(root), a.length);
+	}
+
+	public T[] inputOfAlice(double d) {
+		return env.inputOfAlice(Utils.fromLong((long) d, width));
+	}
+
+	public T[] inputOfBob(double d) {
+		return env.inputOfBob(Utils.fromLong((long) d, width));
+	}
+
+	@Override
+	public CompEnv<T> getEnv() {
+		return env;
+	}
+
+	@Override
+	public T[] toSecureInt(T[] a, IntegerLib<T> lib) {
+		return a;
+	}
+
+	// not fully implemented, more cases to consider
+	@Override
+	public T[] toSecureFloat(T[] a, FloatLib<T> lib) {
+		T[] v = padSignal(a, lib.VLength);
+		T[] p = leadingZeros(v);
+		v = leftPrivateShift(v, p);
+		p = padSignal(p, lib.PLength);
+		p = sub(zeros(p.length), p);
+		return lib.pack(new FloatLib.Representation<T>(SIGNAL_ZERO, v, p));
+	}
+
+	@Override
+	public T[] toSecureFixPoint(T[] a, FixedPointLib<T> lib) {
+		return leftPublicShift(padSignal(a, lib.width), lib.offset);
+	}
+
+	@Override
+	public double outputToAlice(T[] a) {
+		return Utils.toInt(env.outputToAlice(a));
+	}
+
+	@Override
+	public int numBits() {
+		return width;
+	}
+}

+ 63 - 0
ObliVMGC/com/oblivm/backend/circuits/arithmetic/VectorLib.java

@@ -0,0 +1,63 @@
+package com.oblivm.backend.circuits.arithmetic;
+
+import com.oblivm.backend.flexsc.CompEnv;
+
+public class VectorLib<T> {
+	ArithmeticLib<T> lib;
+	CompEnv<T> env;
+
+	public VectorLib(CompEnv<T> e, ArithmeticLib<T> lib) {
+		env = e;
+		this.lib = lib;
+	}
+
+	public T[][] xor(T[][] a, T[][] b) {
+		IntegerLib<T> ilib = new IntegerLib<T>(lib.getEnv());
+		T[][] res = env.newTArray(a.length, 1);
+		for (int i = 0; i < a.length; ++i)
+			res[i] = ilib.xor(a[i], b[i]);
+		return res;
+	}
+
+	public T[][] add(T[][] a, T[][] b) {
+		T[][] res = env.newTArray(a.length, 1);
+		for (int i = 0; i < a.length; ++i)
+			res[i] = lib.add(a[i], b[i]);
+		return res;
+	}
+
+	public T[][] sub(T[][] a, T[][] b) {
+		T[][] res = env.newTArray(a.length, 1);
+		for (int i = 0; i < a.length; ++i)
+			res[i] = lib.sub(a[i], b[i]);
+		return res;
+	}
+
+	public T[] innerProduct(T[][] a, T[][] b) {
+		T[] res = lib.publicValue(0);
+		for (int i = 0; i < a.length; ++i)
+			res = lib.add(res, lib.multiply(a[i], b[i]));
+		return res;
+	}
+
+	public T[][] scalarProduct(T[] scalar, T[][] v) {
+		T[][] res = env.newTArray(v.length, 1);
+		for (int i = 0; i < v.length; ++i)
+			res[i] = lib.multiply(scalar, v[i]);
+		return res;
+	}
+
+	public T[][] projection(T[][] a, T[][] e) {
+		T[] ea = innerProduct(e, a);
+		T[] ee = innerProduct(e, e);
+		T[] scalar = lib.div(ea, ee);
+		return scalarProduct(scalar, e);
+	}
+
+	public T[][] normalize(T[][] vec) {
+		T[] scalar = innerProduct(vec, vec);
+		scalar = lib.sqrt(scalar);
+		scalar = lib.div(lib.publicValue(1), scalar);
+		return scalarProduct(scalar, vec);
+	}
+}

+ 97 - 0
ObliVMGC/com/oblivm/backend/example/HammingDistance.java

@@ -0,0 +1,97 @@
+package com.oblivm.backend.example;
+
+import com.oblivm.backend.circuits.arithmetic.IntegerLib;
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.gc.BadLabelException;
+import com.oblivm.backend.util.EvaRunnable;
+import com.oblivm.backend.util.GenRunnable;
+
+public class HammingDistance {
+
+	static int totalLength = 100;
+
+	private static int countOnes(boolean[] in) {
+		int cnt = 0;
+		for (int i = 0; i < in.length; i++)
+			if (in[i])
+				cnt++;
+		return cnt;
+	}
+
+	private static int booleansToInt(boolean[] arr) {
+		int n = 0;
+		for (int i = arr.length - 1; i >= 0; i--)
+			n = (n << 1) | (arr[i] ? 1 : 0);
+		return n;
+	}
+
+	public static class Generator<T> extends GenRunnable<T> {
+
+		T[] inputA;
+		T[] inputB;
+		T[] scResult;
+		int cnt;
+
+		@Override
+		public void prepareInput(CompEnv<T> gen) {
+			boolean[] in = new boolean[totalLength];
+			for (int i = 0; i < in.length; ++i)
+				in[i] = CompEnv.rnd.nextBoolean();
+			inputA = gen.inputOfAlice(in);
+			gen.flush();
+			inputB = gen.inputOfBob(new boolean[totalLength]);
+
+			cnt = countOnes(in);
+		}
+
+		@Override
+		public void secureCompute(CompEnv<T> gen) {
+			scResult = compute(gen, inputA, inputB);
+		}
+
+		private T[] compute(CompEnv<T> gen, T[] inputA, T[] inputB) {
+			return new IntegerLib<T>(gen).hammingDistance(inputA, inputB);
+		}
+
+		@Override
+		public void prepareOutput(CompEnv<T> gen) throws BadLabelException {
+			boolean[] out = gen.outputToAlice(scResult);
+			int outValue = booleansToInt(out);
+			System.out.println((outValue == cnt) + " " + cnt + " " + outValue);
+		}
+
+	}
+
+	public static class Evaluator<T> extends EvaRunnable<T> {
+		T[] inputA;
+		T[] inputB;
+		T[] scResult;
+
+		@Override
+		public void prepareInput(CompEnv<T> gen) {
+			boolean[] in = new boolean[totalLength];
+			// for(int i = 0; i < in.length; ++i)
+			// in[i] = CompEnv.rnd.nextBoolean();
+			inputA = gen.inputOfAlice(new boolean[totalLength]);
+			gen.flush();
+			inputB = gen.inputOfBob(in);
+		}
+
+		@Override
+		public void secureCompute(CompEnv<T> gen) {
+			scResult = compute(gen, inputA, inputB);
+		}
+
+		private T[] compute(CompEnv<T> gen, T[] inputA, T[] inputB) {
+			IntegerLib<T> il = new IntegerLib<T>(gen);
+			il.hammingDistance(inputA, inputB);
+			gen.setEvaluate();
+			return il.hammingDistance(inputA, inputB);
+		}
+
+		@Override
+		public void prepareOutput(CompEnv<T> gen) throws BadLabelException {
+			gen.outputToAlice(scResult);
+		}
+	}
+}

+ 62 - 0
ObliVMGC/com/oblivm/backend/example/Millionaire.java

@@ -0,0 +1,62 @@
+package com.oblivm.backend.example;
+
+import com.oblivm.backend.circuits.arithmetic.IntegerLib;
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.gc.BadLabelException;
+import com.oblivm.backend.util.EvaRunnable;
+import com.oblivm.backend.util.GenRunnable;
+import com.oblivm.backend.util.Utils;
+
+public class Millionaire {
+
+	static public <T> T compute(CompEnv<T> gen, T[] inputA, T[] inputB) {
+		return new IntegerLib<T>(gen).geq(inputA, inputB);
+	}
+
+	public static class Generator<T> extends GenRunnable<T> {
+
+		T[] inputA;
+		T[] inputB;
+		T scResult;
+
+		@Override
+		public void prepareInput(CompEnv<T> gen) {
+			inputA = gen.inputOfAlice(Utils.fromInt(new Integer(args[0]), 32));
+			gen.flush();
+			inputB = gen.inputOfBob(new boolean[32]);
+		}
+
+		@Override
+		public void secureCompute(CompEnv<T> gen) {
+			scResult = compute(gen, inputA, inputB);
+		}
+
+		@Override
+		public void prepareOutput(CompEnv<T> gen) throws BadLabelException {
+			System.out.println(gen.outputToAlice(scResult));
+		}
+	}
+
+	public static class Evaluator<T> extends EvaRunnable<T> {
+		T[] inputA;
+		T[] inputB;
+		T scResult;
+
+		@Override
+		public void prepareInput(CompEnv<T> gen) {
+			inputA = gen.inputOfAlice(new boolean[32]);
+			gen.flush();
+			inputB = gen.inputOfBob(Utils.fromInt(new Integer(args[0]), 32));
+		}
+
+		@Override
+		public void secureCompute(CompEnv<T> gen) {
+			scResult = compute(gen, inputA, inputB);
+		}
+
+		@Override
+		public void prepareOutput(CompEnv<T> gen) throws BadLabelException {
+			gen.outputToAlice(scResult);
+		}
+	}
+}

+ 63 - 0
ObliVMGC/com/oblivm/backend/example/Sort.java

@@ -0,0 +1,63 @@
+package com.oblivm.backend.example;
+
+import java.util.Arrays;
+
+import com.oblivm.backend.circuits.BitonicSortLib;
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.util.EvaRunnable;
+import com.oblivm.backend.util.GenRunnable;
+import com.oblivm.backend.util.Utils;
+
+public class Sort {
+	static public <T> void compute(CompEnv<T> gen, T[][] inputB) {
+		BitonicSortLib<T> lib = new BitonicSortLib<T>(gen);
+		lib.sort(inputB, lib.SIGNAL_ONE);
+	}
+
+	public static class Generator<T> extends GenRunnable<T> {
+		T[][] inputB;
+
+		@Override
+		public void prepareInput(CompEnv<T> gen) {
+			inputB = gen.newTArray(4000, 0);
+			T[] scTemp = gen.inputOfBob(new boolean[4000 * 16]);
+			for (int i = 0; i < inputB.length; ++i)
+				inputB[i] = Arrays.copyOfRange(scTemp, i * 16, i * 16 + 16);
+		}
+
+		@Override
+		public void secureCompute(CompEnv<T> gen) {
+			compute(gen, inputB);
+		}
+
+		@Override
+		public void prepareOutput(CompEnv<T> gen) {
+		}
+	}
+
+	public static class Evaluator<T> extends EvaRunnable<T> {
+		T[][] inputB;
+		T[] scResult;
+
+		@Override
+		public void prepareInput(CompEnv<T> gen) {
+			inputB = gen.newTArray(4000, 0);
+			boolean[] temp = new boolean[4000 * 16];
+			for (int i = 0; i < 4000; ++i)
+				System.arraycopy(Utils.fromInt(CompEnv.rnd.nextInt(), 16), 0, temp, 16 * i, 16);
+
+			T[] scTemp = gen.inputOfBob(temp);
+			for (int i = 0; i < inputB.length; ++i)
+				inputB[i] = Arrays.copyOfRange(scTemp, i * 16, i * 16 + 16);
+		}
+
+		@Override
+		public void secureCompute(CompEnv<T> gen) {
+			compute(gen, inputB);
+		}
+
+		@Override
+		public void prepareOutput(CompEnv<T> gen) {
+		}
+	}
+}

+ 44 - 0
ObliVMGC/com/oblivm/backend/flexsc/BooleanCompEnv.java

@@ -0,0 +1,44 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.flexsc;
+
+import com.oblivm.backend.network.Network;
+
+public abstract class BooleanCompEnv extends CompEnv<Boolean> {
+	Boolean t = true;
+	Boolean f = false;
+
+	public BooleanCompEnv(Network cha, Party p, Mode m) {
+		super(cha, p, m);
+	}
+
+	@Override
+	public Boolean[] newTArray(int len) {
+		Boolean[] res = new Boolean[len];
+		return res;
+	}
+
+	@Override
+	public Boolean newT(boolean v) {
+		return v;
+	}
+
+	@Override
+	public Boolean[][] newTArray(int d1, int d2) {
+		return new Boolean[d1][d2];
+	}
+
+	@Override
+	public Boolean[][][] newTArray(int d1, int d2, int d3) {
+		return new Boolean[d1][d2][d3];
+	}
+
+	@Override
+	public Boolean ONE() {
+		return t;
+	}
+
+	@Override
+	public Boolean ZERO() {
+		return f;
+	}
+}

+ 98 - 0
ObliVMGC/com/oblivm/backend/flexsc/CVCompEnv.java

@@ -0,0 +1,98 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.flexsc;
+
+import com.oblivm.backend.network.Network;
+import com.oblivm.backend.util.Utils;
+
+public class CVCompEnv extends BooleanCompEnv {
+	public CVCompEnv(Network channel, Party p) {
+		super(channel, p, Mode.VERIFY);
+		this.party = p;
+	}
+
+	@Override
+	public Boolean inputOfAlice(boolean in) {
+		Boolean res = null;
+		res = in;
+		if (party == Party.Alice)
+			channel.writeInt(in ? 1 : 0);
+		else {
+			int re = channel.readInt();
+			res = re == 1;
+		}
+		channel.flush();
+		return res;
+	}
+
+	@Override
+	public Boolean inputOfBob(boolean in) {
+		Boolean res = null;
+		channel.flush();
+		res = in;
+		if (party == Party.Bob)
+			channel.writeInt(in ? 1 : 0);
+		else {
+			int re = channel.readInt();
+			res = re == 1;
+		}
+		channel.flush();
+		return res;
+	}
+
+	@Override
+	public boolean outputToAlice(Boolean out) {
+		return out;
+	}
+
+	public boolean outputToBob(Boolean out) {
+		return out;
+	}
+
+	@Override
+	public Boolean and(Boolean a, Boolean b) {
+		++Flag.sw.ands;
+		++numOfAnds;
+		return a && b;
+	}
+
+	@Override
+	public Boolean xor(Boolean a, Boolean b) {
+		return a ^ b;
+	}
+
+	@Override
+	public Boolean not(Boolean a) {
+		return !a;
+	}
+
+	public Boolean[] inputOfAlice(boolean[] in) {
+		Boolean[] res = new Boolean[in.length];
+		for (int i = 0; i < res.length; ++i)
+			res[i] = inputOfAlice(in[i]);
+		return res;
+	}
+
+	@Override
+	public Boolean[] inputOfBob(boolean[] in) {
+		Boolean[] res = new Boolean[in.length];
+		for (int i = 0; i < res.length; ++i)
+			res[i] = inputOfBob(in[i]);
+		return res;
+	}
+
+	@Override
+	public boolean[] outputToAlice(Boolean[] out) {
+		return Utils.tobooleanArray(out);
+	}
+
+	@Override
+	public boolean[] outputToBob(Boolean[] out) {
+		return Utils.tobooleanArray(out);
+	}
+
+	@Override
+	public void setEvaluate() {
+		// TODO Auto-generated method stub
+
+	}
+}

+ 147 - 0
ObliVMGC/com/oblivm/backend/flexsc/CompEnv.java

@@ -0,0 +1,147 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.flexsc;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.Security;
+
+import com.oblivm.backend.network.Network;
+import com.oblivm.backend.rand.ISAACProvider;
+import com.oblivm.backend.util.Utils;
+
+public abstract class CompEnv<T> {
+	public long numOfAnds = 0;
+	public static SecureRandom rnd;
+
+	static {
+		Security.addProvider(new ISAACProvider());
+		try {
+			rnd = SecureRandom.getInstance("ISAACRandom");
+
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		}
+	}
+
+	@SuppressWarnings("rawtypes")
+	public static CompEnv getEnv(Mode mode, Party p, Network w) {
+		if (mode == Mode.REAL)
+			if (p == Party.Bob)
+				return new com.oblivm.backend.gc.regular.GCEva(w);
+			else
+				return new com.oblivm.backend.gc.regular.GCGen(w);
+		else if (mode == Mode.OPT)
+			if (p == Party.Bob)
+				return new com.oblivm.backend.gc.halfANDs.GCEva(w);
+			else
+				return new com.oblivm.backend.gc.halfANDs.GCGen(w);
+		else if (mode == Mode.VERIFY)
+			return new CVCompEnv(w, p);
+		else if (mode == Mode.COUNT)
+			return new PMCompEnv(w, p);
+		else if (mode == Mode.OFFLINE) {
+			if (p == Party.Bob)
+				return new com.oblivm.backend.gc.offline.GCEva(w);
+			else
+				return new com.oblivm.backend.gc.offline.GCGen(w);
+		} else {
+			try {
+				throw new Exception("not a supported Mode!");
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			return null;
+		}
+	}
+
+	public Network channel;
+	public Party party;
+	public Mode mode;
+
+	public CompEnv(Network w, Party p, Mode m) {
+		this.channel = w;
+		this.mode = m;
+		this.party = p;
+	}
+
+	public abstract T inputOfAlice(boolean in);
+
+	public abstract T inputOfBob(boolean in);
+
+	public abstract boolean outputToAlice(T out);
+
+	public abstract boolean outputToBob(T out);
+
+	public abstract T[] inputOfAlice(boolean[] in);
+
+	public abstract T[] inputOfBob(boolean[] in);
+
+	public T[][] inputOfAlice(boolean[][] in) {
+		boolean[] flattened = Utils.flatten(in);
+		T[] res = inputOfAlice(flattened);
+		T[][] unflattened = newTArray(in.length, in[0].length);
+		Utils.unflatten(res, unflattened);
+		return unflattened;
+	}
+
+	public T[][] inputOfBob(boolean[][] in) {
+		boolean[] flattened = Utils.flatten(in);
+		T[] res = inputOfBob(flattened);
+		T[][] unflattened = newTArray(in.length, in[0].length);
+		Utils.unflatten(res, unflattened);
+		return unflattened;
+	}
+
+	public T[][][] inputOfAlice(boolean[][][] in) {
+		boolean[] flattened = Utils.flatten(in);
+		T[] res = inputOfAlice(flattened);
+		T[][][] unflattened = newTArray(in.length, in[0].length, in[0][0].length);
+		Utils.unflatten(res, unflattened);
+		return unflattened;
+	}
+
+	public T[][][] inputOfBob(boolean[][][] in) {
+		boolean[] flattened = Utils.flatten(in);
+		T[] res = inputOfBob(flattened);
+		T[][][] unflattened = newTArray(in.length, in[0].length, in[0][0].length);
+		Utils.unflatten(res, unflattened);
+		return unflattened;
+	}
+
+	public abstract boolean[] outputToAlice(T[] out);
+
+	public abstract boolean[] outputToBob(T[] out);
+
+	public abstract T and(T a, T b);
+
+	public abstract void setEvaluate();
+
+	public abstract T xor(T a, T b);
+
+	public abstract T not(T a);
+
+	public abstract T ONE();
+
+	public abstract T ZERO();
+
+	public abstract T[] newTArray(int len);
+
+	public abstract T[][] newTArray(int d1, int d2);
+
+	public abstract T[][][] newTArray(int d1, int d2, int d3);
+
+	public abstract T newT(boolean v);
+
+	public Party getParty() {
+		return party;
+	}
+
+	public void flush() {
+		channel.flush();
+	}
+
+	public Mode getMode() {
+		return mode;
+	}
+}

+ 5 - 0
ObliVMGC/com/oblivm/backend/flexsc/Comparator.java

@@ -0,0 +1,5 @@
+package com.oblivm.backend.flexsc;
+
+public interface Comparator<T> {
+	public abstract T compare(T[] a, T[] b) throws Exception;
+}

+ 17 - 0
ObliVMGC/com/oblivm/backend/flexsc/Flag.java

@@ -0,0 +1,17 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// 					 and Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.flexsc;
+
+import com.oblivm.backend.util.StopWatch;
+
+public class Flag {
+	public static boolean CountTime = false;
+	public static StopWatch sw = new StopWatch(CountTime);
+	public static boolean countIO = false;
+	public static boolean FakeOT = true;
+	public static boolean ProprocessOT = false;
+	public static int OTBlockSize = 1024 * 64;
+	public static boolean offline = true;
+	public static String tableName = "table";
+}

+ 19 - 0
ObliVMGC/com/oblivm/backend/flexsc/IWritable.java

@@ -0,0 +1,19 @@
+package com.oblivm.backend.flexsc;
+
+// for compiler generated code
+public interface IWritable<T1 extends IWritable<T1, T2>, T2> {
+	public int numBits();
+
+	public T2[] getBits() throws Exception;
+
+	public T1 newObj(T2[] data) throws Exception;
+
+	default T1 fake() throws Exception {
+		return newObj(getBits());
+	};
+
+	default T1 muxFake(T2 dummy) throws Exception {
+		return fake();
+	}
+
+}

+ 32 - 0
ObliVMGC/com/oblivm/backend/flexsc/Mode.java

@@ -0,0 +1,32 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// 					 and Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.flexsc;
+
+public enum Mode {
+	// verify the correctness of the circuit without running the protocol
+	VERIFY,
+	// GRR3 + Free XOR
+	REAL,
+	// Simulating the protocol and count number of gates/encs
+	COUNT,
+	// Half Gates
+	OPT,
+	// Offline
+	OFFLINE;
+
+	public static Mode getMode(String optionValue) {
+		if (optionValue.equals("VERIFY")) {
+			return VERIFY;
+		} else if (optionValue.equals("REAL")) {
+			return REAL;
+		} else if (optionValue.equals("COUNT")) {
+			return COUNT;
+		} else if (optionValue.equals("OPT")) {
+			return OPT;
+		} else if (optionValue.equals("OFFLINE")) {
+			return OPT;
+		} else
+			return null;
+	}
+}

+ 142 - 0
ObliVMGC/com/oblivm/backend/flexsc/PMCompEnv.java

@@ -0,0 +1,142 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.flexsc;
+
+import com.oblivm.backend.network.Network;
+import com.oblivm.backend.util.Utils;
+
+/*
+ * The computational environment for performance measurement. 
+ */
+public class PMCompEnv extends BooleanCompEnv {
+	public static class Statistics {
+		public long andGate = 0;
+		public long xorGate = 0;
+		public long notGate = 0;
+		public long OTs = 0;
+		public long NumEncAlice = 0;
+		public long NumEncBob = 0;
+		public long bandwidth = 0;
+
+		public void flush() {
+			bandwidth = 0;
+			andGate = 0;
+			xorGate = 0;
+			notGate = 0;
+			OTs = 0;
+			NumEncAlice = 0;
+			NumEncBob = 0;
+		}
+
+		public void add(Statistics s2) {
+			andGate += s2.andGate;
+			xorGate += s2.xorGate;
+			notGate += s2.notGate;
+			OTs += s2.OTs;
+			NumEncAlice += s2.NumEncAlice;
+			NumEncBob += s2.NumEncBob;
+			bandwidth += s2.bandwidth;
+		}
+
+		public void finalize() {
+			NumEncAlice = andGate * 4 + OTs * 2;
+			NumEncBob = andGate * 1 + OTs * 1;
+		}
+
+		public Statistics newInstance() {
+			Statistics s = new Statistics();
+			s.andGate = andGate;
+			s.xorGate = xorGate;
+			s.notGate = notGate;
+			s.OTs = OTs;
+			s.NumEncAlice = NumEncAlice;
+			s.NumEncBob = NumEncBob;
+			s.bandwidth = bandwidth;
+			return s;
+		}
+	}
+
+	public Statistics statistic;
+
+	public PMCompEnv(Network channel, Party p) {
+		super(channel, p, Mode.COUNT);
+		this.party = p;
+		t = true;
+		f = false;
+		statistic = new Statistics();
+	}
+
+	@Override
+	public Boolean inputOfAlice(boolean in) {
+		return f;
+	}
+
+	@Override
+	public Boolean inputOfBob(boolean in) {
+		++statistic.OTs;
+		statistic.bandwidth += 10;
+		return f;
+	}
+
+	@Override
+	public boolean outputToAlice(Boolean out) {
+		statistic.bandwidth += 10;
+		return false;
+	}
+
+	@Override
+	public boolean outputToBob(Boolean out) {
+		statistic.bandwidth += 10;
+		return false;
+	}
+
+	@Override
+	public Boolean and(Boolean a, Boolean b) {
+		++statistic.andGate;
+		++this.numOfAnds;
+		statistic.bandwidth += 3 * 10;
+		return f;
+	}
+
+	@Override
+	public Boolean xor(Boolean a, Boolean b) {
+		++statistic.xorGate;
+		return f;
+	}
+
+	@Override
+	public Boolean not(Boolean a) {
+		++statistic.notGate;
+		return f;
+	}
+
+	@Override
+	public boolean[] outputToAlice(Boolean[] out) {
+		statistic.bandwidth += 10 * out.length;
+		return Utils.tobooleanArray(out);
+	}
+
+	@Override
+	public boolean[] outputToBob(Boolean[] out) {
+		statistic.bandwidth += 10 * out.length;
+		return Utils.tobooleanArray(out);
+	}
+
+	@Override
+	public Boolean[] inputOfAlice(boolean[] in) {
+		statistic.bandwidth += 10 * in.length;
+		return Utils.toBooleanArray(in);
+	}
+
+	@Override
+	public Boolean[] inputOfBob(boolean[] in) {
+		statistic.OTs += in.length;
+		statistic.bandwidth += 10 * 2 * (80 + in.length);
+		return Utils.toBooleanArray(in);
+	}
+
+	@Override
+	public void setEvaluate() {
+		// TODO Auto-generated method stub
+
+	}
+}

+ 8 - 0
ObliVMGC/com/oblivm/backend/flexsc/Party.java

@@ -0,0 +1,8 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// 					 and Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.flexsc;
+
+public enum Party {
+	Alice, Bob;
+}

+ 11 - 0
ObliVMGC/com/oblivm/backend/gc/BadLabelException.java

@@ -0,0 +1,11 @@
+package com.oblivm.backend.gc;
+
+public class BadLabelException extends Exception {
+
+	private static final long serialVersionUID = 1L;
+
+	public BadLabelException(String message) {
+		super(message);
+	}
+
+}

+ 39 - 0
ObliVMGC/com/oblivm/backend/gc/DbgUtils.java

@@ -0,0 +1,39 @@
+package com.oblivm.backend.gc;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.gc.regular.GCEva;
+import com.oblivm.backend.gc.regular.GCGen;
+
+public class DbgUtils {
+
+	static void debugMsg(CompEnv<GCSignal> env, String msg) {
+		if (env instanceof GCEva)
+			System.err.println(msg);
+	}
+
+	static void debugVal(CompEnv<GCSignal> env, GCSignal bs, String msg) throws Exception {
+		if (env instanceof GCGen) {
+			bs.send(((GCGen) env).channel);
+			GCGen.R.send(((GCGen) env).channel);
+		} else {
+			int x;
+			GCSignal glb = GCSignal.receive(((GCEva) env).channel);
+			GCSignal R = GCSignal.receive(((GCEva) env).channel);
+			if (bs.equals(glb))
+				x = 0;
+			else if (bs.equals(R.xor(glb)))
+				x = 1;
+			else
+				throw new Exception(String.format("bad label: %s", bs.toHexStr()));
+			System.out.println(String.format("%s = %d", msg, x));
+
+		}
+	}
+
+	static void debugLabel(CompEnv<GCSignal> env, GCSignal bs, String msg) {
+		if (env instanceof GCGen) {
+			System.err.println(String.format("[%s] %s, %s", msg, bs.toHexStr(), GCGen.R.xor(bs).toHexStr()));
+		} else
+			System.out.println(String.format("[%s] %s", msg, bs.toHexStr()));
+	}
+}

+ 36 - 0
ObliVMGC/com/oblivm/backend/gc/GCCompEnv.java

@@ -0,0 +1,36 @@
+package com.oblivm.backend.gc;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.flexsc.Party;
+import com.oblivm.backend.network.Network;
+
+public abstract class GCCompEnv extends CompEnv<GCSignal> {
+	public GCCompEnv(Network channel, Party p, Mode mode) {
+		super(channel, p, mode);
+	}
+
+	public GCSignal ONE() {
+		return new GCSignal(true);
+	}
+
+	public GCSignal ZERO() {
+		return new GCSignal(false);
+	}
+
+	public GCSignal[] newTArray(int len) {
+		return new GCSignal[len];
+	}
+
+	public GCSignal[][] newTArray(int d1, int d2) {
+		return new GCSignal[d1][d2];
+	}
+
+	public GCSignal[][][] newTArray(int d1, int d2, int d3) {
+		return new GCSignal[d1][d2][d3];
+	}
+
+	public GCSignal newT(boolean v) {
+		return new GCSignal(v);
+	}
+}

+ 139 - 0
ObliVMGC/com/oblivm/backend/gc/GCEvaComp.java

@@ -0,0 +1,139 @@
+package com.oblivm.backend.gc;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.flexsc.Party;
+import com.oblivm.backend.network.Network;
+import com.oblivm.backend.ot.FakeOTReceiver;
+import com.oblivm.backend.ot.OTExtReceiver;
+import com.oblivm.backend.ot.OTPreprocessReceiver;
+import com.oblivm.backend.ot.OTReceiver;
+
+public abstract class GCEvaComp extends GCCompEnv {
+
+	OTReceiver rcv;
+
+	protected long gid = 0;
+
+	public GCEvaComp(Network channel, Mode mode) {
+		super(channel, Party.Bob, mode);
+
+		if (Flag.FakeOT)
+			rcv = new FakeOTReceiver(channel);
+		else if (Flag.ProprocessOT)
+			rcv = new OTPreprocessReceiver(channel);
+		else
+			rcv = new OTExtReceiver(channel);
+
+	}
+
+	public GCSignal inputOfAlice(boolean in) {
+		Flag.sw.startOT();
+		GCSignal signal = GCSignal.receive(channel);
+		Flag.sw.stopOT();
+		return signal;
+	}
+
+	public GCSignal inputOfBob(boolean in) {
+		Flag.sw.startOT();
+		GCSignal signal = null;
+		try {
+			signal = rcv.receive(in);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		Flag.sw.stopOT();
+		return signal;
+	}
+
+	public GCSignal[] inputOfBob(boolean[] x) {
+		GCSignal[] ret = new GCSignal[x.length];
+		for (int i = 0; i < x.length; i += Flag.OTBlockSize) {
+			GCSignal[] tmp = inputOfBobInter(Arrays.copyOfRange(x, i, Math.min(i + Flag.OTBlockSize, x.length)));
+			System.arraycopy(tmp, 0, ret, i, tmp.length);
+		}
+		return ret;
+	}
+
+	public GCSignal[] inputOfBobInter(boolean[] x) {
+		Flag.sw.startOT();
+		GCSignal[] signal = null;
+		try {
+			signal = rcv.receive(x);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		Flag.sw.stopOT();
+		return signal;
+	}
+
+	public GCSignal[] inputOfAlice(boolean[] x) {
+		Flag.sw.startOT();
+		GCSignal[] result = new GCSignal[x.length];
+		for (int i = 0; i < x.length; ++i)
+			result[i] = GCSignal.receive(channel);
+		Flag.sw.stopOT();
+		return result;
+	}
+
+	public boolean outputToAlice(GCSignal out) {
+		if (!out.isPublic())
+			out.send(channel);
+		return false;
+	}
+
+	public boolean outputToBob(GCSignal out) {
+		if (out.isPublic())
+			return out.v;
+
+		GCSignal lb = GCSignal.receive(channel);
+		if (lb.equals(out))
+			return false;
+		else
+			return true;
+	}
+
+	public boolean[] outputToAlice(GCSignal[] out) {
+		boolean[] result = new boolean[out.length];
+		for (int i = 0; i < result.length; ++i) {
+			if (!out[i].isPublic())
+				out[i].send(channel);
+		}
+
+		channel.flush();
+
+		for (int i = 0; i < result.length; ++i)
+			result[i] = false;
+		return result;
+	}
+
+	public boolean[] outputToBob(GCSignal[] out) {
+		boolean[] result = new boolean[out.length];
+		for (int i = 0; i < result.length; ++i) {
+			result[i] = outputToBob(out[i]);
+		}
+		return result;
+	}
+
+	public GCSignal xor(GCSignal a, GCSignal b) {
+		if (a.isPublic() && b.isPublic())
+			return ((a.v ^ b.v) ? new GCSignal(true) : new GCSignal(false));
+		else if (a.isPublic())
+			return a.v ? not(b) : b;
+		else if (b.isPublic())
+			return b.v ? not(a) : a;
+		else
+			return a.xor(b);
+	}
+
+	public GCSignal not(GCSignal a) {
+		if (a.isPublic())
+			return ((!a.v) ? new GCSignal(true) : new GCSignal(false));
+		else {
+			return a;
+		}
+	}
+}

+ 191 - 0
ObliVMGC/com/oblivm/backend/gc/GCGenComp.java

@@ -0,0 +1,191 @@
+package com.oblivm.backend.gc;
+
+import java.io.IOException;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.flexsc.Party;
+import com.oblivm.backend.network.Network;
+import com.oblivm.backend.ot.FakeOTSender;
+import com.oblivm.backend.ot.OTExtSender;
+import com.oblivm.backend.ot.OTPreprocessSender;
+import com.oblivm.backend.ot.OTSender;
+
+public abstract class GCGenComp extends GCCompEnv {
+
+	static public GCSignal R = null;
+
+	static {
+		R = GCSignal.freshLabel(CompEnv.rnd);
+		R.setLSB();
+	}
+
+	OTSender snd;
+	protected long gid = 0;
+
+	public GCGenComp(Network channel, Mode mode) {
+		super(channel, Party.Alice, mode);
+
+		if (Flag.FakeOT)
+			snd = new FakeOTSender(80, channel);
+		else if (Flag.ProprocessOT)
+			snd = new OTPreprocessSender(80, channel);
+		else
+			snd = new OTExtSender(80, channel);
+	}
+
+	public static GCSignal[] genPairForLabel(Mode mode) {
+		GCSignal[] label = new GCSignal[2];
+		if (mode != Mode.OFFLINE || !Flag.offline)
+			label[0] = GCSignal.freshLabel(rnd);
+		if (mode == Mode.OFFLINE) {
+			if (Flag.offline) {
+				label[0] = new GCSignal(com.oblivm.backend.gc.offline.GCGen.fread.read(10));
+			} else
+				label[0].send(com.oblivm.backend.gc.offline.GCGen.fout);
+		}
+		label[1] = R.xor(label[0]);
+		return label;
+	}
+
+	public static GCSignal[] genPair() {
+		GCSignal[] label = new GCSignal[2];
+		label[0] = GCSignal.freshLabel(rnd);
+		label[1] = R.xor(label[0]);
+		return label;
+	}
+
+	public GCSignal inputOfAlice(boolean in) {
+		Flag.sw.startOT();
+		GCSignal[] label = genPairForLabel(mode);
+		Flag.sw.startOTIO();
+		label[in ? 1 : 0].send(channel);
+		flush();
+		Flag.sw.stopOTIO();
+		Flag.sw.stopOT();
+		return label[0];
+	}
+
+	public GCSignal inputOfBob(boolean in) {
+		Flag.sw.startOT();
+		GCSignal[] label = genPairForLabel(mode);
+		try {
+			snd.send(label);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		Flag.sw.stopOT();
+		return label[0];
+	}
+
+	public GCSignal[] inputOfAlice(boolean[] x) {
+		Flag.sw.startOT();
+		GCSignal[][] pairs = new GCSignal[x.length][2];
+		GCSignal[] result = new GCSignal[x.length];
+		for (int i = 0; i < x.length; ++i) {
+			pairs[i] = genPairForLabel(mode);
+			result[i] = pairs[i][0];
+		}
+		Flag.sw.startOTIO();
+		for (int i = 0; i < x.length; ++i)
+			pairs[i][x[i] ? 1 : 0].send(channel);
+		flush();
+		Flag.sw.stopOTIO();
+		Flag.sw.stopOT();
+		return result;
+	}
+
+	public GCSignal[] inputOfBob(boolean[] x) {
+		Flag.sw.startOT();
+		GCSignal[][] pair = new GCSignal[x.length][2];
+		for (int i = 0; i < x.length; ++i)
+			pair[i] = genPairForLabel(mode);
+		try {
+			snd.send(pair);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		GCSignal[] result = new GCSignal[x.length];
+		for (int i = 0; i < x.length; ++i)
+			result[i] = pair[i][0];
+		Flag.sw.stopOT();
+		return result;
+	}
+
+	protected boolean gatesRemain = false;
+
+	public boolean outputToAlice(GCSignal out) {
+
+		if (gatesRemain) {
+			gatesRemain = false;
+			flush();
+		}
+
+		if (out.isPublic())
+			return out.v;
+
+		GCSignal lb = GCSignal.receive(channel);
+
+		if (lb.equals(out))
+			return false;
+		else if (lb.equals(R.xor(out)))
+			return true;
+
+		try {
+			throw new Exception("bad label at final output.");
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return false;
+	}
+
+	public boolean outputToBob(GCSignal out) {
+		if (!out.isPublic())
+			out.send(channel);
+		return false;
+	}
+
+	public boolean[] outputToBob(GCSignal[] out) {
+		boolean[] result = new boolean[out.length];
+
+		for (int i = 0; i < result.length; ++i) {
+			if (!out[i].isPublic())
+				out[i].send(channel);
+		}
+		flush();
+
+		for (int i = 0; i < result.length; ++i)
+			result[i] = false;
+		return result;
+	}
+
+	public boolean[] outputToAlice(GCSignal[] out) {
+		boolean[] result = new boolean[out.length];
+		for (int i = 0; i < result.length; ++i) {
+			result[i] = outputToAlice(out[i]);
+		}
+		return result;
+	}
+
+	public GCSignal xor(GCSignal a, GCSignal b) {
+		if (a.isPublic() && b.isPublic())
+			return new GCSignal(a.v ^ b.v);
+		else if (a.isPublic())
+			return a.v ? not(b) : new GCSignal(b);
+		else if (b.isPublic())
+			return b.v ? not(a) : new GCSignal(a);
+		else {
+			return a.xor(b);
+		}
+	}
+
+	public GCSignal not(GCSignal a) {
+		if (a.isPublic())
+			return new GCSignal(!a.v);
+		else
+			return R.xor(a);
+	}
+}

+ 115 - 0
ObliVMGC/com/oblivm/backend/gc/GCSignal.java

@@ -0,0 +1,115 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// Improved by Xiao Shaun Wang <wangxiao@cs.umd.edu> and Kartik Nayak <kartik@cs.umd.edu>
+
+package com.oblivm.backend.gc;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import com.oblivm.backend.network.Network;
+
+public class GCSignal {
+	public static final int len = 10;
+	public byte[] bytes;
+	public boolean v;
+
+	public static final GCSignal ZERO = new GCSignal(new byte[len]);
+
+	public GCSignal(byte[] b) {
+		bytes = b;
+	}
+
+	public GCSignal(boolean b) {
+		v = b;
+	}
+
+	public static GCSignal freshLabel(SecureRandom rnd) {
+		byte[] b = new byte[len];
+		rnd.nextBytes(b);
+		return new GCSignal(b);
+	}
+
+	public static GCSignal newInstance(byte[] bs) {
+		assert (bs.length <= len) : "Losing entropy when constructing signals.";
+		byte[] b = new byte[len];
+		Arrays.fill(b, (byte) ((bs[0] < 0) ? 0xff : 0));
+		int newlen = len < bs.length ? len : bs.length;
+		System.arraycopy(bs, 0, b, len - newlen, newlen);
+		return new GCSignal(b);
+	}
+
+	public GCSignal(GCSignal lb) {
+		v = lb.v;
+		bytes = (lb.bytes == null) ? null : Arrays.copyOf(lb.bytes, len);
+	}
+
+	public boolean isPublic() {
+		return bytes == null;
+	}
+
+	public GCSignal xor(GCSignal lb) {
+		byte[] nb = new byte[len];
+		for (int i = 0; i < len; i++)
+			nb[i] = (byte) (bytes[i] ^ lb.bytes[i]);
+		return new GCSignal(nb);
+	}
+
+	public static void xor(GCSignal l, GCSignal r, GCSignal ret) {
+		for (int i = 0; i < len; i++)
+			ret.bytes[i] = (byte) (l.bytes[i] ^ r.bytes[i]);
+	}
+
+	public void setLSB() {
+		bytes[0] |= 1;
+	}
+
+	public int getLSB() {
+		return (bytes[0] & 1);
+	}
+
+	// 'send' and 'receive' are supposed to be used only for secret signals
+	public void send(Network channel) {
+		channel.writeByte(bytes, len);
+	}
+
+	// 'send' and 'receive' are supposed to be used only for secret signals
+	public void send(OutputStream os) {
+		try {
+			os.write(bytes);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	// 'send' and 'receive' are supposed to be used only for secret signals
+	public static GCSignal receive(Network channel) {
+		byte[] b = channel.readBytes(len);
+		return new GCSignal(b);
+	}
+
+	public static void receive(Network channel, GCSignal s) {
+		if (s.bytes == null)
+			s.bytes = new byte[len];
+		channel.readBytes(s.bytes);
+	}
+
+	@Override
+	public boolean equals(Object lb) {
+		if (this == lb)
+			return true;
+		else if (lb instanceof GCSignal)
+			return Arrays.equals(bytes, ((GCSignal) lb).bytes);
+		else
+			return false;
+	}
+
+	public String toHexStr() {
+		StringBuilder str = new StringBuilder();
+		for (byte b : bytes)
+			str.append(Integer.toHexString(b & 0xff));
+		return str.toString();
+	}
+}

+ 58 - 0
ObliVMGC/com/oblivm/backend/gc/halfANDs/GCEva.java

@@ -0,0 +1,58 @@
+package com.oblivm.backend.gc.halfANDs;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.gc.GCEvaComp;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class GCEva extends GCEvaComp {
+	Garbler gb;
+
+	public GCEva(Network channel) {
+		super(channel, Mode.OPT);
+		gb = new Garbler();
+	}
+
+	public GCSignal and(GCSignal a, GCSignal b) {
+		Flag.sw.startGC();
+		GCSignal res;
+		if (a.isPublic() && b.isPublic())
+			res = ((a.v && b.v) ? new GCSignal(true) : new GCSignal(false));
+		else if (a.isPublic())
+			res = a.v ? b : new GCSignal(false);
+		else if (b.isPublic())
+			res = b.v ? a : new GCSignal(false);
+		else {
+			++numOfAnds;
+			int i0 = a.getLSB();
+			int i1 = b.getLSB();
+
+			GCSignal TG = GCSignal.ZERO, WG, TE = GCSignal.ZERO, WE;
+			try {
+				Flag.sw.startGCIO();
+				TG = GCSignal.receive(channel);
+				TE = GCSignal.receive(channel);
+				Flag.sw.stopGCIO();
+			} catch (Exception e) {
+				e.printStackTrace();
+				System.exit(1);
+			}
+
+			WG = gb.hash(a, gid, false).xor((i0 == 1) ? TG : GCSignal.ZERO);
+			WE = gb.hash(b, gid, true).xor((i1 == 1) ? (TE.xor(a)) : GCSignal.ZERO);
+
+			res = WG.xor(WE);
+
+			gid++;
+		}
+		Flag.sw.stopGC();
+		return res;
+	}
+
+	@Override
+	public void setEvaluate() {
+		// TODO Auto-generated method stub
+
+	}
+}

+ 82 - 0
ObliVMGC/com/oblivm/backend/gc/halfANDs/GCGen.java

@@ -0,0 +1,82 @@
+package com.oblivm.backend.gc.halfANDs;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.gc.GCGenComp;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class GCGen extends GCGenComp {
+	Garbler gb;
+
+	public GCGen(Network channel) {
+		super(channel, Mode.OPT);
+		gb = new Garbler();
+	}
+
+	private GCSignal labelL[] = new GCSignal[2];
+	private GCSignal labelR[] = new GCSignal[2];
+
+	private GCSignal TG, WG, TE, WE;
+
+	private GCSignal garble(GCSignal a, GCSignal b) {
+		labelL[0] = a;
+		labelL[1] = R.xor(labelL[0]);
+		labelR[0] = b;
+		labelR[1] = R.xor(labelR[0]);
+
+		int cL = a.getLSB();
+		int cR = b.getLSB();
+
+		// first half gate
+		GCSignal G1 = gb.hash(labelL[0], gid, false);
+		TG = G1.xor(gb.hash(labelL[1], gid, false)).xor((cR == 1) ? R : GCSignal.ZERO);
+		WG = G1.xor((cL == 1) ? TG : GCSignal.ZERO);
+
+		// second half gate
+		G1 = gb.hash(labelR[0], gid, true);
+		TE = G1.xor(gb.hash(labelR[1], gid, true)).xor(labelL[0]);
+		WE = G1.xor((cR == 1) ? (TE.xor(labelL[0])) : GCSignal.ZERO);
+
+		// send the encrypted gate
+		try {
+			Flag.sw.startGCIO();
+			TG.send(channel);
+			TE.send(channel);
+			Flag.sw.stopGCIO();
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+
+		// combine halves
+		return WG.xor(WE);
+	}
+
+	public GCSignal and(GCSignal a, GCSignal b) {
+
+		Flag.sw.startGC();
+		GCSignal res;
+		if (a.isPublic() && b.isPublic())
+			res = ((a.v && b.v) ? new GCSignal(true) : new GCSignal(false));
+		else if (a.isPublic())
+			res = a.v ? b : new GCSignal(false);
+		else if (b.isPublic())
+			res = b.v ? a : new GCSignal(false);
+		else {
+			++numOfAnds;
+			GCSignal ret = garble(a, b);
+			gid++;
+			res = ret;
+			gatesRemain = true;
+		}
+		Flag.sw.stopGC();
+		return res;
+	}
+
+	@Override
+	public void setEvaluate() {
+		// TODO Auto-generated method stub
+
+	}
+}

+ 27 - 0
ObliVMGC/com/oblivm/backend/gc/halfANDs/Garbler.java

@@ -0,0 +1,27 @@
+package com.oblivm.backend.gc.halfANDs;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+
+import com.oblivm.backend.gc.GCSignal;
+
+final class Garbler {
+	private MessageDigest sha1 = null;
+
+	Garbler() {
+		try {
+			sha1 = MessageDigest.getInstance("SHA-1");
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	ByteBuffer buffer = ByteBuffer.allocate(GCSignal.len + 9);
+
+	public GCSignal hash(GCSignal lb, long k, boolean b) {
+		buffer.clear();
+		sha1.update(buffer.put(lb.bytes).putLong(k).put(b ? (byte) 1 : (byte) 0));
+		return GCSignal.newInstance(sha1.digest());
+	}
+}

+ 25 - 0
ObliVMGC/com/oblivm/backend/gc/halfANDs/TestGarbler.java

@@ -0,0 +1,25 @@
+package com.oblivm.backend.gc.halfANDs;
+
+import java.security.SecureRandom;
+
+import com.oblivm.backend.gc.GCSignal;
+
+public class TestGarbler {
+	SecureRandom rnd = new SecureRandom();
+	GCSignal a = GCSignal.freshLabel(rnd);
+	GCSignal b = GCSignal.freshLabel(rnd);
+	GCSignal m = GCSignal.freshLabel(rnd);
+	Garbler gb = new Garbler();
+
+	// public void test() {
+	// gb.enc(a, b, 0, m);
+	//
+	//// Assert.assertTrue(m.equals(gb.dec(a, b, 0L, gb.enc(a, b, 0L, m))));
+	// }
+	//
+	// @Test
+	// public void test1000() {
+	// for(int i = 0; i<10000; i++)
+	// test();
+	// }
+}

+ 46 - 0
ObliVMGC/com/oblivm/backend/gc/offline/FileReader.java

@@ -0,0 +1,46 @@
+package com.oblivm.backend.gc.offline;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+public class FileReader {
+	byte[] data;
+	int pos = 0;
+
+	public FileReader(String name) {
+		try {
+			File file = new File(name);
+			FileInputStream fis;
+			fis = new FileInputStream(file);
+			data = new byte[(int) file.length()];
+			fis.read(data);
+			fis.close();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	public void read(byte[] a) {
+		System.arraycopy(data, pos, a, 0, a.length);
+		pos += a.length;
+	}
+
+	public byte[] read(int len) {
+		byte[] res = Arrays.copyOfRange(data, pos, pos + len);
+		pos += len;
+		return res;
+	}
+
+	static public void main(String[] args) {
+		double t1 = System.nanoTime();
+		FileReader a = new FileReader("table");
+		double t2 = System.nanoTime();
+		System.out.println(t2 - t1);
+		System.out.println(a.data.length);
+		byte[] b = new byte[10];
+		a.read(b);
+	}
+}

+ 61 - 0
ObliVMGC/com/oblivm/backend/gc/offline/GCEva.java

@@ -0,0 +1,61 @@
+package com.oblivm.backend.gc.offline;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.gc.GCEvaComp;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class GCEva extends GCEvaComp {
+	Garbler gb;
+	GCSignal[][] gtt = new GCSignal[2][2];
+
+	public GCEva(Network channel) {
+		super(channel, Mode.OFFLINE);
+		gb = new Garbler();
+		gtt[0][0] = GCSignal.ZERO;
+	}
+
+	private void receiveGTT() {
+		try {
+			Flag.sw.startGCIO();
+			gtt[0][1] = GCSignal.receive(channel);
+			gtt[1][0] = GCSignal.receive(channel);
+			gtt[1][1] = GCSignal.receive(channel);
+			Flag.sw.stopGCIO();
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	public GCSignal and(GCSignal a, GCSignal b) {
+		Flag.sw.startGC();
+
+		GCSignal res;
+		if (a.isPublic() && b.isPublic())
+			res = ((a.v && b.v) ? new GCSignal(true) : new GCSignal(false));
+		else if (a.isPublic())
+			res = a.v ? b : new GCSignal(false);
+		else if (b.isPublic())
+			res = b.v ? a : new GCSignal(false);
+		else {
+			++numOfAnds;
+			receiveGTT();
+
+			int i0 = a.getLSB();
+			int i1 = b.getLSB();
+
+			res = gb.dec(a, b, gid, gtt[i0][i1]);
+			gid++;
+		}
+		Flag.sw.stopGC();
+		return res;
+	}
+
+	@Override
+	public void setEvaluate() {
+		// TODO Auto-generated method stub
+
+	}
+}

+ 131 - 0
ObliVMGC/com/oblivm/backend/gc/offline/GCGen.java

@@ -0,0 +1,131 @@
+package com.oblivm.backend.gc.offline;
+
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.gc.GCGenComp;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class GCGen extends GCGenComp {
+	Garbler gb;
+
+	public static BufferedOutputStream fout = null;
+	public static FileReader fread = null;
+
+	public GCGen(Network channel) {
+		super(channel, Mode.OFFLINE);
+		gtt[0][1] = GCSignal.freshLabel(CompEnv.rnd);
+		gtt[1][0] = GCSignal.freshLabel(CompEnv.rnd);
+		gtt[1][1] = GCSignal.freshLabel(CompEnv.rnd);
+		gb = new Garbler();
+	}
+
+	private GCSignal[][] gtt = new GCSignal[2][2];
+
+	private GCSignal labelL[] = new GCSignal[2];
+	private GCSignal labelR[] = new GCSignal[2];
+	GCSignal[] lb = new GCSignal[2];;
+
+	private GCSignal garble(GCSignal a, GCSignal b) {
+		labelL[0] = a;
+		labelL[1] = R.xor(labelL[0]);
+		labelR[0] = b;
+		labelR[1] = R.xor(labelR[0]);
+
+		int cL = a.getLSB();
+		int cR = b.getLSB();
+
+		lb[cL & cR] = gb.enc(labelL[cL], labelR[cR], gid, GCSignal.ZERO);
+		lb[1 - (cL & cR)] = R.xor(lb[cL & cR]);
+
+		gtt[0 ^ cL][0 ^ cR] = lb[0];
+		gtt[0 ^ cL][1 ^ cR] = lb[0];
+		gtt[1 ^ cL][0 ^ cR] = lb[0];
+		gtt[1 ^ cL][1 ^ cR] = lb[1];
+
+		if (cL != 0 || cR != 0)
+			gtt[0 ^ cL][0 ^ cR] = gb.enc(labelL[0], labelR[0], gid, gtt[0 ^ cL][0 ^ cR]);
+		if (cL != 0 || cR != 1)
+			gtt[0 ^ cL][1 ^ cR] = gb.enc(labelL[0], labelR[1], gid, gtt[0 ^ cL][1 ^ cR]);
+		if (cL != 1 || cR != 0)
+			gtt[1 ^ cL][0 ^ cR] = gb.enc(labelL[1], labelR[0], gid, gtt[1 ^ cL][0 ^ cR]);
+		if (cL != 1 || cR != 1)
+			gtt[1 ^ cL][1 ^ cR] = gb.enc(labelL[1], labelR[1], gid, gtt[1 ^ cL][1 ^ cR]);
+		return lb[0];
+	}
+
+	public double t;
+
+	private GCSignal readGateFromFile() {
+		fread.read(gtt[0][1].bytes);
+		fread.read(gtt[1][0].bytes);
+		fread.read(gtt[1][1].bytes);
+		GCSignal a = new GCSignal(fread.read(10));
+		return a;
+	}
+
+	private void writeGateToFile(GCSignal a) {
+		gtt[0][1].send(fout);
+		gtt[1][0].send(fout);
+		gtt[1][1].send(fout);
+		a.send(fout);
+		try {
+			fout.flush();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	private void sendGTT() {
+		try {
+			Flag.sw.startGCIO();
+			gtt[0][1].send(channel);
+			gtt[1][0].send(channel);
+			gtt[1][1].send(channel);
+			Flag.sw.stopGCIO();
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	public GCSignal and(GCSignal a, GCSignal b) {
+
+		Flag.sw.startGC();
+		GCSignal res = null;
+		if (a.isPublic() && b.isPublic())
+			res = ((a.v && b.v) ? new GCSignal(true) : new GCSignal(false));
+		else if (a.isPublic())
+			res = a.v ? b : new GCSignal(false);
+		else if (b.isPublic())
+			res = b.v ? a : new GCSignal(false);
+		else {
+			++numOfAnds;
+			if (Flag.offline) {
+				res = readGateFromFile();
+			} else {
+				res = garble(a, b);
+				writeGateToFile(res);
+				if (gid % 100000 == 0) {
+					System.out.println(gid);
+				}
+			}
+			sendGTT();
+			gid++;
+			gatesRemain = true;
+		}
+		Flag.sw.stopGC();
+		return res;
+	}
+
+	@Override
+	public void setEvaluate() {
+		// TODO Auto-generated method stub
+
+	}
+
+}

+ 36 - 0
ObliVMGC/com/oblivm/backend/gc/offline/Garbler.java

@@ -0,0 +1,36 @@
+package com.oblivm.backend.gc.offline;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+
+import com.oblivm.backend.gc.GCSignal;
+
+final class Garbler {
+	private MessageDigest sha1 = null;
+
+	Garbler() {
+		try {
+			sha1 = MessageDigest.getInstance("SHA-1");
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	public GCSignal enc(GCSignal lb0, GCSignal lb1, long k, GCSignal m) {
+		return getPadding(lb0, lb1, k).xor(m);
+	}
+
+	public GCSignal dec(GCSignal lb0, GCSignal lb1, long k, GCSignal c) {
+		return getPadding(lb0, lb1, k).xor(c);
+	}
+
+	ByteBuffer buffer = ByteBuffer.allocate(GCSignal.len * 2 + 8);
+
+	private GCSignal getPadding(GCSignal lb0, GCSignal lb1, long k) {
+		buffer.clear();
+		sha1.update((buffer.put(lb0.bytes).put(lb1.bytes).putLong(k)));
+		GCSignal ret = GCSignal.newInstance(sha1.digest());
+		return ret;
+	}
+}

+ 34 - 0
ObliVMGC/com/oblivm/backend/gc/offline/TestGarbler.java

@@ -0,0 +1,34 @@
+package com.oblivm.backend.gc.offline;
+
+import java.security.SecureRandom;
+
+import org.junit.Test;
+
+import com.oblivm.backend.gc.GCSignal;
+
+public class TestGarbler {
+	SecureRandom rnd = new SecureRandom();
+	GCSignal a = GCSignal.freshLabel(rnd);
+	GCSignal b = GCSignal.freshLabel(rnd);
+	GCSignal m = GCSignal.freshLabel(rnd);
+	Garbler gb = new Garbler();
+
+	public void test() {
+		gb.enc(a, b, 0, m);
+	}
+
+	@Test
+	public void test1000() {
+		double t1 = System.nanoTime();
+		int len = 1000000;
+		for (int i = 0; i < len; i++)
+			test();
+		double t2 = System.nanoTime();
+		System.out.println(len / (t2 - t1) * 1000000000.0);
+	}
+
+	public static void main(String[] args) {
+		TestGarbler a = new TestGarbler();
+		a.test1000();
+	}
+}

+ 88 - 0
ObliVMGC/com/oblivm/backend/gc/regular/GCEva.java

@@ -0,0 +1,88 @@
+package com.oblivm.backend.gc.regular;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.gc.GCEvaComp;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class GCEva extends GCEvaComp {
+	Garbler gb;
+	GCSignal[][] gtt = new GCSignal[2][2];
+
+	boolean evaluate = false;
+	GCEva next = null;
+	GCEva curr = null;
+
+	public GCEva(Network channel) {
+		super(channel, Mode.REAL);
+		gb = new Garbler();
+		gtt[0][0] = GCSignal.ZERO;
+		gtt[0][1] = GCSignal.newInstance(new byte[10]);
+		gtt[1][0] = GCSignal.newInstance(new byte[10]);
+		gtt[1][1] = GCSignal.newInstance(new byte[10]);
+	}
+
+	public GCEva(GCEva env) {
+		super(env.channel, Mode.REAL);
+		gb = new Garbler();
+		gtt[0][0] = GCSignal.ZERO;
+		gtt[0][1] = GCSignal.newInstance(new byte[10]);
+		gtt[1][0] = GCSignal.newInstance(new byte[10]);
+		gtt[1][1] = GCSignal.newInstance(new byte[10]);
+	}
+
+	public void setEvaluate() {
+		evaluate = true;
+		curr = this;
+	}
+
+	private void receiveGTT() {
+		try {
+			Flag.sw.startGCIO();
+			GCSignal.receive(channel, gtt[0][1]);
+			GCSignal.receive(channel, gtt[1][0]);
+			GCSignal.receive(channel, gtt[1][1]);
+			// gtt[1][0] = GCSignal.receive(channel);
+			// gtt[1][1] = GCSignal.receive(channel);
+			Flag.sw.stopGCIO();
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	public GCSignal and(GCSignal a, GCSignal b) {
+		Flag.sw.startGC();
+
+		GCSignal res;
+		if (a.isPublic() && b.isPublic())
+			res = new GCSignal(a.v && b.v);
+		else if (a.isPublic())
+			res = a.v ? b : new GCSignal(false);
+		else if (b.isPublic())
+			res = b.v ? a : new GCSignal(false);
+		else {
+			res = new GCSignal(new byte[10]);
+			if (!evaluate) {
+				++numOfAnds;
+
+				if (curr == null) {
+					curr = this;
+				} else {
+					curr.next = new GCEva(this);
+					curr = curr.next;
+				}
+				curr.receiveGTT();
+			} else {
+				int i0 = a.getLSB();
+				int i1 = b.getLSB();
+				gb.dec(a, b, gid, curr.gtt[i0][i1], res);
+				curr = curr.next;
+				gid++;
+			}
+		}
+		Flag.sw.stopGC();
+		return res;
+	}
+}

+ 99 - 0
ObliVMGC/com/oblivm/backend/gc/regular/GCGen.java

@@ -0,0 +1,99 @@
+package com.oblivm.backend.gc.regular;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.gc.GCGenComp;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class GCGen extends GCGenComp {
+	Garbler gb;
+
+	public GCGen(Network channel) {
+		super(channel, Mode.REAL);
+		gb = new Garbler();
+		for (int i = 0; i < 2; ++i) {
+			labelL[i] = new GCSignal(new byte[10]);
+			labelR[i] = new GCSignal(new byte[10]);
+			lb[i] = new GCSignal(new byte[10]);
+			toSend[0][i] = new GCSignal(new byte[10]);
+			toSend[1][i] = new GCSignal(new byte[10]);
+		}
+	}
+
+	private GCSignal[][] gtt = new GCSignal[2][2];
+	private GCSignal[][] toSend = new GCSignal[2][2];
+	private GCSignal labelL[] = new GCSignal[2];
+	private GCSignal labelR[] = new GCSignal[2];
+	private GCSignal[] lb = new GCSignal[2];
+
+	private GCSignal garble(GCSignal a, GCSignal b) {
+		labelL[0] = a;
+		GCSignal.xor(R, labelL[0], labelL[1]);
+		labelR[0] = b;
+		GCSignal.xor(R, labelR[0], labelR[1]);
+
+		int cL = a.getLSB();
+		int cR = b.getLSB();
+
+		gb.enc(labelL[cL], labelR[cR], gid, GCSignal.ZERO, lb[cL & cR]);
+		GCSignal.xor(R, lb[cL & cR], lb[1 - (cL & cR)]);
+
+		gtt[0 ^ cL][0 ^ cR] = lb[0];
+		gtt[0 ^ cL][1 ^ cR] = lb[0];
+		gtt[1 ^ cL][0 ^ cR] = lb[0];
+		gtt[1 ^ cL][1 ^ cR] = lb[1];
+
+		if (cL != 0 || cR != 0)
+			gb.enc(labelL[0], labelR[0], gid, gtt[0 ^ cL][0 ^ cR], toSend[0 ^ cL][0 ^ cR]);
+		if (cL != 0 || cR != 1)
+			gb.enc(labelL[0], labelR[1], gid, gtt[0 ^ cL][1 ^ cR], toSend[0 ^ cL][1 ^ cR]);
+		if (cL != 1 || cR != 0)
+			gb.enc(labelL[1], labelR[0], gid, gtt[1 ^ cL][0 ^ cR], toSend[1 ^ cL][0 ^ cR]);
+		if (cL != 1 || cR != 1)
+			gb.enc(labelL[1], labelR[1], gid, gtt[1 ^ cL][1 ^ cR], toSend[1 ^ cL][1 ^ cR]);
+
+		return GCSignal.newInstance(lb[0].bytes);
+	}
+
+	private void sendGTT() {
+		try {
+			Flag.sw.startGCIO();
+			toSend[0][1].send(channel);
+			toSend[1][0].send(channel);
+			toSend[1][1].send(channel);
+			Flag.sw.stopGCIO();
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	public GCSignal and(GCSignal a, GCSignal b) {
+		Flag.sw.startGC();
+		GCSignal res;
+		if (a.isPublic() && b.isPublic())
+			res = ((a.v && b.v) ? new GCSignal(true) : new GCSignal(false));
+		else if (a.isPublic())
+			res = a.v ? b : new GCSignal(false);
+		else if (b.isPublic())
+			res = b.v ? a : new GCSignal(false);
+		else {
+			++numOfAnds;
+			GCSignal ret;
+			ret = garble(a, b);
+
+			sendGTT();
+			gid++;
+			gatesRemain = true;
+			res = ret;
+		}
+		Flag.sw.stopGC();
+		return res;
+	}
+
+	@Override
+	public void setEvaluate() {
+	}
+
+}

+ 37 - 0
ObliVMGC/com/oblivm/backend/gc/regular/Garbler.java

@@ -0,0 +1,37 @@
+package com.oblivm.backend.gc.regular;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+
+import com.oblivm.backend.gc.GCSignal;
+
+final class Garbler {
+	private MessageDigest sha1 = null;
+
+	Garbler() {
+		try {
+			sha1 = MessageDigest.getInstance("SHA-1");
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	public void enc(GCSignal lb0, GCSignal lb1, long k, GCSignal m, GCSignal ret) {
+		getPadding(lb0, lb1, k, ret);
+		GCSignal.xor(ret, m, ret);
+	}
+
+	public void dec(GCSignal lb0, GCSignal lb1, long k, GCSignal c, GCSignal ret) {
+		getPadding(lb0, lb1, k, ret);
+		GCSignal.xor(ret, c, ret);
+	}
+
+	ByteBuffer buffer = ByteBuffer.allocate(GCSignal.len * 2 + 8);
+
+	private void getPadding(GCSignal lb0, GCSignal lb1, long k, GCSignal ret) {
+		buffer.clear();
+		sha1.update((buffer.put(lb0.bytes).put(lb1.bytes).putLong(k)));
+		System.arraycopy(sha1.digest(), 0, ret.bytes, 0, GCSignal.len);
+	}
+}

+ 28 - 0
ObliVMGC/com/oblivm/backend/gc/regular/TestGarbler.java

@@ -0,0 +1,28 @@
+package com.oblivm.backend.gc.regular;
+
+import java.security.SecureRandom;
+
+import org.junit.Test;
+
+import com.oblivm.backend.gc.GCSignal;
+
+public class TestGarbler {
+	SecureRandom rnd = new SecureRandom();
+	GCSignal a = GCSignal.freshLabel(rnd);
+	GCSignal b = GCSignal.freshLabel(rnd);
+	GCSignal m = GCSignal.freshLabel(rnd);
+	GCSignal ret = GCSignal.freshLabel(rnd);
+	Garbler gb = new Garbler();
+
+	public void test() {
+		gb.enc(a, b, 0, m, ret);
+
+		// Assert.assertTrue(m.equals(gb.dec(a, b, 0L, gb.enc(a, b, 0L, m))));
+	}
+
+	@Test
+	public void test1000() {
+		for (int i = 0; i < 10000; i++)
+			test();
+	}
+}

+ 35 - 0
ObliVMGC/com/oblivm/backend/lang/inter/BoxedInt.java

@@ -0,0 +1,35 @@
+package com.oblivm.backend.lang.inter;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.IWritable;
+
+public class BoxedInt<T1> implements IWritable<BoxedInt<T1>, T1> {
+	public T1[] value;
+	public CompEnv<T1> env;
+
+	public BoxedInt(CompEnv<T1> env, T1[] data) {
+		this.value = data;
+		this.env = env;
+	}
+
+	public BoxedInt(CompEnv<T1> env, T1 data) {
+		this.value = env.newTArray(1);
+		this.value[0] = data;
+		this.env = env;
+	}
+
+	@Override
+	public int numBits() {
+		return value.length;
+	}
+
+	@Override
+	public T1[] getBits() {
+		return value;
+	}
+
+	@Override
+	public BoxedInt<T1> newObj(T1[] data) throws Exception {
+		return new BoxedInt<T1>(env, data);
+	}
+}

+ 56 - 0
ObliVMGC/com/oblivm/backend/lang/inter/Cmd.java

@@ -0,0 +1,56 @@
+/***
+ * Copyright (C) 2015 by Chang Liu <liuchang@cs.umd.edu>
+ */
+package com.oblivm.backend.lang.inter;
+
+import net.sourceforge.argparse4j.ArgumentParsers;
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+import net.sourceforge.argparse4j.inf.ArgumentParserException;
+import net.sourceforge.argparse4j.inf.Namespace;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.util.EvaRunnable;
+import com.oblivm.backend.util.GenRunnable;
+
+/**
+ * A single entry point to call EvaRunnable and GenRunnable. This class should
+ * be used as the entry point for the jar file.
+ *
+ */
+public class Cmd {
+
+	@SuppressWarnings("rawtypes")
+	public static void main(String[] args) throws Exception {
+		ArgumentParser ap = ArgumentParsers.newArgumentParser("Cmd");
+		ap.addArgument("file").nargs("*").help("File to compile");
+		ap.addArgument("--config").setDefault("Config.conf").help("Config file");
+		ap.addArgument("-la", "--lenghAlice").help("input length of Alice");
+		ap.addArgument("-t", "--type").choices("gen", "eva").setDefault("gen")
+				.help("Whether it is the generator or the evaluator");
+		ap.addArgument("-i", "--input").help("Input file");
+		ap.addArgument("-c", "--class").help("Runnable Class");
+		Namespace ns = null;
+		try {
+			ns = ap.parseArgs(args);
+		} catch (ArgumentParserException e) {
+			ap.handleError(e);
+			System.exit(1);
+		}
+
+		if (ns.getString("type").equals("gen")) {
+			GenRunnable gen = new MainRunnable.Generator(ns.getString("class"), ns.getString("input"));
+			gen.loadConfig(ns.getString("config"));
+			gen.runCore();
+			if (Flag.CountTime)
+				Flag.sw.print();
+		} else {
+			EvaRunnable eva = new MainRunnable.Evaluator(ns.getString("class"), ns.getString("input"));
+			eva.loadConfig(ns.getString("config"));
+			eva.runCore();
+			if (Flag.CountTime)
+				Flag.sw.print();
+			if (Flag.countIO)
+				eva.printStatistic();
+		}
+	}
+}

+ 8 - 0
ObliVMGC/com/oblivm/backend/lang/inter/ISecureRunnable.java

@@ -0,0 +1,8 @@
+/***
+ * Copyright (C) 2015 by Chang Liu <liuchang@cs.umd.edu>
+ */
+package com.oblivm.backend.lang.inter;
+
+public interface ISecureRunnable<T> {
+	public T[] main(int lenA, int lenB, T[] x, T[] y) throws Exception;
+}

+ 14 - 0
ObliVMGC/com/oblivm/backend/lang/inter/Input.java

@@ -0,0 +1,14 @@
+/***
+ * Copyright (C) 2015 by Chang Liu <liuchang@cs.umd.edu>
+ */
+package com.oblivm.backend.lang.inter;
+
+public interface Input {
+	public boolean nextBoolean();
+
+	public boolean[] readAll();
+
+	public boolean isEnd();
+
+	public boolean closed();
+}

+ 138 - 0
ObliVMGC/com/oblivm/backend/lang/inter/MainRunnable.java

@@ -0,0 +1,138 @@
+package com.oblivm.backend.lang.inter;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+
+import com.oblivm.backend.flexsc.CompEnv;
+/***
+ * Copyright (C) 2015 by Chang Liu <liuchang@cs.umd.edu>
+ */
+import com.oblivm.backend.gc.BadLabelException;
+import com.oblivm.backend.lang.inter.input.BitFileInput;
+import com.oblivm.backend.util.EvaRunnable;
+import com.oblivm.backend.util.GenRunnable;
+import com.oblivm.backend.util.Utils;
+
+public class MainRunnable {
+
+	public static class Generator<T> extends GenRunnable<T> {
+		public Input inputAlice;
+		public String className;
+		public int lenA, lenB;
+
+		public Generator(String className, String aliceInputFile) {
+			this.className = className;
+			try {
+				inputAlice = BitFileInput.open(aliceInputFile);
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+
+		ISecureRunnable<T> runnable;
+
+		T[] inputA;
+		T[] inputB;
+		T[] scResult;
+
+		@SuppressWarnings("unchecked")
+		@Override
+		public void prepareInput(CompEnv<T> env) {
+			try {
+				Class<?> cl = Class.forName(className);
+				Constructor<?> ctor = cl.getConstructors()[0];
+				runnable = (ISecureRunnable<T>) ctor.newInstance(env);
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+			boolean[] in = inputAlice.readAll();
+			lenA = in.length;
+			lenB = 0;
+			try {
+				os.write(Utils.toByte(lenA));
+				os.flush();
+				lenB = Utils.fromByte(this.readBytes(4));
+				this.flush();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			inputA = env.inputOfAlice(in);
+			env.flush();
+			inputB = env.inputOfBob(new boolean[lenB]);
+
+			// System.out.println("LenA="+lenA+"\tLenB="+lenB);
+		}
+
+		@Override
+		public void secureCompute(CompEnv<T> env) throws Exception {
+			scResult = runnable.main(lenA, lenB, inputA, inputB);
+		}
+
+		@Override
+		public void prepareOutput(CompEnv<T> gen) throws Exception {
+			System.out.println(Utils.toInt(gen.outputToAlice(scResult)));
+			gen.channel.os.write(new byte[] { 0 });
+			gen.flush();
+		}
+
+	}
+
+	public static class Evaluator<T> extends EvaRunnable<T> {
+		public Input inputBob;
+		public String className;
+		public int lenA, lenB;
+
+		public Evaluator(String className, String bobInputFile) {
+			this.className = className;
+			try {
+				inputBob = BitFileInput.open(bobInputFile);
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+
+		ISecureRunnable<T> runnable;
+
+		T[] inputA;
+		T[] inputB;
+		T[] scResult;
+
+		@SuppressWarnings("unchecked")
+		@Override
+		public void prepareInput(CompEnv<T> env) {
+			boolean[] in = inputBob.readAll();
+			lenA = 0;
+			lenB = in.length;
+			try {
+				lenA = Utils.fromByte(this.readBytes(4));
+				os.write(Utils.toByte(lenB));
+				os.flush();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			try {
+				Class<?> cl = Class.forName(className);
+				Constructor<?> ctor = cl.getConstructors()[0];
+				runnable = (ISecureRunnable<T>) ctor.newInstance(env);
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+			inputA = env.inputOfAlice(new boolean[lenA]);
+			env.flush();
+			inputB = env.inputOfBob(in);
+		}
+
+		@Override
+		public void secureCompute(CompEnv<T> env) throws Exception {
+			scResult = runnable.main(lenA, lenB, inputA, inputB);
+		}
+
+		@Override
+		public void prepareOutput(CompEnv<T> env) throws Exception {
+			env.outputToAlice(scResult);
+			env.channel.is.read(new byte[] { 0 });
+			env.flush();
+		}
+	}
+
+}

+ 65 - 0
ObliVMGC/com/oblivm/backend/lang/inter/NullableType.java

@@ -0,0 +1,65 @@
+package com.oblivm.backend.lang.inter;
+
+import com.oblivm.backend.circuits.arithmetic.IntegerLib;
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.IWritable;
+import com.oblivm.backend.flexsc.Mode;
+
+public class NullableType<T1, T2 extends IWritable<T2, T1>> implements IWritable<NullableType<T1, T2>, T1> {
+	public T1 isNull;
+	public T2 value;
+	public CompEnv<T1> env;
+	public IntegerLib<T1> intLib;
+
+	public NullableType(CompEnv<T1> env, T2 data, T1 isNull) {
+		this.value = data;
+		this.isNull = isNull;
+		this.env = env;
+		this.intLib = new IntegerLib<T1>(env);
+	}
+
+	@Override
+	public int numBits() {
+		return value.numBits() + 1;
+	}
+
+	@Override
+	public T1[] getBits() throws Exception {
+		T1[] ret = env.newTArray(numBits());
+		ret[0] = isNull;
+		System.arraycopy(value.getBits(), 0, ret, 1, ret.length - 1);
+		return ret;
+	}
+
+	@Override
+	public NullableType<T1, T2> newObj(T1[] data) throws Exception {
+		T1[] ret = env.newTArray(data.length - 1);
+		System.arraycopy(data, 1, ret, 0, ret.length);
+		return new NullableType<T1, T2>(env, value.newObj(ret), data[0]);
+	}
+
+	public NullableType<T1, T2> mux(T1 is, NullableType<T1, T2> obj) throws Exception {
+		if (env.mode == Mode.COUNT) {
+			intLib.mux(value.getBits(), obj.value.getBits(), is);
+			intLib.mux(isNull, obj.isNull, is);
+			return this;
+		}
+		return new NullableType<T1, T2>(env, value.newObj(intLib.mux(value.getBits(), obj.getBits(), is)),
+				intLib.mux(isNull, obj.isNull, is));
+	}
+
+	public T2 muxFake() throws Exception {
+		if (env.mode == Mode.COUNT) {
+			intLib.mux(value.getBits(), getFake().getBits(), isNull);
+			return value;
+		}
+		return value.newObj(intLib.mux(value.getBits(), getFake().getBits(), isNull));
+	}
+
+	public T2 getFake() throws Exception {
+		if (env.mode == Mode.COUNT) {
+			return value;
+		}
+		return value.fake();
+	}
+}

+ 36 - 0
ObliVMGC/com/oblivm/backend/lang/inter/Util.java

@@ -0,0 +1,36 @@
+package com.oblivm.backend.lang.inter;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+
+import com.oblivm.backend.circuits.arithmetic.IntegerLib;
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.oram.SecureArray;
+import com.oblivm.backend.util.Utils;
+
+public class Util {
+	public static <T> T[][] intToArray(T[] intInput, int bitSize, int arraySize) {
+		@SuppressWarnings("unchecked")
+		T[][] ret = (T[][]) Array.newInstance((Class<T>) intInput[0].getClass(), arraySize, bitSize);
+		for (int i = 0; i < arraySize; ++i) {
+			for (int j = 0; j < bitSize; ++j) {
+				ret[i][j] = intInput[i * bitSize + j];
+			}
+		}
+		return ret;
+	}
+
+	public static <T> SecureArray<T> intToSecArray(CompEnv<T> env, T[] intInput, int bitSize, int arraySize)
+			throws Exception {
+		SecureArray<T> secArray = new SecureArray<T>(env, arraySize, bitSize);
+		IntegerLib<T> intLib = new IntegerLib<T>(env);
+		for (int i = 0; i < arraySize; ++i) {
+			secArray.write(intLib.toSignals(i), Arrays.copyOfRange(intInput, i * bitSize, (i + 1) * bitSize));
+		}
+		// for(int i=0; i<arraySize; ++i) {
+		// System.out.println("Input["+i+"] =
+		// "+Utils.toInt(env.outputToAlice(secArray.read(intLib.toSignals(i)))));
+		// }
+		return secArray;
+	}
+}

+ 72 - 0
ObliVMGC/com/oblivm/backend/lang/inter/input/BitFileInput.java

@@ -0,0 +1,72 @@
+/***
+ * Copyright (C) 2015 by Chang Liu <liuchang@cs.umd.edu>
+ */
+package com.oblivm.backend.lang.inter.input;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.stream.IntStream;
+
+import com.oblivm.backend.lang.inter.Input;
+
+/**
+ * @author Chang Liu
+ *
+ */
+public class BitFileInput implements Input {
+
+	private boolean[] array;
+	private int current = 0;
+
+	public static BitFileInput open(File file) throws IOException {
+		BitFileInput input = new BitFileInput();
+		BufferedReader binput = new BufferedReader(new FileReader(file));
+		String str;
+		StringBuffer sb = new StringBuffer();
+		while ((str = binput.readLine()) != null) {
+			sb.append(str);
+		}
+		binput.close();
+		IntStream ins = sb.toString().chars();
+		int[] a = ins.toArray();
+		input.array = new boolean[a.length];
+		for (int i = 0; i < a.length; ++i) {
+			input.array[i] = a[i] == '1';
+		}
+		input.current = 0;
+		return input;
+	}
+
+	private BitFileInput() {
+
+	}
+
+	@Override
+	public boolean nextBoolean() {
+		if (current >= array.length)
+			return false;
+		return array[current++];
+	}
+
+	@Override
+	public boolean[] readAll() {
+		return array;
+	}
+
+	@Override
+	public boolean isEnd() {
+		return current >= array.length;
+	}
+
+	@Override
+	public boolean closed() {
+		return current >= array.length;
+	}
+
+	public static BitFileInput open(String path) throws IOException {
+		return open(new File(path));
+	}
+
+}

+ 53 - 0
ObliVMGC/com/oblivm/backend/network/Client.java

@@ -0,0 +1,53 @@
+package com.oblivm.backend.network;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+
+import org.apache.commons.io.input.CountingInputStream;
+import org.apache.commons.io.output.CountingOutputStream;
+
+import com.oblivm.backend.flexsc.Flag;
+
+public class Client extends Network {
+
+	CountingOutputStream cos;
+	CountingInputStream cis;
+
+	public void connect(String server, int port) throws InterruptedException {
+		try {
+			while (true) {
+				try {
+					sock = new java.net.Socket(server, port); // create socket
+																// and
+					// connect
+					if (sock != null)
+						break;
+				} catch (IOException e) {
+					Thread.sleep(10);
+				}
+			}
+			if (Flag.countIO) {
+				cos = new CountingOutputStream(sock.getOutputStream());
+				cis = new CountingInputStream(sock.getInputStream());
+				os = new BufferedOutputStream(cos);
+				is = new BufferedInputStream(cis);
+			} else {
+				os = new BufferedOutputStream(sock.getOutputStream());
+				is = new BufferedInputStream(sock.getInputStream());
+
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		setUpThread();
+	}
+
+	public void printStatistic() {
+		if (Flag.countIO) {
+			System.out.println("\n********************************\n" + "Data Sent from Client :"
+					+ cos.getByteCount() / 1024.0 / 1024.0 + "MB\n" + "Data Sent to Client :"
+					+ cis.getByteCount() / 1024.0 / 1024.0 + "MB" + "\n********************************");
+		}
+	}
+}

+ 47 - 0
ObliVMGC/com/oblivm/backend/network/CustomizedConcurrentQueue.java

@@ -0,0 +1,47 @@
+package com.oblivm.backend.network;
+
+public class CustomizedConcurrentQueue {
+	int capacity;
+	int size = 0;
+	byte[] data;
+	boolean finished = false;
+
+	public CustomizedConcurrentQueue(int capacity) {
+		this.capacity = capacity;
+		data = new byte[capacity];
+	}
+
+	public void destory() {
+		finished = true;
+	}
+
+	public void insert(byte[] in) {
+		while (in.length + atomic(null, 3) > capacity) {
+		}
+		atomic(in, 1);
+	}
+
+	public synchronized int atomic(byte[] in, int op) {
+		if (op == 1) {
+			System.arraycopy(in, 0, data, size, in.length);
+			size += in.length;
+			return 0;
+		} else if (op == 3) {
+			return size;
+		} else {
+			System.arraycopy(data, 0, in, 0, size);
+			int oldsize = size;
+			size = 0;
+			return oldsize;
+		}
+	}
+
+	public int pop(byte[] d) {
+		int res = atomic(d, 2);
+		if (res == 0 && finished) {
+			// System.out.println("!");
+			return -1;
+		} else
+			return res;
+	}
+}

+ 55 - 0
ObliVMGC/com/oblivm/backend/network/CustomizedConcurrentQueue2.java

@@ -0,0 +1,55 @@
+package com.oblivm.backend.network;
+
+public class CustomizedConcurrentQueue2 {
+	int capacity;
+	int head = 0;
+	int tail = 0;
+	byte[] data;
+	boolean finished = false;
+
+	public CustomizedConcurrentQueue2(int capacity) {
+		this.capacity = capacity;
+		data = new byte[capacity];
+	}
+
+	public void destory() {
+		finished = true;
+	}
+
+	public int insert(byte[] in) {
+		int remains = capacity - head;
+		if (remains >= in.length) {
+			System.arraycopy(in, 0, data, head, in.length);
+			head += in.length;
+		} else {
+			System.arraycopy(in, 0, data, head, remains);
+			System.arraycopy(in, remains, data, 0, in.length - remains);
+			head = in.length - remains;
+		}
+		return 0;
+	}
+
+	synchronized public int pop(byte[] d) {
+		int h = head;
+		int size = (h - tail + capacity) % capacity;
+		// if(h != 0)
+		// System.out.println(h+" "+size+" "+tail+" "+size);
+		if (finished && size == 0)
+			return -1;
+
+		if (size == 0)
+			return 0;
+		// System.out.println(size);
+
+		if (h > tail) {
+			System.arraycopy(data, tail, d, 0, h - tail);
+		} else {
+			System.arraycopy(data, tail, d, 0, capacity - tail);
+			System.arraycopy(data, 0, d, capacity - tail, h);
+		}
+		// System.out.println("!!");
+
+		tail = h;
+		return size;
+	}
+}

+ 249 - 0
ObliVMGC/com/oblivm/backend/network/Network.java

@@ -0,0 +1,249 @@
+package com.oblivm.backend.network;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.gc.GCSignal;
+
+public class Network {
+	protected Socket sock;
+	protected ServerSocket serverSock;
+	public CustomizedConcurrentQueue queue;
+	ThreadedIO threadedio;
+	public InputStream is;
+	public OutputStream os;
+	Thread thd;
+	boolean THREADEDIO = true;
+	static int NetworkThreadedQueueSize = 1024 * 256;
+
+	public void setUpThread() {
+		if (THREADEDIO) {
+			queue = new CustomizedConcurrentQueue(NetworkThreadedQueueSize);
+			threadedio = new ThreadedIO(queue, os);
+			thd = new Thread(threadedio);
+			thd.start();
+		}
+	}
+
+	public Network() {
+
+	}
+
+	public Network(InputStream is, OutputStream os, Socket sock) {
+		this.is = is;
+		this.os = os;
+		this.sock = sock;
+	}
+
+	public void disconnect() {
+		try {
+			if (THREADEDIO) {
+				queue.destory();
+				os.flush();
+				thd.join();
+
+			}
+			os.flush();
+			// protocol payloads are received.
+			if (sock != null) {
+				sock.close();
+			}
+			if (serverSock != null) {
+				serverSock.close();
+			}
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	public void flush() {
+		try {
+			os.flush();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	public byte[] readBytes(int len) {
+		byte[] temp = new byte[len];
+		try {
+			int remain = len;
+			while (0 < remain) {
+				int readBytes;
+
+				readBytes = is.read(temp, len - remain, remain);
+				if (readBytes != -1) {
+					remain -= readBytes;
+				}
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return temp;
+	}
+
+	public void readBytes(byte[] temp) {
+		// byte[] temp = new byte[len];
+		try {
+			int remain = temp.length;
+			while (0 < remain) {
+				int readBytes;
+
+				readBytes = is.read(temp, temp.length - remain, remain);
+				if (readBytes != -1) {
+					remain -= readBytes;
+				}
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	public byte[] readBytes() {
+		byte[] lenBytes = readBytes(4);
+		int len = ByteBuffer.wrap(lenBytes).getInt();
+		return readBytes(len);
+	}
+
+	public void writeByte(byte[] data) {
+		writeByte(ByteBuffer.allocate(4).putInt(data.length).array(), 4);
+		writeByte(data, data.length);
+	}
+
+	public void writeByte(byte[] data, int length) {
+		try {
+			if (THREADEDIO) {
+				queue.insert(data);
+				// System.out.println(data.length);
+			} else {
+				os.write(data);
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	public void writeByte(byte data) {
+		try {
+			if (THREADEDIO)
+				queue.insert(new byte[] { data });
+			else {
+				os.write(data);
+			}
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	public void writeBI(BigInteger bi) {
+		writeByte(bi.toByteArray());
+	}
+
+	public BigInteger readBI() {
+		byte[] rep = readBytes();
+
+		return new BigInteger(rep);
+	}
+
+	public void writeInt(int i) {
+		writeByte(ByteBuffer.allocate(4).putInt(i).array(), 4);
+	}
+
+	public int readInt() {
+		return ByteBuffer.wrap(readBytes(4)).getInt();
+	}
+
+	public <T> void send(T[][][] data, CompEnv<T> env) throws IOException {
+		for (int i = 0; i < data.length; i++) {
+			send(data[i], env);
+		}
+	}
+
+	public <T> void send(T[][] data, CompEnv<T> env) throws IOException {
+		for (int i = 0; i < data.length; i++) {
+			send(data[i], env);
+		}
+	}
+
+	public <T> T[][] read(int length1, int length2, CompEnv<T> env) throws IOException {
+		T[][] ret = env.newTArray(length1, 1);
+		for (int i = 0; i < length1; i++) {
+			ret[i] = read(length2, env);
+		}
+		return ret;
+	}
+
+	public <T> T[][][] read(int length1, int length2, int length3, CompEnv<T> env) throws IOException {
+		T[][][] ret = env.newTArray(length1, 1, 1);
+		for (int i = 0; i < length1; i++) {
+			ret[i] = read(length2, length3, env);
+		}
+		return ret;
+	}
+
+	public <T> void send(T[] data, CompEnv<T> env) throws IOException {
+		for (int i = 0; i < data.length; i++) {
+			send(data[i], env);
+		}
+	}
+
+	public <T> void send(T data, CompEnv<T> env) throws IOException {
+		Mode mode = env.getMode();
+		if (mode == Mode.REAL) {
+			GCSignal gcData = (GCSignal) data;
+			gcData.send(this);
+		} else if (mode == Mode.VERIFY) {
+			writeBoolean((Boolean) data);
+		} else if (mode == Mode.COUNT) {
+
+		}
+	}
+
+	public <T> T[] read(int length, CompEnv<T> env) throws IOException {
+		T[] ret = env.newTArray(length);
+		for (int i = 0; i < length; i++) {
+			ret[i] = read(env);
+		}
+		return ret;
+	}
+
+	@SuppressWarnings("unchecked")
+	public <T> T read(CompEnv<T> env) throws IOException {
+		Mode mode = env.getMode();
+		if (mode == Mode.REAL || mode == Mode.OPT || mode == Mode.OFFLINE) {
+			GCSignal signal = GCSignal.receive(this);
+			return (T) signal;
+		} else if (mode == Mode.VERIFY) {
+			Boolean vData = readBoolean();
+			return (T) vData;
+		} else if (mode == Mode.COUNT) {
+			return env.ZERO();
+		}
+		// shouldn't happen;
+		return null;
+	}
+
+	public boolean readBoolean() throws IOException {
+		int read = readInt();
+		return read == 1;
+	}
+
+	public void writeBoolean(boolean data) throws IOException {
+		int sen = data ? 1 : 0;
+		writeInt(sen);
+	}
+}

+ 23 - 0
ObliVMGC/com/oblivm/backend/network/Server.java

@@ -0,0 +1,23 @@
+package com.oblivm.backend.network;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.net.ServerSocket;
+
+public class Server extends Network {
+
+	public void listen(int port) {
+		try {
+			serverSock = new ServerSocket(port);
+			sock = serverSock.accept(); // wait for client to connect
+
+			os = new BufferedOutputStream(sock.getOutputStream());
+			is = new BufferedInputStream(sock.getInputStream());
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} // create socket and bind to port
+		setUpThread();
+	}
+}

+ 34 - 0
ObliVMGC/com/oblivm/backend/network/ThreadedIO.java

@@ -0,0 +1,34 @@
+package com.oblivm.backend.network;
+
+import java.io.OutputStream;
+
+public class ThreadedIO implements Runnable {
+	public CustomizedConcurrentQueue queue;
+	OutputStream os;
+
+	public ThreadedIO(CustomizedConcurrentQueue queue2, OutputStream os) {
+		this.queue = queue2;
+		this.os = os;
+	}
+
+	byte[] res = new byte[Network.NetworkThreadedQueueSize];
+
+	public void run() {
+		try {
+			while (true) {
+				int len = queue.pop(res);
+				if (len == -1)
+					return;
+				if (len != 0) {
+					os.write(res, 0, len);
+					os.flush();
+				}
+			}
+
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+}

+ 27 - 0
ObliVMGC/com/oblivm/backend/oram/Block.java

@@ -0,0 +1,27 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import java.util.Arrays;
+
+public class Block<T> {
+
+	public T[] iden;
+	public T[] pos;
+	public T[] data;
+	public T isDummy;
+
+	public Block(T[] iden, T[] pos, T[] data, T isDummy) {
+		this.iden = iden;
+		this.pos = pos;
+		this.data = data;
+		this.isDummy = isDummy;
+	}
+
+	public Block(T[] Tarray, int lengthOfIden, int lengthOfPos, int lengthOfData) {
+		iden = Arrays.copyOfRange(Tarray, 0, lengthOfIden);
+		pos = Arrays.copyOfRange(Tarray, lengthOfIden, lengthOfIden + lengthOfPos);
+		data = Arrays.copyOfRange(Tarray, lengthOfIden + lengthOfPos, lengthOfIden + lengthOfPos + lengthOfData);
+		isDummy = Tarray[Tarray.length - 1];
+	}
+
+}

+ 184 - 0
ObliVMGC/com/oblivm/backend/oram/BucketLib.java

@@ -0,0 +1,184 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import com.oblivm.backend.circuits.BitonicSortLib;
+import com.oblivm.backend.flexsc.CompEnv;
+
+public class BucketLib<T> extends BitonicSortLib<T> {
+	public Block<T> dummyBlock;
+	protected int lengthOfIden;
+	protected int lengthOfPos;
+	protected int lengthOfData;
+
+	public BucketLib(int lengthOfIden, int lengthOfPos, int lengthOfData, CompEnv<T> e) {
+		super(e);
+		this.lengthOfData = lengthOfData;
+		this.lengthOfIden = lengthOfIden;
+		this.lengthOfPos = lengthOfPos;
+		dummyBlock = new Block<T>(zeros(lengthOfIden), zeros(lengthOfPos), zeros(lengthOfData), SIGNAL_ONE);
+	}
+
+	public T isFull(Block<T>[] bucket) {
+		T res = SIGNAL_ONE;
+		for (int i = 0; i < bucket.length; ++i) {
+			res = and(res, not(bucket[i].isDummy));
+		}
+		return res;
+	}
+
+	public T isEmpty(Block<T>[] bucket) {
+		T res = SIGNAL_ONE;
+		for (int i = 0; i < bucket.length; ++i) {
+			res = and(res, bucket[i].isDummy);
+		}
+		return res;
+	}
+
+	public Block<T> conditionalReadAndRemove(Block<T>[] bucket, T[] iden, T condition) {
+		Block<T> result = dummyBlock;
+		for (int i = 0; i < bucket.length; ++i) {
+			T match = eq(iden, bucket[i].iden);
+			match = and(match, not(bucket[i].isDummy));
+			match = and(match, condition);
+			result = mux(result, bucket[i], match);
+			bucket[i].isDummy = mux(bucket[i].isDummy, SIGNAL_ONE, match);
+		}
+		return result;
+	}
+
+	public Block<T> readAndRemove(Block<T>[] bucket, T[] iden) {
+		Block<T> result = dummyBlock;
+		for (int i = 0; i < bucket.length; ++i) {
+			T match = eq(iden, bucket[i].iden);
+			match = and(match, not(bucket[i].isDummy));
+			result = mux(result, bucket[i], match);
+			bucket[i].isDummy = mux(bucket[i].isDummy, SIGNAL_ONE, match);
+		}
+		return result;
+	}
+
+	public Block<T> conditionalReadAndRemove(Block<T>[][] blocks, T[] iden, T condition) {
+		Block<T>[] res = newBlockArray(blocks.length);
+		for (int i = 0; i < blocks.length; ++i)
+			res[i] = conditionalReadAndRemove(blocks[i], iden, condition);
+		return conditionalReadAndRemove(res, iden, condition);
+	}
+
+	public Block<T> readAndRemove(Block<T>[][] blocks, T[] iden) {
+		Block<T>[] res = newBlockArray(blocks.length);
+		for (int i = 0; i < blocks.length; ++i)
+			res[i] = readAndRemove(blocks[i], iden);
+		return readAndRemove(res, iden);
+	}
+
+	public void conditionalAdd(Block<T>[] bucket, Block<T> newBlock, T condition) {
+		T added = not(condition);
+		for (int i = 0; i < bucket.length; ++i) {
+			T match = and(not(bucket[i].isDummy), eq(newBlock.iden, bucket[i].iden));
+			added = or(match, added);
+		}
+		for (int i = 0; i < bucket.length; ++i) {
+			T match = bucket[i].isDummy;
+			T shouldAdd = and(not(added), match);
+			added = or(added, shouldAdd);
+			bucket[i] = mux(bucket[i], newBlock, shouldAdd);
+		}
+	}
+
+	public void add(Block<T>[] bucket, Block<T> newBlock) {
+		T added = SIGNAL_ZERO;
+		for (int i = 0; i < bucket.length; ++i) {
+			T match = and(not(bucket[i].isDummy), eq(newBlock.iden, bucket[i].iden));
+			added = or(match, added);
+		}
+		for (int i = 0; i < bucket.length; ++i) {
+			T match = bucket[i].isDummy;
+			T shouldAdd = and(not(added), match);
+			added = or(added, shouldAdd);
+			bucket[i] = mux(bucket[i], newBlock, shouldAdd);
+		}
+
+	}
+
+	public Block<T> pop(Block<T>[] bucket) {
+		Block<T> result = dummyBlock;
+		T poped = SIGNAL_ZERO;// condition=T => shouldpop => set to poped;
+		for (int i = 0; i < bucket.length; ++i) {
+			T notDummy = not(bucket[i].isDummy);
+			T shouldPop = and(not(poped), notDummy);
+			poped = or(poped, shouldPop);
+			result = mux(result, bucket[i], shouldPop);
+
+			bucket[i].isDummy = mux(bucket[i].isDummy, SIGNAL_ONE, shouldPop);
+		}
+		return result;
+	}
+
+	public Block<T> conditionalPop(Block<T>[] bucket, T condition) {
+		Block<T> result = dummyBlock;
+		T poped = not(condition);// condition=T => shouldpop => set to poped;
+		for (int i = 0; i < bucket.length; ++i) {
+			T notDummy = not(bucket[i].isDummy);
+			T shouldPop = and(not(poped), notDummy);
+			poped = or(poped, shouldPop);
+			result = mux(result, bucket[i], shouldPop);
+
+			bucket[i].isDummy = mux(bucket[i].isDummy, SIGNAL_ONE, shouldPop);
+		}
+		return result;
+	}
+
+	public Block<T> mux(Block<T> a, Block<T> b, T choose) {
+		T[] iden = mux(a.iden, b.iden, choose);
+		T[] pos = mux(a.pos, b.pos, choose);
+		T[] data = mux(a.data, b.data, choose);
+		T isDummy = mux(a.isDummy, b.isDummy, choose);
+		return new Block<T>(iden, pos, data, isDummy);
+	}
+
+	public Block<T> xor(Block<T> a, Block<T> b) {
+		T[] iden = xor(a.iden, b.iden);
+		T[] pos = xor(a.pos, b.pos);
+		T[] data = xor(a.data, b.data);
+		T isDummy = xor(a.isDummy, b.isDummy);
+		return new Block<T>(iden, pos, data, isDummy);
+	}
+
+	public Block<T>[] xor(Block<T>[] a, Block<T>[] b) {
+		assert (a.length == b.length) : "xor Block<T>s error";
+		Block<T>[] result = newBlockArray(b.length);
+		for (int i = 0; i < a.length; ++i)
+			result[i] = xor(a[i], b[i]);
+		return result;
+	}
+
+	public Block<T>[][] xor(Block<T>[][] a, Block<T>[][] b) {
+		assert (a.length == b.length) : "xor Block<T>s error";
+		Block<T>[][] result = newBlockMatrix(a.length);
+		for (int i = 0; i < a.length; ++i) {
+			result[i] = newBlockArray(a[i].length);
+			for (int j = 0; j < a[i].length; ++j)
+				result[i][j] = xor(a[i][j], b[i][j]);
+		}
+		return result;
+	}
+
+	public Block<T> copy(Block<T> b) {
+		return new Block<T>(b.iden, b.pos, b.data, b.isDummy);
+	}
+
+	@SuppressWarnings("unchecked")
+	public Block<T>[] newBlockArray(int len) {
+		return new Block[len];
+	}
+
+	@SuppressWarnings("unchecked")
+	public Block<T>[][] newBlockMatrix(int x, int y) {
+		return new Block[x][y];
+	}
+
+	@SuppressWarnings("unchecked")
+	public Block<T>[][] newBlockMatrix(int x) {
+		return new Block[x][];
+	}
+}

+ 162 - 0
ObliVMGC/com/oblivm/backend/oram/CircuitOram.java

@@ -0,0 +1,162 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Party;
+import com.oblivm.backend.util.Utils;
+
+public class CircuitOram<T> extends TreeBasedOramParty<T> {
+	public CircuitOramLib<T> lib;
+	Block<T>[] scQueue;
+	int cnt = 0;
+	public PlainBlock[] queue;
+	public int queueCapacity;
+
+	boolean[] nextPath() {
+		boolean[] res = new boolean[logN];
+		int temp = cnt;
+		for (int i = res.length - 1; i >= 0; --i) {
+			res[i] = (temp & 1) == 1;
+			temp >>= 1;
+		}
+		cnt = (cnt + 1) % N;
+		return res;
+	}
+
+	public CircuitOram(CompEnv<T> env, int N, int dataSize, int cap, int sp) {
+		super(env, N, dataSize, cap);
+		lib = new CircuitOramLib<T>(lengthOfIden, lengthOfPos, lengthOfData, logN, capacity, env);
+		queueCapacity = 30;
+		queue = new PlainBlock[queueCapacity];
+
+		for (int i = 0; i < queue.length; ++i)
+			queue[i] = getDummyBlock(p == Party.Alice);
+
+		scQueue = prepareBlocks(queue, queue);
+	}
+
+	public CircuitOram(CompEnv<T> env, int N, int dataSize) {
+		super(env, N, dataSize, 3);
+		lib = new CircuitOramLib<T>(lengthOfIden, lengthOfPos, lengthOfData, logN, capacity, env);
+		queueCapacity = 30;
+		queue = new PlainBlock[queueCapacity];
+
+		for (int i = 0; i < queue.length; ++i)
+			queue[i] = getDummyBlock(p == Party.Alice);
+
+		scQueue = prepareBlocks(queue, queue);
+
+	}
+
+	protected void ControlEviction() {
+		flushOneTime(nextPath());
+		flushOneTime(nextPath());
+	}
+
+	public void flushOneTime(boolean[] pos) {
+		PlainBlock[][] blocks = getPath(pos);
+		Block<T>[][] scPath = preparePath(blocks, blocks);
+
+		lib.flush(scPath, pos, scQueue);
+
+		blocks = preparePlainPath(scPath);
+		putPath(blocks, pos);
+	}
+
+	int initalValue = 0;
+
+	public void setInitialValue(int intial) {
+		initalValue = intial;
+	}
+
+	public T[] readAndRemove(T[] scIden, boolean[] pos, boolean RandomWhenNotFound) {
+		PlainBlock[][] blocks = getPath(pos);
+		Block<T>[][] scPath = preparePath(blocks, blocks);
+
+		Block<T> res = lib.readAndRemove(scPath, scIden);
+		Block<T> res2 = lib.readAndRemove(scQueue, scIden);
+		res = lib.mux(res, res2, res.isDummy);
+
+		blocks = preparePlainPath(scPath);
+		putPath(blocks, pos);
+
+		if (RandomWhenNotFound) {
+			PlainBlock b = randomBlock();
+			Block<T> scb = inputBlockOfClient(b);
+			Block<T> finalRes = lib.mux(res, scb, res.isDummy);
+
+			return finalRes.data;
+		} else {
+			return lib.mux(res.data, lib.toSignals(initalValue, res.data.length), res.isDummy);
+		}
+	}
+
+	public void putBack(T[] scIden, T[] scNewPos, T[] scData) {
+		Block<T> b = new Block<T>(scIden, scNewPos, scData, lib.SIGNAL_ZERO);
+		lib.add(scQueue, b);
+
+		env.flush();
+		ControlEviction();
+	}
+
+	public T[] read(T[] scIden, boolean[] pos, T[] scNewPos) {
+		scIden = Arrays.copyOf(scIden, lengthOfIden);
+		T[] r = readAndRemove(scIden, pos, false);
+		putBack(scIden, scNewPos, r);
+		return r;
+	}
+
+	public void write(T[] scIden, boolean[] pos, T[] scNewPos, T[] scData) {
+		scIden = Arrays.copyOf(scIden, lengthOfIden);
+		readAndRemove(scIden, pos, false);
+		putBack(scIden, scNewPos, scData);
+	}
+
+	public void write(T[] scIden, T[] pos, T[] scNewPos, T[] scData, T dummy) {
+		scIden = Arrays.copyOf(scIden, lengthOfIden);
+		conditionalReadAndRemove(scIden, pos, dummy);
+		conditionalPutBack(scIden, scNewPos, scData, dummy);
+	}
+
+	public T[] access(T[] scIden, boolean[] pos, T[] scNewPos, T[] scData, T op) {
+		scIden = Arrays.copyOf(scIden, lengthOfIden);
+		T[] r = readAndRemove(scIden, pos, false);
+		T[] toWrite = lib.mux(r, scData, op);
+		putBack(scIden, scNewPos, toWrite);
+		return toWrite;
+	}
+
+	public T[] conditionalReadAndRemove(T[] scIden, T[] pos, T condition) {
+		// Utils.print(env, "rar: iden:", scIden, pos, condition);
+		scIden = Arrays.copyOf(scIden, lengthOfIden);
+		T[] scPos = Arrays.copyOf(pos, lengthOfPos);
+		T[] randbools = lib.randBools(scPos.length);
+		T[] posToUse = lib.mux(randbools, scPos, condition);
+
+		boolean[] path = lib.declassifyToBoth(posToUse);
+
+		PlainBlock[][] blocks = getPath(path);
+		Block<T>[][] scPath = preparePath(blocks, blocks);
+
+		Block<T> res = lib.conditionalReadAndRemove(scPath, scIden, condition);
+		Block<T> res2 = lib.conditionalReadAndRemove(scQueue, scIden, condition);
+		res = lib.mux(res, res2, res.isDummy);
+
+		blocks = preparePlainPath(scPath);
+		putPath(blocks, path);
+		env.flush();
+		return lib.mux(res.data, lib.toSignals(initalValue, res.data.length), res.isDummy);
+	}
+
+	public void conditionalPutBack(T[] scIden, T[] scNewPos, T[] scData, T condition) {
+		env.flush();
+		scIden = Arrays.copyOf(scIden, lengthOfIden);
+
+		Block<T> b = new Block<T>(scIden, scNewPos, scData, lib.SIGNAL_ZERO);
+		lib.conditionalAdd(scQueue, b, condition);
+		env.flush();
+		ControlEviction();
+	}
+}

+ 199 - 0
ObliVMGC/com/oblivm/backend/oram/CircuitOramLib.java

@@ -0,0 +1,199 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Party;
+import com.oblivm.backend.util.Utils;
+
+public class CircuitOramLib<T> extends BucketLib<T> {
+	int logN;
+	int loglogN;
+	int capacity;
+
+	public CircuitOramLib(int lengthOfIden, int lengthOfPos, int lengthOfData, int logN, int capacity, CompEnv<T> e) {
+		super(lengthOfIden, lengthOfPos, lengthOfData, e);
+		this.logN = logN;
+		this.capacity = capacity;
+	}
+
+	public T[] deepestLevellocal(T[] pos, T[] path) {
+		T[] xored = xor(pos, path);
+		return leadingZeros(xored);
+	}
+
+	public T[][] deepestBlockShort(Block<T>[] bucket, T[] pathSignal) {
+		T[][] deepest = env.newTArray(bucket.length, 0);// ;new
+														// T[nodeCapacity][];
+		for (int j = 0; j < bucket.length; ++j) {
+			deepest[j] = deepestLevellocal(bucket[j].pos, pathSignal);
+		}
+
+		T[] maxIden = bucket[0].iden;
+		T[] maxdepth = deepest[0];
+		T isDummy = bucket[0].isDummy;
+		for (int j = 1; j < bucket.length; ++j) {
+			T greater = geq(deepest[j], maxdepth);
+			greater = and(greater, not(bucket[j].isDummy));
+
+			maxIden = mux(maxIden, bucket[j].iden, greater);
+			maxdepth = mux(maxdepth, deepest[j], greater);
+			isDummy = mux(isDummy, bucket[j].isDummy, greater);
+		}
+		T[][] result = env.newTArray(3, 0);
+		result[0] = maxIden;
+		result[1] = maxdepth;
+		result[2] = env.newTArray(1);
+		result[2][0] = isDummy;
+		return result;
+	}
+
+	public void flush(Block<T>[][] scPath, boolean[] path, Block<T>[] scQueue) {
+		// make path to signal
+		T[] pathSignal = env.newTArray(path.length);
+		for (int i = 0; i < path.length; ++i)
+			pathSignal[i] = path[i] ? SIGNAL_ONE : SIGNAL_ZERO;
+
+		// PrepareDeepest(path)
+		T[][] stashDeepest = deepestBlockShort(scQueue, pathSignal);
+		loglogN = stashDeepest[1].length;
+		T[][] deepest = env.newTArray(scPath.length + 1, 0);
+		T[][] deepestIden = env.newTArray(scPath.length + 1, 0);
+		for (int i = 0; i < deepest.length; ++i) {
+			deepest[i] = zeros(loglogN);
+			deepestIden[i] = zeros(lengthOfIden);
+		}
+		T[] deepestBot = ones(scPath.length + 1);
+
+		T[] cur = zeros(loglogN);
+		T curBot = SIGNAL_ONE;
+		// T emptyStash = isEmpty(scQueue);
+		T[] curv = stashDeepest[1];// mux(, zeros(loglogN), emptyStash);
+		deepestIden[0] = stashDeepest[0];
+		curBot = stashDeepest[2][0];
+		for (int i = 0; i < logN; ++i) {
+			T[] iSignal = toSignals(i + 1, loglogN);
+			T curvGEQI = geq(curv, iSignal);
+			deepest[i + 1] = mux(deepest[i + 1], cur, curvGEQI);
+			deepestBot[i + 1] = mux(deepestBot[i + 1], curBot, curvGEQI);
+
+			T[][] pathiDeepest = deepestBlockShort(scPath[i], pathSignal);
+			deepestIden[i + 1] = pathiDeepest[0];
+
+			T lGcurv = not(leq(pathiDeepest[1], curv));
+			lGcurv = and(lGcurv, not(pathiDeepest[2][0]));
+			lGcurv = or(lGcurv, curBot);
+			curv = mux(curv, pathiDeepest[1], lGcurv);
+			cur = mux(cur, iSignal, lGcurv);
+			curBot = mux(curBot, SIGNAL_ZERO, lGcurv);
+		}
+
+		// prepareTarget(path)
+		T[] c = toSignals(0, loglogN);
+		T cBot = SIGNAL_ONE;
+		T[] l = toSignals(0, loglogN);
+		T lBot = SIGNAL_ONE;
+
+		T[][] target = env.newTArray(scPath.length + 1, 0);
+		for (int i = 0; i < target.length; ++i)
+			target[i] = zeros(loglogN);
+		T[] targetBot = ones(scPath.length + 1);
+
+		for (int i = logN; i >= 0; --i) {
+			// prepare conditions
+			T[] iSignal = toSignals(i, curv.length);
+			T iEQl;
+			iEQl = and(not(lBot), eq(iSignal, l));
+			T isFull;
+			if (i > 0) {
+				isFull = isFull(scPath[i - 1]);
+			} else {
+				isFull = isFull(scQueue);
+			}
+			T hasSlot = or(and(cBot, not(isFull)), not(targetBot[i]));
+			T canPush = not(deepestBot[i]);
+
+			// begin assignment
+			target[i] = mux(target[i], c, iEQl);
+			targetBot[i] = mux(targetBot[i], cBot, iEQl);
+			if (i > 0) {// the last one can be skipped
+				cBot = mux(cBot, SIGNAL_ONE, iEQl);
+				lBot = mux(lBot, SIGNAL_ONE, iEQl);
+
+				T secondIf = and(hasSlot, canPush);
+				l = mux(l, deepest[i], secondIf);
+				lBot = mux(lBot, deepestBot[i], secondIf);
+				c = mux(c, iSignal, secondIf);
+				cBot = mux(cBot, SIGNAL_ZERO, secondIf);
+			}
+		}
+
+		// evictionFast(path)
+		Block<T> hold = dummyBlock;
+		lBot = SIGNAL_ONE;
+		// do it for stash first
+		{
+			T toRemove = not(targetBot[0]);
+			hold = conditionalReadAndRemove(scQueue, deepestIden[0], toRemove);
+			l = mux(l, target[0], toRemove);
+			lBot = mux(lBot, targetBot[0], toRemove);
+		}
+
+		for (int i = 0; i < logN; ++i) {
+			T[] iSignal = toSignals(i + 1, curv.length);
+			T iEQl = eq(iSignal, l);
+			iEQl = and(iEQl, not(lBot));
+			T firstIf = and(not(hold.isDummy), iEQl);
+			Block<T> holdTmp = copy(hold);
+
+			hold.isDummy = mux(hold.isDummy, SIGNAL_ONE, firstIf);
+			lBot = mux(lBot, SIGNAL_ONE, firstIf);
+
+			T notBot = not(targetBot[i + 1]);
+
+			if (i != logN - 1) {
+				Block<T> tmp = conditionalReadAndRemove(scPath[i], deepestIden[i + 1], notBot);
+				hold = mux(hold, tmp, notBot);
+			}
+
+			l = mux(l, target[i + 1], notBot);
+			lBot = mux(lBot, targetBot[i + 1], notBot);
+			conditionalAdd(scPath[i], holdTmp, firstIf);
+		}
+	}
+
+	public void print(T[][] data, T[] bot) {
+		if (env.getParty() == Party.Bob || env instanceof com.oblivm.backend.gc.GCCompEnv)
+			return;
+		for (int i = 0; i < data.length; ++i) {
+			if ((Boolean) bot[i]) {
+				System.out.print("d ");
+			} else
+				System.out.print(Utils.toInt(Utils.tobooleanArray((Boolean[]) data[i])) + " ");
+		}
+		System.out.print("\n");
+	}
+
+	public void print(T[] data, T bot) {
+		if (env.getParty() == Party.Bob || env instanceof com.oblivm.backend.gc.GCCompEnv)
+			return;
+
+		if ((Boolean) bot) {
+			System.out.print("d ");
+		} else
+			System.out.print(Utils.toInt(Utils.tobooleanArray((Boolean[]) data)) + " ");
+		System.out.print("\n");
+	}
+
+	public void print(String s, T[] data, T bot) {
+
+		if (env.getParty() == Party.Bob)
+			return;
+
+		System.out.print(s);
+		if ((Boolean) bot) {
+			System.out.print("d ");
+		} else
+			System.out.print(Utils.toInt(Utils.tobooleanArray((Boolean[]) data)) + " ");
+		System.out.print("\n");
+	}
+}

+ 71 - 0
ObliVMGC/com/oblivm/backend/oram/LinearScanOram.java

@@ -0,0 +1,71 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import com.oblivm.backend.circuits.arithmetic.IntegerLib;
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.util.Utils;
+
+public class LinearScanOram<T> {
+	public T[][] content;
+	public CompEnv<T> env;
+	public int lengthOfIden;
+	public IntegerLib<T> lib;
+	public int dataSize;
+
+	public LinearScanOram(CompEnv<T> env, int N, int dataSize) {
+		this.env = env;
+		this.dataSize = dataSize;
+		lib = new IntegerLib<T>(env);
+		content = env.newTArray(N, 0);
+		lengthOfIden = Utils.log2Ceil(N);
+		for (int i = 0; i < N; ++i)
+			content[i] = lib.zeros(dataSize);
+	}
+
+	public void add(T[] iden, T[] data, T dummy) {
+		T[] iden1 = lib.padSignal(iden, lengthOfIden);
+		for (int i = 0; i < content.length; ++i) {
+			T eq = lib.eq(iden1, lib.toSignals(i, lengthOfIden));
+			eq = lib.and(eq, dummy);
+			content[i] = lib.mux(content[i], data, eq);
+		}
+	}
+
+	public void add(T[] iden, T[] data) {
+		T[] iden1 = lib.padSignal(iden, lengthOfIden);
+		for (int i = 0; i < content.length; ++i) {
+			T eq = lib.eq(iden1, lib.toSignals(i, lengthOfIden));
+			content[i] = lib.mux(content[i], data, eq);
+		}
+	}
+
+	public T[] readAndRemove(T[] iden) {
+		return readAndRemove(iden, false);
+	}
+
+	public T[] readAndRemove(T[] iden, boolean randomWhennotFound) {
+		T[] iden1 = lib.padSignal(iden, lengthOfIden);
+		T[] res = lib.zeros(content[0].length);
+		for (int i = 0; i < content.length; ++i) {
+			T eq = lib.eq(iden1, lib.toSignals(i, lengthOfIden));
+			res = lib.mux(res, content[i], eq);
+		}
+		return res;
+	}
+
+	public T[] read(T[] iden) {
+		return readAndRemove(iden, false);
+	}
+
+	public void write(T[] iden, T[] data) {
+		add(iden, data);
+	}
+
+	public void write(T[] iden, T[] data, T dummy) {
+		add(iden, data, dummy);
+	}
+
+	public void putBack(T[] scIden, T[] scData) {
+		add(scIden, scData);
+	}
+}

+ 192 - 0
ObliVMGC/com/oblivm/backend/oram/OramParty.java

@@ -0,0 +1,192 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.flexsc.Party;
+import com.oblivm.backend.util.Utils;
+
+public abstract class OramParty<T> {
+	public int N;
+	int dataSize;
+
+	public int logN;
+	public int lengthOfIden;
+	public int lengthOfPos;
+	public int lengthOfData;
+
+	public CompEnv<T> env;
+	public Party p;
+	public Mode mode;
+
+	public BucketLib<T> lib;
+	boolean[] dummyArray;
+
+	void setParameters(CompEnv<T> env, int N, int dataSize) {
+		this.env = env;
+
+		this.dataSize = dataSize;
+		long a = 1;
+		logN = 1;
+		while (a < N) {
+			a *= 2;
+			++logN;
+		}
+
+		--logN;
+
+		this.N = 1 << logN;
+		lengthOfData = dataSize;
+		lengthOfIden = logN;
+	}
+
+	public OramParty(CompEnv<T> env, int N, int dataSize) {
+		setParameters(env, N, dataSize);
+		lengthOfPos = logN - 1;
+		p = env.party;
+		mode = env.mode;
+		init();
+
+	}
+
+	public OramParty(CompEnv<T> env, int N, int dataSize, int lengthOfPos) {
+		setParameters(env, N, dataSize);
+		this.lengthOfPos = lengthOfPos;
+		p = env.party;
+		mode = env.mode;
+		init();
+
+	}
+
+	public void init() {
+		dummyArray = new boolean[lengthOfIden + lengthOfPos + lengthOfData + 1];
+		for (int i = 0; i < dummyArray.length; ++i)
+			dummyArray[i] = false;
+		lib = new BucketLib<T>(lengthOfIden, lengthOfPos, lengthOfData, env);
+
+		boolean[] data = new boolean[lengthOfData];
+		for (int i = 0; i < lengthOfData; ++i)
+			data[i] = true;
+		pb_for_count_mode = new PlainBlock(0, 0, data, false);
+
+	}
+
+	public Block<T>[] prepareBlocks(PlainBlock[] clientBlock, PlainBlock[] serverBlock) {
+		Block<T>[] s = inputBucketOfServer(serverBlock);
+		Block<T>[] c = inputBucketOfClient(clientBlock);
+		return lib.xor(s, c);
+	}
+
+	public Block<T> prepareBlock(PlainBlock clientBlock, PlainBlock serverBlock) {
+		Block<T> s = inputBlockOfServer(serverBlock);
+		Block<T> c = inputBlockOfClient(clientBlock);
+		return lib.xor(s, c);
+	}
+
+	public PlainBlock preparePlainBlock(Block<T> blocks, Block<T> randomBlock) {
+		PlainBlock result = outputBlock(lib.xor(blocks, randomBlock));
+		return result;
+	}
+
+	public PlainBlock[] preparePlainBlocks(Block<T>[] blocks, Block<T>[] randomBlock) {
+		PlainBlock[] result = outputBucket(lib.xor(blocks, randomBlock));
+		return result;
+	}
+
+	public Block<T> inputBlockOfServer(PlainBlock b) {
+		T[] TArray = env.inputOfBob(b.toBooleanArray(lengthOfIden, lengthOfPos));
+		return new Block<T>(TArray, lengthOfIden, lengthOfPos, lengthOfData);
+
+	}
+
+	public Block<T> inputBlockOfClient(PlainBlock b) {
+		T[] TArray = env.inputOfAlice(b.toBooleanArray(lengthOfIden, lengthOfPos));
+		return new Block<T>(TArray, lengthOfIden, lengthOfPos, lengthOfData);
+	}
+
+	public Block<T>[] toBlocks(T[] Tarray, int lengthOfIden, int lengthOfPos, int lengthOfData, int capacity) {
+		int blockSize = lengthOfIden + lengthOfPos + lengthOfData + 1;
+		Block<T>[] result = lib.newBlockArray(capacity);
+		for (int i = 0; i < capacity; ++i) {
+			result[i] = new Block<T>(Arrays.copyOfRange(Tarray, i * blockSize, (i + 1) * blockSize), lengthOfIden,
+					lengthOfPos, lengthOfData);
+		}
+		return result;
+	}
+
+	public Block<T>[] inputBucketOfServer(PlainBlock[] b) {
+		T[] TArray = env.inputOfBob(PlainBlock.toBooleanArray(b, lengthOfIden, lengthOfPos));
+		return toBlocks(TArray, lengthOfIden, lengthOfPos, lengthOfData, b.length);// new
+																					// Block<T>(TArray,
+																					// lengthOfIden,lengthOfPos,lengthOfData);
+	}
+
+	public Block<T>[] inputBucketOfClient(PlainBlock[] b) {
+		T[] TArray = env.inputOfAlice(PlainBlock.toBooleanArray(b, lengthOfIden, lengthOfPos));
+		env.flush();
+		return toBlocks(TArray, lengthOfIden, lengthOfPos, lengthOfData, b.length);
+	}
+
+	public PlainBlock outputBlock(Block<T> b) {
+		boolean[] iden = env.outputToAlice(b.iden);
+		boolean[] pos = env.outputToAlice(b.pos);
+		boolean[] data = env.outputToAlice(b.data);
+		boolean isDummy = env.outputToAlice(b.isDummy);
+
+		return new PlainBlock(Utils.toLong(iden), Utils.toLong(pos), data, isDummy);
+	}
+
+	public PlainBlock[] outputBucket(Block<T>[] b) {
+		PlainBlock[] result = new PlainBlock[b.length];
+		for (int i = 0; i < b.length; ++i)
+			result[i] = outputBlock(b[i]);
+		return result;
+	}
+
+	public PlainBlock[][] outputBuckets(Block<T>[][] b) {
+		PlainBlock[][] result = new PlainBlock[b.length][];
+		for (int i = 0; i < b.length; ++i)
+			result[i] = outputBucket(b[i]);
+		env.flush();
+		return result;
+	}
+
+	PlainBlock pb_for_count_mode;
+
+	public PlainBlock getDummyBlock(boolean b) {
+		if (mode == Mode.COUNT)
+			return pb_for_count_mode;
+		boolean[] data = new boolean[lengthOfData];
+
+		for (int i = 0; i < lengthOfData; ++i)
+			data[i] = true;
+		return new PlainBlock(0, 0, data, b);
+	}
+
+	PlainBlock r = getDummyBlock(true);
+
+	public PlainBlock randomBlock() {
+		if (mode == Mode.COUNT)
+			return pb_for_count_mode;
+
+		// PlainBlock result = getDummyBlock(true);
+		// for (int i = 0; i < lengthOfIden; ++i)
+		// result.iden[i] = CompEnv.rnd.nextBoolean();
+		// for (int i = 0; i < lengthOfPos; ++i)
+		// result.pos[i] = CompEnv.rnd.nextBoolean();
+		boolean[] data = new boolean[lengthOfData];
+		for (int i = 0; i < lengthOfData; ++i)
+			data[i] = CompEnv.rnd.nextBoolean();
+		boolean isDummy = CompEnv.rnd.nextBoolean();
+		return new PlainBlock(CompEnv.rnd.nextLong(), CompEnv.rnd.nextLong(), data, isDummy);
+	}
+
+	public PlainBlock[] randomBucket(int length) {
+		PlainBlock[] result = new PlainBlock[length];
+		for (int i = 0; i < length; ++i)
+			result[i] = randomBlock();
+		return result;
+	}
+}

+ 37 - 0
ObliVMGC/com/oblivm/backend/oram/PlainBlock.java

@@ -0,0 +1,37 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import com.oblivm.backend.util.Utils;
+
+public class PlainBlock {
+	public long iden;
+	public long pos;
+	public boolean[] data;
+	public boolean isDummy;
+
+	public PlainBlock(long iden, long pos, boolean[] data, boolean isDummy) {
+		this.iden = iden;
+		this.pos = pos;
+		this.data = data;
+		this.isDummy = isDummy;
+	}
+
+	public boolean[] toBooleanArray(int lengthOfIden, int lengthOfPos) {
+		boolean[] result = new boolean[lengthOfIden + lengthOfPos + data.length + 1];
+		System.arraycopy(Utils.fromLong(iden, lengthOfIden), 0, result, 0, lengthOfIden);
+		System.arraycopy(Utils.fromLong(pos, lengthOfIden), 0, result, lengthOfIden, lengthOfPos);
+		System.arraycopy(data, 0, result, lengthOfPos + lengthOfIden, data.length);
+		result[result.length - 1] = isDummy;
+		return result;
+	}
+
+	static public boolean[] toBooleanArray(PlainBlock[] blocks, int lengthOfIden, int lengthOfPos) {
+		int blockSize = (lengthOfIden + lengthOfPos + blocks[0].data.length + 1);
+		boolean[] result = new boolean[blockSize * blocks.length];
+		for (int i = 0; i < blocks.length; ++i) {
+			boolean[] tmp = blocks[i].toBooleanArray(lengthOfIden, lengthOfPos);
+			System.arraycopy(tmp, 0, result, i * blockSize, blockSize);
+		}
+		return result;
+	}
+}

+ 149 - 0
ObliVMGC/com/oblivm/backend/oram/RecursiveCircuitOram.java

@@ -0,0 +1,149 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Party;
+
+public class RecursiveCircuitOram<T> {
+	public LinearScanOram<T> baseOram;
+	public ArrayList<CircuitOram<T>> clients = new ArrayList<>();
+	public int lengthOfIden;
+	int recurFactor;
+	int cutoff;
+	int capacity;
+
+	Party p;
+
+	public RecursiveCircuitOram(CompEnv<T> env, int N, int dataSize, int cutoff, int recurFactor, int capacity,
+			int sp) {
+		init(env, N, dataSize, cutoff, recurFactor, capacity, sp);
+	}
+
+	public RecursiveCircuitOram(CompEnv<T> env, int N, int dataSize, int cutoff, int recurFactor) {
+		init(env, N, dataSize, cutoff, recurFactor, 3, 80);
+	}
+
+	// with default params
+	public RecursiveCircuitOram(CompEnv<T> env, int N, int dataSize) {
+		init(env, N, dataSize, 1 << 6, 8, 3, 80);
+	}
+
+	public void setInitialValue(int initial) {
+		clients.get(0).setInitialValue(initial);
+	}
+
+	void init(CompEnv<T> env, int N, int dataSize, int cutoff, int recurFactor, int capacity, int sp) {
+		this.p = env.party;
+		this.cutoff = cutoff;
+		this.recurFactor = recurFactor;
+		this.capacity = capacity;
+		CircuitOram<T> oram = new CircuitOram<T>(env, N, dataSize, capacity, sp);
+		lengthOfIden = oram.lengthOfIden;
+		clients.add(oram);
+		int newDataSize = oram.lengthOfPos * recurFactor, newN = (1 << oram.lengthOfIden) / recurFactor;
+		while (newN > cutoff) {
+			oram = new CircuitOram<T>(env, newN, newDataSize, capacity, sp);
+			clients.add(oram);
+			newDataSize = oram.lengthOfPos * recurFactor;
+			newN = (1 << oram.lengthOfIden) / recurFactor;
+		}
+		CircuitOram<T> last = clients.get(clients.size() - 1);
+		baseOram = new LinearScanOram<T>(env, (1 << last.lengthOfIden), last.lengthOfPos);
+	}
+
+	public T[] read(T[] iden) {
+		T[][] poses = travelToDeep(iden, 1);
+		CircuitOram<T> currentOram = clients.get(0);
+		boolean[] oldPos = baseOram.lib.declassifyToBoth(poses[0]);
+
+		T[] res = currentOram.read(iden, oldPos, poses[1]);
+		return res;
+	}
+
+	public void write(T[] iden, T[] data) {
+		T[][] poses = travelToDeep(iden, 1);
+		CircuitOram<T> currentOram = clients.get(0);
+
+		boolean[] oldPos = baseOram.lib.declassifyToBoth(poses[0]);
+		currentOram.write(iden, oldPos, poses[1], data);
+	}
+
+	public void write(T[] iden, T[] data, T dummy) {
+		T[][] poses = travelToDeep(iden, 1);
+		CircuitOram<T> currentOram = clients.get(0);
+
+		currentOram.write(iden, poses[0], poses[1], data, dummy);
+	}
+
+	public T[] access(T[] iden, T[] data, T op) {
+		T[][] poses = travelToDeep(iden, 1);
+		CircuitOram<T> currentOram = clients.get(0);
+
+		boolean[] oldPos = baseOram.lib.declassifyToBoth(poses[0]);
+		return currentOram.access(iden, oldPos, poses[1], data, op);
+	}
+
+	public T[][] travelToDeep(T[] iden, int level) {
+		if (level == clients.size()) {
+			T[] baseMap = baseOram.readAndRemove(baseOram.lib.padSignal(iden, baseOram.lengthOfIden));
+			T[] ithPos = baseOram.lib.rightPublicShift(iden, baseOram.lengthOfIden);// iden>>baseOram.lengthOfIden;
+
+			T[] pos = extract(baseMap, ithPos, clients.get(level - 1).lengthOfPos);
+
+			T[] newPos = baseOram.lib.randBools(clients.get(level - 1).lengthOfPos);
+			put(baseMap, ithPos, newPos);
+			baseOram.putBack(baseOram.lib.padSignal(iden, baseOram.lengthOfIden), baseMap);
+			T[][] result = baseOram.env.newTArray(2, 0);
+			result[0] = pos;
+			result[1] = newPos;
+			return result;
+		} else {
+			CircuitOram<T> currentOram = clients.get(level);
+
+			T[][] poses = travelToDeep(subIdentifier(iden, currentOram), level + 1);
+
+			boolean[] oldPos = baseOram.lib.declassifyToBoth(poses[0]);
+
+			T[] data = currentOram.readAndRemove(subIdentifier(iden, currentOram), oldPos, true);
+			T[] ithPos = currentOram.lib.rightPublicShift(iden, currentOram.lengthOfIden);// iden>>currentOram.lengthOfIden;//iden/(1<<currentOram.lengthOfIden);
+
+			T[] pos = extract(data, ithPos, clients.get(level - 1).lengthOfPos);
+			T[] tmpNewPos = baseOram.lib.randBools(clients.get(level - 1).lengthOfPos);
+			put(data, ithPos, tmpNewPos);
+			currentOram.putBack(subIdentifier(iden, currentOram), poses[1], data);
+			T[][] result = currentOram.env.newTArray(2, 0);
+			result[0] = pos;
+			result[1] = tmpNewPos;
+			return result;
+		}
+	}
+
+	public T[] subIdentifier(T[] iden, OramParty<T> o) {
+		// int a = iden & ((1<<o.lengthOfIden)-1);//(iden % (1<<o.lengthOfIden))
+		return o.lib.padSignal(iden, o.lengthOfIden);
+	}
+
+	public T[] extract(T[] array, T[] ithPos, int length) {
+		int numberOfEntry = array.length / length;
+		T[] result = Arrays.copyOfRange(array, 0, length);
+		for (int i = 1; i < numberOfEntry; ++i) {
+			T hit = baseOram.lib.eq(baseOram.lib.toSignals(i, ithPos.length), ithPos);
+			result = baseOram.lib.mux(result, Arrays.copyOfRange(array, i * length, (i + 1) * length), hit);
+		}
+		return result;
+	}
+
+	public void put(T[] array, T[] ithPos, T[] content) {
+		int numberOfEntry = array.length / content.length;
+		for (int i = 0; i < numberOfEntry; ++i) {
+			T hit = baseOram.lib.eq(baseOram.lib.toSignals(i, ithPos.length), ithPos);
+			T[] tmp = baseOram.lib.mux(Arrays.copyOfRange(array, i * content.length, (i + 1) * content.length), content,
+					hit);
+			System.arraycopy(tmp, 0, array, i * content.length, content.length);
+		}
+	}
+
+}

+ 62 - 0
ObliVMGC/com/oblivm/backend/oram/SecureArray.java

@@ -0,0 +1,62 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.gc.BadLabelException;
+
+public class SecureArray<T> {
+	static final int threshold = 256;
+	boolean useTrivialOram = false;
+	public LinearScanOram<T> trivialOram = null;
+	public RecursiveCircuitOram<T> circuitOram = null;
+	public int lengthOfIden;
+	public int length;
+	public int dataSize;
+
+	public SecureArray(CompEnv<T> env, int N, int dataSize) throws Exception {
+		length = N;
+		this.dataSize = dataSize;
+		useTrivialOram = N <= threshold;
+		if (useTrivialOram) {
+			trivialOram = new LinearScanOram<T>(env, N, dataSize);
+			lengthOfIden = trivialOram.lengthOfIden;
+		} else {
+			circuitOram = new RecursiveCircuitOram<T>(env, N, dataSize);
+			lengthOfIden = circuitOram.lengthOfIden;
+		}
+	}
+
+	public T[] readAndRemove(T[] iden) throws BadLabelException {
+		return circuitOram.clients.get(0).readAndRemove(iden,
+				Arrays.copyOfRange(circuitOram.clients.get(0).lib.declassifyToBoth(iden), 0,
+						circuitOram.clients.get(0).lengthOfPos),
+				false);
+	}
+
+	public T[] read(T[] iden) throws BadLabelException {
+		if (useTrivialOram)
+			return trivialOram.read(iden);
+		else
+			return circuitOram.read(iden);
+	}
+
+	public void write(T[] iden, T[] data) throws Exception {
+		if (useTrivialOram)
+			trivialOram.write(iden, data);
+		else
+			circuitOram.write(iden, data);
+	}
+
+	public void conditionalWrite(T[] iden, T[] data, T condition) throws BadLabelException {
+		if (useTrivialOram) {
+			T[] readData = trivialOram.readAndRemove(iden);
+			T[] toAdd = trivialOram.lib.mux(readData, data, condition);
+			trivialOram.putBack(iden, toAdd);
+		} else {
+			// op == 1 means write, 0 means read
+			circuitOram.access(iden, data, condition);
+		}
+	}
+}

+ 136 - 0
ObliVMGC/com/oblivm/backend/oram/TreeBasedOramParty.java

@@ -0,0 +1,136 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.flexsc.Party;
+
+public abstract class TreeBasedOramParty<T> extends OramParty<T> {
+	public PlainBlock[][] tree;
+	protected int capacity;
+
+	public TreeBasedOramParty(CompEnv<T> env, int N, int dataSize, int capacity) {
+		super(env, N, dataSize);
+		this.capacity = capacity;
+
+		if (env.mode != Mode.COUNT) {
+			tree = new PlainBlock[this.N][capacity];
+
+			PlainBlock b = getDummyBlock(p == Party.Alice);
+
+			for (int i = 0; i < this.N; ++i)
+				for (int j = 0; j < capacity; ++j)
+					tree[i][j] = b;
+		}
+	}
+
+	protected PlainBlock[][] getPath(boolean[] path) {
+		PlainBlock[][] result = new PlainBlock[logN][];
+		if (env.mode == Mode.COUNT) {
+			for (int i = 0; i < logN; ++i) {
+				result[i] = new PlainBlock[capacity];
+				for (int j = 0; j < capacity; ++j)
+					result[i][j] = getDummyBlock(true);
+			}
+			return result;
+		}
+		int index = 1;
+		result[0] = tree[index];
+		for (int i = 1; i < logN; ++i) {
+			index *= 2;
+			if (path[lengthOfPos - i])
+				++index;
+			result[i] = tree[index];
+		}
+		return result;
+	}
+
+	protected void putPath(PlainBlock[][] blocks, boolean[] path) {
+		if (env.mode == Mode.COUNT)
+			return;
+		int index = 1;
+		tree[index] = blocks[0];
+		for (int i = 1; i < logN; ++i) {
+			index *= 2;
+			if (path[lengthOfPos - i])
+				++index;
+			tree[index] = blocks[i];
+		}
+	}
+
+	public Block<T>[][] preparePath(PlainBlock[][] clientBlock, PlainBlock[][] serverBlock) {
+		Block<T>[][] s = inputPathOfServer(serverBlock);
+		Block<T>[][] c = inputPathOfClient(clientBlock);
+		return lib.xor(s, c);
+	}
+
+	public Block<T>[][] inputPathOfClient(PlainBlock[][] b) {
+		int length = 0;
+		for (int i = 0; i < b.length; ++i)
+			length += b[i].length;
+
+		PlainBlock[] tmp = new PlainBlock[length];
+		int cnt = 0;
+		for (int i = 0; i < b.length; ++i)
+			for (int j = 0; j < b[i].length; ++j)
+				tmp[cnt++] = b[i][j];
+
+		Block<T>[] tmpResult = inputBucketOfClient(tmp);
+		cnt = 0;
+		Block<T>[][] result = lib.newBlockMatrix(b.length);
+		for (int i = 0; i < b.length; ++i) {
+			result[i] = lib.newBlockArray(b[i].length);
+			for (int j = 0; j < b[i].length; ++j)
+				result[i][j] = tmpResult[cnt++];
+		}
+		return result;
+	}
+
+	public Block<T>[][] inputPathOfServer(PlainBlock[][] b) {
+		int length = 0;
+		for (int i = 0; i < b.length; ++i)
+			length += b[i].length;
+
+		PlainBlock[] tmp = new PlainBlock[length];
+		int cnt = 0;
+		for (int i = 0; i < b.length; ++i)
+			for (int j = 0; j < b[i].length; ++j)
+				tmp[cnt++] = b[i][j];
+		Block<T>[] tmpResult = inputBucketOfServer(tmp);
+
+		cnt = 0;
+		Block<T>[][] result = lib.newBlockMatrix(b.length);
+		for (int i = 0; i < b.length; ++i) {
+			result[i] = lib.newBlockArray(b[i].length);
+			for (int j = 0; j < b[i].length; ++j)
+				result[i][j] = tmpResult[cnt++];
+		}
+		return result;
+	}
+
+	public PlainBlock[][] preparePlainPath(Block<T>[][] blocks) {
+		Block<T>[][] randomSCPath = lib.newBlockMatrix(blocks.length);
+
+		PlainBlock[][] randomPath = new PlainBlock[blocks.length][];
+		for (int i = 0; i < randomPath.length; ++i) {
+			randomPath[i] = randomBucket(blocks[i].length);
+		}
+		env.flush();
+
+		randomSCPath = inputPathOfServer(randomPath);
+
+		PlainBlock[][] result = outputBuckets(lib.xor(blocks, randomSCPath));
+
+		if (p == Party.Alice)
+			return result;
+		else
+			return randomPath;
+	}
+
+	public PlainBlock[][] randomPath(PlainBlock[][] path) {
+		PlainBlock[][] result = new PlainBlock[path.length][];
+		for (int i = 0; i < path.length; ++i)
+			result[i] = randomBucket(path[i].length);
+		return result;
+	}
+}

+ 95 - 0
ObliVMGC/com/oblivm/backend/oram/TrivialPrivateOram.java

@@ -0,0 +1,95 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.oram;
+
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Party;
+
+public class TrivialPrivateOram<T> extends OramParty<T> {
+	public PlainBlock[] bucket;
+	Block<T>[] result;
+	int capacity;
+
+	public TrivialPrivateOram(CompEnv<T> env, int N, int dataSize) {
+		super(env, N, dataSize, 1);
+		this.capacity = N;
+		bucket = new PlainBlock[capacity];
+
+		for (int i = 0; i < bucket.length; ++i) {
+			bucket[i] = getDummyBlock(p == Party.Alice);
+		}
+		result = prepareBlocks(bucket, bucket);
+	}
+
+	int InitialValue = 0;
+
+	public void setInitialValue(int initial) {
+		InitialValue = initial;
+	}
+
+	public void add(T[] iden, T[] data) {
+		T[] pos = env.newTArray(1);
+		pos[0] = lib.SIGNAL_ONE;
+		Block<T> scNewBlock = new Block<T>(iden, pos, data, lib.SIGNAL_ZERO);
+		lib.add(result, scNewBlock);
+	}
+
+	public T[] readAndRemove(T[] scIden) {
+		return readAndRemove(scIden, true);
+	}
+
+	public T[] readAndRemove(T[] scIden, boolean randomWhennotFound) {
+		scIden = lib.padSignal(scIden, lengthOfIden);
+		Block<T> res = lib.readAndRemove(result, scIden);
+		T[] finalRes;
+		if (randomWhennotFound) {
+			PlainBlock b1 = randomBlock();
+			Block<T> scb1 = inputBlockOfClient(b1);
+			finalRes = lib.mux(res.data, scb1.data, res.isDummy);
+		} else {
+			finalRes = lib.mux(res.data, lib.toSignals(InitialValue, res.data.length), res.isDummy);
+		}
+
+		return finalRes;
+	}
+
+	public T[] read(int index) {
+		return result[index].data;
+	}
+
+	public void write(int index, T[] d) {
+		result[index].data = d;
+	}
+
+	public T[] read(T[] scIden) {
+		scIden = Arrays.copyOf(scIden, lengthOfIden);
+		T[] r = readAndRemove(scIden, false);
+		putBack(scIden, r);
+
+		return r;
+	}
+
+	public void write(T[] scIden, T[] b) {
+		scIden = Arrays.copyOf(scIden, lengthOfIden);
+		readAndRemove(scIden);
+		putBack(scIden, b);
+	}
+
+	public void putBack(T[] scIden, T[] scData) {
+		scIden = Arrays.copyOf(scIden, lengthOfIden);
+		add(scIden, scData);
+	}
+
+	public T[] conditionalReadAndRemove(T[] iden, T condition) {
+		return lib.conditionalReadAndRemove(result, iden, condition).data;
+	}
+
+	public void conditionalPutBack(T[] iden, T[] data, T condition) {
+		T[] pos = env.newTArray(1);
+		pos[0] = lib.SIGNAL_ONE;
+		Block<T> scNewBlock = new Block<T>(iden, pos, data, lib.SIGNAL_ZERO);
+		lib.conditionalAdd(result, scNewBlock, condition);
+	}
+
+}

+ 67 - 0
ObliVMGC/com/oblivm/backend/ot/BitMatrix.java

@@ -0,0 +1,67 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// Improved by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+class BitMatrix {
+	private int nRows;
+	private int nCols;
+	BigInteger[] data; // column vectors of the matrix
+
+	public BitMatrix(int rows, int cols) {
+		nRows = rows;
+		nCols = cols;
+		data = new BigInteger[nCols];
+	}
+
+	public void initialize(SecureRandom rnd) {
+		for (int i = 0; i < nCols; i++)
+			data[i] = new BigInteger(nRows, rnd);
+	}
+
+	public BitMatrix transpose() {
+		return NaiveTranspose(this);
+	}
+
+	static public BitMatrix NaiveTranspose(BitMatrix a) {
+		BitMatrix b = new BitMatrix(a.nCols, a.nRows);
+
+		for (int i = 0; i < a.nRows; i++)
+			b.data[i] = BigInteger.ZERO;
+
+		for (int j = 0; j < a.nCols; j++)
+			for (int i = 0; i < a.nRows; i++)
+				if (a.data[j].testBit(i))
+					b.data[i] = b.data[i].setBit(j);
+		return b;
+	}
+
+	static public BitMatrix COtranspose(BitMatrix a) {
+		BitMatrix b = new BitMatrix(a.nCols, a.nRows);
+		for (int i = 0; i < a.nRows; i++)
+			b.data[i] = BigInteger.ZERO;
+		COtranspose(a, b, 0, 0, a.nRows, a.nCols);
+		return b;
+	}
+
+	static public void COtranspose(BitMatrix a, BitMatrix b, int startx, int starty, int endx, int endy) {
+
+		if (endy - starty == 1 && endx - startx == 1) {
+			if (a.data[starty].testBit(startx))
+				b.data[startx] = b.data[startx].setBit(starty);
+			return;
+		} else if (endy - starty < endx - startx) {
+
+			int midx = (startx + endx) / 2;
+			COtranspose(a, b, startx, starty, midx, endy);
+			COtranspose(a, b, midx, starty, endx, endy);
+		} else {
+			int midy = (starty + endy) / 2;
+			COtranspose(a, b, startx, starty, endx, midy);
+			COtranspose(a, b, startx, midy, endx, endy);
+		}
+	}
+}

+ 97 - 0
ObliVMGC/com/oblivm/backend/ot/Cipher.java

@@ -0,0 +1,97 @@
+//Copyright (C) 2014 by Yan Huang <yhuang@virginia.edu>
+
+package com.oblivm.backend.ot;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+
+import com.oblivm.backend.gc.GCSignal;
+
+public final class Cipher {
+	private static final int unitLength = 160; // SHA-1 has 160-bit output.
+	private static final int bytesPerUnit = (unitLength - 1) / 8 + 1; // SHA-1
+																		// has
+																		// 20
+																		// bytes.
+
+	private MessageDigest sha1;
+
+	public Cipher() {
+		try {
+			sha1 = MessageDigest.getInstance("SHA-1");
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	BigInteger a = BigInteger.ONE;
+
+	public BigInteger encrypt(byte[] key, BigInteger msg, int msgLength) {
+		assert (msgLength <= unitLength) : "Message longer than hash block width.";
+		return msg.xor(getPaddingOfLength(key, msgLength));
+	}
+
+	public BigInteger decrypt(byte[] key, BigInteger cph, int cphLength) {
+		assert (cphLength > unitLength) : "Ciphertext longer than hash block width.";
+		return cph.xor(getPaddingOfLength(key, cphLength));
+	}
+
+	private BigInteger getPaddingOfLength(byte[] key, int padLength) {
+
+		byte[] pad = new byte[(padLength - 1) / 8 + 1];
+		byte[] tmp;
+		int i;
+		for (i = 0; i < (pad.length - 1) / bytesPerUnit; i++) {
+			assert (i < 128) : "Padding is unexpectedly long.";
+			sha1.update(key);
+			sha1.update((byte) i);
+			tmp = sha1.digest();
+			System.arraycopy(tmp, 0, pad, i * bytesPerUnit, bytesPerUnit);
+		}
+
+		return new BigInteger(1, pad);
+	}
+
+	public BigInteger encrypt(int j, byte[] key, BigInteger msg, int msgLength) {
+		return msg.xor(getPaddingOfLength(j, key, msgLength));
+	}
+
+	public BigInteger decrypt(int j, byte[] key, BigInteger cph, int cphLength) {
+		return cph.xor(getPaddingOfLength(j, key, cphLength));
+	}
+
+	private BigInteger getPaddingOfLength(int j, byte[] key, int padLength) {
+		sha1.update(ByteBuffer.allocate(4).putInt(j).array());
+		sha1.update(key);
+
+		byte[] pad = new byte[(padLength - 1) / 8 + 1];
+		byte[] tmp;
+		tmp = sha1.digest();
+		int i;
+		for (i = 0; i < (pad.length - 1) / bytesPerUnit; i++) {
+			System.arraycopy(tmp, 0, pad, i * bytesPerUnit, bytesPerUnit);
+			sha1.update(tmp);
+			tmp = sha1.digest();
+		}
+		System.arraycopy(tmp, 0, pad, i * bytesPerUnit, pad.length - i * bytesPerUnit);
+
+		return new BigInteger(1, pad);
+	}
+
+	public GCSignal enc(GCSignal key, GCSignal m, int k) {
+		return getPadding(key, k).xor(m);
+	}
+
+	public GCSignal dec(GCSignal key, GCSignal c, int k) {
+		return getPadding(key, k).xor(c);
+	}
+
+	private GCSignal getPadding(GCSignal key, int k) {
+		sha1.update(key.bytes);
+		sha1.update(ByteBuffer.allocate(4).putInt(k).array());
+		GCSignal ret = GCSignal.newInstance(sha1.digest());
+		return ret;
+	}
+}

+ 33 - 0
ObliVMGC/com/oblivm/backend/ot/FakeOTReceiver.java

@@ -0,0 +1,33 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// Improved by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class FakeOTReceiver extends OTReceiver {
+	public FakeOTReceiver(Network channel) {
+		super(channel);
+	}
+
+	@Override
+	public GCSignal receive(boolean c) {
+		GCSignal[] m = new GCSignal[2];
+		m[0] = GCSignal.receive(channel);
+		m[1] = GCSignal.receive(channel);
+		return m[c ? 1 : 0];
+	}
+
+	@Override
+	public GCSignal[] receive(boolean[] c) {
+		GCSignal[] res = new GCSignal[c.length];
+		for (int i = 0; i < c.length; i++) {
+			GCSignal[] m = new GCSignal[2];
+			m[0] = GCSignal.receive(channel);
+			m[1] = GCSignal.receive(channel);
+			res[i] = m[c[i] ? 1 : 0];
+		}
+		return res;
+	}
+}

+ 30 - 0
ObliVMGC/com/oblivm/backend/ot/FakeOTSender.java

@@ -0,0 +1,30 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// Improved by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.io.IOException;
+
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class FakeOTSender extends OTSender {
+	public FakeOTSender(int bitLen, Network channel) {
+		super(bitLen, channel);
+	}
+
+	@Override
+	public void send(GCSignal[] m) {
+		m[0].send(channel);
+		m[1].send(channel);
+	}
+
+	@Override
+	public void send(GCSignal[][] m) throws IOException {
+		for (int i = 0; i < m.length; i++) {
+			m[i][0].send(channel);
+			m[i][1].send(channel);
+		}
+		channel.flush();
+	}
+}

+ 108 - 0
ObliVMGC/com/oblivm/backend/ot/NPOTReceiver.java

@@ -0,0 +1,108 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.Security;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+import com.oblivm.backend.rand.ISAACProvider;
+
+public class NPOTReceiver extends OTReceiver {
+	static SecureRandom rnd;
+
+	static {
+		Security.addProvider(new ISAACProvider());
+		try {
+			rnd = SecureRandom.getInstance("ISAACRandom");
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		}
+	}
+
+	private BigInteger p, q, g, C;
+	private BigInteger gr;
+
+	private BigInteger[][] pk;
+
+	private BigInteger[] keys;
+
+	Cipher cipher;
+
+	public NPOTReceiver(Network channel) throws Exception {
+		super(channel);
+
+		cipher = new Cipher();
+
+		initialize();
+	}
+
+	@Override
+	public GCSignal receive(boolean c) throws IOException {
+		return receive(new boolean[] { c })[0];
+	}
+
+	public GCSignal[] receive(boolean[] choices) throws IOException {
+		step1(choices);
+		return step2(choices);
+	}
+
+	private void initialize() throws Exception {
+		Flag.sw.startOTIO();
+		C = channel.readBI();
+		p = channel.readBI();
+		q = channel.readBI();
+		g = channel.readBI();
+		gr = channel.readBI();
+		msgBitLength = channel.readInt();
+		Flag.sw.stopOTIO();
+	}
+
+	private void step1(boolean[] choices) throws IOException {
+		keys = new BigInteger[choices.length];
+		pk = new BigInteger[choices.length][2];
+		BigInteger[] pk0 = new BigInteger[choices.length];
+		for (int i = 0; i < choices.length; i++) {
+			BigInteger k = (new BigInteger(q.bitLength(), rnd)).mod(q);
+			BigInteger gk = g.modPow(k, p);
+			BigInteger C_over_gk = C.multiply(gk.modInverse(p)).mod(p);
+			keys[i] = gr.modPow(k, p);
+
+			int sigma = choices[i] ? 1 : 0;
+			pk[i][sigma] = gk;
+			pk[i][1 - sigma] = C_over_gk;
+
+			pk0[i] = pk[i][0];
+		}
+
+		Flag.sw.startOTIO();
+		for (int i = 0; i < choices.length; i++)
+			channel.writeBI(pk0[i]);
+		channel.flush();
+		Flag.sw.stopOTIO();
+
+	}
+
+	private GCSignal[] step2(boolean[] choices) {
+		BigInteger[][] msg = new BigInteger[choices.length][2];
+		Flag.sw.startOTIO();
+		for (int i = 0; i < choices.length; i++) {
+			msg[i][0] = channel.readBI();
+			msg[i][1] = channel.readBI();
+		}
+		Flag.sw.stopOTIO();
+
+		GCSignal[] data = new GCSignal[choices.length];
+		for (int i = 0; i < choices.length; i++) {
+			int sigma = choices[i] ? 1 : 0;
+			data[i] = GCSignal
+					.newInstance(cipher.decrypt(keys[i].toByteArray(), msg[i][sigma], msgBitLength).toByteArray());
+		}
+		return data;
+	}
+}

+ 160 - 0
ObliVMGC/com/oblivm/backend/ot/NPOTSender.java

@@ -0,0 +1,160 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.Security;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+import com.oblivm.backend.rand.ISAACProvider;
+
+public class NPOTSender extends OTSender {
+
+	static SecureRandom rnd;
+
+	static {
+		Security.addProvider(new ISAACProvider());
+		try {
+			rnd = SecureRandom.getInstance("ISAACRandom");
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		}
+	}
+
+	private static final int certainty = 80;
+
+	private final static int qLength = 160; // 512;
+	private final static int pLength = 1024; // 15360;
+
+	private BigInteger p, q, g, C, r;
+	private BigInteger Cr, gr;
+
+	Cipher cipher;
+
+	public NPOTSender(int msgBitLength, Network channel) throws Exception {
+		super(msgBitLength, channel);
+		cipher = new Cipher();
+
+		initialize();
+	}
+
+	public void send(GCSignal[][] msgPairs) throws IOException {
+		step1(msgPairs);
+	}
+
+	private void initialize() throws Exception {
+		File keyfile = new File("NPOTKey");
+		if (keyfile.exists()) {
+			FileInputStream fin = new FileInputStream(keyfile);
+			ObjectInputStream fois = new ObjectInputStream(fin);
+
+			C = (BigInteger) fois.readObject();
+			p = (BigInteger) fois.readObject();
+			q = (BigInteger) fois.readObject();
+			g = (BigInteger) fois.readObject();
+			gr = (BigInteger) fois.readObject();
+			r = (BigInteger) fois.readObject();
+			fois.close();
+
+			Flag.sw.startOTIO();
+			channel.writeBI(C);
+			channel.writeBI(p);
+			channel.writeBI(q);
+			channel.writeBI(g);
+			channel.writeBI(gr);
+			channel.writeInt(msgBitLength);
+			channel.flush();
+			Flag.sw.stopOTIO();
+
+			Cr = C.modPow(r, p);
+		} else {
+			BigInteger pdq;
+			q = new BigInteger(qLength, certainty, rnd);
+
+			do {
+				pdq = new BigInteger(pLength - qLength, rnd);
+				pdq = pdq.clearBit(0);
+				p = q.multiply(pdq).add(BigInteger.ONE);
+			} while (!p.isProbablePrime(certainty));
+
+			do {
+				g = new BigInteger(pLength - 1, rnd);
+			} while ((g.modPow(pdq, p)).equals(BigInteger.ONE) || (g.modPow(q, p)).equals(BigInteger.ONE));
+
+			r = (new BigInteger(qLength, rnd)).mod(q);
+			gr = g.modPow(r, p);
+			C = (new BigInteger(qLength, rnd)).mod(q);
+
+			Flag.sw.startOTIO();
+			channel.writeBI(C);
+			channel.writeBI(p);
+			channel.writeBI(q);
+			channel.writeBI(g);
+			channel.writeBI(gr);
+			channel.writeInt(msgBitLength);
+			channel.flush();
+			Flag.sw.stopOTIO();
+
+			Cr = C.modPow(r, p);
+
+			FileOutputStream fout = new FileOutputStream(keyfile);
+			ObjectOutputStream foos = new ObjectOutputStream(fout);
+
+			foos.writeObject(C);
+			foos.writeObject(p);
+			foos.writeObject(q);
+			foos.writeObject(g);
+			foos.writeObject(gr);
+			foos.writeObject(r);
+
+			foos.flush();
+			foos.close();
+		}
+	}
+
+	GCSignal[][] m = new GCSignal[1][2];
+
+	@Override
+	public void send(GCSignal[] msgPair) throws IOException {
+		m[0][0] = msgPair[0];
+		m[0][1] = msgPair[1];
+		send(m);
+	}
+
+	private void step1(GCSignal[][] msgPairs) throws IOException {
+		BigInteger[] pk0 = new BigInteger[msgPairs.length];
+		Flag.sw.startOTIO();
+		for (int i = 0; i < pk0.length; i++)
+			pk0[i] = channel.readBI();
+		Flag.sw.stopOTIO();
+
+		BigInteger[] pk1 = new BigInteger[msgPairs.length];
+		BigInteger[][] msg = new BigInteger[msgPairs.length][2];
+
+		for (int i = 0; i < msgPairs.length; i++) {
+			pk0[i] = pk0[i].modPow(r, p);
+			pk1[i] = Cr.multiply(pk0[i].modInverse(p)).mod(p);
+
+			msg[i][0] = cipher.encrypt(pk0[i].toByteArray(), new BigInteger(msgPairs[i][0].bytes), msgBitLength);
+			msg[i][1] = cipher.encrypt(pk1[i].toByteArray(), new BigInteger(msgPairs[i][1].bytes), msgBitLength);
+		}
+		Flag.sw.startOTIO();
+		for (int i = 0; i < msg.length; i++) {
+			channel.writeBI(msg[i][0]);
+			channel.writeBI(msg[i][1]);
+		}
+		channel.flush();
+		Flag.sw.stopOTIO();
+
+	}
+}

+ 143 - 0
ObliVMGC/com/oblivm/backend/ot/OTExtReceiver.java

@@ -0,0 +1,143 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// Improved by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+import com.oblivm.backend.ot.OTExtSender.SecurityParameter;
+import com.oblivm.backend.rand.ISAACProvider;
+
+public class OTExtReceiver extends OTReceiver {
+	static SecureRandom rnd;
+
+	static {
+		Security.addProvider(new ISAACProvider());
+		try {
+			rnd = SecureRandom.getInstance("ISAACRandom");
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		}
+	}
+
+	private int msgBitLength;
+
+	private OTSender snder;
+	private GCSignal[][] keyPairs;
+
+	Cipher cipher;
+
+	public OTExtReceiver(Network channel) {
+		super(channel);
+
+		cipher = new Cipher();
+
+		try {
+			initialize();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	boolean[] s = new boolean[SecurityParameter.k1];
+
+	public GCSignal[] receive(boolean[] choices) throws IOException {
+		GCSignal[] keys = new GCSignal[SecurityParameter.k1];
+
+		boolean[] c = new boolean[SecurityParameter.k1 + choices.length];
+		for (int i = 0; i < SecurityParameter.k1; i++)
+			c[i] = rnd.nextBoolean();
+		for (int i = SecurityParameter.k1; i < c.length; i++)
+			c[i] = choices[i - SecurityParameter.k1];
+
+		GCSignal[] received = reverseAndExtend(keyPairs, c, msgBitLength, channel, cipher);
+
+		for (int i = 0; i < OTExtSender.SecurityParameter.k1; i++) {
+			keys[i] = received[i];
+			s[i] = c[i];
+		}
+		for (int i = 0; i < OTExtSender.SecurityParameter.k1; i++) {
+			keyPairs[i][0] = GCSignal.freshLabel(rnd);
+			keyPairs[i][1] = GCSignal.freshLabel(rnd);
+		}
+		OTExtSender.reverseAndExtend(s, keys, msgBitLength, keyPairs, channel, cipher);
+
+		return Arrays.copyOfRange(received, SecurityParameter.k1, received.length);
+	}
+
+	static GCSignal[] reverseAndExtend(GCSignal[][] keyPairs, boolean[] choices, int msgBitLength, Network channel,
+			Cipher cipher) throws IOException {
+		BigInteger[][] msgPairs = new BigInteger[SecurityParameter.k1][2];
+		BigInteger[][] cphPairs = new BigInteger[SecurityParameter.k1][2];
+
+		BitMatrix T = new BitMatrix(choices.length, SecurityParameter.k1);
+		T.initialize(rnd);
+
+		BigInteger biChoices = OTExtSender.fromBoolArray(choices);
+		for (int i = 0; i < SecurityParameter.k1; i++) {
+			msgPairs[i][0] = T.data[i];
+			msgPairs[i][1] = T.data[i].xor(biChoices);
+
+			cphPairs[i][0] = cipher.encrypt(keyPairs[i][0].bytes, msgPairs[i][0], choices.length);
+			cphPairs[i][1] = cipher.encrypt(keyPairs[i][1].bytes, msgPairs[i][1], choices.length);
+			channel.writeBI(cphPairs[i][0]);
+			channel.writeBI(cphPairs[i][1]);
+		}
+
+		Flag.sw.startOTIO();
+		channel.flush();
+		Flag.sw.stopOTIO();
+
+		BitMatrix tT = T.transpose();
+		GCSignal[] res = new GCSignal[choices.length];
+
+		GCSignal[][] y = new GCSignal[choices.length][2];
+
+		for (int i = 0; i < choices.length; i++) {
+			y[i][0] = GCSignal.receive(channel);
+			y[i][1] = GCSignal.receive(channel);
+			int sigma = choices[i] ? 1 : 0;
+			res[i] = cipher.dec(GCSignal.newInstance(tT.data[i].toByteArray()), y[i][sigma], i);
+		}
+
+		return res;
+	}
+
+	private void initialize() throws Exception {
+		Flag.sw.startOTIO();
+		msgBitLength = channel.readInt();
+		Flag.sw.stopOTIO();
+
+		snder = new NPOTSender(OTExtSender.SecurityParameter.k1, channel);
+
+		keyPairs = new GCSignal[OTExtSender.SecurityParameter.k1][2];
+		for (int i = 0; i < OTExtSender.SecurityParameter.k1; i++) {
+			keyPairs[i][0] = GCSignal.freshLabel(rnd);
+			keyPairs[i][1] = GCSignal.freshLabel(rnd);
+		}
+
+		snder.send(keyPairs);
+		channel.flush();
+	}
+
+	GCSignal[] pool;
+	int poolIndex = 0;
+
+	@Override
+	public GCSignal receive(boolean c) {
+		try {
+			throw new Exception("It doesn't make sense to do single OT with OT extension!");
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return null;
+	}
+}

+ 155 - 0
ObliVMGC/com/oblivm/backend/ot/OTExtSender.java

@@ -0,0 +1,155 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// Improved by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.Security;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+import com.oblivm.backend.rand.ISAACProvider;
+
+public class OTExtSender extends OTSender {
+	static class SecurityParameter {
+		public static final int k1 = 80; // number of columns in T
+	}
+
+	private static SecureRandom rnd;
+
+	static {
+		Security.addProvider(new ISAACProvider());
+		try {
+			rnd = SecureRandom.getInstance("ISAACRandom");
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		}
+	}
+
+	private OTReceiver rcver;
+	private boolean[] s;
+	private GCSignal[] keys;
+
+	Cipher cipher;
+
+	public OTExtSender(int msgBitLength, Network channel) {
+		super(msgBitLength, channel);
+
+		cipher = new Cipher();
+
+		try {
+			initialize();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	int poolIndex = 0;
+
+	@Override
+	public void send(GCSignal[] m) {
+		try {
+			throw new Exception("It doesn't make sense to do single OT with OT extension!");
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/*
+	 * Everything in msgPairs are effective Sender's messages.
+	 */
+	GCSignal[][] keyPairs = new GCSignal[SecurityParameter.k1][2];
+
+	public void send(GCSignal[][] msgPairs) throws IOException {
+		GCSignal[][] pairs = new GCSignal[SecurityParameter.k1 + msgPairs.length][2];
+		for (int i = 0; i < SecurityParameter.k1; i++) {
+			pairs[i][0] = GCSignal.freshLabel(rnd);
+			pairs[i][1] = GCSignal.freshLabel(rnd);
+		}
+
+		for (int i = SecurityParameter.k1; i < pairs.length; i++) {
+			pairs[i][0] = msgPairs[i - SecurityParameter.k1][0];
+			pairs[i][1] = msgPairs[i - SecurityParameter.k1][1];
+		}
+
+		reverseAndExtend(s, keys, msgBitLength, pairs, channel, cipher);
+
+		for (int i = 0; i < SecurityParameter.k1; i++) {
+			keyPairs[i][0] = pairs[i][0];
+			keyPairs[i][1] = pairs[i][1];
+		}
+		for (int i = 0; i < s.length; i++)
+			s[i] = rnd.nextBoolean();
+		keys = OTExtReceiver.reverseAndExtend(keyPairs, s, SecurityParameter.k1, channel, cipher);
+	}
+
+	// Given s and keys, obliviously sends msgPairs which contains 'numOfPairs'
+	// pairs of strings, each of length 'msgBitLength' bits.
+
+	static void reverseAndExtend(boolean[] s, GCSignal[] keys, int msgBitLength, GCSignal[][] msgPairs, Network channel,
+			Cipher cipher) throws IOException {
+		BigInteger[][] cphPairs = new BigInteger[SecurityParameter.k1][2];
+
+		Flag.sw.startOTIO();
+		for (int i = 0; i < SecurityParameter.k1; i++) {
+			cphPairs[i][0] = channel.readBI();
+			cphPairs[i][1] = channel.readBI();
+		}
+		Flag.sw.stopOTIO();
+
+		int numOfPairs = msgPairs.length;
+
+		BitMatrix Q = new BitMatrix(numOfPairs, SecurityParameter.k1);
+
+		for (int i = 0; i < SecurityParameter.k1; i++) {
+			if (s[i])
+				Q.data[i] = cipher.decrypt(keys[i].bytes, cphPairs[i][1], numOfPairs);
+			else
+				Q.data[i] = cipher.decrypt(keys[i].bytes, cphPairs[i][0], numOfPairs);
+		}
+
+		BitMatrix tQ = Q.transpose();
+
+		BigInteger biS = fromBoolArray(s);
+
+		GCSignal[][] y = new GCSignal[numOfPairs][2];
+		for (int i = 0; i < numOfPairs; i++) {
+			y[i][0] = cipher.enc(GCSignal.newInstance(tQ.data[i].toByteArray()), msgPairs[i][0], i);
+			y[i][1] = cipher.enc(GCSignal.newInstance(tQ.data[i].xor(biS).toByteArray()), msgPairs[i][1], i);
+			y[i][0].send(channel);
+			y[i][1].send(channel);
+		}
+
+		Flag.sw.startOTIO();
+		channel.flush();
+		Flag.sw.stopOTIO();
+
+	}
+
+	private void initialize() throws Exception {
+		Flag.sw.startOTIO();
+		channel.writeInt(msgBitLength);
+		channel.flush();
+		Flag.sw.stopOTIO();
+
+		rcver = new NPOTReceiver(channel);
+
+		s = new boolean[SecurityParameter.k1];
+		for (int i = 0; i < s.length; i++)
+			s[i] = rnd.nextBoolean();
+
+		keys = rcver.receive(s);
+	}
+
+	public static BigInteger fromBoolArray(boolean[] a) {
+		BigInteger res = BigInteger.ZERO;
+		for (int i = 0; i < a.length; i++)
+			if (a[i])
+				res = res.setBit(i);
+		return res;
+	}
+}

+ 84 - 0
ObliVMGC/com/oblivm/backend/ot/OTPreprocessReceiver.java

@@ -0,0 +1,84 @@
+// Copyright (C) by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class OTPreprocessReceiver extends OTReceiver {
+	GCSignal[] buffer = new GCSignal[OTPreprocessSender.bufferSize];
+	boolean[] choose = new boolean[OTPreprocessSender.bufferSize];
+	int bufferusage = 0;
+
+	public void fillup() {
+		channel.flush();
+
+		while (bufferusage < OTPreprocessSender.bufferSize) {
+			int l = Math.min(OTPreprocessSender.fillLength, OTPreprocessSender.bufferSize - bufferusage);
+
+			for (int i = bufferusage; i < bufferusage + l; ++i)
+				choose[i] = CompEnv.rnd.nextBoolean();
+			GCSignal[] kc = null;
+			try {
+				kc = reciever.receive(Arrays.copyOfRange(choose, bufferusage, bufferusage + l));
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			System.arraycopy(kc, 0, buffer, bufferusage, kc.length);
+			bufferusage += l;
+		}
+
+		channel.flush();
+
+	}
+
+	OTExtReceiver reciever;
+
+	public OTPreprocessReceiver(Network channel) {
+		super(channel);
+		reciever = new OTExtReceiver(channel);
+		fillup();
+	}
+
+	public GCSignal receive(boolean b) throws IOException {
+		bufferusage--;
+		byte z = (b ^ choose[bufferusage]) ? (byte) 1 : (byte) 0;
+		Flag.sw.startOTIO();
+		channel.writeByte(z);
+		channel.flush();
+		GCSignal[] y = new GCSignal[] { GCSignal.receive(channel), GCSignal.receive(channel) };
+		Flag.sw.stopOTIO();
+		if (bufferusage == 0)
+			fillup();
+		return y[b ? 1 : 0].xor(buffer[bufferusage]);
+	}
+
+	public GCSignal[] receive(boolean[] b) throws IOException {
+		if (bufferusage < b.length)
+			fillup();
+		byte[] z = new byte[b.length];
+		int tmp = bufferusage;
+		for (int i = 0; i < b.length; ++i) {
+			--tmp;
+			z[i] = (b[i] ^ choose[tmp]) ? (byte) 1 : (byte) 0;
+		}
+		Flag.sw.startOTIO();
+		channel.writeByte(z, z.length);
+		channel.flush();
+		Flag.sw.stopOTIO();
+		GCSignal[] ret = new GCSignal[b.length];
+		for (int i = 0; i < b.length; ++i) {
+			bufferusage--;
+			Flag.sw.startOTIO();
+			GCSignal[] y = new GCSignal[] { GCSignal.receive(channel), GCSignal.receive(channel) };
+			Flag.sw.stopOTIO();
+			ret[i] = y[b[i] ? 1 : 0].xor(buffer[bufferusage]);
+		}
+		return ret;
+	}
+}

+ 79 - 0
ObliVMGC/com/oblivm/backend/ot/OTPreprocessSender.java

@@ -0,0 +1,79 @@
+// Copyright (C) by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.gc.GCGenComp;
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public class OTPreprocessSender extends OTSender {
+	OTExtSender sender;
+
+	public OTPreprocessSender(int msgBitLength, Network channel) {
+		super(msgBitLength, channel);
+		sender = new OTExtSender(msgBitLength, channel);
+		fillup();
+	}
+
+	final static public int bufferSize = 1024 * 1024 * 1;
+	final static public int fillLength = 300000;
+	GCSignal[][] buffer = new GCSignal[bufferSize][2];
+	int bufferusage = 0;
+
+	public void fillup() {
+
+		channel.flush();
+
+		while (bufferusage < bufferSize) {
+			int l = Math.min(fillLength, bufferSize - bufferusage);
+			for (int i = bufferusage; i < bufferusage + l; ++i)
+				buffer[i] = GCGenComp.genPair();
+			try {
+				sender.send(Arrays.copyOfRange(buffer, bufferusage, bufferusage + l));
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			bufferusage += l;
+			System.out.println("preprocessing OT" + bufferusage / (double) bufferSize);
+		}
+		channel.flush();
+	}
+
+	public void send(GCSignal[] m) throws IOException {
+		Flag.sw.startOTIO();
+		byte z = channel.readBytes(1)[0];
+		Flag.sw.stopOTIO();
+		bufferusage--;
+		if (z == 0) {
+			m[0].xor(buffer[bufferusage][0]).send(channel);
+			m[1].xor(buffer[bufferusage][1]).send(channel);
+		} else {
+			m[0].xor(buffer[bufferusage][1]).send(channel);
+			m[1].xor(buffer[bufferusage][0]).send(channel);
+		}
+		if (bufferusage == 0)
+			fillup();
+	}
+
+	public void send(GCSignal[][] m) throws IOException {
+		if (bufferusage < m.length)
+			fillup();
+		Flag.sw.startOTIO();
+		byte[] z = channel.readBytes(m.length);
+		Flag.sw.stopOTIO();
+		for (int i = 0; i < m.length; ++i) {
+			bufferusage--;
+			if (z[i] == 0) {
+				m[i][0].xor(buffer[bufferusage][0]).send(channel);
+				m[i][1].xor(buffer[bufferusage][1]).send(channel);
+			} else {
+				m[i][0].xor(buffer[bufferusage][1]).send(channel);
+				m[i][1].xor(buffer[bufferusage][0]).send(channel);
+			}
+		}
+	}
+}

+ 22 - 0
ObliVMGC/com/oblivm/backend/ot/OTReceiver.java

@@ -0,0 +1,22 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// Improved by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.io.IOException;
+
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public abstract class OTReceiver {
+	Network channel;
+	int msgBitLength;
+
+	public OTReceiver(Network channel) {
+		this.channel = channel;
+	}
+
+	public abstract GCSignal receive(boolean c) throws IOException;
+
+	public abstract GCSignal[] receive(boolean[] c) throws IOException;
+}

+ 23 - 0
ObliVMGC/com/oblivm/backend/ot/OTSender.java

@@ -0,0 +1,23 @@
+// Copyright (C) 2013 by Yan Huang <yhuang@cs.umd.edu>
+// Improved by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+
+package com.oblivm.backend.ot;
+
+import java.io.IOException;
+
+import com.oblivm.backend.gc.GCSignal;
+import com.oblivm.backend.network.Network;
+
+public abstract class OTSender {
+	Network channel;
+	int msgBitLength;
+
+	public OTSender(int bitLen, Network channel) {
+		this.channel = channel;
+		msgBitLength = bitLen;
+	}
+
+	public abstract void send(GCSignal[] m) throws IOException;
+
+	public abstract void send(GCSignal[][] m) throws IOException;
+}

+ 264 - 0
ObliVMGC/com/oblivm/backend/rand/ISAACAlgorithm.java

@@ -0,0 +1,264 @@
+package com.oblivm.backend.rand;
+
+/**
+ * <h3>ISAAC: a fast cryptographic pseudo-random number generator</h3>
+ * 
+ * ISAAC (Indirection, Shift, Accumulate, Add, and Count) generates 32-bit
+ * random numbers.<br>
+ * ISAAC has been designed to be cryptographically secure and is inspired by
+ * RC4.<br>
+ * Cycles are guaranteed to be at least 2<sup>40</sup> values long, and they are
+ * 2<sup>8295</sup> values long on average.<br>
+ * The results are uniformly distributed, unbiased, and unpredictable unless you
+ * know the seed.<br>
+ * <br>
+ * This is the original implementation by Bob Jenkins with some minor changes.
+ * <br>
+ * <br>
+ * <b>Changelog:</b><br>
+ * <ul>
+ * <li>050325: Added <code>supplementSeed(int[] seed )</code> method; made all
+ * variables private</li>
+ * <li>050320: Use <code>System.arraycopy()</code> in
+ * <code>ISAACAlgorithm(int[] seed)</code></li>
+ * <li>980224: Translate to Java</li>
+ * <li>970719: Use context, not global variables, for internal state</li>
+ * <li>960327: Creation (addition of randinit, really)</li>
+ * </ul>
+ * 
+ * @author Bob Jenkins
+ * @version 050325
+ */
+class ISAACAlgorithm {
+	private static final int SIZEL = 8; // Log of size of rsl[] and mem[]
+	private static final int SIZE = 1 << SIZEL; // Size of rsl[] and mem[]
+	private static final int MASK = (SIZE - 1) << 2; // For pseudorandom lookup
+	private int count; // Count through the results in rsl[]
+	private int rsl[]; // The results given to the user
+	private int mem[]; // The internal state
+	private int a; // Accumulator
+	private int b; // The last result
+	private int c; // Counter, guarantees cycle is at least 2^40
+
+	/**
+	 * This constructor creates and initializes an new instance without using a
+	 * seed.<br>
+	 * Equivalent to <code>randinit(ctx,FALSE)</code> in the C implementation.
+	 */
+	ISAACAlgorithm() {
+		mem = new int[SIZE];
+		rsl = new int[SIZE];
+
+		init(false);
+	}
+
+	/**
+	 * This constructor creates and initializes an new instance using a
+	 * user-provided seed.<br>
+	 * Equivalent to <code>randinit(ctx, TRUE)</code> after putting seed in
+	 * <code>randctx</code> in the C implementation.
+	 * 
+	 * @param seed
+	 *            The seed.
+	 */
+	ISAACAlgorithm(int[] seed) {
+		mem = new int[SIZE];
+		rsl = new int[SIZE];
+
+		// This is slow and throws an ArrayIndexOutOfBoundsException if
+		// seed.length > rsl.length ...
+		/* for (int i = 0; i < seed.length; ++i) rsl[i] = seed[i]; */
+		// ... this is faster and safe:
+		System.arraycopy(seed, 0, rsl, 0, (seed.length <= rsl.length) ? seed.length : rsl.length);
+
+		init(true);
+	}
+
+	/**
+	 * Generate 256 results.<br>
+	 * This is a small (not fast) implementation.
+	 */
+	private final void isaac() {
+		int i, x, y;
+
+		b += ++c;
+		for (i = 0; i < SIZE; ++i) {
+			x = mem[i];
+			switch (i & 3) {
+			case 0:
+				a ^= a << 13;
+				break;
+			case 1:
+				a ^= a >>> 6;
+				break;
+			case 2:
+				a ^= a << 2;
+				break;
+			case 3:
+				a ^= a >>> 16;
+				break;
+			}
+			a += mem[(i + SIZE / 2) & (SIZE - 1)];
+			mem[i] = y = mem[((x) & MASK) >> 2] + a + b;
+			rsl[i] = b = mem[((y >> SIZEL) & MASK) >> 2] + x;
+		}
+	}
+
+	/**
+	 * Initialize or reinitialize this instance.
+	 * 
+	 * @param flag
+	 *            If <code>true</code> then use the seed (which the constructor
+	 *            placed in <code>rsl[]</code>) for initialization.
+	 */
+	private final void init(boolean flag) {
+		int i;
+		int a, b, c, d, e, f, g, h;
+		a = b = c = d = e = f = g = h = 0x9e3779b9; // The golden ratio
+
+		for (i = 0; i < 4; ++i) {
+			a ^= b << 11;
+			d += a;
+			b += c;
+			b ^= c >>> 2;
+			e += b;
+			c += d;
+			c ^= d << 8;
+			f += c;
+			d += e;
+			d ^= e >>> 16;
+			g += d;
+			e += f;
+			e ^= f << 10;
+			h += e;
+			f += g;
+			f ^= g >>> 4;
+			a += f;
+			g += h;
+			g ^= h << 8;
+			b += g;
+			h += a;
+			h ^= a >>> 9;
+			c += h;
+			a += b;
+		}
+
+		for (i = 0; i < SIZE; i += 8) { // Fill in mem[] with messy stuff
+			if (flag) {
+				a += rsl[i];
+				b += rsl[i + 1];
+				c += rsl[i + 2];
+				d += rsl[i + 3];
+				e += rsl[i + 4];
+				f += rsl[i + 5];
+				g += rsl[i + 6];
+				h += rsl[i + 7];
+			}
+			a ^= b << 11;
+			d += a;
+			b += c;
+			b ^= c >>> 2;
+			e += b;
+			c += d;
+			c ^= d << 8;
+			f += c;
+			d += e;
+			d ^= e >>> 16;
+			g += d;
+			e += f;
+			e ^= f << 10;
+			h += e;
+			f += g;
+			f ^= g >>> 4;
+			a += f;
+			g += h;
+			g ^= h << 8;
+			b += g;
+			h += a;
+			h ^= a >>> 9;
+			c += h;
+			a += b;
+			mem[i] = a;
+			mem[i + 1] = b;
+			mem[i + 2] = c;
+			mem[i + 3] = d;
+			mem[i + 4] = e;
+			mem[i + 5] = f;
+			mem[i + 6] = g;
+			mem[i + 7] = h;
+		}
+
+		if (flag) { // Second pass: makes all of seed affect all of mem[]
+			for (i = 0; i < SIZE; i += 8) {
+				a += mem[i];
+				b += mem[i + 1];
+				c += mem[i + 2];
+				d += mem[i + 3];
+				e += mem[i + 4];
+				f += mem[i + 5];
+				g += mem[i + 6];
+				h += mem[i + 7];
+				a ^= b << 11;
+				d += a;
+				b += c;
+				b ^= c >>> 2;
+				e += b;
+				c += d;
+				c ^= d << 8;
+				f += c;
+				d += e;
+				d ^= e >>> 16;
+				g += d;
+				e += f;
+				e ^= f << 10;
+				h += e;
+				f += g;
+				f ^= g >>> 4;
+				a += f;
+				g += h;
+				g ^= h << 8;
+				b += g;
+				h += a;
+				h ^= a >>> 9;
+				c += h;
+				a += b;
+				mem[i] = a;
+				mem[i + 1] = b;
+				mem[i + 2] = c;
+				mem[i + 3] = d;
+				mem[i + 4] = e;
+				mem[i + 5] = f;
+				mem[i + 6] = g;
+				mem[i + 7] = h;
+			}
+		}
+
+		isaac();
+		count = SIZE;
+	}
+
+	/**
+	 * Get a random integer value.
+	 */
+	final int nextInt() {
+		if (0 == count--) {
+			isaac();
+			count = SIZE - 1;
+		}
+
+		return (rsl[count]);
+	}
+
+	/**
+	 * Reseeds this random object.<br>
+	 * The given seed supplements (using bitwise xor), rather than replaces, the
+	 * existing seed.
+	 * 
+	 * @param seed
+	 *            An integer array containing the seed.
+	 */
+	final void supplementSeed(int[] seed) {
+		for (int i = 0; i < seed.length; i++)
+			mem[i % mem.length] ^= seed[i];
+	}
+}

+ 183 - 0
ObliVMGC/com/oblivm/backend/rand/ISAACEngine.java

@@ -0,0 +1,183 @@
+package com.oblivm.backend.rand;
+
+import java.security.SecureRandom;
+import java.security.SecureRandomSpi;
+
+/**
+ * This class defines the Service Provider for the ISAAC algorithm.
+ * 
+ * @author Daniel Berlin
+ */
+public class ISAACEngine extends SecureRandomSpi {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private ISAACAlgorithm isaac;
+	private byte[] remainder;
+	private int remCount = 0;
+
+	/**
+	 * Creates a new instance and seeds it with random data obtained from
+	 * <code>java.security.SecureRandom</code>'s <code>getSeed()</code> method.
+	 */
+	public ISAACEngine() {
+		byte[] temp = new byte[1024];// SecureRandom.getSeed (1024);
+		new SecureRandom().nextBytes(temp);
+		this.isaac = new ISAACAlgorithm(ISAACEngine.packToIntArray(temp));
+	}
+
+	/**
+	 * Returns the given number of seed bytes computed using the ISAAC
+	 * algorithm.<br>
+	 * It just calls <code>engineNextBytes()</code> internally.<br>
+	 * This call may be used to seed other random number generators.
+	 * 
+	 * @param numBytes
+	 *            The number of seed bytes to generate.
+	 * @return The seed bytes.
+	 */
+	public byte[] engineGenerateSeed(int numBytes) {
+		byte[] seed = new byte[numBytes];
+		this.engineNextBytes(seed);
+
+		return (seed);
+	}
+
+	/**
+	 * Generates a user-specified number of random bytes.
+	 * 
+	 * @param bytes
+	 *            The array to fill with random bytes.
+	 */
+	public void engineNextBytes(byte[] bytes) {
+		int index = 0;
+		int todo;
+		byte[] output = this.remainder;
+
+		// First use remainder from last time
+		int rC = this.remCount;
+		if (rC > 0) {
+			todo = (bytes.length - index) < (4 - rC) ? (bytes.length - index) : (4 - rC);
+			for (int i = 0; i < todo; i++, rC++)
+				bytes[i] = output[rC];
+
+			this.remCount += todo;
+			index += todo;
+		}
+
+		// If we need more bytes, get them
+		while (index < bytes.length) {
+			output = ISAACEngine.toByteArray(this.isaac.nextInt());
+
+			todo = (bytes.length - index) > 4 ? 4 : (bytes.length - index);
+			for (int i = 0; i < todo; i++, index++)
+				bytes[index] = output[i];
+
+			this.remCount += todo;
+		}
+
+		// Store remainder for next time
+		this.remainder = output;
+		this.remCount %= 4;
+	}
+
+	/**
+	 * Reseeds this random object. The given seed supplements, rather than
+	 * replaces, the existing seed.
+	 * 
+	 * @param seed
+	 *            The seed.
+	 */
+	public void engineSetSeed(byte[] seed) {
+		this.isaac.supplementSeed(ISAACEngine.packToIntArray(seed));
+	}
+
+	// ====================================
+	// ===== private "helper" methods =====
+	// ====================================
+
+	private static final int[] mask = new int[] { 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF };
+
+	/**
+	 * Returns a byte array containing the two's-complement representation of
+	 * the integer.<br>
+	 * The byte array will be in big-endian byte-order with a fixes length of 4
+	 * (the least significant byte is in the 4th element).<br>
+	 * <br>
+	 * <u>Example:</u><br>
+	 * <code>toByteArray(258)</code> returns { 0, 0, 1, 2 },<br>
+	 * <code>BigInteger.valueOf(258).toByteArray()</code> returns { 1, 2 }.
+	 *
+	 * @param intValue
+	 *            The integer to be converted.
+	 * @return The byte array of length 4.
+	 */
+	private static byte[] toByteArray(final int intValue) {
+		int byteNum = (40 - numberOfLeadingZeros(intValue < 0 ? ~intValue : intValue)) / 8;
+		byte[] byteArray = new byte[4];
+
+		for (int i = 0; i < byteNum; i++)
+			byteArray[3 - i] = (byte) (intValue >>> (i * 8));
+
+		return (byteArray);
+	}
+
+	/**
+	 * Returns the number of zero bits preceding the highest-order ("leftmost")
+	 * one-bit in the two's complement binary representation of the specified
+	 * integer value.
+	 * 
+	 * @return The number of zero bits preceding the highest-order one-bit in
+	 *         the two's complement binary representation of the specified
+	 *         integer value, or 32 if the value is equal to zero.
+	 */
+	private static int numberOfLeadingZeros(int intValue) {
+		if (intValue == 0)
+			return (32);
+
+		int num = 1;
+		for (int i = 16, j = 16; j > 1; i += j) {
+			if (intValue >>> i == 0) {
+				num += j;
+				intValue <<= j;
+			}
+			j /= 2;
+		}
+		num -= intValue >>> 31;
+
+		return (num);
+	}
+
+	/**
+	 * Creates an array of integers and "packs" the bytes from the byte array
+	 * into it.<br>
+	 * This method returns an integer array of length zero if <code>ba</code> is
+	 * <code>null</code>.<br>
+	 * <br>
+	 * <u>Example:</u><br>
+	 * <code>packToIntArray(new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5 })</code>
+	 * returns an integer array<br>
+	 * containing the values <code>0x01020304</code> and <code>0x00000005</code>
+	 * .
+	 * 
+	 * @param ba
+	 *            The byte array, may be <code>null</code>.
+	 * @return An array of integers containing the "packed" byte(s).
+	 */
+	private static int[] packToIntArray(final byte[] ba) {
+		if (ba == null)
+			return (new int[0]);
+
+		int[] ia = new int[(ba.length + 3) / 4];
+
+		for (int i = 0; i < ia.length; i++) {
+			int restLen = Math.min(4, ba.length - i * 4);
+
+			for (int b = 0; b < restLen; b++)
+				ia[i] |= (ba[b + i * 4] << ((restLen - b - 1) * 8)) & mask[b + 4 - restLen];
+		}
+
+		return (ia);
+	}
+}

+ 26 - 0
ObliVMGC/com/oblivm/backend/rand/ISAACProvider.java

@@ -0,0 +1,26 @@
+package com.oblivm.backend.rand;
+
+/**
+ * @author Daniel Berlin
+ */
+public final class ISAACProvider extends java.security.Provider {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	public static final String NAME = "ISAACProvider";
+	public static final double VERSION = 0.3;
+	public static final String INFO = "Provider for the ISAAC PRNG";
+
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public ISAACProvider() {
+		super(NAME, VERSION, INFO);
+
+		java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {
+			public Object run() {
+				put("SecureRandom.ISAACRandom", "com.oblivm.backend.rand.ISAACEngine");
+				return (null);
+			}
+		});
+	}
+}

+ 7 - 0
ObliVMGC/com/oblivm/backend/util/Constants.java

@@ -0,0 +1,7 @@
+package com.oblivm.backend.util;
+
+public class Constants {
+	public static final String MACHINE_SPEC = "machine_spec/";
+	public static final String INPUT_DIR = "in/";
+	public static final int OFFLINE_FILE_BUFFER_SIZE = 1024 * 1024 * 1024;
+}

+ 126 - 0
ObliVMGC/com/oblivm/backend/util/EvaRunnable.java

@@ -0,0 +1,126 @@
+package com.oblivm.backend.util;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.Scanner;
+
+import org.apache.commons.cli.ParseException;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.flexsc.Party;
+
+public abstract class EvaRunnable<T> extends com.oblivm.backend.network.Client implements Runnable {
+	public abstract void prepareInput(CompEnv<T> gen) throws Exception;
+
+	public abstract void secureCompute(CompEnv<T> gen) throws Exception;
+
+	public abstract void prepareOutput(CompEnv<T> gen) throws Exception;
+
+	Mode m;
+	int port;
+	String host;
+	protected String[] args;
+	public boolean verbose = true;
+
+	public void setParameter(Mode m, String host, int port, String[] args) {
+		this.m = m;
+		this.port = port;
+		this.host = host;
+		this.args = args;
+	}
+
+	public void setParameter(Mode m, String host, int port) {
+		this.m = m;
+		this.port = port;
+		this.host = host;
+	}
+
+	public void runCore() throws Exception {
+		if (verbose)
+			System.out.println("connecting " + host + " " + port);
+		connect(host, port);
+		if (verbose)
+			System.out.println("connected");
+
+		@SuppressWarnings("unchecked")
+		CompEnv<T> env = CompEnv.getEnv(m, Party.Bob, this);
+
+		double s = System.nanoTime();
+		Flag.sw.startTotal();
+		prepareInput(env);
+		os.flush();
+		secureCompute(env);
+		os.flush();
+		prepareOutput(env);
+		os.flush();
+		Flag.sw.stopTotal();
+		double e = System.nanoTime();
+		disconnect();
+		if (verbose) {
+			System.out.println("Eva running time:" + (e - s) / 1e9);
+			System.out.println("Number Of AND Gates:" + env.numOfAnds);
+		}
+	}
+
+	public void run() {
+		try {
+			runCore();
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	public void loadConfig() {
+		loadConfig("config/Config.conf");
+	}
+
+	public void loadConfig(String fileName) {
+		File file = new File(fileName);
+		Scanner scanner;
+		String host = null;
+		int port = 0;
+		Mode mode = null;
+
+		try {
+			scanner = new Scanner(file);
+			while (scanner.hasNextLine()) {
+				String a = scanner.nextLine();
+				String[] content = a.split(":");
+				if (content.length == 2) {
+					if (content[0].equals("Host"))
+						host = content[1].replace(" ", "");
+					else if (content[0].equals("Port"))
+						port = new Integer(content[1].replace(" ", ""));
+					else if (content[0].equals("Mode"))
+						mode = Mode.getMode(content[1].replace(" ", ""));
+					else {
+					}
+				}
+			}
+			scanner.close();
+		} catch (FileNotFoundException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+		this.setParameter(mode, host, port);
+	}
+
+	@SuppressWarnings("rawtypes")
+	public static void main(String[] args)
+			throws InstantiationException, IllegalAccessException, ParseException, ClassNotFoundException {
+
+		Class<?> clazz = Class.forName(args[0] + "$Evaluator");
+		EvaRunnable run = (EvaRunnable) clazz.newInstance();
+		run.loadConfig();
+		run.run();
+		if (Flag.CountTime)
+			Flag.sw.print();
+		if (Flag.countIO)
+			run.printStatistic();
+	}
+}

+ 116 - 0
ObliVMGC/com/oblivm/backend/util/GenRunnable.java

@@ -0,0 +1,116 @@
+package com.oblivm.backend.util;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.Scanner;
+
+import org.apache.commons.cli.ParseException;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Flag;
+import com.oblivm.backend.flexsc.Mode;
+import com.oblivm.backend.flexsc.Party;
+
+public abstract class GenRunnable<T> extends com.oblivm.backend.network.Server implements Runnable {
+
+	Mode m;
+	int port;
+	protected String[] args;
+	public boolean verbose = true;
+
+	public void setParameter(Mode m, int port, String[] args) {
+		this.m = m;
+		this.port = port;
+		this.args = args;
+	}
+
+	public void setParameter(Mode m, int port) {
+		this.m = m;
+		this.port = port;
+	}
+
+	public abstract void prepareInput(CompEnv<T> gen) throws Exception;
+
+	public abstract void secureCompute(CompEnv<T> gen) throws Exception;
+
+	public abstract void prepareOutput(CompEnv<T> gen) throws Exception;
+
+	public void runCore() throws Exception {
+		if (verbose)
+			System.out.println("connecting " + port);
+		listen(port);
+		if (verbose)
+			System.out.println("connected");
+
+		@SuppressWarnings("unchecked")
+		CompEnv<T> env = CompEnv.getEnv(m, Party.Alice, this);
+
+		double s = System.nanoTime();
+		Flag.sw.startTotal();
+		prepareInput(env);
+		os.flush();
+		secureCompute(env);
+		os.flush();
+		prepareOutput(env);
+		os.flush();
+		Flag.sw.stopTotal();
+		double e = System.nanoTime();
+		disconnect();
+		if (verbose) {
+			System.out.println("Gen running time:" + (e - s) / 1e9);
+			System.out.println("Number Of AND Gates:" + env.numOfAnds);
+		}
+
+	}
+
+	public void run() {
+		try {
+			runCore();
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	public void loadConfig(String configFile) {
+		File file = new File(configFile);
+
+		Scanner scanner;
+		int port = 0;
+		Mode mode = null;
+
+		try {
+			scanner = new Scanner(file);
+			while (scanner.hasNextLine()) {
+				String a = scanner.nextLine();
+				String[] content = a.split(":");
+				if (content.length == 2) {
+					if (content[0].equals("Port"))
+						port = new Integer(content[1].replace(" ", ""));
+					else if (content[0].equals("Mode"))
+						mode = Mode.getMode(content[1].replace(" ", ""));
+					else {
+					}
+				}
+			}
+			scanner.close();
+		} catch (FileNotFoundException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		this.setParameter(mode, port);
+	}
+
+	@SuppressWarnings("rawtypes")
+	public static void main(String[] args)
+			throws ParseException, ClassNotFoundException, InstantiationException, IllegalAccessException {
+
+		Class<?> clazz = Class.forName(args[0] + "$Generator");
+		GenRunnable run = (GenRunnable) clazz.newInstance();
+		run.loadConfig("config/Config.conf");
+		run.run();
+		if (Flag.CountTime)
+			Flag.sw.print();
+	}
+}

+ 31 - 0
ObliVMGC/com/oblivm/backend/util/Reciever.java

@@ -0,0 +1,31 @@
+package com.oblivm.backend.util;
+
+import org.apache.commons.cli.ParseException;
+
+public class Reciever<T> extends com.oblivm.backend.network.Server implements Runnable {
+
+	public void run() {
+		try {
+			listen(54321);
+
+			while (true) {
+				byte[] res = new byte[65536];// 1024*1024bits
+				double t = System.nanoTime();
+				os.write(res);
+				double t2 = System.nanoTime();
+				System.out.println((t2 - t) / 1000000000);
+
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	@SuppressWarnings("rawtypes")
+	public static void main(String[] args)
+			throws ParseException, ClassNotFoundException, InstantiationException, IllegalAccessException {
+		Reciever r = new Reciever();
+		r.run();
+	}
+}

+ 34 - 0
ObliVMGC/com/oblivm/backend/util/Sender.java

@@ -0,0 +1,34 @@
+package com.oblivm.backend.util;
+
+import org.apache.commons.cli.ParseException;
+
+import com.oblivm.backend.flexsc.Flag;
+
+public class Sender<T> extends com.oblivm.backend.network.Client implements Runnable {
+
+	public void run() {
+		try {
+			connect("192.168.1.102", 54321);
+			System.out.println("connected");
+
+			while (true) {
+				double t = System.nanoTime();
+				readBytes(65536);
+				double t2 = System.nanoTime();
+				System.out.println((t2 - t) / 1000000000);
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+
+	@SuppressWarnings("rawtypes")
+	public static void main(String[] args)
+			throws InstantiationException, IllegalAccessException, ParseException, ClassNotFoundException {
+		Sender r = new Sender();
+		r.run();
+		Flag.sw.print();
+
+	}
+}

+ 136 - 0
ObliVMGC/com/oblivm/backend/util/StopWatch.java

@@ -0,0 +1,136 @@
+// Copyright (C) 2014 by Xiao Shaun Wang <wangxiao@cs.umd.edu>
+package com.oblivm.backend.util;
+
+public class StopWatch {
+	public long ands = 0;
+	double startTimeOT = 0;
+	double stopTimeOT = 0;
+	public double elapsedTimeOT = 0;
+
+	double startTimeGC = 0;
+	double stopTimeGC = 0;
+	public double elapsedTimeGC = 0;
+
+	double startTimeTotal = 0;
+	double stopTimeTotal = 0;
+	public double elapsedTimeTotal = 0;
+
+	double startTimeOTIO = 0;
+	double stopTimeOTIO = 0;
+	public double elapsedTimeOTIO = 0;
+
+	double startTimeGCIO = 0;
+	double stopTimeGCIO = 0;
+	public double elapsedTimeGCIO = 0;
+	boolean countTime;
+	long counter = 1;
+
+	public StopWatch(boolean countTime) {
+		this.countTime = countTime;
+	}
+
+	public void startOT() {
+		if (countTime)
+			startTimeOT = System.nanoTime();
+	}
+
+	public void stopOT() {
+		if (countTime) {
+			stopTimeOT = System.nanoTime();
+			elapsedTimeOT += stopTimeOT - startTimeOT;
+		}
+	}
+
+	public void startOTIO() {
+		if (countTime)
+			startTimeOTIO = System.nanoTime();
+	}
+
+	public void stopOTIO() {
+		if (countTime) {
+			stopTimeOTIO = System.nanoTime();
+			elapsedTimeOTIO += stopTimeOTIO - startTimeOTIO;
+		}
+	}
+
+	public void startGC() {
+		if (countTime)
+			startTimeGC = System.nanoTime();
+	}
+
+	public void stopGC() {
+		if (countTime) {
+			stopTimeGC = System.nanoTime();
+			elapsedTimeGC += stopTimeGC - startTimeGC;
+		}
+	}
+
+	public void startGCIO() {
+		if (countTime)
+			startTimeGCIO = System.nanoTime();
+	}
+
+	public void stopGCIO() {
+		if (countTime) {
+			stopTimeGCIO = System.nanoTime();
+			elapsedTimeGCIO += stopTimeGCIO - startTimeGCIO;
+		}
+	}
+
+	public void startTotal() {
+		startTimeTotal = System.nanoTime();
+	}
+
+	public double stopTotal() {
+		stopTimeTotal = System.nanoTime();
+		elapsedTimeTotal += stopTimeTotal - startTimeTotal;
+		return stopTimeTotal - startTimeTotal;
+	}
+
+	public void addCounter() {
+		++counter;
+	}
+
+	public void flush() {
+		ands = 0;
+		startTimeOT = 0;
+		stopTimeOT = 0;
+		elapsedTimeOT = 0;
+
+		startTimeGC = 0;
+		stopTimeGC = 0;
+		elapsedTimeGC = 0;
+
+		startTimeTotal = 0;
+		stopTimeTotal = 0;
+		elapsedTimeTotal = 0;
+
+		startTimeOTIO = 0;
+		stopTimeOTIO = 0;
+		elapsedTimeOTIO = 0;
+
+		startTimeGCIO = 0;
+		stopTimeGCIO = 0;
+		elapsedTimeGCIO = 0;
+		counter = 1;
+
+	}
+
+	public void print() {
+		System.out.println("Total Time \t GC CPU Time\t GCIO Time\t OTCPU Time\t OTIO Time\n");
+		System.out.println(elapsedTimeTotal / 1000000000.0 / counter + "\t"
+				+ (elapsedTimeGC - elapsedTimeGCIO) / 1000000000.0 / counter + "\t"
+				+ elapsedTimeGCIO / 1000000000.0 / counter + " "
+				+ (elapsedTimeOT - elapsedTimeOTIO) / 1000000000.0 / counter + "\t"
+				+ elapsedTimeOTIO / 1000000000.0 / counter + "\n");
+		System.out.println("Number of Gate:" + ands);
+	}
+
+	public void print(int i) {
+		System.out.println("timer:\t" + i + " \t" + elapsedTimeTotal / 1000000000.0 / counter + "\t"
+				+ (elapsedTimeGC - elapsedTimeGCIO) / 1000000000.0 / counter + "\t"
+				+ elapsedTimeGCIO / 1000000000.0 / counter + " "
+				+ (elapsedTimeOT - elapsedTimeOTIO) / 1000000000.0 / counter + "\t"
+				+ elapsedTimeOTIO / 1000000000.0 / counter + "\n");
+	}
+}

+ 360 - 0
ObliVMGC/com/oblivm/backend/util/Utils.java

@@ -0,0 +1,360 @@
+package com.oblivm.backend.util;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+
+import com.oblivm.backend.flexsc.CompEnv;
+import com.oblivm.backend.flexsc.Party;
+
+public class Utils {
+	public static int logFloor(int n) {
+		int w = 0;
+		n--;
+		while (n > 0) {
+			w++;
+			n >>= 1;
+		}
+		return w == 0 ? 1 : w;
+	}
+
+	public static <T> void print(CompEnv<T> env, String name, T[] data, T[] data2, T con) throws Exception {
+		int a = toInt(env.outputToAlice(data));
+		int ab = toInt(env.outputToAlice(data2));
+		boolean cc = env.outputToAlice(con);
+
+		if (cc)
+			if (env.getParty() == Party.Alice && a != 0)
+				System.out.println(name + " " + a + " " + ab);
+
+	}
+
+	public static <T> void print(CompEnv<T> env, String name, T[] data) throws Exception {
+		long a = toSignedInt(env.outputToAlice(data));
+
+		if (env.getParty() == Party.Alice && a != 0)
+			System.out.println(name + " " + a);
+	}
+
+	public static <T> void print(CompEnv<T> env, String name, T data) throws Exception {
+		boolean a = env.outputToAlice(data);
+
+		if (env.getParty() == Party.Alice)
+			System.out.println(name + " " + a);
+	}
+
+	public static Boolean[] toBooleanArray(boolean[] a) {
+		Boolean[] res = new Boolean[a.length];
+		for (int i = 0; i < a.length; i++)
+			res[i] = a[i];
+		return res;
+	}
+
+	public static boolean[] tobooleanArray(Boolean[] a) {
+		boolean[] res = new boolean[a.length];
+		for (int i = 0; i < a.length; i++)
+			res[i] = a[i];
+		return res;
+	}
+
+	public static boolean[] fromInt(int value, int width) {
+		boolean[] res = new boolean[width];
+		for (int i = 0; i < width; i++)
+			res[i] = (((value >> i) & 1) == 0) ? false : true;
+
+		return res;
+	}
+
+	public static int toInt(boolean[] value) {
+		int res = 0;
+		for (int i = 0; i < value.length; i++)
+			res = (value[i]) ? (res | (1 << i)) : res;
+
+		return res;
+	}
+
+	public static long toUnSignedInt(boolean[] v) {
+		long result = 0;
+		for (int i = 0; i < v.length; ++i) {
+			if (v[i])
+				result += ((long) 1 << i);
+		}
+		return result;
+	}
+
+	public static long toSignedInt(boolean[] v) {
+		int i = 0;
+		if (v[v.length - 1] == false)
+			return toUnSignedInt(v);
+
+		boolean[] c2 = new boolean[v.length];
+		while (v[i] != true) {
+			c2[i] = v[i];
+			++i;
+		}
+		c2[i] = v[i];
+		++i;
+		for (; i < v.length; ++i)
+			c2[i] = !v[i];
+		return toUnSignedInt(c2) * -(long) (1);
+	}
+
+	public static boolean[] fromLong(long value, int width) {
+		boolean[] res = new boolean[width];
+		for (int i = 0; i < width; i++)
+			res[i] = (((value >> i) & 1) == 0) ? false : true;
+
+		return res;
+	}
+
+	public static long toLong(boolean[] value) {
+		long res = 0;
+		for (int i = 0; i < value.length; i++)
+			res = (value[i]) ? (res | (1L << i)) : res;// 1L!! not 1!!
+
+		return res;
+	}
+
+	public static double toFloat(boolean[] value, int widthV, int widthP) {
+		boolean[] v = Arrays.copyOfRange(value, 1, 1 + widthV);
+		boolean[] p = Arrays.copyOfRange(value, 1 + widthV, value.length);
+
+		double result = value[0] ? -1 : 1;
+		long value_v = Utils.toUnSignedInt(v);
+		long value_p = Utils.toSignedInt(p);
+		result = result * value_v;
+		result = result * Math.pow(2, value_p);
+		BigDecimal b = new BigDecimal(result);
+		return b.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue(); // 6 is
+																		// should
+																		// not
+																		// be
+																		// fixed.
+	}
+
+	public static boolean[] fromFloat(double d, int widthV, int widthP) {
+		boolean s;
+		boolean[] v, p;
+		v = new boolean[widthV];
+		p = new boolean[widthP];
+		s = d < 0;
+		if (d == 0) {
+			for (int i = 0; i < widthV; ++i)
+				v[i] = false;
+			for (int i = 0; i < widthP; ++i)
+				p[i] = false;
+			p[widthP - 1] = true;
+		} else {
+			d = s ? -1 * d : d;
+			int pInt = 0;
+
+			double lower_bound = Math.pow(2, widthV - 1);
+			double upper_bound = Math.pow(2, widthV);
+			while (d < lower_bound) {
+				d *= 2;
+				pInt--;
+			}
+
+			while (d >= upper_bound) {
+				d /= 2;
+				pInt++;
+			}
+
+			p = Utils.fromInt(pInt, widthP);
+			long tmp = (long) (d + 0.000001);// a hack...
+			v = Utils.fromLong(tmp, widthV);
+		}
+		boolean[] result = new boolean[1 + widthV + widthP];
+		result[0] = s;
+		System.arraycopy(v, 0, result, 1, v.length);
+		System.arraycopy(p, 0, result, 1 + v.length, p.length);
+		return result;
+	}
+
+	final static int[] mask = { 0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00100000, 0b01000000,
+			0b10000000 };
+
+	public static boolean[] fromBigInteger(BigInteger bd, int length) {
+		byte[] b = bd.toByteArray();
+		boolean[] result = new boolean[length];
+		for (int i = 0; i < b.length; ++i) {
+			for (int j = 0; j < 8 && i * 8 + j < length; ++j)
+				result[i * 8 + j] = (((b[b.length - i - 1] & mask[j]) >> j) == 1);
+		}
+		return result;
+	}
+
+	public static BigInteger toBigInteger(boolean[] b) {
+		BigInteger res = new BigInteger("0");
+		BigInteger c = new BigInteger("1");
+		for (int i = 0; i < b.length; i++) {
+			if (b[i])
+				res = res.add(c);
+			c = c.multiply(new BigInteger("2"));
+		}
+		return res;
+	}
+
+	public static boolean[] fromFixPoint(double a, int width, int offset) {
+		a *= Math.pow(2, offset);
+		return Utils.fromLong((long) a, width);
+	}
+
+	public static double toFixPoint(boolean[] b, int offset) {
+		double a = toSignedInt(b);
+		a /= Math.pow(2, offset);
+		return a;
+	}
+
+	public static boolean[] flatten(boolean[][] data) {
+		int length = 0;
+		for (int i = 0; i < data.length; i++) {
+			length += data[i].length;
+		}
+		boolean[] ret = new boolean[length];
+		int pos = 0;
+		for (int i = 0; i < data.length; i++) {
+			System.arraycopy(data[i], 0, ret, pos, data[i].length);
+			pos += data[i].length;
+		}
+		return ret;
+	}
+
+	public static boolean[] flatten(boolean[][][] data) {
+		int length = 0;
+		for (int i = 0; i < data.length; i++) {
+			for (int j = 0; j < data[0].length; j++) {
+				length += data[i][j].length;
+			}
+		}
+		boolean[] ret = new boolean[length];
+		int pos = 0;
+		for (int i = 0; i < data.length; i++) {
+			for (int j = 0; j < data[0].length; j++) {
+				System.arraycopy(data[i][j], 0, ret, pos, data[i][j].length);
+				pos += data[i][j].length;
+			}
+		}
+		return ret;
+	}
+
+	public static <T> T[] flatten(CompEnv<T> env, T[]... data) {
+		int length = 0;
+		for (int i = 0; i < data.length; i++) {
+			length += data[i].length;
+		}
+		T[] ret = env.newTArray(length);
+		int pos = 0;
+		for (int i = 0; i < data.length; i++) {
+			System.arraycopy(data[i], 0, ret, pos, data[i].length);
+			pos += data[i].length;
+		}
+		return ret;
+	}
+
+	public static <T> T[][] flatten(CompEnv<T> env, T[][]... data) {
+		int length = 0;
+		for (int i = 0; i < data.length; i++) {
+			length += data[i][0].length;
+		}
+		T[][] ret = env.newTArray(data[0].length, length);
+		int pos = 0;
+		for (int i = 0; i < data.length; i++) {
+			for (int j = 0; j < data[0].length; j++) {
+				System.arraycopy(data[i][j], 0, ret[j], pos, data[i][j].length);
+			}
+			pos += data[i][0].length;
+		}
+		return ret;
+	}
+
+	public static <T> void unflatten(T[][] flat, T[][]... x) {
+		int pos = 0;
+		for (int i = 0; i < x.length; i++) {
+			for (int j = 0; j < x[i].length; j++) {
+				System.arraycopy(flat[j], pos, x[i][j], 0, x[i][j].length);
+			}
+			pos += x[i][0].length;
+		}
+	}
+
+	public static <T> void unflatten(T[] flat, T[]... x) {
+		int pos = 0;
+		for (int i = 0; i < x.length; i++) {
+			System.arraycopy(flat, pos, x[i], 0, x[i].length);
+			pos += x[i].length;
+		}
+	}
+
+	public static <T> void unflatten(T[] flat, T[][][] x) {
+		int pos = 0;
+		for (int i = 0; i < x.length; i++) {
+			for (int j = 0; j < x[0].length; j++) {
+				System.arraycopy(flat, pos, x[i][j], 0, x[i][j].length);
+				pos += x[i][j].length;
+			}
+		}
+	}
+
+	private static double getMega(double bytes) {
+		return bytes / (1024.0 * 1024);
+	}
+
+	public static int log2(int n) {
+		if (n <= 0) {
+			throw new IllegalArgumentException();
+		}
+		return 31 - Integer.numberOfLeadingZeros(n);
+	}
+
+	public static int log2Ceil(int n) {
+		int m = log2(n);
+		if ((1 << m) < n)
+			m++;
+		return m;
+	}
+
+	public static double getRandom() {
+		double ret = Utils.RAND[Utils.RAND_CNT];
+		Utils.RAND_CNT = (Utils.RAND_CNT + 1) % Utils.RAND_LIM;
+		return ret;
+	}
+
+	public static void generateRandomNumbers() throws FileNotFoundException, IOException {
+		Utils.RAND = new double[Utils.RAND_LIM];
+		BufferedReader reader = new BufferedReader(new FileReader("in/rand.out"));
+		for (int i = 0; i < Utils.RAND_LIM; i++) {
+			Utils.RAND[i] = Double.parseDouble(reader.readLine());
+		}
+		reader.close();
+	}
+
+	public static double RAND[];
+	public static int RAND_CNT = 0;
+	public static int RAND_LIM = 10000000;
+
+	public static byte[] toByte(int value) {
+		byte[] b = new byte[4];
+		for (int i = 0; i < 4; ++i) {
+			b[i] = (byte) (value & ((1 << 8) - 1));
+			value >>= 8;
+		}
+		return b;
+	}
+
+	public static int fromByte(byte[] b) {
+		int value = 0;
+		for (int i = 3; i >= 0; --i) {
+			int t = b[i];
+			if (t < 0) {
+				t += 1 << 8;
+			}
+			value = (value << 8) | t;
+		}
+		return value;
+	}
+}

+ 4 - 1
build.xml

@@ -5,14 +5,17 @@
   </target>
 
   <target name="compile" depends="init" >
-    <javac srcdir="src:test" destdir="bin" debug="on" debuglevel="lines,vars,source" source="1.8" includeantruntime="false">
+    <javac srcdir="src:test:ObliVMGC" destdir="bin" debug="on" debuglevel="lines,vars,source" source="1.8" includeantruntime="false">
       <classpath>
+      	<pathelement location="lib/argparse4j-0.1.0.jar"/>
         <pathelement location="lib/bcprov-jdk15on-151.jar"/>
         <pathelement location="lib/commons-cli-1.2.jar"/>
         <pathelement location="lib/commons-io-2.4.jar"/>
         <pathelement location="lib/commons-lang3-3.3.2.jar"/>
         <pathelement location="lib/jargs.jar"/>
         <pathelement location="lib/junit-4.10.jar"/>
+        <pathelement location="lib/oblivm-flexsc-0.2.jar"/>
+        <pathelement location="lib/org.hamcrest.core_1.3.0.v201303031735.jar"/>
         <pathelement location="lib/snakeyaml-1.11.jar"/>
         <pathelement path="bin"/>
       </classpath>

+ 8 - 0
config/Config.conf

@@ -0,0 +1,8 @@
+# ObliVMGC's config file
+
+#Host: 192.168.1.102
+Host: localhost
+Port: 54321
+#Mode can be OPT, VERIFY, COUNT and REAL 
+Mode: REAL
+#Mode: VERIFY

BIN
lib/argparse4j-0.1.0.jar


BIN
lib/oblivm-flexsc-0.2.jar


BIN
lib/org.hamcrest.core_1.3.0.v201303031735.jar