├── .gitignore ├── Makefile ├── README.md ├── bench ├── benchFourAccess.oc ├── benchSqrtAccess.c ├── benchSqrtAccess.h ├── benchSqrtAccess.oc ├── search.c ├── search.h ├── search.oc ├── search.oh ├── timecopy.c ├── timecopy.h └── timecopy.oc ├── oram ├── block.oc ├── block.oh ├── circuit_oram.oc ├── circuit_oram.oh ├── ckt_utils.oc ├── ckt_utils.oh ├── decoder.oc ├── decoder.oh ├── eraseSet │ ├── README.txt │ ├── eraseSet.oc │ ├── eraseSet.oh │ ├── lazyFilter.oc │ ├── testPropagate.c │ ├── testPropagate.h │ └── testPropagate.oc ├── linearoram.oc ├── linearoram.oh ├── nonrecursive_oram.oc ├── nonrecursive_oram.oh ├── obliv_copy_internal.h ├── oram.oh ├── qroram │ ├── README.txt │ ├── qroram.c │ ├── qroram.h │ ├── qroram.oc │ ├── qroram.oh │ ├── testPropagate.c │ ├── testPropagate.h │ ├── testPropagate.oc │ ├── testQrShuffleTime.c │ └── testqrtable.c ├── shuffle.oc ├── shuffle.oh ├── sort.c ├── sort.h ├── sort.oc ├── sort.oh ├── sqrtoram.oc ├── sqrtoram.oh ├── waksman.c └── waksman.h ├── test ├── testOramAccess.c ├── testOramAccess.h ├── testOramAccess.oc ├── test_oqueue.c ├── test_oqueue.h ├── test_oqueue.oc ├── testcopy.c ├── testcopy.h ├── testcopy.oc ├── testshuffle.c ├── testshuffle.h ├── testshuffle.oc ├── testsort.c ├── testunapply.c ├── testunapply.h ├── testunapply.oc └── waksmanStrataTest.c ├── todo.txt └── util ├── oqueue.oc ├── oqueue.oh ├── util.c └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | *.swp 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Usage instructions 2 | # ================== 3 | # 4 | # Ensure $OBLIVC_PATH environment variable is set to 5 | # point to the Obliv-C source repository. Running `make` builds build/liboram.a. 6 | # Compile your own programs by running Obliv-C compiler as follows 7 | # 8 | # oblivcc myprog.c myprog.oc -lobliv -L../path/for/libobliv 9 | # 10 | # Try to keep a separate folder for your own programs. 11 | # 12 | # 13 | # Instructions for modifying liboram 14 | # ================================== 15 | # 16 | # Adding new ORAM constructions 17 | # ----------------------------- 18 | # 19 | # Pretty much anything you place in the folder oram/ will get packaged 20 | # up into build/liboram.a on `make`. So use that for any new code that 21 | # you want to add to liboram. 22 | # 23 | # Adding new test cases 24 | # --------------------- 25 | # 26 | # Use the test/ folder. Right now, there is no makefile target that makes 27 | # builds all test executable (i.e. no automated regression testing). We really 28 | # need one. But till then, any file named test/foo.c will allow you to do 29 | # 'make build/test/foo' which will be linked to liboram. This makefile will 30 | # recursively follow any included header files, find their matching .c or .oc 31 | # source files, and link those in as well. So try not to include files you 32 | # don't actually use. The bench/ folder works the same way, but used mostly 33 | # for measurement code. 34 | # 35 | # 36 | # Adding new test/benchmark helpers 37 | # --------------------------------- 38 | # 39 | # Sometimes you will want extra code shared between many test executables. 40 | # You can't put them in oram/ (or it will get linked into libobliv), and you 41 | # can't put it in test/ (or test/bar.c will create non-sensical rules for 42 | # build/test/bar). So you can just create a new folder at the repository root 43 | # (like oram/, util/). In fact, util/util.c is indeed shared by test cases 44 | # a lot. If you do, remember to add it to SRC_DIRS = ... below, so that the 45 | # folder is searched for include files and a corresponding folder is created in 46 | # build/. 47 | 48 | SHELL = /bin/bash 49 | OBLIVCC = $(OBLIVC_PATH)/bin/oblivcc 50 | OBLIVCH = $(OBLIVC_PATH)/src/ext/oblivc 51 | OBLIVCA = $(OBLIVC_PATH)/_build/libobliv.a 52 | CFLAGS=-O3 53 | 54 | SRC_DIRS = oram util 55 | TEST_DIRS = test bench 56 | SRC_TEST_DIRS = $(SRC_DIRS) $(TEST_DIRS) 57 | TEST_BINS=$(patsubst %.c,build/%, \ 58 | $(patsubst %.oc,%,$(shell grep -l '^int main\>' $(TEST_DIRS:=/*)))) 59 | ALL_C_FILES = $(wildcard $(addsuffix /*.c,$(SRC_TEST_DIRS))) 60 | ALL_OC_FILES = $(wildcard $(addsuffix /*.oc,$(SRC_TEST_DIRS))) 61 | INCLUDE_FLAGS = $(addprefix -I ,$(SRC_DIRS) $(OBLIVCH)) 62 | 63 | .PHONY: all test clean 64 | .SECONDARY: 65 | all: build/liboram.a 66 | 67 | test: $(TEST_BINS) 68 | 69 | clean: 70 | rm -rf build 71 | 72 | # Gather up all files in oram/ and pack them into liboram.a 73 | LIBORAM_OBJS=$(addprefix build/,\ 74 | $(patsubst %.c,%.o,$(wildcard oram/*.c)) \ 75 | $(patsubst %.oc,%.oo,$(wildcard oram/*.oc))) 76 | build/liboram.a: $(LIBORAM_OBJS) 77 | ar -rc $@ $^ 78 | 79 | # Create directories 80 | .PHONY: builddirs 81 | BUILD_SUBDIRS=$(addprefix build/,$(SRC_TEST_DIRS)) 82 | $(BUILD_SUBDIRS): 83 | mkdir -p $(BUILD_SUBDIRS) 84 | 85 | builddirs: $(BUILD_SUBDIRS) 86 | 87 | # Include generated dependencies 88 | ifneq (clean,$(MAKECMDGOALS)) 89 | -include $(addprefix build/,$(ALL_C_FILES:.c=.d) $(ALL_OC_FILES:.oc=.od)) 90 | endif 91 | 92 | localincs=$(filter %.h %.oh,$(filter-out /%,$(filter-out %:,$(shell cat $1)))) 93 | srcofh=$(wildcard $(patsubst %.oh,%.oc,$(patsubst %.h,%.c,$1) \ 94 | $(patsubst %.h,%.oc,$1))) 95 | objofh=$(patsubst %.c,build/%.o, \ 96 | $(patsubst %.oc,build/%.oo,$(call srcofh,$1))) 97 | dofobj=$(patsubst %.oo,%.od,$(patsubst %.o,%.d,$1)) 98 | objdeps=$(call objofh,$(filter-out oram/%,\ 99 | $(call localincs,$(call dofobj,$1)))) 100 | 101 | build/%.d: %.c | builddirs 102 | cpp -MM $(CFLAGS) $*.c $(INCLUDE_FLAGS) -MT $*.o > $@ 103 | 104 | build/%.o: %.c build/%.d 105 | gcc -Wall -std=gnu99 -c $(CFLAGS) $*.c -o $@ $(INCLUDE_FLAGS) 106 | 107 | build/%.od: %.oc | builddirs 108 | cpp -MM $(CFLAGS) $*.oc $(INCLUDE_FLAGS) -MT $*.oo > $@ 109 | 110 | build/%.oo: %.oc build/%.od 111 | $(OBLIVCC) -c $(CFLAGS) $*.oc $(INCLUDE_FLAGS) -o $@ 112 | 113 | # Build test executables 114 | build/test/%: build/test/%.o build/liboram.a 115 | $(OBLIVCC) -o $@ $(filter %.o %.oo,$^) -loram -Lbuild -lm 116 | 117 | build/bench/%: build/bench/%.o build/liboram.a 118 | $(OBLIVCC) -o $@ $(filter %.o %.oo,$^) -loram -Lbuild -lm 119 | 120 | # Create link-time dependencies for binaries 121 | ifneq (clean,$(MAKECMDGOALS)) 122 | -include $(TEST_BINS:=.exec_d) 123 | endif 124 | 125 | dfsobj=$(sort $(foreach x,$1,$(call dfsobj_aux,$x,))) 126 | in_list=$(filter $1,$2) 127 | 128 | dfsobj_aux = \ 129 | $(if $(call in_list,$1,$2),,\ 130 | $(sort $1 $(foreach nxt,$(call objdeps,$1),$(call dfsobj_aux,$(nxt),$1 $2)))) 131 | 132 | 133 | # Depend on .o instead of .c, so that .d gets built with it 134 | # Test binaries need main() in .c, not .oc 135 | build/%.exec_d: build/%.o 136 | echo $@ build/$*: $(call dfsobj,$^) > $@ 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ORAM library for Obliv-C 2 | ======================== 3 | 4 | This is a library extension for [Obliv-C](http://oblivc.org/), a language for 5 | collaborative cryptographic computation on private data. Typically Obliv-C does 6 | not allow array access such that the element location depends on private data. 7 | This library provides data structures for overcoming this limitation, at least 8 | for honest-but-curious protocols. 9 | 10 | **Status:** The library itself is ready for use, but the test/benchmarking code is still 11 | being posted as we clean it up. In the meantime, we are happy to help out if you 12 | contact us at sza4uq@virginia.edu. 13 | 14 | 15 | Installation 16 | ------------ 17 | 18 | First, install Obliv-C if you have not done so already. Follow the instructions 19 | from this [repository](https://github.com/samee/obliv-c). After that, perform 20 | the following actions: 21 | 22 | 1. Add this to your `.bashrc`, since it is used by the Makefile. This should 23 | allow you to invoke the compiler as `$OBLIVC_PATH/bin/oblivcc`. 24 | 25 | ```bash 26 | export OBLIVC_PATH=/path/to/oblivc 27 | ``` 28 | 29 | 2. Clone the repository: `git clone https://github.com/samee/sqrtOram.git` 30 | 3. Perform `make` 31 | 32 | This will build a `build/liboram.a` file in the repository. Now you can use it 33 | in any project as follows: 34 | 35 | ```bash 36 | OBLIVCC=$OBLIVC_PATH/bin/oblivcc 37 | LIBORAM=path/to/liboram/repo 38 | $OBLIVCC yourproject.oc -I $LIBORAM/oram -L $LIBORAM/build -loram 39 | ``` 40 | 41 | As always, questions always welcome at sza4uq@virginia.edu 42 | -------------------------------------------------------------------------------- /bench/benchFourAccess.oc: -------------------------------------------------------------------------------- 1 | // This file is no longer used. It's an early draft of sqrtOram. 2 | // In order to make it work, testFourAccess.h and .oc will have to be 3 | // moved to util and then linked in with this. 4 | #include 5 | #include"testFourAccess.h" 6 | #include"qroram.oh" 7 | #include"copy.oh" 8 | #include 9 | #include 10 | 11 | #define REP 9 12 | 13 | void testFourAccess(void* vargs) 14 | { 15 | TestFourAccessIO* args = vargs; 16 | int pcontent[4][REP]={}; 17 | obliv int content[4][REP]; 18 | int size = ocBroadcastInt(args->size,2); 19 | obliv int* indices = calloc(size,sizeof(obliv int)); 20 | obliv int output[REP]; 21 | int i,j; 22 | for(i=0;i<4;++i) pcontent[i][0]=args->content[i]; 23 | OcCopy cpy = ocCopyIntN(REP); 24 | feedOblivIntArray(content,(void*)pcontent,4*REP,1); 25 | feedOblivIntArray(indices,args->indices,size,2); 26 | ProtocolDesc* pd = ocCurrentProto(); 27 | int start = tcp2PBytesSent(pd),mid,end; 28 | OcFourBlock* ram = ocFourBlockNew(&cpy,content); 29 | args->outputs = malloc(size*sizeof(int)); 30 | for(i=0;ioutputs+i,output[0],0); 33 | } 34 | mid = tcp2PBytesSent(pd); 35 | printf("ORAM bytes sent: %d\n",mid-start); 36 | for(i=0;ioutputs+i,output[0],0); 41 | } 42 | end = tcp2PBytesSent(pd); 43 | printf("LinearScan bytes sent: %d\n",end-mid); 44 | ocFourBlockRelease(ram); 45 | free(indices); 46 | args->size=size; // for party 1 47 | } 48 | -------------------------------------------------------------------------------- /bench/benchSqrtAccess.c: -------------------------------------------------------------------------------- 1 | #include"benchSqrtAccess.h" 2 | #include"util.h" 3 | #include 4 | #include 5 | #include 6 | 7 | void showUsage(const char* exec) 8 | { 9 | fprintf(stderr,"Usage: %s -- \n" 10 | " or: %s \n", 11 | exec,exec); 12 | exit(1); 13 | } 14 | int main(int argc,char* argv[]) 15 | { 16 | ProtocolDesc pd; 17 | TestSqrtAccessIO io; 18 | int i,me; 19 | if(argc<4) showUsage(argv[0]); 20 | else if(strcmp(argv[1],"--")==0) 21 | { if(argc<5) showUsage(argv[0]); 22 | if(sscanf(argv[4],"%d",&io.rep)!=1) showUsage(argv[0]); 23 | if(sscanf(argv[3],"%d",&io.size)!=1) showUsage(argv[0]); 24 | io.content=malloc(sizeof(int)*io.size); 25 | for(i=0;i 2 | #include"benchSqrtAccess.h" 3 | #include"sqrtoram.oh" 4 | #include"copy.oh" 5 | #include"decoder.oh" 6 | #include 7 | #include 8 | #include"util.h" 9 | 10 | void testSqrtAccess(void* vargs) 11 | { 12 | TestSqrtAccessIO* args = vargs; 13 | int size = ocBroadcastInt(args->indexn,2); 14 | int n = ocBroadcastInt(args->size,1); 15 | const int rep = ocBroadcastInt(args->rep,1); 16 | int* pcontent = calloc(n*rep,sizeof(int)); 17 | obliv int* content = calloc(n*rep,sizeof(obliv int)); 18 | obliv int* indices = calloc(size,sizeof(obliv int)); 19 | obliv int *output = calloc(rep,sizeof(obliv int)); 20 | int i,j; 21 | if(ocCurrentParty()==1) for(i=0;icontent[i]; 22 | OcCopy cpy = ocCopyIntN(rep); 23 | feedOblivIntArray(content,pcontent,n*rep,1); 24 | feedOblivIntArray(indices,args->indices,size,2); 25 | ProtocolDesc* pd = ocCurrentProto(); 26 | size_t start = tcp2PBytesSent(pd),mid,end; 27 | double startt = wallClock(), midt, endt; 28 | OcOram* ram = (OcOram*)ocSqrtOramNew(&cpy,content,n); 29 | args->outputs = malloc(size*sizeof(int)); 30 | for(int i=0;ioutputs+i,output[0],0); 33 | } 34 | mid = tcp2PBytesSent(pd); 35 | midt = wallClock(); 36 | printf("ORAM bytes sent: %zd, time taken: %f s\n",mid-start,midt-startt); 37 | obliv bool* dec = calloc(n,sizeof(obliv bool)); 38 | for(i=0;ioutputs+i,output[0],0); 44 | } 45 | end = tcp2PBytesSent(pd); 46 | endt = wallClock(); 47 | printf("LinearScan bytes sent: %zd, time taken: %f s\n",end-mid,endt-midt); 48 | free(dec); 49 | ocOramRelease(ram); 50 | free(indices); 51 | free(content); 52 | free(pcontent); 53 | free(output); 54 | args->indexn=size; // for party 1 55 | } 56 | -------------------------------------------------------------------------------- /bench/search.c: -------------------------------------------------------------------------------- 1 | /* Common parts: 2 | * Parse server:port, connect TCP 3 | * Parse 4 | * Initialize with zeroed/garbage ORAMs (utils) 5 | * Runtime reporting 6 | Uncommon parts: 7 | * Concrete inputs (test mode) 8 | * Input size, test count (bench mode) 9 | Todo: 10 | * Write search/bfs, refactor later 11 | * Tons of boilerplate, to refactor later 12 | 13 | ./search test :1234 -t lin 3 2 4 4 9 2 14 | # mode and netspec can be flipped 15 | # '-x' options can appear pretty much anywhere 16 | ./search :1234 test 3 9 2 8 3 4 -t lin 17 | ./search bench server:1234 --type=sqrt -z 499 -c 100 18 | Bench shows timing, test uses return value or one-line error. 19 | 20 | There should be a "mismatched params" error. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include"search.h" 30 | 31 | const char cmdUsage[] = 32 | "\n" 33 | "Usage: search test :port \n" 34 | " or: search test server:port \n" 35 | " or: search bench --size=# --axcount=# :port\n" 36 | " or: search bench server:port\n" 37 | "\n" 38 | "Options:\n" 39 | " -t ORAM type. One of linear, sqrt, or ckt.\n" 40 | " --oramtype=\n" 41 | "\n" 42 | "Test mode:\n" 43 | " Runs ORAM search on manually entered data. The search is followed by\n" 44 | " a plaintext evaluation that checks correctness.\n" 45 | " A sequence of integers. Must be sorted.\n" 46 | " A sequence of integers to search for.\n" 47 | " --showResult, +o Show output locations (default).\n" 48 | " --hideResult, -o Don't show output locations.\n" 49 | "\n" 50 | "Benchmark mode:\n" 51 | " --size=n, -z n Number of integers in autogenerated array\n" 52 | " --axcount=n, -c n Number of random searches to perform\n" 53 | ; 54 | 55 | bool searchCmdSizeCount(CmdParseState* s,void* vio) 56 | { 57 | SearchIO* io=vio; 58 | return cmdParseSingleInt(s,'z',"size",&io->n,-1) 59 | || cmdParseSingleInt(s,'c',"axcount",&io->axc,-1); 60 | } 61 | 62 | int main(int argc,char *argv[]) 63 | { 64 | SearchIO io = {.data=NULL,.indices=NULL,.outputs=NULL,.n=-1,.axc=-1}; 65 | ProtocolDesc pd; 66 | CmdParseState ps = cmdParseInit(argc,argv); 67 | cmdSetUsage(cmdUsage); 68 | cmdParseCommon(&ps,searchCmdSizeCount,&io); 69 | if(cmdMode==cmdModeTest) 70 | { if(cmdMeServing()) 71 | { cmdParseTermInts(&ps,&io.data,&io.n); 72 | for(int i=1;iio.data[i]) 73 | error(-1,0,"Input data should be sorted\n"); 74 | } 75 | else cmdParseTermInts(&ps,&io.indices,&io.axc); 76 | } 77 | cmdParseEnd(&ps); 78 | cmdConnectOrDie(&pd); 79 | execYaoProtocol(&pd,searchProto,&io); 80 | if(cmdShowResult) 81 | { printf("Outputs:"); 82 | for(int i=0;i 3 | #include 4 | #include 5 | #include 6 | 7 | typedef obliv bool (* block_lt_function)(void * blk, void * arg) obliv; 8 | int rangeHalf(int x) { return x>1?(x+1)/2:0; } 9 | 10 | obliv int binary_search(void* dest, OcOram* ram, 11 | block_lt_function fn, void* arg) { 12 | int range; 13 | if(ram->n==0) return 0; 14 | 15 | // In the obliv world, we don't know exactly how many iterations 16 | // are required. So there is a risk that we might invoke ocOramRead() 17 | // on out of bound index like n. 18 | obliv int iimin = 0; 19 | obliv int iimax = ram->n - 1; 20 | obliv int less; 21 | void * temp_element = calloc(1, ram->cpy->eltsize); 22 | for (range=ram->n-1; range; range=rangeHalf(range)) { 23 | obliv int iimid = (iimin + iimax) / 2; 24 | ocOramRead(temp_element, ram, iimid); 25 | less = fn(temp_element, arg); 26 | obliv if(less & iiminsuper.n; 40 | obliv bool done = false; 41 | OcCopy* cpy = ram->super.cpy; 42 | for (int ii = 0; ii < ram->super.n; ii++) { 43 | void * elt = ocCopyElt(cpy,ram->data,ii); 44 | obliv bool less = fn(elt,arg); 45 | obliv if (!done & !less) { 46 | ocCopy(cpy,dest,elt); 47 | index = ii; 48 | done = true; 49 | } 50 | } 51 | return index; 52 | } 53 | 54 | static int cmpint(void* a,void* b) { return *(int*)a-*(int*)b; } 55 | obliv bool intLessThan(void* a,void* b) obliv 56 | { return *(obliv int*)a<*(obliv int*)b; } 57 | 58 | // Needs to go into util.oc 59 | #include 60 | #include 61 | OcOram* benchmarkOram(void* data,int n) 62 | { if(cmdOramType==oramTypeLin) 63 | return &ocLinearOramNew(&ocCopyInt,data,n)->super; 64 | else if(cmdOramType==oramTypeSqrt) 65 | return CAST(ocSqrtOramNew(&ocCopyInt,data,n)); 66 | else 67 | // Despite the name, this returns an *uninitialized* ORAM 68 | // Initializing would take too long 69 | return &ckt_initialize(n,&ocCopyInt)->super; 70 | } 71 | 72 | // Does the input verification/initialization that require both parties. 73 | void searchProto(void* varg) 74 | { 75 | SearchIO* arg=varg; 76 | matchedBroadcastInt(&arg->n,arg->n!=-1,"size"); 77 | matchedBroadcastInt(&arg->axc,arg->axc!=-1,"axcount"); 78 | matchedBroadcastInt(&cmdOramType,true,"oram type"); 79 | if(!arg->data) 80 | { arg->data=randomIntArray((1<<31)-1,arg->n); 81 | qsort(arg->data,arg->n,sizeof(int),cmpint); 82 | } 83 | if(!arg->indices) arg->indices=randomIntArray(arg->n,arg->axc); 84 | 85 | obliv int *in = calloc(arg->n,sizeof*in); 86 | obliv int *pos = calloc(arg->axc,sizeof*pos); 87 | obliv int *out = calloc(arg->axc,sizeof*out); 88 | obliv int x; 89 | int k; 90 | feedOblivIntArray(in,arg->data,arg->n,1); 91 | feedOblivIntArray(pos,arg->indices,arg->axc,2); 92 | if(cmdOramType==oramTypeLin) 93 | { OcLinearOram *ram = ocLinearOramNew(&ocCopyInt,in,arg->n); 94 | for(k=0;kaxc;++k) 95 | out[k]=linear_search(&x,ram,intLessThan,pos+k); 96 | ocOramRelease(&ram->super); 97 | }else 98 | { 99 | OcOram *ram = benchmarkOram(in,arg->n); 100 | for(k=0;kaxc;++k) 101 | out[k]=binary_search(&x,ram,intLessThan,pos+k); 102 | ocOramRelease(ram); 103 | } 104 | if(!arg->outputs) arg->outputs=malloc(arg->axc*sizeof(int)); 105 | for(k=0;kaxc;++k) revealOblivInt(arg->outputs+k,out[k],1); 106 | for(k=0;kaxc;++k) revealOblivInt(arg->outputs+k,out[k],2); 107 | free(out); free(pos); free(in); 108 | } 109 | -------------------------------------------------------------------------------- /bench/search.oh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef obliv int (* block_cmp_function)(void * blk, void * arg) obliv; 4 | -------------------------------------------------------------------------------- /bench/timecopy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include"timecopy.h" 3 | #include 4 | #include"util.h" 5 | 6 | int main(int argc,char* argv[]) 7 | { 8 | if(argc<6) 9 | { 10 | fprintf(stderr,"Usage: %s \n", 11 | argv[0]); 12 | return 1; 13 | } 14 | ProtocolDesc pd; 15 | TimeCopyIO io; 16 | io.useShare = (argv[3][0]!='y'); 17 | sscanf(argv[4],"%d",&io.batchsz); 18 | sscanf(argv[5],"%d",&io.rounds); 19 | const char* server=argv[1]; 20 | connectOrDie(&pd,server,argv[2]); 21 | setCurrentParty(&pd,strcmp(server,"--")==0?1:2); 22 | execYaoProtocol(&pd,timeCopy,&io); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /bench/timecopy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef struct 5 | { int rounds,batchsz; 6 | bool useShare; 7 | } TimeCopyIO; 8 | 9 | void timeCopy(void* varg); 10 | -------------------------------------------------------------------------------- /bench/timecopy.oc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"copy.oh" 4 | #include 5 | #include"timecopy.h" 6 | #include"util.h" 7 | 8 | #include 9 | #define HERE printf("Party %d: %s:%d\n",ocCurrentParty(),__FILE__,__LINE__) 10 | void timeCopy(void* vargs) 11 | { 12 | TimeCopyIO* args = vargs; 13 | int r,i, n = args->batchsz; 14 | obliv int* data0 = calloc(n,sizeof(obliv int)); 15 | obliv int* data1 = calloc(n,sizeof(obliv int)); 16 | obliv bool* sel = calloc(n,sizeof(obliv bool)); 17 | int* zeroes = calloc(n,sizeof(int)); 18 | 19 | double start = wallClock(); 20 | feedOblivBoolArray(sel,(bool*)zeroes,n,2); 21 | int me = ocCurrentParty(); 22 | printf("Feed inputs done: %lf\n",wallClock()-start); 23 | 24 | if(args->useShare) 25 | { ProtocolDesc* pd = ocCurrentProto(); 26 | ocShareInit(pd); 27 | OcCopy* cpy = ocShareCopyNew(pd,n,sizeof(OcSharedInt)); 28 | OcSharedInt* sh0 = calloc(n,sizeof(OcSharedInt)); 29 | OcSharedInt* sh1 = calloc(n,sizeof(OcSharedInt)); 30 | printf("Memallocs done: %lf\n",wallClock()-start); 31 | ocFeedSharedIntN(sh0,zeroes,n,1); 32 | ocFeedSharedIntN(sh1,zeroes,n,1); 33 | printf("Setups done: %lf\n",wallClock()-start); 34 | for(r=0;rrounds;++r) ocCopyCondN(cpy,sh0,sh1,sel,n); 35 | printf("Main loop done: %lf\n",wallClock()-start); 36 | free(sh0); free(sh1); 37 | ocCopyRelease(cpy); 38 | ocShareCleanup(pd); 39 | printf("All done: %lf\n",wallClock()-start); 40 | }else 41 | { OcCopy* cpy = &ocCopyInt; 42 | // Feed in lots of zeroes 43 | feedOblivIntArray(data0,zeroes,n,1); 44 | feedOblivIntArray(data1,zeroes,n,1); 45 | for(r=0;rrounds;++r) ocCopyCondN(cpy,data0,data1,sel,n); 46 | } 47 | 48 | free(zeroes); free(sel); free(data0); free(data1); 49 | } 50 | -------------------------------------------------------------------------------- /oram/block.oc: -------------------------------------------------------------------------------- 1 | #include "block.oh" 2 | 3 | Block* block_initialize(OcCopy* cpy) obliv { 4 | Block * res = calloc_obliv(sizeof(Block), 1); 5 | res->data = calloc_obliv(1, cpy->eltsize); 6 | res->is_dummy = true; 7 | return res; 8 | } 9 | 10 | void block_release(Block* b) obliv { 11 | free_obliv(b->data); 12 | free_obliv(b); 13 | } 14 | 15 | void block_copy(Block* block, Block * des, OcCopy* cpy) obliv { 16 | des->index = block->index; 17 | des->is_dummy = block->is_dummy; 18 | des->position_label = block->position_label; 19 | ocCopy(cpy,des->data,block->data); 20 | } 21 | -------------------------------------------------------------------------------- /oram/block.oh: -------------------------------------------------------------------------------- 1 | #ifndef BLOCK_H__ 2 | #define BLOCK_H__ 3 | #include "ckt_utils.oh" 4 | #include "copy.oh" 5 | 6 | typedef struct Block { 7 | obliv int index; 8 | obliv bool is_dummy; 9 | obliv int position_label; 10 | void* data; 11 | } Block; 12 | 13 | Block* block_initialize(OcCopy* cpy) obliv; 14 | void block_release(Block* b) obliv; 15 | void block_copy(Block* a, Block* des, OcCopy* cpy) obliv; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /oram/circuit_oram.oc: -------------------------------------------------------------------------------- 1 | #include "linearoram.oh" 2 | #include "circuit_oram.oh" 3 | 4 | void get_random (CircuitOram * oram, obliv bool * res, int length) obliv { 5 | if (length + oram->rand_pool_size >= oram->rand_pool_cap) { 6 | get_rand_obliv(oram->gen, oram->rand_pool, oram->rand_pool_cap); 7 | oram->rand_pool_size = 0; 8 | } 9 | for(int i = 0; i < length; ++i) 10 | res[i] = oram->rand_pool[oram->rand_pool_size+i]; 11 | oram->rand_pool_size+=length; 12 | } 13 | 14 | CircuitOram* ckt_initialize_more_param(int N, OcCopy* cpy, int recursion_factor, int cutoff){ 15 | CircuitOram* res = calloc(sizeof(CircuitOram), 1); 16 | res->super.n=N; 17 | res->super.cpy=cpy; 18 | res->super.release = ckt_release; 19 | res->super.access = ckt_apply; 20 | res->cutoff = cutoff; 21 | res->recursion_factor = recursion_factor; 22 | res->orams = calloc(sizeof(NonRecursiveOram*), 10);//this is an upperbound 23 | res->poscpy = malloc(sizeof(OcCopy)*10); 24 | 25 | res->orams[0] = nro_initialize(N, cpy); 26 | 27 | int new_data_size = res->orams[0]->position_label_size * recursion_factor; 28 | int newN = (1 << res->orams[0]->index_size) / recursion_factor; 29 | int cur = 0; 30 | while(newN*recursion_factor > cutoff) { 31 | cur++; 32 | res->poscpy[cur] = ocCopyBoolN(new_data_size); 33 | res->orams[cur] = nro_initialize(newN, res->poscpy+cur); 34 | new_data_size = res->orams[cur]->position_label_size * recursion_factor; 35 | newN = (1 << res->orams[cur]->index_size) / recursion_factor; 36 | } 37 | res->num_recursion = cur+1; 38 | 39 | res->poscpy[cur+1]=ocCopyBoolN(res->orams[cur]->position_label_size); 40 | res->base = ocLinearOramNew(res->poscpy+cur+1, 41 | NULL,1<orams[cur]->index_size); 42 | 43 | res -> gen = newBCipherRandomGen(); 44 | 45 | res->rand_pool_cap = 200000; 46 | res->rand_pool_size = 0; 47 | res->rand_pool = calloc(sizeof(obliv bool), res->rand_pool_cap); 48 | get_rand_obliv(res->gen, res->rand_pool, res->rand_pool_cap); 49 | return res; 50 | } 51 | 52 | CircuitOram* ckt_initialize(int N, OcCopy* cpy) { 53 | return ckt_initialize_more_param(N, cpy, 8, 1<<8); 54 | } 55 | void ckt_release(OcOram* super) { 56 | CircuitOram* oram = CAST(super); 57 | for(int i = 0; i < oram->num_recursion; ++i) 58 | nro_release(oram->orams[i]); 59 | 60 | ocOramRelease(oram->base); 61 | free(oram->poscpy); 62 | free(oram->orams); 63 | releaseBCipherRandomGen(oram->gen); 64 | free(oram->rand_pool); 65 | free(oram); 66 | } 67 | 68 | void ckt_read(CircuitOram* oram, obliv int index, void* data) obliv { 69 | obliv int pos = 0; 70 | obliv int new_pos = 0; 71 | 72 | update_trees(oram, index, 1, &pos, &new_pos); 73 | 74 | /* ~obliv(){int p1; revealOblivInt(&p1,index, 0); 75 | int p2; revealOblivInt(&p2,pos, 0); 76 | int p3; revealOblivInt(&p3,new_pos, 0); 77 | printf("idx,pos,n_pos, %d,%d,%d\n", p1,p2,p3);} 78 | */ 79 | nro_read(oram->orams[0], index, pos, new_pos, data); 80 | } 81 | 82 | void ckt_apply(OcOram* super, obliv int index, OcOramAccessCb func, void * ext_data) obliv { 83 | CircuitOram* oram = CAST(super); 84 | obliv int pos = 0; 85 | obliv int new_pos = 0; 86 | 87 | update_trees(oram, index, 1, &pos, &new_pos); 88 | 89 | void * data = calloc_obliv(1,super->cpy->eltsize); 90 | nro_read_and_remove(oram->orams[0], index, pos, data); 91 | func(super, data, ext_data); 92 | nro_put_back(oram->orams[0], index, new_pos, data); 93 | free_obliv(data); 94 | } 95 | 96 | void ckt_write(CircuitOram* oram, obliv int index, void* data) obliv { 97 | obliv int pos = 0; 98 | obliv int new_pos = 0; 99 | 100 | update_trees(oram, index, 1, &pos, &new_pos); 101 | 102 | /* ~obliv(){int p1; revealOblivInt(&p1,index, 0); 103 | int p2; revealOblivInt(&p2,pos, 0); 104 | int p3; revealOblivInt(&p3,new_pos, 0); 105 | printf("idx,pos,n_pos, %d,%d,%d\n", p1,p2,p3);} 106 | */ 107 | nro_write(oram->orams[0], index, pos, new_pos, data); 108 | } 109 | 110 | void update_trees(CircuitOram* oram, obliv int index, int level, obliv int * pos, obliv int * new_pos) obliv { 111 | int entry_size = oram->orams[level-1]->position_label_size; 112 | int block_size = oram->recursion_factor*entry_size; 113 | if(level == oram->num_recursion) { 114 | obliv bool* bools = calloc_obliv(sizeof(obliv bool), entry_size); 115 | ocOramRead(bools, oram->base, index); 116 | obliv bool * new_pos_bools = calloc_obliv(sizeof(obliv bool), entry_size); 117 | get_random(oram, new_pos_bools, entry_size); 118 | ocOramWrite(oram->base, index, new_pos_bools); 119 | 120 | bool_to_int_obliv(bools, pos, entry_size); 121 | bool_to_int_obliv(new_pos_bools, new_pos, entry_size); 122 | free_obliv(bools); 123 | free_obliv(new_pos_bools); 124 | } else { 125 | NonRecursiveOram * current_oram = oram->orams[level]; 126 | obliv bool * pos_map = calloc_obliv(sizeof(obliv bool), block_size); 127 | obliv bool * bools = calloc_obliv(sizeof(obliv bool), entry_size); 128 | obliv bool * new_pos_bools = calloc_obliv(sizeof(obliv bool), entry_size); 129 | 130 | obliv int new_index = index >> (oram->orams[level-1]->index_size - current_oram->index_size), 131 | f_pos = 0, f_new_pos = 0; 132 | 133 | update_trees(oram, new_index, level+1, &f_pos, &f_new_pos); 134 | 135 | nro_read_and_remove(current_oram, new_index, f_pos, pos_map); 136 | 137 | obliv int ith_pos = ((1<< (oram->orams[level-1]->index_size-current_oram->index_size))-1)&index;// (index >> current_oram->index_size); 138 | 139 | extract_bits(pos_map, ith_pos, entry_size, bools, oram); 140 | get_random(oram, new_pos_bools, entry_size); 141 | put_bits(pos_map, ith_pos, entry_size, new_pos_bools, oram); 142 | 143 | nro_put_back(current_oram, new_index, f_new_pos, pos_map); 144 | bool_to_int_obliv(bools, pos, entry_size); 145 | bool_to_int_obliv(new_pos_bools, new_pos, entry_size); 146 | free_obliv(bools); 147 | free_obliv(new_pos_bools); 148 | free_obliv(pos_map); 149 | } 150 | } 151 | 152 | void extract_bits(obliv bool * data_chunk, obliv int ith_pos, int entry_size, obliv bool * res, CircuitOram * oram) obliv { 153 | for(int i = 0; i < oram->recursion_factor; ++i) { 154 | obliv if(ith_pos == i) { 155 | for(int j = 0; j < entry_size; ++j) { 156 | res[j] = data_chunk[i*entry_size + j]; 157 | } 158 | } 159 | } 160 | } 161 | 162 | void put_bits(obliv bool * data_chunk, obliv int ith_pos, int entry_size, obliv bool * res, 163 | CircuitOram * oram) obliv { 164 | for(int i = 0; i < oram->recursion_factor; ++i) { 165 | obliv if(ith_pos == i) { 166 | for(int j = 0; j < entry_size; ++j) { 167 | data_chunk[i*entry_size + j] = res[j]; 168 | } 169 | } 170 | } 171 | } 172 | 173 | -------------------------------------------------------------------------------- /oram/circuit_oram.oh: -------------------------------------------------------------------------------- 1 | #include "block.oh" 2 | #include "nonrecursive_oram.oh" 3 | #include 4 | #include 5 | #include "copy.oh" 6 | #include "oram.oh" 7 | #ifndef ORAM_H__ 8 | #define ORAM_H__ 9 | 10 | typedef struct CircuitOram{ 11 | OcOram super; 12 | OcCopy *poscpy; 13 | NonRecursiveOram ** orams; 14 | OcOram* base; 15 | int recursion_factor; 16 | int cutoff; 17 | int num_recursion; 18 | BCipherRandomGen* gen; 19 | obliv bool * rand_pool; 20 | int rand_pool_cap; 21 | int rand_pool_size; 22 | } CircuitOram; 23 | 24 | void get_random (CircuitOram * oram, obliv bool * res, int length) obliv ; 25 | CircuitOram* ckt_initialize(int N, OcCopy* cpy); 26 | CircuitOram* ckt_initialize_more_param(int N, OcCopy* cpy, int recursion_factor, int cutoff); 27 | void ckt_release(OcOram* oram); 28 | 29 | void ckt_read(CircuitOram* oram, obliv int index, void* data) obliv; 30 | void ckt_write(CircuitOram* oram, obliv int index, void* data) obliv; 31 | void ckt_apply(OcOram* super, obliv int index, OcOramAccessCb func, void * ext_data) obliv; 32 | 33 | void update_trees(CircuitOram* oram, obliv int index, int level, obliv int * pos, obliv int * new_pos) obliv; 34 | 35 | void extract_bits(obliv bool * data_chunk, obliv int ith_pos, int entry_size, obliv bool * res, CircuitOram * oram) obliv; 36 | void put_bits(obliv bool * data_chunk, obliv int ith_pos, int entry_size, obliv bool * res, CircuitOram * oram) obliv; 37 | #endif 38 | -------------------------------------------------------------------------------- /oram/ckt_utils.oc: -------------------------------------------------------------------------------- 1 | #include "ckt_utils.oh" 2 | #include 3 | 4 | obliv int bit_mask(obliv int input, int high) obliv { 5 | int mask = (1<= 0; --i) { 78 | *res = (*res << 1); 79 | *res = (*res ^ (bools[i])); 80 | } 81 | } 82 | 83 | void int_to_bool_obliv(obliv int * input, obliv bool * res, int length) obliv { 84 | ~obliv(en) { 85 | obliv int tmp = *input; 86 | for(int i = 0; i < length && i < 32; ++i) { 87 | obliv if (en) 88 | res[i] = (tmp&1); 89 | tmp = tmp >> 1; 90 | } 91 | } 92 | } 93 | 94 | obliv int compute_depth(obliv int pos1, obliv int pos2, int logN) obliv 95 | { 96 | //return pos1^pos2; 97 | obliv int x = pos1 ^ pos2; 98 | obliv int n = logN; 99 | obliv int y; 100 | obliv int res = 0; 101 | y = x >>16; obliv if (y != 0) { n = n -16; x = y; } 102 | y = x >> 8; obliv if (y != 0) { n = n - 8; x = y; } 103 | y = x >> 4; obliv if (y != 0) { n = n - 4; x = y; } 104 | y = x >> 2; obliv if (y != 0) { n = n - 2; x = y; } 105 | y = x >> 1; 106 | obliv if (y != 0) 107 | res = n - 2; 108 | else 109 | res = n - x; 110 | return res; 111 | } 112 | 113 | void bool_to_char_obliv(obliv bool * bools, obliv char * chars, int length) { 114 | for(int i = 0; i < (length+7)/8; ++i) { 115 | obliv char tmp = 0; 116 | for(int j = 0; j < 8 && 8*i+j < length; ++j) { 117 | obliv char c = bools[8*i+j]; 118 | tmp ^= (c << j); 119 | } 120 | chars[i] = tmp; 121 | } 122 | } 123 | 124 | void char_to_bool_obliv(obliv char * chars, obliv bool * bools, int length) { 125 | for(int i = 0; i < (length+7)/8; ++i) { 126 | obliv char tmp = chars[i]; 127 | for(int j = 0; j < 8 && 8*i+j < length; ++j) { 128 | bools[8*i+j] = ((tmp & 1) == 1); 129 | tmp>>=1; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /oram/ckt_utils.oh: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #ifndef UTILS_H__ 5 | #define UTILS_H__ 6 | obliv int bit_mask(obliv int input, int high) obliv ; 7 | void *calloc_obliv(size_t nitems, size_t size) obliv; 8 | void free_obliv (void* ptr) obliv; 9 | void print_obliv (char* c,int i) obliv; 10 | void get_rand_obliv (BCipherRandomGen* gen, obliv bool * data, int len) obliv; 11 | 12 | void get_rand_obliv_ints(BCipherRandomGen* gen, obliv int * data, int len, int logN) obliv; 13 | 14 | void bool_to_int_obliv(obliv bool * bools, obliv int * res, int length) obliv; 15 | void int_to_bool_obliv(obliv int * bools, obliv bool * res, int length) obliv; 16 | 17 | obliv int compute_depth(obliv int pos1, obliv int pos2, obliv int logN) obliv; 18 | 19 | void bool_to_char_obliv(obliv bool * bools, obliv char * chars, int length); 20 | void char_to_bool_obliv(obliv char * chars, obliv bool * bools, int length); 21 | 22 | void batcherSort(void* data,size_t n,size_t w, void (*cmpswap)(void*,void*,void*),void* arg); 23 | void sort_int(obliv int * data, int n); 24 | #endif 25 | -------------------------------------------------------------------------------- /oram/decoder.oc: -------------------------------------------------------------------------------- 1 | #include"decoder.oh" 2 | // Low-level decoder method: meant to be used inside ~obliv(en) {...} 3 | void decoderEnAux(obliv bool* dest,obliv bool en, 4 | obliv unsigned ind,unsigned indlim,unsigned step) 5 | { 6 | if(indlim==1) { *dest=en; return; } 7 | obliv bool en1=((ind&1)&en); // FIXME "&&" should have worked too 8 | obliv bool en0=(en1!=en); 9 | ind>>=1; 10 | decoderEnAux(dest,en0,ind,(indlim+1)/2,step*2); 11 | decoderEnAux(dest+step,en1,ind,indlim/2,step*2); 12 | } 13 | void decoderEn(obliv bool* dest,obliv bool en, 14 | obliv unsigned ind,unsigned indlim) 15 | { decoderEnAux(dest,en,ind,indlim,1); } 16 | -------------------------------------------------------------------------------- /oram/decoder.oh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Essentially does this, but more optimized: 4 | for(int i=0;i 5 | #include 6 | 7 | typedef frozen struct 8 | { OcCmp *cmp; 9 | obliv bool *iserase, *isdata; 10 | void *data, *scratch; 11 | } PropagateArg; 12 | 13 | #define DATA(i) (arg->cmp->cpy->eltsize*(i)+arg->data) 14 | void swapDataFlags(PropagateArg* arg,size_t i,size_t j) obliv 15 | { 16 | obliv bool xx; 17 | ocSwap(&ocCopyBool, &arg->isdata[i], &arg->isdata[j], &xx); 18 | ocSwap(&ocCopyBool, &arg->iserase[i],&arg->iserase[j],&xx); 19 | ocSwap(arg->cmp->cpy,DATA(i),DATA(j),arg->scratch); 20 | } 21 | void sortByFlagsCmp(void* varg,size_t i,size_t j) 22 | { 23 | PropagateArg *arg = varg; 24 | obliv bool res = (!arg->iserase[i] & arg->iserase[j]); 25 | res = ocLessThanTie(&ocCmpBool,&arg->isdata[i],&arg->isdata[j],res); 26 | obliv if(!res) swapDataFlags(arg,i,j); 27 | } 28 | // This might go better if we had isblank rather than iserase. TODO optimize 29 | void sortAugmentedCmp(void* varg,size_t i,size_t j) 30 | { 31 | PropagateArg *arg = varg; 32 | obliv bool nonblanki = (arg->isdata[i]|arg->iserase[i]); 33 | obliv bool nonblankj = (arg->isdata[j]|arg->iserase[j]); 34 | // Sort by nonblank, data, isdata 35 | obliv bool res = (!arg->isdata[i]&arg->isdata[j]); 36 | res = ocLessThanTie(arg->cmp,DATA(i),DATA(j),res); 37 | res = ocLessThanTie(&ocCmpBool,&nonblanki,&nonblankj,res); 38 | obliv if(!res) swapDataFlags(arg,i,j); 39 | } 40 | /* 41 | Resolves erase commands and propagates unerased elements to the head. 42 | 43 | Transforms an array sort of like this: 44 | x!x--!xxx!---xxx! --> ----xxxx -----!!xx 45 | Conceptually, we have an array of n elements. Some of them are blank slots, 46 | some are data items (isdata[i]==true), while the rest are erase commands 47 | (iserase[i]==true). In the end, we want to have a head with a certain 48 | number of blank elements, and a certain number of data elements. All erase 49 | commands that can be resolved within this array gets resolved here. 50 | 51 | Caller should make sure that the array actually has the given number of 52 | head blank and data elements, specially after internal erases have been 53 | resolved. isdata[i] and iserase[i] should not both be true for any 54 | given i. Moreover, propagate() does not support duplicate elements 55 | in non-blank sorts ((isdata[i],data[i]) is unique). 56 | 57 | Params: 58 | cmp - object defining element properties 59 | data - array of n elements, each of size cpy->eltsize bytes 60 | n - number of elements in array 61 | isdata - array of n bools. isdata[i] == true implies element(cpy,data,i) 62 | is a valid data item 63 | iserase - array of n bools. iserase[i] == true implies element(cpy,data,i) 64 | specifies an element to be erased. 65 | head_data_out - number of data elements in the output 'head' 66 | head_blank_out - number of empty slots in the output 'head' 67 | */ 68 | void 69 | eraseSetPropagate(OcCmp* cmp, 70 | char* data, size_t n, 71 | obliv bool* isdata, obliv bool* iserase, 72 | size_t head_data_out, size_t head_blank_out) 73 | { 74 | PropagateArg arg_ = 75 | { .cmp = cmp, .isdata = isdata, .iserase = iserase, 76 | .data = data, .scratch = calloc(1,cmp->cpy->eltsize) 77 | }; 78 | PropagateArg *arg=&arg_; 79 | size_t i; 80 | // We might be able to do tons of merge, instead of a sort 81 | batcherSort(arg,0,n,sortAugmentedCmp); 82 | for(i=1;icpy,DATA(i+off),DATA(n-i-1),arg->scratch); 92 | } 93 | free(arg->scratch); 94 | } 95 | #undef DATA 96 | 97 | // Either we should assume headTotal = head0*powerOfTwo 98 | // Or, we should have well-defined semantics for other cases TODO 99 | static void sift(OcCopy* cpy,void* data,size_t headTotal,size_t head0) 100 | { 101 | 102 | } 103 | -------------------------------------------------------------------------------- /oram/eraseSet/eraseSet.oh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include"sort.oh" 3 | 4 | frozen typedef struct EraseSet EraseSet; 5 | 6 | // Stores things that can be copied and compared 7 | // Comparison allows polylog search 8 | 9 | EraseSet* eraseSetNew(OcCmp* cmp,OcCopy* cpy,const char* data,size_t n); 10 | void eraseSetRelease(EraseSet* s); 11 | const char* eraseSetTop(EraseSet* s); 12 | void eraseSetErase(EraseSet* s,const char* x); 13 | 14 | // Internal functions only used in debugging 15 | void 16 | eraseSetPropagate(OcCmp* cmp, 17 | char* data, size_t n, 18 | obliv bool* isdata, obliv bool* iserase, 19 | size_t head_data_out, size_t head_blank_out); 20 | -------------------------------------------------------------------------------- /oram/eraseSet/lazyFilter.oc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // ------------------ Batcher sorting ----------------------------------------- 4 | 5 | void batcherSwap(unsigned char* data,size_t n,size_t w, 6 | void (*cmpswap)(void*,void*,void*),void* arg) 7 | { 8 | size_t i; 9 | for(i=0;i+1t; 48 | int k = (t-(t&(t-1))); // number of elements to shift 49 | // assume isIndex[k..2k) are true, isHole[k..2k) are false 50 | // TODO 51 | // Merge by index (sorted, but porous warning) 52 | // Scan for repeats 53 | // filter x 2 to extract them back 54 | } 55 | -------------------------------------------------------------------------------- /oram/eraseSet/testPropagate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include"testPropagate.h" 5 | #include"util.h" 6 | 7 | void showUsage() 8 | { 9 | fprintf(stderr, 10 | "Usage: ./testPropagate -- (.|-num|num)*\n" 11 | " ./testPropagate \n"); 12 | exit(1); 13 | } 14 | 15 | int intCmp(const void* a, const void* b) 16 | { return *(const int*)a-*(const int*)b; } 17 | void initArrays(int** dataCopy,bool** hasdata,bool** haserase, 18 | int* data,size_t n) 19 | { 20 | *dataCopy=malloc(n*sizeof(int)); 21 | *hasdata = calloc(n,sizeof(bool)); 22 | *haserase = calloc(n,sizeof(bool)); 23 | memcpy(*dataCopy,data,n*(sizeof(int))); 24 | qsort(*dataCopy,n,sizeof(int),intCmp); 25 | } 26 | bool recordArrayCheck(const int dataCopy[],bool hasdata[],bool haserase[], 27 | size_t n,int data,bool isdata,bool iserase) 28 | { 29 | if(!isdata && !iserase) return true; 30 | size_t i = (const int*)bsearch(&data,dataCopy,n,sizeof(int),intCmp)-dataCopy; 31 | if(iserase) // can't have duplicates 32 | { if(haserase[i]) return false; 33 | else haserase[i]=true; 34 | }else 35 | { if(hasdata[i]) return false; 36 | else hasdata[i]=true; 37 | } 38 | return true; 39 | } 40 | bool resultCheckArray(const int dataCopy[], 41 | bool hasdata[],bool haserase[], 42 | size_t n,int data,bool isdata,bool iserase) 43 | { 44 | if(!isdata && !iserase) return true; 45 | size_t i = (const int*)bsearch(&data,dataCopy,n,sizeof(int),intCmp)-dataCopy; 46 | if(hasdata[i]==haserase[i]) return false; // Should have cancelled out 47 | if(haserase[i]!=iserase) return false; // Conflicting with input data 48 | hasdata[i]=haserase[i]=false; // Don't want new duplicates 49 | return true; 50 | } 51 | void cleanupArray(int dataCopy[],bool hasdata[],bool haserase[]) 52 | { free(dataCopy); free(hasdata); free(haserase); } 53 | 54 | int main(int argc,char* argv[]) 55 | { 56 | PropagateArgs args; 57 | size_t n,i; 58 | if(argc<3) showUsage(); 59 | int me = strcmp(argv[1],"--")==0?1:2; 60 | int *dataCopy; 61 | bool *hasdata,*haserase; 62 | if(me==1) 63 | { args.n=n=argc-3; 64 | args.data=malloc(n*sizeof(int)); 65 | args.isdata=calloc(n,sizeof(bool)); 66 | args.iserase=calloc(n,sizeof(bool)); 67 | for(i=0;i 4 | 5 | void testPropagate(void* vargs) 6 | { 7 | PropagateArgs* args = vargs; 8 | size_t n = ocBroadcastInt(args->n,1), 9 | outBlank = ocBroadcastInt(args->outBlank,2), 10 | outData = ocBroadcastInt(args->outData,2); 11 | obliv int *data = calloc(n,sizeof(obliv int)); 12 | obliv bool *isdata = calloc(n,sizeof(obliv bool)), 13 | *iserase = calloc(n,sizeof(obliv bool)); 14 | feedOblivIntArray(data,args->data,n,1); 15 | feedOblivBoolArray(isdata,args->isdata,n,1); 16 | feedOblivBoolArray(iserase,args->iserase,n,1); 17 | eraseSetPropagate(&ocCmpInt,data,n,isdata,iserase,outData,outBlank); 18 | if(ocCurrentParty()==2) 19 | { args->data = malloc(n*sizeof(int)); 20 | args->isdata = malloc(n*sizeof(bool)); 21 | args->iserase = malloc(n*sizeof(bool)); 22 | } 23 | for(size_t i=0;idata+i,data[i],0); 25 | revealOblivBool(args->isdata+i,isdata[i],0); 26 | revealOblivBool(args->iserase+i,iserase[i],0); 27 | } 28 | args->n=n; 29 | args->outBlank=outBlank; 30 | args->outData=outData; 31 | free(data); 32 | free(isdata); 33 | free(iserase); 34 | } 35 | -------------------------------------------------------------------------------- /oram/linearoram.oc: -------------------------------------------------------------------------------- 1 | #include"linearoram.oh" 2 | #include"decoder.oh" 3 | void ocLinearOramRelease(OcOram* super) 4 | { OcLinearOram* ram = CAST(super); 5 | free(ram->data); 6 | free(ram->flags); 7 | free(ram); 8 | } 9 | 10 | void 11 | ocLinearOramAccess(OcOram* super,obliv int index, 12 | OcOramAccessCb f,void* arg) obliv 13 | { 14 | OcLinearOram* ram = CAST(super); 15 | ~obliv(en) decoderEn(ram->flags,en,index,super->n); 16 | for(int i=0;in;++i) obliv if(ram->flags[i]) 17 | f(super,ocCopyElt(super->cpy,ram->data,i),arg); 18 | } 19 | 20 | OcLinearOram* ocLinearOramNew(OcCopy* cpy,void* data,int n) 21 | { 22 | OcLinearOram* ram = malloc(sizeof*ram); 23 | ram->data=malloc(cpy->eltsize*n); 24 | if(data) memcpy(ram->data,data,cpy->eltsize*n); 25 | else ocCopyZeroFill(cpy,ram->data,n); 26 | ram->flags=calloc(n,sizeof(obliv bool)); 27 | OcOram *s = &ram->super; 28 | s->n=n; 29 | s->cpy=cpy; 30 | s->access=ocLinearOramAccess; 31 | s->release=ocLinearOramRelease; 32 | return ram; 33 | } 34 | -------------------------------------------------------------------------------- /oram/linearoram.oh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include"oram.oh" 3 | 4 | typedef struct 5 | { OcOram super; 6 | obliv bool* flags; 7 | void* data; 8 | } OcLinearOram; 9 | 10 | // If data is NULL, it is zero-filled with ocCopyZeroFill 11 | OcLinearOram* ocLinearOramNew(OcCopy* cpy,void* data,int n); 12 | -------------------------------------------------------------------------------- /oram/nonrecursive_oram.oc: -------------------------------------------------------------------------------- 1 | #include "nonrecursive_oram.oh" 2 | 3 | void print_block(Block * b) obliv { 4 | ~obliv(){ 5 | int tmp, tmp2; 6 | revealOblivInt(&tmp, b->index, 0); 7 | revealOblivBool(&tmp2, b->is_dummy, 0); 8 | if (ocCurrentParty() == 1) 9 | printf("Idx:%d;isD:%d ", tmp, tmp2); 10 | } 11 | } 12 | void print_oram(NonRecursiveOram * oram) obliv { 13 | ~obliv() { 14 | if (ocCurrentParty() == 1) 15 | printf("%s", "stash:"); 16 | for(int i = 0; i < oram->stash_size && i < 10; ++i) 17 | print_block(oram->stash[i]); 18 | printf("%s", "\n"); 19 | } 20 | } 21 | 22 | NonRecursiveOram* nro_initialize(int _N, OcCopy* cpy) { 23 | NonRecursiveOram* res = calloc_obliv(sizeof(NonRecursiveOram), 1); 24 | res->stash_size = 33; 25 | res->bucket_size = 3; 26 | res -> cpy = cpy; 27 | 28 | int a = 1; 29 | int logN = 1; 30 | while (a < _N) { 31 | a *= 2; 32 | ++logN; 33 | } 34 | --logN; 35 | res->index_size = logN; 36 | res->position_label_size = logN; 37 | res->N = 1 << logN; 38 | 39 | res-> tree = calloc_obliv(sizeof(Block**), res->N); 40 | res-> stash = calloc_obliv(sizeof(Block*), res->stash_size); 41 | for(int i = 0; i < res->N; ++i) { 42 | res->tree[i] = calloc_obliv(sizeof(Block*), res->bucket_size); 43 | for(int j = 0; j < res->bucket_size; ++j) 44 | res->tree[i][j] = block_initialize(res->cpy); 45 | } 46 | for(int i = 0; i < res->stash_size; ++i) 47 | res->stash[i] = block_initialize(res->cpy); 48 | 49 | res->eviction_cnt = 0; 50 | res->deepest_index = calloc_obliv(res->index_size + 1, sizeof(obliv int)); 51 | res->deepest_depth = calloc_obliv(res->index_size + 1, sizeof(obliv int)); 52 | res->deepest = calloc_obliv(sizeof(obliv int), res->index_size+1); 53 | res->target = calloc_obliv(sizeof(obliv int), res->index_size+1); 54 | 55 | res->hold = block_initialize(res->cpy); 56 | res->to_write = block_initialize(res->cpy); 57 | res->path = path_initialize(res); 58 | return res; 59 | } 60 | 61 | void nro_release(NonRecursiveOram * oram) { 62 | for(int i = 0; i < oram->N; ++i) { 63 | for(int j = 0; j < oram->bucket_size; ++j) 64 | block_release(oram -> tree[i][j]); 65 | free_obliv(oram->tree[i]); 66 | } 67 | free_obliv(oram->tree); 68 | for(int i = 0; i < oram->stash_size; ++i) 69 | block_release(oram -> stash[i]); 70 | free_obliv(oram->stash); 71 | free_obliv(oram->deepest_index); 72 | free_obliv(oram->deepest_depth); 73 | free_obliv(oram->deepest); 74 | free_obliv(oram->target); 75 | block_release(oram->hold); 76 | block_release(oram->to_write); 77 | path_release(oram, oram->path); 78 | free_obliv(oram); 79 | } 80 | 81 | 82 | Block*** path_initialize(NonRecursiveOram* oram) obliv { 83 | Block*** path = calloc_obliv(sizeof(Block**), oram->index_size +1); 84 | path[0] = calloc_obliv(sizeof(Block*), oram->stash_size); 85 | for(int i = 0; i < oram->index_size; ++i) 86 | path[i+1] = calloc_obliv(sizeof(Block*), oram->bucket_size); 87 | return path; 88 | } 89 | 90 | void path_release(NonRecursiveOram * oram, Block *** path) obliv{ 91 | for(int i = 0; i < oram->index_size + 1; ++i) 92 | free_obliv(path[i]); 93 | free_obliv(path); 94 | } 95 | 96 | 97 | 98 | void bucket_read_and_remove(Block** blocks, int bucket_size, obliv int index, Block* res, OcCopy* cpy) obliv { 99 | for(int i = 0; i < bucket_size; ++i) { 100 | obliv if (blocks[i]->index == index & ( !blocks[i]->is_dummy)) { 101 | block_copy(blocks[i], res, cpy); 102 | blocks[i]->is_dummy = true; 103 | } 104 | } 105 | } 106 | 107 | void bucket_add(Block** blocks, int bucket_size, Block* new_block, OcCopy* cpy) obliv { 108 | obliv bool added = false; 109 | for(int i = 0; i < bucket_size; ++i) { 110 | obliv if( blocks[i]->is_dummy & (!added) ) { 111 | block_copy(new_block, blocks[i], cpy); 112 | added = true; 113 | } 114 | } 115 | } 116 | 117 | void path_read_and_remove(NonRecursiveOram* oram, obliv int index, Block* res) obliv { 118 | int bucket_size = oram->index_size*oram->bucket_size + oram->stash_size; 119 | Block** arr = calloc_obliv(sizeof(Block*), bucket_size); 120 | int cnt = 0; 121 | for(int i = 0; i < oram->stash_size; ++i) 122 | arr[cnt ++] = oram->path[0][i]; 123 | 124 | for(int i = 0; i < oram->index_size; ++i) 125 | for(int j = 0; j < oram->bucket_size; ++j) 126 | arr[cnt++] = oram->path[i+1][j]; 127 | bucket_read_and_remove(arr, bucket_size, index, res, oram->cpy); 128 | free_obliv(arr); 129 | } 130 | 131 | void nro_read_and_remove(NonRecursiveOram* oram, obliv int index, obliv int position_label, void* data) obliv { 132 | int position_label_clear = 0; 133 | ~obliv() { 134 | // struct timeval tv; 135 | // gettimeofday(&tv, 0); 136 | // printf("%d, %d s, %d milli\n", ocCurrentParty(), tv.tv_sec, tv.tv_usec/1000); 137 | revealOblivInt(&position_label_clear, position_label, 0); 138 | } 139 | get_path(oram, position_label_clear); 140 | Block* res_block = block_initialize(oram->cpy); 141 | path_read_and_remove(oram, index, res_block); 142 | 143 | ocCopy(oram->cpy,data,res_block->data); 144 | block_release(res_block); 145 | } 146 | 147 | void nro_put_back(NonRecursiveOram * oram, obliv int index, obliv int position_label, void* data) obliv { 148 | Block* des = block_initialize(oram->cpy); 149 | des->index = index; 150 | des->is_dummy = false; 151 | des->position_label = position_label; 152 | ocCopy(oram->cpy,des->data,data); 153 | bucket_add(oram->stash, oram->stash_size, des, oram->cpy); 154 | block_release(des); 155 | nro_flush(oram); 156 | nro_flush(oram); 157 | int haha; 158 | } 159 | 160 | 161 | void get_path( NonRecursiveOram* oram, int position_label) obliv { 162 | int index = 1; 163 | for(int i = 0; i < oram->stash_size; ++i) 164 | oram->path[0][i] = oram->stash[i]; 165 | for(int i = 0; i < oram->bucket_size; ++i) 166 | oram->path[1][i] = oram->tree[index][i]; 167 | for(int i = 1; i < oram->index_size; ++i) { 168 | index *= 2; 169 | if( (position_label >> (oram->position_label_size - i ) & 1) == 1) index++; 170 | for(int j = 0; j < oram->bucket_size; ++j) 171 | oram->path[i+1][j] = oram->tree[index][j]; 172 | } 173 | } 174 | 175 | 176 | void nro_read(NonRecursiveOram * oram, obliv int index, obliv int position_label, obliv int new_position_label, void* data) obliv { 177 | nro_read_and_remove(oram, index, position_label, data); 178 | nro_put_back(oram, index, new_position_label, data); 179 | } 180 | 181 | void nro_write(NonRecursiveOram * oram, obliv int index, obliv int position_label, obliv int new_position_label, void* data) { 182 | void* tmp = calloc_obliv(1,oram->cpy->eltsize); 183 | nro_read_and_remove(oram, index, position_label, tmp); 184 | nro_put_back(oram, index, new_position_label, data); 185 | free_obliv(tmp); 186 | } 187 | 188 | void nro_flush(NonRecursiveOram * oram) { 189 | int res = 0; 190 | int temp = oram->eviction_cnt; 191 | for (int i = oram->index_size - 1; i >= 0; --i) { 192 | res = res | ((temp & 1) << i); 193 | temp >>= 1; 194 | } 195 | oram->eviction_cnt = (oram -> eviction_cnt + 1)% oram-> N; 196 | get_path(oram, res); 197 | circuit_oram_flush(oram, res); 198 | //circuit_oram_flush(oram, res); 199 | // print_oram(oram); 200 | } 201 | 202 | 203 | void path_oram_flush(NonRecursiveOram * oram, int path_val) obliv { 204 | for(int i = oram->index_size; i > 0; --i) { 205 | for(int j = 0; j < oram->bucket_size; ++j) { 206 | obliv bool added = !oram->path[i][j]->is_dummy; 207 | for(int k = 0; k < i; ++k) { 208 | int cap = oram->bucket_size; 209 | if(k == 0) cap = oram->stash_size; 210 | for(int l = 0; l < cap; ++l) { 211 | obliv int depth = compute_depth(oram->path[k][l]->position_label, path_val, oram->index_size); 212 | obliv if(depth >= i & !oram->path[k][l]->is_dummy & !added) { 213 | block_copy(oram->path[k][l], oram->path[i][j], oram->cpy); 214 | oram->path[k][l]->is_dummy = true; 215 | added = true; 216 | } 217 | } 218 | } 219 | } 220 | } 221 | } 222 | 223 | void circuit_oram_flush(NonRecursiveOram * oram, int path_val) obliv { 224 | for (int i = 0; i <= oram->index_size; ++i) { 225 | int cap = oram->bucket_size; 226 | if (i == 0) cap = oram->stash_size; 227 | oram->deepest_index[i] = -1; 228 | oram->deepest_depth[i] = -1; 229 | for(int j = 0; j < cap; ++j) { 230 | obliv block_depth = compute_depth(oram->path[i][j]->position_label, path_val, oram->index_size); 231 | obliv if (block_depth > oram->deepest_depth[i] & !oram->path[i][j]->is_dummy) { 232 | oram->deepest_depth[i] = block_depth; 233 | oram->deepest_index[i] = j; 234 | } 235 | } 236 | } 237 | /*~obliv(){ 238 | for (int i = 0; i < oram->index_size; ++i) { 239 | int tmp; 240 | revealOblivInt(&tmp, deepest_depth[i], 0); 241 | printf("%d: dpeth,%d ",i, tmp); 242 | revealOblivInt(&tmp, deepest_index[i], 0); 243 | printf("index, %d\n", tmp); 244 | } 245 | }*/ 246 | 247 | //prepare deepest 248 | for (int i = 0; i < oram->index_size+1; ++i) 249 | oram->deepest[i] = oram->target[i] = -1; 250 | obliv int src = -1; 251 | obliv int goal = -1; 252 | obliv bool is_stash_empty = true; 253 | for(int i = 0; i < oram->stash_size; ++i) 254 | is_stash_empty = is_stash_empty & oram->stash[i]->is_dummy; 255 | obliv if (!is_stash_empty) { 256 | src = 0; 257 | goal = oram->deepest_depth[0]; 258 | } 259 | 260 | for(int i = 1; i <= oram->index_size; ++i) { 261 | obliv if (goal >= i) 262 | oram->deepest[i] = src; 263 | obliv int l = oram->deepest_depth[i]; 264 | obliv if (l > goal) { 265 | goal = l; 266 | src = i; 267 | } 268 | } 269 | 270 | /*~obliv(){ 271 | for (int i = 0; i < oram->index_size; ++i) { 272 | int tmp; 273 | revealOblivInt(&tmp, deepest[i], 0); 274 | printf("deepest, %d\n", tmp); 275 | } 276 | }*/ 277 | 278 | //prepare target 279 | obliv int dest = -1; src = -1; 280 | for(int i = oram->index_size; i >= 0; --i) { 281 | obliv if (i == src) { 282 | oram->target[i] = dest; 283 | dest = -1; 284 | src = -1; 285 | } 286 | 287 | obliv bool not_full = false; 288 | int cap = oram->bucket_size; 289 | if(i == 0) cap = oram->stash_size; 290 | for(int j = 0; j < cap; ++j) 291 | not_full = not_full | oram->path[i][j] -> is_dummy; 292 | obliv if ( ((dest == -1 & not_full ) | oram->target[i] != -1 ) 293 | & oram->deepest[i] != -1) { 294 | src = oram->deepest[i]; 295 | dest = i; 296 | } 297 | } 298 | /*~obliv(){ 299 | for (int i = 0; i < oram->index_size; ++i) { 300 | int tmp; 301 | revealOblivInt(&tmp, target[i], 0); 302 | printf("target, %d\n", tmp); 303 | } 304 | printf("===============\n"); 305 | }*/ 306 | 307 | 308 | dest = -1; 309 | obliv int to_write_depth = 0; 310 | obliv int hold_depth = 0; 311 | for(int i = 0; i <= oram->index_size; ++i) { 312 | oram->to_write->is_dummy = true; 313 | obliv if (!oram->hold->is_dummy & i == dest) { 314 | block_copy(oram->hold, oram->to_write, oram->cpy); 315 | oram->hold->is_dummy = true; 316 | to_write_depth = hold_depth; 317 | dest = -1; 318 | } 319 | int cap = oram->bucket_size; 320 | if(i == 0) cap = oram->stash_size; 321 | obliv if(oram->target[i] != -1) { 322 | for(int j = 0; j < cap; ++j) { 323 | obliv if (oram->deepest_index[i] == j) { 324 | block_copy(oram->path[i][j], oram->hold, oram->cpy); 325 | oram->path[i][j]->is_dummy = true; 326 | dest = oram->target[i]; 327 | hold_depth = oram->deepest_depth[i]; 328 | } 329 | } 330 | } 331 | 332 | obliv bool added = false; 333 | obliv if (!oram->to_write->is_dummy) { 334 | for(int j = 0; j < cap; ++j) { 335 | obliv if (oram->path[i][j]->is_dummy & !added) { 336 | block_copy(oram->to_write, oram->path[i][j], oram->cpy); 337 | added = true; 338 | obliv if (to_write_depth > oram->deepest_depth[i]) { 339 | oram->deepest_depth[i] = to_write_depth; 340 | oram->deepest_index[i] = j; 341 | } 342 | } 343 | } 344 | } 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /oram/nonrecursive_oram.oh: -------------------------------------------------------------------------------- 1 | #include "block.oh" 2 | #include "ckt_utils.oh" 3 | #include 4 | #ifndef NONORAM_H__ 5 | #define NONORAM_H__ 6 | 7 | typedef struct NonRecursiveOram{ 8 | Block *** tree; 9 | Block *** path; 10 | Block ** stash; 11 | int stash_size; 12 | int bucket_size; 13 | int index_size; 14 | int position_label_size; 15 | int N; 16 | OcCopy* cpy; 17 | int eviction_cnt; 18 | obliv int * deepest_index; 19 | obliv int * deepest_depth; 20 | obliv int *deepest; 21 | obliv int * target; 22 | Block * hold; 23 | Block * to_write; 24 | } NonRecursiveOram; 25 | 26 | NonRecursiveOram* nro_initialize(int _N, OcCopy* cpy); 27 | void nro_release(NonRecursiveOram * oram); 28 | 29 | Block*** path_initialize(NonRecursiveOram* oram) obliv; 30 | void path_release(NonRecursiveOram * oram, Block *** path) obliv; 31 | 32 | void bucket_read_and_remove(Block** blocks, int bucket_size, obliv int index, Block* res, OcCopy* cpy) obliv; 33 | void bucket_add(Block** blocks, int bucket_size, Block* new_block, OcCopy* cpy) obliv; 34 | void nro_put_back(NonRecursiveOram * oram, obliv int index, obliv int position_label, void* data) obliv; 35 | 36 | void path_read_and_remove(NonRecursiveOram* oram, obliv int index, Block* res) obliv; 37 | 38 | 39 | void nro_flush(NonRecursiveOram * oram) obliv; 40 | void circuit_oram_flush(NonRecursiveOram * oram, int path_val) obliv ; 41 | void path_oram_flush(NonRecursiveOram * oram, int path_val) obliv ; 42 | void get_path( NonRecursiveOram* oram, int position_label)obliv; 43 | 44 | void nro_read(NonRecursiveOram * oram, obliv int index, obliv int position_label, obliv int new_position_label, void* data) obliv; 45 | void nro_write(NonRecursiveOram * oram, obliv int index, obliv int position_label, obliv int new_position_label, void* data) obliv; 46 | 47 | 48 | void nro_read_and_remove(NonRecursiveOram* oram, obliv int index, obliv int position_label, void* data) obliv; 49 | void nro_put_back(NonRecursiveOram * oram, obliv int index, obliv int position_label, void* data) obliv; 50 | 51 | void print_block(Block * b) obliv; 52 | void print_oram(NonRecursiveOram * oram) obliv; 53 | #endif 54 | -------------------------------------------------------------------------------- /oram/obliv_copy_internal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void ocShareMuxes(ProtocolDesc* pd,char* z, 4 | const char* x0,const char* x1,size_t n,size_t eltsize, 5 | const bool* c,const __obliv_c__bool* wc,char* t); 6 | 7 | void ocFromShared_impl(ProtocolDesc* pd, void* dest, const void* src, 8 | size_t n,size_t bits,size_t bytes); 9 | -------------------------------------------------------------------------------- /oram/oram.oh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "copy.oh" 3 | 4 | // TODO remove decl from sqrtoram.oh 5 | // Type changed to Oram* 6 | // Callback params: OcOram* oram, void* oramblock, void* externalArgument 7 | typedef struct OcOram OcOram; 8 | typedef void (*OcOramAccessCb)(OcOram*, void*, void*) obliv; 9 | 10 | // TODO n,cpy has moved to parent type OcOram 11 | struct OcOram 12 | { size_t n; 13 | OcCopy* cpy; 14 | void (*access)(OcOram*,obliv int,OcOramAccessCb,void*) obliv; 15 | void (*release)(OcOram*); 16 | }; 17 | 18 | // Virtual function wrappers 19 | static inline void 20 | ocOramAccess(OcOram* ram,obliv int index,OcOramAccessCb f,void* arg) obliv 21 | { ram->access(ram,index,f,arg); } 22 | static inline void 23 | ocOramRelease(OcOram* ram) { ram->release(ram); } 24 | 25 | // Read/write convenience wrappers 26 | static void 27 | ocOramReadAux(OcOram* ram, void* oramBlock, void* extBlock) obliv 28 | { ocCopy(ram->cpy,extBlock,oramBlock); } 29 | static void inline 30 | ocOramRead(void* dest,OcOram* ram,obliv int index) obliv 31 | { ocOramAccess(ram,index,ocOramReadAux,dest); } 32 | 33 | static void 34 | ocOramWriteAux(OcOram* ram, void* oramBlock, void* extBlock) obliv 35 | { ocCopy(ram->cpy,oramBlock,extBlock); } 36 | static void inline 37 | ocOramWrite(OcOram* ram,obliv int index,const void* src) obliv 38 | { ocOramAccess(ram,index,ocOramWriteAux,src); } 39 | -------------------------------------------------------------------------------- /oram/qroram/README.txt: -------------------------------------------------------------------------------- 1 | QRORAM was a "first draft" version that is not currently being used. 2 | -------------------------------------------------------------------------------- /oram/qroram/qroram.c: -------------------------------------------------------------------------------- 1 | #include"qroram.h" 2 | #include 3 | #include // debugging 4 | #define HERE fprintf(stderr,"%s:%d\n",__FILE__,__LINE__) 5 | 6 | struct QroramTable 7 | { long long *cost; 8 | int *lastShuff; 9 | int *shuffleCost; 10 | int nmax,amax; 11 | }; 12 | 13 | static inline long long* cost(QroramTable* tbl,int a,int t) 14 | { return tbl->cost+a*(tbl->nmax+1)+t; } 15 | static inline int* lastShuff(QroramTable* tbl,int a,int t) 16 | { return tbl->lastShuff+a*(tbl->nmax+1)+t; } 17 | 18 | static int maxDepth(int nmax) { return nmax>=2?1+maxDepth((nmax+1)/2):1; } 19 | static long long linearCost(int a,int t) 20 | { return 1LL*a*t*(t+1)/2; } 21 | 22 | QroramTable* qroramTable(int nmax) 23 | { 24 | int amax = maxDepth(nmax)+1; 25 | QroramTable *tbl = malloc(sizeof(*tbl)); 26 | tbl->cost=malloc((nmax+1)*(amax+1)*sizeof(long long)); 27 | tbl->lastShuff=malloc((nmax+1)*(amax+1)*sizeof(int)); 28 | tbl->nmax=nmax; 29 | tbl->amax=amax; 30 | int d,a,t,t2; 31 | 32 | // Waksman network costs 33 | int *shuffleCost = malloc((1+nmax)*sizeof(int)); 34 | tbl->shuffleCost=shuffleCost; 35 | shuffleCost[0]=shuffleCost[1]=0; 36 | for(t=2;t<=nmax;++t) shuffleCost[t]=t-1+shuffleCost[t/2]+shuffleCost[(t+1)/2]; 37 | 38 | // Initialize main table 39 | for(a=1;a<=amax;++a) 40 | for(t=0;t*a<=nmax;t++) 41 | { *cost(tbl,a,t) = linearCost(a,t); 42 | *lastShuff(tbl,a,t) = -1; 43 | } 44 | for(d=1;d<=amax;++d) 45 | for(a=1;a<=amax-d;++a) 46 | for(t=1;t*a<=nmax;++t) 47 | { int lo=0,hi=t; 48 | if(t>1 && *lastShuff(tbl,a,t-1)>=0) 49 | { int windowmid = *lastShuff(tbl,a,t-1); 50 | if(lowindowmid+2) hi=windowmid+2; 52 | } 53 | for(t2=lo;t20) 54 | { int tnext=t-t2; 55 | if(tnext*(a+1)>nmax||t2*acost); 69 | free(tbl->lastShuff); 70 | free(tbl->shuffleCost); 71 | free(tbl); 72 | } 73 | 74 | int qroramBestPeriod(QroramTable* tbl,int n) 75 | { 76 | double c=n; 77 | int p=-1,i; 78 | for(i=1;i<=n;++i) 79 | { double c2=(tbl->shuffleCost[n]+*cost(tbl,1,i))*1.0/i; 80 | if(c2amax;++a) 88 | { printf("%d:",a); 89 | for(t=0;t*a<=tbl->nmax;++t) 90 | printf(" %d",*lastShuff(tbl,a,t)); 91 | printf("\n"); 92 | } 93 | } 94 | typedef struct { int t,a; } pair; 95 | static int cmpByT(const void* va,const void* vb) 96 | { return ((const pair*)va)->t-((const pair*)vb)->t; } 97 | 98 | int qroramShuffTimes_aux(QroramTable* tbl,pair p[],int a,int t) 99 | { 100 | int rv=0,i; 101 | while(t>0) 102 | { int t2=*lastShuff(tbl,a,t); 103 | if(t2<0) break; 104 | int nestC = qroramShuffTimes_aux(tbl,p+rv,a+1,t-t2); 105 | for(i=0;i either the correct element 148 | // or a previously unread new element. 149 | 150 | // On access to a layer, we either: 151 | // 1) Access the real element if it is in this layer and unused 152 | // 2) Access a random element of the ones unused 153 | // Reveal the one that is accessed, and publicly mark it as being used. 154 | -------------------------------------------------------------------------------- /oram/qroram/qroram.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // I don't think this file is used anymore TODO delete me 3 | typedef struct QroramTable QroramTable; 4 | 5 | QroramTable* qroramTable(int nmax); 6 | void qroramTableRelease(QroramTable* tbl); 7 | int qroramBestPeriod(QroramTable* tbl,int n); 8 | void qroramDebugInfo(QroramTable* tbl); 9 | int qroramShuffTimes(QroramTable* tbl,int** outT,int** outA,int n); 10 | -------------------------------------------------------------------------------- /oram/qroram/qroram.oc: -------------------------------------------------------------------------------- 1 | // Implements a silly 4-block ORAM that improves over linear scan by at most 2 | // 10%. Used only as a stepping-stone, till we implement a full-blown n-block 3 | // one, which has more moving parts. 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include"qroram.oh" 9 | #include"shuffle.oh" 10 | 11 | struct OcFourBlock 12 | { 13 | OcCopy* cpy; 14 | obliv int *shuffi,*stashi; 15 | void* shuff; 16 | void* stash; 17 | obliv int* pos; 18 | obliv bool* used; 19 | bool* usedShuff; 20 | int time,period; 21 | BCipherRandomGen* gen; 22 | }; 23 | 24 | static void* element(OcCopy* cpy,void* arr,int x) obliv 25 | { return x*cpy->eltsize+(char*)arr; } 26 | 27 | // Shuffles stash and stores it into "shuff". Stash gets "emptied" 28 | // By resetting 'time' to 0, and used to all false. Finally, 29 | // 'pos' gets initialized according to the shuffle permutation. 30 | static void ocFourBlockShuffle(OcFourBlock* ram) 31 | { 32 | int i,j=0; 33 | // Copy stash elements into the empty slots of shuff 34 | for(i=0;i<4;++i) if(ram->usedShuff[i]) 35 | { ram->shuffi[i]=ram->stashi[j]; 36 | ocCopy(ram->cpy,element(ram->cpy,ram->shuff,i), 37 | element(ram->cpy,ram->stash,j)); 38 | j++; 39 | } 40 | // Shuffle data 41 | OcPermNetwork w = ocPermNetworkRandom(4); 42 | ocPermNetworkHalfApply(&w,ram->cpy,ram->shuff); 43 | ocPermNetworkHalfApply(&w,&ocCopyInt,ram->shuffi); 44 | ocPermInverseAssumingPerm(&w,ram->pos,ram->shuffi); 45 | ocPermNetworkCleanup(&w); 46 | 47 | for(i=0;i<4;++i) 48 | { ram->used[i]=false; 49 | ram->usedShuff[i]=false; 50 | ram->pos[i]&=3; 51 | } 52 | ram->time=0; 53 | } 54 | 55 | OcFourBlock* ocFourBlockNew(OcCopy* cpy,void* data) 56 | { 57 | assert(*((char*)ocCurrentProto()->extra)==OC_PD_TYPE_YAO); 58 | OcFourBlock* ram = malloc(sizeof(*ram)); 59 | ram->cpy=cpy; 60 | ram->shuff = malloc(cpy->eltsize*4); 61 | ocCopyN(cpy,ram->shuff,data,4); 62 | ram->stash = malloc(cpy->eltsize*4); 63 | ram->pos = calloc(4,sizeof(obliv int)); 64 | ram->used = calloc(4,sizeof(obliv bool)); 65 | ram->usedShuff = calloc(4,sizeof(bool)); 66 | ram->shuffi = calloc(4,sizeof(obliv int)); 67 | ram->stashi = calloc(4,sizeof(obliv int)); 68 | for(int i=0;i<4;++i) ram->shuffi[i]=ram->stashi[i]=i; 69 | ram->gen=newBCipherRandomGen(); 70 | ram->period=3; 71 | ram->time=0; 72 | ocFourBlockShuffle(ram); 73 | return ram; 74 | } 75 | void ocFourBlockRelease(OcFourBlock* ram) 76 | { 77 | free(ram->usedShuff); 78 | free(ram->used); 79 | free(ram->pos); 80 | free(ram->stash); 81 | free(ram->shuff); 82 | free(ram->stashi); free(ram->shuffi); 83 | releaseBCipherRandomGen(ram->gen); 84 | free(ram); 85 | } 86 | 87 | void ocFourBlockAccess(OcFourBlock* ram,obliv int index,bool doRead,void* data) 88 | { 89 | int i,ppos; 90 | obliv int unusedIndex,unusedPos,itPos; 91 | obliv bool itUsed; 92 | index&=3; 93 | // Pick an element to read out 94 | for(i=0;i<4;++i) 95 | { obliv if(i==index) 96 | { itUsed=ram->used[i]; 97 | itPos=ram->pos[i]; 98 | } 99 | obliv if(!ram->used[i]) 100 | { unusedPos=ram->pos[i]; 101 | unusedIndex=i; 102 | } 103 | } 104 | obliv if(!itUsed) 105 | { unusedPos=itPos; 106 | unusedIndex=index; 107 | } 108 | revealOblivInt(&ppos,unusedPos,0); 109 | ram->usedShuff[ppos]=true; 110 | ocCopy(ram->cpy,element(ram->cpy,ram->stash,ram->time), 111 | element(ram->cpy,ram->shuff,ppos)); 112 | ram->stashi[ram->time]=ram->shuffi[ppos]; 113 | // Update index 114 | for(i=0;i<4;++i) 115 | { obliv if(i==unusedIndex) 116 | { ram->used[i]=true; 117 | ram->pos[i]=ram->time; 118 | } 119 | } 120 | ram->time++; 121 | for(i=0;itime;++i) obliv if(ram->stashi[i]==index) 122 | { if(doRead) ocCopy(ram->cpy,data,element(ram->cpy,ram->stash,i)); 123 | else ocCopy(ram->cpy,element(ram->cpy,ram->stash,i),data); 124 | } 125 | if(ram->time==3) ocFourBlockShuffle(ram); 126 | } 127 | 128 | void ocFourBlockRead(OcFourBlock* ram,obliv int index,void* data) 129 | { ocFourBlockAccess(ram,index,true,data); } 130 | void ocFourBlockWrite(OcFourBlock* ram,obliv int index,const void* data) 131 | { ocFourBlockAccess(ram,index,false,data); } 132 | -------------------------------------------------------------------------------- /oram/qroram/qroram.oh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include"copy.oh" 3 | 4 | typedef struct OcFourBlock OcFourBlock; 5 | 6 | OcFourBlock* ocFourBlockNew(OcCopy* cpy,void * data); 7 | void ocFourBlockRelease(OcFourBlock* ram); 8 | void ocFourBlockRead(OcFourBlock* ram,obliv int index,void* data); 9 | void ocFourBlockWrite(OcFourBlock* ram,obliv int index,const void* data); 10 | -------------------------------------------------------------------------------- /oram/qroram/testPropagate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include"testPropagate.h" 5 | #include"util.h" 6 | 7 | void showUsage() 8 | { 9 | fprintf(stderr, 10 | "Usage: ./testPropagate -- (.|-num|num)*\n" 11 | " ./testPropagate \n"); 12 | exit(1); 13 | } 14 | 15 | int intCmp(const void* a, const void* b) 16 | { return *(const int*)a-*(const int*)b; } 17 | void initArrays(int** dataCopy,bool** hasdata,bool** haserase, 18 | int* data,size_t n) 19 | { 20 | *dataCopy=malloc(n*sizeof(int)); 21 | *hasdata = calloc(n,sizeof(bool)); 22 | *haserase = calloc(n,sizeof(bool)); 23 | memcpy(*dataCopy,data,n*(sizeof(int))); 24 | qsort(*dataCopy,n,sizeof(int),intCmp); 25 | } 26 | bool recordArrayCheck(const int dataCopy[],bool hasdata[],bool haserase[], 27 | size_t n,int data,bool isdata,bool iserase) 28 | { 29 | if(!isdata && !iserase) return true; 30 | size_t i = (const int*)bsearch(&data,dataCopy,n,sizeof(int),intCmp)-dataCopy; 31 | if(iserase) // can't have duplicates 32 | { if(haserase[i]) return false; 33 | else haserase[i]=true; 34 | }else 35 | { if(hasdata[i]) return false; 36 | else hasdata[i]=true; 37 | } 38 | return true; 39 | } 40 | bool resultCheckArray(const int dataCopy[], 41 | bool hasdata[],bool haserase[], 42 | size_t n,int data,bool isdata,bool iserase) 43 | { 44 | if(!isdata && !iserase) return true; 45 | size_t i = (const int*)bsearch(&data,dataCopy,n,sizeof(int),intCmp)-dataCopy; 46 | if(hasdata[i]==haserase[i]) return false; // Should have cancelled out 47 | if(haserase[i]!=iserase) return false; // Conflicting with input data 48 | hasdata[i]=haserase[i]=false; // Don't want new duplicates 49 | return true; 50 | } 51 | void cleanupArray(int dataCopy[],bool hasdata[],bool haserase[]) 52 | { free(dataCopy); free(hasdata); free(haserase); } 53 | 54 | int main(int argc,char* argv[]) 55 | { 56 | PropagateArgs args; 57 | size_t n,i; 58 | if(argc<3) showUsage(); 59 | int me = strcmp(argv[1],"--")==0?1:2; 60 | int *dataCopy; 61 | bool *hasdata,*haserase; 62 | if(me==1) 63 | { args.n=n=argc-3; 64 | args.data=malloc(n*sizeof(int)); 65 | args.isdata=calloc(n,sizeof(bool)); 66 | args.iserase=calloc(n,sizeof(bool)); 67 | for(i=0;i 4 | 5 | void testPropagate(void* vargs) 6 | { 7 | PropagateArgs* args = vargs; 8 | size_t n = ocBroadcastInt(args->n,1), 9 | outBlank = ocBroadcastInt(args->outBlank,2), 10 | outData = ocBroadcastInt(args->outData,2); 11 | obliv int *data = calloc(n,sizeof(obliv int)); 12 | obliv bool *isdata = calloc(n,sizeof(obliv bool)), 13 | *iserase = calloc(n,sizeof(obliv bool)); 14 | feedOblivIntArray(data,args->data,n,1); 15 | feedOblivBoolArray(isdata,args->isdata,n,1); 16 | feedOblivBoolArray(iserase,args->iserase,n,1); 17 | eraseSetPropagate(&ocCmpInt,data,n,isdata,iserase,outData,outBlank); 18 | if(ocCurrentParty()==2) 19 | { args->data = malloc(n*sizeof(int)); 20 | args->isdata = malloc(n*sizeof(bool)); 21 | args->iserase = malloc(n*sizeof(bool)); 22 | } 23 | for(size_t i=0;idata+i,data[i],0); 25 | revealOblivBool(args->isdata+i,isdata[i],0); 26 | revealOblivBool(args->iserase+i,iserase[i],0); 27 | } 28 | args->n=n; 29 | args->outBlank=outBlank; 30 | args->outData=outData; 31 | free(data); 32 | free(isdata); 33 | free(iserase); 34 | } 35 | -------------------------------------------------------------------------------- /oram/qroram/testQrShuffleTime.c: -------------------------------------------------------------------------------- 1 | #include"qroram.h" 2 | #include 3 | #include 4 | 5 | int main(int argc,char* argv[]) 6 | { 7 | int size; 8 | if(argc<2 || sscanf(argv[1],"%d",&size)!=1) 9 | { fprintf(stderr,"Usage: %s \n",argv[0]); 10 | return 1; 11 | } 12 | QroramTable* tbl = qroramTable(size); 13 | int *schedT,*schedD; 14 | int i,schedSize = qroramShuffTimes(tbl,&schedT,&schedD,size); 15 | for(i=0;i 3 | #include 4 | 5 | void stormOut(const char* myname) 6 | { 7 | fprintf(stderr,"Usage: %s \n",myname); 8 | exit(1); 9 | } 10 | 11 | int parseParams(int** sizes,int argc,char* argv[]) 12 | { 13 | int i,rv=argc-1; 14 | *sizes=malloc(sizeof(int)*rv); 15 | for(i=0;i 2 | #include 3 | #include"shuffle.oh" 4 | #include 5 | #include 6 | #include 7 | #include"copy.oh" 8 | #include"waksman.h" 9 | #include 10 | 11 | static unsigned* randomPermutation(size_t n) 12 | { 13 | BCipherRandomGen* gen = newBCipherRandomGen(); 14 | unsigned* rv = malloc(n*sizeof*rv); 15 | bcRandomPermutation(gen,rv,n); 16 | releaseBCipherRandomGen(gen); 17 | return rv; 18 | } 19 | 20 | static void applyNetwork_2way(OcCopy* cpy,void* data, 21 | const unsigned a[], const unsigned b[], 22 | const obliv bool c[],size_t n,size_t sc, 23 | const size_t lsize[],size_t lc,bool forw) 24 | { 25 | int l,l_,i,off=forw?0:sc; 26 | size_t elt = cpy->eltsize; 27 | char *opt0 = calloc((n/2)*elt,1); 28 | char *opt1 = calloc((n/2)*elt,1); 29 | char *scratch = calloc((n/2)*elt,1); 30 | for(l_=0;l_eltsize; 70 | int me = ocCurrentParty(); 71 | ProtocolDesc* pd = ocCurrentProto(); 72 | YaoEHalfSwapper sw; 73 | if(controlparty==2) sw = yaoEHalfSwapSetup(pd,c,sc); 74 | for(i=0;iperm_share); 87 | free(w->a); free(w->b); 88 | free(w->oc1); free(w->oc2); 89 | free(w->level_size); 90 | free(w->c); 91 | if(w->cpy) ocCopyRelease(w->cpy); 92 | } 93 | 94 | void ocPermNetworkFeedControls(OcPermNetwork* w) 95 | { 96 | if(w->oc1) return; // already initialized 97 | obliv bool *oc1 = calloc(w->sc,sizeof*oc1), *oc2 = calloc(w->sc,sizeof*oc2); 98 | feedOblivBoolArray(oc1,w->c,w->sc,1); 99 | feedOblivBoolArray(oc2,w->c,w->sc,2); 100 | w->oc1=oc1; w->oc2=oc2; 101 | } 102 | 103 | OcPermNetwork ocPermNetworkRandom(size_t n) 104 | { 105 | size_t sc = waksmanSwapCount(n), lc = waksmanStrataCount(n); 106 | unsigned *a = malloc(sc*sizeof*a), *b = malloc(sc*sizeof*b); 107 | bool* c = malloc(sc*sizeof*c); 108 | unsigned *perm_share = randomPermutation(n); 109 | size_t *level_size = malloc(lc*sizeof*level_size); 110 | waksmanNetwork(a,b,n); 111 | waksmanSwitches(perm_share,n,c); 112 | waksmanStratify(a,b,c,n,level_size); 113 | 114 | OcPermNetwork rv = { 115 | .perm_share = perm_share, .a = a, .b = b, .oc1 = NULL, .oc2 = NULL, .n = n, 116 | .sc = sc, .level_size = level_size, .lc = lc, .cpy = NULL, .c=c 117 | }; 118 | return rv; 119 | } 120 | 121 | void ocPermNetwork_xorinit(OcPermNetwork* w) 122 | { 123 | if(!w->cpy) 124 | w->cpy = ocShareCopyNew(ocCurrentProto(),w->n,sizeof(OcSharedInt)); 125 | } 126 | // Writes out the combined permutation in an array 127 | void ocPermNetworkPerm(OcPermNetwork* w,obliv int perm[]) 128 | { 129 | feedOblivIntArray(perm,w->perm_share,w->n,1); 130 | applyNetwork(&ocCopyInt,perm,w->a,w->b,w->oc2,w->n,w->sc, 131 | w->level_size,w->lc); 132 | } 133 | void ocPermNetworkPerm_xorShare(OcPermNetwork* w,OcSharedInt perm[]) 134 | { 135 | ocPermNetwork_xorinit(w); 136 | ocFeedSharedIntN(perm,w->perm_share,w->n,1); 137 | applyNetwork(w->cpy,perm,w->a,w->b,w->oc2,w->n,w->sc, 138 | w->level_size,w->lc); 139 | } 140 | void ocPermNetworkPermInv_impl(const OcPermNetwork* w,void* perm,bool isyao) 141 | { 142 | unsigned *inv,i; 143 | size_t n=w->n; 144 | // Compute permutation inverse 145 | if(ocCurrentParty()==2) 146 | { inv = malloc(n*sizeof*inv); 147 | for(i=0;iperm_share[i]]=i; 148 | } 149 | OcCopy* cpy = &ocCopyInt; 150 | if(isyao) feedOblivIntArray(perm,inv,n,2); 151 | else 152 | { ocFeedSharedIntN(perm,inv,n,2); 153 | ocPermNetwork_xorinit(w); 154 | cpy = w->cpy; 155 | } 156 | ocPermNetworkFeedControls(w); 157 | unapplyNetwork(cpy,perm,w->a,w->b,w->oc1,n,w->sc, 158 | w->level_size,w->lc); 159 | if(ocCurrentParty()==2) free(inv); 160 | } 161 | void ocPermNetworkPermInv(const OcPermNetwork* w,obliv int perm[]) 162 | { ocPermNetworkPermInv_impl(w,perm,true); } 163 | 164 | void ocPermNetworkApply(const OcPermNetwork* w, OcCopy* cpy, void* data) 165 | { 166 | ocPermNetworkFeedControls(w); 167 | applyNetwork(cpy,data,w->a,w->b,w->oc1,w->n,w->sc,w->level_size,w->lc); 168 | applyNetwork(cpy,data,w->a,w->b,w->oc2,w->n,w->sc,w->level_size,w->lc); 169 | } 170 | void ocPermNetworkUnapply(const OcPermNetwork* w, OcCopy* cpy, void* data) 171 | { 172 | ocPermNetworkFeedControls(w); 173 | unapplyNetwork(cpy,data,w->a,w->b,w->oc2,w->n,w->sc,w->level_size,w->lc); 174 | unapplyNetwork(cpy,data,w->a,w->b,w->oc1,w->n,w->sc,w->level_size,w->lc); 175 | } 176 | void ocPermNetworkHalfApply(const OcPermNetwork* w, OcCopy* cpy, void* data) 177 | { 178 | assert(*((char*)ocCurrentProto()->extra)==OC_PD_TYPE_YAO); 179 | applyNetworkHalf(cpy,data,w->a,w->b,w->c,w->n,w->sc,1); 180 | applyNetworkHalf(cpy,data,w->a,w->b,w->c,w->n,w->sc,2); 181 | } 182 | // Two parties jointly shuffle the data, with the resultant 183 | // permutation being written into perm_out. perm_out[] should be of length 184 | // at least n. Does O(log n) invocations of ocCopyCondN(), each of size ~ n/2 185 | // Also calls oCopy O(n log n) times, but only unconditionally 186 | // perm_out should be of size n*elt, where elt is the size of an obliv int or 187 | // OcSharedInt, depending on the value of isyao 188 | void ocShuffleData(const OcCopy* cpy,void* data,size_t n, 189 | void* perm_out,bool isyao) 190 | { 191 | OcPermNetwork w = ocPermNetworkRandom(n); 192 | ocPermNetworkApply(&w,cpy,data); 193 | if(!perm_out); // do nothing 194 | ocPermNetworkPermInv_impl(&w,perm_out,isyao); 195 | ocPermNetworkCleanup(&w); 196 | } 197 | 198 | //int bitcount(int x) { return x<=1?1:1+bitcount(x/2); } 199 | int bitcount(int n) { return n>1?1+bitcount((n+1)/2):0; } 200 | 201 | /* 202 | // Debugging code 203 | void problemPerm(size_t n,const int plain[]) 204 | { for(size_t i=0;in; 229 | int mask = (1<sc,sizeof(obliv bool)); 233 | unsigned *perm_share,*share_inverse=NULL; 234 | // TODO avoid reinitializing here, reuse from w. We need a and b to stratify c 235 | // Ugly function. Major refactoring necessary. 236 | unsigned *a = malloc(w->sc*sizeof*a), *b = malloc(w->sc*sizeof*b); 237 | c=malloc(w->sc*sizeof(bool)); 238 | 239 | if(ocCurrentParty()==1) 240 | { perm_share = randomPermutation(n); 241 | share_inverse = malloc(n*sizeof(unsigned)); 242 | for(i=0;ilevel_size); 246 | memcpy(inv,perm,sizeof(obliv int)*n); 247 | for(i=0;isc,1); 249 | for(i=0;isc,2); 254 | free(perm_share); 255 | free(share_inverse); 256 | }else 257 | { perm_share = calloc(n,sizeof(unsigned)); 258 | share_inverse = malloc(n*sizeof(unsigned)); // XXX 259 | waksmanNetwork(a,b,n); 260 | waksmanStratify(a,b,NULL,n,w->level_size); 261 | memcpy(inv,perm,sizeof(obliv int)*n); 262 | for(i=0;isc,1); 264 | for(i=0;ilevel_size); 269 | feedOblivIntArray(inv,NULL,n,1); 270 | for(i=0;isc,2); 273 | free(perm_share); 274 | free(share_inverse); 275 | } 276 | free(a); free(b); free(c); free(oc); 277 | } 278 | -------------------------------------------------------------------------------- /oram/shuffle.oh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include"copy.oh" 3 | 4 | // Utilities used for implementing variants of ocShuffleData 5 | typedef struct OcPermNetwork 6 | { 7 | unsigned* perm_share; 8 | unsigned *a,*b; 9 | obliv bool *oc1,*oc2; 10 | bool *c; 11 | size_t n,sc,lc,*level_size; 12 | OcCopy* cpy; 13 | }OcPermNetwork; 14 | 15 | void ocPermNetworkCleanup(OcPermNetwork* w); 16 | OcPermNetwork ocPermNetworkRandom(size_t n); 17 | void ocPermNetworkPerm(OcPermNetwork* w,obliv int perm[]); 18 | void ocPermNetworkPermInv(const OcPermNetwork* w,obliv int perm[]); 19 | void ocPermNetworkApply(const OcPermNetwork* w, OcCopy* cpy, void* data); 20 | void ocPermNetworkUnapply(const OcPermNetwork* w, OcCopy* cpy, void* data); 21 | void ocPermNetworkHalfApply(const OcPermNetwork* w, OcCopy* cpy, void* data); 22 | void ocShuffleData(const OcCopy* cpy,void* data,size_t n, 23 | void* perm_out,bool isyao); 24 | 25 | // Finds inverse of a given permutation, of the same size as the one 26 | // used in w. TODO We can reuse much of the initialization machinery. 27 | // Assumes that input is actually a permutation: insecure otherwise! 28 | void ocPermInverseAssumingPerm(const OcPermNetwork* w, 29 | obliv int inv[],const obliv int perm[]); 30 | -------------------------------------------------------------------------------- /oram/sort.c: -------------------------------------------------------------------------------- 1 | #include"sort.h" 2 | 3 | // Copied and modified from the Obliv-C source repository. 4 | // Uses indices rather than actual data in cmpswap, since we are working on 5 | // multiple arrays quite frequently. 6 | void batcherSwap(void* data, 7 | size_t step,size_t st,size_t en, 8 | void (*cmpswap)(void*,size_t,size_t)) 9 | { 10 | size_t i; 11 | for(i=st;i+step 3 | 4 | // Sorts the part of data between indices [st,en) 5 | // Uses cmpswap(data,i,j) to compare and swap data elements i and j 6 | void batcherSort(void* data,size_t st,size_t en, 7 | void (*cmpswap)(void*,size_t,size_t)); 8 | -------------------------------------------------------------------------------- /oram/sort.oc: -------------------------------------------------------------------------------- 1 | #include"sort.oh" 2 | 3 | /* Definition for: 4 | ocCmpBool, ocCmpShort, ocCmpInt, ocCmpLong, ocCmpLLong, ocCmpSizeT*/ 5 | #define DEFINE_OC_CMP(Type,type) \ 6 | obliv bool ocCmpLtt##Type \ 7 | (OcCmp* cmp,const void* va,const void* vb, \ 8 | obliv bool chain) obliv \ 9 | { \ 10 | ~obliv() \ 11 | { obliv type x = *(const obliv type*)va; \ 12 | obliv bool res; \ 13 | /* Obliv-C Magic built-in */ \ 14 | __obliv_c__setBitsSub(&x,&res,&x,vb,&chain,ocBitSize(obliv type)); \ 15 | return res; \ 16 | } \ 17 | } \ 18 | obliv bool ocCmpEq##Type (OcCmp* cmp, const void* va, const void* vb) obliv \ 19 | { return *(const obliv type*)va == *(const obliv type*)vb; } \ 20 | OcCmp ocCmp##Type = \ 21 | { .cpy = &ocCopy##Type, \ 22 | .lessThanTie = ocCmpLtt##Type, \ 23 | .equal = ocCmpEq##Type \ 24 | }; 25 | 26 | DEFINE_OC_CMP(Bool,bool) 27 | DEFINE_OC_CMP(Short,short) 28 | DEFINE_OC_CMP(Int,int) 29 | DEFINE_OC_CMP(Long,long) 30 | DEFINE_OC_CMP(LLong,long) 31 | DEFINE_OC_CMP(SizeT,size_t) 32 | -------------------------------------------------------------------------------- /oram/sort.oh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include"sort.h" 3 | #include"copy.oh" 4 | 5 | typedef frozen struct OcCmp OcCmp; 6 | 7 | struct OcCmp 8 | { OcCopy* cpy; 9 | obliv bool (*lessThanTie)(OcCmp*,const void*, const void*, obliv bool) obliv; 10 | obliv bool (*equal)(OcCmp*,const void*, const void*) obliv; 11 | }; 12 | 13 | // Less than comparison. Takes in custom comparator. 14 | static inline obliv bool 15 | ocLessThan(OcCmp* cmp, const void* a, const void* b) obliv 16 | { return cmp->lessThanTie(cmp,a,b,false); } 17 | static inline obliv bool 18 | ocEqual(OcCmp* cmp, const void* a, const void* b) obliv 19 | { return cmp->equal(cmp,a,b); } 20 | 21 | /* 22 | Less than comparison with specified equality result. 23 | In effect, this can be either a "less than" or "less than or equal", 24 | depending on the value of 'eq'. For obliv comparisons, it is useful 25 | for cheaply tying multiple comparisons together. For example, if we are 26 | trying to compare structs such as 27 | struct Triple { obliv int x,y,z; } p,q; 28 | We can compare such as this: 29 | obliv bool chain = false; 30 | chain = ocLessThanTie(cmpInt,p.z,q.z,chain); 31 | chain = ocLessThanTie(cmpInt,p.y,q.y,chain); 32 | chain = ocLessThanTie(cmpInt,p.x,q.x,chain); 33 | return chain; 34 | This will perform comparison based on .x, break ties with .y, and use .z as 35 | the final tiebreaker. 36 | */ 37 | static inline obliv bool 38 | ocLessThanTie(OcCmp* cmp, const void* a, const void* b, obliv bool eq) obliv 39 | { return cmp->lessThanTie(cmp,a,b,eq); } 40 | 41 | 42 | extern OcCmp ocCmpBool, ocCmpShort, ocCmpInt, ocCmmpLong, ocCmpLLong, ocCmpSizeT; 43 | -------------------------------------------------------------------------------- /oram/sqrtoram.oc: -------------------------------------------------------------------------------- 1 | // Implements a silly 4-block ORAM that improves over linear scan by at most 2 | // 10%. Used only as a stepping-stone, till we implement a full-blown n-block 3 | // one, which has more moving parts. 4 | #include 5 | #include 6 | #include 7 | #include"waksman.h" 8 | #include 9 | #include 10 | #include"decoder.oh" 11 | #include"sqrtoram.oh" 12 | #include"shuffle.oh" 13 | 14 | /* Positionmaps export the following interface: 15 | They store logical->physical index mapping, as well as a "used" flag 16 | for each index. Used are all initialized to false. 17 | getPos(obliv int logicalIndex,obliv bool fake) 18 | --> int physicalIndex of some unused element. If "fake" is true, 19 | this will be a uniformly randomly selected unused index. Otherwise, 20 | it will be the one corresponding to logicalIndex. In either case, 21 | the returned entry is now marked "used", and will no longer be 22 | returned. Note: secret logical index may not be random. Physical 23 | index is uniformly random. 24 | It is an error to ask for an index (with fake==false) when the 25 | corresponding entry has already been used. 26 | callsRemaining --> int says how many getPos() calls are allowed before we 27 | run out of unused elements. 28 | reinitialize(obliv int physical[]) --> O(n log n) shuffle, everything 29 | reinitialized. Everybody also gets new physical indices as specified. 30 | It is assumed that physical is a uniformly randomly selected 31 | secret permutation of [0,n). 32 | */ 33 | 34 | // Todo: Cube-root, when we implement it, will have to return two indices with 35 | // getPos. May also have different levels of reinitialize. 36 | typedef struct SqrtPosMap 37 | { 38 | void* data; 39 | int n; 40 | int (*getPos)(struct SqrtPosMap*,obliv int,obliv bool); 41 | int callsRemaining; 42 | void (*reinitialize)(struct SqrtPosMap*,obliv int*); 43 | void (*release)(struct SqrtPosMap*); 44 | } SqrtPosMap; 45 | 46 | // Linear scan maps 47 | typedef struct SqrtPosMapLinear 48 | { 49 | obliv int *physical; 50 | obliv bool *used,*decoder; 51 | } SqrtPosMapLinear; 52 | 53 | void sqrtPosMapLinearRelease(SqrtPosMap* map) 54 | { 55 | SqrtPosMapLinear* mapdata=map->data; 56 | free(mapdata->physical); 57 | free(mapdata->used); 58 | free(mapdata->decoder); 59 | free(mapdata); 60 | free(map); 61 | } 62 | void sqrtPosMapLinearReinitialize(SqrtPosMap* map,obliv int physical[]) 63 | { 64 | SqrtPosMapLinear* mapdata = map->data; 65 | memcpy(mapdata->physical,physical,map->n*sizeof(obliv int)); 66 | memset(mapdata->used,0,map->n*sizeof(obliv bool)); 67 | map->callsRemaining=map->n; 68 | } 69 | int 70 | sqrtPosMapLinearGetPos(SqrtPosMap* map,obliv int logical,obliv bool fake) 71 | { 72 | SqrtPosMapLinear* mapdata = map->data; 73 | decoderEn(mapdata->decoder,true,logical,map->n); 74 | obliv int result; 75 | obliv bool first=true; 76 | for(int i=0;in;++i) 77 | obliv if((!fake&mapdata->decoder[i]) ^ (fake&!mapdata->used[i]&first)) 78 | { first=false; 79 | mapdata->used[i]=true; 80 | result = mapdata->physical[i]; 81 | } 82 | int res; 83 | revealOblivInt(&res,result,0); 84 | map->callsRemaining--; 85 | return res; 86 | } 87 | 88 | SqrtPosMap* sqrtPosMapLinearNew(obliv int physical[],int n) 89 | { 90 | SqrtPosMap* map = malloc(sizeof*map); 91 | map->n=n; 92 | map->getPos=sqrtPosMapLinearGetPos; 93 | map->callsRemaining=n; 94 | map->reinitialize=sqrtPosMapLinearReinitialize; 95 | map->release=sqrtPosMapLinearRelease; 96 | 97 | SqrtPosMapLinear* mapdata = malloc(sizeof*mapdata); 98 | mapdata->physical=malloc(n*sizeof(physical[0])); 99 | memcpy(mapdata->physical,physical,n*sizeof(physical[0])); 100 | mapdata->used=calloc(n,sizeof(obliv bool)); 101 | mapdata->decoder=calloc(n,sizeof(obliv bool)); 102 | map->data=mapdata; 103 | return map; 104 | } 105 | 106 | struct OcSqrtOram 107 | { 108 | OcOram super; 109 | int packingLog,packing; // packing = (1<super.cpy; } 120 | static inline int oramN(OcSqrtOram* oram) { return oram->super.n; } 121 | 122 | // Forward declarations of OcSqrtOram methods 123 | void ocSqrtOramReinitialize(OcSqrtOram* oram,const void* data); 124 | void ocSqrtOramRelease(OcOram* oram); 125 | OcSqrtOram* ocSqrtOramNew(OcCopy* cpy,const void* data,int n); 126 | OcSqrtOram* ocSqrtOramNewAux(OcCopy* cpy,void* data,int n,int period); 127 | void ocSqrtOramAccess(OcOram* ram, obliv int index,OcOramAccessCb fn, 128 | void* data); 129 | 130 | void sqrtPosMapRecurRelease(SqrtPosMap* map) 131 | { 132 | OcSqrtOram* mapdata = map->data; 133 | free(oramCpy(mapdata)); 134 | ocSqrtOramRelease(CAST(mapdata)); 135 | free(map); 136 | } 137 | void sqrtPosMapRecurReinitialize(SqrtPosMap* map,obliv int physical[]) 138 | { 139 | OcSqrtOram* mapdata = map->data; 140 | // Pre-copying since map->n != mapdata->n * pk 141 | ocCopyN(&ocCopyInt,mapdata->shuff,physical,map->n); 142 | ocSqrtOramReinitialize(mapdata,NULL); 143 | map->callsRemaining = mapdata->period; 144 | } 145 | // Very, very similar to an ordinary ORAM access 146 | int sqrtPosMapRecurGetPos(SqrtPosMap* map,obliv int logical,obliv bool fake) 147 | { 148 | // Each block of this oram holds pk obliv integers. The decoderEn ... for() 149 | // constructs loop through elements inside a single block. 150 | OcSqrtOram* mapdata = map->data; 151 | const int pk = mapdata->packing, pkl = mapdata->packingLog; 152 | // Go through stash for equality 153 | logical&=(1<indexBits+pkl)-1; // assuming indices are within bounds 154 | obliv int msb = (logical>>pkl), lsb = (logical&(pk-1)); 155 | assert(pk<=16); 156 | obliv bool decoder[16]; 157 | int i; 158 | obliv int data; 159 | obliv bool found=fake; 160 | for(i=0;itime;++i) obliv if(mapdata->stashi[i]==msb) 161 | { ~obliv(en) decoderEn(decoder,en,lsb,pk); 162 | found=true; 163 | for(int j=0;jstash)[i*pk+j]; 165 | } 166 | // Recursive step: fake lookup if already found 167 | int lookupIndex = mapdata->pos->getPos(mapdata->pos,msb,found); 168 | mapdata->usedShuff[lookupIndex]=true; 169 | obliv int* fetched = ((obliv int*)mapdata->shuff)+lookupIndex*pk; 170 | obliv if(fake) lsb = 0; 171 | // Decide what to reveal 172 | decoderEn(decoder,fake|!found,lsb,pk); 173 | for(i=0;istash)+mapdata->time*pk,fetched, 178 | pk*sizeof(obliv int)); 179 | mapdata->stashi[mapdata->time] = mapdata->shuffi[lookupIndex]; 180 | mapdata->time++; 181 | 182 | int res; 183 | revealOblivInt(&res,data,0); 184 | return res; 185 | } 186 | SqrtPosMap* sqrtPosMapRecurNew(obliv int physical[],int n,int period) 187 | { 188 | const int pkl = 3; // TODO tweak 189 | const int pk = (1<packingLog = pkl; 202 | oram->packing = pk; 203 | 204 | SqrtPosMap* map = malloc(sizeof*map); 205 | map->data=oram; 206 | map->n = n; 207 | map->callsRemaining = period; 208 | map->getPos = sqrtPosMapRecurGetPos; 209 | map->reinitialize = sqrtPosMapRecurReinitialize; 210 | map->release = sqrtPosMapRecurRelease; 211 | return map; 212 | } 213 | 214 | // --------------- OcSqrtOram ----------------------------------------------- 215 | 216 | 217 | void ocSqrtOramShuffleData(OcSqrtOram* ram) 218 | { 219 | OcPermNetwork w = ocPermNetworkRandom(oramN(ram)); 220 | ocPermNetworkHalfApply(&w,oramCpy(ram),ram->shuff); 221 | ocPermNetworkHalfApply(&w,&ocCopyInt,ram->shuffi); 222 | ocPermInverseAssumingPerm(&w,ram->physicalTemp,ram->shuffi); 223 | for(int i=0;iphysicalTemp[i]&=(1<indexBits)-1; 224 | ocPermNetworkCleanup(&w); 225 | } 226 | 227 | // Shuffles stash and stores it into "shuff". Stash gets "emptied" 228 | // by resetting 'time' to 0, and used to all false. Finally, 229 | // 'pos' gets initialized according to the shuffle permutation. 230 | void ocSqrtOramRefresh(OcSqrtOram* ram) 231 | { 232 | int i,j=0; 233 | // Copy stash elements into the empty slots of shuff 234 | for(i=0;iusedShuff[i]) 235 | { ram->shuffi[i]=ram->stashi[j]; 236 | ocCopy(oramCpy(ram),ocCopyElt(oramCpy(ram),ram->shuff,i), 237 | ocCopyElt(oramCpy(ram),ram->stash,j)); 238 | j++; 239 | } 240 | ocSqrtOramShuffleData(ram); 241 | ram->pos->reinitialize(ram->pos,ram->physicalTemp); 242 | for(i=0;iusedShuff[i]=false; 243 | ram->time=0; 244 | } 245 | // If data == NULL, this function assumes data already 246 | // resides in ram->shuff 247 | void ocSqrtOramReinitialize(OcSqrtOram* ram,void* data) 248 | { 249 | int i,j=0; 250 | if(data) ocCopyN(oramCpy(ram),ram->shuff,data,oramN(ram)); 251 | for(i=0;ishuffi[i]=i; 252 | ocSqrtOramShuffleData(ram); 253 | ram->pos->reinitialize(ram->pos,ram->physicalTemp); 254 | for(i=0;iusedShuff[i]=false; 255 | ram->time=0; 256 | } 257 | 258 | int indexBits(int n) { return n>1?1+indexBits((n+1)/2):0; } 259 | 260 | OcSqrtOram* ocSqrtOramNewAux(OcCopy* cpy,void* data,int n,int period) 261 | { 262 | assert(*((char*)ocCurrentProto()->extra)==OC_PD_TYPE_YAO); 263 | OcSqrtOram* ram = malloc(sizeof*ram); 264 | ram->super.n=n; 265 | ram->super.cpy=cpy; 266 | ram->super.access=ocSqrtOramAccess; 267 | ram->super.release=ocSqrtOramRelease; 268 | ram->shuff = malloc(cpy->eltsize*n); 269 | ocCopyN(cpy,ram->shuff,data,n); 270 | int i; 271 | ram->stash = malloc(cpy->eltsize*period); 272 | ram->shuffi = calloc(n,sizeof(obliv int)); 273 | ram->stashi = calloc(period,sizeof(obliv int)); 274 | for(i=0;ishuffi[i]=i; 275 | ram->physicalTemp = calloc(n,sizeof(obliv int)); 276 | ram->indexBits = indexBits(n); 277 | ocSqrtOramShuffleData(ram); 278 | ram->pos = sqrtPosMapRecurNew(ram->physicalTemp,n,period); 279 | ram->usedShuff = calloc(n,sizeof(bool)); 280 | ram->period=period; 281 | ram->time=0; 282 | return ram; 283 | } 284 | 285 | OcSqrtOram* ocSqrtOramNew(OcCopy* cpy,void* data,int n) 286 | { int period = (int)(1e-7+ceil(sqrt(waksmanSwapCount(n)))); 287 | return ocSqrtOramNewAux(cpy,data,n,period); 288 | } 289 | 290 | void ocSqrtOramRelease(OcOram* ramsuper) 291 | { 292 | OcSqrtOram* ram=CAST(ramsuper); 293 | free(ram->usedShuff); 294 | ram->pos->release(ram->pos); 295 | free(ram->stashi); 296 | free(ram->shuffi); 297 | free(ram->stash); 298 | free(ram->shuff); 299 | free(ram->physicalTemp); 300 | free(ram); 301 | } 302 | 303 | void ocSqrtOramAccess(OcOram* ramsuper, obliv int index, 304 | OcOramAccessCb fn,void* data) obliv 305 | { 306 | OcSqrtOram* ram = CAST(ramsuper); 307 | ~obliv(en) { 308 | int i; 309 | obliv bool found=false; 310 | OcCopy *cpy = oramCpy(ram); 311 | // Scan through stash 312 | for(i=0;itime;++i) obliv if(index==ram->stashi[i]) 313 | { obliv if(en) fn(ram,ocCopyElt(cpy,ram->stash,i),data); 314 | found=true; 315 | } 316 | 317 | // Fake/unfake posmap lookup 318 | int lookupIndex = ram->pos->getPos(ram->pos,index,found|!en); 319 | // Access one more element from shuffled array 320 | ocCopy(oramCpy(ram),ocCopyElt(oramCpy(ram),ram->stash,ram->time), 321 | ocCopyElt(oramCpy(ram),ram->shuff,lookupIndex)); 322 | ram->usedShuff[lookupIndex]=true; 323 | ram->stashi[ram->time]=ram->shuffi[lookupIndex]; 324 | obliv if(!found & en) 325 | fn(ram,ocCopyElt(cpy,ram->stash,ram->time),data); 326 | ram->time++; 327 | if(ram->time==ram->period) { 328 | ocSqrtOramRefresh(ram); 329 | } 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /oram/sqrtoram.oh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "oram.oh" 3 | 4 | // All the "useful" functions such as read/write are declared in oram.oh 5 | typedef struct OcSqrtOram OcSqrtOram; 6 | OcSqrtOram* ocSqrtOramNew(OcCopy* cpy,void* data,int n); 7 | -------------------------------------------------------------------------------- /oram/waksman.c: -------------------------------------------------------------------------------- 1 | #include"waksman.h" 2 | #include 3 | #include 4 | 5 | size_t waksmanSwapCount(size_t n) 6 | { 7 | if(n<=1) return 0; 8 | if(n==2) return 1; 9 | return n-1+waksmanSwapCount(n/2)+waksmanSwapCount((n+1)/2); 10 | } 11 | 12 | // Creates network. Output array lengths should be at least 13 | // waksmanSwapCount(n). Returns this size waksmanSwapCount(n) 14 | // If conventions here change, waksmanSwitches must also be changed 15 | size_t waksmanNetwork(unsigned a[],unsigned b[],size_t n) 16 | { 17 | size_t i,j=0,jd; 18 | if(n<=1) return 0; 19 | for(i=0;i i -> 2*i for i in [0,n/2] 25 | jd=waksmanNetwork(a+j,b+j,n/2); 26 | for(i=0;i i -> 2*i+1 for i in [0,n/2] 29 | // n-1 -> n/2 -> n-1 30 | jd=waksmanNetwork(a+j,b+j,(n+1)/2); 31 | for(i=0;i0) if(!set[i]) 64 | { j=i; 65 | do 66 | { unsigned prej=arr[j]; 67 | set[j]=true; 68 | // go from prej to j through lower box 69 | if(prej/2b?a:b; } 102 | // The number of "layers" in the circuit 103 | size_t waksmanStrataCount(size_t n) 104 | { 105 | if(n<=1) return 0; 106 | if(n==2) return 1; 107 | return 2 + max(waksmanStrataCount(n/2),waksmanStrataCount((n+1)/2)); 108 | } 109 | 110 | // The above functions do not produce neat "layers" in the circuit 111 | // This function assigns "levels" to each swap gate, so we know in which order 112 | // to evaluate them. Levels range in [0,waksmanStrataCount(n)) 113 | // Output buffer should be of size waksmanSwapCount(n). 114 | void waksmanStrataAssign(unsigned level[], 115 | const unsigned a[], const unsigned b[], size_t n) 116 | { 117 | int i,sc = waksmanSwapCount(n); 118 | unsigned *dlevel = calloc(n,sizeof(*dlevel)); 119 | memset(level,0,sc*sizeof(*level)); 120 | for(i=0;i 3 | #include 4 | 5 | size_t waksmanSwapCount(size_t n); 6 | size_t waksmanNetwork(unsigned a[],unsigned b[],size_t n); 7 | size_t waksmanSwitches(const unsigned arr[],unsigned n,bool output[]); 8 | 9 | size_t waksmanStrataCount(size_t n); 10 | void waksmanStratify(unsigned a[],unsigned b[],bool switches[], 11 | size_t n,size_t strata_sizes[]); 12 | -------------------------------------------------------------------------------- /test/testOramAccess.c: -------------------------------------------------------------------------------- 1 | #include"testOramAccess.h" 2 | #include"util.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void showUsage(const char* exec) 11 | { 12 | fprintf(stderr,"Usage: %s -- \n" 13 | " or: %s \n" 14 | "Where:\n" 15 | " type - ORAM type, one of 'lin', 'sqrt', 'ckt'\n" 16 | " initial data - either a list of integers\n" 17 | " or --auto=n for autogenerated values\n" 18 | " indices - either a list of positions to access\n" 19 | " or --auto=n for random positions\n", 20 | exec,exec); 21 | exit(1); 22 | } 23 | // Populate the entire array of given size with values in range [0,lim) 24 | void populateArray(int dest[],int size,int lim) 25 | { 26 | int i; 27 | for(i=0;iindices = malloc(accn*sizeof(int)); 34 | else args->content = malloc(n*sizeof(int)); 35 | int i; 36 | for(i=0;iindices[i]=ocBroadcastInt(args->indices[i],2); 37 | for(i=0;icontent[i]=ocBroadcastInt(args->content[i],1); 38 | args->detailedOut = ( ocBroadcastBool(args->detailedOut,1) 39 | && ocBroadcastBool(args->detailedOut,2)); 40 | } 41 | 42 | int main(int argc,char* argv[]) 43 | { 44 | bool autoSize=false,autoAccess=false; 45 | ProtocolDesc pd; 46 | TestOramAccessIO io; 47 | int i,me; 48 | srand(time(0)); 49 | 50 | // Parse parameters 51 | if(argc<5) showUsage(argv[0]); 52 | else if(strcmp(argv[1],"--")==0) 53 | { // Get ORAM size 54 | if(strncmp(argv[4],"--auto=",strlen("--auto="))==0) 55 | { autoSize=true; 56 | if(sscanf(argv[4]+strlen("--auto="),"%d",&io.size)!=1) showUsage(argv[0]); 57 | } 58 | else io.size=argc-4; 59 | // Populate with initial content 60 | io.content=malloc(sizeof(int)*io.size); 61 | if(autoSize) populateArray(io.content,io.size,RAND_MAX); 62 | else for(i=0;i 3 | #include 4 | typedef struct 5 | { int size; 6 | int *content,*indices,*outputs; 7 | OramType type; 8 | bool detailedOut; 9 | } TestOramAccessIO; 10 | 11 | void testOramAccess(void* vargs); 12 | void exchangeInputs(TestOramAccessIO* args,int accn,int n); 13 | -------------------------------------------------------------------------------- /test/testOramAccess.oc: -------------------------------------------------------------------------------- 1 | #include 2 | #include"testOramAccess.h" 3 | #include"sqrtoram.oh" 4 | #include"linearoram.oh" 5 | #include"circuit_oram.oh" 6 | #include"copy.oh" 7 | 8 | void testOramAccess(void* vargs) 9 | { 10 | TestOramAccessIO* args = vargs; 11 | int size = ocBroadcastInt(args->size,2); 12 | int n = ocBroadcastInt(args->size,1); 13 | obliv int* content = calloc(n,sizeof(obliv int)); 14 | obliv int* indices = calloc(size,sizeof(obliv int)); 15 | obliv int output; 16 | feedOblivIntArray(content,args->content,n,1); 17 | feedOblivIntArray(indices,args->indices,size,2); 18 | OcOram* ram; 19 | if(args->type==oramTypeSqrt) ram=(OcOram*)ocSqrtOramNew(&ocCopyInt,content,n); 20 | else if(args->type==oramTypeCkt) 21 | { ram=(OcOram*)ckt_initialize(n,&ocCopyInt); 22 | for(int i=0;ioutputs = malloc(size*sizeof(int)); 26 | for(int i=0;ioutputs+i,output,0); 29 | } 30 | exchangeInputs(args,size,n); 31 | ocOramRelease(ram); 32 | free(indices); 33 | free(content); 34 | args->size=size; // for party 1 35 | } 36 | -------------------------------------------------------------------------------- /test/test_oqueue.c: -------------------------------------------------------------------------------- 1 | #include"test_oqueue.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc,char* argv[]) 9 | { 10 | ProtocolDesc pd; 11 | 12 | if(argc<3) 13 | { 14 | if(argc<2) fprintf(stderr,"Port number missing\n"); 15 | else fprintf(stderr,"Party missing\n"); 16 | fprintf(stderr,"Usage: %s \n",argv[0]); 17 | return 1; 18 | } 19 | 20 | int party = (strcmp(argv[1],"--")==0?1:2); 21 | 22 | connectOrDie(&pd,argv[1],argv[2]); 23 | 24 | setCurrentParty(&pd,party); 25 | 26 | srand(time(0)); 27 | 28 | double lap = wallClock(); 29 | fprintf(stderr,"Executing test: %s\n","oqueue"); 30 | fprintf(stderr,"Role: %s\n", (party==1?"1/Server":"2/Client")); 31 | execYaoProtocol(&pd,testMain,0); 32 | fprintf(stderr,"Total time: %lf s\n",wallClock()-lap); 33 | cleanupProtocol(&pd); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /test/test_oqueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void testMain(void*varg); 4 | -------------------------------------------------------------------------------- /test/test_oqueue.oc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "oqueue.oh" 3 | #include "test_oqueue.h" 4 | #include 5 | 6 | 7 | #define STATUS_SUCCESS "\e[32m[SUCCESS]\e[0m" 8 | #define STATUS_FAILURE "\e[31m[FAILURE]\e[0m" 9 | 10 | void testMain(void*varg) { 11 | 12 | { 13 | 14 | int testEls = 378; 15 | 16 | oqueue * testQueue = oqueue_new_static(&ocCopyInt, testEls); 17 | 18 | bool success = true; 19 | 20 | for (int ii = 0; ii 0) { 135 | testBuffer[testBufferTail] = srnd; 136 | if (testBufferTail < 200) { 137 | testBufferTail ++; 138 | } else { 139 | testBufferTail = 0; 140 | } 141 | otemp = feedOblivInt(srnd, ii % 2 + 1); 142 | opSuccess = oqueue_push(testQueue, &otemp); 143 | revealOblivBool(&tempBool, opSuccess, 0); 144 | if (!tempBool) fprintf(stderr,"FAILURE at %d:3\n", ii); 145 | success &= tempBool; 146 | } else { 147 | thisVal = testBuffer[testBufferHead]; 148 | if (testBufferHead < 200) { 149 | testBufferHead ++; 150 | } else { 151 | testBufferHead = 0; 152 | } 153 | opSuccess = oqueue_pop(&otemp, testQueue); 154 | revealOblivInt(&temp, otemp, 0); 155 | revealOblivBool(&tempBool, opSuccess, 0); 156 | success &= tempBool && (temp == thisVal); 157 | if (!tempBool) fprintf(stderr,"FAILURE at %d:4.1\n", ii); 158 | if (temp != thisVal) fprintf(stderr,"FAILURE at %d:4.2\n", ii); 159 | } 160 | } 161 | } 162 | } 163 | 164 | oqueue_free(testQueue); 165 | 166 | fprintf(stderr, "Test Item: %-70s %s\n", "oqueue - 4000 random operations on empty 200 element queue", (success)?STATUS_SUCCESS:STATUS_FAILURE); 167 | 168 | } 169 | 170 | { 171 | 172 | int testEls = 200; 173 | int testOps = 4000; 174 | 175 | uint32_t testBuffer[201]; 176 | uint32_t testBufferHead = 0; 177 | uint32_t testBufferTail = 0; 178 | 179 | oqueue * testQueue = oqueue_new_static(&ocCopyInt, testEls); 180 | 181 | obliv uint32_t otemp; 182 | obliv bool opSuccess; 183 | bool success = true; 184 | bool tempBool; 185 | uint32_t thisVal; 186 | uint32_t temp; 187 | obliv uint32_t rnd; 188 | uint32_t srnd; 189 | 190 | for (int ii = 0; ii < testEls; ii ++) { 191 | srnd = ocBroadcastInt(rand(), ii % 2 + 1); 192 | 193 | testBuffer[testBufferTail] = srnd; 194 | if (testBufferTail < 200) { 195 | testBufferTail ++; 196 | } else { 197 | testBufferTail = 0; 198 | } 199 | otemp = feedOblivInt(srnd, ii % 2 + 1); 200 | opSuccess = oqueue_push(testQueue, &otemp); 201 | revealOblivBool(&tempBool, opSuccess, 0); 202 | success &= tempBool; 203 | } 204 | 205 | for (int ii = 0; ii < testOps; ii ++) { 206 | srnd = ocBroadcastInt(rand(), ii % 2 + 1); 207 | 208 | if (testBufferHead == testBufferTail) { 209 | // queue is empty; push 210 | testBuffer[testBufferTail] = srnd; 211 | if (testBufferTail < 200) { 212 | testBufferTail ++; 213 | } else { 214 | testBufferTail = 0; 215 | } 216 | otemp = feedOblivInt(srnd, ii % 2 + 1); 217 | opSuccess = oqueue_push(testQueue, &otemp); 218 | revealOblivBool(&tempBool, opSuccess, 0); 219 | success &= tempBool; 220 | } else { 221 | bool queue_full = (testBufferTail + 1) == testBufferHead || (testBufferTail == 200 && testBufferHead == 0); 222 | if (queue_full) { 223 | // queue is full; pop 224 | thisVal = testBuffer[testBufferHead]; 225 | if (testBufferHead < 200) { 226 | testBufferHead ++; 227 | } else { 228 | testBufferHead = 0; 229 | } 230 | opSuccess = oqueue_pop(&otemp, testQueue); 231 | revealOblivInt(&temp, otemp, 0); 232 | revealOblivBool(&tempBool, opSuccess, 0); 233 | success &= tempBool && (temp == thisVal); 234 | } else { 235 | if (srnd %2 > 0) { 236 | testBuffer[testBufferTail] = srnd; 237 | if (testBufferTail < 200) { 238 | testBufferTail ++; 239 | } else { 240 | testBufferTail = 0; 241 | } 242 | otemp = feedOblivInt(srnd, ii % 2 + 1); 243 | opSuccess = oqueue_push(testQueue, &otemp); 244 | revealOblivBool(&tempBool, opSuccess, 0); 245 | success &= tempBool; 246 | } else { 247 | thisVal = testBuffer[testBufferHead]; 248 | if (testBufferHead < 200) { 249 | testBufferHead ++; 250 | } else { 251 | testBufferHead = 0; 252 | } 253 | opSuccess = oqueue_pop(&otemp, testQueue); 254 | revealOblivInt(&temp, otemp, 0); 255 | revealOblivBool(&tempBool, opSuccess, 0); 256 | success &= tempBool && (temp == thisVal); 257 | } 258 | } 259 | } 260 | } 261 | 262 | oqueue_free(testQueue); 263 | 264 | fprintf(stderr, "Test Item: %-70s %s\n", "oqueue - 4000 random operations on full 200 element queue", (success)?STATUS_SUCCESS:STATUS_FAILURE); 265 | 266 | } 267 | 268 | { 269 | 270 | int testEls = 189; 271 | 272 | oqueue * testQueue = oqueue_new_static(&ocCopyInt, testEls); 273 | 274 | bool success = true; 275 | 276 | obliv bool testQueueFullness = oqueue_empty(testQueue); 277 | bool tempBool; 278 | revealOblivBool(&tempBool, testQueueFullness, 0); 279 | success &= (tempBool == true); 280 | 281 | for (int ii = 0; ii 4 | #include 5 | #include 6 | 7 | void showUsage(const char* exec) 8 | { 9 | fprintf(stderr,"Parameters missing\n"); 10 | fprintf(stderr,"Usage: %s \n",exec); 11 | exit(1); 12 | } 13 | int main(int argc,char *argv[]) 14 | { 15 | ProtocolDesc pd; 16 | TestCopyIO io; 17 | int i,me; 18 | const char* server; 19 | if(argc<3) showUsage(argv[0]); 20 | else 21 | { server=argv[1]; 22 | me = (strcmp(server,"--")==0?1:2); 23 | if(me==1) 24 | { if(argc>=7) 25 | for(i=0;i<4;++i) sscanf(argv[3+i],"%d",io.data+i); 26 | else showUsage(argv[0]); 27 | } 28 | else 29 | { if(argc>=5) 30 | for(i=0;i<2;++i) io.sel[i]=(argv[3+i][0]=='1'); 31 | else showUsage(argv[0]); 32 | } 33 | } 34 | connectOrDie(&pd,server,argv[2]); 35 | setCurrentParty(&pd,me); 36 | execYaoProtocol(&pd,testcopy,&io); 37 | printf("Result = %x,%x\n",io.result[0],io.result[1]); 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /test/testcopy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef struct 5 | { 6 | int data[4]; 7 | bool sel[2]; 8 | int result[2]; 9 | } TestCopyIO; 10 | 11 | void testcopy(void* vargs); 12 | -------------------------------------------------------------------------------- /test/testcopy.oc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"copy.oh" 4 | #include"testcopy.h" 5 | 6 | #include 7 | 8 | #ifndef USE_SHARES 9 | #ifdef FEED_SHARES_DIRECT 10 | #undef FEED_SHARES_DIRECT 11 | #endif 12 | #endif 13 | 14 | void testcopy(void* vargs) 15 | { 16 | TestCopyIO* args = vargs; 17 | int i; 18 | obliv bool osel[2]; 19 | obliv int odata[4]; 20 | #ifndef FEED_SHARES_DIRECT 21 | feedOblivIntArray(odata,args->data,4,1); 22 | #endif 23 | feedOblivBoolArray(osel,args->sel,2,2); 24 | #ifndef USE_SHARES 25 | OcCopy* cpy = &ocCopyInt; 26 | ocCopyCondN(cpy,odata,odata+2,osel,2); 27 | revealOblivInt(&args->result[0],odata[0],0); 28 | revealOblivInt(&args->result[1],odata[1],0); 29 | #else 30 | ProtocolDesc* pd = ocCurrentProto(); 31 | ocShareInit(pd); 32 | OcCopy* cpy = ocShareCopyNew(pd,2,sizeof(OcSharedInt)); 33 | OcSharedInt sh[4]; 34 | #ifdef FEED_SHARES_DIRECT 35 | ocFeedSharedIntN(pd,sh,args->data,4,1); 36 | #else 37 | ocToSharedIntN(pd,sh,odata,4); 38 | #endif 39 | ocCopyCondN(cpy,sh,sh+2,osel,2); 40 | #ifdef FEED_SHARES_DIRECT 41 | ocRevealSharedIntN(pd,args->result,sh,2,0); 42 | #else 43 | ocFromSharedIntN(pd,odata,sh,2); 44 | revealOblivInt(&args->result[0],odata[0],0); 45 | revealOblivInt(&args->result[1],odata[1],0); 46 | #endif 47 | ocCopyRelease(cpy); 48 | ocShareCleanup(pd); 49 | #endif 50 | } 51 | 52 | // I should allow implicit conversions from frozen void* to obliv int* 53 | 54 | typedef void (*ocopy)(frozen void*,frozen void*) obliv; 55 | 56 | void fun(obliv bool c,ocopy set) 57 | { 58 | obliv int x,y; 59 | obliv if(c) set(&x,&y); 60 | } 61 | void fun2(obliv bool c, void* a, void* b, ocopy set) 62 | { 63 | obliv if(c) set(a,b); 64 | } 65 | 66 | // Both of this need to fail TODO 67 | void bad(obliv bool c, void* a,void (*f)(void*) obliv) 68 | { 69 | int* p=a; 70 | obliv if(c) f(a); 71 | obliv if(c) 72 | { 73 | int* x = p; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /test/testshuffle.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"util.h" 4 | #include"testshuffle.h" 5 | 6 | void showUsage(const char* exec) 7 | { 8 | fprintf(stderr,"Parameters missing\n"); 9 | fprintf(stderr,"Usage: %s n\n",exec); 10 | exit(1); 11 | } 12 | // Compile with -DPERM_STORE_YAO for pure yao protocol, no shares 13 | // Compile with -DUSE_SHARES for pure share shuffling 14 | // Use both for pure shares, along with yao-based index handling 15 | int main(int argc,char *argv[]) 16 | { 17 | ProtocolDesc pd; 18 | int n; 19 | if(argc<4) showUsage(argv[0]); 20 | else sscanf(argv[3],"%d",&n); 21 | connectOrDie(&pd,argv[1],argv[2]); 22 | setCurrentParty(&pd,strcmp(argv[1],"--")==0?1:2); 23 | execYaoProtocol(&pd,testShuffle,&n); 24 | cleanupProtocol(&pd); 25 | printf(n?"Checks passed\n":"Checks failed\n"); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/testshuffle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void testShuffle(void*); 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/testshuffle.oc: -------------------------------------------------------------------------------- 1 | #include 2 | #include"shuffle.oh" 3 | #include"testshuffle.h" 4 | #include 5 | #ifndef MUX_BATCH 6 | #define MUX_BATCH n 7 | #endif 8 | 9 | #ifdef PERM_STORE_YAO 10 | const bool permYao = true; 11 | #else 12 | const bool permYao = false; 13 | #endif 14 | 15 | #if 1 16 | typedef int dint; 17 | typedef OcSharedInt OcSharedDInt; 18 | void (*ocFeedSharedDIntN)(OcSharedDInt dest[],const dint src[], 19 | size_t n,int party) = ocFeedSharedIntN; 20 | void (*ocRevealSharedDIntN)(dint dest[], 21 | const OcSharedDInt src[], size_t n,int party) = ocRevealSharedIntN; 22 | void (*feedOblivDIntArray)(obliv dint[],dint[],size_t,int) 23 | = feedOblivIntArray; 24 | OcCopy* ocCopyDInt = &ocCopyInt; 25 | #else 26 | typedef long long dint; 27 | typedef OcSharedLLong OcSharedDInt; 28 | void (*ocFeedSharedDIntN)(OcSharedDInt dest[],const dint src[], 29 | size_t n,int party) = ocFeedSharedLLongN; 30 | void (*ocRevealSharedDIntN)(dint dest[], 31 | const OcSharedDInt src[], size_t n,int party) = ocRevealSharedLLongN; 32 | void (*feedOblivDIntArray)(obliv dint[],dint[],size_t,int) 33 | = feedOblivLLongArray; 34 | OcCopy* ocCopyDInt = &ocCopyLLong; 35 | #endif 36 | 37 | void revealPerm(ProtocolDesc* pd, int plain[], void* cipher,size_t n) 38 | { 39 | #ifdef PERM_STORE_YAO 40 | for(int i=0;i 3 | #include 4 | #include 5 | 6 | void showUsage(int argc,char* argv[]) 7 | { 8 | fprintf(stderr,"Usage: %s \n",argc>0?argv[0]:"testsort"); 9 | exit(1); 10 | } 11 | 12 | void cmpswap(void* v,size_t i,size_t j) 13 | { 14 | int* d = v; 15 | if(d[i]>d[j]) { int x=d[i]; d[i]=d[j]; d[j]=x; } 16 | } 17 | 18 | int main(int argc,char* argv[]) 19 | { 20 | size_t n,i; 21 | if(argc<2) showUsage(argc,argv); 22 | if(sscanf(argv[1],"%zd",&n)!=1) showUsage(argc,argv); 23 | int *a = malloc(sizeof(int)*n); 24 | srand(time(0)); 25 | for(i=0;ia[i]) break; 28 | if(i==n) printf("Checks passed\n"); 29 | else printf("Checks failed\n"); 30 | free(a); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /test/testunapply.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include"testunapply.h" 5 | 6 | void showUsage(const char* exec) 7 | { 8 | fprintf(stderr,"Parameters missing\n"); 9 | fprintf(stderr,"Usage: %s n\n",exec); 10 | exit(1); 11 | } 12 | int main(int argc,char *argv[]) 13 | { 14 | ProtocolDesc pd; 15 | int n; 16 | if(argc<4) showUsage(argv[0]); 17 | else sscanf(argv[3],"%d",&n); 18 | connectOrDie(&pd,argv[1],argv[2]); 19 | setCurrentParty(&pd,strcmp(argv[1],"--")==0?1:2); 20 | execYaoProtocol(&pd,testUnapply,&n); 21 | cleanupProtocol(&pd); 22 | printf(n?"Checks passed\n":"Checks failed\n"); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /test/testunapply.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | void testUnapply(void*); 3 | 4 | -------------------------------------------------------------------------------- /test/testunapply.oc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"shuffle.oh" 4 | #include"testunapply.h" 5 | 6 | #define MAGIC 92 7 | 8 | void revealOblivIntArray(int dest[],const obliv int src[],size_t n) 9 | { 10 | int i; 11 | for(i=0;i 2 | #include"waksman.c" 3 | #include 4 | 5 | void random_permute(unsigned p[],size_t n) 6 | { 7 | int i,j; 8 | for(i=0;i0;--i) 11 | { j = rand()%i; 12 | unsigned t = p[i]; 13 | p[i]=p[j]; p[j]=t; 14 | } 15 | } 16 | 17 | void printPerm(const unsigned p[],size_t n) 18 | { 19 | int i; 20 | for(i=0;i=n || b[i]>=n) return printf("out of bounds\n"),false; 33 | t = vals[a[i]]; 34 | vals[a[i]] = vals[b[i]]; 35 | vals[b[i]] = t; 36 | } 37 | for(i=0;i=level_size[l]) 51 | { j=i; ++l; 52 | memset(used,0,sizeof(bool)*n); 53 | } 54 | if(used[a[i]]||used[b[i]]) rv=false; 55 | used[a[i]] = used[b[i]] = true; 56 | } 57 | free(used); 58 | if(l>lc) rv=false; 59 | return rv; 60 | } 61 | 62 | int main(int argc,char* argv[]) 63 | { 64 | int type,i; 65 | size_t n,sc; 66 | bool verbose = (argc>1 && strcmp(argv[1],"-v")==0); 67 | while(1) 68 | { 69 | if(verbose) printf( 70 | "Test 1: strata count\n" 71 | "Test 2: strata assign\n" 72 | "Test 3: permute_in_place\n" 73 | "Test 4: stratify\n" 74 | " 5: exit\n" 75 | "\n" 76 | "Enter test type: \n" 77 | ); 78 | if(scanf("%d",&type)<1) break; 79 | if(type<1||type>4) break; 80 | if(verbose) printf("Network size: \n"); 81 | if(scanf("%zd",&n)<1) break; 82 | sc = waksmanSwapCount(n); 83 | switch(type) 84 | { 85 | case 1: 86 | printf("Strata count: %zd\n",waksmanStrataCount(n)); 87 | break; 88 | case 2: 89 | { 90 | unsigned *a = malloc(sc*sizeof(*a)); 91 | unsigned *b = malloc(sc*sizeof(*b)); 92 | unsigned *level = malloc(sc*sizeof(*level)); 93 | waksmanNetwork(a,b,n); 94 | waksmanStrataAssign(level,a,b,n); 95 | printf("Levels:"); 96 | for(i=0;i bench/ 6 | 7 | Circuit ORAM files ... need uniformizing pass. 8 | block.oc 9 | block.oh 10 | circuit_oram.oc 11 | circuit_oram.oh 12 | ckt_utils.oc 13 | ckt_utils.oh 14 | nonrecursive_oram.oc 15 | nonrecursive_oram.oh 16 | -------------------------------------------------------------------------------- /util/oqueue.oc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "oqueue.oh" 3 | 4 | struct oqueue { 5 | oqueue * child; 6 | OcCopy * cpy; 7 | size_t layer_index; 8 | size_t copymult; 9 | bool dynamic_sizing; 10 | obliv uint8_t head; 11 | obliv uint8_t tail; 12 | obliv uint32_t current_elements; 13 | uint8_t push_time; 14 | uint8_t pop_time; 15 | void * data; 16 | }; 17 | 18 | static void* element(OcCopy* cpy,void* arr,int x) obliv 19 | { return x*cpy->eltsize+(char*)arr; } 20 | 21 | obliv bool oqueue_empty(oqueue * layer) obliv { 22 | return (layer->current_elements == 0); 23 | } 24 | 25 | obliv bool oqueue_full (oqueue * layer) obliv { 26 | if (layer->child == NULL) { 27 | return (layer->tail == 6); 28 | } else { 29 | return (layer->tail == 6 & oqueue_full(layer->child)); 30 | } 31 | } 32 | 33 | obliv bool oqueue_push(oqueue * layer, void * input) obliv { 34 | obliv bool success = false; 35 | ~obliv(en) { 36 | if (layer->child != NULL) { 37 | if (layer->push_time == 1) { 38 | obliv if (layer->tail >= 5) { 39 | obliv if (oqueue_push(layer->child, element(layer->cpy,layer->data,3*layer->copymult))) { 40 | ocCopyN(layer->cpy,element(layer->cpy,layer->data,3*layer->copymult), element(layer->cpy,layer->data,5*layer->copymult),layer->copymult); 41 | layer->tail -= 2; 42 | } 43 | } 44 | layer->push_time = 0; 45 | } else { 46 | layer->push_time ++; 47 | } 48 | } 49 | } 50 | obliv if (layer->tail < 6) { 51 | for (uint8_t ii = 0; ii < 6; ii++) { 52 | obliv if (ii == layer->tail) { 53 | ocCopyN(layer->cpy,element(layer->cpy,layer->data,ii * layer->copymult), input, layer->copymult); 54 | success = true; 55 | layer->current_elements ++; 56 | } 57 | } 58 | layer->tail++; 59 | } 60 | return success; 61 | } 62 | 63 | obliv bool oqueue_pop(void * output, oqueue * layer) obliv { 64 | obliv bool success = false; 65 | 66 | ~obliv(en) { 67 | if (layer->pop_time == 0) { 68 | if (layer->child == NULL) { 69 | obliv if (layer->head >= 2) { 70 | for (uint8_t ii = 0; ii < 4; ii ++) { 71 | ocCopyN(layer->cpy,element(layer->cpy,layer->data,ii*layer->copymult), element(layer->cpy,layer->data,(ii + 2)*layer->copymult),layer->copymult); 72 | } 73 | layer->head -= 2; 74 | layer->tail -= 2; 75 | } 76 | } else { 77 | obliv if (layer->head >= 2) { 78 | ocCopyN(layer->cpy,element(layer->cpy,layer->data,0), element(layer->cpy,layer->data,2*layer->copymult), layer->copymult); 79 | layer->head -= 2; 80 | obliv if(~oqueue_pop(element(layer->cpy,layer->data,1*layer->copymult), layer->child)) { 81 | for (uint8_t ii = 1; ii < 4; ii ++) { 82 | ocCopyN(layer->cpy,element(layer->cpy,layer->data,ii*layer->copymult), element(layer->cpy,layer->data,(ii + 2)*layer->copymult),layer->copymult); 83 | } 84 | layer->tail -= 2; 85 | } 86 | } 87 | } 88 | layer->pop_time = 1; 89 | } else { 90 | layer->pop_time --; 91 | } 92 | } 93 | 94 | obliv if (layer->head < 3 & layer->head != layer->tail) { 95 | for (uint8_t ii = 0; ii < 3; ii++) { 96 | obliv if (ii == layer->head) { 97 | ocCopyN(layer->cpy,output,element(layer->cpy,layer->data,ii*layer->copymult),layer->copymult); 98 | success = true; 99 | layer->current_elements --; 100 | } 101 | } 102 | layer->head++; 103 | } 104 | return success; 105 | } 106 | 107 | oqueue * oqueue_new_static(OcCopy * cpy, size_t n) { 108 | size_t queue_size = 0; 109 | size_t layer_index = 0; 110 | oqueue * result; 111 | oqueue * this_layer = NULL; 112 | oqueue * last_layer = NULL; 113 | 114 | while (queue_size < n) { 115 | this_layer = malloc(sizeof(oqueue)); 116 | this_layer->layer_index = layer_index; 117 | this_layer->head = 0; 118 | this_layer->tail = 0; 119 | this_layer->current_elements = 0; 120 | this_layer->push_time = 0; 121 | this_layer->pop_time = 0; 122 | this_layer->dynamic_sizing = false; 123 | this_layer->child = NULL; 124 | 125 | this_layer->copymult = pow(2, layer_index); 126 | this_layer->cpy = cpy; 127 | this_layer->data = calloc(1, this_layer->cpy->eltsize * this_layer->copymult * 6); 128 | 129 | if (last_layer == NULL) { 130 | result = this_layer; 131 | } else { 132 | last_layer->child = this_layer; 133 | } 134 | last_layer = this_layer; 135 | 136 | queue_size += 3 * pow(2, layer_index); 137 | layer_index++; 138 | } 139 | 140 | return result; 141 | } 142 | 143 | //TODO make this work in O(N) instead of O(NlogN) 144 | oqueue * oqueue_static_from_array(OcCopy * cpy, size_t n, void * src) { 145 | oqueue * result = oqueue_new_static(cpy, n); 146 | 147 | for (size_t ii = 0; ii < n; ii++) { 148 | oqueue_push(result, element(cpy, src, ii)); 149 | } 150 | 151 | return result; 152 | } 153 | 154 | void oqueue_free(oqueue * layer) { 155 | if (layer->child != NULL) { 156 | oqueue_free(layer->child); 157 | } 158 | free(layer->data); 159 | free(layer); 160 | } -------------------------------------------------------------------------------- /util/oqueue.oh: -------------------------------------------------------------------------------- 1 | #ifndef OBLIV_QUEUE 2 | #define OBLIV_QUEUE 3 | 4 | #include 5 | #include "copy.oh" 6 | //#include "oram.oh" 7 | 8 | /******************************************************************************** 9 | * This implements an O(log(n)) oblivious queue, as descriped in the paper: 10 | * 11 | * Zahur, S. & Evans, D. (2013). Circuit Structures for Improving Efficiency of 12 | * Security and Privacy Tools. IEEE Symposium on Security and Privacy 2013. 13 | ********************************************************************************/ 14 | 15 | typedef struct oqueue oqueue; 16 | 17 | oqueue * oqueue_new_static(OcCopy * cpy, size_t n); 18 | oqueue * oqueue_static_from_array(OcCopy * cpy, size_t n, void * src); 19 | void oqueue_free(oqueue *); 20 | 21 | obliv bool oqueue_empty(oqueue *) obliv; 22 | obliv bool oqueue_full(oqueue *) obliv; 23 | obliv bool oqueue_push(oqueue *, void *) obliv; 24 | obliv bool oqueue_pop(void *, oqueue *) obliv; 25 | 26 | 27 | 28 | /******************************************************************************** 29 | * The following implements a ring queue atop Sqrt ORAM; it is left here for 30 | * purposes of comparison only, and should not be used in practice, as the log(n) 31 | * queue above is much faster. 32 | ********************************************************************************/ 33 | 34 | /*typedef struct oring_queue oring_queue; 35 | 36 | oring_queue * oring_queue_new(size_t size, size_t); 37 | void oring_queue_free(oring_queue *); 38 | 39 | obliv bool oring_queue_empty(oring_queue *); 40 | obliv bool oring_queue_empty_obliv(oring_queue *) obliv; 41 | obliv bool oring_queue_full(oring_queue *); 42 | obliv bool oring_queue_full_obliv(oring_queue *) obliv; 43 | void oring_queue_push(oring_queue *, obliv uint32_t *); 44 | void oring_queue_push_obliv(oring_queue *, obliv uint32_t *) obliv; 45 | void oring_queue_pop(obliv uint32_t *, oring_queue *); 46 | void oring_queue_pop_obliv(obliv uint32_t *, oring_queue *) obliv;*/ 47 | 48 | #endif -------------------------------------------------------------------------------- /util/util.c: -------------------------------------------------------------------------------- 1 | #include"util.h" 2 | #include // for ocBroadcast 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | double wallClock() 12 | { 13 | struct timespec t; 14 | clock_gettime(CLOCK_REALTIME,&t); 15 | return t.tv_sec+1e-9*t.tv_nsec; 16 | } 17 | 18 | void connectOrDieAux(ProtocolDesc* pd,const char* server,const char* port) 19 | { 20 | if(!server) // I *am* the server 21 | { if(protocolAcceptTcp2P(pd,port)!=0) error(1,0,"TCP accept failed\n"); 22 | setCurrentParty(pd,1); 23 | }else 24 | { if(protocolConnectTcp2P(pd,server,port)!=0) 25 | error(1,0,"TCP connect failed\n"); 26 | setCurrentParty(pd,2); 27 | } 28 | } 29 | void connectOrDie(ProtocolDesc* pd,const char* server,const char* port) 30 | { connectOrDieAux(pd,strcmp("--",server)==0?0:server,port); } 31 | 32 | void cmdConnectOrDie(ProtocolDesc* pd) 33 | { const char* s = cmdNetSpec.server; 34 | s=(s&&s[0]?s:NULL); 35 | connectOrDieAux(pd,s,cmdNetSpec.port); 36 | } 37 | 38 | int 39 | cmdFindFirst(const char* search,const char* alts[],int n) 40 | { 41 | int i; 42 | for(i=0;icmdIndex!=cargs->argc) 88 | error(-1,0,"Unrecognized parameter '%s'\n",cargs->argv[cargs->cmdIndex]); 89 | } 90 | bool cmdParseMode(CmdParseState* cargs) 91 | { 92 | const char* modes[] = {"test","bench"}; 93 | int i = cmdFindFirst(cargs->argv[cargs->cmdIndex],modes,2); 94 | if(i==-1) return false; 95 | if(cmdMode!=-1 && cmdMode!=i) 96 | error(-1,0,"Choose either 'test' or 'bench', not both\n"); 97 | cmdMode=i; 98 | if(i==cmdModeBench) cmdShowResult=false; 99 | cargs->cmdIndex++; 100 | return true; 101 | } 102 | static bool numericString(const char* s) 103 | { while(*s) if(!isdigit(*(s++))) return false; 104 | return true; 105 | } 106 | void cmdParseCheckNumeric(const char* s) 107 | { if(!numericString(s)) 108 | { fprintf(stderr,"Expecting integer, not '%s'.\n",s); 109 | exit(-1); 110 | } 111 | } 112 | bool cmdParseNetwork(CmdParseState* cargs) 113 | { 114 | if(cmdNetDone()) return false; 115 | const char* a = cargs->argv[cargs->cmdIndex]; 116 | char* p=strchr(a,':'); 117 | if(!p) return false; 118 | if(!numericString(p+1)) return false; 119 | cmdNetSpec.port=p+1; 120 | *p='\0'; 121 | cmdNetSpec.server=a; 122 | cargs->cmdIndex++; 123 | return true; 124 | } 125 | bool cmdParseShowResult(CmdParseState* cargs) 126 | { 127 | const char* a = cargs->argv[cargs->cmdIndex]; 128 | const char* opt[] = {"--showResult","--hideResult","+o","-o"}; 129 | int i = cmdFindFirst(a,opt,sizeof(opt)/sizeof(*opt)); 130 | if(i==-1) return false; 131 | if(cmdMode!=cmdModeTest) 132 | error(-1,0,"Option '%s' can only be used with 'search test'.i\n",a); 133 | cmdShowResult=(i%2==0); 134 | cargs->cmdIndex++; 135 | return true; 136 | } 137 | 138 | OramType cmdOramType = oramTypeNone; 139 | bool cmdOramTypeDone() { return cmdOramType!=oramTypeNone; } 140 | 141 | // Returns NULL on mismatch, pointer to argument on success. 142 | const char* 143 | cmdParseSingleArg(CmdParseState* cargs,char shortopt,const char* longopt) 144 | { 145 | const char* a = cargs->argv[cargs->cmdIndex]; 146 | if(cmdIsPrefix("--",a)) // --longopt case 147 | { int n=strlen(longopt); 148 | if(strncmp(longopt,a+2,n)!=0 || a[n+2]!='=') return 0; 149 | cargs->cmdIndex++; 150 | return a+n+3; 151 | } 152 | else if(a[0]=='-' && a[1]==shortopt) 153 | { if(a[2]!='\0') { cargs->cmdIndex++; return a+2; } 154 | else if(cargs->cmdIndex+1==cargs->argc) 155 | error(-1,0,"Error: argument missing for -%c\n",shortopt); 156 | else { cargs->cmdIndex+=2; return cargs->argv[cargs->cmdIndex-1]; } 157 | } 158 | return 0; 159 | } 160 | bool 161 | cmdParseSingleInt(CmdParseState* cargs,char shortopt,const char* longopt, 162 | int* dest,int init) 163 | { 164 | const char* a = cmdParseSingleArg(cargs,shortopt,longopt); 165 | if(!a) return false; 166 | int x; 167 | if(sscanf(a,"%d",&x)!=1) error(-1,0,"Integer expected, not '%s'\n",a); 168 | if(*dest==init || *dest==x) *dest=x; 169 | else error(-1,0,"Conflicting values for --%s\n",longopt); 170 | return true; 171 | } 172 | 173 | // Parses all remaining arguments as integers. 174 | void cmdParseTermInts(CmdParseState* ps,int** outarray,int* outsize) 175 | { 176 | int *dest,n,i; 177 | n=ps->argc-ps->cmdIndex; 178 | dest=malloc(n*sizeof(int)); 179 | 180 | for(i=0;iargv[i+ps->cmdIndex],"%d",dest+i)!=1) 181 | error(-1,0,"Integer expected, not '%s'\n",ps->argv[i+ps->cmdIndex]); 182 | 183 | *outarray=dest; 184 | *outsize=n; 185 | ps->cmdIndex+=n; 186 | } 187 | bool cmdParseOramType(CmdParseState* cargs) 188 | { 189 | const char* targ = cmdParseSingleArg(cargs,'t',"oramtype"); 190 | if(!targ) return false; 191 | OramType t = oramTypeFromString(targ); 192 | if(t==oramTypeNone) error(-1,0,"Invalid oram type %s\n",targ); 193 | if(cmdOramType!=oramTypeNone && cmdOramType!=t) 194 | error(-1,0,"Conflicting oram types specified\n"); 195 | cmdOramType=t; 196 | return true; 197 | } 198 | 199 | static const char* cmdUsage = ""; 200 | void cmdSetUsage(const char* c) { cmdUsage=c; } 201 | 202 | /* 203 | Grammar: 204 | genr := (type|netw) 205 | cmd := search genr* (("test" (genr|testopt)* inputs) | 206 | ("bench" (genr|benchopt)* inputs))) 207 | */ 208 | void 209 | cmdParseCommon(cargs,appopts,appoptArgs) 210 | CmdParseState* cargs; 211 | bool (*appopts)(CmdParseState*,void*); 212 | void* appoptArgs; 213 | { 214 | assert(cargs->cmdIndex==1); 215 | if(cargs->argc==1) error(-1,0,"%s\n",cmdUsage); 216 | 217 | while(cargs->cmdIndexargc) 218 | { 219 | if(!cmdParseMode(cargs) && 220 | !cmdParseOramType(cargs) && 221 | !cmdParseNetwork(cargs)) 222 | cmdUnknownOptionExit(cargs->argv[cargs->cmdIndex]); 223 | if(cmdMode!=cmdModeNone) break; 224 | } 225 | 226 | while(cargs->cmdIndexargc) 227 | { // Mode is set at this point 228 | const char* a=cargs->argv[cargs->cmdIndex]; 229 | if(a[0]!='-' && a[0]!='+' && cmdModeNetDone()) break; // End of options 230 | if(!cmdParseNetwork(cargs) && 231 | !cmdParseOramType(cargs) && 232 | !cmdParseShowResult(cargs) && 233 | !appopts(cargs,appoptArgs)) 234 | cmdUnknownOptionExit(cargs->argv[cargs->cmdIndex]); 235 | } 236 | if(cmdMode==cmdModeNone) 237 | error(-1,0,"Neither 'test' nor 'bench' was specified\n"); 238 | if(!cmdNetDone()) 239 | error(-1,0,"Network server/port options missing\n"); 240 | if(!cmdOramTypeDone()) 241 | error(-1,0,"Required --oramtype is missing\n"); 242 | } 243 | CmdParseState 244 | cmdParseInit(int argc, char* argv[]) 245 | { 246 | CmdParseState rv = {.argc=argc,.argv=argv,.cmdIndex=1}; 247 | return rv; 248 | } 249 | 250 | void 251 | matchedBroadcastInt(int* x,bool init,const char* parname) 252 | { 253 | bool init1 = ocBroadcastBool(init,1); 254 | int x1 = ocBroadcastInt(*x,1); 255 | bool init2 = ocBroadcastBool(init,2); 256 | int x2 = ocBroadcastInt(*x,2); 257 | if(!init1 && !init2) 258 | error(-1,0,"Missing parameter %s\n",parname); 259 | if(init1 && init2 && x1!=x2) 260 | error(-1,0,"Mismatched parameter %s\n",parname); 261 | *x=(init1?x1:x2); 262 | } 263 | int* randomIntArray(int max,int n) 264 | { 265 | // TODO initialize random generator in main() somewhere 266 | int i,*rv = malloc(n*sizeof(int)); 267 | for(i=0;i 3 | 4 | // Legacy version: server == "--" means we listen 5 | void connectOrDie(ProtocolDesc* pd,const char* server,const char* port); 6 | // New version: uses whatever is in cmdNetSpec. .server==NULL means we listen 7 | void cmdConnectOrDie(ProtocolDesc* pd); 8 | 9 | double wallClock(); 10 | 11 | bool cmdIsPrefix(const char* prefix,const char* str); 12 | int cmdFindFirst(const char* search,const char* alts[],int n); 13 | int cmdFindFirstPrefix(const char* search,const char* alts[],int n); 14 | 15 | typedef enum 16 | { oramTypeNone=-1, 17 | oramTypeLin, 18 | oramTypeSqrt, 19 | oramTypeCkt 20 | } OramType; 21 | 22 | static inline OramType 23 | oramTypeFromString(const char* s) 24 | { const char* types[] = {"linear","sqrt","ckt"}; 25 | return cmdFindFirstPrefix(s,types,sizeof(types)/sizeof(*types)); 26 | } 27 | 28 | void cmdShowUsageExit(const char cmdUsage[]); 29 | 30 | extern struct CmdNetSpec { const char *server,*port; } cmdNetSpec; 31 | // Call this *after* cmdParseCommon() returns 32 | static inline bool cmdMeServing(void) 33 | { return cmdNetSpec.server==NULL || cmdNetSpec.server[0]=='\0'; } 34 | enum CmdMode { cmdModeNone=-1,cmdModeTest,cmdModeBench } cmdMode; 35 | extern bool cmdShowResult; 36 | void cmdParseCheckNumeric(const char* s); 37 | 38 | 39 | void cmdSetUsage(const char* c); 40 | static inline bool cmdModeNetDone() 41 | { return cmdMode!=-1 && cmdNetSpec.port!=0; } 42 | static inline bool cmdNetDone() { return cmdNetSpec.port; } 43 | 44 | typedef struct { int argc; char** argv; int cmdIndex; } CmdParseState; 45 | CmdParseState cmdParseInit(int argc, char* argv[]); 46 | extern OramType cmdOramType; 47 | 48 | const char* cmdParseSingleArg(CmdParseState* cargs, 49 | char shortopt,const char* longopt); 50 | bool cmdParseSingleInt(CmdParseState* cargs,char shortopt,const char* longopt, 51 | int* dest,int init); 52 | // Parses all remaining arguments as integers. 53 | void cmdParseTermInts(CmdParseState* ps,int** outarray,int* outsize); 54 | void cmdParseEnd(CmdParseState* cargs); 55 | 56 | void cmdParseCommon( 57 | CmdParseState* cargs, 58 | bool (*appopts)(CmdParseState*,void*), 59 | void* appoptArgs 60 | ); 61 | 62 | // TODO need to standardize error policy. Some functions return false on error, 63 | // while others simply exit. Things to ponder about: 64 | // Unrecognized error, syntax error, error messages (e.g. "-n 50" vs "-n -x") 65 | // Combined single options (e.g. "-xk"), conflicting values (compare with 66 | // -1, check bool etc.). 67 | 68 | void matchedBroadcastInt(int* x,bool init,const char* msg); 69 | int* randomIntArray(int max,int n); 70 | --------------------------------------------------------------------------------