ZK13: openbanking.nr - Proving banking transactions onchain - Mohammed Mahmoud & Jack Gilcrest

24 May 2025 · 26:07

Mohammed Mahmoud and Jack Gilcrest of Attested Frontiers present openbanking.nr at ZK13, the Zero Knowledge Summit in Toronto, on proving banking transactions onchain. They walk through the cryptography behind open banking APIs, where a payment confirmation carries a first-party signature from the bank, and how that signed artifact can unlock an onchain escrow for onramping or settling real-world assets. The talk includes a demo built on Revolut using the Aztec testnet.

Speakers

Topics

Transcript

[Music] Cool. Good morning everyone. Uh really excited to be here with you uh talking about this. Uh so the idea is that we want to prove banking transactions on chain and uh how would that look like? Uh before I start, how many people are familiar with the open banking uh API? Do you know what open banking is at all? Nice. starting from scratch. Great. So, we can um we can we can trace back this all the way back to the start of the internet. We had internet banking in the early 2000s come in and then in the 20110s we started seeing um things like

GDPR, um banking as a service, APIs, everything was starting fintech revolution, Venmo revolute, the the big names. Um and there was a need to standardize all these APIs and that's what the open banking API standard standardization push started moving. 2015 we had a payment service directive in Europe which is an a a law that that forces people to forces banks and institutions to to enfor to enable this API standard and things went live around 2020 uh with open banking APIs. UK EU one of the most advanced um implementations but it's implemented in Australia, Brazil and uh Hong Kong,

South Korea, Japan and many countries are still adopting it and want to adopt it more. Uh cool. So why why is this why is this interesting? Uh I'll just explain really quickly how the architecture works in open bank in the standard. Uh just so you don't like so so we have a user that wants to enter um that has some some fintech application that they're they're using and they want to initiate a payment maybe like they're paying for some insurance cool fintech insurance thing and they instruct their their app to contact the bank on their behalf. you do an off similar to sign in with Google with your bank and

um the the third party app calls the bank and that those are the APIs we're talking about. It's the it's the link between the third party apps and the financial institution. That's where they um that's where the API standard comes in. And there are two types account information and payment initiation. We are interested in payment initiation because they're signed and that's the crux of what we're doing. So, okay. So the really cool part is you have a piece of data that says um this the status of the payment who it's going from who it's going to and uh this data this is signed by the bank basically as a first party signature and first party signatures are interesting because they have some legal

weight and they have legal precedence they have you can trace it back legally to the the person that signed it and it's the best kind of trust we can have. It's the bank that's saying this bank this bank transaction occurred. Um yeah digital digital signatures are like a framework in every major every major country um today. So they're very very like they have legal weight all the way um to understand a little bit how the signatures and the root of trust like who how do we know these public keys belong to the banks in the first place. So we can think of we can think of it as the initial starting point is the law right like the the law is what gives the power to any authority to run this uh route to become a root certificate

authority. So the law is our layer zero. It's L0 starting point. Um the law gives power to some trust authorities. In the UK it's one authority open banking directory. In the EU we have this IDAS framework for for trust services. There's like tens and more than 350 trust providers for different types of things. But we have a certificate authority and the certificate authority signs to the bank the certificates for the bank and then the bank signs the payment and that also has a certificate that you can trace. So the root certificate authority the root is 20 years. the root gives to the issuing certificate authority which

is also part of the the the the trust um world but we have 10 this one has 10 years on it and then the bank certificate is one year and then we have this server that's called OCSP I'll come to it in a second which is like a quick ping service to check if a certificate has been revoked or not and that it has a duration of 3 days. So, how do we actually verify? Like if we have a signature, the OB proof, open banking proof at the bottom. How do we actually verify this? Like what do we actually need to do whenever we're talking about signatures? There's two things we have to do. First of all, does the signature go back all the way to the to the root? Like, do we have a do we have a chain of signatures that

takes us all the way back to the to the root? And the second thing we want to check is has the certificate been revoked because it the bank could have done something wrong in the meantime or maybe there was a leak of some sort and the keys have rotated and they no longer valid valid. So traditionally like we have certificate um certificate revocation lists. Um we in a more modern era we have this OCSP um online status online certificate status protocol and um yeah it just tells you if it's good this is a sample of it over there it tells you if it's good when was it produced when it till when is it valid and where which URL you can access it on and the smart contract doesn't

have cannot go into the URL and verify itself so there is this technique called OCSP Stapling is whoever is proving go to the server get this uh recent um that just recent signature that says that this has not been revoked staple it to your application and send it to me and then I can just verify everything together. So with OCSP you're also verifying whether the signature goes to the root and you're verifying if the time stamp is with is still good if the if it's if the status is good as well. So this is like the the two things main things we need to do to verify an open banking payment. Uh just a quick summary about the cryptography that's used in open banking APIs. The certificates are X509

