[MUSIC] I'm very happy to announce to you a speaker who has a very long experience with pen testing, who's been doing crypto since he was a kid after he read a book that inspired him when he was a teenager. But he also told me that he doesn't want to talk about himself. He's here to talk about projects, but I even would recommend to check out his bio because Steph has really interesting projects done in his life, and I'm really, really happy that he's here today to show us, in his words, "cinematic version" of a talk that was already published on YouTube, where he's going to show the link afterwards where you can see the director's cut later, if you feel like your appetite was whetted. We are most likely not going to have a Q&A afterwards, but Steph will be available from 4 p.m. on in the House of T to do the Q&A. So, without further ado, please applause for Steph. [APPLAUSE] Hello. Hello. Can you hear me? Great. Hello. Welcome. This is going to be my little rabbit hole, and maybe some of you will also follow me down this rabbit hole. I don't have much time. There's a lot of really awesome stuff to be shown. So, there's two parts of this talk. First of all, I'm going to tell you a bit about how OPRFs work, what they can do. This is based on a very awesome paper by Casa Cubeta, Hesse and Lehmann, which is called "Systemization of Knowledge," which I can warmly recommend to all of you. The reference is always in the footer. You can download the slides, and then if you are interested in this whole topic, this is a really good starting point, this paper. It has references to a lot of very exciting and very accessible papers, academic crypto papers. The second part is going to be some practical examples of software and deployments where OPRFs are deployed in the real world, or where you could think of deploying OPRFs yourself. Okay. First of all, just a little to whet your appetite, what you can do with OPRFs. OPRFs are essentially a building block for privacy. It's not so much about encryption or decryption or signing stuff. Of course, you can do those things as well. But here, oblivious keyword search is when you have a database which knows all the details in the database, but you don't want to disclose the queries to the database. So, you have a client, and you don't want the database to know what you are looking for. And so, keyword search is like a key value store where you go with a key and you get some value back if it's oblivious without the database actually learning what your query was, what the keyword was you were looking for. Private information retrieval is something similar, but here you don't go with a keyword or a key, but you know the index of the record in the database that you're querying, really. Secure pattern matching is when a server has like a string or something, and you're looking for a substring and the position of the substring, and you don't want the server to know what you're actually looking for while you actually learn the answer to your query. Private set intersection is also a very exciting topic that I'm going to come later in the practical example, so we're going to skip that. Also, password key exchange and cloud management and password storage are topics I'm going to come back later to. And the last four points I'm leaving up as an exercise for you to follow up, either reading the papers or something. These are also quite exciting topics that you can, for example, this is of course a non-exhaustive list of awesomeness that you can build from OPRFs. So first, let's have a look what a PRF is before we go into what an oblivious PRF is. So a pseudo-random function is basically a keyed function with a second input that generates some output that is non-distinguishable from random output. So if you want to imagine this, it's really like a hash with a key and a message, and the output is some hash value that is indistinguishable from random output. So it's like keyed hashing or calculating a Mac. Something happened with my slides. So it's like a keyed message authentication code, for example, or something like that. That's a pseudo-random function. Very simplified. There will be people who do crypto who will be screaming right now. But I think for this audience this might be enough. Okay, so this is a pseudo-random function. And if you do the same, so basically you have two inputs. You have a key and a message, and you have some output that is some random value, really. And if you do this in an oblivious setting, then you have two parties. You have a party that holds the key and another party that holds the message, and you compute a PRF together, but only the party who holds the message learns actually the output of the computation. So in this example here you don't see anything of my cursor. You see the cursor. Okay, so Alice has a message and Bob has the key, and they contribute the key and the message to this function, the OPRF function, and only Alice... So only Alice learns the output of this OPRF. This is like an interactive keyed hash, really, or a multi-party computation, if you want to consider it like that. So there's a bunch of techniques how you can create an OPRF. Basically, you have a PRF, and with some kind of conversion you can create an oblivious version of a PRF. The first that was possible to do so was in 2004, the Nowher Rangold, and there you apply oblivious transfer or homomorphic encryption, and then you have an OPRF. Then you have these others, but I'm not going to spend much time. This is something that you should either look in my director's cart. Shit. Ah, it's back. So these three constructions, I'm not going to go into much detail later. I'm going to refer to some of them, but the most exciting and most important one is the hash DH or two hash DH construction. It basically just calculates this very simple formula. If you see the one, I don't know how much you see the red part that is like the inner one, you have a special hash function that hashes your message to a point on a group. Most of the time, we are always working here with elliptic curves, so whatever you hash the message is going to be, after the hash, a point on an elliptic curve, on a specific elliptic curve. So this is not a normal hash. This is something we call hash to curve, and this just came out with the IRTF CFRG specification just this last week. So after 21 years of trying to define one that applies to all elliptic curves, also the NIST curves, not only the 25.519 derivates. So this is a very simple thing. You hash to a curve, and then you just raise to the secret key. And then there's a second variant of this. This is the two hash DH, where we hash the message again with the result of the hash DH construct. This is also very nice because the second hash destroys this algebraic structure that the hash DH has, which allows us to do some nifty stuff. But with the second hash, we actually get to a construct that can be proven in the universal composability framework, which is a very strong way to actually argue about protocols and constructs. Yes, there's a question. So, H prime and H are both elliptic curves? No, only H is a hash to curve. The second is just a normal hash and can be really any hash if you want. Very good question. The question was if those both are for elliptic curves, not just the inner one is for the elliptic curve or hash to the group, really. One thing. So the outer hash can also be memory-hard or cache-hard or any other hash function like argon2, for example. There's a follow-up question. So how do you convert the elliptic curve back to something you can have? Well, the elliptic curve in their serialized format, we usually use RESTRETO 255, and that is 32 bytes, really, and that's just 32 bytes. That's it. That's the most common way of actually doing that. Okay, so how do you instantiate this? So the client has the message and generates a random scalar R, and that is what we call the blinding factor. It just hashes to the curve of their message and then blinds this point by raising it to this blinding factor R. This we call alpha. Alpha is being sent over to the server. The server just raises this alpha value to K and then sends this beta value back. And then in the end, this is the -- I don't know how many of you people see this, but this beta value is then risen to 1 under R, and then the R eliminates the blinding, the raising to R here, and then raising to 1 under R here eliminates the whole blinding factor, and what you are left with in the end is actually exactly what hash DH was supposed to do. It's a very simple thing if you look at this, I think. The brilliance is also in the simplicity. Okay, so this is the base from which we are going to start, and we are going to look at a bunch of really exciting properties that you can build on top of this or that are actually inherent in this construction already. So the first thing that you can build from an OPRF is something we call a verifiable OPRF, and which is useful if you have some kind of iterated OPRF calculation, and you want to make sure that the server always uses the same K key correctly, and for that the server publishes a zero-knowledge proof that they actually used key correctly. This can be done for any OPRF really, but there are some OPRF constructions that lend themselves to more efficient proofs. So why is this useful? For example, imagine you want to have an OPRF calculation in which you provide privacy for yourself and the server cannot identify you later on. So imagine the case when the server is actually malicious and knows that you are you, but doesn't know who you will be in the future if it operates with this protocol correctly. So now that it knows that you are you and it wants to re-identify you, instead of using K that it's using for everyone else, it uses a specific K value only for you. And the next time you come and use this calculated OPRF value to the server, the server will see, "Oh, I'm not using the K value that I use for everyone, but I use this K value that I only use for you." And so this is how the server can later on anonymize you. And so for defending against this, you want to have a zero-knowledge proof that K has been used and verify OPRFs actually provide that. Okay, the next one as a property, as a partially oblivious pseudo-random function, this is exactly the same as the one that I showed you earlier. There's just one extra value. This is this tag T. This is a public value that also needs to go into the calculation of the OPRF. This might be known by the client and the server. This might be public. It might be sent over in any of that direction. But the thing is, this is a public value that is known by the server. This is not a secret value. And here you can see this is a very generic construction. This public value tag T is actually sent by the client to the server together with alpha. And then the server in this generic construction actually calculates a PRF. So this is the non-oblivious version. It's just a keyed hash, really. And it takes the input, the tag as the input for this PRF, and that generates a new key that is depending only on the tag and the key it has. And then that is being used instead of the key. So why is this useful? This might be useful, for example, if you have a username and the server wants to have a distinct key for each user. So in this case, the username would be the tag T. And this also helps the server, for example, to identify brute force attacks or to enable rate limiting. So if the server sees that user Bob has thousands of OPF evaluations per second, then it might say, hey, slow down mate. And so that allows rate limiting or any other security measure. Yes, there's another question. [inaudible] So the question was what R is. Yes, I am a bit sloppy in writing this down. It is a scalar on the field of... yes. So, okay, so that's the blinding factor. Yes, indeed. Okay, so that is a partially oblivious. You can combine these two with the verifiable and the partially oblivious one. But with hash DH, this is, especially in this way of its construction, is very difficult and not very efficient. Because for every key you need to publish a public key for the zero-knowledge proof. This other construction, this Dodis Jampols key, is actually one where this is efficiently possible. [inaudible] This construction is not very nice to combine to create a verifiable OPRF. Yes, yes. So there is more efficient constructions if you want to have a verifiable and partial OPRF. Okay, then you can have also the case when you want to do batching, which means you want to calculate an OPRF over multiple keys, like with the same message but with multiple keys. Or the other way around when you have multiple messages and you want to calculate them with the same key. And of course, if they can do batching, then that really means that this is more efficient than if you would do individual OPRF calculations. So this batching really is a performance property that is actually possible to achieve in some constructions. Okay, then a really nifty one is an updatable OPRF. In this case, you already have the results. So Alice has the result of a previous calculation of an OPRF. And then Bob says, "Shit, my key needs updating because it got compromised or because I'm just ratcheting my key, I need to regularly update my key." And so Alice doesn't want to recalculate a full OPRF with Bob with the new key. So with an updatable OPRF, Bob can send an update token so that Alice can update the previous calculation of the OPRF to be valid with the new key of Bob. And this is really simple, actually. So when Bob generates a new key, which is just a random number k', and then the update token, which we call delta, is simply just k' divided by k. And this update token doesn't disclose anything about neither the previous or the new key. And this delta is then sent to Alice, and she can apply this delta value to the previous result by just raising the previous result to delta, and the result will be as if she calculated the OPRF with k'. And I think this is a very elegant way. And this is also a way where you can actually... the update of the previous value can be done in a completely untrusted environment, which we will be in the practical part, we'll be seeing an example of. Then you have distributed OPRFs, where you don't have one key, but you have a bunch of keys, and all of them have to contribute to the calculation of the OPRF. This is really nice because an attacker, in this case, has to actually compromise all the key holders to actually have any security impact on this thing. So all of them need to be... And it's very simple because you just calculate OPRFs with each of the key holders, and then you just sort the values together, and that's the output of your OPRF. This is a distributed OPRF. It's very simple, can be easily instantiated from just any other OPRF. And then the most sexiest of all of them is a threshold OPRF, where you have the value key is shared among a bunch of shareholders, and you need T shareholders to actually operate on this key. And T is, of course, less than the total value of all shares that are existing. This is something like, show me a secret sharing, if you know that, where the key is distributed among the people. And indeed, you never reconstruct a key at all, but you do the operation. Each party operates on their share, and in the end, the client is doing the recombination in a way that the value key is actually never recalculated, never manifests itself in RAM or on disk or anywhere on the network at all. And this is a really nifty thing. And the only thing, if you combine it with a distributed key generation, then this is especially true. And it's really, really awesome. The only thing that you need to do for actually making this happen is this Lagrange interpolation in the exponent, which is something that took me quite some time to understand. But basically, you need to understand how Lagrange interpolation works, and then for that you need the Lagrange coefficient. And it's in mathematics that looks like this horrible form, but it boils down that you need to know the indexes of the shares. When you split your key into shares, then each share has an index, like this is the first share, second share, and so on. And you need to know the indexes of the shares that are used in this calculation. And so this ES variable is just a set of the indexes that are contributing to this calculation. And then you can calculate the Lagrange coefficient for each of the participants. And this is the Python code that implements the horrible formula above there. And on the right side you see this is a real world example of actually the numbers that you are working with, because the indexes of the shares are 0, 1, 2, 3. Maybe if you have a setup with five shares in total, then the highest number you have in this formula is 5, and the result are something like 3, 1, and -3. So this is not even high school math, but the formula looks really, really scary. But in the end, these are all public values. This is not even secrets or anything. You just need to know the indexes of the shares that are contributing so that you can calculate the Lagrange coefficients. Yes, sir? No, there's no trusted... The question was if the shares are trusted. No, the shares are like the shares that the value key is split into. The question is if there's a trusted person who splits this. You can do that, but if you use a distributed key generation, then there's no trusted leader. So there's no trusted... This is completely every node is... If you use it with a distributed key generation, there's no trusted leader. Every node is equal. This is how it looks if you do this. There's two ways. If you know in advance which shares are contributing, then Alice can actually... She knows ES. This is the set of the indexes. She knows that, and she can send that along. So as you can see, this is still the same thing as with the hash DH. And Alice sends over this ES set of indexes that we know in advance that are going to contribute. And all the server does is actually does two exponentiations here. First to their own key share and then to their own Lagrange coefficient, which the server can calculate using this formula or this Python code. And then that sends it back, and then all the client has to do is actually just multiply all the results that are coming back together and then unblind the whole thing, and then the client has exactly the same result as if the client would have done this in a non-threshold setting, where the value k is not split among all those people but is in one. Then it's exactly the same result. But most of the time, you don't know this in advance which servers are going to answer because some is DOS, some is in a safe because for offline backup purposes, or some is slow. So you just send your request to all of them, and then in the end you do the Lagrange interpolation. So in this case, actually the first two steps are completely the same as in a non-threshold setting. So the client is doing the same as in a non-threshold setting. The server doesn't even have to know this is a threshold setting. And then the only thing that is different is the client has to do this Lagrange interpolation in the exponent down here before the multiplication of all the results. And this is a bit more inefficient. This means that the client has to do a lot of computation. Whereas in the case when it knows in advance what is going to happen, then all the servers can do a lot of extra computation that the client doesn't have to do. So these are the two kinds of implementations or instantiations of how to do this. Okay, there are some other properties. I don't think I'm going to waste time on this. The only thing I'm going to mention is the three-party one, which is exciting. It's an OPRF where you have a message as an input, you have a key as an input, and the output is learned by a third party. So this is nice for pseudonymization or something. For example, you have a database, you want to anonymize it. So one has the database, one has the key that is doing the anonymization, and the third party learns the output. So this is a really nice compartmentalization. The rest is also exciting, but we're running out of time. Post-quantum OPRFs. It's not a success story, sadly. One thing that is really nice is that with hash DH and two hash DH-based OPRFs, the message is actually unconditionally secure. This is like with one-time pads. The one-time pad is also unbreakable as long as you don't use the same pad twice or more times. So an attacker can have unlimited computing power or unlimited post-quantum computers, and they will not be able to learn anything about the message that is the input to the OPRF function, which is super cool. The problem is that the value key, however, is computationally, so it's not post-quantum, and that sucks. So there are attempts at making all kinds of post-quantum OPRFs. Some of them that I listed here, I think one of them is already broken. Most of them are not very efficient. There's one that does actually a verifiable and partial OPRF, which I showed earlier, which is not so easy to do with two hash DH. But they are all not very efficient still, like all post-quantum things have huge keys and lots of computation. There is, however, a way if you don't need any of the special properties that I showed you before, you can just construct a post-quantum OPRF by combining oblivious transfer or multiparty computation with IES as the primitive that you do as a multiparty computation, and the result will be post-quantum. And if you use it with an oblivious transfer conversion, then this is actually going to be very, very efficient even. But it has no special properties. But it's post-quantum in all ways. Okay, so which to use of all of these? I didn't show you earlier, this Dodes-Jampolsky construction is the one that you want to use if you want to do partial, oblivious, and verifiable OPRFs. If you want to do something really, really quick, then just combine oblivious transfer with IES. And for everything else, you should be really using 2-HASH-DH unless you need updateability because an updatable OPRF needs the algebraic structure that is being destroyed by the auto-HASH. So that's my first part of the talk. And now let's see some practical examples. So the first one is a private set intersection. This is basically when two parties have two sets of values and one of them wants to learn which are the shared values in the two sets. And here what you can do is that one of the parties takes all of their values and calculates an OPRF over each of those values, kind of like encrypting in a non-decryptable way all of those values, and then creates a new set that is anonymized, or pseudonymized, or obfuscated, or whatever. And then this is a new set that you cannot really recalculate what was the preimage to that, and that is being sent over to the other party. And then the other party just calculates an OPRF for each of their values with the same key that has been used by the first party. And then if the OPRF output is exactly the same as one of the values in the set that the first party sent, then the party knows that this is a shared value. And so where is this useful? You can use it for contact discovery in messengers. So Vicker, for example, is using this for privacy-respecting contact discovery, which is, I think, super cool. And the other thing where you can use this is, for example, services like HaveIBeenPwned, which don't use this kind of stuff, but Google has a service which can tell you if your account has been leaked in some user database leak. And Cloudflare also has a protocol MIGP that uses private set intersection OPRFs to have a big database that you can query if you are in there or not. So this is private set intersection. Then there's another thing that is one of my projects. It's called Sphinx. It's a password storage. It's really just all that it's doing. It's an OPRF. So you have a server which might be a threshold settings OPRF, so multiple servers which hold a value k. And then you just input your password, and what comes out of it is 32 bytes, which with simple conversion, you convert into ASCII printable passwords, and then that's what you're using as a password. Yes? OPEC is going to come in later, but the question is how is this different from OPEC? OPEC is this love child between an OPRF and an authenticated key exchange. There is no authenticated key exchange. This is just a naked OPRF. And you can even force some certain output values. We have, if you have a pad that you sort the output of the OPRF with to the value that will generate the output in ASCII that you want to have. So the only limitation with this password store is that the only thing it can store really is about 45 character long ASCII strings. Or if you only use the number of digits, then it can be like 110 or so long strings of only digits, decimal digits. So this is not what you expect like these encrypted databases that everyone uses like Bitwarden or KeePass. It has a bunch of really nice security properties that these legacy password managers don't have. First of all, the password that, as I said, with OPRF, the input password and the output password is unconditionally secure. This is like a one-time pad. Then, because this is an online construct, you always have the whole thing forces you to only have online brute force ability. So with a GPU, if there's a leak of your database or password database, a GPU or FPGA will not be able to password crack your passwords because every test means they have to go to a server to ask for a computation and then come back. And that really slows it down. And then you can also say, hey, after 10 tries, enough. So there is no offline brute force ability of passwords in Sphinx, which is a really cool thing that you want to have. It's unconditionally secure, offline secure, offline brute force secure. And since there's no encryption, like with legacy password stores, you can actually have multiple input passwords for like the one that you regularly use for all the websites you don't care about and some that you care more about. So you can have multiple input passwords. And if the servers that you're authenticating to supports it, you can even have something like distress and panic passwords and your regular passwords. Depending on what you input, the output will be either your regular password, your panic password, or your distress password, which just notify someone, hey, he's in here, there's no alarm, but you know, or like we are deleting everything now. And an attacker will not be able to distinguish between those three output passwords. So this is a really nifty thing that you can do. So there's some URLs that you can look at. It's in Debian and it's basically mostly just a command line thing because it's not my thing to do the rest. OK, now OPAQ is a widely deployed instantiation of OPR or protocol based on OPRFs. This is a love child of an OPRF, an authenticated key exchange. And most common usage use scenario, we use triple DIPV-HERMAN, which is the same authenticated key exchange that is also used in the signal protocol. And really what you can do with an authenticated key exchange or OPAQ itself is from the client perspective, on the client you don't have any state, you don't have anything stored. The only thing that you need for OPAQ as an input is your password. And then using that password and the OPAQ protocol, you can have three things. The first thing is you can mutually authenticate each other to each other, the server and the client. And actually the server is first authenticated. And so the user actually knows that the other party is the server and then afterwards the user can authenticate themselves to the server as well if it's necessary. It's not always necessary. You can have data protected at rest on the server so you can store files there on the server and you can get access to them with only your password from the client. Or since it's an authenticated key exchange, of course, you can also just use this whole thing to set up a protected communication channel between the client and the server. There is a draft in the IRTF, the International Research Task Force Cryptographic Forum Research Group or something. It's kind of stable-ish now. There's an implementation by this, by me. It's called LibOPAQ. It has bindings to all the languages that you can imagine. But there's also other implementations like Facebook has one that is OPAQ Care and that is actually being deployed for WhatsApp. They store backups using OPAQ where the client only needs their password and their username and then they can restore all their data on any device if they know their username and their password. And this is a really cool thing. And I also implemented something like that. It is called OPAQ Store and it really goes well with Sphinx because Sphinx is very limited in storing data. And it shouldn't actually. And with OPAQ Store, you can do that. And OPAQ Store is the first public implementation of a threshold OPAQ instantiation. So OPAQ itself can also, because it's an OPRF underneath, you can actually, instead of using just a normal OPRF, you can also instantiate this with a threshold OPRF, which I did. And so you can store your data in a way that the keys are distributed among a bunch of servers or shareholders or whatever. And then there's one more thing. There's also work in integrating OPAQ on TLS level. And I think that's actually very reasonable because then you can eliminate client authentication certs. You can authenticate yourself to the server and based on the password also set up a protected channel, which is the right thing to do. I implemented also OPAQ for Sassle, which is this authentication layer for EMAP, POP3, FTP and so on. But that is the wrong layer of actually integrating this. I think this is the TLS level where this should be done. So I'm very hopeful that one day we will have TLS OPAQ. Okay, next topic. Privacy pass is an instantiation that is also widely deployed. Some of you might know that. You might have seen it when you browse websites using the Tor browser. Then you get these captchas from CloudFair that they want to actually know that you are not a bot and then you have to solve the captcha. And people don't like that. And so CloudFair came up with this privacy pass protocol, which when you solve a captcha, you can get a bunch of tokens, privacy pass tokens, that you can show to CloudFair later on when CloudFair wants to solve your new captcha. And instead of solving a captcha, you just pass on one of these privacy pass tokens. And this is used by CloudFair. But since a year, this exact same protocol is also used by Apple for the Web Environment Integrity implementation, which is now a big hoo-ha for Google that wants to do this in Chrome. I think you heard about that. And so Apple actually deployed this one year ago in Safari. And Google doesn't want to use privacy pass because it has two strong privacy guarantees and they want to have more invasive DRM. So fuck them. And so the whole thing is really a very simple protocol. Actually, it's just a blind signature over some tokens that you give that you, as a client, make CloudFair or Apple sign. And then later on, this blind sign token can be presented. It's a very simple system. But I think it's also a bit hypocritical because it protects you against CloudFair and snooping by CloudFair, while at the same time they are the ones that deploy the protocol, the implementation. So whenever they want, they can just play something else to you. And so this is Landau's law, which I warmly recommend to you and contemplate if it makes sense to deploy a security protocol implemented by the people that you want to protect against. This also applies to Signal, actually. And then the last one, this is the Verifiable Threshold Updatable Oblivious Key Management Service. Key Management Service is a data address service. Amazon has one of these. So with Amazon, there is a KMS service that you can rent. You have a client that wants to do things. You have a storage that is able to store data, but in an untrusted way. And you have a key management server that is good with handling keys or protecting keys. So that is most of the time. It's an HSM and storage is just some Amazon bucket or something. So this is how it works. There's nothing really exciting about this. When you encrypt some data, you generate a random key. You encrypt your data. Then you send the key over to the KMS server, who has their own global key that encrypts your unique key. And then that gets sent back. And then you can store the encrypted key with the data that it encrypts on the storage. And then the other way around. This is something that we are kind of doing since the 90s. There's nothing really exciting about this. I just wanted to show you. It sucks in many, many ways. The server knows all the encryption keys. The KMS knows all the encryption keys. You need to somehow encrypt between your client and the KMS. So you need TLS. If there's middle boxes or TLS terminators, then they also learn your decryption keys. They can trace the usage of these keys. And they're not updatable. Or if they are updatable, these keys, then those take a lot of time and are not very efficient. Also, one HSM is just a single point of failure and backups are not very easy. But you can solve all of these problems if you just use an updatable threshold OPRF, where the decryption key is really just an OPRF with a key that is stored at the KMS and the data ID. And that's it. And then there's this awesome paper, this updatable oblivious key management for storage systems by these three guys, Jaradzki, Krafchik and Resh. It's a brilliant paper. I warmly recommend everyone to have a look. And it solves all those problems. Okay, there's two implementations. One is by Jason Resh, who is one of the authors of the paper. It's called Protec. It's in Java. And it does a bunch of a lot more things than just implement the paper. And I have my own implementation, which is called Klucznik. And it has some URLs and you can stare at code and so on. The whole thing works like this. And I'm not going to go into detail, but basically we saw all the details during this presentation, how this works. And you can actually do the update. And this is the thing that is a bit interesting. How do you do a threshold updatable OPRF? Here you need, first of all, there's one hard requirement that you need to have more shares distributed than two times your threshold plus one. So that means you need a lot of threshold shares. All the shares need to participate in the update, otherwise they get out of sync. So this is a bit of a limitation. And then you just do a distributed key generation among all the shareholders. And then that is a new value. And then you just do a multiparty multiplication between this new value and the shared key, the old key. And so you multiply the old key in theory with this new value that you just generated. And then this new value that you generated is actually the delta token for updating on the storage. And this is really nice because you can send this delta token to Amazon, the storage, and say this is the delta token and Amazon is not able to use this token for anything but updating the key. And so this is all possible, but it's a bit more involved. So that is it. And so why this is super cool? First of all, you have very cheap key rotation. So that can provide you with forward and post-compromised security. The whole thing is a threshold operation, so you are very resilient against denial of service and loss of keys and compromise of keys. The master key is never stored anywhere at all, not even in RAM during computations. Whereas if you consider like PGP or AGE or something, then you have somewhere a key stored on your disk. Most of the time it might be even next to your encrypted files. And so it has drawbacks. First of all, it's online, but I don't know if that's really a drawback. In some cases it might be, in some cases it doesn't. And there's strong authentication needed. So the key management servers need actually to somehow authorize you if you are actually able to do the operation that you want to do. So that's something. But that can also be depending on the use case that you want to do. Okay, so they are cool. Mostly provide privacy, these OPRFs. You need to have two parties and they don't want to share all the information with each other. It's also very useful if you don't have anything, you don't want to store anything on the client. No data, only like a password when you want to convert low entropy something into high entropy cryptographic value. And it's very useful for rate limiting. Okay, there's a bunch of papers that I wanted to show as outtakes. Just shortly, these are all very exciting. So if anyone ever wants to play with OPRFs and do some cool shit, these are papers you might want to work with. And questions and comments at the Tea House. Thank you so much, Steph, for sharing your insights. As he said at the beginning, there's also a director's cut of this talk on YouTube. So check this out if you want even more details about this. And there's a Q&A at the House of Tea from 4 p.m. on if you have any more questions. [Music]