 Hi, everyone. I'm Ethan Heilman, and I'll be talking to you about my work on CRLP. So in this talk, I'll present our crypt analysis of CRLP 27, a hash function, which until 2018, when we published this research, was used to compute signatures and IOTA cryptocurrency. And in our research, we extend this attack to break IOTA signature scheme for even valid payments. In this talk, we won't be covering the full signature attack, but see our paper or asking questions about it. I have some extra slides, but unfortunately, there isn't time to go into those details. So what is IOTA? Well, when we were doing our research, IOTA was one of the largest cryptocurrencies focused on IOT, I think was the fifth or fourth largest cryptocurrency by market cap. And it had partnerships with several large companies. Bosch was quoted as saying they had purchased a significant amount of IOTA tokens and Volkswagen talked about releasing IOTA-related product in 2019, although that doesn't appear to have happened. So why is this interesting to look at? Well, IOTA uses balanced ternary instead of binary. So ternary is base three, binary is base two. So rather than bits, zero and one, IOTA uses trits, minus one, zero and one. Instead of 8-bit bytes, IOTA uses three trites. And you'll hear me use the term trit a lot. And I'm just referring to base three unit minus one, zero or one. So the hash function that IOTA uses, Coral P27, is a ternary hash function. So rather than bits, it is using trits. And IOTA uses a variant of Winternit's one-time signatures for their signature scheme. Winternit's one-time signatures are a hash-based signature scheme. And they haven't seen much practical deployment. So this is interesting to look at because it's a deployment of Winternit's one-time signatures used to secure large sums of digital currency. And we can look at attacks and see how these signatures may fail in practice when they're deployed. So as previously mentioned, IOTA builds on Winternit's one-time signatures. But it makes a change to how normally Winternit's one-time signatures are thought about. So Winternit's one-time signatures often have the property that the signature is proportional in size to the message which is signed. So if you have a large message, your signature is also of the same size as your message. But this is not an attractive feature in many cases. So to ensure that signatures are of constant size, regardless of how large the message is, IOTA's signature scheme hashes the message down. So we see the message M come in and it uses curl P27 to hash the message down to a constant size. And then it uses its variants of Winternit's one-time signatures to sign this hash of the message. And that way signatures are always the same size. The size of the signature does not vary with the message. But as a byproduct of this, if you have two messages that hash to the same value, say message one and message two, they both hash to the same value, that is, there's a collision, then a signature on message one, a signature on the hash of message one, is also a signature on the hash of message two. What this means is that an attacker could perform a chosen message attack against this signature scheme by creating two messages that collide, one of them harmless and one of them malicious, and then asking another party to sign the harmless message. And then when they see the signature on the harmless message, they can use that same signature on the malicious message. Now getting a chosen message attack to work in a cryptocurrency setting with payments is a little bit tricky. And we exploit the multi-sig aspect of the IOTA signature scheme to perform this and read our paper for the full details. And we won't be discussing them in any detail. So what we want to do is we want to create two messages that hash to the same value under curl p27. We want to break the collision resistance of curl p27. And to do this, we're going to do differential crypt analysis. But slightly different because we have to do differential crypt analysis on ternary, which is minus one, zero and one. So let's look at how curl p27 works internally. It's built on the sponge construction. So you have a message gets broken into message blocks. The message block is put into a state. A transformation function t is called on the state to generate a new state. The next message block is then put into that state. The transformation function is called again and so on and so on. And then once all the message blocks have been absorbed, a final transformation is called. And the first third of the state is the output. Note that security depends on the transformation function. If the transformation function is bad, the security of the scheme is likely broken. For example, the identity function would be very bad here. But this works a little bit differently than many, many other sponge constructions because when we take the message block and we put it in the first third of the state, we don't XOR it into the state or add it into the state. This actually just overwrites the state. So if we have two messages and they have a different message block, like message block 1A and message block 1B here, and after running the transformation function, all of the differences exist in the first third of the state. Then when the next message block comes along, it will just overwrite those differences. So our plan is to figure out some way of getting all the differences into the first third of the state and then using the next message block to overwrite those differences and cause a collision. So let's dive a little bit deeper on the transformation function. So the transformation function is actually just repeated calls of this round function RF. And in curl P27, the round function is just applied 27 times. The round function is always the same. It has no round constants. So you just take the input state to the transformation function and you apply the round function to generate a new state. Then you apply the round function again and do that 27 times. And then the last version of the state is the output of the transformation function. And this transformation function is very, very simple. In fact, it's just an S box applied to the input of the state. So each trit in the input is mapped to is read into an S box. And then the S box produces one output trit. And we can see the S box here on the left. So because it is always one trit can only influence two S boxes, if we change a trit, the change can at most diffuse to one or two other trits. So in this case, the change has diffused to two other trits. But it's also possible where it just diffuses to one other trit. So what we're going to try to do is we're going to try to prevent diffusion through many rounds. So in this case, we have a single trit difference here. The round function is applied. And we still have a single trit function here. A single trit difference here. Round function applied again. Single trit difference. So our plan will be to create two message blocks that differ at only one trit. We'll ensure that no diffusion takes place for many rounds. And we'll do this so that we can arrange that all the differences end up in the first third of the state. So by the time diffusion occurs, there's so few rounds left that we can arrange for that small number of differences to be in the first third of the state. And then they'll be erased by the next message block. So to figure out how many rounds we have to arrest diffusion and where we should put our one trit difference, we ran a large number of experiments. And here we graph the output of these experiments. So along the x-axis here, we have the position that the one trit difference is in. Is it in the 50th trit? Is it in the 100th trit? And along the y-axis, we have the number of rounds before diffusion occurs. And the color is just the probability that a collision results from this. So for position 17, we see that if we prevent diffusion up until the 20th round, the probability of a collision is basically one or guaranteed to have a collision. So this is our plan. If we can prevent diffusion for 20 rounds, we win. We will cause a collision. So just briefly visualizing difference propagation in curl p27. This is what it normally looks like. You start with a one trit difference. It slowly diffuses, slowly diffuses. And by about the 10th round, it's diffused throughout the entire state. If you prevent it for nine rounds, it pretty much diffuses through the entire state by the 18th or 20th round. And then what our goal is shown on this third version is no diffusion has occurred for 20 rounds. So you can see by round 20, diffusion starts occurring, but it is so small, but it's so late, and it's so few rounds that by the 27th and final round, it hasn't diffused through the entire state. And because we chose position 27, where it has diffused is in fact within the first third of the state and will be erased with the next message block. All right. So let's look at the S box and look at the probability of no diffusion occurring in a single round. So when a zero is changed to a one, the probability is one third or three out of ninth. And we can just see this trivially from the S box. Minus one to zero is also one third. And minus one to one is zero. And you can see why because it's perfectly balanced. Whatever you change will result in a change. So let's look at this through multiple rounds. We use the symbol, this like circled minus symbol, to mean that that is a change from A to B. That is, it is a difference. So in our state machine, if message one at the one-trick difference is zero and message two is one, we use the symbol to represent that. So let's say we start with a zero to one difference. In one out of nine cases, we will just return to this state. In six out of nine cases diffusion will occur and we will treat this as a failure. And in two out of nine, the difference will change but no diffusion will occur. We can take this state machine and turn it into a matrix to calculate the probability for K rounds that no diffusion will occur. So given a one-trick change at the beginning, what's the probability we can prevent diffusion for K rounds? Well, we want K to be 20 or higher. 4K is equal to zero rounds. It's two to the minus 47. So basically using this attack, we have 47 bits of collision resistance in curl P27. And note that no diffusion for 20 rounds results in a collision. So the way in which we find collisions is we choose a random message, we flip a trit. And if we flip the 17th trit, the probability of a collision is one over two to the 47th. And if we're clever about choosing the message rather than just choose a purely random message, if we fix some of the trits, we can ensure that diffusion won't happen in the first few rounds. And this actually significantly boosts our probability of getting to the 20th round without any diffusion. So if we choose our message carefully and we fix some of the trits, it curl P27 has about 23 bits of collision resistance. So as collisions are very likely, we try many messages. One of the things that IOTA transactions have that make our attack much easier is that they have a data structure called a tag. The tag has no impact on validity. It's not used anywhere else. Generally, it is just used to put in messages like I heart IOTA. So we can just randomly change this field. And so once we choose a payment that we want to perform this attack on, we can just exploit the fact that there's this tag to try and find lots of collisions. So generating colliding IOTA payment takes about on average 15 seconds on 80 core machine. This average is averaging over 5,000 collisions that we found. And just to look at this in a little bit more detail, the paper has much more detail on this. We wanted to do this for valid IOTA payments. So we created two payments, message one and message two that collide. And message one pays Alice 29 million IOTA. And message two pays Eve 29 million IOTA. So Eve can show Alice message one, say sign this, look, you get this 29 million IOTA, Alice signs it, and now Eve can use that signature to authorize message two because message one and message two both hash to the same value. So let me show you a quick demo, a video of us running this attack. So we run our crypt analysis code on AD CPUs. Now we found a collision. We're actually going to generate a second collision. And this is necessary for making a valid IOTA payment. These are our two bundles. Bundles are what they call payment in IOTA. We see that they pay different amounts, but that they collide to the same value or they hash to the same value. And you can see that IOTA, they passed a validation check. So they were, in fact, valid messages inside IOTA. So we disclosed this vulnerability to IOTA developers in response. They replaced Curl P27 with a hash function called Curl with a K, which is based on SHA-3. And you can see the places, this might be a little bit out of date, but these are the places where they still use Curl P27. And then Curl P81, which has 81 rounds and then Curl with a K. And I believe they're moving away from Curl with a K if they haven't already done it. Interestingly, IOTA and CyberCrypt work together to develop a new ternary hash function to replace Curl P27. It looks really cool. You should all go check it out. And they ran a crypt analysis competition for this new hash function. So in response to our vulnerability disclosure, IOTA claimed that the weakness was actually put into the hash function intentionally as a copy protection mechanism. And so I don't know if it was a backdoor or not, but I asked them, did we discover a copy protection backdoor in IOTA? And they wrote the answer to my first question is, of course, yes. I believe this is, you can read this on their blog. So it's kind of interesting to think that people are taking cryptographic hash functions and potentially adding vulnerabilities to them for the purpose of copy protection or exploitation. So the signature forgery attacks presented in this talk, as I stated before, we disclosed them to IOTA developers. They deployed mitigations and they no longer impact IOTA security. And at no time did we send any of these forward signatures or payments to the IOTA network nor did we interfere with the IOTA network in any way. We ran all of our validation offline. So in conclusion, we broke the collision resistance of Curl P27, a ternary hash function. We exploited this to perform a chosen message attack forging signatures on valid IOTA payments, such that the payment one pays EVE, one IOTA, and payment two pays EVE, 129 million IOTA. For more details, especially about how we engineered these IOTA payments to be valid IOTA payments and how we exploited multisig to perform a chosen message attack, please read our full paper. Also, you can download our proof of proof of concept and crypt analysis tools if you want to create your own IOTA collisions. Questions?