 So first of all, let's dive into what is an oblivious RAM. So it's a technique that was introduced in 96 by Goldweiss and Ostrowski, which basically encrypts the access pattern of a random access algorithm. So in a little bit more detail, we can imagine a setting with a server and a client. So the server will act basically as a large passive store of data. And the client will have random access to the memory on the server. The client itself will run a program which is simulating an array, which is also a random access data structure. The client has some small, persistent memory itself, but it's outsourcing most of the storage onto the server. In between the server and the client, there will be an eavesdropper which can see the access pattern made onto the memory of the server. So whenever the client accesses some position in the RAM of the server, the eavesdropper will be informed of the position, not the data being written or read. The reason why we can make that abstraction is that the data itself, we could just simply encrypt. So that would be a triviality to protect the data. However, hiding the access patterns is in general much harder. Security then says that if you take any two sequences of accesses to the simulated array, the one on the client, then the memory accesses that the client are making onto the server will look indistinguishable. So the eavesdropper will not be able to know which of the two sequences of operations to the array have been performed. A little bit more detail, it will look like this. So on the left here, we have the array that's being simulated by the client, the data structure we're trying to implement. It will have write operations, read operations. The words in this memory will call R. It's R bits long. And then the client also have a small memory itself. Whenever an operation is being made, for example, a read operation here, that will result in some probes onto the memory here of the server. We'll call these probes to distinguish them from operations. And I'll call this the array. And I'll call this the memory to distinguish these two things. The eavesdropper is sitting here. And you can see the axis pattern, but not the data. That's the basic model. So an important notion is the bandwidth overhead. How much extra communication or memory accesses are needed to hide the real axis pattern made onto the simulated array? So it's just as follows. So if we take a sequence of n accesses to the array that generates m probes to implement it, then the overhead will just be m divided by n. So that's an amortized overhead. If there's a difference between the word size of the physical memory and the simulated one, we'll just include that in the overhead. So if we are doing m operations and each of them reading w bits, that's the total amount of bits being moved on the bus across this border. And we are simulating the storage of that many bits. We just include w divided by r into the overhead. But in general, it's just the number of probes divided by the number of operations. So we want to keep that small. So what do we know about how much it was cost? I mean, first of all, there's some upper bounds. Already in 96, a Gold-Rison construct could prove the polylog upper bound. You don't need more than a polylog overhead. And since then, there's been a lot of research on more efficient programs. There's a seminal work from 13 called path program. It was the first one to get a bandwidth overhead of log n. And as we shall see today, that's optimal. So it's the first paper to show that you can actually get an optimal overhead. There's a slight restriction to this result namely the word size in the physical memory is the natural log n, whereas the word size in the array that is being simulated is larger. It's the square of that, which is maybe a little bit unnatural. But except for that, this one gets like an optimal overhead. Then there's a very nice result from the upcoming Fox where Patel and all is proving a bandwidth overhead of log n. Also the optimal one. And then some tiny stuff over there that we can probably live with. But basically, an optimal overhead again all the way down without having this restriction of having large words in the simulated array. OK, so that's the upper bounds. What about lower bounds? Well, already in 96, there was a proof that log n is needed. I mean, you cannot do better than log n. There were some restrictions to this result. Namely, there were some restrictions on the constructions that were being analyzed. They had to be what is called balls and bins. That means the algorithm or the ORAM, the algorithm simulating the array, is not allowed to look at the data being stored. So you can just move the data around in monolithic blobs. That, of course, puts some restrictions on what the algorithm can do. For example, you would not be able to use error-correcting codes, which would, of course, have to look at the actual data. Also, in this model, the adversary was allowed to have unbounded computing time, which is, of course, a restriction if you're proving a lower bound line, because it makes it easier to prove lower bounds. For example, it disallowed to use all of computational crypto to do any kind of magic. So there were some restrictions on the lower bound, but nonetheless, it was known that it was quite strong. It even holds for what's called offline ORAMs, where the ORAM is given the entire sequence of accesses to the array ahead of time. So it's being told before it has to do any simulation what all the operations will be. That's the strengthening of that result. OK, I'm going to get some water. And then there was a 30-year break where there was no further work on that. So that was the standing result for 30 years. So it was known that log-in was optimal, but that there were some kind of restrictions to this result, but people lived with it. Then there was a paper in 2016 which casts some doubts on whether we actually have a lower bound. So now, ORAM Boil published a paper called Is There an Oblivious RAM Lower Bound? And what they proved there was that suppose there exists a Boolean circuit family for sorting n words of size w bits with size little o of n times w times log n, then there exists an offline ORAM compiler for small memory, client memory, which have an overhead smaller than log n. So in fact, on this, we can prove strong lower bounds on circuits, we don't have a log n lower bound. It's all about the sorting. And the way this circumvented is it's breaking the assumptions, the two restrictions on the algorithms, in particular, this algorithm here is not balls in bins. It's using sorting algorithms that can look at the data, for example, being put into the ORAM. So it shows that these restrictions really are restrictions. It could be possible to go below the log n lower bound with some other kind of algorithm. And then they also propose that what they show here is going to be very hard to prove a lower bound, unless we are very good at proving circuit lower bounds and we are not. So we seem stuck. But then they notice that if we move to the online model instead and look only at ORAMs that have to simulate each access to the array before it's told what the next access to the array is, then the result here doesn't apply. So it might, again, be possible to get a lower bound. So that's what we're doing today. So we're going to prove today a lower bound of log n. And we're going to do it for arbitrary algorithms. So the ORAM can be arbitrary. In particular, we're going to skip the balls in bins algorithm. The ORAM algorithm can be arbitrary. And we're going to say that the adversary must be efficient. So he must be polynomial time. And still we can prove the lower bound. And then we get a much stronger result. The only flip side of it is it only holds for online ORAMs where you have to simulate each access to the array when it comes. But that's anyway the constructions that we need in practice for the applications. OK, so let's get to that. Just to remind you, so we're going to call this here the array. That's the simulated thing. We're going to call that the memory. That's the physical memory. Accesses to this thing we call probes. That can be write probes and read probes. And then there will be a small client memory here over here. So let's start with a simple case. I'm going to prove that if there's no client memory, if there's perfect correctness, you always get back what you write in a position in the array. And there's perfect obliviousness. And the word sizes in the array and the physical memory are the same. Then you need a log n overhead. OK, so try to look at the following sequence of operations. First, we will write random words into positions 1, 2, 3, up to 8. And replace that with an n later in the array. So we just write random stuff into the array. And then we read it back. So the next eight operations would to be to read these operations back. Then we can ask the questions. During these read operations, how often must we probe a memory position that was last time written while these write operations were performed? So we look at that operation here. It probes a memory position that was last time written while we were doing these positions. So how many times must that happen? Well, trivially, since we are transferring eight random words from that point in time onto this point in time, there must be eight such things. Otherwise, we're compressing random data. And that's not allowed. Shannon does not allow that. OK, so that was easy. It has to be eight on average. But let's pretend that it's just exactly eight for now. That makes stuff easier. OK, this is a technique called information transfer by a Patrescu and the main that we are using there. OK, let's ask another question then. Let's do a trivial sequence instead. I'm just writing the zero, all zero word to the zero position eight times. And then I'm reading that thing back again. So how many times must that happen that while I'm doing these read operations that I probed something that was last time written over here? Well, so we have to use obliviousness at some point. So we have an adversary sitting, an eavesdropper sitting here. And she's not supposed to learn whether I'm running the blue sequence or the red sequence. And when I'm running the blue sequence, I will be probing the memory here in a pattern such that during the last eight operations, I probe eight times a memory cell that was written last time during the first eight ones. This is something she can keep telling you of just by looking at the axis pattern. She just keeps track of where I'm probing during the first eight operations. And then she checks whether I eight times probe the same things again in the last eight operations. So that's something she can keep track of in pulley time. So by obliviousness, I must do it again eight times. OK. That means during this silly sequence, I must also eight time probe something over here while I'm doing these operations, something that was last time written over there. OK, that was fun. Let's do it again. Let's look at this sequence. I'm going to write four random words with them back, write four new, fresh, random words, and then read them back. OK? So during, let's say, these four read operations, how often must I probe something that was last time written over here? Four, right? Otherwise, I'm compressing random data that is not allowed. The same over here. As I'm reading these things, I must four times read something that was last time written here because that random data there was not in the memory until I did those writes. So I have to go back and get it there when I'm reading it out again. So I must also here do four of those, right? And we're going to off those onto the dummy sequence again because of obliviousness. When I'm doing the dummy sequence, the same accesses must be happening. And importantly, these probes are distinct. For example, here I'm counting four probes, which are done while I'm doing these four operations and are probing memory positions that was last time probed during these, right? So for example, if we look at the eight-week counting here, these are something that was last time probed over here. And you cannot, at the same time, last time have been probed here and there, right? So because that interval is not overlapping with that interval, we know that these are counting distinct accesses. And the same with these and the same with these. OK. I think you can complete the proof by now. Let's do it again, because we're finally good at it, so let's try it again. I'm going to write two random words, read them back, write two random words, read them back, write two random words, read them back. How many must be transferring? I mean, while I do these, I must probe something that was written over here at least two times all the way up. Then we use obliviousness to offload that onto the dummy sequence. And we can also do it with, like, write, read, write, read, write, read. And then I get once, all of these are distinct. How many are there in each row? There are, in this case, eight, but in general, in half. So if I did this with an n instead, I would have n half in each row. They're all distinct. They're slug n rows. So I get that if I make m accesses, now if I do n accesses, then m, the number of probes, must be at least n divided by two times slug n probes to the summary over here. So that gives an overhead of looking. Let's try to make it a little bit harder. So let's see, does this really affect the results? So let's say we have a larger r, then we have a w. Then just by, I mean, we saw it's an information transfer result. So if I'm writing, let's say, eight random words of this size, how many probes do I need to retrieve them? Well, eight, and then accounting also for the difference that these words might be smaller, right? So the overhead just grows with r divided by w. And then because in computing the overhead, w divided with r was in there, so that thing takes that thing, so the overhead is again and again. So it's the same overhead, that the word size, the differences in word sizes there doesn't really affect the result at all. OK, can we make it harder? It turns out that this kind of information transfer lower bound is extremely robust. So we try to circumvent it. So one can try more. I mean, first an obvious thing. Let's try to add a client memory, by the way. Let's do client memory. Let's assume the client have m words of memory. If we look at the first result, I mean, the first result was to write eight random values and then read them back. So that was how we got the eight there. So now let's assume that memory, the client is allowed to store two words of this stuff in his memory. So how many times must he at least probe back in time here? Well, we just have to subtract the client memory, right? Because he could store some of these values in his memory. But worst case, I mean, he's just there storing two of them. He still has six times to go back here. It's very easy to prove that using just Shannon source coding theorem. You just look at the client at this point here. He consists of two words. And then you try to run him and see which memory positions are he probing when he's reading this stuff back. Whenever he probes a position, you just write that value down next to him. That stuff you can send for someone. And then that someone can run the O-ram and get all these values back, because it's just running the O-ram. And whenever it makes a probe, it looks up in the list what would be in the memory of that position, right? And Shannon tells us, if we are sending eight random words, we must be sending something that has at least that length on average. So it's just a coding argument. So we have to subtract. And the same applies everywhere, right? So we just have to subtract in each of these blobs the size of the client memory. It doesn't hurt us up here. It hurts us down here. But what we can do is just prune the log m plus 1 lower layers, m being the size of the client memory. So in this case, we would remove those. If we take log m plus 1, then what's left in the blob is at least half the size as before. So here I take 4 and I subtract 2. Already here is at least half the size up here. I get even more for the budget, right? So I'm removing at most half of the weight. And I'm removing at most that many layers, right? So again, the weight of these will be at least n divided by 4 per row. And I have how many layers will log n minus log m, right? So that will be how it sums up. That gives a total weight of n divided by 4 times log n minus log m. And if we remember a little bit of math, then log n minus log m, that is the same as that. So asymptotically, we see that the overhead becomes log n divided by m. So it means if you have a lot of accesses, you have to basically have a client memory that is as big as the number of accesses to beat the log n lower bound. So it's extremely robust bound. So having square root n client memory will not help you at all. It will just half the lower bound. So that's devastating. Can we make it even more? We could try to relax correctness and say we only have correctness with some small constant probability. You have probability 1% of getting the right word back when you read a position independently everywhere. And obliviousness is also just some small constant. It means if I do two different sequences, then adversaries might be able to distinguish with probability 99%. I allow that. Well, there's a 1% chance that he's going to get confused whether I'm doing the blue or the red sequence. It will not help us. For example, if we look at the correctness, when I'm reading back here, if I'm getting in 1% of the case is the right word back, how many times do I have to go back? Well, Shannon's source coding thing just have to multiply by the correctness thing here. Because whenever you're locking, get the right thing, you're transferring a random word. And then you have to send something that's at least that long. For the obliviousness, it's easy to see that's Marko. Doing a Marko bound in a second. We're going to use obliviousness and Marko. So you just put this, I mean, if in one sequence you do at least c times n probes, then it's easy to see that if you're doing another sequence, and the eavesdropper have 1% chance of not being able to distinguish, then you cannot always do significantly less than c times n probes. If you would always do only 1%, I mean, if the average goes down to, let's say, 1%, then the distinguishing probability cannot be 2%. It's a simple Marko bound. So even for only constant obliviousness, you only get a constant drop in the ability to offload the hardness onto the red sequence. So the lower bound survives that too. So it means if you have m words of memory, constant correctness, constant obliviousness, the overhead stays n divided by m. And we have tried and tried and tried, and it's really hard. I mean, it's a nice open problem. Can you relax the O-RAM definition in such a way you can circumvent this kind of bound? OK. There's other obvious future work to do. There's more cell probe lower bound techniques out there. We used a pretty standard one as starting point here. And there are more oblivious data structures out there. So go prove some more lower bounds. And then there's this to actually get exact upper and lower bounds that's matching. So remember that we have the path O-RAM from 13, which is optimal, but have this restriction that the size of these words here have to be fairly big. And then we have the panorama O-RAM that's going to be presented at Fox, which have this overhead here. And what I proved today is that the overhead has to be at least log in. So it means that if we have log in sized array entries here, then there is not a complete match between the lower and the upper bounds yet. So there's something going on here that we don't understand. So it would be nice if someone could close that gap. We try it. We don't know how to do it. And that brings me to the conclusion, which is yes, there is an oblivious RAM lower bound. That's it. Thanks.