From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Tue, 14 Apr 2026 08:55:02 -0700 Received: from mail-oa1-f56.google.com ([209.85.160.56]) by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1wCg6M-00036b-1c for bitcoindev@gnusha.org; Tue, 14 Apr 2026 08:55:02 -0700 Received: by mail-oa1-f56.google.com with SMTP id 586e51a60fabf-40efa542b8asf7689230fac.2 for ; Tue, 14 Apr 2026 08:54:57 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1776182092; cv=pass; d=google.com; s=arc-20240605; b=OPzBUUy+VOS5q5mzkLukTLAH4Foero6IRryKWYSOL4se88qU6oDpUll+qnprwn0Fx0 nS+sYFLNQOIm4xzVnS0Z5FSYsbatbVp7G7b2mVHfV2S6I9U7ZQASGEXGHnyKqTqIhzY7 LYciWGvkku3q/BO/Fuzk/OW0uuofjri4XcKXK/QO/66lkCYY4Fomrz/REs2GCJfA5Ciy 7X/3novks0KQBrq6g5gUM4rLbR1Ar4PKLaJjvC1Esi1MQaUsqfrZ3BVb8ESkW0cz3VhO jB4zwMZQAcfA2YN+9rXcgX/Btr1of9Y9tN7kBQ/FT1/4KcgoNQ5BI0fhFeLzj1eK07w2 pL3Q== ARC-Message-Signature: i=2; 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:reply-to:mime-version:feedback-id :references:in-reply-to:message-id:subject:cc:from:to:date :dkim-signature; bh=cKxZJ8/yPmozyJfpcoQ3xNHh11uWaQ7jY2ZplHeAViU=; fh=EBwNmeprrAOHAcl1/Nrlo6pX+YMy27OgBCjeV10UtP8=; b=hEXGur34EK79wBwfcZM+f6X4TDh8l5NyRjm3abkhA7B4icF118eOyAryg93aiNsuGR rbv2EHY2BWtb/PtgDkvs1IPfhzQscWEv/IxPh/7bYeje1S1iTDZyVnLctXmEMfrWE4Cr 1/DbjrFKODYOyX/gq0FONdc9eJHc1awSU1ZdG9WMmu1Vst77Z6iji2vdH55KBe1fm7qq yCPjIU5HW0v3pVrABB1dtuwJUrvFxX6DiQ8vP9XfFJijZhdp8/oWhECjs6KuhZ+326Y1 h+a7srm3rwgMiiyJCxgaWLXw1D4zXQSbn1J6kFqM1FtPJWnW07wXMZnZaEI6N2y29UrM qdnA==; darn=gnusha.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=B6f6ufW8; spf=pass (google.com: domain of conduition@proton.me designates 109.224.244.27 as permitted sender) smtp.mailfrom=conduition@proton.me; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1776182092; x=1776786892; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :date:from:to:cc:subject:date:message-id:reply-to; bh=cKxZJ8/yPmozyJfpcoQ3xNHh11uWaQ7jY2ZplHeAViU=; b=LLqlzFxJas+NvXKQTLwoABLpX1bf9DuxzCnFhDORuJc6WMZNlptnqFrLRrfxD7Ptr+ bDtK6ykZwxnOJXNSodWgv6VFP1PSjLA3aFL0Ku1a5CZSdsLbNbiQwE0lYfcJejup10ME R9iZY9VApf8urG/t5Rl1uITFnQU3WdHbTnMPcU+dcZ0lVzwNYthLC+vamP/noUWMjDxd Yd4tm8YE6MDk2JU7DUnLJjaiV+RMAn0JHo/8YfAdsqz8usilCvzyFwX+lC9k50DISc1t tQdA43Rg+SQR0OiYhGZ5yg5RMCFT4zV8GoARXnebIUaw1/xowNlBdKYGbHCkAX3FMLOK /uqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776182092; x=1776786892; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :date:x-beenthere:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=cKxZJ8/yPmozyJfpcoQ3xNHh11uWaQ7jY2ZplHeAViU=; b=F3guKdrS4+yIzn+6t+iZOfSK4JhCcSxhKUg252XHWBW3IJc7o0tVbY367nTbPVLLof rnID20aN4F2Awu02DyMo9ownnWrWX3AU3bv33rUmH9b5n5O9FjzSSQLni71/z3v0DD/H RqOdp3UnH5gIpdHgasKZv/C1J4xVYycCHcYEM1YlJmEx274ClrLQHvs5GFgIQE5XOoNp MO3FzvtWm+Uf7DpHFK7aRDeo1bZYkV/SuEtl2b7jBV+TlZeZHAZFSg0RSGuyONTiO40C H+mVG4eIGQKNVCKpOdrAdJ5krVMvsryGAOuZIBw58PkuI3bZa6cmAqaLgTIwqg6NRvws gvlg== X-Forwarded-Encrypted: i=2; AFNElJ8oW2MC0Vp8hHmWsN8aoEOJPZSzHz48mPhfX6514F55Rhig5lR6a21dWOv5yoVaYmBKnrGNlNTOqSC8@gnusha.org X-Gm-Message-State: AOJu0YwWiyK4Vs9TvxTPna3AqakOFZ/ZyRXZmWWGrmXWhKeHQnkuCqhh S9cLGoQC1jdCXjeQWEm8j6FXsLGZbR5vtmMNHLD4x1wr2M0ynWEoRS0O X-Received: by 2002:a05:6871:c713:b0:416:b429:28e with SMTP id 586e51a60fabf-423e101883bmr9605051fac.20.1776182091608; Tue, 14 Apr 2026 08:54:51 -0700 (PDT) X-BeenThere: bitcoindev@googlegroups.com; h="AYAyTiLvfbRHFE3e3EDKu/qio46JoIiM1YPCdNz+FiD0GFNLrw==" Received: by 2002:a05:6870:b9b:b0:423:2c4e:f14b with SMTP id 586e51a60fabf-423dd9a3e41ls2485638fac.1.-pod-prod-01-us; Tue, 14 Apr 2026 08:54:47 -0700 (PDT) X-Received: by 2002:a05:6808:17a0:b0:46a:d9fc:1425 with SMTP id 5614622812f47-4789f10762dmr9447962b6e.34.1776182087222; Tue, 14 Apr 2026 08:54:47 -0700 (PDT) Received: by 2002:a05:6808:30da:b0:46b:22a1:35fc with SMTP id 5614622812f47-47974646e16msb6e; Tue, 14 Apr 2026 08:53:03 -0700 (PDT) X-Received: by 2002:a05:6a00:391a:b0:82f:5726:be23 with SMTP id d2e1a72fcca58-82f5726c0a3mr3027116b3a.49.1776181982156; Tue, 14 Apr 2026 08:53:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1776181982; cv=none; d=google.com; s=arc-20240605; b=RrcWacCpZ8F+QHiCKQgMdtL+RrJrsrTkxEp9eI0RjB5IZs83ijIDP6Ds21QUsSclkb 0escwAURy25NwpnbYRUO3C0SCBT7SCi0e5zhTlk2yHSDnxVU1HcAvreRL/Zvvgl/9pK+ GHmu0o+rQxQQkGxwyKBxWTJpzCa7nShSva1UGdC12Enpi7aqvjJuMT07RShOl8wl+Vvy hzmd5PEVlVHkvOkP/Gbqje298ABdbpsSEUlLBmf0ff1CjZL9cAhBzSU0zPk+lSVP6LYO 8HXZoUo8hqTiXsLAuSFlGfAgpbBr2d+79/y7h2kooMIFKCUXCP+7cuZiaV1+cIpSq9Ua vvRQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=mime-version:feedback-id:references:in-reply-to:message-id:subject :cc:from:to:date:dkim-signature; bh=HRwkut3JcWcUvci+ltn3ERh5xufnOVxrw5WaduV8ams=; fh=apggEuJgW4uaLwt6WMeOWmRsxbdevZ9R4Mlfs7LDMYo=; b=V7SSBdgVEVHgQQJ9GtiT0/X59+u1RtSRdAAerGBAHizq9F9BKO5ml4GVWNSnuBNINI DxrYlamb4yoiK/COCtify9/ekhspv7OU7gc6xN2QsEuLgf0ftfWeG8TQll16SZtl1x96 kNPWQUQZEJQRPVsJORn5XHR7Fr6qhv58DcRCPWRK/ITP49QbYryD1mOutlQbrvepirXG TCGLPb2IFKLLw+ryd9oTzX/eXBC47kSDZPm4ll/pZf6G5PaHMCI1O+aL/TnyDXUZ6kTm qEkOCJ6dAG28H8ViCnNXNBmSJLeGdoIXN8N1xUeYCyILZZN7r5P7DTQsu4d5Z8A49ph8 kSCA==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=B6f6ufW8; spf=pass (google.com: domain of conduition@proton.me designates 109.224.244.27 as permitted sender) smtp.mailfrom=conduition@proton.me; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from mail-24427.protonmail.ch (mail-24427.protonmail.ch. [109.224.244.27]) by gmr-mx.google.com with ESMTPS id d2e1a72fcca58-82f0c448437si488503b3a.6.2026.04.14.08.53.01 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Apr 2026 08:53:02 -0700 (PDT) Received-SPF: pass (google.com: domain of conduition@proton.me designates 109.224.244.27 as permitted sender) client-ip=109.224.244.27; Date: Tue, 14 Apr 2026 15:52:51 +0000 To: sadiq Ismail From: "'conduition' via Bitcoin Development Mailing List" Cc: Bitcoin Development Mailing List Subject: Re: [bitcoindev] Post-Quantum BIP-86 Recovery via zk-STARK Proof of BIP-32 Seed Knowledge Message-ID: In-Reply-To: <02378fd1-17a4-47aa-89fa-ee87626def65n@googlegroups.com> References: <02378fd1-17a4-47aa-89fa-ee87626def65n@googlegroups.com> Feedback-ID: 72003692:user:proton X-Pm-Message-ID: a33f412531547240283c5baf93f794a351170fd4 MIME-Version: 1.0 Content-Type: multipart/signed; protocol="application/pgp-signature"; micalg=pgp-sha512; boundary="------bf7d74349df6eed82a8afa99fde8c11e4be5a55ecf0338d3cddda146c4f8420d"; charset=utf-8 X-Original-Sender: conduition@proton.me X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=B6f6ufW8; spf=pass (google.com: domain of conduition@proton.me designates 109.224.244.27 as permitted sender) smtp.mailfrom=conduition@proton.me; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me X-Original-From: conduition Reply-To: conduition 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: -1.0 (-) This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --------bf7d74349df6eed82a8afa99fde8c11e4be5a55ecf0338d3cddda146c4f8420d Content-Type: multipart/mixed;boundary=---------------------e804b9dfced1a04be2dd09b3e2737b4f -----------------------e804b9dfced1a04be2dd09b3e2737b4f Content-Type: multipart/alternative;boundary=---------------------c2d9ccf5eaa15e50460689f32fb8a6be -----------------------c2d9ccf5eaa15e50460689f32fb8a6be Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="UTF-8" Hi Abubakar, Awesome point! A single STARK could be used to prove you knew an xpriv whic= h derives the xpriv at `m/352'/coin'/account'`. Then any verifier could eas= ily derive the private scan/spend keys=C2=A0`m/352'/coin'/account'/0'/0` or= `m/352'/coin'/account'/1'/0`, then replicate the ECDH process (with some B= IP352-specific tweaks that the spender can provide), and add the result tog= ether. This reproduces the private key of the SP taproot output being spent= , proving the spender is authentic. With proper labeling of input metadata, this procedure could cover every UT= XO in a silent payment wallet, because the scan/spend keys are common to ev= ery derived output-specific address. > Curious why not generalise beyond BIP-32? P2PKH and P2WPKH without BIP-32= still commit to an unrevealed secret =E2=80=94 HASH160(k=C2=B7G) =E2=80=94= as long as the pubkey has never previously appeared on-chain. A zk-STARK p= roof should apply here too? The prover argues for the correctness of HASH16= 0(k=C2=B7G) =3D h, where k is the private key scalar and k=C2=B7G is the el= liptic-curve point, without ever revealing k or the pubkey. This would allo= w recovery of a broader set of funds. I agree this type of thing would also be useful, but it is harder to argue = security for this than for BIP32 xpriv ownership. Typically, xpubs and xprivs are not shared on-chain, and wallets usually tr= eat them with greater care since xpubs compromise privacy, and xprivs compr= omise security. Hashed address pubkeys on the other hand are commonly shared on-chain and a= lmost never treated as sensitive. So it seems likely that if we DO permit s= pending using a ZK proof of knowledge of `k` such that `HASH160(k*G) =3D h`= , then some non-negligible fraction of those coins will still be vulnerable= to a CRQC because `k*G` may be known to the attacker, which to a CRQC is e= quivalent to knowing `k`.=C2=A0 To mitigate, a verifier would need to reject such proofs when someone tries= to spend coins locked to such an "exposed pubkey" address. Since bitcoin n= odes do not maintain an address index, they don't intrinsically know which = addresses have exposed pubkeys or not. We would have to compose a list of s= uch addresses, and since that list changes over time, it would need to be u= pdated by nodes in real-time when indexing transactions. This list will alm= ost certainly be incomplete, because we don't have any record of pubkeys ex= posed off-chain (e.g. by hardware wallets, by xpubs shared in multi-party p= rotocols, by lost TXs in orphaned blocks). This idea also collides very unfortunately with the BIP32 xpriv proof of kn= owledge. With the faster proof style i suggested to modify Laolu's original= one, a spender immediately gives up knowledge of their account-level xpriv= to the CRQC when publishing a TX. Even if the spender was using a hashed-a= ddress with a hidden pubkey,=C2=A0the CRQC now knows the secret key=C2=A0`k= ` for that address, and could use it to forge a proof that `h =3D HASH160(k= *G)` to attempt to double-spend/RBF the authentic transaction. So we can't just add hashed-address proofs alongside BIP32 xpriv proofs. Th= ey'd have to be mutually exclusive: A verifier would accept a BIP32 xpriv p= roof if and only if the address is on the "exposed pubkey" list. The verifi= er would accept a hashed-address proof if and only if the address is NOT on= the "exposed pubkey" list. It's definitely feasible, it's just hard to do = both safely. This is also difficult to motivate, as we lack hard statistics about the re= levant portion of the Bitcoin supply that we could use hashed-address proof= s (but not BIP32 proofs) to rescue: Those UTXOs which fall into the venn-di= agram overlap of "Not using BIP32" and "Not exposed-pubkey". BIP32 was intr= oduced in 2012, whereas P2PKH was introduced in 2009, so clearly there must= be=C2=A0some=C2=A0overlap, but how much? I suppose one could estimate by i= ndexing all the P2PKH UTXOs received before BIP32 was published, and counti= ng what portion of them still have (probably) hidden public keys. This woul= d be useful research for anyone with the time and a working node. regards, conduition On Monday, April 13th, 2026 at 2:21 PM, sadiq Ismail wrote: > Hi Laolu, list, >=20 > Nice work. >=20 > The scheme extends to BIP-352 (Silent Payments). The BIP-352 receiver rec= onstructs the output P using their private scan key, public spend key, and = public information from the spending transaction A. > See BIP-352 Scanning. BIP-352 recommends but does not mandate BIP-32 for = deriving the scan and spend keys, but specifies the following derivation pa= ths when BIP-32 is used: >=20 > b_scan =3D BIP32Derive(s, m/352'/coin_type'/account'/1'/0) > b_spend =3D BIP32Derive(s, m/352'/coin_type'/account'/0'/0) >=20 > For all silent payment addresses generated using BIP-32, your technique a= pplies. The prover produces a zk-STARK proof that the program BIP32Derive(s= , p_scan) and BIP32Derive(s, p_spend) were run correctly, > and that the resulting keys reconstruct the on-chain output P using along= with A. >=20 > As you highlighted txid is not committed in the proof currently, the argu= ment is replayable. The current POC does not bind to where the coins go. An= yone who observes the chain could copy it and attach it to a different tran= saction, spending the same UTXO to a different address. Worse for silent pa= yment, because all user UTXO have the same secret BIP32Derive(s, p_scan) an= d BIP32Derive(s, p_spend) except for A. > The zk-STARK proof? or this mechanism should definitely be bound to the s= pending transaction and the input being spent. >=20 > Curious why not generalise beyond BIP-32? P2PKH and P2WPKH without BIP-32= still commit to an unrevealed secret =E2=80=94 HASH160(k=C2=B7G) =E2=80=94= as long as the pubkey has never previously appeared on-chain. A zk-STARK p= roof should apply here too? The prover argues for the correctness of HASH16= 0(k=C2=B7G) =3D h, where k is the private key scalar and k=C2=B7G is the el= liptic-curve point, without ever revealing k or the pubkey. This would allo= w recovery of a broader set of funds. If it were decided that classical sig= natures for these output types are invalidated and only a valid zk-STARK pr= oof is required to spend, anyone who holds the original secret can unlock t= heir funds. >=20 > P.S. I am not for or against disabling valid spend paths post-quantum, ju= st discussing the technical possibilities. >=20 > Best, > Abubakar Sadiq > On Friday, April 10, 2026 at 7:47:09=E2=80=AFPM UTC+2 conduition wrote: >=20 > > Ah! Amazing work! 2 seconds to prove is really crazy. Proving a single = SHA256 and one modular addition on my CPU back in the day took like 20 seco= nds. Your GPU is coming in clutch for this. I best RISC0 has also improved = quite a bit since then. > > I think the next optimization step would be pre-seeding the two SHA512 = midstates from the host, so you only need to prove two SHA512 compression c= alls instead of four. Intuitively I expect this would at best halve your pr= over time from 2sec, to probably a little over 1sec, and your verifier time= will probably drop as well since that also seems to scale with circuit com= plexity. > >=20 > > I think I have two half-decent arguments now as to why this won't affec= t security: > >=20 > > First, even if a fraudulent prover is handed the correct midstates to u= se, the prover would still have to do the hard work of finding the parent s= ecret key needed as a witness. This is at least the same difficulty as find= ing the parent `sk` if we just hashed it without a chaincode at all, using = two bare SHA512 calls - the only thing that changes is the midstate, and th= e SHA512 input length suffix. Starting from a different midstate doesn't ma= gically give the attacker a head-start in a 256-bit search space looking fo= r `sk`. A frauduent prover would know the child secret key `k =3D sk + int(= I[32:]) % n`, but they don't know `int(I[32:])` or `sk` so they cannot solv= e for either. > >=20 > >=20 > > Nominally, the fraudulent prover wouldn't even know the correct midstat= es, so their task is strictly harder. > >=20 > > Secondly, here's another argument as to why finding the midstates in th= e first place should also be hard. > >=20 > >=20 > > Any adversary who could solve this problem by finding the right midstat= es could be used as an oracle to prove the existence of partial 2-cycles in= SHA512. > >=20 > >=20 > > - Given a SHA512 hash `I`, set `sk =3D int(I[32:])` > > - Compute `k =3D sk + sk % n` > > - Use the black-box fraudulent prover on the child key `k` to find co= rrect midstates such that > > =20 > >=20 > > ` ` > > `` `I =3D=3D SHA512( || SHA512( || 0x00 || sk || = i))` `` > > `k =3D=3D int(I[32:]) + sk % n` > > `=3D=3D sk + sk % n` > >=20 > >=20 > > Remember that `sk =3D int(I[32:])`. Thus for these conditions to hold, = the proof forger must be able to find not just the correct midstates, but a= lso midstates which give a 2-stage partial hash cycle so that: > >=20 > >=20 > > `I =3D=3D SHA512( || SHA512( || 0x00 || I[32:] ||= i))` > >=20 > >=20 > > This seems unlikely or at least very difficult. > >=20 > >=20 > > regards, > > conduition > >=20 > > On Thursday, April 9th, 2026 at 5:56 PM, Olaoluwa Osuntokun wrote: > >=20 > > > Hi Condution, > > >=20 > > > So I implemented both variants of your idea. My intuition was right i= n that it > > > doesn't do much to reduce the size of the final succinct size, but th= e final > > > xpriv variant resulted in a significant reduction in both proving tim= e, and > > > also memory usage. I also re-ran the original succint proof for the o= riginal > > > Taproot claim and got a better value for the final proof time (def ne= ed a > > > better benchmark env+set up!). > > >=20 > > > Here's a breakdown of the resource requirements for the various proof= s: > > > * Full Taproot > > > image ID: > > > 8a6a2c27dd54d8fa0f99a332b57cb105f88472d977c84bfac077cbe70907a690 > > > composite: > > > seal 1797880 > > > prove 49.32s > > > verify 0.10s > > > peak RSS 11907399680 > > > succinct: > > > seal 222668 > > > prove 64.30s > > > verify 0.03s > > > peak RSS 11927207936 > > >=20 > > > * Hardened xpub > > > image ID: > > > ad4ebc0ef6ce51e0f581cc8d14742a5b97738e9decd3fe2b0f1746de5bad9617 > > > composite: > > > seal 513680 > > > prove 14.63s > > > verify 0.04s > > > peak RSS 11783503872 > > > succinct: > > > seal 222668 > > > prove 17.29s > > > verify 0.02s > > > peak RSS 11782307840 > > >=20 > > > * Hardened xpriv > > > image ID: > > > 8401a36e4f54cb2beaf9ac7677603806cf9d775e90ef5a70168045a3c0df0849 > > > composite: > > > seal 234568 > > > prove 1.98s > > > verify 0.02s > > > peak RSS 3144171520 > > > succinct: > > > seal 222668 > > > prove 2.84s > > > verify 0.02s > > > peak RSS 3145990144 > > >=20 > > > So we can see that the succinct proof sizes are all about the same. H= owever the > > > xpriv variant can be proved directly in just 2 seconds on my machine!= It also > > > requires just 3 GB of memory for the proof as well. > > >=20 > > > I've created some additional supporting documentation to detail exact= ly what > > > the new proofs do and their results: > > >=20 > > > * https://github.com/Roasbeef/bip32-pq-zkp/blob/main/docs/reduced-var= iants.md > > >=20 > > > * https://github.com/Roasbeef/bip32-pq-zkp/blob/1c89fdb398180a2b3eff7= 761b7f4b233d455c6c9/README.md#reduced-proof-variants > > >=20 > > > * https://github.com/Roasbeef/bip32-pq-zkp/blob/438c548ca9b49d83ef401= 9974a5171f5e06fa840/docs/claim.md#reduced-variant-claims > > >=20 > > >=20 > > > Once again, thanks for the great ideas! I wonder if we can improve on= this > > > round of proof golf further before reaching down a lower level with s= ome sort > > > of AIR compiler =F0=9F=A4=94. > > >=20 > > > -- Laolu > > >=20 > > > On Thu, Apr 9, 2026 at 1:53=E2=80=AFPM Olaoluwa Osuntokun wrote: > > >=20 > > > > Hi Conduition, > > > >=20 > > > > > You need only prove this much more general statement (2): "I know= a BIP32 > > > > > xpriv which derives this xpub via one or more hardened steps". > > > >=20 > > > > > I'm amending my prior suggestion slightly: The circuit (guest pro= gram) > > > > > could take in an xpriv (e.g. at m/86'/0') and output a child xpri= v > > > > > (e.g. at m/86'/0'/0') to the journal (instead of outputting a chi= ld > > > > > xpub). > > > >=20 > > > > That's an excellent insight! > > > >=20 > > > > As mentioned in my recent reply, with risc0's "succinct" receipt ty= pe, I was > > > > able to get the proof size down to 220 KB, at the cost of 3.5x long= er total > > > > proving time. > > > >=20 > > > > Your proposal definitely reduces the complexity of the core stateme= nt to be > > > > proved, which would speed up the proving time for the normal > > > > default/composite receipt type. > > > >=20 > > > > I'll try to hack this up, and then run a head to head comparison to= see this > > > > simpler statement actually results in a smaller proof then the fina= l > > > > succinct receipt of either of the proof variants. Based on my curre= nt > > > > intuition w.r.t the lower level details, I think the final succinct= proof > > > > size would be on the same order of magnitude re size. > > > >=20 > > > > However, this can still be a win as then this would provide potenti= al future > > > > users with a less resource intensive proof, which can then be > > > > aggregated/rolled up into a final succinct proof in a batched manne= r. > > > >=20 > > > > This line of optimization is also more interesting if one were to l= ook at > > > > hand rolling a custom AIR to avoid the overhead that the RISC-V emu= lation > > > > adds to the rirsc0 proof chain, given that it entirely skips doing = any EC > > > > operations at all for the final statement. > > > >=20 > > > > ---- > > > >=20 > > > > Re the commit/reveal approach, to be honest I'm not fully caught up= on that > > > > proposal. That original thread got pretty long, so I dropped of aft= er a > > > > point =F0=9F=98=85. I'll revisit that specific branch of the thread= so I can digest it > > > > and develop a proper opinion, then get back to you re comparisons! > > > >=20 > > > > -- Laolu > > > >=20 > > > > On Wed, Apr 8, 2026 at 1:23=E2=80=AFPM conduition wrote: > > > >=20 > > > > > Oh, I've been a fool, a foolish fool. > > > > >=20 > > > > > We don't even need to do point multiplication in the circuit at a= ll. > > > > >=20 > > > > > I'm amending my prior suggestion slightly: The circuit (guest pro= gram) could take in an xpriv (e.g. at `m/86'/0'`) and output a child xpriv = (e.g. at `m/86'/0'/0'`) to the journal (instead of outputting a child xpub)= . > > > > >=20 > > > > > This is safe because remember, EC spending has been disabled in t= his context, and to a quantum attacker, an xpub is computationally equivale= nt to its xpriv. So why bother hiding it? The child xpriv doesn't give an o= bserver anything they can't already do with the equivalent xpub. > > > > >=20 > > > > > The guest program then is basically the BIP32 CKDpriv algorithm, = restricted to a single hardened derivation step. The verifier gets the chil= d xpriv, but can't use it to forge new proofs. Honest verifiers use the xpr= iv to derive the child address(es) as suggested in my last message, to auth= enticate spending. > > > > >=20 > > > > > Designing the guest program like this will massively reduce your = circuit complexity, because EC point multiplication is wayyyyy harder for t= he RISC0 compiler to arithmetize than a simple hash function. In my prior w= ork with RISC0, I made a guest program which ran a SHA256 hash and an EC po= int multiplication. I found that pruning EC point arithmetic from my guest = program improved prover runtime by a factor of over 100x. > > > > >=20 > > > > > If I am not fever-dreaming and this is indeed possible, then the = new circuit's complexity will be dominated not by point multiplication, but= by the HMAC-SHA512 call. Our new task is then to figure out how much we ca= n internally optimize the HMAC-SHA512 call for STARK proving. Here's a few = ideas. > > > > >=20 > > > > > If you bust open HMAC-SHA512, it looks like this: > > > > >=20 > > > > > `HMAC_SHA512 =3D SHA512((K=E2=8A=950x5c) || SHA512((K=E2=8A=950x3= 6) || msg))` > > > > >=20 > > > > > ...where in the context of BIP32 hardened CKD, the HMAC key `K` i= s the chaincode (padded with zeros to 128 bytes) and `msg =3D (0x00 || sk |= | i)` is the parent secret key and child index. > > > > >=20 > > > > > Since `len(K) =3D 128` is the SHA512 block size, we need a total = of 4 SHA512 compression calls: > > > > >=20 > > > > > 1. to compress `(K=E2=8A=950x36)` > > > > > 2. to compress the `msg` (and SHA512 padding/length) > > > > > 3. to compress (K=E2=8A=950x5c), and > > > > > 4. a final compression call to tie it all together. > > > > >=20 > > > > >=20 > > > > > The output of that last compression call is partitioned into the = child chaincode, and a key delta which is added to the parent secret key (m= odulo the curve order), producing the child EC secret key. This last step i= s arithmetically simple; the SHA512 calls are where most of the arithmetic = complexity lies. > > > > >=20 > > > > > The question then becomes, which of these compression calls can b= e done outside the circuit, and which are truly essential for security? > > > > >=20 > > > > > Note how the parent secret key is the most important piece for so= undness. The circuit needs to prove the parent secret key existed in the ha= sh function preimage, and is correctly related to the child secret key via = modular addition. So compression call (2) seems unavoidable. The others are= less rigid. > > > > >=20 > > > > > I'd argue that if we really dig into the hard relation we're tryi= ng to prove here, we can reduce it to this statement: > > > > >=20 > > > > > Given a child xpriv with secret key `k`, chaincode `c` and index = `i`, I know a preimage `x` and secret key `sk` such that: > > > > > ` ` > > > > > `I <- SHA512( || SHA512( || 0x00 || sk || i= )`) > > > > > `c =3D=3D I[:32]` > > > > > `k =3D=3D int(I[32:]) + sk % n` > > > > >=20 > > > > > Seeing as the `` slots are arbitrary, and we know in B= IP32 they are always exactly one-block long, it seems easy to throw out the= compression calls (1) and (3). The host can precompute the relevant SHA512= midstates outside the circuit, and pass the midstates into the guest progr= am as secret inputs. The tradeoff is that this permits malicious provers th= e flexibility of choosing their starting midstates (though hash input lengt= h can be fixed at 192 bytes). I'm not entirely sure if this meaningfully we= akens the verifier's soundness. Ethan Heilman might have opinions on this, = he knows a lot more about attacking hash functions than I do. Intuitively, = I doubt sampling random SHA512 midstates is that much better than sampling = a random HMAC key (chaincode) `K` and computing the resulting midstates. > > > > >=20 > > > > >=20 > > > > > This reduces our circuit to, i think, the minimum acceptable secu= rity floor for provers: two SHA512 compression calls, which commit to a par= ent secret key. > > > > >=20 > > > > >=20 > > > > >=20 > > > > >=20 > > > > > regards, > > > > > conduition > > > > > On Wednesday, April 8th, 2026 at 12:09 PM, 'conduition' via Bitco= in Development Mailing List wrote: > > > > >=20 > > > > > > Hi Laolu, > > > > > > Great work getting this working in the real world. I've heard m= any people on delving and the mailing list conjecture based on this idea, b= ut you're the first person i've seen who's willing to put their money where= their mouth is, and actually build a prototype. Bravo! > > > > > >=20 > > > > > > It seems to me the circuit (guest program) could be simplified.= Notice how the guest code computes the entire HD wallet key path, includin= g hardened and non-hardened derivation steps, and also computes the taproot= output key with key-tweaking. I'd argue these steps are extraneous to the = core hard relation you want the STARK to prove, and could be safely removed= to reduce proof size and improve performance. > > > > > >=20 > > > > > > In reality, you needn't go so far as to prove (1) "I know a BIP= 39 seed which derives this taproot output key". You need only prove this mu= ch more general statement (2): "I know a BIP32 xpriv which derives this xpu= b via one or more hardened steps". The latter statement (2) still cannot be= forged by a quantum adversary even if they know your account-level xpub, b= ut it entails far less computation to prove and verify. The rest of the ori= ginal statement (1) can be done externally outside the circuit. > > > > > >=20 > > > > > > Example. If i have a wallet with a taproot address at `m/86'/0'= /0'/1/2`, I could prove I know the xpriv at `m/86'/0'` which derives the xp= ub at `m/86'/0'/0'`. Then I provide the remaining key path elements /`1/2` = in the witness. Note, i do not mean we derive the xpriv at `m/86'/0'` insid= e the guest program. I mean the prover derives `m/86'/0'` first (in the hos= t), and then writes that xpriv into the guest program's inputs. The guest p= rogram derives and outputs the xpub at `m/86'/0'/0'`. The verifier may chec= k the STARK output (xpub) is correctly computed, then use the given key-pat= h to manually derive the taproot address from the xpub themselves, outside = the circuit, and validate that address against the UTXO i'm spending. The v= erifier thus has confirmed the prover knew an xpriv which (through a harden= ed derivation step) derives the correct taproot output key. > > > > > >=20 > > > > > > This change significantly reduces the size of the circuit. From= a glance, I see the original guest program performs 6 HMAC-SHA512 calls (1= for the master key, 5 for the BIP32 derivation steps), two SHA256 compress= ion calls (for the taptweak hash), and two point multiplications. With this= simplified variant, we are invoking only a single HMAC-SHA512 call and a s= ingle point multiplication. I can't say for sure, but I expect this will im= prove your proof size and runtime significantly. > > > > > >=20 > > > > > > This change also makes the circuit more generally applicable to= other rescue contexts. For instance, it could be applied to BIP340 xonly k= eys inside a taproot script tree, or in a P2(W)SH address to an ECDSA publi= c key, or to P2(W)PKH addresses. > > > > > >=20 > > > > > > Concerned about publishing xpubs? Remember that we are assuming= regular EC spending is locked in this context, so it is safe-ish to share = account xpubs with quantum attackers. At best the xpub can be used for surv= eillance but not forgery. If one would prefer not to share the account-leve= l xpub on-chain for privacy reasons, the proof could be extended to also de= rive the unhardened child xpub at `/1/2` inside the guest program (but we s= till do not need to do the taproot key tweaking in the guest program). > > > > > >=20 > > > > > > We should also talk scaling efficiency. Given the cost of STARK= s, this style of proof should be able to authorize spends for more than one= UTXO. Say you have a wallet with 10 different UTXOs held by distinct addre= sses in the same BIP44 account. One single STARK proof could authorize spen= ding all 10 of them, by simply committing all 10 input signature hashes int= o the journal, and labeling the inputs with the corresponding 10 BIP32 key = paths somehow. The verifier would need to check the proof only once and not= 10 times. The 10 UTXO spends could be validated using the common xpub from= the STARK proof's journal. > > > > > >=20 > > > > > > For a slightly related work proving a similar relation for hash= ed addresses, using different STARK technology stacks, see this delving pos= t. > > > > > >=20 > > > > > > However, all this said, my personal preference for long-term pr= ocrastinator rescue is still for commit/reveal strategies which prove essen= tially the same statement about BIP32 in a two-step procedure. They get the= job done with much lighter cryptographic machinery and much smaller witnes= ses: a few hundred bytes over two transactions, compared to a few million b= ytes in one transaction with STARKs. Boris Nagaev and I discussed this on t= he list a while back. That said, commit/reveal requires more careful design= and seems to demand the use of external quantum-safe coins to make the com= mitment in the first place, so perhaps the cost would be worth it to some p= eople? IDK. What do you think of commit/reveal compared to STARKs for this = purpose? > > > > > >=20 > > > > > > regards, > > > > > > conduition > > > > > > On Wednesday, April 8th, 2026 at 12:18 AM, Olaoluwa Osuntokun <= lao...@gmail.com> wrote: > > > > > >=20 > > > > > > > Hi y'all, > > > > > > >=20 > > > > > > > I found some spare time this last weekend to dust off a littl= e side project > > > > > > > I started last August: extend TinyGo [1] to be able to produc= e RISC-V ELF > > > > > > > binaries capable of being run as a guest on the risc0 platfor= m to generate > > > > > > > zk-STARK proofs of arbitrary programs. Initially, I didn't re= ally have a > > > > > > > clear end target application, it was mainly a technical chall= enge 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 i= nitial 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. > > > > > > >=20 > > > > > > > More formally: > > > > > > > ```math > > > > > > > \mathcal{R} =3D \left\lbrace\; > > > > > > > (\overbrace{K,\, C}^{\textsf{public}} ;\; \underbrace{s,\, \m= athbf{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 > > > > > > > ``` > > > > > > >=20 > > > > > > > where $K$ is the Taproot output key, $C$ is the path commitme= nt, $s$ is the > > > > > > > BIP-32 seed, and $\mathbf{p}$ is the derivation path. > > > > > > >=20 > > > > > > >=20 > > > > > > > I was able to get everything working e2e over the weekend, af= ter making > > > > > > > some tweaks to my initial architectural game plan! > > > > > > >=20 > > > > > > > The TL;DR is that: > > > > > > >=20 > > > > > > > * Given that the Taproot commitment scheme is post-quantum se= cure [3], in > > > > > > > the future we can deploy a soft fork to _disable_ the keyspen= d path, > > > > > > > and force all Taproot spends to instead flow through the scri= pt path > > > > > > > (not my idea, commonly discussed amongst developers, not sure= who > > > > > > > proposed it first). At that point, Taproot starts to resemble= BIP-360. > > > > > > >=20 > > > > > > > * That works for script path spends, but then leaves all the = BIP-86 > > > > > > > wallets in a bad position, as they generated outputs that pro= vably > > > > > > > don't commit to a script path at all. > > > > > > >=20 > > > > > > > * A 2023 paper (Protecting Quantum Procrastinators with Signa= ture > > > > > > > Lifting: A Case Study in Cryptocurrencies [4]) proposed a sol= ution 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 o= f secret > > > > > > > information a quantum attacker wouldn't be able to easily obt= ain. > > > > > > >=20 > > > > > > > * The downside of that is that it reveals the secret BIP 32 s= eed, > > > > > > > exposing other non migrated UTXOs of a user. > > > > > > >=20 > > > > > > > * With this project I've cobbled together a series of project= s 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. > > > > > > >=20 > > > > > > > * In the future a variant of this scheme can be used to enabl= e wallets > > > > > > > that generated the private keys via BIP-86, to have a post qu= antum safe > > > > > > > exit path in case they don't bother moving their coins in tim= e to the > > > > > > > yet-to-be-decided post quantum signature scheme. > > > > > > >=20 > > > > > > > To achieve this end, I needed to create/fork a series of repo= s: > > > > > > >=20 > > > > > > > * 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 b= e proved > > > > > > > by the host. > > > > > > >=20 > > > > > > > * 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 re= po is > > > > > > > unmodified other than that. Recent updates to the repo made t= he > > > > > > > entire process much easier (Go guest+host), more on that late= r. > > > > > > >=20 > > > > > > > * 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 us= er > > > > > > > generated RISC-V ELF (the thing that is executed to generate = the > > > > > > > proof) along with the v1compat ELF kernel, which is risc0's e= xecution > > > > > > > environment. > > > > > > >=20 > > > > > > > * This also includes a Go host package, which loads the guest= program, > > > > > > > executes it, and generates a trace to later be proved. This i= s > > > > > > > achieved via a C FFI compat layer between Go and the original= Rust > > > > > > > host/proving/verification code. > > > > > > >=20 > > > > > > > * bip-32-pq-zkp: https://github.com/Roasbeef/bip32-pq-zkp > > > > > > > * The project that packages everything together, this contain= s the: > > > > > > > * Guest Go program that defines the secret witness and > > > > > > > claim/constraints of the proof. > > > > > > >=20 > > > > > > > * 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. > > > > > > >=20 > > > > > > > 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 execut= ion. 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. > > > > > > >=20 > > > > > > > On several layers, this demo is far from optimized (more on t= hat 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. > > > > > > >=20 > > > > > > > For those curious re the e2e details I've generated this tuto= rial that > > > > > > > explains the entire system top to bottom: > > > > > > > https://github.com/Roasbeef/go-zkvm/blob/main/docs/tutorial.m= d. > > > > > > >=20 > > > > > > > If you got to this point in this mail, and don't care about t= he lower level > > > > > > > details, thanks for reading up until now, and feel free to re= turn back to > > > > > > > the _The Net of a Million Lies_, or as better known in our Un= iverse: > > > > > > > Monitoring the Situation and/or slopfotainment! =F0=9F=AB=A1 > > > > > > >=20 > > > > > > > ## Motivation + Background > > > > > > >=20 > > > > > > > As commonly known, in the case of an adversary that possesses= a quantum > > > > > > > computer capable of breaking classical asymmetric cryptograph= y, 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 out= puts that have > > > > > > > revealed their public key. Pubkey reveal might happen due to = address re-use > > > > > > > (spending from the same script twice), or Taproot outputs, wh= ich publish > > > > > > > the public key plainly in the pkScript. > > > > > > >=20 > > > > > > > As detailed in [3], for Taproot outputs, a widely circulated = plan is > > > > > > > roughly to: disable the _keyspend_ path (requires a simple si= gnature), > > > > > > > enforcing a new rule that all Taproot spends must then flow t= hrough 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. > > > > > > >=20 > > > > > > > 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 f= uture. > > > > > > > However, what about all the other wallets that use BIP 86, an= d don't commit > > > > > > > to a script path at all? Under a strict version of this exist= ing > > > > > > > proposal, those wallets would basically be locked forever. > > > > > > >=20 > > > > > > > The goal of this work is to demonstrate a practical solution = (discussed > > > > > > > against devs, but never implemented AFAICT): generate a zk pr= oof that an > > > > > > > output was generated using BIP-86. For the zk-Proof, we selec= t zk-STARKs, > > > > > > > as they're plausibly post quantum since they rely only on sym= metric > > > > > > > cryptography: layers of merkle trees over an execution trace,= along with > > > > > > > some novel sampling/error-correction algorithms. > > > > > > >=20 > > > > > > > At this point, you may be asking: "if the quantum adversary c= an 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 ta= kes an initial > > > > > > > 128-512-bit seed (with BIP-39, either 12 or 24 words), then r= uns it through > > > > > > > HMAC-SHA512 keyed by "Bitcoin seed" to produce the master ext= ended 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-Tapp [= 6]) is the > > > > > > > best known quantum collision finder, and it runs in time prop= ortional to the > > > > > > > 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 high= est > > > > > > > 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! > > > > > > >=20 > > > > > > > This demo focuses on the Taproot case, but the rough approach= also applies > > > > > > > to any other output generated via BIP-32. BIP 32 was original= ly published in > > > > > > > 2012, over 14 years ago. So safe to say that _most_ wallets w= ere generated > > > > > > > under this scheme. However, Bitcoin Core only officially adop= ted 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 original > > > > > > > key pool, but if you have coins generated via that mechanism,= you may want > > > > > > > to consider migrating them to a BIP-32 wallet. > > > > > > >=20 > > > > > > > ## TinyGo + RISC-V + risc0 > > > > > > >=20 > > > > > > > Now for some of the lower level details. risc0 is a STARK bas= ed proving > > > > > > > system that takes a RISC-V ELF binary generated by a guest pr= ogram (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. > > > > > > >=20 > > > > > > > Today you can take some subset of Rust, compile it to an ELF = using their > > > > > > > toolchain, then execute it, generate a trace, to finally prov= e+verify it > > > > > > > using their system. > > > > > > >=20 > > > > > > > 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! > > > > > > >=20 > > > > > > > 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 th= em, first for > > > > > > > this demo, then also in the future for other projects. > > > > > > >=20 > > > > > > > TinyGo is a special Go compiler based on LLVM, that targets m= ostly embedded > > > > > > > environments. You can use it to generate go programs that can= run on > > > > > > > micro controllers, or on web assembly (producing a smaller bi= nary than if > > > > > > > you used the normal stdlib path). > > > > > > >=20 > > > > > > > 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 + multi= ply/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 memor= y layer > > > > > > > identical to what risc0 expects. The final component was a ne= w runtime > > > > > > > (`src/runtime/runtime_zkvm.go`), which implemented a few plat= form specific > > > > > > > syscalls for risc0 (putchar(), exit(), ticks(), and growHeap(= )). > > > > > > >=20 > > > > > > > When I tried to get this working last year, I had to also imp= lement a number > > > > > > > of kernel syscalls (called ecalls in the platform [7]) to han= dle: read+write > > > > > > > to stdin/stdout, halting, and the journaling mechanism (the t= ranscript of > > > > > > > execution committed to), which basically implement the kernel= that the guest > > > > > > > executes in. Fast forward to 2026, and after pulling the late= st version of > > > > > > > the repo, I realized that they now make a libzkvm_platform.a,= which packages > > > > > > > up the kernel nicely to be linked against. So I threw out my = custom kernel > > > > > > > code, and slotted that in instead. > > > > > > >=20 > > > > > > > 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 tha= t executes the > > > > > > > program and generates the final proof). > > > > > > >=20 > > > > > > > ## BIP-32+Taproot zk-STARK Proof > > > > > > >=20 > > > > > > > With basic proofs working (like the classic: I know the facto= rization of a > > > > > > > number `n`), I was unblocked to generate the actual proof. Th= e claim/proof > > > > > > > is represented with the following JSON artifact: > > > > > > > ``` > > > > > > > { > > > > > > > "schema_version": 1, > > > > > > > "image_id": "8a6a2c27dd54d8fa0f99a332b57cb105f88472d977c84bfa= c077cbe70907a690", > > > > > > > "claim_version": 1, > > > > > > > "claim_flags": 1, > > > > > > > "require_bip86": true, > > > > > > > "taproot_output_key": "00324bf6fa47a8d70cb5519957dd54a02b385c= 0ead8e4f92f9f07f992b288ee6", > > > > > > > "path_commitment": "4c7de33d397de2c231e7c2a7f53e5b581ee3c2007= 3ea79ee4afaab56de11f74b", > > > > > > > "journal_hex": "010000000100000000324bf6fa47a8d70cb5519957dd5= 4a02b385c0ead8e4f92f9f07f992b288ee64c7de33d397de2c231e7c2a7f53e5b581ee3c200= 73ea79ee4afaab56de11f74b", > > > > > > > "journal_size_bytes": 72, > > > > > > > "proof_seal_bytes": 1797880, > > > > > > > "receipt_encoding": "borsh" > > > > > > > } > > > > > > > ```` > > > > > > >=20 > > > > > > > The `image_id` is basically a hash of the ELF, so you know wh= at the prover > > > > > > > executed. There are then a few flags that control the claim v= ersion 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 to > > > > > > > claim that instead. The Taproot key we're generating the proo= f against is > > > > > > > also part of the _public data_, as it sits plainly on the cha= in for all to > > > > > > > see. We then also include a `path_commitment`, which is a com= mitment to the > > > > > > > exact BIP 86 path that the prover used. Finally, we also comm= it to the > > > > > > > journal hex, which is basically a commitment to the public cl= aim. > > > > > > >=20 > > > > > > > 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 > > > > > > > ``` > > > > > > >=20 > > > > > > > Then verify it with: > > > > > > > ``` > > > > > > > make verify GO_GOROOT=3D/path/to/go1.24.4 > > > > > > > ``` > > > > > > >=20 > > > > > > > The default prove target writes: > > > > > > > * ./artifacts/bip32-test-vector.receipt > > > > > > > * ./artifacts/bip32-test-vector.claim.json > > > > > > >=20 > > > > > > > The receipt is the STARK proof artifact. claim.json is the st= able, > > > > > > > human-readable description of the public statement being prov= ed. > > > > > > >=20 > > > > > > > ## Application to a Future Keyspend Disabling Soft fork > > > > > > >=20 > > > > > > > As mentioned above, assuming the community is forced to deplo= y a keyspend > > > > > > > disabling soft fork in the future, we can also deploy some va= riant of > > > > > > > this proof to enable both BIP-86 wallets, and also any BIP-32= wallet, to > > > > > > > sweep their funds into a new PQ output. > > > > > > >=20 > > > > > > > In 2026, we've shown that this is achievable using 2 year old= consumer > > > > > > > hardware. I don't doubt that the upcoming advancements (eg: p= hotonics, new > > > > > > > flavor of high bandwidth memory, etc) in hardware (driven by = the fierce AI > > > > > > > race) will make such a proof even more feasible. > > > > > > >=20 > > > > > > > One thing to note is that this proof has a few layers of indi= rection, > > > > > > > mainly the RISC-V layer that adds overhead which increase the= total amount > > > > > > > of steps, and therefore the size of the proof. A production g= rade > > > > > > > deployment would likely instead hand roll a custom STARK proo= f for this > > > > > > > exact statement, to achieve a faster and smaller proof). > > > > > > >=20 > > > > > > > # Future Work > > > > > > >=20 > > > > > > > In terms of future work, there're a number of interesting fol= lowing up > > > > > > > projects that can be pursued from here. > > > > > > >=20 > > > > > > > One basic one is that the current proof doesn't actually comm= it to a > > > > > > > spending txid and/or sighash. That can be trivially incorpora= ted into the > > > > > > > proof. Going a step further, the execution of the guest progr= am can even > > > > > > > _generate_ a valid schnorr signature to permit spending. > > > > > > >=20 > > > > > > > Looking to the memory+computational requirements necessary to= generate the > > > > > > > proof, I've left two low hanging fruits: > > > > > > >=20 > > > > > > > 1. First, we can speed up the Elliptic Curve operations the p= roof 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 arithmet= ic: > > > > > > > sys_bigint and sys_bigint2. With this, the guest calls into t= he kernel > > > > > > > to use an optimized/accelerated circuit for the modular arith= metic, > > > > > > > reducing cycles, steps, and thus proof size. > > > > > > >=20 > > > > > > > 2. Second right now, the entire claim is a single proof. Inst= ead, we can > > > > > > > first break that up using their recursive proof/composition s= yscalls: > > > > > > > sys_verify_integrity+sys_verify_integrity2. We can then assem= bled a > > > > > > > series of these proofs into a _single_ statement, which can s= ave block > > > > > > > space by aggregating N proofs into a single proof. > > > > > > >=20 > > > > > > > -- Laolu > > > > > > >=20 > > > > > > > [1]: https://tinygo.org/ > > > > > > >=20 > > > > > > > [2]: https://risczero.com/ > > > > > > >=20 > > > > > > > [3]: https://eprint.iacr.org/2025/1307 > > > > > > >=20 > > > > > > > [4]: https://eprint.iacr.org/2023/362 > > > > > > >=20 > > > > > > > [5]: https://microsoft.github.io/Picnic/ > > > > > > >=20 > > > > > > > [6]: https://en.wikipedia.org/wiki/BHT_algorithm > > > > > > >=20 > > > > > > > [7]: https://github.com/Roasbeef/go-zkvm/blob/main/docs/ecall= -reference.md > > > > > > >=20 > > > > > > > -- > > > > > > > You received this message because you are subscribed to the G= oogle Groups "Bitcoin Development Mailing List" group. > > > > > > > To unsubscribe from this group and stop receiving emails from= it, send an email to bitcoindev+...@googlegroups.com. > > > > > > > To view this discussion visit https://groups.google.com/d/msg= id/bitcoindev/CAO3Pvs_PciUi%2BzBrCps3acO14sgeHVUANx9w6TVwUf_AYcd_qQ%40mail.= gmail.com. > > > > > >=20 > > > > > > -- > > > > > > You received this message because you are subscribed to the Goo= gle Groups "Bitcoin Development Mailing List" group. > > > > > > To unsubscribe from this group and stop receiving emails from i= t, send an email to bitcoindev+...@googlegroups.com. > > > > > > To view this discussion visit https://groups.google.com/d/msgid= /bitcoindev/ciibnh-b0x-rLwA8pY5NURBfPvG58gLcS7yPLIIkFV5IzA1k-PTsPZqYU8uUyQR= xLCnEFhGcrRCTM39N2AYEy0Db2H_UwIse3Hg9XEXNEYg%3D%40proton.me. > > >=20 > > > -- > > > You received this message because you are subscribed to the Google Gr= oups "Bitcoin Development Mailing List" group. > > > To unsubscribe from this group and stop receiving emails from it, sen= d an email to bitcoindev+...@googlegroups.com. > >=20 > > > To view this discussion visit https://groups.google.com/d/msgid/bitco= indev/CAO3Pvs9tps%3DbsMQyA%2BHvhK-u%2BXqRwWtjTq8WXZi%2BcveAVwPi9A%40mail.gm= ail.com. >=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= email to bitcoindev+unsubscribe@googlegroups.com. > To view this discussion visit https://groups.google.com/d/msgid/bitcoinde= v/02378fd1-17a4-47aa-89fa-ee87626def65n%40googlegroups.com. --=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/= YmXg6QUwLlLB7hYkqL9AnexCHy70dFPVZSZ2GyGrGPlEBna4gc1ZlaHptaVzsVAcEh7gadakxHX= Tk6CJDZfQ-9Ycjg4BI77qttmgaP1LWtc%3D%40proton.me. -----------------------c2d9ccf5eaa15e50460689f32fb8a6be Content-Type: multipart/related;boundary=---------------------80189ce6e70552e021a4a651a71b5bf9 -----------------------80189ce6e70552e021a4a651a71b5bf9 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Abubakar= ,

=
Aweso= me point! A single STARK could be used to prove you knew an xpriv which der= ives the xpriv at m/352'/coin'/account'=E2=80=8B. Then any ver= ifier could easily derive the private scan/spend keys m/352'/coi= n'/account'/0'/0=E2=80=8B or m/352'/coin'/account'/1'/0= =E2=80=8B, then replicate the ECDH process (with some BIP352-specifi= c tweaks that the spender can provide), and add the result together.= This reproduces the private key of the SP taproot output being spent, prov= ing the spender is authentic.

With proper labeling of input metadata= , this procedure could cover every UTXO in a silent payment wallet, because= the scan/spend keys are common to every derived output-specific address.

Curious why not generalise beyond BIP-32? P2PKH and P2WPKH without BIP-= 32 still commit to an unrevealed secret =E2=80=94 HASH160(k=C2=B7G) =E2=80= =94 as long as the pubkey has never previously appeared on-chain. A zk-STAR= K proof should apply here too? The prover argues for the correctness of HAS= H160(k=C2=B7G) =3D h, where k is the private key scalar and k=C2=B7G is the= elliptic-curve point, without ever revealing k or the pubkey. This would a= llow recovery of a broader set of funds.

I agree this type of thing would also be useful, but it is harder to argu= e security for this than for BIP32 xpriv ownership.

Typ= ically, xpubs and xprivs are not shared on-chain, and wallets usually treat= them with greater care since xpubs compromise privacy, and xprivs compromi= se security.

Hashed address pubkeys on the other hand are comm= only shared on-chain and almost never treated as sensitive. So it seems lik= ely that if we DO permit spending using a ZK proof of knowledge of k<= /code>=E2=80=8B such that HASH160(k*G) =3D h=E2=80=8B, then so= me non-negligible fraction of those coins will still be vulnerable to a CRQ= C because k*G=E2=80=8B may be known to the attacker, which to = a CRQC is equivalent to knowing k=E2=80=8B. 

To mitigate, a veri= fier would need to reject such proofs when someone tries to spend coins loc= ked to such an "exposed pubkey" address. Since bitcoin nodes do not maintai= n an address index, they don't intrinsically know which addresses have expo= sed pubkeys or not. We would have to compose a list of such addresses, and = since that list changes over time, it would need to be updated by nodes in = real-time when indexing transactions. This list will almost certainly be in= complete, because we don't have any record of pubkeys exposed off-chain (e.= g. by hardware wallets, by xpubs shared in multi-party protocols, by lost T= Xs in orphaned blocks).

This idea also collides very unfortunately with the BIP32 = xpriv proof of knowledge. With the faster proof style i suggested to modify= Laolu's original one, a spender immediately gives up knowledge of their ac= count-level xpriv to the CRQC when publishing a TX. Even if the spender was= using a hashed-address with a hidden pubkey, the CRQC now knows the s= ecret key k=E2=80=8B for that address, and could use it t= o forge a proof that h =3D HASH160(k*G)=E2=80=8B to attempt to= double-spend/RBF the authentic transaction.

So we can't just add hashed-address p= roofs alongside BIP32 xpriv proofs. They'd have to be mutually exclusive: A= verifier would accept a BIP32 xpriv proof if and only if the address is on= the "exposed pubkey" list. The verifier would accept a hashed-address proo= f if and only if the address is NOT on the "exposed pubkey" list. It's defi= nitely feasible, it's just hard to do both safely.

This is also difficul= t to motivate, as we lack hard statistics about the relevant portion of the= Bitcoin supply that we could use hashed-address proofs (but not BIP32 proo= fs) to rescue: Those UTXOs which fall into the venn-diagram overlap of "Not= using BIP32" and "Not exposed-pubkey". BIP32 was introduced in 2012, where= as P2PKH was introduced in 2009, so clearly there must be some&= nbsp;overlap, but how much? I suppose one could estimate by indexing all th= e P2PKH UTXOs received before BIP32 was published, and counting what portio= n of them still have (probably) hidden public keys. This would be useful re= search for anyone with the time and a working node.

regards,
conduition
On Monday, April 13th, 2026 at 2:21 PM, sadiq Ismail <ask4ismail= sadiq@gmail.com> wrote:
Hi Laolu, list,

Nice work.

The scheme extends to = BIP-352 (Silent Payments). The BIP-352 receiver reconstructs the output P u= sing their private scan key, public spend key, and public information from = the spending transaction A.
See BIP-352 Scanning. BIP-352 recommends but= does not mandate BIP-32 for deriving the scan and spend keys, but specifie= s the following derivation paths when BIP-32 is used:

b_scan = =3D BIP32Derive(s, m/352'/coin_type'/account'/1'/0)
b_spend =3D BIP3= 2Derive(s, m/352'/coin_type'/account'/0'/0)

For all silent payment a= ddresses generated using BIP-32, your technique applies. The prover produce= s a zk-STARK proof that the program BIP32Derive(s, p_scan) and BIP32Derive(= s, p_spend) were run correctly,
and that the resulting keys reconstruct= the on-chain output P using along with A.

As you highlighted = txid is not committed in the proof currently, the argument is replayable. T= he current POC does not bind to where the coins go. Anyone who observes the= chain could copy it and attach it to a different transaction, spending the= same UTXO to a different address. Worse for silent payment, because all us= er UTXO have the same secret BIP32Derive(s, p_scan) and BIP32Derive(s, p_sp= end) except for A.
The zk-STARK proof? or this mechanism should d= efinitely be bound to the spending transaction and the input being spent. <= br>
Curious why not generalise beyond BIP-32? P2PKH and P2WPKH without B= IP-32 still commit to an unrevealed secret =E2=80=94 HASH160(k=C2=B7G) =E2= =80=94 as long as the pubkey has never previously appeared on-chain. A zk-S= TARK proof should apply here too? The prover argues for the correctness of = HASH160(k=C2=B7G) =3D h, where k is the private key scalar and k=C2=B7G is = the elliptic-curve point, without ever revealing k or the pubkey. This woul= d allow recovery of a broader set of funds. If it were decided that classic= al signatures for these output types are invalidated and only a valid zk-ST= ARK proof is required to spend, anyone who holds the original secret can un= lock their funds.

P.S. I am not for or against di= sabling valid spend paths post-quantum, just discussing the technical possi= bilities.

Best,
Abubakar Sadiq
On Friday, April 10, 2026 at 7:47:09= =E2=80=AFPM UTC+2 conduition wrote:
Ah! Amazing work! = 2 seconds to prove is really crazy. Proving a single SHA256 and one modular= addition on my CPU back in the day took like 20 seconds. Your GPU is coming in clutch for this. I best RISC= 0 has also improved quite a bit since then.

I think the next optimizatio= n step would be pre-seeding the two SHA512 midstates from the host, so you = only need to prove two SHA512 compression calls instead of four. Intuitivel= y I expect this would at best halve your prover time from 2sec, to probably= a little over 1sec, and your verifier time will probably drop as well sinc= e that also seems to scale with circuit complexity.

<= /div>
I think I have two h= alf-decent arguments now as to why this won't affect security:

First, ev= en if a fraudulent prover is handed the cor= rect midstates to use, the prover would still have to do the hard work of finding the parent s= ecret key needed as a witness. This is at least the same difficulty as find= ing the parent sk=E2=80=8B=E2=80=8B if we just hashed it without a chaincode at all, using two = bare SHA512 calls - the only thing that changes is the midstate, and the SH= A512 input length suffix. Starting from a different midstate doesn't magica= lly give the attacker a head-start in a 256-bit search space looking for sk=E2=80=8B. A frauduent prover would know the child secret key k =3D sk + int(I[32= :]) % n=E2=80=8B<= /span>=E2= =80=8B, but they don't know int(I[32:]) or sk=E2=80=8B so they= cannot solve for either.

Nominally, the fraudulent prover wouldn't even know the correct= midstates, so their task is strictly harder.

<= div>Secondly, here's another a= rgument as to why finding the midstates in the first place should also be h= ard.

Any adversary w= ho could solve this problem by finding the right midstates could be used as= an oracle to prove the existence of partial 2-cycles in SHA512.

  • Given a SHA512 hash I=E2=80=8B=E2=80=8B, set sk =3D i= nt(I[32:])=E2=80=8B= =E2=80=8B=E2=80=8B
  • C= ompute k =3D sk + sk % n=E2=80=8B
  • Use the black-box fraudulent prover on the child key k=E2=80=8B=E2=80=8B to find correct midstates= such that

I =3D=3D = SHA512(<something> || SHA512(<something> || 0x00 || sk || i))=E2=80=8B= =E2=80=8B=E2=80=8B
k =3D=3D int(I[32:]) + sk % n=E2=80=8B
=3D=3D sk + sk % n=E2=80=8B=E2=80=8B
<= span style=3D"font-family:Arial,sans-serif">

Remember that sk =3D = int(I[32:])=E2=80=8B=E2=80=8B. Thus for these conditions to hold, the proof forger must be = able to find not just the correct midstates, but also midstates which give = a 2-stage partial hash cycle so that:

<= /div>
I =3D=3D SHA5= 12(<something> || SHA512(<something> || 0x00 || I[32:] || i))=E2=80=8B

This seems unlikely or at least very difficult= .

regards,
conduition
On Thursday, April 9th, 2026 at 5:56 PM, Olaoluwa Osuntokun <lao...@gmail.com> wrote:
Hi Condution,

So I implemented both va= riants of your idea. My intuition was right in that it
doesn't do much t= o reduce the size of the final succinct size, but the final
xpriv varian= t resulted in a significant reduction in both proving time, and
also mem= ory usage. I also re-ran the original succint proof for the original
Tap= root claim and got a better value for the final proof time (def need a
b= etter benchmark env+set up!).

Here's a breakdown of the resource req= uirements for the various proofs:
* Full Taproot
image ID:
= 8a6a2c27dd54d8fa0f99a332b57cb105f88472d977c84bfac077cbe70907a690
= composite:
seal 1797880
prove 49.32s
verify 0.= 10s
peak RSS 11907399680
succinct:
seal 222668
= prove 64.30s
verify 0.03s
peak RSS 11927207936
<= br> * Hardened xpub
image ID:
ad4ebc0ef6ce51e0f581cc8d14742a= 5b97738e9decd3fe2b0f1746de5bad9617
composite:
seal 513680 prove 14.63s
verify 0.04s
peak RSS 11783503872 succinct:
seal 222668
prove 17.29s
verify 0= .02s
peak RSS 11782307840

* Hardened xpriv
image I= D:
8401a36e4f54cb2beaf9ac7677603806cf9d775e90ef5a70168045a3c0df084= 9
composite:
seal 234568
prove 1.98s
veri= fy 0.02s
peak RSS 3144171520
succinct:
seal 222668
prove 2.84s
veri= fy 0.02s
peak RSS
3145990144

So we can see that the succinct proof sizes are all about the sam= e. However the
xpriv variant can be proved directly in just 2 seconds on= my machine! It also
requires just 3 GB of memory for the proof as well.=

I've created some additional supporting documentation to detail exa= ctly what
the new proofs do and their results:

*
https://github.= com/Roasbeef/bip32-pq-zkp/blob/main/docs/reduced-variants.md

*= https://github.com/Roasbeef/bip32-pq-zkp/blob/1c89fdb398180a2b= 3eff7761b7f4b233d455c6c9/README.md#reduced-proof-variants

* https://github.com/Roasbeef/bip32-pq-zkp/blob/438c548ca9b= 49d83ef4019974a5171f5e06fa840/docs/claim.md#reduced-variant-claims
<= br>
Once again, thanks for the great ideas! I wonder if we can improve o= n this
round of proof golf further before reaching down a lower level wi= th some sort
of AIR compiler =F0=9F=A4=94.

-- Lao= lu

On Thu, Apr 9, 2026 at 1:53=E2=80=AFPM Olaoluwa Osuntokun <lao...@gmail.com> wrote:
Hi Conduit= ion,

> You need only prove this much more general statement (2): = "I know a BIP32
> xpriv which derives this xpub via one or more harde= ned steps".

> I'm amending my prior suggestion slightly: The circ= uit (guest program)
> could take in an xpriv (e.g. at m/86'/0') and o= utput a child xpriv
> (e.g. at m/86'/0'/0') to the journal (instead o= f outputting a child
> xpub).

That's an excellent insight!
As mentioned in my recent reply, with risc0's "succinct" receipt type= , I was
able to get the proof size down to 220 KB, at the cost of 3.5x l= onger total
proving time.

Your proposal definitely reduces the co= mplexity of the core statement to be
proved, which would speed up the pr= oving time for the normal
default/composite receipt type.

I'll t= ry to hack this up, and then run a head to head comparison to see this
s= impler statement actually results in a smaller proof then the final
succ= inct receipt of either of the proof variants. Based on my current
intuit= ion w.r.t the lower level details, I think the final succinct proof
size= would be on the same order of magnitude re size.

However, this can = still be a win as then this would provide potential future
users with a = less resource intensive proof, which can then be
aggregated/rolled up in= to a final succinct proof in a batched manner.

This line of optimiza= tion is also more interesting if one were to look at
hand rolling a cust= om AIR to avoid the overhead that the RISC-V emulation
adds to the rirsc= 0 proof chain, given that it entirely skips doing any EC
operations at a= ll for the final statement.

----

Re the commit/reveal approac= h, to be honest I'm not fully caught up on that
proposal. That original = thread got pretty long, so I dropped of after a
point =F0=9F=98=85. I'll= revisit that specific branch of the thread so I can digest it
and devel= op a proper opinion, then get back to you re comparisons!

-- Laolu


On Wed, Apr 8, 2026 at 1:23=E2=80=AFPM conduition <condu...@proton.me> wrote:
Oh, I've been a fool, a foolish fool.

We don't even need to do poin= t multiplication in the circuit at all.

I'm amending my prior suggestion slightly: The circu= it (guest program) could take in an xpriv (e.g. at m/86'/0'=E2= =80=8B) and output a child xpriv (e.g. at m/86'/0'/0'= =E2=80=8B) to the journal (instead of outputting a child xpub).

This is safe because= remember, EC spending has been disabled in this context, and to a quantum = attacker, an xpub is computationally equivalent to its xpriv. So why bother= hiding it? The child xpriv doesn't give an observer anything they can't al= ready do with the equivalent xpub.

The guest program then is basically the BIP32 CKDpriv al= gorithm, restricted to a single hardened derivation step. The verifier gets= the child xpriv, but can't use it to forge new proofs. Honest verifiers us= e the xpriv to derive the child address(es) as suggested in my last message= , to authenticate spending.

Designing the guest program like this will massively reduce your= circuit complexity, because EC point multiplication is wayyyyy hard= er for the RISC0 compiler to arithmetize than a simple hash function. In my prior work with RISC0, I made a= guest program which ran a SHA256 hash and an EC point multiplication. I fo= und that pruning EC point arithmetic from my guest program improved prover = runtime by a factor of over 100x.

If I am not fever-dreaming and this is indeed possible, th= en the new circuit's complexity will be dominated not by point multiplicati= on, but by the HMAC-SHA512 call. Our new task is then to figure out how muc= h we can internally optimize the HMAC-SHA512 call for STARK proving. Here's= a few ideas.

If = you bust open HMAC-SHA512, it looks like this:

HMAC_SHA512 =3D SHA512((K=E2=8A= =950x5c) || SHA512((K=E2=8A=950x36) || msg))=E2= =80=8B
...where = in the context of BIP32 hardened CKD, the HMAC key K=E2=80=8B = is the chaincode (padded with zeros to 128 bytes) and msg =3D (0x00 |= | sk || i) is the parent secret key and child index.

Since len(K) =3D 128=E2=80=8B is the SHA512=E2=80=8B block size, we need a total of 4 SHA512 = compression calls:
  1. to compress (K=E2=8A=950x36)= =E2=80=8B
  2. to= compress the msg=E2=80=8B (and SHA512 padding/length)<= /li>
  3. to compress (K=E2=8A=950x5c), and
  4. a final compression call to t= ie it all together.

The output of that last compression call is partitioned into the= child chaincode, and a key delta which is added to the parent secret key (modulo the c= urve order), producing the child EC secret key. This last step is arith= metically simple; the SHA512 calls are where most of the arithmetic complex= ity lies.

The question then becomes, which of these compression calls can be done= outside the circuit, and which are truly essential for security?

Note how the parent secre= t key is the most important piece for soundness. The circuit needs to prove= the parent secret key existed in the hash function preimage, and is correc= tly related to the child secret key via modular addition. So compression ca= ll (2) seems unavoidable. The others are less rigid.

I'd argue that if we really dig into th= e hard relation we're trying to prove here, we can reduce it to this statem= ent:

Given a child xpriv with secret key k=E2=80=8B, chaincode <= code style=3D"font-style:italic;font-family:Arial,sans-serif">c=E2=80=8B and index= i=E2=80=8B,= I know a preimage x=E2=80=8B and sec= ret key sk=E2=80=8B such that:

I <- SHA512(<someth= ing> || SHA512(<something> || 0x00 || sk || i)=E2=80=8B)
c =3D= =3D I[:32]=E2=80=8B
k =3D=3D int(I[32:]) + sk % n=E2=80=8B

Seeing as the = <something>=E2=80=8B slots are arbitrary, and we know in BIP32= they are always exactly one-block long, it seems easy to throw out the com= pression calls (1) and (3). The host can precompute the relevant SHA512 mid= states outside the circuit, and pass the midstates into the guest program a= s secret inputs. The tradeoff is that this permits malicious provers the flexibility = of choosing their starting midstates (though hash input length can be fixed= at 192 bytes). I'm not entirely sure if this meaningfully weakens the veri= fier's soundness. Ethan Heilman might have opinions on this, he knows a lot= more about attacking hash functions than I do. Intuitively, I doubt sampli= ng random SHA512 midstates is that much better than sampling a random HMAC = key (chaincode) K=E2=80=8B and computing the resulting midstat= es.

This reduces our circuit to, i think, the minimum = acceptable security floor for provers: two SHA512 compression calls, which = commit to a parent secret key.
<= br>
=

=
= regards,
conduition
On Wednesday, April 8th, 2026 at 12:09 PM, 'conduition' via Bitcoin= Development Mailing List <bitco...@google= groups.com> wrote:
Hi Laolu,

Great work getting this working= in the real world. I've heard many people on delving and the mailing list = conjecture based on this idea, but you're the first person i've seen who's = willing to put their money where their mouth is, and actually build a proto= type. Bravo!

It seems to me the circuit (guest pro= gram) could be simplified. Notice how the guest code compute= s the entire HD wallet key path, including hardened and= non-hardened derivation steps, and also computes the tapr= oot output key with key-tweaking. I'd argue these steps are extraneous to t= he core hard relation you want the STARK to prove, and could be safely remo= ved to reduce proof size and improve performance.

= In reality, you needn't go so far as to prove (1) "I know a BIP39 seed w= hich derives this taproot output key". You need only prove this much mo= re general statement (2): "I know a BIP32 xpriv which derives this xpub = via one or more hardened steps". The latter statement (2) still cannot = be forged by a quantum adversary even if they know your account-level xpub,= but it entails far less computation to prove and verify. The rest of the o= riginal statement (1) can be done externally outside the circuit.

Example. If i have a wallet with a taproot address at= m/86'/0'/0'/1/2=E2=80=8B, I could prove I know the xpr= iv at m/86'/0'=E2=80=8B which derives the xpub at= m/86'/0'/0'=E2=80=8B. Then I provide the remaini= ng key path elements /1/2=E2=80=8B in the witness. Note, i = do not mean we derive the xpriv at m/86'/0'=E2=80=8B inside the guest program. I mean the prover der= ives m/86'/0'=E2=80=8B first (in the host), and then writes that xpriv into the guest program's inputs. = The guest program derives and outputs the xpub at m/86'/= 0'/0'=E2=80=8B. The verifier may check the STARK output (xpub) is co= rrectly computed, then use the given key-path to manually derive the taproo= t address from the xpub themselves, outside the circuit, and validate= that address against the UTXO i'm spending. The verifier thu= s has confirmed the prover knew an xpriv which (through a hardened derivati= on step) derives the correct taproot output key.

T= his change significantly reduces the size of the circuit. From a glance, I = see the original guest program performs 6 HMAC-SHA512 calls (1 for the mast= er key, 5 for the BIP32 derivation steps), two SHA256 compression calls (fo= r the taptweak hash), and two point multiplications. With this simplified v= ariant, we are invoking only a single HMAC-SHA512 call and a single point m= ultiplication. I can't say for sure, but I expect this will improve your pr= oof size and runtime significantly.

This change al= so makes the circuit more generally applicable to other rescue contexts. Fo= r instance, it could be applied to BIP340 xonly keys inside a taproot scrip= t tree, or in a P2(W)SH address to an ECDSA public key, or to P2(W)PKH addr= esses.

Concerned about publishing xpubs? Remember that we are assuming= regular EC spending is locked in this context, so it is safe-ish to share = account xpubs with quantum attackers. At best the xpub can be used for surv= eillance but not forgery. If one would prefer not to share the accou= nt-level xpub on-chain for privacy reasons, the proof could be extended to = also derive the unhardened child xpub at /1/2=E2=80=8B inside the guest program (but we still do= not need to do the taproot key tweaking in the guest program).
<= /div>

We should also talk scaling efficiency. Given the = cost of STARKs, this style of proof should be able to authorize spends for = more than one UTXO. Say you have a wallet with 10 different UTXOs held by d= istinct addresses in the same BIP44 account. One single STARK proof could a= uthorize spending all 10 of them, by simply committing all 10 input signatu= re hashes into the journal, and labeling the inputs with the corresponding 10 BIP32 key paths some= how. The verifier would need to check the proof only once and= not 10 times. The 10 UTXO spends could be validated using the common xpub = from the STARK proof's journal.

For a slightly rel= ated work proving a similar relation for hashed addresses, using different = STARK technology stacks, see this delving post.=

However, all this said, my personal preference fo= r long-term procrastinator rescue is still for commit/reveal strategies whi= ch prove essentially the same statement about BIP32 in a two-step procedure= . They get the job done with much lighter cryptographic machinery and much = smaller witnesses: a few hundred bytes over two transactions, compared to a= few million bytes in one transaction with STARKs. Boris N= agaev and I discussed this on the list a while back. That said, commit/= reveal requires more careful design and seems to demand the use of external= quantum-safe coins to make the commitment in the first place, so perhaps t= he cost would be worth it to some people? IDK. What do you think of commit/= reveal compared to STARKs for this purpose?

regards,
condui= tion

<= /div>
On Wednesday, April 8th, 2026 at 12:18 AM, Olaoluwa Osuntokun <<= a href=3D"" rel=3D"noreferrer nofollow noopener" data-email-masked=3D"" sty= le=3D"pointer-events: none;">lao...@gmail.com> wrote:
Hi y'all,
I found some spare time this last weekend to dust off a little side pr= oject
I started last August: extend TinyGo [1] to be able to produce RIS= C-V ELF
binaries capable of being run as a guest on the risc0 platform t= o generate
zk-STARK proofs of arbitrary programs. Initially, I didn't re= ally have a
clear end target application, it was mainly a technical chal= lenge to force
me to learn a bit more about the RISC-V platform, and als= o the host/guest
architecture of risc0. Fast forward ~9 months later, an= d 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 \le= ft\lbrace\;
(\overbrace{K,\, C}^{\textsf{public}} ;\; \underbrace{s,\, \= mathbf{p}}_{\textsf{witness}})
\;\middle|\;
\begin{aligned}
K &a= mp;=3D \textsf{BIP86Taproot}\bigl(\textsf{BIP32Derive}(s,\, \mathbf{p})\big= r) \\
C &=3D \textsf{SHA256}\bigl(\texttt{"bip32-pq-zkp:path:v1"} = \;\|\; \mathbf{p}\bigr)
\end{aligned}
\;\right\rbrace
```

w= here $K$ is the Taproot output key, $C$ is the path commitment, $s$ is the<= br>BIP-32 seed, and $\mathbf{p}$ is the derivation path.


I was a= ble to get everything working e2e over the weekend, after making
some tw= eaks 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 pa= th,
and force all Taproot spends to instead flow through the script = path
(not my idea, commonly discussed amongst developers, not sure w= ho
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 pr= ovably
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 S= ignature scheme) to provide a post-quantum proof of secret
informati= on a quantum attacker wouldn't be able to easily obtain.

* The dow= nside of that is that it reveals the secret BIP 32 seed,
exposing ot= her 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 pro= of that a Taproot output public key was
generated via BIP-32 invocat= ion of a BIP-86 derivation path.

* In the future a variant of this= scheme can be used to enable wallets
that generated the private key= s 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 q= uantum signature scheme.

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

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

* risc0: https://github.com/Roasbeef= /risc0
* Mostly a bug fix to their c-guest example, along with s= ome
additional documentation on how to get things running. The rep= o is
unmodified other than that. Recent updates to the repo made t= he
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 i= t in the expected R0BF format, which combines the user
generated R= ISC-V ELF (the thing that is executed to generate the
proof) along= with the v1compat ELF kernel, which is risc0's execution
environm= ent.

* This also includes a Go host package, which loads the gue= st program,
executes it, and generates a trace to later be proved.= This is
achieved via a C FFI compat layer between Go and the orig= inal 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 progra= m that defines the secret witness and
claim/constraints of the p= roof.

* The C FFI wrapper around the OG Rust host, which is us= ed 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):
* T= akes ~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 fro= m optimized (more on that later),
this is meant to serve as a PoC to dem= onstrate that with the latest
software+hardware, a proof of this complex= ity 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 rea= ding up until now, and feel free to return back to
the _The Net of a Mil= lion Lies_, or as better known in our Universe:
Monitoring the Situation= and/or slopfotainment! =F0=9F=AB=A1

## Motivation + Background
<= br>As commonly known, in the case of an adversary that possesses a quantum<= br>computer capable of breaking classical asymmetric cryptography, any coin= s
stored in UTXOs with a known public key are vulnerable. This is the ca= se
for any P2PK outputs from waaaay back, and also any other outputs tha= t have
revealed their public key. Pubkey reveal might happen due to addr= ess re-use
(spending from the same script twice), or Taproot outputs, wh= ich publish
the public key plainly in the pkScript.

As detailed i= n [3], for Taproot outputs, a widely circulated plan is
roughly to: disa= ble the _keyspend_ path (requires a simple signature),
enforcing a new r= ule that all Taproot spends must then flow through the
script path. Spen= ding 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 classi= c assumptions, as H(M) (tapscript merkle root) is still a
collision-resi= stant function.

That means any UTXO that _does_ commit to a script p= ath has a future escape
hatch _if_ such a softfork would need to be depl= oyed in the future.
However, what about all the other wallets that use B= IP 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 forev= er.

The goal of this work is to demonstrate a practical solution (di= scussed
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 sym= metric
cryptography: layers of merkle trees over an execution trace, alo= ng with
some novel sampling/error-correction algorithms.

At this = point, you may be asking: "if the quantum adversary can derive the
priva= te 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
12= 8-512-bit seed (with BIP-39, either 12 or 24 words), then runs it throughHMAC-SHA512 keyed by "Bitcoin seed" to produce the master extended privat= e
key. An adversary who wants to forge this proof needs to find a _colli= ding_
seed: a different seed s' such that HMAC-SHA512("Bitcoin seed", s'= ) produces
the same master key. The BHT algorithm (Brassard-Hoyer-Tapp [= 6]) is the
best known quantum collision finder, and it runs in time prop= ortional to the
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 advers= ary can't
efficiently reconstruct!

This demo focuses on the Tapro= ot case, but the rough approach also applies
to any other output generat= ed via BIP-32. BIP 32 was originally published in
2012, over 14 years ag= o. So safe to say that _most_ wallets were generated
under this scheme. = However, Bitcoin Core only officially adopted BIP-32 in
2016/2018, movin= g away from their existing key pool structure. I can't say
how much BTC = is held today in outputs generated with Bitcoin Core's original
key pool= , but if you have coins generated via that mechanism, you may want
to co= nsider migrating them to a BIP-32 wallet.

## TinyGo + RISC-V + risc0=

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

Today you can take some subset of Rust, compi= le 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 Bitco= in stack of choice (lnd/btcsuite) uses
a series of Go libraries, so I wa= nted to be able to re-use them, first for
this demo, then also in the fu= ture for other projects.

TinyGo is a special Go compiler based on LL= VM, that targets mostly embedded
environments. You can use it to generat= e go programs that can run on
micro controllers, or on web assembly (pro= ducing 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<= br>relies on. So the first step here was to create a new target definition = for
TinyGo: riscv32-unknown-none, which uses base integer + multiply/div= ide
instructions with no compressed instructions, which uses 4 KB stacks= for
each task. From there, I created a new linker script
(`targets/r= iscv32im-risc0-zkvm-elf.ld`) which created a memory layer
identical to w= hat risc0 expects. The final component was a new runtime
(`src/runtime/r= untime_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 number
of kernel = syscalls (called ecalls in the platform [7]) to handle: read+write
to st= din/stdout, halting, and the journaling mechanism (the transcript of
exe= cution committed to), which basically implement the kernel that the guestexecutes in. Fast forward to 2026, and after pulling the latest version o= f
the repo, I realized that they now make a libzkvm_platform.a, which pa= ckages
up the kernel nicely to be linked against. So I threw out my cust= om 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 t= o be proved) and a Go host (the thing that executes the
program and gene= rates the final proof).

