 All right, thanks. So this is joint work. I'm in Hadsberg, Hotpin, Newen, and Haier-Schulman. It's a concurrent work to the talk you've just seen. So some of the parts may even overlap. But it's conceptually two different approaches how you can build such things. All right, so you have already seen how obfuscation works in theory. Just let me give you a quick reminder that you can find plenty of obfuscators in the wild in practice, even free obfuscators, even through web forms. So this is an example I just found it on the internet. I just typed in a small JavaScript, and this is what it produced. And I think it's pretty obvious to say that that one is not really secure, because you can see the hello world here appearing clear. I'm not claiming that all of the practical schemes are secure, but you have plenty of them, actually. Most of them are actually commercial, so you pay a few hundred dollars to get an obfuscator. The interesting thing is that it's not even clear what they really provide to you. This is a quote from one of the commercial software saying obfuscators do not stop reverse-engineering efforts. If you're really determined, they keep on also saying that we basically only provide security against amateurs. So I should mention that there are people in the software obfuscation community, software engineering, who try to at least establish some form of formalism, what it means to be secure, especially the work by Karl Berg et al. For some talks about cyclomatic numbers, which is a complexity measure for software. Now, if you look at theory, actually, it looks different. So far, we have a few fully reliable candidates. And here, I don't want to offend anyone who is working on proposing. I know this is hard, but given the history from the first very nice work proposing the first candidates, it's really hard to keep track of the new proposals and the attacks and what exactly they break and so on. And this is partly due to the fact that we have a clear vision of what kind of security we want, and this is usually nowadays indistinguishable. But indistinguishability obfuscation, saying for any circuits which compute the same functions, the obfuscated versions look alike. And of course, achieving this is hard, and this is why maybe in theory, we don't have a fully satisfying solution yet. Now, if you compare the two worlds and talk about practice and theory, actually, the face seems like they face different problems, but in the end, it points down to the same questions. Which candidate should I use if I want to have a secure obfuscator? And this is where the combiners enter the stage, and you've just seen that the basic idea is you take N candidates. You don't know which of them are secure. Take your, let's say, five favorite ones, then you combine them somehow into a single, maybe bigger obfuscator. And what you want to have from the final result is you should say you really want to build it constructively, so not purely existential, saying in math there exists a secure obfuscator, or assuming that the polynomial hierarchy collapses and so on, really want to have a program here. And so what the guarantee is, what you want is that if at least T of these N obfuscators are secure, then the overall thing is secure. So in this example, if you have 3T equals to 3, good ones, and only 2 are malicious, then the overall combiner should still be secure. And here, as in the previous talk, we assume that all the malicious candidates are under control of a single adversary, and they may arbitrarily conspire. So when we started thinking about this, especially my co-authors, or Amir, was really much into, OK, we should have a solution which really works in practice. And he wanted to have one which works on both sides, theory and practice. So in particular, it should be fast enough to cover maybe the bad combiner you've seen on the first slide. OK, before I tell you how we do this, let me tell you how it's not going to work. And then partly, the good news isn't partly if you missed the argument in the previous talk, why you can't nest obfuscator securely, you'll see a sort of rerun of this argument here. OK, so two of the three combiners. So let's say you have three combiners. Your task is now, in theory, to build an obfuscator such that if you insert the x, you get the circuit value c of x. So here's what you can do. You can just take your circuit, view it as a program, run it through the obfuscators. So you get three programs, and you just put them into the circuit. And then what you do is whenever you get some access input to the obfuscated version, you just put it into all the obfuscated circuits. And then in the end, you do a majority. And the majority should exactly prevent all the trouble you've just seen with the incorrectness of obfuscators. Because if you assume two of them are correct, then it doesn't matter if the third one just even gives you a wrong answer. As long as you do a majority, a bitwise majority, you can be sure that the output is correct. Now the problem is, this gives you functional correctness, but it does not give you the indistinguishability property. So if you suppose that obfuscator number two is corrupt, then this obfuscator can just put anything it likes into the program here. In particular, it may just print a copy in clear of the input circuit c. And then since this appears in clear in your obfuscated circuit, you can just leak information about the input circuit through that. So this is now the sequential obfuscator. We've just seen the case of three obfuscators. This is now the simpler version of two obfuscators where you take the output of the first obfuscator, the inner one, and just insert it into the second one. And then the obfuscator is just the description of the program, the output program of the second obfuscator. Now here, if obfuscator two, the outer one is corrupt, then you're still good in terms of leakage because you still have the inner obfuscator which basically hides everything about the input circuit. So you can't really leak through the second obfuscator. Now the problem appears if the inner obfuscator is corrupt because then it may just, or you may hope that it cannot leak because you still have the outer obfuscator which hides everything, but this is where indistinguishability obfuscation is not sufficient because it only guarantees you that the output is indistinguishable if the input functions are the same. So you can just, the malicious obfuscator can just output a different program, like saying if you give me a certain input, I will just output the circuit in clear, and else I will compute the original function. And then if you run this to the second obfuscator which may obfuscate arbitrary programs, it's easy really to trigger this event and have the circuit be printed. So you can leak through the functions because of functional incorrectness. Basically you can taint the outer obfuscator by that. OK, so here's what works. It's a three out of four combiner, so this means we need four candidates and you need to assume that three of them are actually secure. So first what you do is go back to the idea of having a majority combiner, so you take three obfuscators and then you just build the majority over it. Then you still know you can leak this, this combiner can leak, but at least it's functionally correct. And the good news is if one of the obfuscator, the three obfuscators you're using here is malicious, then again you can leak, but you get a guarantee and I mean that the fourth one, the complimenting one is actually secure. One of the three used here is insecure, the fourth one must be secure. And we can use that to build our obfuscator. So what we do is we layer obfuscated versions of this majority combiner, right? So we take the majority combiner, which we just seen, and then use the fourth obfuscator to obfuscate the output. And actually it suffices to do it for any three combinations of the four numbers. So in this example we have the outer obfuscators are four, three, and two, and then you just take the complimenting three numbers for the majority obfuscator. And then you do another majority on top, and we'll see in a second why this is the case. And this is your obfuscator, this is your combiner, that's how it works. So let's look at the case that the obfuscator number three is malicious, right? Then you still have the guarantee that the obfuscator and the majority combiner, one, two, and four are still good. Basically they hide everything about this input circuit C at this point. So if the malicious circuit, if circuit, sorry, if obfuscator three is malicious, then it also appears in the other majority circuits, but there you still at least provide functional correctness because of the majority. And this means that the outer obfuscator, so obfuscator number four in this case and number two in this case, they basically hide everything about the input. So this means everything about the input circuit is shielded by the right choice of the obfuscators. And actually you can prove this if you go back to the formal requirements, you can show that this combiner works for indistinguishably obfuscation and all the other stronger notions of obfuscation which we have there, like VVB and VGB. I should say if you dare to even put in more candidates, you can generalize this instead of having three out of four, you have a two D plus one out of three D plus one combines just doing more majorities and so on, but still staying on a layer two circuit. So we actually implemented this. No, we didn't implement any cryptographically secure obfuscator, I'm sorry. We just took one of these available open source obfuscators and we settled for JavaScript just to have an example. So actually the two related obfuscators by Yahoo, one is more or less a randomized version for security purposes. You should not do this for relation purposes. I think it was hard enough to get the implementations running. So they are related, but they should not affect the significantly the runtime or the output load ratio. Okay, so here's an example. One is just a simple obfuscator is called Compressor because very often in practice, these obfuscators come as also code optimizers and they really shrink the code. And then we just used two versions, different choices of how to order the obfuscators. The two by Yahoo and one by Google and one JavaScript packer. So we ran this for a couple of standard programs ranging from a few kilobytes. So all the dots is a program more or less to more or less a megabyte. And you see the obfuscation time. You just run the simple obfuscator 01, which is the blue line. It's essentially not significant in the first part only if you really blow up the program size and you can spot some few seconds. It takes a few seconds. And for our combined as you see that for the bigger program, well, let's say the order does not really matter almost. And then for the megabyte, you see that it took us maybe three minutes to really output the final program. So what's interesting is the size of the output program. So here you can see, again, if you just run the simple obfuscator, Yahoo's compressor obfuscator on these programs, then you would expect something like one. You could actually, because of the code optimization, you could actually something which is smaller, I guess because standard programs carry a lot of redundancy like comments, intelligible names and so on. And they kind of throw all this away. And if you compare this to our obfuscator, here you see that you get a factor of between two and four, maybe up to five. Depends, of course, on the program in code size increase. And if you're really interested, you want to play around with this, I think, hot has put the programs on GitHub and you can find the reference in the proceedings. So the question is, can we do better than three out of four? So initially when we started designing the first schemes, we actually had five out of six, then we arrived at the three out of four and we were curious to see if we can do better. The answer is, yes, you can. If you just remember the previous talk, they had a one out of N combiner, so they just needed one of the candidates to secure. They do have some extra steps and assumptions in there which we don't. But in this sense, of course, you can beat the bound. The answer is no, if you look at the certain kind of way how you can build combiners, and this is what we call structural combiners. So what is the structural combiner? It's basically what we've just done with the majority and so on, you just layer all your obfuscators in a certain way and the structure, how you layer this is actually independent of your input circuits and of the candidates. So you start with saying, I just put place holders of my obfuscators into a circuit, then I do some other steps like majority or some NANDs or some XORs, whatever. And I just put this into a so-called units and the structure then says, if I have a unit, it determines the output circuit and I can use this as input to the next level unit. So and then if you want to actually build your combiner, what you do is you initialize the first level units with your input circuit. So you just run C through all the obfuscators, you get some output. This gives you the first level units in a full description of the first level units and then you can just run them through the obfuscators on the second level unit and so on. And recursively, you of course get then some output description and the actual combiner result is the final unit on this path. And of course, our combiner, our three out of four combiner was structural in that sense. Okay, so let's try to do a two out of three, right? Just lower it by just one compared to our three out of four combiner. So the first thing we notice that if there exists a path on these units such that the same obfuscator appears in each unit, then there's no hope to get a secure one. So here's the example. Let's suppose that obfuscator number three is on this path from the first level unit to the actual output unit and it's supposed that this combiner's malicious. Then if you initialize the combiner in the first level units, the malicious obfuscator may just output information about C in clear. And if this is done on the first level unit, then the malicious combiner on the second level unit can more or less forward this information. So you can basically leak through the entire path. So this means there's no path where there's the same obfuscator in each unit. This cannot be or you will not get a secure one. So this means on each path there is one unit and we can always take the right most one where there are only obfuscators number one and two. Okay, let's say in this example it's these. It doesn't matter what's happening in the other obfuscators or in the other units, sorry. What obfuscators are in the other units. Okay, then assume that the obfuscator number one is malicious and it will try to confuse our combiner but just saying instead of really obfuscating something about C, it will just obfuscate something about C star. Okay, then basically our combiner doesn't really know because there are only two obfuscators, one is saying the truth, one is lying. It cannot really tell if C or C star is the actual obfuscation it should work with. If you want to do it more formally, you can go to the case that obfuscator number two is malicious and now this time you actually wanted to obfuscate C star but now this malicious obfuscator tells you oh, I obfuscated C. Okay, so both look alike from you so the combiner would have to give the same result in both cases which means it needs to give the same result for both C and C star and if they are different then this cannot be a good combiner. Okay, this is why it doesn't work if you want to at least work with structural combiners to get something better. Okay, so then we thought about maybe we don't need a combiner which always works correctly and gives you functional correctness so we introduced something which we call detecting combiners and basically they say this is as before, if all candidates are secured then you get a secure combiner which provides functional correctness and so on. If you have that only T out of n combiners are secured there may be cases where the combiner tells you here's an error, there's something going on which is fishy, I cannot correct it but at least you should know that there's something false with that. And if you do this then you can actually go to two out of three instead of three out of four and you can also give a very similar lower bound saying that you cannot do one out of two but at least you can do a little bit better. So to conclude let me wrap up and show again what we did. I think we have what I would consider reasonable three out of four combiners I know it's hard to get three secure candidates especially in theory currently but at least in practice maybe you have hoped that some of the problems are actually doing a good job. We did implementations just to see how, let's say bad it is and surprisingly you didn't look that bad. We were expecting some blow up in output size for example by a factor of, because it's layered like maybe nine or 10 but it was about four which is an increase in size. If you talk about structural combiners things which you will nest basically outputs of the up for skaters then you cannot do any better unless you go to detecting combiners and there you can do two out of three but you cannot even go to one out of two. All right so that concludes my talk about the up for skating combiners. Thanks.