From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Tue, 07 Apr 2026 21:18:52 -0700 Received: from mail-oa1-f55.google.com ([209.85.160.55]) by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1wAKNO-0001SU-L0 for bitcoindev@gnusha.org; Tue, 07 Apr 2026 21:18:52 -0700 Received: by mail-oa1-f55.google.com with SMTP id 586e51a60fabf-42342b79ae4sf7194323fac.1 for ; Tue, 07 Apr 2026 21:18:49 -0700 (PDT) ARC-Seal: i=3; a=rsa-sha256; t=1775621924; cv=pass; d=google.com; s=arc-20240605; b=dS7JqvKxqrIpkKWj1gWbJuH8a5ubBtjkks4FpogoVmCFafonSRVHajgRs2EiQPAqp6 tYcjhgwks60QP/Z7I5IPCMIGyzJq1pZIIGVyg0CDG83TlELLD3A5yzIZoMFLtIcBUTeG l7pi110E6QnklvQzMYvXmHMq8hBGWzulwUKqXasQn0yktyhp0aRqQUS8xMOOpxrBZ2J6 ErFCxAk5kXkHHLQ6k3Eh0Cxnwb50XT2/NDSQpjQexcUMUIbYE/iCx6pq8IzwA3zsksWE fnr8XtQLSqKpuAQsI1rL/LmuUzG+hPAH4ZJO6Kmao38FPBU0cfrAtV3iHDxW7JdH5ZzD thug== ARC-Message-Signature: i=3; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:to:subject:message-id:date:from :mime-version:sender:dkim-signature:dkim-signature; bh=/9y7YcM0gyAzDBofWFoEIXPMXWE1o6Bjq+QNtfkTywg=; fh=z/8O1cTAGIXU++yW5nSAnB9hOpnX4/SLtEyEmtdplQI=; b=OtBikyjfyVDwXlAec8aRHGbnrVYxkdM+siRB4V2hiUtaJR4J0FmrdPeaXWnDQj5KNh qSqwXF38I6dyIC8zNQcvCfVPe2hHtvJGbxelZGynGdv7L7WvyKKWXIovJnTBDZzrfzCR LhHLF2fqgxZbcdLoqc4MfXiFPPRw18NJeUdpibUUjagax/d99J99D4afiBxjI+Rtq4xr NfZmUTmhtFaI6/ljcQWLPgzSzGpJFKgnv70HY/ZMvLBf/hLPc6KQuGTPXU877w+ELgDv BvAyx+sgm+0xVrft+hzlJZn5OeKjzlUmYxZB07b/5IUdSJkoLU1f6OBjlLo+qVhZNz3W VQ7w==; darn=gnusha.org ARC-Authentication-Results: i=3; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20251104 header.b=ltNrOyCo; arc=pass (i=1); spf=pass (google.com: domain of laolu32@gmail.com designates 2607:f8b0:4864:20::b12d as permitted sender) smtp.mailfrom=laolu32@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@googlegroups.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1775621924; x=1776226724; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:to:subject:message-id:date:from:mime-version :sender:from:to:cc:subject:date:message-id:reply-to; bh=/9y7YcM0gyAzDBofWFoEIXPMXWE1o6Bjq+QNtfkTywg=; b=yMuhWdcyjVWk4jNY1hUAGBJARM7vrNgb7ZbMli6j0uUMijHijjMuMyeVYUaVCKD/Sw FEiIvL0q5hrVUc1mlJaJ1kBpHtBxK1aqOFDyKSzZ/486BefSLFNLwEemCZqDHu0LHUyB O8aXUhDsxa6x31Dzp14O7amZD0iIgZNQdrJEQUhE0rQur2CSJNkgIiz3wztwuMQpoRwI 27jmMnvDG7p9k/5Hk5fa4SYXZvPSGXi0ROKr7xZcQVNNPa1CG73fySYtqmD9N3s8soyo 4X3/Zjts0ai8flOQp9IS9eAoUM7ts3iKl0Sv1wxo5kXrCb5lflEkOEAQ/enOu/9+FIG9 4XCQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775621924; x=1776226724; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:to:subject:message-id:date:from:mime-version:from :to:cc:subject:date:message-id:reply-to; bh=/9y7YcM0gyAzDBofWFoEIXPMXWE1o6Bjq+QNtfkTywg=; b=rMdNOkSCEmeRoAWtf8XxiwIlq2Z8YSz9H7gvE9oJLWhViD0nhg5aS1GCRLf4m+On5M PrhgX82pqW3vixiG0EJRJGTa3PIcV1S9f/eYmgI57lyTaFyR4yWcXc6cxHP83D33mEK/ k1jLdra3ly/THqhC1NdgfUj/vMKsmsNweoSx7wiZ8j6tEvY+Nr5wMn1ufIX3SOBEFxEa eYXrSnx9Nbk77zDxp3HcmOn/skuU7eZhmomRd88QdLufex5fW5hu9kI4vc0TLlC9SIGx 0I9/RI33icVeMBBcb70FgNONp7ALHzNpwt6FUylASG0/VQSDw3QkD3Fucl7ZydIjzyzD 36vQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775621924; x=1776226724; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:to:subject:message-id:date:from:mime-version :x-gm-gg:x-beenthere:x-gm-message-state:sender:from:to:cc:subject :date:message-id:reply-to; bh=/9y7YcM0gyAzDBofWFoEIXPMXWE1o6Bjq+QNtfkTywg=; b=Saf/iciUKlj8m843bnP3ZJh0pvaT6QPZJqzteEVzC1MJYpA3mnuLuuBExji7p27fxu VE2EKi773YUzjV/TyVNN+JlUsMudOz+Oy7xLVL2n1DmHcZoyvejBVIcfZDjVlOu/6cJe QZ4U7V4Yfejou8dFS5YtXhmRGedUDwTPWvnn7EST5OKcO+SbkkfT5g6APf/OB4oM0JwM /fCJrfYgNqcJ0VHbbpYVAAd2Kp5DBXH+Gm2rGba26yzircbDigSNZeRod5IXPA6jWMws SEXiwfqkI32O+ep9+KifordxtOI54Wl7e4yoFqwbv530YJ0fPWux4eIqqua5EC40Plj0 bokA== Sender: bitcoindev@googlegroups.com X-Forwarded-Encrypted: i=3; AJvYcCVjX4aBU02wIP6tIEqWb9Z4b0cW9OpZamxuhEFmp7WF98U2JJ2VnHYDvmF/UGnBsOUHa7ARqS7X7HZZ@gnusha.org X-Gm-Message-State: AOJu0YzGtAU5UP9KBQJYkY8YKMV2i/anH9yUyHKYP5ZBpVhQq7jrAuQ8 dmWOTsUEDio/gsbvj8AhOT605OO4qQeJVf3ANgVtcuiKG3iWsqpPDnyw X-Received: by 2002:a05:6870:8313:b0:41c:fdd7:5b4b with SMTP id 586e51a60fabf-4230fdcf7a4mr11279407fac.21.1775621923587; Tue, 07 Apr 2026 21:18:43 -0700 (PDT) X-BeenThere: bitcoindev@googlegroups.com; h="AYAyTiKt+p7OiOjMb9lN4iFK78/xuQHn2PcWH64ncBdwvA3+Gg==" Received: by 2002:a05:6870:2b0c:b0:417:821f:fca0 with SMTP id 586e51a60fabf-422ee0aa24dls4818256fac.0.-pod-prod-09-us; Tue, 07 Apr 2026 21:18:38 -0700 (PDT) X-Received: by 2002:a05:6808:5088:b0:468:1574:4cc1 with SMTP id 5614622812f47-46ef8d5bf29mr9924726b6e.3.1775621918000; Tue, 07 Apr 2026 21:18:38 -0700 (PDT) Received: by 2002:a05:6808:2806:b0:46b:22a1:35fc with SMTP id 5614622812f47-46bd6fcb9b4msb6e; Tue, 7 Apr 2026 20:39:54 -0700 (PDT) X-Received: by 2002:a05:6870:918c:b0:409:5560:72f8 with SMTP id 586e51a60fabf-4230f6b34cfmr10199520fac.0.1775619594069; Tue, 07 Apr 2026 20:39:54 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1775619594; cv=pass; d=google.com; s=arc-20240605; b=LESzdNx6hchGSvW5EfTG8MPSzG5OG2v1p9UrqHWBPA7hSinO7XWAgM10wcXhYxhJXN moBkY2guDf22h62eGg0HcYhNKDIjp1rHCa4ZSfVIKQXSJ4SnrXVcmuzaFEErrnHqDTnc tf5VVAoFIZjMNvgqZR7Ag7+vDslj9aSnJ9X5vBvSVZ7dTqxnZMQP9GZ+6yrpOGGJSJLM b7M9i2VxUQTs6aqMMeDcPrzbfwQ3ZtZQ9BAMATiPZexrXtdcAhPHQ8I3pWBKWxr0E3jM qiWthLvhEr1KOafNVof3TynAX9tm8wL0otb37y/y3x5zp1aWyR1P0vJCsfaLg2nTRYZM jS6Q== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=cZD4U5oE9efbmltsKnLg90hmVsWGUC3WLK9YlaSB4Qk=; fh=DMP0F9ULS1guKiqimntQRCN8ZraraesEgQuVcn7F0Z0=; b=RSTBDXD+jxsofU61wUDrBaW9EKJTaxPeh8yN0ynjO5X0XACnGp9WeVeUnoMZs0/UqX PQPRhz2H3PSIrq93BBl0riEph92RAur9p1JyEPHyHsoimfy8vp/Zj150lUCn13EH6EwQ 9hrksA4VLXYHH2S7xBrApwSSI/Gf/2l+UlOzKSt3Jld69/1JoHjfwisWRcNyTtmdUeqH 5pKJbZC4uWSNGdNtzeENC33WFHkGsfsE6JY6jYjP6mleDeF1jGF2Ulm1Xp30b4E9XlBR jUf+39RV7t3q3ipO1CstboKDJQRCjvaJ1MssokSNmfUUTX4oPl+mZzD9Y3l/591MTLvZ x9wA==; dara=google.com ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20251104 header.b=ltNrOyCo; arc=pass (i=1); spf=pass (google.com: domain of laolu32@gmail.com designates 2607:f8b0:4864:20::b12d as permitted sender) smtp.mailfrom=laolu32@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@googlegroups.com Received: from mail-yx1-xb12d.google.com (mail-yx1-xb12d.google.com. [2607:f8b0:4864:20::b12d]) by gmr-mx.google.com with ESMTPS id 586e51a60fabf-422eaf2096bsi594055fac.1.2026.04.07.20.39.54 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 07 Apr 2026 20:39:54 -0700 (PDT) Received-SPF: pass (google.com: domain of laolu32@gmail.com designates 2607:f8b0:4864:20::b12d as permitted sender) client-ip=2607:f8b0:4864:20::b12d; Received: by mail-yx1-xb12d.google.com with SMTP id 956f58d0204a3-6505ef94043so3231602d50.2 for ; Tue, 07 Apr 2026 20:39:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1775619593; cv=none; d=google.com; s=arc-20240605; b=UCJf3BZK8mJ9/8cmypmzPKdrh35+VVspEnqQTUl9Ohqj3sJ0JK0IW282r5iNBO7BQa Q7mGL9Av43TXKUK1QiarCvZpcysbtAx9i0+2fqsfqe1FWSCQV9LJb57Wp35/QiWUuZxA Wf+qfI73bStUVl/c0HyXixiXvE0nyQZZU2It6ah4Y6VTMaswfLfpCrxyiGi1b94oolP9 b3mUI2/Rf5Hy36Fg2DWfuJ+T2pbDOY6GfDuTXXN6sdVPRNu5fgZheKuEvhXr2H8QfZ0B aoPGmZ+39zFfNPN5W0PWCLrqzNVttuFlu/EV9r7lhWHD2CrSPNf5s4Zjg8BxWtbEzHXS /Z3Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=cZD4U5oE9efbmltsKnLg90hmVsWGUC3WLK9YlaSB4Qk=; fh=DMP0F9ULS1guKiqimntQRCN8ZraraesEgQuVcn7F0Z0=; b=Sap/Z8NskTfAKYT5FqcxGfnRr3HCqMDvZXolZUtOIzwdwJd6ApU6IOGPJEz490R3QF z/cLnpxWmBa/GxvByHpcrFy3ikDvaTVC6HQiBqPTjOaa+xoPXIf5PTLkgFdOI80+f9nP TlpozTdEHCmy2/Lf7QyNkpZypNQbcQDDgPa3eRNSUzcw33Tl/8deb0wtT9i0HLM6T9g/ WrTlbf2VHbq7FW/+Vh49LcIqBizk8Dz8IqGQTurh8wPoR70rPgmS0R028V9C1/1Nbrij pa8sSTKDNcjNebbvK2pCR8MVfcWTTqeuJsPBRglf5CXTOWF7ZjCYO95LY/HatMLixRWT YzqQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; arc=none X-Gm-Gg: AeBDietyJe/AcbJ81qCIU4VHxtFth/ZFrn4kJoG8ilV150QRErH3+/iazPh9pFe4t7r lS8bV8pFd3nh0GkXNN/5JamUT4b8PpFq/v9k0Et0JGme7tXjMxWaSSECSmhBLpOGpZxT83R1Nlj FJdAOQw2haHS+SC0kwjxqf60TlutSMjKyTCEfkP7quk2VgxSmoGY3EpCiG8ObAfnG6Lg2xq4PoS i7wNtZmd1TEozx+ux4e7eiait4TgohIQV5xp9f8nL6QxUHHjiBAJBfARZehcCO0O3DF/XpyDis9 PlVHujxQTRnGjO9o/xnyJjj7HSW5kKjPwZ2Q2zVek6c2Y32CVmQ= X-Received: by 2002:a05:690e:1590:20b0:650:33ea:b9fa with SMTP id 956f58d0204a3-65048710ecfmr14795316d50.20.1775619593020; Tue, 07 Apr 2026 20:39:53 -0700 (PDT) MIME-Version: 1.0 From: Olaoluwa Osuntokun Date: Tue, 7 Apr 2026 20:39:41 -0700 X-Gm-Features: AQROBzB6Nw0bXrTMxETGqp5SgFEQVZkG2GLer7mASXPFV_UIPxbHxioZp2OuOn0 Message-ID: Subject: [bitcoindev] Post-Quantum BIP-86 Recovery via zk-STARK Proof of BIP-32 Seed Knowledge To: Bitcoin Development Mailing List Content-Type: multipart/alternative; boundary="000000000000192982064eeaa7ea" X-Original-Sender: laolu32@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20251104 header.b=ltNrOyCo; arc=pass (i=1); spf=pass (google.com: domain of laolu32@gmail.com designates 2607:f8b0:4864:20::b12d as permitted sender) smtp.mailfrom=laolu32@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@googlegroups.com Precedence: list Mailing-list: list bitcoindev@googlegroups.com; contact bitcoindev+owners@googlegroups.com List-ID: X-Google-Group-Id: 786775582512 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Score: -0.5 (/) --000000000000192982064eeaa7ea Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi y'all, I found some spare time this last weekend to dust off a little side project I started last August: extend TinyGo [1] to be able to produce RISC-V ELF binaries capable of being run as a guest on the risc0 platform to generate zk-STARK proofs of arbitrary programs. Initially, I didn't really have a clear end target application, it was mainly a technical challenge to force me to learn a bit more about the RISC-V platform, and also the host/guest architecture of risc0. Fast forward ~9 months later, and an initial killer use case popped into my mind: a zk-STARK proof that a Taproot output public key was generated using BIP-32, via a given BIP-86 derivation path. More formally: ```math \mathcal{R} =3D \left\lbrace\; (\overbrace{K,\, C}^{\textsf{public}} ;\; \underbrace{s,\, \mathbf{p}}_{\textsf{witness}}) \;\middle|\; \begin{aligned} K &=3D \textsf{BIP86Taproot}\bigl(\textsf{BIP32Derive}(s,\, \mathbf{p})\bigr) \\ C &=3D \textsf{SHA256}\bigl(\texttt{"bip32-pq-zkp:path:v1"} \;\|\; \mathbf{p}\bigr) \end{aligned} \;\right\rbrace ``` where $K$ is the Taproot output key, $C$ is the path commitment, $s$ is the BIP-32 seed, and $\mathbf{p}$ is the derivation path. I was able to get everything working e2e over the weekend, after making some tweaks to my initial architectural game plan! The TL;DR is that: * Given that the Taproot commitment scheme is post-quantum secure [3], in the future we can deploy a soft fork to _disable_ the keyspend path, and force all Taproot spends to instead flow through the script path (not my idea, commonly discussed amongst developers, not sure who proposed it first). At that point, Taproot starts to resemble BIP-360. * That works for script path spends, but then leaves all the BIP-86 wallets in a bad position, as they generated outputs that provably don't commit to a script path at all. * A 2023 paper (Protecting Quantum Procrastinators with Signature Lifting: A Case Study in Cryptocurrencies [4]) proposed a solution to this, namely _seed lifting_ (use BIP-32 as the one-way function to the Picnic PQ Signature scheme) to provide a post-quantum proof of secret information a quantum attacker wouldn't be able to easily obtain. * The downside of that is that it reveals the secret BIP 32 seed, exposing other non migrated UTXOs of a user. * With this project I've cobbled together a series of projects to be able to generate a zk-STARK proof that a Taproot output public key was generated via BIP-32 invocation of a BIP-86 derivation path. * In the future a variant of this scheme can be used to enable wallets that generated the private keys via BIP-86, to have a post quantum safe exit path in case they don't bother moving their coins in time to the yet-to-be-decided post quantum signature scheme. To achieve this end, I needed to create/fork a series of repos: * tinygo-zkvm: https://github.com/Roasbeef/tinygo-zkvm * A fork of TinyGo that supports the flavor of RISC-V (rv32im) that risc0 requires to generate/execute a guest program to later be proved by the host. * risc0: https://github.com/Roasbeef/risc0 * Mostly a bug fix to their c-guest example, along with some additional documentation on how to get things running. The repo is unmodified other than that. Recent updates to the repo made the entire process much easier (Go guest+host), more on that later. * go-zkvm: https://github.com/Roasbeef/go-zkvm * Go utilities to take a RISC-V ELf binary produced by tinygo-zkvm, and package it in the expected R0BF format, which combines the user generated RISC-V ELF (the thing that is executed to generate the proof) along with the v1compat ELF kernel, which is risc0's execution environment. * This also includes a Go host package, which loads the guest program, executes it, and generates a trace to later be proved. This is achieved via a C FFI compat layer between Go and the original Rust host/proving/verification code. * bip-32-pq-zkp: https://github.com/Roasbeef/bip32-pq-zkp * The project that packages everything together, this contains the: * Guest Go program that defines the secret witness and claim/constraints of the proof. * The C FFI wrapper around the OG Rust host, which is used to load the guest program, execute it, generate a trace, then finally generate a proof. Details of the final proof as generated on my Mac Book (Apple Silicon M4 Max, 128 GB of RAM): * Takes ~55 seconds or so to generate+proof, including execution. This uses Metal for GPU acceleration on the platform. * Uses ~12 GB of ram. * Final proof size is ~1.7 MB. * Verification takes ~1.8 seconds, and uses ~32 MB of memory. On several layers, this demo is far from optimized (more on that later), this is meant to serve as a PoC to demonstrate that with the latest software+hardware, a proof of this complexity is well within reach. For those curious re the e2e details I've generated this tutorial that explains the entire system top to bottom: https://github.com/Roasbeef/go-zkvm/blob/main/docs/tutorial.md. If you got to this point in this mail, and don't care about the lower level details, thanks for reading up until now, and feel free to return back to the _The Net of a Million Lies_, or as better known in our Universe: Monitoring the Situation and/or slopfotainment! =F0=9F=AB=A1 ## Motivation + Background As commonly known, in the case of an adversary that possesses a quantum computer capable of breaking classical asymmetric cryptography, any coins stored in UTXOs with a known public key are vulnerable. This is the case for any P2PK outputs from waaaay back, and also any other outputs that have revealed their public key. Pubkey reveal might happen due to address re-use (spending from the same script twice), or Taproot outputs, which publish the public key plainly in the pkScript. As detailed in [3], for Taproot outputs, a widely circulated plan is roughly to: disable the _keyspend_ path (requires a simple signature), enforcing a new rule that all Taproot spends must then flow through the script path. Spending via the script path requires an opening of the Taproot commitment (C =3D I + H(I || H(M))), which was shown to be binding even under classic assumptions, as H(M) (tapscript merkle root) is still a collision-resistant function. That means any UTXO that _does_ commit to a script path has a future escape hatch _if_ such a softfork would need to be deployed in the future. However, what about all the other wallets that use BIP 86, and don't commit to a script path at all? Under a strict version of this existing proposal, those wallets would basically be locked forever. The goal of this work is to demonstrate a practical solution (discussed against devs, but never implemented AFAICT): generate a zk proof that an output was generated using BIP-86. For the zk-Proof, we select zk-STARKs, as they're plausibly post quantum since they rely only on symmetric cryptography: layers of merkle trees over an execution trace, along with some novel sampling/error-correction algorithms. At this point, you may be asking: "if the quantum adversary can derive the private key to a random taproot public key, then how exactly does this help?". The answer lies in the structure of BIP-32! BIP-32 takes an initial 128-512-bit seed (with BIP-39, either 12 or 24 words), then runs it through HMAC-SHA512 keyed by "Bitcoin seed" to produce the master extended private key. An adversary who wants to forge this proof needs to find a _colliding_ seed: a different seed s' such that HMAC-SHA512("Bitcoin seed", s') produce= s the same master key. The BHT algorithm (Brassard-Hoyer-Tapp [6]) is the best known quantum collision finder, and it runs in time proportional to th= e cube root of the output space: 2^(n/3). For HMAC-SHA512's 512-bit output, that's ~2^171 quantum operations, well above even NIST's highest post-quantum security category. Therefore, if you generated a wallet using BIP-32, you possess _another_ secret that a quantum adversary can't efficiently reconstruct! This demo focuses on the Taproot case, but the rough approach also applies to any other output generated via BIP-32. BIP 32 was originally published i= n 2012, over 14 years ago. So safe to say that _most_ wallets were generated under this scheme. However, Bitcoin Core only officially adopted BIP-32 in 2016/2018, moving away from their existing key pool structure. I can't say how much BTC is held today in outputs generated with Bitcoin Core's origina= l key pool, but if you have coins generated via that mechanism, you may want to consider migrating them to a BIP-32 wallet. ## TinyGo + RISC-V + risc0 Now for some of the lower level details. risc0 is a STARK based proving system that takes a RISC-V ELF binary generated by a guest program (any program generating using their flavor of rv32im can be proved), executes that in a host environment, generates a trace, then produces a STARK proof from that. Today you can take some subset of Rust, compile it to an ELF using their toolchain, then execute it, generate a trace, to finally prove+verify it using their system. This demo took a bit of a round about journey to achieve this, as after all, the journey is most of the fun, ain't it! For the past 10 years or so, my Bitcoin stack of choice (lnd/btcsuite) uses a series of Go libraries, so I wanted to be able to re-use them, first for this demo, then also in the future for other projects. TinyGo is a special Go compiler based on LLVM, that targets mostly embedded environments. You can use it to generate go programs that can run on micro controllers, or on web assembly (producing a smaller binary than if you used the normal stdlib path). TinyGo supports RISC-V, but _not_ the 32-bit variant of RISC-V that risc0 relies on. So the first step here was to create a new target definition for TinyGo: riscv32-unknown-none, which uses base integer + multiply/divide instructions with no compressed instructions, which uses 4 KB stacks for each task. From there, I created a new linker script (`targets/riscv32im-risc0-zkvm-elf.ld`) which created a memory layer identical to what risc0 expects. The final component was a new runtime (`src/runtime/runtime_zkvm.go`), which implemented a few platform specific syscalls for risc0 (putchar(), exit(), ticks(), and growHeap()). When I tried to get this working last year, I had to also implement a numbe= r of kernel syscalls (called ecalls in the platform [7]) to handle: read+writ= e to stdin/stdout, halting, and the journaling mechanism (the transcript of execution committed to), which basically implement the kernel that the gues= t executes in. Fast forward to 2026, and after pulling the latest version of the repo, I realized that they now make a libzkvm_platform.a, which package= s up the kernel nicely to be linked against. So I threw out my custom kernel code, and slotted that in instead. The final component is a C FFI layer that enables me to use _both_ a Go guest (the program to be proved) and a Go host (the thing that executes the program and generates the final proof). ## BIP-32+Taproot zk-STARK Proof With basic proofs working (like the classic: I know the factorization of a number `n`), I was unblocked to generate the actual proof. The claim/proof is represented with the following JSON artifact: ``` { "schema_version": 1, "image_id": "8a6a2c27dd54d8fa0f99a332b57cb105f88472d977c84bfac077cbe70907a690", "claim_version": 1, "claim_flags": 1, "require_bip86": true, "taproot_output_key": "00324bf6fa47a8d70cb5519957dd54a02b385c0ead8e4f92f9f07f992b288ee6", "path_commitment": "4c7de33d397de2c231e7c2a7f53e5b581ee3c20073ea79ee4afaab56de11f74b", "journal_hex": "010000000100000000324bf6fa47a8d70cb5519957dd54a02b385c0ead8e4f92f9f07f992b= 288ee64c7de33d397de2c231e7c2a7f53e5b581ee3c20073ea79ee4afaab56de11f74b", "journal_size_bytes": 72, "proof_seal_bytes": 1797880, "receipt_encoding": "borsh" } ```` The `image_id` is basically a hash of the ELF, so you know what the prover executed. There are then a few flags that control the claim version and whether BIP-86 derivation is a part of the proof. BIP-86 was only adopted post-Taproot, so if you have an existing BIP-44 path, you can instead opt t= o claim that instead. The Taproot key we're generating the proof against is also part of the _public data_, as it sits plainly on the chain for all to see. We then also include a `path_commitment`, which is a commitment to the exact BIP 86 path that the prover used. Finally, we also commit to the journal hex, which is basically a commitment to the public claim. Assuming you've built the project, then you can generate the proof (even passing in an arbitrary BIP-32 seed and derivation path with) ``` make prove GO_GOROOT=3D/path/to/go1.24.4 ``` Then verify it with: ``` make verify GO_GOROOT=3D/path/to/go1.24.4 ``` The default prove target writes: * ./artifacts/bip32-test-vector.receipt * ./artifacts/bip32-test-vector.claim.json The receipt is the STARK proof artifact. claim.json is the stable, human-readable description of the public statement being proved. ## Application to a Future Keyspend Disabling Soft fork As mentioned above, assuming the community is forced to deploy a keyspend disabling soft fork in the future, we can also deploy some variant of this proof to enable both BIP-86 wallets, and also any BIP-32 wallet, to sweep their funds into a new PQ output. In 2026, we've shown that this is achievable using 2 year old consumer hardware. I don't doubt that the upcoming advancements (eg: photonics, new flavor of high bandwidth memory, etc) in hardware (driven by the fierce AI race) will make such a proof even more feasible. One thing to note is that this proof has a few layers of indirection, mainly the RISC-V layer that adds overhead which increase the total amount of steps, and therefore the size of the proof. A production grade deployment would likely instead hand roll a custom STARK proof for this exact statement, to achieve a faster and smaller proof). # Future Work In terms of future work, there're a number of interesting following up projects that can be pursued from here. One basic one is that the current proof doesn't actually commit to a spending txid and/or sighash. That can be trivially incorporated into the proof. Going a step further, the execution of the guest program can even _generate_ a valid schnorr signature to permit spending. Looking to the memory+computational requirements necessary to generate the proof, I've left two low hanging fruits: 1. First, we can speed up the Elliptic Curve operations the proof requires (scalar base mult, then addition, or more performantly Double Scalar Multiplication via the Strauss-Shamir trick). For this we can use the syscalls/precompile in the risc0 env for big integer arithmetic: sys_bigint and sys_bigint2. With this, the guest calls into the kernel to use an optimized/accelerated circuit for the modular arithmetic, reducing cycles, steps, and thus proof size. 2. Second right now, the entire claim is a single proof. Instead, we can first break that up using their recursive proof/composition syscalls: sys_verify_integrity+sys_verify_integrity2. We can then assembled a series of these proofs into a _single_ statement, which can save block space by aggregating N proofs into a single proof. -- Laolu [1]: https://tinygo.org/ [2]: https://risczero.com/ [3]: https://eprint.iacr.org/2025/1307 [4]: https://eprint.iacr.org/2023/362 [5]: https://microsoft.github.io/Picnic/ [6]: https://en.wikipedia.org/wiki/BHT_algorithm [7]: https://github.com/Roasbeef/go-zkvm/blob/main/docs/ecall-reference.md --=20 You received this message because you are subscribed to the Google Groups "= Bitcoin Development Mailing List" group. To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoindev+unsubscribe@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/= CAO3Pvs_PciUi%2BzBrCps3acO14sgeHVUANx9w6TVwUf_AYcd_qQ%40mail.gmail.com. --000000000000192982064eeaa7ea Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi y'all,