## BIP-32+Taproot zk-STARK Proof

With= basic proofs working (like the classic: I know the factorization of a
n= umber `n`), I was unblocked to generate the actual proof. The claim/proofis represented with the following JSON artifact:
```
{
"schema= _version": 1,
"image_id": "8a6a2c27dd54d8fa0f99a332b57cb105f88472d977c= 84bfac077cbe70907a690",
"claim_version": 1,
"claim_flags": 1,
= "require_bip86": true,
"taproot_output_key": "00324bf6fa47a8d70cb551= 9957dd54a02b385c0ead8e4f92f9f07f992b288ee6",
"path_commitment": "4c7de= 33d397de2c231e7c2a7f53e5b581ee3c20073ea79ee4afaab56de11f74b",
"journal= _hex": "010000000100000000324bf6fa47a8d70cb5519957dd54a02b385c0ead8e4f92f9f= 07f992b288ee64c7de33d397de2c231e7c2a7f53e5b581ee3c20073ea79ee4afaab56de11f7= 4b",
"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 derivatio= n is a part of the proof. BIP-86 was only adopted
post-Taproot, so if yo= u have an existing BIP-44 path, you can instead opt to
claim that instea= d. The Taproot key we're generating the proof against is
also part of th= e _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 BI= P 86 path that the prover used. Finally, we also commit to the
journal h= ex, which is basically a commitment to the public claim.

Assuming yo= u'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:
```
ma= ke verify GO_GOROOT=3D/path/to/go1.24.4
```

The default prove tar= get writes:
* ./artifacts/bip32-test-vector.receipt
* ./artifacts= /bip32-test-vector.claim.json

The receipt is the STARK proof artifac= t. claim.json is the stable,
human-readable description of the public st= atement being proved.

## Application to a Future Keyspend Disabling = Soft fork

As mentioned above, assuming the community is forced to de= ploy a keyspend
disabling soft fork in the future, we can also deploy so= me 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, w= e've shown that this is achievable using 2 year old consumer
hardware. I= don't doubt that the upcoming advancements (eg: photonics, new
flavor o= f 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 tha= t this proof has a few layers of indirection,
mainly the RISC-V layer th= at adds overhead which increase the total amount
of steps, and therefore= the size of the proof. A production grade
deployment would likely inste= ad 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 s= pending.

Looking to the memory+computational requirements necessary = to generate the
proof, I've left two low hanging fruits:

1. Firs= t, 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 th= at up using their recursive proof/composition syscalls:
sys_verify_i= ntegrity+sys_verify_integrity2. We can then assembled a
series of th= ese 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://micro= soft.github.io/Picnic/

[6]: https://en.wikipedia.org/wik= i/BHT_algorithm

[7]: https://github.com/Roasbeef/go-zkvm/blob/main/docs/ecall-r= eference.md

--
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+...@googlegroups.com.<= br> To view this discussion visit https://groups.google.com/d/msgid/bitco= indev/CAO3Pvs_PciUi%2BzBrCps3acO14sgeHVUANx9w6TVwUf_AYcd_qQ%40mail.gmail.co= m.

--
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+...@googlegroups.com.<= br> To view this discussion visit https://gr= oups.google.com/d/msgid/bitcoindev/ciibnh-b0x-rLwA8pY5NURBfPvG58gLcS7yPLIIk= FV5IzA1k-PTsPZqYU8uUyQRxLCnEFhGcrRCTM39N2AYEy0Db2H_UwIse3Hg9XEXNEYg%3D%40pr= oton.me.

--
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+...@googlegroups.com.<= br>

--
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/02378fd1-17a4-47aa-89fa-ee87626def65n%40googlegroups.com= .

--
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/YmXg6Q= UwLlLB7hYkqL9AnexCHy70dFPVZSZ2GyGrGPlEBna4gc1ZlaHptaVzsVAcEh7gadakxHXTk6CJD= ZfQ-9Ycjg4BI77qttmgaP1LWtc%3D%40proton.me.
-----------------------80189ce6e70552e021a4a651a71b5bf9-- -----------------------c2d9ccf5eaa15e50460689f32fb8a6be-- -----------------------e804b9dfced1a04be2dd09b3e2737b4f Content-Type: application/pgp-keys; filename="publickey - conduition@proton.me - 0x474891AD.asc"; name="publickey - conduition@proton.me - 0x474891AD.asc" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="publickey - conduition@proton.me - 0x474891AD.asc"; name="publickey - conduition@proton.me - 0x474891AD.asc" LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tCgp4ak1FWkRub0tSWUpLd1lCQkFI YVJ3OEJBUWRBcnBZYWFjZDgwcXdocmNaQW9VbW9NSHNWS21iZWlPZUEKcFhXbk1ybFdPZkxOSzJO dmJtUjFhWFJwYjI1QWNISnZkRzl1TG0xbElEeGpiMjVrZFdsMGFXOXVRSEJ5CmIzUnZiaTV0WlQ3 Q2pBUVFGZ29BUGdXQ1pEbm9LUVFMQ1FjSUNaQjRLV3p0aFBhenhRTVZDQW9FRmdBQwpBUUlaQVFL YkF3SWVBUlloQkVkSWthMENNdHJMZGcxM2EzZ3BiTzJFOXJQRkFBQTZhQUVBM1RmNHdqSVoKYnox K0diS0h4K09WQytNUXlVdi84RStoWUpjTE5QZnA0NEFBLzNiak5OTXN4WHdJTGZEM0xManNVVWFo CitBV2JyblVjVUFqQ2R1d3hUT01LempnRVpEbm9LUklLS3dZQkJBR1hWUUVGQVFFSFFDSXYxZW5J MU5MbAo3Zm55RzlVWk1wQ3ZsdG5vc0JrTmhQUVZxT3BXL3RKSkF3RUlCOEo0QkJnV0NBQXFCWUpr T2VncENaQjQKS1d6dGhQYXp4UUtiREJZaEJFZElrYTBDTXRyTGRnMTNhM2dwYk8yRTlyUEZBQUFR TFFEL2NCR2kwUDdwCkZTTkl2N1B6OVpkeUNVQjhzTy90dWZkV3NjQkNZK2ZMYTV3QkFNK0hTL3Jp S014RGt0TkhLakRGc2EvUgpEVDFxUGNBYXZCaXc2dDZ4Ti9jRgo9Y3d5eAotLS0tLUVORCBQR1Ag UFVCTElDIEtFWSBCTE9DSy0tLS0tCg== -----------------------e804b9dfced1a04be2dd09b3e2737b4f-- --------bf7d74349df6eed82a8afa99fde8c11e4be5a55ecf0338d3cddda146c4f8420d Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: ProtonMail wrsEARYKAG0FgmneYsMJEHgpbO2E9rPFRRQAAAAAABwAIHNhbHRAbm90YXRp b25zLm9wZW5wZ3Bqcy5vcmfuA8wCKQEn31SAiTGc/dRigZa+s8PIrvj9bmX0 emguchYhBEdIka0CMtrLdg13a3gpbO2E9rPFAACu1QEA3OW+TVgQUYZgEw7t kZzsDK3RxhuEFv0lEh6b6WTEXMwBALcp7kvniAUgNw0FEJhJKj/+b0t8xjjN ABn/2IiA1GoA =CKi7 -----END PGP SIGNATURE----- --------bf7d74349df6eed82a8afa99fde8c11e4be5a55ecf0338d3cddda146c4f8420d--