 Hello everyone, I'm very happy to talk about Oblivious Run with worst case logarithmic overhead. I'm Gilad Ashram from Bailan University and this is a joint work with Ilan Komogotsky, Wake Eileen and Elaine Shee. So what is the problem that Oran comes to address? Suppose that we have a secure processor and an untrusted memory, or suppose that we have some client that uploads this information to an untrusted cell. Even if the uploaded information is encrypted, the access pattern, the memory locations that the client accesses, reveals some sensitive information. For instance, let's say that a medical doctor uploads all the genomic information of its client to the cloud. Suppose also that the doctor always accesses regions that relates to the kidney. Even though the data is encrypted and therefore the server cannot see this information, the server can still infer that the patient has some kidney problem and not say a heart problem and this is leakage that we want to prevent. Oblivious Run addresses this exact problem. It can be viewed as a compiler that takes the program that the client wishes to execute and converts it into an Oblivious program where the untrusted server cannot understand which elements the client is actually accessing. This is achieved by shuffling parts of the memory every now and then and moving blocks around to hide the access pattern. The security requirement is that the access pattern, which addresses are being accessed in the physical memory, can be simulated and therefore they do not reveal information on which addresses are being accessed by the program. Naturally, Oblivious Runs also introduce some overhead. This shuffling of the memory and moving blocks around every now and then are expensive and every access to the logical in the logical memory is translated to many accesses by the Oblivious Run compiler to the physical memory. How many accesses? So we are looking at a standard setting where n is the size of the memory. The word size is log n and the client's memory size is of all the one words. In this setting, there is a law bound that every around must introduce omega log n overhead. This means that if the program has to perform m accesses to a memory of size n that the Oblivious program or the compiled program must have m log n accesses to the physical memory. In this setting, there is a long line of forks that try to match this law bound and this law bound was just matched last year by a construction that is called OPTORRAMA. Also, a closer look shows that in all those works, they achieve those complexities in the amortized sense. This means that on m accesses, the total work would be m log n, but for some accesses, they might take much longer. In particular, in those constructions, the worst case complexity is sometimes even linear. Some techniques were previously introduced for de-amortizing ORAM, however those techniques are not compatible with the recent constructions of panorama and OPTORRAMA. This means that when we look at worst case complexity, we have a relatively large gap between the best known ORAM and the lower one. To elaborate further, both panorama and OPTORRAMA use what is so-called the random mystery use technique. I will talk about this technique later in the talk. The de-amortization method of Stravsky and Schup is not compatible with this technique. This leads us to our question, is it even possible to de-amortize constructions that are based on random mystery use technique, such as panorama and OPTORRAMA? Our results? We show that there is an ORAM with order log n worst case over it. We show a new de-amortization method that is compatible with the random mystery use technique. This means in particular that we show how to de-amortize the OPTORRAMA construction. Along the way, we also show a new algorithm for removing duplications in array, which might be of an independent interest. The algorithm works in linear time, assuming some assumption on the inputs where the best known algorithm before and without this input assumption requires or takes n log n. I'm going to describe this primitive later. In the rest of this presentation, I will start by briefly explaining hierarchical ORAM. This is a common framework for building an ORAM introduced by Ostrowski in 1990. Both panorama and OPTORRAMA follow this framework. I will then explain the de-amortization method of Ostrowski and Schupp. I will cover the random mystery use technique of panorama and OPTORRAMA, and I will explain why this technique is not compatible with the de-amortization method of Ostrowski and Schupp. I will then say some words about our de-amortization method while referring to the paper for the actual details. I will start with briefly explaining hierarchical ORAM. We have log n levels of doubling sizes. Each level is a hash table where the life level is of size 2 to the i. Some of the levels are going to be empty, and some of the levels are going to be full. Each level of size n can support up to n lookups. This means that every n accesses to the level, every n lookups, we must rebuild that level. The lookups are cheap. For this talk, we can assume that the lookup takes a constant amount of work, but rebuilding the level is an expensive operation that takes order n log n work. I will now explain how an access looks like. For demonstration purposes, I am going to add some pairs of addresses and data. For example, the content of address 5 in the memory will be found in this table, in the fourth table, and its associated data is TLT. Now let's assume that the client wants to read the content of address 9. This is translated to lookups in each one of the non-empty levels, and the element is going to be found in the last level over here. We can now read the data associated to 9, which is BCD in this example. After we read the element, we are going to write it into the first level. Now let's assume that the client wishes to write address 25 to address 25, the value gry. Again, it's going to lookup of 25 in each one of the, in each level. After it's going to find 25 over here, it's going to pretend to lookup in the rest of the levels to have the same access pattern. After finding 25, we now know its value. We are going to overwrite on this value, and we're going to write into the first level the value gry, the new value that the client wishes to write. Now, however, we cannot really write into the first level because it's full, and we have to rebuild the next level, level 2. We're going to rebuild the level from the content of the two previous levels, of the level 1 and the new element 25. After some more accesses, we're going to have the same things. We're going to lookup in each one of the levels, write it into the first level, and then the first level is going to be full. After some more accesses, we have to rebuild the next level, the next empty level from the content of all previous levels. So we're going to write level 3 from the content of level 1 and 2. In general, what happens here is that every 2 to the i accesses, level i is being rebuilt from the content of all levels that are above. After another 2 to the i accesses, its elements will be pushed down and will become empty again. After another 2 to the i accesses, it will again be rebuilt from the content of all levels above. Each rebuild is an expensive operation, which costs something like M log N. I'm now going to describe a slightly different approach for rebuilding. This new approach will be easier to de-armortize. So in the previous approach, every 2 to the i accesses, we pushed all the top levels into the i level. This is quite expensive. Instead, I want to break it down into smaller operations. And what we do is that we push the content of each table to the level below it. Previously each level could have been either full or empty. Now what we're going to have is that each level is either full or half full. And only the first level can be completely empty. So what's going to happen now is that I'm going to push each level to the level below it. So the content of all those elements is going to be pushed over here. And therefore this one is going to be half empty, half full after the rebuild process. This level is going to be pushed over here. And this level is going to be pushed into this level and it's going to be merged actually. So at the end of this process, the first level is going to be empty. Those two levels are going to be half full and this level is going to be full. So if previously we looked for the first empty level, now we are going to look for the first half full level. We're going to push down all elements into it. How does it help us and why does it help us? Now when we rebuild, we just need to look on two levels, two consecutive levels. We don't need to look on the entire structure above it. There are two possible procedures, either we just push down or we are going to merge the two levels, either I rebuild. I know exactly what I'm going to rebuild, exactly all the elements above me. And my elements are going to be pushed down also. Or that I am the last level to be rebuilt. So I'm just getting more elements from the level above me. That's like a melge between the two levels. Okay, so this is easier to de-amortize because I need now only to look at two consecutive levels. Now let's take a look at the life cycle of level i and i minus one. This line represents a timeline. Remember that on each table of size n, we can accommodate only n lookups. And after n lookups, it has to be rebuilt. Those after two to the i minus one accesses, level i minus one cannot be accessed anymore and we must rebuild it. Now the rebuild is expensive, we have to wait, we have some delay, and so on. Okay, at this point, we have to rebuild level i minus one. At this point, level i minus one was rebuilt. We can accommodate another two to the i minus one accesses. And here we must rebuild both level i minus one and level i. Again, this is expensive, we'll have to wait, it will take time. After those two levels were rebuilt, I again can accommodate two to the i minus one accesses, I reach this point, I need to rebuild again. Another two to the i minus one accesses and then I have to rebuild both level i minus one and level i. Now, let's de-amortize this process, we are now focusing, I'm now going to focus only on level i and not level i minus one. And let's take a look at this point of time. At this point, this level i minus one is already, it was already rebuilt. And I know that in the future, at this point, I will need to rebuild level i and I know exactly which elements are going to be rebuilt, which elements will be pushed down into level i. So I can start the rebuild process of level i already at this point. And I can start rebuilding level i from the content of all elements in level i minus one and because I know it in advance, I can spread the rebuild process over many accesses such that in each access, I'm going to do a little bit of work towards rebuilding level i. So the cost per access is low. When we reach this point, level i is already rebuilt. We finish the rebuilding of level i and we can immediately start to use the new table that we just built. And we can proceed without any delays. Again, after i2 did the i minus one accesses, at this point of time, level i minus one is rebuilt. And now I know exactly which elements I'm going to rebuild in level i when I need to rebuild it. So I can start the rebuild process in advance. When we cannot, okay, and then I start the rebuild, again, I'm spreading it throughout many accesses. And when I cannot use the i table anymore, we finish the rebuild process exactly at the same time and we can just proceed with the new table, with the table just rebuilt. To conclude, the idea is that we know in advance what exactly we want to rebuild. And we can just start the rebuild process earlier and in parallel to our accesses far before the deadline. So that when we reach the deadline with the new table, it's already ready. We feed access to the structure, we perform a little bit of the rebuild. So what goes wrong with panorama and optorama? The key idea of panorama and optorama is what is so called the randomly used technique. The idea is that if we take a table and we shuffle all the elements and then whatever we don't touch, whatever elements we didn't look for, those elements are still randomly shuffle from the i of the adversary, didn't see where those elements are. So the idea is that we don't really need to rebuild everything from scratch in each rebuild process. We can just rebuild whatever the adversary didn't see, is still a secret and we don't have to rebuild it. So this reduces this idea, the paper shows how to reduce the rebuild process from end login to just order and work. And the idea is that whatever we didn't look for, we don't really have to rebuild it. We don't really have to re-shuffle it. We can reuse the randomness that we have. What is the main challenge when you come to de-amortize this process? So this randomness reuse brings the following problem. If we want to start rebuilding the table, but then let's assume that we are going to access element 25. This means that we cannot, now we reveal the randomness at 25, we consume that randomness, and therefore this rebuild process is just not going to work. We perform the lookup and we cannot reuse the randomness of 25. We just consumed it over here. So this is problematic. We cannot start to build in advance as we don't know which elements we are going to look at. On the other end, we also cannot allow ourselves to start rebuild after we know what lookups will be looked for because this is going to be too late. This brings us to the main idea of our new technique. So the main idea behind our solution is the following. We maintain two copies of each level, copy A and copy B, and each has its own independent randomness. Whenever we rebuild, let's say we're rebuilding copy B, we're building this table, this level of copy B, all the lookups are going to be performed on level A, on the copy A, so on copy A. We're not going to perform the lookups on copy B. And vice versa, when A is being rebuilt, we are going to perform all the lookups on copy B. This means that we never really re-consume randomness as the lookups are going to be in a different structure, completely independent to whatever we are rebuilding. Whenever an element is found in one of the structures, we are going to write it to both copies. This means that we are going to make new copies of the same elements. This is very, very high-level description and the actual scheduling is a bit subtle because elements move from one to another and we're just referring to the paper for the actual details. This solution brings us to some more challenges. One of them is the problem of de-duplication, removing de-duplications. So remember that when an element is found, we're going to put it in both structures. This means that we're going to have the same keys more than once in the same hash, in the same column. So we need to remove duplications. Now, in the panorama, we didn't have this problem. We never needed to delete an element. Whenever we looked for an element, we deleted it right away. So we didn't have two copies of the same element somewhere in the structure. Now, what's wrong with duplications? We know how to remove the duplication. It's a non-primitive in the ORM literature. However, in the ORM literature, we can afford to remove duplications in time and again. With the recent constructions, we want to push down the rebuild process from end again into ORM. So this means that we must have a duplication, a removing de-duplication process that takes linear time. So we show how to perform a linear, we show a linear time algorithm that gets us input two sets A and B and outputs the union and remove duplications along the way. And the algorithm is oblivious if A and B are randomly shuffled, assuming one refunctions. So we show something that is linear time assuming that it's an input assumption. And without the input assumption, we still cannot do better than end again. Another challenge that we have is something that I put under the rack so far. I presented here as each hash table is completely independent. In fact, all hash tables have also a stash and looking for an element inside the stash is quite priceless. All recent constructions also follow what is so-called the combined stash technique where they take the stashes of all hash tables and combine it into one big stash which allows them looking into the stashes much, much faster. Well, this means that all levels have something, some shared memory that are not completely independent. And in particular, they are not, when we come to rebuild and move things to rebuild the level, we cannot just lock the shared memory because other tables have to look into it at the same time and so on. To solve this issue, we use a version of an oblivious dictionary that supports lookup of elements with respect to various auxiliary keys such as the level they came from and so on. We show how to build such a dictionary. So to conclude the talk, I want to mention our results and techniques. So we show a new de-amortization method for constructions that are based on the random history use technique. We show the method for removing duplications in linear time into arrays. We show a new method for handling shared memory. And our main theorem, we show that there exists a computational alarm with the worst case or the log n overhead. Thank you very much. And I hope that next year, we'll see you in person.