Oblivious RAM

An oblivious RAM (ORAM) simulator is a compiler that transforms algorithms in such a way that the resulting algorithms preserve the input-output behavior of the original algorithm but the distribution of memory access pattern of the transformed algorithm is independent of the memory access pattern of the original algorithm. The definition of ORAMs is motivated by the fact that an adversary can obtain nontrivial information about the execution of a program and the nature of the data that it is dealing with, just by observing the pattern in which various locations of memory are accessed during its execution. An adversary can get this information even if the data values are all encrypted. The definition suits equally well to the settings of protected programs running on unprotected shared memory as well as a client running a program on its system by accessing previously stored data on a remote server. The concept was formulated by Oded Goldreich in 1987.
Definition.
A Turing machine (TM), the mathematical abstraction of a real computer (program), is said to be oblivious if for any two inputs of the same length, the motions of the tape heads remain the same. Pippenger and Fischer proved that every TM with running time formula_1 can be made oblivious and that the running time of the oblivious TM is formula_2. A more realistic model of computation is the RAM model. In the RAM model of computation, there is a CPU that can execute the basic mathematical, logical and control instructions. The CPU is also associated with a few registers and a physical random access memory, where it stores the operands of its instructions. The CPU in addition has instructions to read the contents of a memory cell and write a specific value to a memory cell. The definition of ORAMs capture a similar notion of obliviousness memory accesses in this model.
Informally, an ORAM is an algorithm at the interface of a protected CPU and the physical RAM such that it acts like a RAM to the CPU by querying the physical RAM for the CPU while hiding information about the actual memory access pattern of the CPU from the physical RAM. In other words, the distribution of memory accesses of two programs that make the same number of memory accesses to the RAM are indistinguishable from each other. This description will still make sense if the CPU is replaced by a client with a small storage and the physical RAM is replaced with a remote server with a large storage capacity, where the data of the client resides.
The following is a formal definition of ORAMs. Let formula_3 denote a program requiring a memory of size formula_4 when executing on an input formula_5. Suppose that formula_3 has instructions for basic mathematical and control operations in addition to two special instructions formula_7 and formula_8, where formula_7 reads the value at location formula_10 and formula_8 writes the value formula_12 to formula_10. The sequence of memory cell accessed by a program formula_3 during its execution is called its memory access pattern and is denoted by formula_15.
A polynomial-time algorithm, formula_16 is an Oblivious RAM (ORAM) compiler with computational overhead formula_17 and memory overhead formula_18, if formula_16 given formula_20 and a deterministic RAM program formula_3 with memory-size formula_4 outputs a program formula_23 with memory-size formula_24 such that for any input formula_5, the running-time of formula_26 is bounded by formula_27 where formula_28 is the running-time of formula_29, and there exists a negligible function formula_30 such that the following properties hold:
Note that the above definition uses the notion of statistical security. One can also have a similar definition for the notion of computational security.
History of ORAMs.
ORAMs were introduced by Goldreich and Ostrovsky wherein the key motivation was stated as software protection from an adversary who can observe the memory access pattern (but not the contents of the memory).
The main result in this work is that there exists an ORAM compiler that uses formula_44 server space and incurs a running time overhead of formula_45 when making a program that uses formula_4 memory cells oblivious. This work initiated a series of works in the construction of oblivious RAMs that is going on till date. There are several attributes that need to be considered when we compare various ORAM constructions. The most important parameters of an ORAM construction are the amounts of client storage, the amount of server storage and the time overhead in making one memory access. Based on these attributes, the construction of Kushilevitz et al. is the best known ORAM construction. It achieves formula_47 client storage, formula_44 server storage and formula_49 access overhead.
Another important attribute of an ORAM construction is whether the access overhead is amortized or worst-case. Several of the earlier ORAM constructions have good amortized access overhead guarantees, but have formula_50 worst-case access overheads. Some of the ORAM constructions with polylogarithmic worst-case computational overheads are. The constructions of were for the random oracle model, where the client assumes access to an oracle that behaves like a random function and returns consistent answers for repeated queries. They also noted that this oracle could be replaced by a pseudorandom function whose seed is a secret key stored by the client, if one assumes the existence of one-way functions. The papers were aimed at removing this assumption completely. The authors of also achieve an access overhead of formula_51, which is just a log-factor away from the best known ORAM access overhead.
While most of the earlier works focus on proving security computationally, there are more recent works that use the stronger statistical notion of security.
One of the only known lower bounds on the access overhead of ORAMs is due to Goldreich et al. They show a formula_52 lower bound for ORAM access overhead, where formula_4 is the data size. There is also a conditional lower bound on the access overhead of ORAMs due to Boyle et al. that relates this quantity with that of the size of sorting networks.
ORAM constructions.
Trivial construction.
A trivial ORAM simulator construction, for each read or write operation, reads from and writes to every single element in the array, only performing a meaningful action for the address specified in that single operation. The trivial solution thus, scans through the entire memory for each operation. This scheme incurs a time overhead of formula_54 for each memory operation, where is the size of the memory.
A simple ORAM scheme.
A simple version of a statistically secure ORAM compiler constructed by Chung and Pass is described in the following along with an overview of the proof of its correctness. The compiler on input and a program with its memory requirement , outputs an equivalent oblivious program .
If the input program uses registers, the output program will need formula_55 registers, where formula_56 is a parameter of the construction. uses formula_57 memory and its (worst-case) access overhead is formula_58.
The ORAM compiler is very simple to describe. Suppose that the original program has instructions for basic mathematical and control operations in addition to two special instructions formula_7 and formula_8, where formula_7 reads the value at location and formula_8 writes the value to . The ORAM compiler, when constructing , simply replaces each and instructions with subroutines and and keeps the rest of the program the same. It may be noted that this construction can be made to work even for memory requests coming in an online fashion.
Memory organization of the oblivious program.
The program stores a complete binary tree of depth formula_63 in its memory. Each node in is represented by a binary string of length at most . The root is the empty string, denoted by . The left and right children of a node represented by the string formula_64 are formula_65 and formula_66 respectively. The program thinks of the memory of as being partitioned into blocks, where each block is a contiguous sequence of memory cells of size . Thus, there are at most formula_67 blocks in total. In other words, the memory cell corresponds to block formula_68.
At any point of time, there is an association between the blocks and the leaves in .
To keep track of this association, also stores a data structure called position map, denoted by formula_69, using formula_70 registers. This data structure, for each block , stores the leaf of associated with in formula_71.
Each node in contains an array with at most triples. Each triple is of the form formula_72, where is a block identifier and is the contents of the block. Here, is a security parameter and is formula_73.
 