I f= ound some spare time this last weekend to dust off a little side projectI started last August: extend TinyGo [1] to be able to produce RISC-V ELF<= br>binaries capable of being run as a guest on the risc0 platform to genera= te
zk-STARK proofs of arbitrary programs. Initially, I didn't really= have a
clear end target application, it was mainly a technical challeng= e to force
me to learn a bit more about the RISC-V platform, and also th= e host/guest
architecture of risc0. Fast forward ~9 months later, and an= initial killer
use case popped into my mind: a zk-STARK proof that a Ta= proot output public
key was generated using BIP-32, via a given BIP-86 d= erivation path.

More formally:
```math
\mathcal{R} =3D \left\l= brace\;
(\overbrace{K,\, C}^{\textsf{public}} ;\; \underbrace{s,\, \math= bf{p}}_{\textsf{witness}})
\;\middle|\;
\begin{aligned}
=C2=A0 K &= amp;=3D \textsf{BIP86Taproot}\bigl(\textsf{BIP32Derive}(s,\, \mathbf{p})\bi= gr) \\
=C2=A0 C &=3D \textsf{SHA256}\bigl(\texttt{"bip32-pq-zkp= :path:v1"} \;\|\; \mathbf{p}\bigr)
\end{aligned}
\;\right\rbrace=
```