certificates very standard um certificate formatting. Uh the signatures are PS256. PS26 is an RSA uh PSS um signature. It's the formatting is JSON um web signatures very standard stuff and yeah the root authorities I spoke a little bit about and the signature you like this is what these are the information that comes with a signature uh when you des serialize it decode it sorry um yeah I'll just caveat something these these open bank APIs are are permissioned so you might ask can I just go now to my bank and call these APIs and get these signatures No, you can't.

We have to go through these third party apps and those apps need to be licensed and to become licensed, you need to, you know, do the usual things um like KYC, AML and and these things which we are going through right now trying to figure out like what is the best way to to bring something like this live so that people can use it. I'll now go to a demo that we did and let Jack explain more about the technical details. Cool. Yeah. Yeah. So, we'll get more into the specifics. Um, we got Yeah. So, uh, I will start with, uh, this is actually live at Bolt StopMoney.

We're having a little bit of issues with the wallet right now. So, uh, if you want to go use it, maybe wait a day or two for a PR to get merged. Um, but this is built, is it going? Yeah, this is built on the Aztec testn net. Um, so basically this is like a ZK P2P style on-ramp. Uh, it's kind of the most simple thing that you could build with, uh, open banking. Um, I will skip forward. So, first off, this part isn't very interesting. Um, you're basically committing to the bank account that you want to send money to, the currency you want to accept, as well as depositing uh some tokens in. Um, in this case, uh, you know, some stable coin. So, nothing really interesting is happening here.

Obviously, there's a little bit to talk about with like uh the bank account and currency you're committing to, but um yeah, I'm going to skip over that because it's not not cool. The cool part happens when you want to actually on-ramp. Um essentially what you're going to do is uh again like CKP2P uh you're going to go onto this app. You'll find a liquidity position that uh you might want to ramp through. You can see like this is Revolute. We haven't sent any transactions yet. Um, but okay, let's let's go on. So, all we want to do is we want to bring £350 onchain. And the UX for this is actually really nice, right? We get to hook straight into Revolute. Um, and you

basically just authorize your payment. And right there, that's where we got the signature. Um, so now we've actually acquired a signature uh over this payload, which we'll talk about in a second. You can see the payment went through moments ago. We've actually done a payment offchain. Now, on the other side, all we're going to want to do is uh prove the qualities of the open banking transaction uh and use that to extract the tokens out of the uh escrow.

Um, and again, this is done not with ZKTLS, not with ZK email. This is done directly with signatures from a bank. So, I'll I'll skip forward again. And there you go. Yeah, you got your money. Uh 350. So, that's kind of the flow. Um it's it's pretty convenient. Uh and again, the the trust assumptions here are very minimal. Um so, we're pretty excited about uh where that can be applied. But, let's actually go into um what am I looking for? What's going on? So you saw previously um some of the uh payload but this is an actual example payload. Uh this is what you would be actually getting from uh the open banking uh API.

You've got the domestic payment ID. Uh that's just something you would probably use as a nullifier so you can't replay a transaction. Uh but you really only need three things out of this payload which are the identification. This is like the blockchain address uh in in an analogy. It's your bank account number as well as the source code for the bank at least in the UK. Uh as well as how much you're transacting and what currency you're transacting with. And along with this being assigned, this is all we need really to uh basically link a bank transaction to the execution of a smart contract. Um again with the ZK proof. So if you want to see the circuit, there will be more QR codes later, but this is the actual uh Noir

circuit itself. Uh we'll go through it in a second. A little bit about it. Um it is a library. So like if you want to use it, you can obviously just import into like an Aztec smart contract. uh if you want the privacy layer. Um but you can also just very easily import it into like an executable and create verifiers for uh Solidity and Starknet are two that exist currently with uh NRG4 going on. You're going to see a bunch of new uh destinations for proofs as well. Uh so that's really nice because again you get to leverage uh kind of the extensibility of Noir and put this in a lot of different places.

Um, this circuit is also set up specifically for UK domestic payments, but as we'll look at when we're parsing the JSON, um, you just have to know what to look for, like what fields you want to extract. And if if you wanted to mutate this, it would be very simple. Uh, as for the execution itself, it's 250,000 plonish gates. Not super meaningful. What is is the actual proving time, which is uh about 4 to 7 seconds on an M1 Mac. Um, and there's also MoPro, if you're familiar, uh, has very recently uh, begun supporting Noir.

