This is a raw transcript with a medium level of automated cleanup.
Christopher Allen: Just hit the record. Thank you, everybody, for joining us. I’m going to wait just a couple more minutes, but I think we have all the key people. Thank you for your participation.
Just a heads up, we’ll be talking about this a little bit later, but we are planning two more full-featured FROST workshops in the fall. One really focused on the cryptographers and implementers to share progress and status and challenges and future capabilities. And then another more on the library developers to the wallet developers to talk more about the challenges of implementing, of deployment, and things of that nature. So we’d really appreciate it if any of you are interested in doing a 20-30 minute presentation with Q&A on either of those topics. Let me know. We haven’t scheduled it yet because everybody has different conferences and events. So we’re going to schedule it based on the first presenters who want to show something. So let me know.
Okay, I’m going to go ahead and start. So welcome to our Gordian Blockchain Commons FROST CLI meeting. Today is August 6th. Just a bit of a recap, what is Blockchain Commons? We’re a community interested in the self-sovereign control of digital assets. We bring together stakeholders to collaboratively develop interoperable infrastructure. And our goal is to design decentralized solutions where everyone wins. And to do this, we are a neutral not-for-profit to enable people to control their own digital destiny.
I want to particularly thank today Human Rights Foundation. This is now the second grant that they’ve given us to continue our support of FROST, and that’s greatly appreciated. If you’re interested in becoming a sponsor of this event or of other Blockchain Commons work, please let me know.
For our agenda today, we’re going to be talking about two great tools. The first one is the ZF FROST Library in Rust, which is available at the Zcash Foundation, and the Bitcoin Developer Kit, sometimes called BDK. So that’s what we’re going to be talking about, at least in the beginning.
So our puzzle was, how do we combine ZF FROST, which is a more generic toolkit with the specific needs of BDK for Bitcoin, partially signed Bitcoin transaction signing. So fortunately, the libraries for ZF FROST do offer a preliminary SECP256K1 BIP340 Schnorr signing. However, some of their tooling for CLI and server, et cetera, did not enable that by default. So we had to enable that. And we’ve been calling that at this point, the SECP256K1TR cipher suite in our fork of the tool. But you still need to have BDK apply the signature with a tweak in order to avoid a certain class of taproot attacks.
Also, BDK doesn’t allow in the command line interface you to export the transaction hash. It has some options in the library to deal with tweaking, but it’s not clear who should do the tweaking. And it’s also somewhat of a challenge to reinsert the signature. Some of this is all available in library functions, but is not exposed when you use their CLI. So we needed to address all of that.
So again, we’re building on existing FROST CLI tools. That’s the link to the tools. We have submitted a PR for the SECP256K1 cipher suite to the FROST tools. And then we have a branch which does the taproot tweak on top of that. And again, with BDK, extracting the hash wasn’t available on the CLI. So we wrote some code for that. Tweaking is an external process. And we’re doing that separately. But there’s some interesting questions of when and how it should be done.
Again, reinserting the signature was not available in the CLI. So we had to do some libraries to do that. And then, as we’d been doing some research on tweaking, there may be some privacy concerns with how tweaking is done today. When we look at various people who are talking about the particular attack, in fact, tweaking may not be necessary in distributed key generation scenarios. So these are all things we’re going to be talking about more after the demo, but I just want to have those on the front of your mind.
So again, the demo is we’re going to be spending a Taproot Bitcoin transaction. We’re doing this for ease and speed on a private regtest network using a two of three FROST. Wolf is going to demonstrate creating key shares, creating a PSBT, running the sighash helper, signing with FROST, injecting the signature and transmitting it and verifying the transaction. So Wolf, do you want to take over?
Wolf McNally: Yeah, thank you, Christopher. I’m Wolf McNally. I’m the lead researcher for Blockchain Commons, and I’ll be going through the demo Christopher just talked about. The demo is up on HackMD. You can replicate these results yourself. Let me put that in the chat real quickly here. So in the chat now is a link to the HackMD document. We’ll make sure that’s on the YouTube comments as well.
So I’ll be basically following these along in my copy of this in Visual Studio Code. So I’m going to share my screen here. Move stuff around here. Okay, so let’s actually pop in Visual Studio. All right. So here you’re seeing the top of the document here, demonstrating FROST signing using BDK CLI. There’s quite a few steps involved, but they should all be replicable by just doing them in order that you see here.
Some of them I’ve already done, so I’ll skip over some of them. Obviously, cloning the repo would be the first step, and then checking out the taproot tweak branch, which is the branch that Christopher mentioned, which not only implements the SECP256K1TR cipher suite but also adds the taproot tweak on top of that to make the signatures that it produces compatible with the Bitcoin blockchain.
So the next thing you have to do is install it. So this presumes you’ve already installed the Rust toolchain so you have the cargo tool. So you cargo install path frost client in the directory. This installs several tools including the three we’ll be using which is the frost client, the coordinator, and the participant.
Then next thing you have to do to replicate ours, because you could use a testnet or whatever for this, but we’re using regtest, which is a dedicated Bitcoin node that we can fully control and therefore we don’t have to wait for blocks being mined or things like that. So we’re creating some, this is again, stuff I don’t need to do right now because this installs the actual bitcoind and sets up the bitcoin.conf, but you can see it’s just very basic setup here.
Next thing to do is start the bitcoind daemon and I’m actually going to show that running here. So I’m not going to run it in daemon mode, but I’m going to run it in terminal mode so we can actually see what it’s doing. Oops, bitcoind. There we go. All right. So this is actually a fresh…
Christopher: We’re not seeing the terminal interface just…
Wolf: You’re not seeing the terminal interface. Okay. That’s interesting. Okay. Let me see what’s going on with Zoom here because I believe I shared my whole screen, not just a window, but let me double check that. Let me actually share screen. Interesting. Well, this is a perennial issue with Zoom, that for some reason, even though I am the host of the meeting, I cannot share my full screen, so I have to settle for sharing Windows.
So there you see the actual bitcoind running. All I’ve done is type bitcoind and press return and basically it’s setting up a new blockchain because I deleted the previous regtest folder in my bitcoind folder. So basically it’s just waiting for things to happen. So this is going to be a bit annoying as you can see it’s just doing its background refreshes and so on. So okay, most of the time we’ll be spending in this window anyway so I shouldn’t have to back and forth too many times.
So anyway, this is the step I’ve just done. And the daemon is now listening on a local port. The next thing we’re going to do is we’re going to set up two wallets, a regular regtest wallet, which is going to be sending to the FROST wallet, to the FROST quorum, controlled by the FROST quorum. And then we’re going to demonstrate the FROST quorum sending money back to the regular regtest wallet. And that’s the tricky part because that requires the actual FROST signing ceremony of the two out of three participants.
So the actual commands you see here are just unadorned and I have sample output here, which has these vertical bars by them. So you can easily distinguish input from output. So these are basically Bitcoin CLI commands. These go to the bitcoind and you’ll see the output below that. I’m going to use a feature in VS Code that allows me to press control enter and execute the commands.
So here you see that those commands are executed. Those numbers here are the blocks that were just mined. As you can see, I executed three commands here. One actually creates the regtest wallet locally, one that loads it, and one that generates 101 blocks. And the reason why we generate 101 blocks if you’re familiar with Bitcoin is because you cannot spend, actually the first 101 blocks in any blockchain are not spendable and then any miner that receives a reward for mining a block has to wait 100 blocks before they can spend it. So now the chain is mature enough so that the blocks, the new blocks on it are spendable.
The next step is to build the sighash helper tool. Now there’s two helper tools and this is because BDK CLI doesn’t have a way to extract the transaction sighash, which is what we need to sign from the PSBT. So I’m not actually, again, I’ve already done this, but this actually shows how to set it up from scratch, creating the project, how to set up the cargo.toml, which is the dependencies it needs, and then the actual Rust code. And all this does is basically use the, it basically just reads the PSBT and then extracts the sighash from it and prints it out. Then you build it and install it.
The other tool which you install next one time again is called psbt-sig-attach. Again, it gives you how to set the project, how to set your cargo.toml, and then this actually uses BDK to actually read in the transaction and then extract only input zero. Now that’s part of what makes this demo unrealistic is because we’re only using one input and one output, because of course every input UTXO needs to be signed separately. And if they’re all controlled by the quorum, then they would all need to generate signatures for that, which would presumably be automated. Since nothing is automated right now, and especially since we have a fresh blockchain, we’re only going to be using one input anyway, we only are attaching the signature to one input. So you build that.
And now we’re in the mainline demo here. So everything above that is stuff you do one off. The only thing I actually did was start the blockchain. So now I’m basically going to, there we go. So I’ll be executing, I’ll be selecting blocks of commands like this and then pressing control enter. When I do this, you see it’s basically just setting up a number of environment variables here, including the demo directory that we’re using. Before I run that, it needs to be up one level, or it’s going to create a demo directory within the demo directory. Okay, so I’m going to execute that now.
Okay, so now you see I’m in the demo directory, and if we look at my hierarchy here, you can see I have inside the frost-tools, which is what you check out. I have a frost BDK for my demo. This includes the two tools I’ve built, includes the demo directory I just created with the folders in it for the FROST wallet and the regular wallet. We don’t need to pay too much attention to what’s here, but I’ll refer back to a couple of times. You’ll see additional files being added to it as we go through this.
All right. So, and everything in the demo directory is deletable to reset the demo. And if you want a full reset, then you also erase the blockchain, start the regtest blockchain and start again. Again, nothing here is production ready. Everything here works, but we consider it to be fragile, not ready for production, but we’re going to prove the point that we can send money back and forth between FROST quorums.
All right. So the next thing we’re going to do is generate the BIP86 master key and signature. And this is basically for the regular wallet. So we’re telling BDK CLI to actually generate the key for the wallet and creating the descriptors from that. Now, the sample output here obviously is not going to be same as the actual output down here but it should resemble it very closely as we go through this.
Next thing to do is again we’re working with our regular wallet so we’re going to tell BDK CLI which is managing these wallets to grab the next fresh address that we’re going to actually send money from the blockchain to. We’re going to mine a new block directly to our wallet here but we need an address to send it to. So this basically says we’re working on our regtest network. Here’s our data directory, wallet subcommand, and then basically all the other things you need to create a new address and to extract that address. So we’re going to then echo that to the terminal. There’s a new address, begins with bcrt1, which is a regtest testnet address. Again, it’s not the same as above, but that doesn’t matter for our case. Everything down here is what we’re actually working with.
Next thing to do is to mine a block straight into that address and to that we tell Bitcoin CLI on its regtest networks to generate to the address that we just generated. And there it is. So this is basically the block ID of the block that was mined and the funds are basically now on the blockchain for this at this address. We also need because this is a mining operation we need to mine a hundred more blocks before that block is spendable, before that reward is spendable. So we’re going to just do that right now. As you can see there’s the IDs of those blocks that were just mined and they were also mined to a new random address because we didn’t, so presumably those went to other miners.
All right so now we’re going to let BDK notice its money so we’re syncing it with the blockchain. This is a sync command and the balance command to actually show us the current balance. Okay, so as you can see, there’s 5 billion satoshis, 50 bitcoins in the confirmed balance. That’s the block reward where we mined that block. And that’s confirmed now because we mined that with 100 additional blocks in mind. If it were not confirmed, it would be under immature, basically being not spendable yet.
So now we’re going to create the other wallet where we’ll be using the FROST wallet. And in this case, we can’t create the FROST wallet without having the actual key material from the FROST quorum. Now, there’s two basic ways of generating this material. One is called Trusted Dealer, where the Trusted Dealer itself is a process that actually generates the private key and then splits it and distributes that to the participants. The other form is called Distributed Key Generation.
In the FROST tools libraries from the Zcash Foundation, they’re working on distributed key generation, but it’s not fully functional yet. But the workflow for Trusted Dealer is working, and that’s what we’re using here. In any case, it would make a considerably more complex demo, but the algorithms are fundamentally the same. Ultimately, the nice thing with distributed key generation is the private key never exists in one place ever, whereas here it exists in the Trusted Dealer for a very short period of time, but not afterwards.
So as you can see, we’re giving a threshold of two and a quorum of three or a total number of participants of three. And we’re definitely telling it to use our SECP256K1TR cipher suite. And you’ll see this throughout because the default is, I think, ED25519, which is what Zcash uses. Here you see that it’s doing three shares, the threshold two, and it’s writing out both the public key package and then the participant packages. The public key package is public, it contains a verifying key that will be used by the public, whereas the participant keys have their private shares, not the full private key, but the shares that FROST splits. So I’m going to run this.
And as you can see in my demo directory here, I now have the key package one, two, and three JSON and public key package. We can look at those briefly. They’re just JSON. So now we’re going to extract the FROST quorum, verifying key, and compose the watch-only descriptors. And this is so basically the wallet can watch the balance as it’s sent money and as its balance changes. So we’re basically extracting the aggregate key from the public key package and then creating its descriptors. And you can see that in the output there. So we’re going to go do that. There’s our key and our descriptors. And one descriptor is for the receiving and the other is for change.
All right, so then we’re going to actually create the FROST wallet using the descriptors and ask for its first address. And this is so that the regular wallet can send the FROST wallet some money. This is pretty much very similar to what we did earlier with a regular wallet. Okay, there’s the new address that the regular wallet will be sending to.
Then we’re going to send one Bitcoin, 100 million satoshis, to the FROST address that we just created. So we’re sending that amount as a variable here. And then we’re doing three steps here. We’re actually creating the sending PSBT. We’re signing the PSBT from the regular wallet. And then we’re broadcasting the PSBT to the network using, to the address, which is the FROST wallet. So I’m going to execute all these together. Compose the transaction, sign the transaction and broadcast the transaction. And we should see the transaction ID appear. There’s the transaction ID.
And if I switch back to the bitcoind window during this demo, you actually see it scrolling on, things that, as it recognizes things coming in like this. So now we have to mine another block on top of that to confirm the transaction to make sure it’s spendable. So we’re just going to tell Bitcoin CLI to generate a new random, a new block to a new random address, which we just did.
Now our regular wallet should have a reduced balance because it has sent money to the FROST wallet. So I’m going to now tell it to sync again and show its balance again. As you can see, it’s no longer the 50 bitcoins. It’s somewhat less than 50 bitcoins. In fact, it’s 50 bitcoins minus one bitcoin minus 155 satoshi’s fee, which gives the current balance.
Meanwhile, at the FROST wallet, which has the watch only descriptors, we should be able to sync it and then look at its balance. And as you can see it has an even bitcoin there.
All right so now we’ve there basically we now have the ability to spend this UTXO that has this one bitcoin in it. And again this is an optional step in the workflow here but because if you run this on the same Bitcoin test network or whatever over and over again you might eventually be sent two inputs, only one of which will be spendable. So you don’t have to do this, and especially you don’t have to do it if you just started a fresh blockchain on your own, but I will select these commands just so you can see that the one we spent has one transaction, and this is its input that we’ll be signing.
All right, so now we’re going to have the FROST wallet generate a one input, one output PSBT that the quorum will sign. Now, normally you’d use BDK CLI to sign this, but it has watch-only descriptors, so it cannot sign a transaction on its own. So we’re going to ask the regular wallet here to create a fresh receive address. That’s what this is. So this is the address to which the FROST wallet will be sending.
Then we’re going to create the FROST to regular PSBT. So we’re going to select the one Bitcoin UTXO, construct a one input, one output transaction, and pay half a Bitcoin to the new regular address. And then putting any change, remainder of the change in the output descriptor that still belongs to the FROST descriptor. And then we serialize everything as a base64 PSBT ready for signing. So here’s where we’re setting the amount. Then we’re creating an unsigned PSBT with the create transaction command. And then we’re extracting that to a PSBT and writing that to a local file here. So when we write that, you should see this is the base 64 of that transaction.
Okay, so the next thing we’re going to do is we want to sign this transaction now. We have to sign the sighash of the transaction. And this is the first place where BDK CLI does not give us a built-in command to do this. The only things we’ve hacked here are the Zcash Foundation’s FROST tools. We did not hack BDK CLI in any way. So we’re actually using our little Rust helper here to ingest the PSBT and output the hex of the sighash. And we’re going to show that to the terminal. There it is. Our second tool, this particular tool prints it as hex for readability, but we’re going to have to sign it as binary. So we’re going to convert that back to binary with a single command line here. And this basically shows that it’s a 32-byte binary file. So that’s our sighash as binary.
Next thing we’re going to do now is since we already generated our key material, we already have, we’ve set up the FROST quorum and now we’re going to start the coordinator. And I think I can do this. Let’s see, copy my current directory, start your terminal here. I would normally do this by flipping back and forth between terminal windows but sharing my whole screen seems to be a problem for some reason.
Okay so I’m going to change the directories to the demo directory here and we’re going to start the coordinator. Now the coordinator is now listening for participants to connect and it’s going to need two participants to offer their shares. So as you may know, FROST is a two round protocol. So the first thing to do is that the first participant has to send its key package up. And again, all these things are labeled as using the SECP256K1TR cipher suite.
So I’m going to start another terminal here and change to the demo directory. And this participant is going to send package up. And again if I look at, list the demo directory right now you see that it has all the key packages in it as well as the directories, the regular wallet and the FROST wallet. So I’m going to execute this now. Now it’s read its key package and it’s connected to the server. If we go back to the coordinator you can see that the coordinator has a client connected now and what it’s received from the client. So it’s got the first client coming in.
So now we’re going to do the same thing with the second one. We’re going to start another terminal, change to the demo directory, and then we’re going to the second one. Now this printed out more and the reason is it connected and then it received something back from the coordinator. So if we go back to the coordinator you’ll see that it’s basically has two clients connected and then it’s basically using, it’s applying the taproot tweak at this point and it’s created the signing package for Taproot. We can go without warning for now.
And then, and basically it’s sending, it’s basically waiting for participants to send now their signature shares. So it’s informed the participants now, as you can see, it sent this first participant. It’s basically saying, here’s what I’m asking you to sign. Do you actually want to sign it? So this handshake goes back and forth. So everybody knows exactly what they’re signing. And the message to be signed is in fact the sighash. We’re going to say yes. And then this participant is now actually completely done.
And then the second participant says yes. And this participant is done. Meanwhile, back at the coordinator, it’s basically said it’s received from the first client, received from the second client, and then written now the signature to sig.raw. Okay, that’s great. That basically means that if we do an ls here, we see sig.raw. That’s the raw binary signature.
So I’m going to skip past these sample outputs here. All right. So we see that sig.raw is a 64-byte binary file. 64-byte is the proper length of the signature. We’re going to echo that as hex here and assign it to a variable. That’s the hex signature. And now we’re going to use our second helper tool written in Rust, the psbt-sig-attach to, and we’re going to basically have it ingest the PSBT and then hand it as its argument, the hash, the hex of the signature. And we’ll basically attach that as you saw in the code to input zero. And this gives us the signed, but not quite finalized PSBT. And there it is.
So the next step is to finalize the PSBT. This gets it ready to send it to the network. And this is something that BDK CLI can do. So once you give it, so basically make sure that it’s properly signed and ready to send. So here we’re echoing it back out to the frost_to_regular_final PSBT. And then we’re going to print that to the terminal.
And then the main moment of truth comes when we broadcast that final transaction to our local network. In this case, we’re telling the wallet, broadcast the final PSBT. And if all goes well, we should get back a transaction ID. The only step after this will be to make sure that the balances are correct. There’s our transaction ID. So we’ve successfully FROST signed and sent this transaction to the network.
So now we’re just going to confirm that. We’re going to generate another block to confirm the transaction. And then we’re going to verify that the regular wallet received the funds. So we’re going to again do a sync and a balance here. As you can see, the balance is different. The actual calculation is here. The old balance, which was what was sent minus the fee, plus what was the 0.5 Bitcoins that was just received, gives us the actual balance that we see here.
And that’s the demo. Obviously, we could check the balance of the FROST wallet as well, but we know it’s now half a Bitcoin lighter minus its fee. So, and with that, that’s my demo. I’m open to questions. Okay, if there’s questions later, please feel free to speak up. Christopher, back to you.
Dan Pape: Wolf, I just wanted to say that is the most exciting text-based demo I’ve seen.
Wolf: I wish it could have been more visual. I’m a very visual thinker.
Dan: But all that cutting and pasting was great.
Wolf: Great. Well, I’m glad it landed the way I hoped. It’s definitely tedious because I’m a very visual thinker, so that was not easy to do. Conrado, I believe you had a question.
Conrado Gouvea: Yeah, thank you for the demo. It was very interesting. I know these are difficult. I made several demos in the past, and they all go wrong in some manner, and you did it first try. Congratulations.
Wolf: Not too many tries before that to get it right.
Conrado: Yeah. That was very cool. Yeah, this is great. This is something that we did for Zcash and it’s exciting to see being used in other ecosystems. I don’t have any specific questions about it. I just have some comments about the tools, the FROST tools, right, that you have been using. These are like a previous version of the tools that like the first version that we did. But after that, we’ve done a new version, which is called frost-client to frost-d.
And the goal there was two goals, the first to make it easier for users to use it. And the others make it easier for participants to communicate with each other because like, currently, the tools you use, like the participants connect directly to the coordinator, which works fine on the demo, but in real world, like people are behind firewalls and whatnot, NATs, stuff like that. So you build a FROST server, which basically the only purpose of this FROST server is just to like for participants to connect to the server and then they can message back and forth. And that’s easier than connecting directly to each other. So like if you’re interested in doing this the next step might be to migrate to use frost-client to frost-d which should be very easy I hope.
Wolf: I actually did work with the frost-client and the frost-d for a little bit while attempting to set up the distributed key generation scenario. I was not able to get it to work in time for this demo. But it’s, and there’s some open questions about how ready for primetime the actual, that side of things is, is using the distributed key generation scenario. It appears to be a work in progress. And anyway, maybe we should talk out of band and talk about how complete that is and how to implement it properly, especially given that we’ve now added our own, opened up the SECP cipher suite as well as our taproot tweak stuff on top of that. So, our work on this is very rough. It proves the concept, but you’re right.
Wolf: Yeah. A real life scenario would use a more kind of a nexus like frost-d that you have and more kind of flexible client tools. So it’s good that you’ve been a good start on that.
Conrado: Cool. Yeah, the DKG part is ready, it’s working, so you can try to use that next. It should be, everything should be working.
Wolf: Okay. I tried for a while to get it working and wasn’t able to, but that could be our own issues that we’ve introduced on the code since we’ve started modifying it. So we’ll investigate that. Yeah, please reach out to…
Christopher: Yeah, it felt like there was maybe some slightly out of sync. If you say you’ve got a newer version, maybe we aren’t using the current branch or it isn’t merged to main or something.
Wolf: So I may be able to pull from upstream or something like that to actually get it to work. It depends on, I haven’t looked for, probably it’s been at least a couple of weeks since I looked at the code base. I don’t know how rapidly it’s been evolving since I forked it.
Christopher: So I did have some, while I’ve got you, Conrado, I did have some open questions on ZF FROST that maybe you can help us with. What is the status of PRs? We’ve got one in. I saw a bunch of other automated PRs, but I know the Zcash Foundation had puts, or maybe Zcash Community Grants was saying something about ZF FROST being on hiatus for a little while, but I didn’t know what the details were there. That’s one. And then I have a couple of others.
Conrado: Sure. Yeah, basically the status is that like we have the FROST, the main FROST library and the FROST tools, right, which are these additional tools to command line tools to help use FROST. So both of them are in a state that we consider mostly ready and complete. Like we completed the FROST tools, we audited them, and we did some final refactorings and that’s it. It’s complete state. There’s one thing or another that could be improved and we might do these improvements over time, but we consider the project complete at this point.
I saw your PRs, I need to, sorry, it’s been like, as Zcash has been occurred, a lot of stuff going on there, so we’ve been busy, but yeah, I’ll try to review those PRs and get them merged. Everything looks fine, I just need to get around doing it. What else? Yeah, I think that’s it.
Christopher: Okay, so the next question, and this was kind of brought up…
Wolf: I had a question. Is that something that you want to take time for now, Christopher or ask Gary to hold it?
Christopher: Sure, Gary, go ahead.
Gary: Hey, thank you. Great demo. I just had one question as far as like the process goes. You’re passing just a sighash to the signers. I assume that each signer will be able to independently audit the PSBT and come to the same sighash conclusion using the same tooling. I know it wasn’t explicitly done in the demo, but I just wanted to confirm that that’s sort of…
Wolf: Presumably that would be part of something that they would, obviously signers need to know what they’re signing. So in a production demo or in a production tool, they would not just get the sighash, they would regenerate the sighash themselves and know exactly what they’re signing.
Gary: Perfect. Thank you for the clarification. Great demo.
Christopher: So the other thing that came up was Jesse had said that there was a, there’s a whole bunch of stuff and it’s kind of, some of it’s on this slide and one is on the other, but Jesse had noted that taproot tweak might not be necessary if the DKG did a particular kind of operation. Jesse, do you have that URL handy to that issue? But we didn’t know if it had actually been implemented in your DKG or what that meant for the trusted dealer. So did you have any off the top of your head recall on that issue? Conrado?
Conrado: Yeah, I remember this cropping up, someone pointed out a possible issue with that. And the whole taproot suite was contributed externally. We just reviewed it. And we’re very grateful that people did this work. Sorry, I can’t remember exactly who did what there, but I remember someone pointed this out and it was fixed. So currently if you do the DKG on the taproot suite, using your library, you should correctly apply the tweak. It’s like, I can’t remember the exact mechanism, but you basically need to apply a kind of a non-invalid tweak, but an artificial tweak to the result of the KG to make sure to avoid a specific attack. And yes, it’s doing that currently, so it should be fine.
Christopher: Okay. So, yeah, so what we submitted in the PR to you is the version without the tweak details, because you may, if you’re doing SECP256K1, you may not want to do tweak in certain scenarios. And we weren’t quite sure what the best thing to do is. And we’re going to be talking about tweaks again in a little bit, a minute, but I just wanted to mention that there’s sort of this open question of what is the best thing on that. Did you have your hand?
Wolf: Yeah.
Conrado: Yeah. Yeah, I can. Like, in Zcash, we have something very similar to the tweak, which is called randomizer. And there, if you use the FROST tools with the Redpallas cipher suite, it changes behavior little bit like instead of just asking for a sighash it asks for both a sighash and a randomizer and this randomizer must be generated externally. We have another tool that does that. So I kind of like I’m not super familiar with how taproot works but I expect the approach is to be something similar. You need like to take the tweak as input like we need to some other tool to generate a tweak. I don’t know how it works on Bitcoin who generates a tweak exactly. But basically with if you have the tweak you can like just like you extracted the sighash from the PSBT maybe you can extract a tweak or something like that and then pass the tweak as an input to the FROST signing. And you can probably take the Redpallas cipher suite and how we handle that to as a reference to how to handle this in the taproot.
Christopher: Okay, well, thank you. Now, I know that the Schnorr BIP340 changes were added kind of last. Were they part of the security review or was that after the security review?
Conrado: No, they were not part of the security review. It was added later, yes.
Christopher: Okay, so yeah, we should talk with our community about also getting funding to do that review. And do you know if Zcash Community Grants, Zcash Foundation plans on any upcoming security reviews? Or is that kind of on hold for a while?
Conrado: That’s a good point. Now that you pointed that out, it might be possible. I know the ZCG has a grant with this authority, if I’m not mistaken, for doing security reviews in general. I don’t know what’s the status of that, but they might be able to assist with this. You probably need to reach out to ZCG to make sure. Because this is like, this specific signature will also be used in Zcash, because there’s ZSAs, Zcash shielded assets coming to Zcash, and their issuance, the signature used for issuance is the taproot signature. So this would also be useful for the Zcash community. So I think the goals are aligned there.
Christopher: Great. Thank you. So do we have anybody here who’s contributed to BDK or is part of the BDK team? I tried to get some. Not seeing any hands raised. Well, we’ll bring that offline. I mean, part of the thing that it turns out that there is some optionality in the library for what they call sign options that allow you to do the hash, do the tweak externally or not do the tweak and et cetera. We’d love to talk with them about what is the right place.
And then, of course, there’s this whole situation where if you use the DKG properly, you may not have to do the tweak because it’ll already kind of do it for you if the right optionality was set. And then this sort of comes to my bigger question, which Jesse may have some thoughts on. Jesse, are you back? I just saw that you… Yeah.
So when actually doing this, we realized that as you talk about it to us in an abstract sense, the tweak is a particular commitment that is made to avoid a particular kind of attack. And as Conrado pointed out, there are other approaches to doing the tweak like operations for security. And there kind of becomes this interesting question of who is really responsible for it. I mean, it feels on one hand, it feels like the coordinator does that, but maybe it’s the first party that signs that should be doing it. I don’t know. Again, this sort of this abstract problem of, if we’re going to try to generalize this for other kinds of security things, where do we do it? How do we not do it when it’s not required, et cetera?
So it feels like we’ve got an architecture problem there that might be a good discussion at our full FROST workshop. But then the other thing is that Jesse had pointed out in some other, I don’t know if it was an issue or a post, that there are some privacy implications of the tweaks. Such that, especially when you’re doing stuff with derived BIP32 derived keys, that you may want to do tweaks a little bit differently than is specified by Taproot to make it more private. And Jesse, do you want to talk a little bit about, we don’t necessarily go into detail, but I think it’s more just trying to raise this as a general architectural issue. Jesse?
Jesse Posner: Yeah. So let’s say FROST is being used in the context of a collaborative custodian where you have a wallet owner and they’re working with a third party who’s going to be part of the FROST quorum. And maybe that third-party signature is not used for the normal spending flows, but only in the case of recovery where one of the other keys is lost. Like, for example, with the BitKey wallet, you have a two of three where there’s a hardware wallet, there’s a phone, and then there’s a third-party server. And so if the user loses their phone or loses their hardware wallet, then they would need to use the server to spend because it’s a two of three. But if the user has both their devices, then they don’t need to get the server involved.
And this extends beyond just FROST, but to this kind of collaborative custodian model in general. One issue is that this third-party server signer is going to be able to… Typically how this is done is they’re made aware of the descriptor and all the XPUBs and all the chain codes. And so this third-party server signer would be able to see all the wallet balance and all the transactions. And if their database was breached, then the customer’s balance information and transaction information would be able to be computed with a descriptor.
And this is the case even if the wallet is signing without this third-party server, they would still be able to detect those transactions by using the descriptor or the chain code to derive all the addresses. And so in a FROST context, there’s only one chain code. If we’re dealing with kind of script-based multi-sig, each signer would have its own chain code, and there’s different considerations there. But in the FROST context, there’s one key that everyone has a share of, and there’s one chain code for that key.
So you could, you don’t have to tell all the participants in the FROST Quorum what the chain code is. So if there are participants that you want to, you want to be able to sign without that participant being able to detect the signature on the blockchain, then if you don’t tell them the chain code and they’re not involved in the signature, let’s say we’re doing a two of three and that third signer isn’t involved, just the first two, then they would not be able to detect the transaction on the blockchain because if you tweak the key with BIP32 and they don’t have the chain code, then they don’t know the tweak and they can’t recognize the child key that was used.
So then when you need that server signer to be involved, you still don’t need to tell them the full chain code. You can just hand them the BIP32 tweak for the UTXOs that you want that signer to sign for. And in that case, the server would learn about the transactions that it signed, but no others. And then you could go even further and combine FROST with Schnorr blind signatures and have the server perform a blind signature. Yeah, actually, yeah. So you could have the server perform a blind signature and then they wouldn’t even be able to recognize the transaction on the blockchain that they were involved with.
And you don’t even have to tell them the BIP32 tweak because the way BIP32 works in FROST is the aggregator can add the BIP32 tweak. So as long as the child key is correct in the challenge hash, the signer doesn’t need to modify their signing share with the tweak. They just do their partial signature with the correct challenge hash. And then after the aggregator gets the partial signature, they can add the tweak to that partial signature.
Wolf: I think that’s actually what we’re doing right now. I don’t think the signers, the participants actually do anything with regard to the tweak in the participant tool code. I think it’s the coordinator that actually performs the tweak.
Jesse: Yeah, that’s right. That’s how it should be done. So, yeah, that gives a nice kind of privacy-preserving way to have certain signers that sign but don’t learn this private information. And further, if they need to enforce certain policies so they’re not just signing anything that they’re given, you could attach a zero-knowledge proof that asserts various statements about the transaction data without revealing anything else.
Christopher: Sonia, I appreciate you sharing that with us. And this may be relevant to you, Conrado, as you’re thinking about your own tweaking-like thing in the Zcash curve, that there may be some similar types of coordinator issues and ability to future proof it for these additional kinds of scenarios is an interesting question. And I’m trying, Blockchain Commons, we’re serving multiple ecosystems. So we’re really trying to think about this at a slightly higher level of what are the requirements for these types of things and what is the right architectures for these. So thank you. And hopefully this will be a topic we’ll talk more about in a future FROST workshop.
Quick question I have for anybody, but in particular, Jesse and Conrado. I mean, one of the things that right now, our envelope tool supports a variety of cipher suites in effect. I don’t like calling them cipher suites but a number of different curves. One of the things that the envelope tool does is it does encryption. So it’s basically able to not just sign things it also it can use keys to encrypt things. Now, it turns out you can’t, there is a technique that you can use to sign, to encrypt something with an ED25519 key, which normally is not the way you would normally want to do it with, do a key agreement with X25519 or whatever, but it’s used a lot for SSH encryption. But that only works because ED25519 signatures are deterministic. Have either of you thought about how we can have that same FROST quorum be able to create a shared secret that can be used to encrypt things? Has there been any work in that side of things, not just sign things, decrypt or encrypt things?
Jesse: Yeah, so there is an encryption protocol that can be used with FROST shares, which I’ll find the link, but there is a paper that sets out how to do that.
Christopher: Okay. Conrado, have you have anybody in kind of the ZF community been thinking about this problem?
Conrado: Yeah, not specifically this problem. Something that is related is that like our tools for people to send, the false package to each other, they need to encrypt end-to-end. So our tools like to generate a key pair for each participant and each participant needs to send their public key to the others in order to set up this end-to-end encrypted channels. So this is something that we already have. We haven’t thought very much about encrypting like the storage key share. We were just assuming that it would be encrypted, like, with something specific operating system-specific protection, like with the user’s password, the biometrics, or something like that. So, yeah, I’m not sure about what is the specific thing you try to achieve. We haven’t thought that much. Sorry.
Christopher: Okay. Yeah, again, a future topic. I mean, we’re trying to think long term and future proofing all of this. As you said, if the quorum can’t create a symmetric secret that it can use for things that are private information between the members of the quorum, it becomes weak as compared to other kinds of cryptosystems that allow for participants to communicate with each other. So I know, Jesse, at one point you said you had hacked a key agreement in Python, but I don’t think there’s been any security review of the cryptographer for that, much less the code. But I think it’s an important thing that we need to look at in the future of FROST.
I see, I forgot what was on the next slide. Yeah, so any other questions or kind of like open topics that people would like to see us do more on in our future workshops and in our future development here? I mean, part of the whole point of this particular CLI tool was to demonstrate that this is how some of this stuff works. And we’ve already found it useful when we’re moving out of, okay, we have some libraries and some APIs that we can do various tests against to say, yes, this actually works. Actually having them in separate shells, having issues with tweaks, having a real coordinator out there that is doing these things and not just as source code tests against the library.
And I also have weird questions like, okay, so obviously seeds have to have special protection because they can generate lots of private keys. We also have private keys that we need to have special protection, but we’re somewhat willing to have private keys generated in user space, maybe have seeds in trust zones or things of that nature. But then when we start talking about these shares, well, they’re not quite as need to be as secret as private keys or seeds, but they do need to be secret. And like, what are the standards there? How do we think about shares that can’t be used alone, but can be used in aggregate when we’re trying to think about the security of things?
I also note that there are three major libraries now that have done demos at our workshop that all have DKGs and all generate fairly different values for them. And the actual FROST code only works with the DKGs of each of these. And I’m not, part of it is, for instance, I’m forgetting what the other Rust DKG is. It was demoed at the last workshop. But they’re actually including and when they store the shares, they’re actually including some of the random values that were used to generate it along the way to make it easier to regenerate it later. Whereas I think those are, you’re not storing those extra values or eliding those extra values, which is the way I would do it. In the Zcash Foundation libraries, you’re just getting the shares. So there’s some interesting questions like what kind of compatibility can we have there? What are the best practices of storing DKG values and the VSSs and such? Any other topics as far as related to the future of FROST and both on Bitcoin and in other scenarios? Wolf did you have any questions when you were trying to move this forward?
Wolf: Well, obviously, I’m not a cryptographer and I’m not a Bitcoin deep expert. So, obviously, the stumbling blocks I ran into, I often was working with both Claude Code and O3 Pro, going back and forth between them with one as my implementer and one as my expert. And it would be helpful to team up with human experts in these areas who could advise me in better ways. So, I think the code that I’ve written is good. I think I would know what to do to move this forward towards a more production ready version. But there are, like you said, open questions in terms of this.
In the short term, if we want to submit another PR on top of the one we’ve already done that includes Taproot, there’s still some cleanup and finalization that needs to be done there. For example, making the Taproot tweak optional as opposed to right now when you run this branch, you’re always going to be doing the Taproot tweak. But our stack in general supports BIP340 Schnorr without the taproot tweak as basically its standard signing mechanism, although we support others. So having that optional would be better for our stack.
But yeah, I mean, just in general, I mean, this is an open conversation is how do we proceed with both making our own stack more FROST enabled as well as contribute to the community in a way that, obviously everything we do is open source. So, but how do we make sure that what we’re doing is valuable to the ZF Foundation? So they find it useful to incorporate our PRs and so on. So I’m open to guidance and so on. But these are kind of vague questions with these are the kinds of things going through my mind right now.
Christopher: Yes. Like one of the questions I have, we already support ED25519 and a few other curves in our envelope tooling. Obviously, BIP340 Schnorr is our default. But should we be adding some of the other Zcash specific curves to Envelope as the Zcash Foundation is now beginning to use Envelope for some of their interoperability types of things?
Wolf: So those are great questions. And obviously, Envelope itself is not going to be suitable for signing, for example, transactions to existing blockchains. It could be used as the basis for a new blockchain of some kind or a new cryptocurrency. But that’s not anything anybody’s talked about yet. So, but yeah, I mean, generally speaking, when you and I have talked about adding a new kind of curve or encryption method or signing method to it, we’ve talked about use cases. For example, we’d use cases for implementing SSH signing. And on top of that, I did implement an encryption method where you sign a nonce and then use that signature as the actual encryption key. But that’s, again, that’s symmetric encryption.
Christopher: And so it also relies on a property of ED25519 signatures that Bitcoin signatures don’t have.
Wolf: Exactly, because there’s no random nonce. There’s no random component to the signature.
Christopher: Yeah. The, anyhow, so these are all interesting future topics. I will close with, we have a wide variety of resources and results from previous FROST workshops at our developer site slash FROST. We’ll be adding the notes from this session and links to all of the HackMD and all of the resources. So that’ll probably be up tomorrow.
And we are having more focused FROST meetings this fall as sponsored by Human Rights Foundation. So if you’re interested in participating in those, make sure that you sign up for the FROST mailing list because that’s a separate meeting. And if you’re interested in demoing what you’re working on, please let me know as soon as possible. Library implementers, tell us about your tech and your roadmap and the things you’re trying to release in the future or would like to get some advice on. And then we do a separate meeting for developers where we focus on what are the wallet developer needs and their use cases. So we’re seeking more on that.
And of course, if you’re interested in sponsoring us to continue this work, let us know. I mean, one of my hopes is to find some people on the BDK side of things, like is BDK going to be independently implementing FROST? Are they going to be using ChillDKG, which is in C? Or are they also interested in using the Zcash Foundation libraries, et cetera? So we’re not really prepared to submit patches to BDK at this point. But we’d like to understand what is out there and what’s going on.
And of course, you can see all of the different things we’re doing at our main website at blockchaincommons.com. And I’m Christopher Allen. I’m at ChristopherA on X and Blue Sky and all those different types of places. And of course, ChristopherA at Blockchain Commons or ChristopherA at Life with Alacrity. Any closing thoughts? Okay, well, I’m going to go ahead. Actually, it looks like Wolf, you need to stop the recording. And we’ll be off the record. If anybody has any off the record… Yep, I’m stopping now. Thank you, Rui. Okay. So…