where $K$ is the Taproot output key, $C$ is the path commitm= ent, $s$ is the
BIP-32 seed, and $\mathbf{p}$ is the derivation path.

I was able to get everything working e2e over the weekend, after m= aking
some tweaks to my initial architectural game plan!

The TL;D= R is that:

=C2=A0 * Given that the Taproot commitment scheme is post= -quantum secure [3], in
=C2=A0 =C2=A0 the future we can deploy a soft fo= rk to _disable_ the keyspend path,
=C2=A0 =C2=A0 and force all Taproot s= pends to instead flow through the script path
=C2=A0 =C2=A0 (not my idea= , commonly discussed amongst developers, not sure who
=C2=A0 =C2=A0 prop= osed it first). At that point, Taproot starts to resemble BIP-360.

= =C2=A0 * That works for script path spends, but then leaves all the BIP-86<= br>=C2=A0 =C2=A0 wallets in a bad position, as they generated outputs that = provably
=C2=A0 =C2=A0 don't commit to a script path at all.

= =C2=A0 * A 2023 paper (Protecting Quantum Procrastinators with Signature=C2=A0 =C2=A0 Lifting: A Case Study in Cryptocurrencies [4]) proposed a so= lution to this,
=C2=A0 =C2=A0 namely _seed lifting_ (use BIP-32 as the o= ne-way function to the
=C2=A0 =C2=A0 Picnic PQ Signature scheme) to prov= ide a post-quantum proof of secret
=C2=A0 =C2=A0 information a quantum a= ttacker wouldn't be able to easily obtain.