So, I think you would get very similar performance actually out of a mobile app, uh, while using this. So, uh, I mean, it's not instant, but it's it's very fast as far as proving goes. So, we'll walk through kind of the the three different buckets of of of logic in the circuit. The first one is we have this JWT payload. we want to actually authenticate that we're allowed to work with it. Um, so we're going to take our JWT and we're going to do something called partial hashing. If you're not familiar, it's just a way to get free gates. Essentially, you partially construct a hash outside of a circuit and then you finish hashing inside of the circuit. You only include the computation of the hash uh for the parts of the pre-image you want to uh

operate over. So, um, yeah, we're just going to take the pre-image, we're going to finish hashing it, and then we're going to verify, uh, the PS26, uh, signature over that payload. And once we've done that, we've basically authenticated that, uh, whatever JWT we're working with is valid, and we can go on to extract information out of it. Um, okay. So, and it's a JWT, which means you're going to see like header delineated by a period and then the body. So, we need to sanitize it a little bit for the JSON parser. Uh, so that's all this probably could be prettier, but um after we've done that,

we've basically just got uh a standard JSON object and uh we'll just use the noir standard uh library for parsing JSON. So, um Whoops. So we'll we'll just basically take the entire payload that we've now sanitized, pass it in. This is a little bit of an expensive setup cost uh to parse this entire JSON object, but once we've done that, selecting out keys and operating over it is is very convenient. So now we've got our JSON object and and we can actually operate with it. And then finally, um so I guess if really quickly we look, we'll see that like some of these are nested objects.

Um, so we might need to like traverse through this JSON object, select key to select another key, but essentially we want to get back out these values. And functionally, this is just doing that. It's finding the key for like uh amount or currency um and then just taking the value. And for for amount specifically also like if you're doing like uh like the on-ramp for instance if you're transacting value there's going to be a little bit of an extra step of like transforming the asky characters into uh the numerical values uh that is in the contracts in this repository but we don't actually include it in the verification logic directly uh

cuz you know there's cases where you might not want to parse that and it's extra constraints but you just have to do a little bit of transformation there to actually get a numerical value and you can do whatever like financial logic you want in a smart contract with that. Okay. So, we've we've proven the validity of uh an open banking transaction, but like what does that really mean? We've signed it by who who signed it? Um, obviously outside of a smart contract, there's all this infrastructure for looking up the uh basically root of trust and verifying stuff. It's it's pretty straightforward.

Um, on chain, it's a little more involved, right? we need to in one manner or another uh get the root of trust on chain. So the ab like the thing you absolutely have to do is you have to get the root certificate at least the first one on chain. Um and from there you can kind of build the rest of your registry. Um you also like I'm I'm not going to dive into the complexities of exactly rotating the root certificates but at the very least you know you want some sort of logic for being able to handle the transitions when they happen like every decade. Um so you know some sort of cross-signing verification. Um but okay we've got our root certificate.

We have uh kind of two approaches that we can go about uh kind of verifying the chain of certificates right um and the first way is just to deal with the root certificates. All right. And and the reason why this is nice is because there's not like a lot of extra infrastructure we need to consider. Um we just tell the prover you're going to have to go verify the search chain. Um, and they don't have to worry about like any sort of like service that is uh responsible for making sure the current registry of like interstitial signing keys is up to date. It can just go get the chain and validate it. Um, the reason why that's undesirable is because you're introducing uh an extra signature verification as well. Like you're you're

checking the root signature over the uh signing certificate. then you need to parse the signing certificate for its public key and then do a second verification. So you're introducing a bunch of proving costs and that will impede the user experience. Right on the other end um we can just cache essentially or register the signing keys and this is nice because we get to have the user basically just do one single signature verification. Problem here being though like what happens if there's a new signing key that appears and that hasn't been registered? you either have to have the user put a transaction in first themselves to add that key or you need to have some sort of either incentivization or centralized

service that is posting these keys as quick as possible and even then there's still like these edge cases where maybe like someone sneaks in before it's it's verified and also hurts the UX. So, um unclear which the best one is. We'll figure that one out, but either of these eventually work. uh and and that's kind of how you would actually establish authenticity on chain. The one caveat here is that these certificates don't they're they're not valid just because they exist. They can be revoked. They can expire. Um and the the basic way to check if a certificate is valid or not is a CRL, a certificate revocation list.

And this is an example of one. It's pretty small. Um but you could imagine as time goes on and the CRL gets larger and larger uh proving inclusion or exclusion uh especially exclusion in uh a CRL would get prohibitively expensive. Um so this is where OCSP that Muhammad spoke about comes back into play. um you know we can uh essentially the same uh roots uh authority will have uh authorized attestations from an OCSP server which will basically give you time stamps that say uh this certificate is valid until this state. Um and you would just basically have to include that with whatever certificate you're using to basically prove it's not

