...
 
Commits (3)
*.cil.c
*.cil.i
*.gates{2,3}
*.i
emp-*
*.od
*.d
*.o
*.a
*.oo
build
benchmark_results
CC ?= gcc
CPP ?= cpp
AR ?= ar
OBLIVCC = $(OBLIVC_PATH)/bin/oblivcc
OBLIVCH = $(OBLIVC_PATH)/src/ext/oblivc
OBLIVCA = $(OBLIVC_PATH)/_build/libobliv.a
CFLAGS+= -D _Float128=double -O3 -march=native -I/usr/include -I . -I $(SRC_PATH) -std=c99 -fopenmp #--save-temps
LDFLAGS += -lm -lgomp -lgcrypt
SRC_PATH=src/
LIB_OUT_PATH=build/lib/
NMLIB = $(LIB_OUT_PATH)/libnoisymax.a
DEPS=ackutil.o
OBJS=$(DEPS) push_only_ostack.oo predfunctions.oo pop_only_rostack.oo odofunctions.oo utils.oo onmfunctions.oo
TEST_PATH=tests/
TEST_OUT_PATH=build/tests/
TEST_DEPS=test_main.o
TEST_BINS = test_push_ostk test_predfunctions test_pop_rostk bench_push_ostk bench_pop_rostk bench_coinflip\
bench_pred test_coinflip test_odo_sample test_onm_sample bench_odo_sample_0_0866 bench_onm_sample_0_0866\
bench_onm_sample_0_1 noisy_max_0_0866
default: $(NMLIB) tests
tests: $(TEST_BINS:%=$(TEST_OUT_PATH)/%)
$(TEST_BINS:%=$(TEST_OUT_PATH)/%): $(TEST_OUT_PATH)/%: $(TEST_PATH)/%.oo $(TEST_DEPS:%=$(TEST_PATH)/%) $(NMLIB)
mkdir -p $(TEST_OUT_PATH)
$(OBLIVCC) -o [email protected] $(OBLIVCA) $^ $(LDFLAGS)
$(NMLIB): $(OBJS:%=$(SRC_PATH)/%) # put all of OBJS into archive file
mkdir -p $(LIB_OUT_PATH)
$(AR) rcs [email protected] $^
-include $($(patsubst %.oo,%.od,$(OBJS:.o=.d)):%=$(SRC_PATH)/%) $(TEST_BINS:%=$(TEST_PATH)/%.od)
%.o: %.c
$(CC) -c $(CFLAGS) $*.c -o $*.o -I $(OBLIVCH)
$(CPP) -MM $(CFLAGS) $*.c -I $(OBLIVCH) > $*.d
%.oo: %.oc
$(OBLIVCC) -c $(CFLAGS) $*.oc -o $*.oo
$(CPP) -MM $(CFLAGS) $*.oc -MT $*.oo > $*.od
clean:
rm -f $(OBJS:%=$(SRC_PATH)/%) $(patsubst %.oo,$(SRC_PATH)/%.od,$(patsubst %.o,$(SRC_PATH)/%.d,$(OBJS))) $(NMLIB)
rm -f $(TEST_BINS:%=$(TEST_OUT_PATH)/%) $(TEST_DEPS:%=$(TEST_PATH)/%) $($(pasubst %.oo, %.od, $(TEST_DEPS)):%=$(TEST_PATH)/%) $(TEST_BINS:%=$(TEST_PATH)/%.oo) $(TEST_BINS:%=$(TEST_PATH)/%.od)
# securely_sampling
Securely Sampling Biased Coins with Applications to Differential Privacy
=====
This repository provides code to accompany the paper Securely Sampling Biased Coins with Applications to Differential Privacy by Jeffrey Champion, abhi shelat, and Jonathan Ullman which was accepted to the 26th ACM Conference on Computer and Communications Security (CCS). Our code takes the form of a library, along with a small number of testing and benchmarking applications. The library is written in [obliv-c](https://github.com/samee/obliv-c/), a c-derived language for secure multiparty computation.
Features
=====
This distribution is intended to provide reference implementations of the MNM (labeled onm in the code) and ODO sampling methods (with utils to compute noisy max), which are described and compared in the aforementioned paper. Naturally, we also have full implementations for the push-only and pop-only stacks described in the paper (inspired by _[Circuit Structures for Improving Efficiency of Security and Privacy Tools](http://www.ieee-security.org/TC/SP2013/papers/4977a493.pdf)_), as well as circuits for the predicate functions used for the values of epsilon evaluated in the paper.
Installing
=====
1. You must first build [obliv-c](https://github.com/samee/obliv-c/), though it need not be installed in any particular location.
2. To compile, set the path to obliv-c's main project directory via `export OBLIVC_PATH=<path to obliv-c>`, then run `make`.
Project Organization
=====
Source for this project is divided into two directories: `src` contains code for the primary library, while `tests` contains code for tests and benchmarks. The library will be compiled to `build/lib/libnoisymax.a`, and all testing and benchmarking binaries are found in `build/tests`.
Reproducing Results
=====
For the purpose of reproducing the results we report in our paper, we provide a suite of benchmark scripts in the `tools/bench` directory. Each script must be executed on one machine as a server, and on another as a client. Scripts will run as server by default, and will output data and summaries to the `benchmark_results` directory. Adding the `-c <address>` flag will cause the script to run as a client and connect to the specified server.
Running Tests and Benchmarks Manually
=====
Each of our benchmarking and testing programs (that is, the binaries, not the benchmarking scripts described above) have individual options for adjusting the parameters relevant to that particular test or benchmark. These can be found by running the programs with the `-h` flag. In addition, there are a few standard parameters shared by all of the included programs, as well as the benchmarking scripts:
* `-h` prints a list of program-specific flags (our main flags for sampling are described in detail in the paper).
* `-p <number>` determines the port on which the program will listen (for servers) or connect (for clients). The default port is 54321.
* `-c <address>` instructs the program to run as a client, and connect to the server at `<address>`. By default, the program will run as a server.
* `-i <number>` (benchmarks only) instructs a benchmark to run for `<number>` iterations, and record results for all of them.
Due to the difficulty of calculating our sampling parameters, we provide a [sage](http://www.sagemath.org/download.html) script in the `tools/findparams` directory for this purpose. Given inputs epsilon, delta, n (as in differential privacy), this script outputs the flags needed for both MNM and ODO benchmark programs, as well as some complexity analysis. We note that when using the predicate method (make-batch 2 in the paper) for epsilon other than what we provide, one must construct predicate circuits that output the binary expansion of the probability that the ith bit of a Geo(2/epsilon) sample is 1 for i=0,...,k. The NIST circuit generator for 6 variable predicates based on truth tables can be found [here](https://github.com/usnistgov/Circuits).
Building on this Work
=====
We encourage others to improve our work and to integrate it with their own applications. As such, we provide it under the 3-clause BSD license. For ease of integration, our code takes the form of a library, to which other software can link directly.
// Taken from ACK
#include<obliv.h>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include"ackutil.h"
uint64_t current_timestamp() {
struct timeval tv;
gettimeofday(&tv,NULL);
return (uint64_t)tv.tv_sec*(uint64_t)1000000+(uint64_t)tv.tv_usec;
}
uint32_t rand_range(uint32_t min, uint32_t max) {
return (uint32_t)((double) rand() / ((uint64_t)RAND_MAX+1)) * (max-min+1) + min;
}
// Taken from ACK
#ifndef UTIL_H
#define UTIL_H
#include <stdint.h>
#include <obliv_common.h>
//Note: the following macros CANNOT be used with obliv arguments (in case it wasn't obivious).
#define LOG2LL(X) ((unsigned) (8*sizeof (unsigned long long) - __builtin_clzll((X)) - 1))
#define MAX(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#define MIN(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
uint64_t current_timestamp();
uint32_t rand_range(uint32_t, uint32_t);
#endif
#include <obliv.oh>
#include "odofunctions.oh"
#include "ackutil.h"
obliv bool biasedFlip(obliv bool* rands, obliv bool* bias, const uint16_t len) {
obliv bool ans;
obliv bool xor;
for (uint16_t i = 0; i < len; i++) {
uint16_t j = len - 1 - i;
xor = *(rands + j) ^ *(bias + j);
obliv if (xor) {
ans = *(rands + j)^1;
}
}
return ans;
}
obliv uint16_t* sample_odo(obliv bool* rands, obliv bool* biases, const uint8_t k, const uint16_t len, const uint32_t n, bool testing) {
obliv uint16_t* noise = malloc(n*sizeof(obliv uint16_t));
obliv uint16_t comp;
int perfeed = 512;
int64_t x = perfeed*len*k;
obliv bool* cur_rands = malloc(x*sizeof(obliv bool));
obliv bool* cur_rands2;
int r = 0;
uint64_t tally = 0;
uint64_t curtime;
for (int i = 0; i < n; i++) {
obliv uint16_t cur = 0;
if (!testing && (r%perfeed == 0)) {
// feed random bits from both parties and xor them together
obliv bool* temp1 = malloc(x*sizeof(obliv bool));
obliv bool* temp2 = malloc(x*sizeof(obliv bool));
bool* raw = malloc(x*sizeof(bool));
for (int z = 0; z < x; z++) raw[z] = rand()&1;
feedOblivBoolArray(temp1, raw, x, 0);
feedOblivBoolArray(temp2, raw, x, 1);
for (int z = 0; z < x; z++) cur_rands[z] = temp1[z] ^ temp2[z];
free(temp1);
free(temp2);
free(raw);
}
for (uint8_t j = 0; j < k; j++) {
if (!testing) {
comp = biasedFlip(cur_rands + len*(j + k*(r%perfeed)), biases + j*len, len);
}
else {
comp = biasedFlip(rands + (i*k + j)*len, biases + j*len, len);
}
cur = cur ^ (comp << j); // put biased flip at correct bit of current sample
}
r++;
*(noise + i) = cur;
}
return noise; // ptr to start of n samples in a row
}
#ifndef ODO_FUNCTIONS
#define ODO_FUNCTIONS
#include <obliv.oh>
//These are the functions needed to implement ODO
// return heads/tails (1/0) if sequence of random bits is less/greater than some known bias
obliv bool biasedFlip(obliv bool* rands, obliv bool* bias, const uint16_t len);
// use a sequence of random bits and k known biases to compute n k-bit noise samples with comps of length len, rands can be input for testing purposes
// rands argument only matters for testing
obliv uint16_t* sample_odo(obliv bool* rands, obliv bool* biases, const uint8_t k, const uint16_t len, const uint32_t n, bool testing);
#endif
#include "onmfunctions.oh"
#include "push_only_ostack.oh"
#include "pop_only_rostack.oh"
#include "utils.oh"
#include "ackutil.h"
#include <copy.oh>
#include <obliv.oh>
obliv uint16_t* sample_onm(obliv bool* rands, uint8_t k, uint16_t cg, uint16_t g, uint16_t rem_cg, uint16_t rem_g, uint32_t n,
obliv bool* biases, uint16_t len, bool testing, uint8_t numReal, frozen bool isPred, obliv bool (*pred)(uint8_t, obliv uint16_t, int)) {
push_ostk* cstk = push_ostk_new_static(&ocCopyBool, g);
push_ostk* rem_cstk = push_ostk_new_static(&ocCopyBool, rem_g);
pop_rostk* biases2[numReal];
int high = len - 1;
int bits = 1;
while(high >>= 1) {bits++;} //find number of bits needed for count
obliv uint16_t count = 0;
if (!isPred) for (int i = 0; i < numReal; i++) biases2[i] = pop_rostk_from_array(&ocCopyBool, len, biases + i*len);
obliv uint16_t* noise = calloc(n, sizeof(obliv uint16_t));
obliv bool* group = malloc(g*sizeof(obliv bool));
int feed = 8*k*cg; // represents the number of rands to be fed at a time at most
int track = 0; //tracks rand bit when not testing
obliv bool* rnds = malloc(feed*sizeof(obliv bool));
uint64_t r = 0; // keeps track of which random bit to use when testing
obliv bool xor, rnd, bias;
bool b;
uint32_t numgroups = n/g + ((n%g) != 0);
obliv bool* temp1 = malloc(feed*sizeof(obliv bool));
obliv bool* temp2 = malloc(feed*sizeof(obliv bool));
bool* raw = malloc(feed*sizeof(bool));
for (uint32_t i = 0; i < numgroups-1; i++) {
if (!testing && (i%8 == 0)) {
if (numgroups - i < 8) feed = k*cg*(numgroups - i - 1) + k*rem_cg; //less than 10 groups to make including rem group
// feed random bits and xor
for (int z = 0; z < feed; z++) raw[z] = rand()&1;
feedOblivBoolArray(temp1, raw, feed, 0);
feedOblivBoolArray(temp2, raw, feed, 1);
for (int z = 0; z < feed; z++) rnds[z] = temp1[z] ^ temp2[z]; //key step is to reassign rnds to xor of 2 parties
track = 0;
}
for (uint8_t j = 0; j < k; j++) {
for (uint16_t w = 0; w < cg; w++) {
if (!testing) rnd = *(rnds + track);
else rnd = *(rands + r);
// comp bias and rand, obliv push/reset
if (j < numReal) {
if (isPred) bias = pred(j, count, len);
else pop_rostk_pop(&bias, biases2[j]);
xor = bias^rnd;
if (isPred) incr_n(&count, bits);
obliv if (xor) {
push_ostk_push(&bias, cstk);
if (isPred) count = 0;
else pop_rostk_reset(biases2[j]);
}
}
// periodic bias case
else {
bias = (count >> (j-numReal))&1;
xor = bias^rnd;
incr_n(&count, bits);
obliv if (xor) {
push_ostk_push(&bias, cstk);
count = 0;
}
}
r++;
track++;
}
// purge and concat noise
push_ostk_purge(group, cstk);
if (!isPred && j<numReal) pop_rostk_reset(biases2[j]);
count = 0;
for (uint16_t v = 0; v < g; v++) {
*(noise + i*g + v) ^= (((obliv uint16_t)(*(group + v))) << j);
}
}
}
free(temp1);
free(temp2);
free(raw);
// remainder group, same as above but with potentially smaller stack size
obliv bool* group_rem = malloc(rem_g*sizeof(obliv bool));
for (uint8_t j = 0; j < k; j++) {
for (uint16_t w = 0; w < rem_cg; w++) {
if (!testing) rnd = *(rnds + track);
else rnd = *(rands + r);
if (j < numReal) {
if (isPred) bias = pred(j, count, len);
else pop_rostk_pop(&bias, biases2[j]);
xor = bias^rnd;
if (isPred) incr_n(&count, bits);
obliv if (xor) {
push_ostk_push(&bias, rem_cstk);
if (isPred) count = 0;
else pop_rostk_reset(biases2[j]);
}
}
else {
bias = (count >> (j-numReal))&1;
xor = bias^rnd;
incr_n(&count, bits);
obliv if (xor) {
push_ostk_push(&bias, rem_cstk);
count = 0;
}
}
r++;
track++;
}
push_ostk_purge(group_rem, rem_cstk);
for (uint16_t v = 0; v < n % g; v++) {
*(noise + (n/g)*g + v) ^= (((obliv uint16_t)(*(group_rem + v))) << j);
}
}
return noise;
}
#ifndef ONM_FUNCTIONS
#define ONM_FUNCTIONS
#include <obliv.oh>
#include "push_only_ostack.oh"
#include "pop_only_rostack.oh"
//These are the functions needed to implement our noisy max
// makes n k-bit noise samples given k biases and the number of pushes cg needed to guarantee g coins are made
// rem_cg and rem_g allow for a slight optimization, since doing a final full size group may create quite a few samples more than n, which is needless work
// testing bool allows for fixing the random bits in the rands arg (important for testing)
// numReal lets the function know whether epsilon is of the form (2^-i)ln2, and if so, how many bits do we actually need pop stacks for (when !isPred)
// isPred tells the function to generate bias with the given pred function or use pop_rostks made from the obliv bool array biases
// if anything fails, let protocol do whatever, since failure is cryptographically small
obliv uint16_t* sample_onm(obliv bool* rands, uint8_t k, uint16_t cg, uint16_t g, uint16_t rem_cg, uint16_t rem_g, uint32_t n,
obliv bool* biases, uint16_t len, bool testing, uint8_t numReal, frozen bool isPred, obliv bool (*pred)(uint8_t, obliv uint16_t, int));
#endif
//from array, free, empty, pop, reset
#include "pop_only_rostack.oh"
struct pop_rostk {
pop_rostk* next; // next level
OcCopy* cpy; // describes data type
size_t bucketsize; // num elements per bucket
obliv bool c1; // 1st bit of count (ones place)
obliv bool c2; // 2nd bit of count (twos place)
obliv bool init_c1; // the initial count for this level (used for assigning count after a reset)
obliv bool init_c2;
obliv bool reset; // if this bit is 1 reset before popping
uint8_t shift_time; // is 1 when this pop will require an obliv shifting circuit
void* data; // generic data array pointer
frozen void* init; // generic pointer for original contents (used for reseting)
};
static void* element(OcCopy* cpy, void* arr, int x) obliv
{ return x*cpy->eltsize+(char*)arr; }
obliv bool pop_rostk_empty(pop_rostk* lvl) obliv {
return (lvl->c1 | lvl->c2) ^ 1;//(lvl->count == 0);
}
obliv bool pop_rostk_pop(void* output, pop_rostk* lvl) obliv {
obliv bool success = false;
int64_t x = 0;
~obliv(en) {
// handle potential reset
obliv if (lvl->reset) {
ocCopyN(lvl->cpy, lvl->data, lvl->init, lvl->bucketsize*3);
lvl->c1 = lvl->init_c1;//lvl->count = lvl->init_count;
lvl->c2 = lvl->init_c2;
}
lvl->reset = 0;
// always check for shift
if (lvl->next != NULL) {
if (lvl->shift_time == 1) {
obliv if (lvl->c2 ^ 1/*lvl->count <= 1*/) {
ocCopyN(lvl->cpy, lvl->data, element(lvl->cpy, lvl->data, lvl->bucketsize*2), lvl->bucketsize);
pop_rostk_pop(element(lvl->cpy, lvl->data, lvl->bucketsize), lvl->next);
lvl->c2 = 1;
obliv if (lvl->c1 ^ 1) {
ocCopyN(lvl->cpy, lvl->data, element(lvl->cpy, lvl->data, lvl->bucketsize), lvl->bucketsize);
ocCopyN(lvl->cpy, element(lvl->cpy, lvl->data, lvl->bucketsize), element(lvl->cpy, lvl->data, lvl->bucketsize*2), lvl->bucketsize);
}
}
lvl->shift_time = 0;
}
else {
lvl->shift_time++;
}
}
}
// always pop, we use slight opt for smaller stack sizes where first element always popped and 2nd/3rd move forward
ocCopyN(lvl->cpy, output, lvl->data, lvl->bucketsize);
lvl->c1 ^= 1; //lvl->count--;
lvl->c2 ^= lvl->c1;
ocCopyN(lvl->cpy, lvl->data, element(lvl->cpy, lvl->data, lvl->bucketsize), lvl->bucketsize);
ocCopyN(lvl->cpy, element(lvl->cpy, lvl->data, lvl->bucketsize), element(lvl->cpy, lvl->data, lvl->bucketsize*2), lvl->bucketsize);
return true;
}
void pop_rostk_reset(pop_rostk* lvl) obliv {
lvl->reset = 1;
if (lvl->next != NULL) {
pop_rostk_reset(lvl->next);
}
}
pop_rostk* pop_rostk_from_array(OcCopy* cpy, size_t elct, void* src) {
int m = elct/3 + ((elct%3)*(elct%3)%3); // if there is rem mod 3 add 1 to truncation
uint8_t lvls = 1;
while (m >>= 1) {lvls++;}
uint8_t* layout = malloc(lvls*sizeof(uint8_t));
uint32_t rem = elct - (1<<lvls) + 1; // since one bucket of each level must be filled
uint32_t r1 = rem/2;
uint32_t r2 = rem/2 + rem%2; //r1 + r2 = rem
for (uint8_t i = 0; i < lvls; i++) { *(layout + i) = 3/*1+((r1>>i)&1)+((r2>>i)&1)*/; } //ith bit of r1/r2 represents an ith lvl bucket full
size_t bucketsize = 1;
size_t n = 0;
pop_rostk* result;
pop_rostk* cur = NULL;
pop_rostk* prev = NULL;
for (uint8_t i = 0; i < lvls; i++) {
cur = malloc(sizeof(pop_rostk));
cur->cpy = cpy;
cur->c1 = *(layout + i) & 1;
cur->c2 = (*(layout + i) >> 1) & 1;
cur->init_c1 = *(layout + i) & 1;
cur->init_c2 = (*(layout + i) >> 1) & 1;
cur->shift_time = 0;
cur->reset = 0;
cur->next = NULL;
cur->bucketsize = bucketsize;
cur->data = calloc(1, cur->cpy->eltsize*cur->bucketsize*3);
ocCopyN(cur->cpy, cur->data, src, cur->bucketsize*3);
if (n + 3*bucketsize > elct) ocCopyN(cur->cpy, element(cur->cpy, cur->data, cur->bucketsize*(3-*(layout + i))), element(cur->cpy, src, n), elct-n);
else ocCopyN(cur->cpy, element(cur->cpy, cur->data, cur->bucketsize*(3-*(layout + i))), element(cur->cpy, src, n), *(layout + i)*cur->bucketsize);
cur->init = calloc(1, cur->cpy->eltsize*cur->bucketsize*3);
ocCopyN(cur->cpy, cur->init, src, cur->bucketsize*3);
if (n + 3*bucketsize > elct) ocCopyN(cur->cpy, element(cur->cpy, cur->init, cur->bucketsize*(3-*(layout + i))), element(cur->cpy, src, n), elct-n);
else ocCopyN(cur->cpy, element(cur->cpy, cur->init, cur->bucketsize*(3-*(layout + i))), element(cur->cpy, src, n), *(layout + i)*cur->bucketsize);
n += *(layout + i)*cur->bucketsize;
if (prev == NULL) {
result = cur;
}
else {
prev->next = cur;
}
prev = cur;
bucketsize *= 2;
}
return result;
}
void pop_rostk_free(pop_rostk* lvl) {
if (lvl->next != NULL) {
pop_rostk_free(lvl->next);
}
free(lvl->data);
free(lvl->init);
free(lvl);
}
#ifndef POP_ONLY_RESETTABLE_OBLIV_STACK
#define POP_ONLY_RESETTABLE_OBLIV_STACK
#include <obliv.oh>
#include <copy.oh>
/* This implements a pop-only resettable oblivious stack inspired by:
Zahur, S. & Evans, D. (2013). Circuit Structures for Improving Efficiency of
Security and Privacy Tools. IEEE Symposium on Security and Privacy 2013. */
typedef struct pop_rostk pop_rostk;
// makes a pop_rostk from an array given # levels (lvls) and how many buckets are full on each level (layout)
pop_rostk* pop_rostk_from_array(OcCopy* cpy, size_t elct, void* src);
// free memory
void pop_rostk_free(pop_rostk*);
// check if level is empty
obliv bool pop_rostk_empty(pop_rostk*) obliv;
// pop with potential reset beforehand
obliv bool pop_rostk_pop(void*, pop_rostk*) obliv;
// obliv reset
void pop_rostk_reset(pop_rostk*) obliv;
#endif
This diff is collapsed.
#ifndef PRED_FUNCTIONS
#define PRED_FUNCTIONS
#include <obliv.oh>
// List of predicate functions used in evaluation, named in the form
// pred_epsilon (epsilon is dp param, digits after dec only) and limited to lambda + logn + log(kappa) (we mostly limited length to 128).
// for epsilon >= 1, put non decimal directly after pred (ex: pred1_1 for eps = 1.1)
// Inputs: k (which bit of noise), j (get jth bit of expansion), len (const limit for this use) Output: jth bit (0 or 1)
// eps = 2ln2, len <= 128
obliv bool pred1_386(uint8_t k, obliv uint16_t j, int len);
// eps = (2^-3)ln2 = 0.0866, len <= 128
obliv bool pred_0866(uint8_t k, obliv uint16_t j, int len);
// eps = (2^-4)ln2 = 0.0433, len <= 128
obliv bool pred_0433(uint8_t k, obliv uint16_t j, int len);
// eps = 0.1, len <= 128
obliv bool pred_1(uint8_t k, obliv uint16_t j, int len);
#endif
#include "push_only_ostack.oh"
struct push_ostk {
push_ostk* next; // next level
OcCopy* cpy; // describes data type
size_t bucketsize; // num elements per bucket
//obliv uint8_t count; // num buckets filled
obliv bool c1; // 1st bit of count (ones place)
obliv bool c2; // 2nd bit of count (twos place)
uint8_t shift_time; // is 1 when this push will require an obliv shifting circuit
void* data; // generic data array pointer
};
static void* element(OcCopy* cpy, void* arr, int x) obliv
{ return x*cpy->eltsize+(char*)arr; }
obliv bool push_ostk_empty(push_ostk* lvl) obliv {
return (lvl->c1 | lvl->c2) ^ 1;//(lvl->count == 0);
}
obliv bool push_ostk_full(push_ostk* lvl) obliv {
return lvl->c1 & lvl->c2;//(lvl->count == 3);
}
obliv bool push_ostk_push(void* input, push_ostk* lvl) obliv {
obliv bool success = false;
~obliv(en) {
if (lvl->next != NULL) {
if (lvl->shift_time == 1) {
obliv if (lvl->c2/*lvl->count >= 2*/) {
obliv if (push_ostk_push(element(lvl->cpy, lvl->data, lvl->bucketsize), lvl->next)) {
ocCopyN(lvl->cpy, element(lvl->cpy, lvl->data, 2*lvl->bucketsize), lvl->data, lvl->bucketsize);
lvl->c2 = 0;//lvl->count -= 2;
}
}
lvl->shift_time = 0;
}
else {
lvl->shift_time++;
}
}
}
success = push_ostk_full(lvl) ^ 1;
for (uint8_t i = 0; i < 3; i++) {
obliv if ((((i >> 1)&1)^lvl->c2^1)&((i&1)^lvl->c1^1)/*i == lvl->count*/) {
ocCopyN(lvl->cpy, element(lvl->cpy, lvl->data, (2-i)*lvl->bucketsize), input, lvl->bucketsize);
}
}
lvl->c1 ^= success;
lvl->c2 ^= lvl->c1^1;
return success;
}
obliv bool push_ostk_purge(void* output, push_ostk* lvl) {
ocCopyN(lvl->cpy, output, lvl->data, 3*lvl->bucketsize);
obliv bool success = push_ostk_full(lvl);
lvl->c1 = 0, lvl->c2 = 0;//lvl->count = 0; // "empty" the stack without actually getting rid of elements
lvl->shift_time = 0;
void* acc = element(lvl->cpy, output, 3*lvl->bucketsize); // track current spot
if (lvl->next == NULL) {
return success;
}
else {
return (success & push_ostk_purge(acc, lvl->next));
}
}
push_ostk* push_ostk_new_static(OcCopy* cpy, size_t n) {
size_t cursize = 0;
size_t bucketsize = 1;
push_ostk* result;
push_ostk* cur = NULL;
push_ostk* prev = NULL;
while (cursize < n) {
cur = malloc(sizeof(push_ostk));
cur->cpy = cpy;
cur->c1 = 0, cur->c2 = 0;//cur->count = 0;
cur->shift_time = 0;
cur->next = NULL;
cur->bucketsize = bucketsize;
cur->data = calloc(1, cur->cpy->eltsize*cur->bucketsize*3);
if (prev == NULL) {
result = cur;
}
else {
prev->next = cur;
}
prev = cur;
cursize += 3*bucketsize;
bucketsize *= 2;
}
return result;
}
void push_ostk_free(push_ostk* lvl) {
if (lvl->next != NULL) {
push_ostk_free(lvl->next);
}
free(lvl->data);
free(lvl);
}
#ifndef PUSH_ONLY_OBLIV_STACK
#define PUSH_ONLY_OBLIV_STACK
#include <obliv.oh>
#include <copy.oh>
/* This implements a push-only oblivious stack inspired by:
Zahur, S. & Evans, D. (2013). Circuit Structures for Improving Efficiency of
Security and Privacy Tools. IEEE Symposium on Security and Privacy 2013. */
typedef struct push_ostk push_ostk;
// init empty stack of size n
push_ostk* push_ostk_new_static(OcCopy* cpy, size_t n);
// free memory
void push_ostk_free(push_ostk*);
// check if level is empty
obliv bool push_ostk_empty(push_ostk*) obliv;
// check if level is full
obliv bool push_ostk_full(push_ostk*) obliv;
// obliv push
obliv bool push_ostk_push(void*, push_ostk*) obliv;
// wire slots of stack to void*
obliv bool push_ostk_purge(void*, push_ostk*);
#endif
#include "utils.oh"
#include <limits.h>
obliv bool* makeRandBits(obliv bool p1[], obliv bool p2[], uint64_t howMany) {
obliv bool* rands = malloc(howMany*sizeof(obliv bool));
for (uint64_t i = 0; i < howMany; i++) {
*(rands + i) = p1[i]^p2[i];
}
return rands;
}
void incr_n(obliv uint16_t* ptr, int n) {
obliv bool carry = 1;
for (int i = 0; i < n; i++) {
*ptr ^= ((obliv uint16_t)carry << i);
carry &= ((*ptr >> i)&1)^1;
}
}
obliv uint32_t max(obliv int data[], const uint32_t n) {
obliv int maxval = INT_MIN;
obliv uint32_t maxidx;
for (int i = 0; i < n; i++) {
obliv if (data[i] > maxval) {
maxval = data[i];
maxidx = i;
}
}
return maxidx;
}
obliv uint32_t noisy_max(obliv int data[], obliv uint16_t samples[], const uint32_t n) {
obliv bool* signs = malloc(n*sizeof(obliv bool)); // obliv bools that will determine whether noise is added or subtracted
obliv bool* temp1 = malloc(n*sizeof(obliv bool));
obliv bool* temp2 = malloc(n*sizeof(obliv bool));
bool* raw = malloc(n*sizeof(bool));
for (int z = 0; z < n; z++) raw[z] = rand()&1;
feedOblivBoolArray(temp1, raw, n, 0);
feedOblivBoolArray(temp2, raw, n, 1);
for (int z = 0; z < n; z++) signs[z] = temp1[z] ^ temp2[z]; // xor random arrays that were fed
for (int i = 0; i < n; i++) {
// for each item in the dataset, we choose whether to add or subtract the noise
obliv int cur = data[i];
data[i] = cur - samples[i];
obliv if (signs[i]) data[i] = cur + samples[i];
}
return max(data, n);
}
#ifndef UTILS
#define UTILS
#include <obliv.oh>
// Functions useful for all noisy max implementations
// XOR two sequences of random bits together (one from each party).
obliv bool* makeRandBits(obliv bool p1[], obliv bool p2[], uint64_t howMany);
// increments a count for first n bits, to allow for counts of any number of bits
void incr_n(obliv uint16_t* ptr, int n);
// obliviously take max of an array of ints (assumes n < 2^32)
obliv uint32_t max(obliv int data[], const uint32_t n);
// given data and samples, add or subtract samples and take max
obliv uint32_t noisy_max(obliv int data[], obliv uint16_t samples[], const uint32_t n);
#endif
#include <obliv.oh>
#include "../src/odofunctions.oh"
#include <copy.oh>
#include "test_generic.h"
// Benchmark for trivial oblivious biased coin flip
static const char TESTNAME[] = "odo_coinflip_benchmark";
#define TEXT_HELP_SUPPLEMENTARY "\
-l \x1b[4mNUMBER\x1b[0m, --length=\x1b[4mNUMBER\x1b[0m \n\t\tcomps of len\x1b[4mNUMBER\x1b[0m\n\n\
-i \x1b[4mNUMBER\x1b[0m, --samples=\x1b[4mNUMBER\x1b[0m \n\t\trun \x1b[4mNUMBER\x1b[0m iterations of the benchmark\n\n"
static const char options_string[] = "l:i:";
static struct option long_options[] = {
{"length", required_argument, NULL, 'l'},
{"samples", required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
char* get_test_name() {
return TESTNAME;
}
char* get_supplementary_options_string() {
return options_string;
}
struct option* get_long_options() {
return long_options;
}
void print_supplementary_help() {
fprintf(stderr, TEXT_HELP_SUPPLEMENTARY);
}
void test_main(void*varg) {
size_t len = 3;
int samples = 1;
args_t * args_pass = varg;
int arg;
optind = 0; // this allows us to getopt a second time
while ((arg = getopt_long(args_pass->argc, args_pass->argv, options_string, long_options, NULL)) != -1) {
if (arg == 'l') {
len = atoll(optarg);
if (len <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'i') {
samples = atoi(optarg);
if (samples <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == '?' || arg == ':') {
if (optopt == 'l' || optopt == 'i') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
return;
} else {
fprintf (stderr, "Option -%c not recognized.\n", optopt);
return;
}
} else {
abort();
}
}
fprintf(stdout, "# ODO_COINFLIP (length, sample 1 microseconds, sample 1 gates, sample 1 bytes, ...)\n");
uint64_t tally1 = 0;
uint64_t tallygates1 = 0;
uint64_t tallybytes1 = 0;
obliv bool * bias = calloc(len, sizeof(obliv bool));
for (int i = 0; i < len; i++) {
*(bias + i) = feedOblivBool(rand()&1, 1);
}
obliv bool * rands = calloc(len, sizeof(obliv bool));
obliv uint32_t a = feedOblivInt(rand(), 0);
obliv uint32_t b = feedOblivInt(rand(), 0);
for (int ii = 0; ii <samples; ii ++) {
for (int i = 0; i < len; i++) {
*(rands + i) = feedOblivBool(rand()&1, 1);
}
int64_t runtime1 = -current_timestamp();
int64_t rungates1 = -yaoGateCount();
int64_t runbytes1 = -tcp2PBytesSent(ocCurrentProto());
obliv uint16_t flip = biasedFlip(rands, bias, len);
runtime1 += current_timestamp();
rungates1 += yaoGateCount();
runbytes1 += tcp2PBytesSent(ocCurrentProto());
//fprintf(stdout, ",%llu,%llu,%llu", runtime1,rungates1, runbytes1);
fflush(stdout);
tally1 += runtime1;
tallygates1 += rungates1;
tallybytes1 += runbytes1;
}
fprintf(stdout, "\n");
fprintf(stderr, "odo_coinflip (length:%lld): %llu microseconds avg, %llu gates avg, %llu bytes avg\n", len, tally1 / samples, tallygates1/samples, tallybytes1/samples);
}
#include <obliv.oh>
#include "../src/odofunctions.oh"
#include "../src/utils.oh"
#include <copy.oh>
#include "test_generic.h"
#include "biases.h"
// Benchmark for ODO sampling with epsilon = 0.0866
static const char TESTNAME[] = "odo_sample_benchmark";
#define TEXT_HELP_SUPPLEMENTARY "\
-k \x1b[4mNUMBER\x1b[0m, --sample-size=\x1b[4mNUMBER\x1b[0m \n\t\tmake samples of \x1b[4mNUMBER\x1b[0m bits\n\n\
-l \x1b[4mNUMBER\x1b[0m, --length=\x1b[4mNUMBER\x1b[0m \n\t\tlimit bias to \x1b[4mNUMBER\x1b[0m bits\n\n\
-n \x1b[4mNUMBER\x1b[0m, --num-samples=\x1b[4mNUMBER\x1b[0m \n\t\tmake \x1b[4mNUMBER\x1b[0m samples\n\n\
-i \x1b[4mNUMBER\x1b[0m, --iters=\x1b[4mNUMBER\x1b[0m \n\t\trun \x1b[4mNUMBER\x1b[0m iterations of the benchmark\n\n"
static const char options_string[] = "k:l:n:i:";
static struct option long_options[] = {
{"sample-size", required_argument, NULL, 'k'},
{"length", required_argument, NULL, 'l'},
{"num-samples", required_argument, NULL, 'n'},
{"iters", required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
char* get_test_name() {
return TESTNAME;
}
char* get_supplementary_options_string() {
return options_string;
}
struct option* get_long_options() {
return long_options;
}
void print_supplementary_help() {
fprintf(stderr, TEXT_HELP_SUPPLEMENTARY);
}
void test_main(void*varg) {
int k = 10;
int len = 128;
int n = 10000;
int samples = 1;
args_t * args_pass = varg;
int arg;
optind = 0; // this allows us to getopt a second time
while ((arg = getopt_long(args_pass->argc, args_pass->argv, options_string, long_options, NULL)) != -1) {
if (arg == 'k') {
k = atoll(optarg);
if (k <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'l') {
len = atoll(optarg);
if (len <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'n') {
n = atoll(optarg);
if (n <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'i') {
samples = atoi(optarg);
if (samples <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == '?' || arg == ':') {
if (optopt == 'k' || optopt == 'l' || optopt == 'n' || optopt == 'i') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
return;
} else {
fprintf (stderr, "Option -%c not recognized.\n", optopt);
return;
}
} else {
abort();
}
}
fprintf(stdout, "# ODO_SAMPLE (sample 1 microseconds, sample 1 gates, sample 1 bytes, ...)\n");
const char* bias[] = {b16thrt2, b8thrt2, b4thrt2, bsqrt2, onethird, onefifth, one17th, one257th, period32, period64, period128};
obliv bool* biases = malloc(len*k*sizeof(obliv bool));
for (int i = 0; i < k*len; i++) {
biases[i] = *(bias[i/len] + i%len)-'0';
}
uint64_t tally1 = 0;
uint64_t tallygates1 = 0;
uint64_t tallybytes1 = 0;
obliv uint16_t* samps;
for (int ii = 0; ii <samples; ii ++) {
int64_t runtime1 = -current_timestamp();
int64_t rungates1 = -yaoGateCount();
int64_t runbytes1 = -tcp2PBytesSent(ocCurrentProto());
samps = sample_odo(NULL, biases, k, len, n, false);
runtime1 += current_timestamp();
rungates1 += yaoGateCount();
runbytes1 += tcp2PBytesSent(ocCurrentProto());
fprintf(stdout, ",%llu,%llu,%llu", runtime1/1000000,2*rungates1, runbytes1);
fflush(stdout);
tally1 += runtime1;
tallygates1 += rungates1;
tallybytes1 += runbytes1;
}
// can uncomment to see samples
for (int i = 0; i<200; i++) {
int s;
//revealOblivInt(&s, samps[i], 0);
//printf("sample: %d,", s);
}
fprintf(stdout, "\n");
fprintf(stderr, "odo_sample (k:%lld, len: %lld, n: %lld): %llu seconds avg, %llu gates + rands avg, %llu bytes avg\n",
k, len, n, tally1/(1000000*samples), 2*tallygates1/samples, tallybytes1/samples);
}
#include <obliv.oh>
#include "../src/onmfunctions.oh"
#include "../src/predfunctions.oh"
#include "../src/utils.oh"
#include "biases.h"
#include <copy.oh>
#include "test_generic.h"
// Benchmark for MNM sampling method with epsilon = 0.0866
static const char TESTNAME[] = "onm_sample_0_0866_benchmark";
#define TEXT_HELP_SUPPLEMENTARY "\
-k \x1b[4mNUMBER\x1b[0m, --sample-size=\x1b[4mNUMBER\x1b[0m \n\t\tmake samples of \x1b[4mNUMBER\x1b[0m bits\n\n\
-l \x1b[4mNUMBER\x1b[0m, --length=\x1b[4mNUMBER\x1b[0m \n\t\tlimit bias to \x1b[4mNUMBER\x1b[0m bits\n\n\
-n \x1b[4mNUMBER\x1b[0m, --num-samples=\x1b[4mNUMBER\x1b[0m \n\t\tmake \x1b[4mNUMBER\x1b[0m samples\n\n\
-u \x1b[4mNUMBER\x1b[0m, --num-pushes=\x1b[4mNUMBER\x1b[0m \n\t\tpush \x1b[4mNUMBER\x1b[0m times per group\n\n\
-g \x1b[4mNUMBER\x1b[0m, --group-size=\x1b[4mNUMBER\x1b[0m \n\t\tmake \x1b[4mNUMBER\x1b[0m coins per group\n\n\
-v \x1b[4mNUMBER\x1b[0m, --rem-num-pushes=\x1b[4mNUMBER\x1b[0m \n\t\tpush \x1b[4mNUMBER\x1b[0m times for rem group\n\n\
-q \x1b[4mNUMBER\x1b[0m, --rem-group-size=\x1b[4mNUMBER\x1b[0m \n\t\tmake \x1b[4mNUMBER\x1b[0m coins for rem group\n\n\
-r \x1b[4mNUMBER\x1b[0m, --pred=\x1b[4mNUMBER\x1b[0m \n\t\tboolean for isPred: \x1b[4mNUMBER\x1b[0m\n\n\
-i \x1b[4mNUMBER\x1b[0m, --iters=\x1b[4mNUMBER\x1b[0m \n\t\trun \x1b[4mNUMBER\x1b[0m iterations of the benchmark\n\n"
static const char options_string[] = "k:l:n:u:g:v:q:r:i:";
static struct option long_options[] = {
{"sample-size", required_argument, NULL, 'k'},
{"length", required_argument, NULL, 'l'},
{"num-samples", required_argument, NULL, 'n'},
{"num-pushes", required_argument, NULL, 'u'},
{"group-size", required_argument, NULL, 'g'},
{"rem-num-pushes", required_argument, NULL, 'v'},
{"rem-group-size", required_argument, NULL, 'q'},
{"pred", required_argument, NULL, 'r'},
{"iters", required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
char* get_test_name() {
return TESTNAME;
}
char* get_supplementary_options_string() {
return options_string;
}
struct option* get_long_options() {
return long_options;
}
void print_supplementary_help() {
fprintf(stderr, TEXT_HELP_SUPPLEMENTARY);
}
void test_main(void*varg) {
int k = 10;
int len = 129;
int n = 10000;
int cg = 2103;
int g = 765;
int rem_cg = 441;
int rem_g = 93;
bool isPred = true;
int samples = 1;
args_t * args_pass = varg;
int arg;
optind = 0; // this allows us to getopt a second time
while ((arg = getopt_long(args_pass->argc, args_pass->argv, options_string, long_options, NULL)) != -1) {
if (arg == 'k') {
k = atoll(optarg);
if (k <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'l') {
len = atoll(optarg);
if (len <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'n') {
n = atoll(optarg);
if (n <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'i') {
samples = atoi(optarg);
if (samples <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'u') {
cg = atoi(optarg);
if (cg <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'g') {
g = atoi(optarg);
if (g <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'v') {
rem_cg = atoi(optarg);
if (rem_cg <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'q') {
rem_g = atoi(optarg);
if (rem_g <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'r') {
isPred = atoi(optarg);
if (isPred < 0 || isPred > 1) {
fprintf (stderr, "Argument for -%c must be 0 or 1.\n", arg);
return;
}
}
else if (arg == '?' || arg == ':') {
if (optopt == 'k' || optopt == 'l' || optopt == 'n' || optopt == 'u' || optopt == 'g' || optopt == 'v' || optopt == 'q' || optopt == 'r' || optopt == 'i') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
return;
} else {
fprintf (stderr, "Option -%c not recognized.\n", optopt);
return;
}
} else {
abort();
}
}
fprintf(stdout, "# ONM_SAMPLE (sample 1 microseconds, sample 1 gates, sample 1 bytes, ...)\n");
const char* bias[] = {b16thrt2, b8thrt2, b4thrt2, bsqrt2, onethird, onefifth, one17th, one257th, period32, period64, period128};
obliv bool* biases = malloc(len*k*sizeof(obliv bool));
for (int i = 0; i < k*len; i++) biases[i] = *(bias[i/len] + i%len) == '0' ? false : true;
uint64_t rand_used = k*(n/g)*cg + k*rem_cg*(n%g > 0); // if g divides n, dont add extra k*rem_cg (very rare)
uint64_t tally1 = 0;
uint64_t tallygates1 = 0;
uint64_t tallybytes1 = 0;
obliv uint16_t* samps;
for (int ii = 0; ii <samples; ii ++) {
int64_t runtime1 = -current_timestamp();
int64_t rungates1 = -yaoGateCount();
int64_t runbytes1 = -tcp2PBytesSent(ocCurrentProto());
if (isPred) samps = sample_onm(NULL, k, cg, g, rem_cg, rem_g, n, NULL, len, false, k, isPred, pred_0866);
else samps = sample_onm(biases, k, cg, g, rem_cg, rem_g, n, NULL, len, false, 4, isPred, NULL);
runtime1 += current_timestamp();
rungates1 += yaoGateCount();
runbytes1 += tcp2PBytesSent(ocCurrentProto());
fprintf(stdout, ",%llu,%llu,%llu", runtime1/1000000,rungates1+rand_used, runbytes1);
fflush(stdout);
tally1 += runtime1;
tallygates1 += rungates1;
tallybytes1 += runbytes1;
}
// can uncomment to see samples
for (int i = 0; i<200; i++) {
int s;
//revealOblivInt(&s, samps[i], 0);
//printf("sample: %d,", s);
}
fprintf(stdout, "\n");
fprintf(stderr, "onm_sample (k:%lld, len: %lld, n: %lld, isPred: %d): %llu seconds avg, %llu gates + rands avg, %llu bytes avg\n",
k,len,n,isPred,tally1/(1000000*samples),rand_used+tallygates1/samples,tallybytes1/samples);
}
#include <obliv.oh>
#include "../src/onmfunctions.oh"
#include "../src/predfunctions.oh"
#include "../src/utils.oh"
#include "biases.h"
#include <copy.oh>
#include "test_generic.h"
// Benchmark for MNM sampling method with epsilon = 0.1
static const char TESTNAME[] = "onm_sample_0_1_benchmark";
#define TEXT_HELP_SUPPLEMENTARY "\
-k \x1b[4mNUMBER\x1b[0m, --sample-size=\x1b[4mNUMBER\x1b[0m \n\t\tmake samples of \x1b[4mNUMBER\x1b[0m bits\n\n\
-l \x1b[4mNUMBER\x1b[0m, --length=\x1b[4mNUMBER\x1b[0m \n\t\tlimit bias to \x1b[4mNUMBER\x1b[0m bits\n\n\
-n \x1b[4mNUMBER\x1b[0m, --num-samples=\x1b[4mNUMBER\x1b[0m \n\t\tmake \x1b[4mNUMBER\x1b[0m samples\n\n\
-u \x1b[4mNUMBER\x1b[0m, --num-pushes=\x1b[4mNUMBER\x1b[0m \n\t\tpush \x1b[4mNUMBER\x1b[0m times per group\n\n\
-g \x1b[4mNUMBER\x1b[0m, --group-size=\x1b[4mNUMBER\x1b[0m \n\t\tmake \x1b[4mNUMBER\x1b[0m coins per group\n\n\
-v \x1b[4mNUMBER\x1b[0m, --rem-num-pushes=\x1b[4mNUMBER\x1b[0m \n\t\tpush \x1b[4mNUMBER\x1b[0m times for rem group\n\n\
-q \x1b[4mNUMBER\x1b[0m, --rem-group-size=\x1b[4mNUMBER\x1b[0m \n\t\tmake \x1b[4mNUMBER\x1b[0m coins for rem group\n\n\
-r \x1b[4mNUMBER\x1b[0m, --pred=\x1b[4mNUMBER\x1b[0m \n\t\tboolean for isPred: \x1b[4mNUMBER\x1b[0m\n\n\
-i \x1b[4mNUMBER\x1b[0m, --iters=\x1b[4mNUMBER\x1b[0m \n\t\trun \x1b[4mNUMBER\x1b[0m iterations of the benchmark\n\n"
static const char options_string[] = "k:l:n:u:g:v:q:r:i:";
static struct option long_options[] = {
{"sample-size", required_argument, NULL, 'k'},
{"length", required_argument, NULL, 'l'},
{"num-samples", required_argument, NULL, 'n'},
{"num-pushes", required_argument, NULL, 'u'},
{"group-size", required_argument, NULL, 'g'},
{"rem-num-pushes", required_argument, NULL, 'v'},
{"rem-group-size", required_argument, NULL, 'q'},
{"pred", required_argument, NULL, 'r'},
{"iters", required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
char* get_test_name() {
return TESTNAME;
}
char* get_supplementary_options_string() {
return options_string;
}
struct option* get_long_options() {
return long_options;
}
void print_supplementary_help() {
fprintf(stderr, TEXT_HELP_SUPPLEMENTARY);
}
void test_main(void*varg) {
int k = 10;
int len = 129;
int n = 10000;
int cg = 2103;
int g = 765;
int rem_cg = 441;
int rem_g = 93;
bool isPred = true;
int samples = 1;
args_t * args_pass = varg;
int arg;
optind = 0; // this allows us to getopt a second time
while ((arg = getopt_long(args_pass->argc, args_pass->argv, options_string, long_options, NULL)) != -1) {
if (arg == 'k') {
k = atoll(optarg);
if (k <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'l') {
len = atoll(optarg);
if (len <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'n') {
n = atoll(optarg);
if (n <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'i') {
samples = atoi(optarg);
if (samples <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'u') {
cg = atoi(optarg);
if (cg <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'g') {
g = atoi(optarg);
if (g <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'v') {
rem_cg = atoi(optarg);
if (rem_cg <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'q') {
rem_g = atoi(optarg);
if (rem_g <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
}
else if (arg == 'r') {
isPred = atoi(optarg);
if (isPred < 0 || isPred > 1) {
fprintf (stderr, "Argument for -%c must be 0 or 1.\n", arg);
return;
}
}
else if (arg == '?' || arg == ':') {
if (optopt == 'k' || optopt == 'l' || optopt == 'n' || optopt == 'u' || optopt == 'g' || optopt == 'v' || optopt == 'q' || optopt == 'r' || optopt == 'i') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
return;
} else {
fprintf (stderr, "Option -%c not recognized.\n", optopt);
return;
}
} else {
abort();
}
}
fprintf(stdout, "# ONM_SAMPLE (sample 1 microseconds, sample 1 gates, sample 1 bytes, ...)\n");
const char* bias[] = {bk0,bk1,bk2,bk3,bk4,bk5,bk6,bk7,bk8,bk9,bk10};
obliv bool* biases = malloc(len*k*sizeof(obliv bool));
for (int i = 0; i < k*len; i++) biases[i] = *(bias[i/len] + i%len)-'0';
uint64_t rand_used = k*(n/g)*cg + k*rem_cg*(n%g > 0); // if g divides n, dont add extra k*rem_cg (very rare)
uint64_t tally1 = 0;
uint64_t tallygates1 = 0;
uint64_t tallybytes1 = 0;
obliv uint16_t* samps;
for (int ii = 0; ii <samples; ii ++) {
int64_t runtime1 = -current_timestamp();
int64_t rungates1 = -yaoGateCount();
int64_t runbytes1 = -tcp2PBytesSent(ocCurrentProto());
samps = sample_onm(biases, k, cg, g, rem_cg, rem_g, n, NULL, len, false, k, isPred, pred_1); // dont need if/else since numReal is k both times (no periodic)
runtime1 += current_timestamp();
rungates1 += yaoGateCount();
runbytes1 += tcp2PBytesSent(ocCurrentProto());
fprintf(stdout, ",%llu,%llu,%llu", runtime1/1000000,rungates1+rand_used, runbytes1);
fflush(stdout);
tally1 += runtime1;
tallygates1 += rungates1;
tallybytes1 += runbytes1;
}
fprintf(stdout, "\n");
fprintf(stderr, "onm_sample (k:%lld, len: %lld, n: %lld, isPred: %d): %llu seconds avg, %llu gates + rands avg, %llu bytes avg\n",
k,len,n,isPred,tally1/(1000000*samples),rand_used+tallygates1/samples,tallybytes1/samples);
}
#include <obliv.oh>
#include "../src/pop_only_rostack.oh"
#include "../src/utils.oh"
#include <copy.oh>
#include "test_generic.h"
// Benchmark for pop and reset ops of pop-only oblivious stack
static const char TESTNAME[] = "pop_rostk_popreset_benchmark";
#define TEXT_HELP_SUPPLEMENTARY "\
-e \x1b[4mNUMBER\x1b[0m, --element-count=\x1b[4mNUMBER\x1b[0m \n\t\tuse stacks of \x1b[4mNUMBER\x1b[0m elements\n\n\
-s \x1b[4mNUMBER\x1b[0m, --element-size=\x1b[4mNUMBER\x1b[0m \n\t\tuse stacks with elements containing \x1b[4mNUMBER\x1b[0m obliv bools\n\n\
-i \x1b[4mNUMBER\x1b[0m, --samples=\x1b[4mNUMBER\x1b[0m \n\t\trun \x1b[4mNUMBER\x1b[0m iterations of the benchmark\n\n"
static const char options_string[] = "e:s:i:";
static struct option long_options[] = {
{"element-count", required_argument, NULL, 'e'},
{"element-size", required_argument, NULL, 's'},
{"samples", required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
char* get_test_name() {
return TESTNAME;
}
char* get_supplementary_options_string() {
return options_string;
}
struct option* get_long_options() {
return long_options;
}
void print_supplementary_help() {
fprintf(stderr, TEXT_HELP_SUPPLEMENTARY);
}
void test_main(void*varg) {
size_t elct = 3;
size_t elsz = 1;
int samples = 1;
args_t * args_pass = varg;
int arg;
optind = 0; // this allows us to getopt a second time
while ((arg = getopt_long(args_pass->argc, args_pass->argv, options_string, long_options, NULL)) != -1) {
if (arg == 'e') {
elct = atoll(optarg);
if (elct <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 's') {
elsz = atoll(optarg);
if (elsz <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'i') {
samples = atoi(optarg);
if (samples <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == '?' || arg == ':') {
if (optopt == 'e' || optopt == 's' || optopt == 'i') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
return;
} else {
fprintf (stderr, "Option -%c not recognized.\n", optopt);
return;
}
} else {
abort();
}
}
fprintf(stdout, "# POP_ROSTK POPRESET (element count, element size, sample 1 microseconds, sample 1 gates, sample 1 bytes, ...)\n");
OcCopy cpy = ocCopyBoolN(elsz);
uint64_t tally1 = 0;
uint64_t tallygates1 = 0;
uint64_t tallybytes1 = 0;
uint64_t tally2 = 0;
uint64_t tallygates2 = 0;
uint64_t tallybytes2 = 0;
obliv bool * src = calloc(elct*elsz, sizeof(obliv bool));
for (int i = 0; i < elct*elsz; i++) {
obliv bool b = feedOblivBool(rand()&1, 1);
src[i] = b;
}
obliv bool * dest = calloc(elsz, sizeof(obliv bool));
pop_rostk * testStk = pop_rostk_from_array(&cpy, elct, src);
obliv uint16_t count = 0;
int q = 1000000;
obliv bool* test1;
obliv bool* test2;
bool testSeq[q];
for (int ii = 0; ii <samples; ii ++) {
obliv bool real1 = feedOblivBool(rand()&1, 1);
obliv bool real2 = feedOblivBool(rand()&1, 2);
int64_t runtime1 = -current_timestamp();
int64_t rungates1 = -yaoGateCount();
int64_t runbytes1 = -tcp2PBytesSent(ocCurrentProto());
pop_rostk_pop(dest, testStk);
runtime1 += current_timestamp();
rungates1 += yaoGateCount();
runbytes1 += tcp2PBytesSent(ocCurrentProto());
int64_t runtime2 = -current_timestamp();
int64_t rungates2 = -yaoGateCount();
int64_t runbytes2 = -tcp2PBytesSent(ocCurrentProto());
obliv if(real2^real1) pop_rostk_reset(testStk);
runtime2 += current_timestamp();
rungates2 += yaoGateCount();
runbytes2 += tcp2PBytesSent(ocCurrentProto());
fprintf(stdout, "pop %llu,%llu,%llu, rst %llu,%llu,%llu ", runtime1,rungates1, runbytes1,runtime2,rungates2, runbytes2);
fflush(stdout);
tally1 += runtime1;
tallygates1 += rungates1;
tallybytes1 += runbytes1;
tally2 += runtime2;
tallygates2 += rungates2;
tallybytes2 += runbytes2;
}
pop_rostk_free(testStk);
fprintf(stdout, "\n");
fprintf(stderr, "pop_rostk pop (count:%lld, size: %lld): %llu microseconds avg, %.6f gates avg, %llu bytes avg\n", elct, elsz, tally1 / samples, tallygates1/(float)samples, tallybytes1/samples);
fprintf(stderr, "pop_rostk reset (count:%lld, size: %lld): %llu microseconds avg, %llu gates avg, %llu bytes avg\n", elct, elsz, tally2 / samples, tallygates2/samples, tallybytes2/samples);
}
#include <obliv.oh>
#include "../src/predfunctions.oh"
#include "../src/utils.oh"
#include <copy.oh>
#include "test_generic.h"
// Benchmark for predicate function with epsilon = 0.0866 and epsilon = 0.1
static const char TESTNAME[] = "pred_128_benchmark";
#define TEXT_HELP_SUPPLEMENTARY "\
-i \x1b[4mNUMBER\x1b[0m, --samples=\x1b[4mNUMBER\x1b[0m \n\t\trun \x1b[4mNUMBER\x1b[0m iterations of the benchmark\n\n"
static const char options_string[] = "i:";
static struct option long_options[] = {
{"samples", required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
char* get_test_name() {
return TESTNAME;
}
char* get_supplementary_options_string() {
return options_string;
}
struct option* get_long_options() {
return long_options;
}
void print_supplementary_help() {
fprintf(stderr, TEXT_HELP_SUPPLEMENTARY);
}
void test_main(void*varg) {
int samples = 1;
args_t * args_pass = varg;
int arg;
optind = 0; // this allows us to getopt a second time
while ((arg = getopt_long(args_pass->argc, args_pass->argv, options_string, long_options, NULL)) != -1) {
if (arg == 'i') {
samples = atoi(optarg);
if (samples <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == '?' || arg == ':') {
if (optopt == 'i') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
return;
} else {
fprintf (stderr, "Option -%c not recognized.\n", optopt);
return;
}
} else {
abort();
}
}
fprintf(stdout, "# PRED_0866_128 \n");
obliv uint16_t count = 0;//feedOblivShort(rand()&0xffff, 1);
for (int k = 0; k < 12; k++) {
uint64_t tally1 = 0;
uint64_t tallygates1 = 0;
uint64_t tallybytes1 = 0;
for (int ii = 0; ii <samples; ii ++) {
obliv bool r1 = feedOblivBool(rand()&1, 1);
obliv bool r2 = feedOblivBool(rand()&1, 2);
int64_t runtime1 = -current_timestamp();
int64_t rungates1 = -yaoGateCount();
int64_t runbytes1 = -tcp2PBytesSent(ocCurrentProto());
obliv bool b = pred_0866(k, count, 128);
runtime1 += current_timestamp();
rungates1 += yaoGateCount();
runbytes1 += tcp2PBytesSent(ocCurrentProto());
incr_n(&count, 7);
obliv if (r1^r2) count = 0;
//fprintf(stdout, ",%llu,%llu,%llu", runtime1,rungates1, runbytes1);
fflush(stdout);
tally1 += runtime1;
tallygates1 += rungates1;
tallybytes1 += runbytes1;
}
fprintf(stdout, "\n");
fprintf(stderr, "pred_0866_128(k = %d): %llu microseconds avg, %llu gates avg, %llu bytes avg\n", k, tally1 / samples, tallygates1/samples, tallybytes1/samples);
}
fprintf(stdout, "\n# PRED_1_128 \n");
for (int k = 0; k < 11; k++) {
uint64_t tally1 = 0;
uint64_t tallygates1 = 0;
uint64_t tallybytes1 = 0;
for (int ii = 0; ii <samples; ii ++) {
obliv bool r1 = feedOblivBool(rand()&1, 1);
obliv bool r2 = feedOblivBool(rand()&1, 2);
int64_t runtime1 = -current_timestamp();
int64_t rungates1 = -yaoGateCount();
int64_t runbytes1 = -tcp2PBytesSent(ocCurrentProto());
obliv bool b = pred_1(k, count, 128);
runtime1 += current_timestamp();
rungates1 += yaoGateCount();
runbytes1 += tcp2PBytesSent(ocCurrentProto());
incr_n(&count, 7);
obliv if (r1^r2) count = 0;
//fprintf(stdout, ",%llu,%llu,%llu", runtime1,rungates1, runbytes1);
fflush(stdout);
tally1 += runtime1;
tallygates1 += rungates1;
tallybytes1 += runbytes1;
}
fprintf(stdout, "\n");
fprintf(stderr, "pred_1_128(k = %d): %llu microseconds avg, %llu gates avg, %llu bytes avg\n", k, tally1 / samples, tallygates1/samples, tallybytes1/samples);
}
}
#include <obliv.oh>
#include "../src/push_only_ostack.oh"
#include <copy.oh>
#include "test_generic.h"
// Benchmark for push-only oblivious stack push and purge operations
static const char TESTNAME[] = "push_ostk_pushpurge_benchmark";
#define TEXT_HELP_SUPPLEMENTARY "\
-e \x1b[4mNUMBER\x1b[0m, --element-count=\x1b[4mNUMBER\x1b[0m \n\t\tuse stacks of \x1b[4mNUMBER\x1b[0m elements\n\n\
-s \x1b[4mNUMBER\x1b[0m, --element-size=\x1b[4mNUMBER\x1b[0m \n\t\tuse stacks with elements containing \x1b[4mNUMBER\x1b[0m obliv bools\n\n\
-i \x1b[4mNUMBER\x1b[0m, --samples=\x1b[4mNUMBER\x1b[0m \n\t\trun \x1b[4mNUMBER\x1b[0m iterations of the benchmark\n\n"
static const char options_string[] = "e:s:i:";
static struct option long_options[] = {
{"element-count", required_argument, NULL, 'e'},
{"element-size", required_argument, NULL, 's'},
{"samples", required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
char* get_test_name() {
return TESTNAME;
}
char* get_supplementary_options_string() {
return options_string;
}
struct option* get_long_options() {
return long_options;
}
void print_supplementary_help() {
fprintf(stderr, TEXT_HELP_SUPPLEMENTARY);
}
void test_main(void*varg) {
size_t elct = 3;
size_t elsz = 1;
int samples = 1;
args_t * args_pass = varg;
int arg;
optind = 0; // this allows us to getopt a second time
while ((arg = getopt_long(args_pass->argc, args_pass->argv, options_string, long_options, NULL)) != -1) {
if (arg == 'e') {
elct = atoll(optarg);
if (elct <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 's') {
elsz = atoll(optarg);
if (elsz <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == 'i') {
samples = atoi(optarg);
if (samples <= 0) {
fprintf (stderr, "Argument for -%c must be positive.\n", arg);
return;
}
} else if (arg == '?' || arg == ':') {
if (optopt == 'e' || optopt == 's' || optopt == 'i') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
return;
} else {
fprintf (stderr, "Option -%c not recognized.\n", optopt);
return;
}
} else {
abort();
}
}
fprintf(stdout, "# PUSH_OSTK PUSH (element count, element size, sample 1 microseconds, sample 1 gates, sample 1 bytes, ...)\n");
OcCopy cpy = ocCopyBoolN(elsz);
uint64_t tally1 = 0;
uint64_t tallygates1 = 0;
uint64_t tallybytes1 = 0;
uint64_t tally2 = 0;
uint64_t tallygates2 = 0;
uint64_t tallybytes2 = 0;
obliv bool * val = calloc(1, elsz * sizeof(obliv bool));
obliv bool * dest = malloc(elct*elsz*sizeof(obliv bool));
push_ostk * testStk = push_ostk_new_static(&cpy, elct);
for (int ii = 0; ii <samples; ii ++) {
for (int i = 0; i < elct; i++) {
for (int jj = 0; jj < elsz; jj++) val[jj] = feedOblivBool(rand()&1, 1);
obliv bool real1 = feedOblivBool(rand()&1, 1);
obliv bool real2 = feedOblivBool(rand()&1, 2);
obliv bool rand = real1 ^ real2;
int64_t runtime1 = -current_timestamp();
int64_t rungates1 = -yaoGateCount();
int64_t runbytes1 = -tcp2PBytesSent(ocCurrentProto());
// two push ops at a time with opposite conditions to ensure stack is full for purges
obliv if (rand) push_ostk_push(val, testStk);
obliv if (rand ^ 1) push_ostk_push(val, testStk);
runtime1 += current_timestamp();
rungates1 += yaoGateCount();
runbytes1 += tcp2PBytesSent(ocCurrentProto());