=C2=A0 * The downside= of that is that it reveals the secret BIP 32 seed,
=C2=A0 =C2=A0 exposi= ng other non migrated UTXOs of a user.

=C2=A0 * With this project I&= #39;ve cobbled together a series of projects to be able
=C2=A0 =C2=A0 to= generate a zk-STARK proof that a Taproot output public key was
=C2=A0 = =C2=A0 generated via BIP-32 invocation of a BIP-86 derivation path.

= =C2=A0 * In the future a variant of this scheme can be used to enable walle= ts
=C2=A0 =C2=A0 that generated the private keys via BIP-86, to have a p= ost quantum safe
=C2=A0 =C2=A0 exit path in case they don't bother m= oving their coins in time to the
=C2=A0 =C2=A0 yet-to-be-decided post qu= antum signature scheme.

To achieve this end, I needed to create/fork= a series of repos:

=C2=A0 * tinygo-zkvm: https://github.com/Roasbeef/tinygo-zkvm
= =C2=A0 =C2=A0 * A fork of TinyGo that supports the flavor of RISC-V (rv32im= ) that
=C2=A0 =C2=A0 =C2=A0 risc0 requires to generate/execute a guest p= rogram to later be proved
=C2=A0 =C2=A0 =C2=A0 by the host.

=C2= =A0 * risc0: https://github.c= om/Roasbeef/risc0
=C2=A0 =C2=A0 * Mostly a bug fix to their c-guest = example, along with some
=C2=A0 =C2=A0 =C2=A0 additional documentation o= n how to get things running. The repo is
=C2=A0 =C2=A0 =C2=A0 unmodified= other than that. Recent updates to the repo made the
=C2=A0 =C2=A0 =C2= =A0 entire process much easier (Go guest+host), more on that later.