revoked. And this is a pretty foolproof way to do that. Okay. Um how are we doing on time? Okay. Um, so there's some other stuff we could talk about. Uh, especially like removing cryptocurrency. Uh, like one of the things that we're very excited about is like basically we can sequence in bank proofs and and use these to recognize payments on chain. So I can run through that if there aren't any questions. Uh, but if there are any questions, I guess we can do that first. Can you cl Yeah. So

yeah. So basically what you're going to do is you're going to uh initiate a bank payment through the open banking API. You saw like in the demo we went through the Revolute kind of like pop-up modal that initiated a payment. Everything went through and then there was like the white screen that said payment authorized. Not very pretty, but they gave us the signature there. And now we have this. Sorry, where's my We have this with a signature over it. Um, we've already made an off-chain payment before we've even talked about the circuit. Uh, the the entire off-chain payment has already occurred. What we're doing afterwards is we're taking this, we're doing like a little pre-processing maybe, but we're taking the signature over this as well as this payload. We're

authenticating it in the circuit. We're parsing it out. Uh doing all that stuff after we've already gotten the payload. And then also we might go on chain and like you know release tokens from an escrow or um do some other logic. But basically the entire like offchain thing happens first and then all of it is retroactive. So like checking that stuff happens or um it would happen well okay so part of that is like kind of the split of like how do you want to uh register this? I'm I'm going to assume that we're just having only the root certificate on

chain. Um, obviously you would check the certificates before you even initiate a payment, but once you've initiated a payment, you're going to uh basically take all that uh certificate data as well, pass it into the circuit and prove it. Um, and this is like because I I guess theoretically you could reveal which bank you're using, but you can uh especially if you're using Aztec, it's it's simple. We're doing this in the Aztec paradigm, but maybe you're on the EVM and you merkelize like all of the certificates. um you would want to obstruct which bank you're using to transact potentially. So um you would do all of that in circuit as well. Yep.

Uh is your project related to ZK P2P or ZKTLS? Um do you how much do you know how much does everyone know about ZK peerto-peer or here? You familiar with it? Okay. Um it's not related to Zik peerto-peer at all, but I'll tell you where it's located, where it's um connected. Ziki peerto-peer is a is an on-ramping off-ramping marketplace, right? Trustless marketplace. What they did initially is they've um integrated Venmo uh as a starting point and then they moved to the TLS approach and they started integrating u revolute and different ones. But they quickly realize they cannot like each one each connector each bank takes an overhead of doing to to to define it on the system doing open

you can think of open banking as like one API that will just on board UK EU in one go. So if we are able to use this one of the first things we could do is just what once we're licensed is to just to plug it into ZK peer-to-peer as as a as a form of connector because ZK peerto-peer cannot build connectors for the rest of the world. That's what they realized. So they will just leave that burden to people who really care about their own local offramping to build their own connectors. So this could act as a connector. That's kind of the link between them if you want to think of them conceptually. If there's no um question, I'll just finalize by just saying something about um that something that we're really excited about is uh yeah,

this this idea that actually with this you don't even need, you know, this whole like we we we thought we're going to ask businesses to go and get a MetaMask and download, you know, figure out how to on-ramp, which is a huge overhead for businesses and even normal people. But with this, there's potentially a path where we don't even have to do that. people can still take part in escros and smart contracts without the need to go and manage their meta mask and like get a figure out how to on-ramp and do these things. So yeah, this is like one of the really cool exciting features of this that we are excited about that we want to lean on and explore as much as possible.

Yeah. Okay. Um, there are some QR codes. Uh, this is just our website. Uh, this is the app. This is the code that we showed you. And, uh, this is like a pretty extensive write up on open banking as well as openbanking.nr. Uh, if you're interested in following up on that. Um, I guess we forgot to put a telegram in there. So, um, do we have Oh, yeah. Yeah. Uh you can you can also engage with us here if you're interested. Uh we'll be here the entire time as well.

So very interested in like exploring open banking and as well uh all first party access stations. Um right like Idas uh this is obviously tied to Idas but um the identity infrastructure as well is very interesting. Um you know PDFs that are often signed with Idas through stuff like docuign actually verifying like the contents of like legal agreements. Um yeah, anything that has to do with uh attestations uh trying to make interesting statements about them is is kind of what we're looking at uh ultimately trying to drive uh this kind of future where all these things are are working together to build more complex proofs. So,