Description of the oblivious program.
The program starts by initializing its memory as well as registers to . Describing the procedures and is enough to complete the description of . The sub-routine is given below. The inputs to the sub-routine are a memory location formula_74 and the value to be stored at the location . It has three main phases, namely FETCH, PUT_BACK and FLUSH.
 input: a location , a value 
 Procedure FETCH // Search for the required block.
 formula_75 // is the block containing .
 formula_76 // is 's component in the block .
 formula_77
 if formula_78 then formula_79. // Set formula_80 to a uniformly random leaf in .
 flag formula_81.
 for each node on the path from root to formula_80 do
 if has a triple of the form formula_83 then
 Remove formula_83 from , store in a register, and write back the updated to .
 flag formula_85.
 else
 Write back to .
 Procedure PUT_BACK // Add back the updated block at the root.
 formula_86. // Set formula_87 to a uniformly random leaf in .
 if flagformula_88 then
 Set formula_89 to be same as except for at the -th position.
 else
 Set formula_89 to be a block with at -th position and 's everywhere else.
 if there is space left in the root then
 Add the triple formula_91 to the root of .
 else
 Abort outputting overflow.
 Procedure FLUSH // Push the blocks present in a random path as far down as possible.
 formula_92. // Set formula_93 to a uniformly random leaf in .
 for each triple formula_94 in the nodes traversed the path from root to formula_93
 Push down this triple to the node that corresponds to the longest common prefix of formula_96 and formula_93.
 if at any point some bucket is about to overflow then
 Abort outputting overflow.
The task of the FETCH phase is to look for the location in the tree . Suppose formula_80 is the leaf associated with the block containing location . For each node in on the path from root to formula_80, this procedure goes over all triples in and looks for the triple corresponding to the block containing . If it finds that triple in , it removes the triple from and writes back the updated state of . Otherwise, it simply writes back the whole node .
In the next phase, it updates the block containing with the new value , associates that block with a freshly sampled uniformly random leaf of the tree, writes back the updated triple to the root of .
The last phase, which is called FLUSH, is an additional operation to release the memory cells in the root and other higher internal nodes. Specifically, the algorithm chooses a uniformly random leaf formula_93 and then tries to push down every node as much as possible along the path from root to formula_93. It aborts outputting an overflow if at any point some bucket is about to overflow its capacity.
The sub-routine is similar to . For the sub-routine, the input is just a memory location formula_74 and it is almost the same as . In the FETCH stage, if it does not find a triple corresponding to the location , it returns as the value at location . In the PUT_BACK phase, it will write back the same block that it read to the root, after associating it with a freshly sampled uniformly random leaf.
Correctness of the simple ORAM scheme.
Let stand for the ORAM compiler that was described above. Given a program , let denote formula_103. Let formula_104 denote the execution of the program on an input using memory cells. Also, let formula_15 denote the memory access pattern of formula_104. Let denote a function such that for any formula_31, for any program and for any input formula_108, the probability that formula_109 outputs an overflow is at most formula_110. The following lemma is easy to see from the description of .
It is easy to see that each and operation traverses root to leaf paths in chosen uniformly and independently at random. 
This fact implies that the distribution of memory access patterns of any two programs that make the same number of memory accesses are indistinguishable, if they both do not overflow.
The following lemma completes the proof of correctness of the ORAM scheme.
Computational and memory overheads.
During each and operation, two random root-to-leaf paths of are fully explored by . This takes formula_123 time. This is the same as the computational overhead, and is formula_58 since is formula_58.
The total memory used up by is equal to the size of . Each triple stored in the tree has formula_126 words in it and thus there are formula_127 words per node of the tree. Since the total number of nodes in the tree is formula_70, the total memory size is formula_129 words, which is formula_130. Hence, the memory overhead of the construction is formula_58.