= =C2=A0 * go-zkvm: https://g= ithub.com/Roasbeef/go-zkvm
=C2=A0 =C2=A0 * Go utilities to take a RI= SC-V ELf binary produced by tinygo-zkvm, and
=C2=A0 =C2=A0 =C2=A0 packag= e it in the expected R0BF format, which combines the user
=C2=A0 =C2=A0 = =C2=A0 generated RISC-V ELF (the thing that is executed to generate the
= =C2=A0 =C2=A0 =C2=A0 proof) along with the v1compat ELF kernel, which is ri= sc0's execution
=C2=A0 =C2=A0 =C2=A0 environment.

=C2=A0 =C2= =A0 * This also includes a Go host package, which loads the guest program,<= br>=C2=A0 =C2=A0 =C2=A0 executes it, and generates a trace to later be prov= ed. This is
=C2=A0 =C2=A0 =C2=A0 achieved via a C FFI compat layer betwe= en Go and the original Rust
=C2=A0 =C2=A0 =C2=A0 host/proving/verificati= on code.

=C2=A0 * bip-32-pq-zkp: https://github.com/Roasbeef/bip32-pq-zkp
=C2=A0 = =C2=A0 * The project that packages everything together, this contains the:<= br>=C2=A0 =C2=A0 =C2=A0 * Guest Go program that defines the secret witness = and
=C2=A0 =C2=A0 =C2=A0 =C2=A0 claim/constraints of the proof.

= =C2=A0 =C2=A0 =C2=A0 * The C FFI wrapper around the OG Rust host, which is = used to load
=C2=A0 =C2=A0 =C2=A0 =C2=A0 the guest program, execute it, = generate a trace, then finally
=C2=A0 =C2=A0 =C2=A0 =C2=A0 generate a pr= oof.

Details of the final proof as generated on my Mac Book (Apple S= ilicon M4
Max, 128 GB of RAM):
=C2=A0 * Takes ~55 seconds or so to ge= nerate+proof, including execution. This
=C2=A0 =C2=A0 uses Metal for GPU= acceleration on the platform.
=C2=A0 * Uses ~12 GB of ram.
=C2=A0 * = Final proof size is ~1.7 MB.
=C2=A0 * Verification takes ~1.8 seconds, a= nd uses ~32 MB of memory.

On several layers, this demo is far from o= ptimized (more on that later),
this is meant to serve as a PoC to demons= trate that with the latest
software+hardware, a proof of this complexity= is well within reach.

For those curious re the e2e details I've= generated this tutorial that
explains the entire system top to bottom:<= br>https://github.com/Roasbeef/go-zkvm/blob/main/docs/tutorial.md.
<= br>If you got to this point in this mail, and don't care about the lowe= r level
details, thanks for reading up until now, and feel free to retur= n back to
the _The Net of a Million Lies_, or as better known in our Uni= verse:
Monitoring the Situation and/or slopfotainment! =F0=9F=AB=A1
<= br>## Motivation + Background

As commonly known, in the case of an a= dversary that possesses a quantum
computer capable of breaking classical= asymmetric cryptography, any coins
stored in UTXOs with a known public = key are vulnerable. This is the case
for any P2PK outputs from waaaay ba= ck, and also any other outputs that have
revealed their public key. Pubk= ey reveal might happen due to address re-use
(spending from the same scr= ipt twice), or Taproot outputs, which publish
the public key plainly in = the pkScript.

As detailed in [3], for Taproot outputs, a widely circ= ulated plan is
roughly to: disable the _keyspend_ path (requires a simpl= e signature),
enforcing a new rule that all Taproot spends must then flo= w through the
script path. Spending via the script path requires an open= ing of the
Taproot commitment (C =3D I + H(I || H(M))), which was shown = to be binding even
under classic assumptions, as H(M) (tapscript merkle = root) is still a
collision-resistant function.

That means any UTX= O that _does_ commit to a script path has a future escape
hatch _if_ suc= h a softfork would need to be deployed in the future.
However, what abou= t all the other wallets that use BIP 86, and don't commit
to a scrip= t path at all? Under a strict version of this existing
proposal, those w= allets would basically be locked forever.

The goal of this work is t= o demonstrate a practical solution (discussed
against devs, but never im= plemented AFAICT): generate a zk proof that an
output was generated usin= g BIP-86. For the zk-Proof, we select zk-STARKs,
as they're plausibl= y post quantum since they rely only on symmetric
cryptography: layers of= merkle trees over an execution trace, along with
some novel sampling/er= ror-correction algorithms.

At this point, you may be asking: "i= f the quantum adversary can derive the
private key to a random taproot p= ublic key, then how exactly does this
help?". The answer lies in th= e structure of BIP-32! BIP-32 takes an initial
128-512-bit seed (with BI= P-39, either 12 or 24 words), then runs it through
HMAC-SHA512 keyed by = "Bitcoin seed" to produce the master extended private
key. An = adversary who wants to forge this proof needs to find a _colliding_
seed= : a different seed s' such that HMAC-SHA512("Bitcoin seed", s= ') produces
the same master key. The BHT algorithm (Brassard-Hoyer-T= app [6]) is the
best known quantum collision finder, and it runs in time= proportional to the
cube root of the output space: 2^(n/3). For HMAC-SH= A512's 512-bit output,
that's ~2^171 quantum operations, well ab= ove even NIST's highest
post-quantum security category. Therefore, i= f you generated a wallet using
BIP-32, you possess _another_ secret that= a quantum adversary can't
efficiently reconstruct!

This demo= focuses on the Taproot case, but the rough approach also applies
to any= other output generated via BIP-32. BIP 32 was originally published in
2= 012, over 14 years ago. So safe to say that _most_ wallets were generatedunder this scheme. However, Bitcoin Core only officially adopted BIP-32 i= n
2016/2018, moving away from their existing key pool structure. I can&#= 39;t say
how much BTC is held today in outputs generated with Bitcoin Co= re's original
key pool, but if you have coins generated via that mec= hanism, you may want
to consider migrating them to a BIP-32 wallet.
<= br>## TinyGo + RISC-V + risc0

Now for some of the lower level detail= s. risc0 is a STARK based proving
system that takes a RISC-V ELF binary = generated by a guest program (any
program generating using their flavor = of rv32im can be proved), executes
that in a host environment, generates= a trace, then produces a STARK proof
from that.

Today you can ta= ke some subset of Rust, compile it to an ELF using their
toolchain, then= execute it, generate a trace, to finally prove+verify it
using their sy= stem.

This demo took a bit of a round about journey to achieve this,= as after
all, the journey is most of the fun, ain't it!

For = the past 10 years or so, my Bitcoin stack of choice (lnd/btcsuite) uses
= a series of Go libraries, so I wanted to be able to re-use them, first for<= br>this demo, then also in the future for other projects.

TinyGo is = a special Go compiler based on LLVM, that targets mostly embedded
enviro= nments. You can use it to generate go programs that can run on
micro con= trollers, or on web assembly (producing a smaller binary than if
you use= d the normal stdlib path).

TinyGo supports RISC-V, but _not_ the 32-= bit variant of RISC-V that risc0
relies on. So the first step here was t= o create a new target definition for
TinyGo: riscv32-unknown-none, which= uses base integer + multiply/divide
instructions with no compressed ins= tructions, which uses 4 KB stacks for
each task. From there, I created a= new linker script
(`targets/riscv32im-risc0-zkvm-elf.ld`) which created= a memory layer
identical to what risc0 expects. The final component was= a new runtime
(`src/runtime/runtime_zkvm.go`), which implemented a few = platform specific
syscalls for risc0 (putchar(), exit(), ticks(), and gr= owHeap()).

When I tried to get this working last year, I had to also= implement a number
of kernel syscalls (called ecalls in the platform [7= ]) to handle: read+write
to stdin/stdout, halting, and the journaling me= chanism (the transcript of
execution committed to), which basically impl= ement the kernel that the guest
executes in. Fast forward to 2026, and a= fter pulling the latest version of
the repo, I realized that they now ma= ke a libzkvm_platform.a, which packages
up the kernel nicely to be linke= d against. So I threw out my custom kernel
code, and slotted that in ins= tead.

The final component is a C FFI layer that enables me to use _b= oth_ a Go
guest (the program to be proved) and a Go host (the thing that= executes the
program and generates the final proof).

## BIP-32+T= aproot zk-STARK Proof

With basic proofs working (like the classic: I= know the factorization of a
number `n`), I was unblocked to generate th= e actual proof. The claim/proof
is represented with the following JSON a= rtifact:
```
{
=C2=A0 "schema_version": 1,
=C2=A0 &qu= ot;image_id": "8a6a2c27dd54d8fa0f99a332b57cb105f88472d977c84bfac0= 77cbe70907a690",
=C2=A0 "claim_version": 1,
=C2=A0 &qu= ot;claim_flags": 1,
=C2=A0 "require_bip86": true,
=C2= =A0 "taproot_output_key": "00324bf6fa47a8d70cb5519957dd54a02= b385c0ead8e4f92f9f07f992b288ee6",
=C2=A0 "path_commitment"= ;: "4c7de33d397de2c231e7c2a7f53e5b581ee3c20073ea79ee4afaab56de11f74b&q= uot;,
=C2=A0 "journal_hex": "010000000100000000324bf6fa47= a8d70cb5519957dd54a02b385c0ead8e4f92f9f07f992b288ee64c7de33d397de2c231e7c2a= 7f53e5b581ee3c20073ea79ee4afaab56de11f74b",
=C2=A0 "journal_si= ze_bytes": 72,
=C2=A0 "proof_seal_bytes": 1797880,
=C2= =A0 "receipt_encoding": "borsh"
}
````

The= `image_id` is basically a hash of the ELF, so you know what the prover
= executed. There are then a few flags that control the claim version and
= whether BIP-86 derivation is a part of the proof. BIP-86 was only adoptedpost-Taproot, so if you have an existing BIP-44 path, you can instead opt= to
claim that instead. The Taproot key we're generating the proof a= gainst is
also part of the _public data_, as it sits plainly on the chai= n for all to
see. We then also include a `path_commitment`, which is a c= ommitment to the
exact BIP 86 path that the prover used. Finally, we als= o commit to the
journal hex, which is basically a commitment to the publ= ic claim.

Assuming you've built the project, then you can genera= te the proof (even
passing in an arbitrary BIP-32 seed and derivation pa= th with)
```
make prove GO_GOROOT=3D/path/to/go1.24.4
```

T= hen verify it with:
```
make verify GO_GOROOT=3D/path/to/go1.24.4
= ```

The default prove target writes:
=C2=A0 * ./artifacts/bip32-t= est-vector.receipt
=C2=A0 * ./artifacts/bip32-test-vector.claim.json
=
The receipt is the STARK proof artifact. claim.json is the stable,
h= uman-readable description of the public statement being proved.

## A= pplication to a Future Keyspend Disabling Soft fork

As mentioned abo= ve, assuming the community is forced to deploy a keyspend
disabling soft= fork in the future, we can also deploy some variant of
this proof to en= able both BIP-86 wallets, and also any BIP-32 wallet, to
sweep their fun= ds into a new PQ output.

In 2026, we've shown that this is achie= vable using 2 year old consumer
hardware. I don't doubt that the upc= oming advancements (eg: photonics, new
flavor of high bandwidth memory, = etc) in hardware (driven by the fierce AI
race) will make such a proof e= ven more feasible.

One thing to note is that this proof has a few la= yers of indirection,
mainly the RISC-V layer that adds overhead which in= crease the total amount
of steps, and therefore the size of the proof. A= production grade
deployment would likely instead hand roll a custom STA= RK proof for this
exact statement, to achieve a faster and smaller proof= ).

# Future Work

In terms of future work, there're a numb= er of interesting following up
projects that can be pursued from here.
One basic one is that the current proof doesn't actually commit t= o a
spending txid and/or sighash. That can be trivially incorporated int= o the
proof. Going a step further, the execution of the guest program ca= n even
_generate_ a valid schnorr signature to permit spending.

L= ooking to the memory+computational requirements necessary to generate theproof, I've left two low hanging fruits:

=C2=A01. First, we ca= n speed up the Elliptic Curve operations the proof requires
=C2=A0 =C2= =A0 (scalar base mult, then addition, or more performantly Double Scalar=C2=A0 =C2=A0 Multiplication via the Strauss-Shamir trick). For this we ca= n use the
=C2=A0 =C2=A0 syscalls/precompile in the risc0 env for big int= eger arithmetic:
=C2=A0 =C2=A0 sys_bigint and sys_bigint2. With this, th= e guest calls into the kernel
=C2=A0 =C2=A0 to use an optimized/accelera= ted circuit for the modular arithmetic,
=C2=A0 =C2=A0 reducing cycles, s= teps, and thus proof size.

=C2=A02. Second right now, the entire cla= im is a single proof. Instead, we can
=C2=A0 =C2=A0 first break that up = using their recursive proof/composition syscalls:
=C2=A0 =C2=A0 sys_veri= fy_integrity+sys_verify_integrity2. We can then assembled a
=C2=A0 =C2= =A0 series of these proofs into a _single_ statement, which can save block<= br>=C2=A0 =C2=A0 space by aggregating N proofs into a single proof.

= -- Laolu

[1]: https://tinygo.org/

[2]:
https://risczero.com/
[3]: https://eprint.iac= r.org/2025/1307

[4]: https://eprint.iacr.org/2023/362

[5]: https://microsoft.github.io/Picnic/

[6]:= https://en.wikiped= ia.org/wiki/BHT_algorithm

[7]: https://github.com/Roasbee= f/go-zkvm/blob/main/docs/ecall-reference.md

--
You received this message because you are subscribed to the Google Groups &= quot;Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoind= ev+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/= msgid/bitcoindev/CAO3Pvs_PciUi%2BzBrCps3acO14sgeHVUANx9w6TVwUf_AYcd_qQ%40ma= il.gmail.com.
--000000000000192982064eeaa7ea--