From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Thu, 07 May 2026 01:45:14 -0700 Received: from mail-ot1-f63.google.com ([209.85.210.63]) by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1wKuM4-0000gI-0g for bitcoindev@gnusha.org; Thu, 07 May 2026 01:45:14 -0700 Received: by mail-ot1-f63.google.com with SMTP id 46e09a7af769-7e0632c733asf1273832a34.1 for ; Thu, 07 May 2026 01:45:11 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1778143505; cv=pass; d=google.com; s=arc-20240605; b=IXiVss/eXytGTOoA2WPrlpv09e8MDhz4giW6u11Fhmrdxouuf4m/3UC6LAkajpmITu qfZPeg+IAn+S2F4iADsMTkcuIkaQ+YT6j9R+9MLKlzObq1lyEcweuomtjokuX/ub+MYS oD+w3BlvgJOcUYbaxGU7pP8dZSoDJMe14nfr3158s5mxCCfBdl+YBFRXedONcbZHTW86 S64au3vd41OvGEgwNU5C5h/kS0jeaivLJDWCBuyH9eoa3FhFzqc9BWD56A+otD4TAQJy 9KAOGZa5EXImPcYSNsHJmXzWPPOj0JljMMGwORUY8hYpk1fN0XN0hHS2s2D8wH+gpNws fTSA== 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:references:to:cc:in-reply-to:date :subject:mime-version:message-id:from:sender:dkim-signature :dkim-signature; bh=qh/5eL0Mv4VjX8vod3kQB2Uvje1DP4teSNo7znxXZyA=; fh=RNtfSZE1KXb8OxvSK82Guiy98Ml5PxCt+vvZTxfRJng=; b=YIujmINtZ1bhlLV9tRO76ueb51mwZR7j3TwnkEQVy/2cFKi/ELwo/bsLU1uC+05dEO fj5YwV2bpwWXKiZeBKmhDKE9Q9YKT1VBZ/jImXL1Dj4gvIbRZzo0MLqhxg/hqZlQNFxS LA+ZOTWIyIUKLKExu/63tDq6par1KVS2G9KVE+Ivux8WQjvsBhnR9+4ExrGTO86rbNK1 WZBpowe1PkySwX/TBpQbN5NvR5JlsmU+sAA/Pw7PbE6g+uU5k6hI8xEhJP6bFbENQUZx mHW5JuK4udOY59xUduEI0te4uGTWNUdnym9/TnL5kM6TLe6Na8guG8mJz0JcI07CVrt3 AYzA==; darn=gnusha.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20251104 header.b=i83PEaHJ; spf=pass (google.com: domain of jonas.schnelli@gmail.com designates 2607:f8b0:4864:20::62a as permitted sender) smtp.mailfrom=jonas.schnelli@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@googlegroups.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1778143505; x=1778748305; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:references:to:cc:in-reply-to:date:subject :mime-version:message-id:from:sender:from:to:cc:subject:date :message-id:reply-to; bh=qh/5eL0Mv4VjX8vod3kQB2Uvje1DP4teSNo7znxXZyA=; b=pCKwv9gbvfy0du8GcsErkOhexftWTjg/E4cuiGWVh3/xOCDtMtevE9QnBJ4mJ60cBS UGDNZiiI27JvZMlS5dWrgnQw1N/Op79vZVSH09b1FBArAzRa39ubcrG37Gl6IZG/ysZO tE+vyYQ4v/pv6xsIpwPNSZUMZUGeVm3/yj7yHesr340PHppPt1r1MosyPAcJ3mkU1GN1 id4DD0eKP96WhxHDOxOM3QRnj0nqhHmfw/S0Z4hLWg/Ac+Y4K5UZ4LA4YkvKdgpmNDrV pA8oxWtxuQ4B5YkVspVmEFsdnNzY1Ltrz5FFlsP/u0c4qXNGAtHafG4AR6TkVqZrXqKy EiEw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778143505; x=1778748305; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:references:to:cc:in-reply-to:date:subject :mime-version:message-id:from:from:to:cc:subject:date:message-id :reply-to; bh=qh/5eL0Mv4VjX8vod3kQB2Uvje1DP4teSNo7znxXZyA=; b=aECJzNfx3gq4USAfQJacjAl1UgKPeG3Omkm0yrp5dnOrh912smNZOouhYd09GFsuCR 8WBF711wv2XcXRlGtQYb8RK88vTJh08DpcTEhLzHz6t3eOBSHPV1qeAFWOBq2FIzX2mU GAmRBv4eIHoTqDkJN1VM0N7agdxzq99LdKsrMN7KRYIzDyZAIsEco8X41Xhqy3+PbWIf oXfBvMKnO5a9nAkZvtmPx9WTeHRhFwmWSsji7zZH0ntMUifPYTWMUz6YFTDJf0P7vi5F AhlVJhEFfRs73OxBXiYs4aaX17VEc4IcbgFEzKDKam2jwtFp6iV2nueeUV/hSqaGCU8z kvJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778143505; x=1778748305; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:references:to:cc:in-reply-to:date:subject :mime-version:message-id:from:x-gm-gg:x-beenthere:x-gm-message-state :sender:from:to:cc:subject:date:message-id:reply-to; bh=qh/5eL0Mv4VjX8vod3kQB2Uvje1DP4teSNo7znxXZyA=; b=jZ77vNT+mbQxHEc/UX/cARJlwNhblN4xAW/5jafK+KE1UKraWPItr7AMsfrNC6L15n 80GHdGfdFUo14ZJzEixfs88GAD9TaPzqiNUS6M/mR/OOOUQwzfnutTWvrJqdcpZGHTw7 gy0xtPQKxrUCTRGdL6vdbuxz8t8NyTM30Y/a41JkRumrMpHlYE3pbccVzNJvZfSOIW29 GUiyWk25ujg8h+Z6PuXdqMM4i9WrLxNUcs/p/aqRWWR7447BBnv10ASm3BHsKHWchEVy ZQy0NEsCqz56MpsdJbv93QWqLBk8kphG4tK85x1tqyZHVSbsd/+ewrzF3jj1KpEN6zop J4lw== Sender: bitcoindev@googlegroups.com X-Forwarded-Encrypted: i=2; AFNElJ/lCUglQMVGjqOZK+Wu2M2wGiWygLVAPG1DKHJHe13u2845J4oS5Xo60pW6zppiDxJEMxEPlbroRYGq@gnusha.org X-Gm-Message-State: AOJu0YwlVMQBU6AdSrPCqNOVaCcfEZp3okTpKHC2pNeYNupBlNdd+uOS FHwS8/8sLWtRimkJ/RWZLPhimAqgt5B0yHlRFb8zYvc61RquC2rfnh5D X-Received: by 2002:a05:6820:80a:b0:696:8c3f:d7cd with SMTP id 006d021491bc7-69998c8f271mr3796785eaf.4.1778143505110; Thu, 07 May 2026 01:45:05 -0700 (PDT) X-BeenThere: bitcoindev@googlegroups.com; h="AUV6zMP0z7fhZpTpQe3Zm3HfWsSOHcy2Zr48QJ9yPcLxzkC1ag==" Received: by 2002:a05:6870:18:b0:42f:c73e:5cef with SMTP id 586e51a60fabf-43525740336ls447242fac.2.-pod-prod-09-us; Thu, 07 May 2026 01:44:59 -0700 (PDT) X-Forwarded-Encrypted: i=2; AFNElJ8FWJ1B5mIl7zgX3IAl4zQ6sPx6WH8Ytc95ZafGi3mo62aM2OYPSs2WaZ79IO91NCno0Qschntc8M2D@googlegroups.com X-Received: by 2002:a05:6808:4e8e:b0:46a:d8b7:1101 with SMTP id 5614622812f47-480424aa8damr2911632b6e.41.1778143499757; Thu, 07 May 2026 01:44:59 -0700 (PDT) Received: by 2002:a05:620a:172c:b0:906:4363:e55d with SMTP id af79cd13be357-90646ca28fcms85a; Wed, 6 May 2026 22:25:23 -0700 (PDT) X-Forwarded-Encrypted: i=2; AFNElJ/dvFSOyI/auOlhodgOqC1QgWtpkkrBq8Onm00OUZIlWyEzQeLhpoWBXPJDGASmq1222UMpbQKAsSO4@googlegroups.com X-Received: by 2002:ac8:5fc5:0:b0:513:a93:b1db with SMTP id d75a77b69052e-51461fa4423mr92248971cf.28.1778131522411; Wed, 06 May 2026 22:25:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1778131522; cv=none; d=google.com; s=arc-20240605; b=JDtm8aJ02MNVv5Rp53SJ+uVUQFhxdnrjqM0IhtUJKSuOz2TR4jxgtslHEZEpStrHA/ s+0SZwz4+iZ/jxkUb8eL5Wtr8oILL3ERPhW7poSxi/0zf4QTNDrYlGZx2aeWhj/lO2MY klZw0exb9nwcToOhRsGgkdYJgeLob7MuYOTZ+eBzDWiRZrqQzO3zBFp61wKA+oXdY6y2 eKCMkvQzPDEUzGFrW82pyuzsKcjJC/13rQ++EZBfVy8gsHD5Im64GU88WqXlvigPKORB BthfZf9OP7S8pz1zcPqjQuHcHGwmHQShgiuHgDAlBVfOFqSKYO97bI210HMYeXb9nWjT pj1A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:dkim-signature; bh=U0THmxdZy0uxN9Cmcq2d+sMAOhS96m/Ul3oDjyC7gd0=; fh=/28wxjkKIuSLhf+TtMjCmd+Ph7jWDV1rcnvi3NANfas=; b=aPI5ZATGIbm+q7gBu2eHH/OG6EMLNgJu+aJ01z0mbzF6Cem49JMRdh/68luNMrPARg G8GH9p5/BEHjC0XSGI9ZIvuw7EK044kks1sHeOokpb2WdS9M4kZCViWl1GGw+Uj+G1Ik wJ3A3ROyBBVF0O4V79P1bg1NrrFieTk+gQO2XRb19Tw2k/qNPVv6DdYMD5T/G2JWCYha PXhRJc+rb1axTIeXkjPzr7hgmHoIW4WFbLwMbBmwcUzh5vjdZdWdbzf2elpxMuc4JQEw 7Q5NlPBdjJMoCzTFSH23+I0LbMyUXVvL+Kf5K0nc48rl67VzecfOPuUJtuK4FxCxlPSl TnOQ==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20251104 header.b=i83PEaHJ; spf=pass (google.com: domain of jonas.schnelli@gmail.com designates 2607:f8b0:4864:20::62a as permitted sender) smtp.mailfrom=jonas.schnelli@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@googlegroups.com Received: from mail-pl1-x62a.google.com (mail-pl1-x62a.google.com. [2607:f8b0:4864:20::62a]) by gmr-mx.google.com with ESMTPS id d75a77b69052e-5104098861bsi6996111cf.5.2026.05.06.22.25.22 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 06 May 2026 22:25:22 -0700 (PDT) Received-SPF: pass (google.com: domain of jonas.schnelli@gmail.com designates 2607:f8b0:4864:20::62a as permitted sender) client-ip=2607:f8b0:4864:20::62a; Received: by mail-pl1-x62a.google.com with SMTP id d9443c01a7336-2ba0714574fso2496065ad.2 for ; Wed, 06 May 2026 22:25:22 -0700 (PDT) X-Forwarded-Encrypted: i=1; AFNElJ9Z1VJ5BpQIE+4FsIEHgJweFarXSjqmI5I1yy8vxUajapXoaDiojFCtMgCU3U6WwE8H9UFCubboPxro@googlegroups.com X-Gm-Gg: AeBDievJI4uM0dMPECBGvSKMwoyQWDwmkeKPhFCdRMwc68ZJQcjIIhpLYEc7+GTdflP C+fcAG5BsqBeYu+LoYHeMYVVrXSCk3TJd3A9hrsOIJfUfCVg9CkCp/HEQv6xaS4UefMcdQASewa D6mT4+o2bBEUjEGXmK98RJ7Wy/Rqg80OXbj/+feCg0hKusrHcb3rwlqpsmRvnwhHvihcypnUWBB GbtCj4RCHC7+APIXApLSN9x6+vsMnsWO1Mbru5cGFgkDYC89rlpZsFRvUZxgpfE8TWbZ0o2qgrR MFee01fWUbcZlDe0zoAD+QLJRcUIbghAAXupkjGyMUD12O6foJdQHp3NsCW1SCq1bEhaiAMl9vG 7KawoWiNkOymQOXxQQfJd6FyrId17jRgUNzqPEcW32463nbPHg99DdzoN0w/tcZEbo4O1ls7N6d MNGXzq5LiPpi9ZDNyd0tDAIDON+Lo6Pkxw+5RfVynFtJgNG/C8mTv3LTfQ5XgQMmh04i4y6bskf 9mjBo88kp5fBp8XsI/jhAf3Jg== X-Received: by 2002:a17:902:ea0e:b0:2b2:481b:de68 with SMTP id d9443c01a7336-2ba79c14a7cmr75581875ad.35.1778131521224; Wed, 06 May 2026 22:25:21 -0700 (PDT) Received: from smtpclient.apple (dhcp-141-239-176-228.hawaiiantel.net. [141.239.176.228]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2babab0488asm10179545ad.36.2026.05.06.22.25.20 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 May 2026 22:25:20 -0700 (PDT) From: Jonas Schnelli Message-Id: <547ADFCA-2BB1-4E16-A26A-C92262EBBD84@gmail.com> Content-Type: multipart/alternative; boundary="Apple-Mail=_254B20D0-F06A-456B-A09A-C2CF54EBE9CD" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3826.700.81\)) Subject: Re: [bitcoindev] A Post-Quantum Path for BIP 324 Date: Wed, 6 May 2026 19:25:09 -1000 In-Reply-To: Cc: Ethan Heilman , Bitcoin Development Mailing List To: Olaoluwa Osuntokun References: X-Mailer: Apple Mail (2.3826.700.81) X-Original-Sender: jonas.schnelli@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20251104 header.b=i83PEaHJ; spf=pass (google.com: domain of jonas.schnelli@gmail.com designates 2607:f8b0:4864:20::62a as permitted sender) smtp.mailfrom=jonas.schnelli@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@googlegroups.com Precedence: list Mailing-list: list bitcoindev@googlegroups.com; contact bitcoindev+owners@googlegroups.com List-ID: X-Google-Group-Id: 786775582512 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Score: -0.5 (/) --Apple-Mail=_254B20D0-F06A-456B-A09A-C2CF54EBE9CD Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="UTF-8" Thanks for writing this up Laolu. I think option 1 (classical-then-PQ-upgrade) is probably the right path, mo= stly because it keeps the byte-0 pseudorandomness property without needing = Kemeleon or any new obfuscation primitive. If the ML-KEM exchange happens inside the already-established v2 ChaCha20Po= ly1305 channel, then to a present-day classical observer the bytes should s= till look random,... the inner PQ handshake is just more ciphertext. A futu= re QC adversary doing harvest-now-decrypt-later would break the outer ECDH = eventually, but I think they'd then still have to break ML-KEM-768 to get t= he v3 transport keys, which is kind of the whole point. So we'd probably ge= t hybrid security against the QC threat and also keep the property that tod= ay's wire bytes are indistinguishable from random. That said, I'm not sure how far we should really take the pseudorandomness = argument,... traffic shape (packet sizes, timings, query/response patterns)= probably already reveals quite a bit about what's going on, so the byte-co= ntent randomness is only one part of the picture. The extra round trip is probably fine given how long Bitcoin P2P connection= s live. The DoS angle you flagged might also be smaller in option 1, since = the responder still commits after 64 bytes and not after a 1184-byte ML-KEM= key,... though I haven't thought hard about wether there are other DoS vec= tors the inner upgrade introduces. On Ethan's TLS 1.3 suggestionm,... I don't think it really fits. Apart from= the dependency cost (which we deliberately kept low in BIP 324), TLS has i= t's own fingerprint, which would probably undo the censorship-resistance an= gle. And it bundles authentication with encryption, which we explicitly dec= oupled. One thing worth looking at: OpenSSH (whose chacha20-poly1305 construction w= e drew from originally) shipped mlkem768x25519-sha256 as default in 10.0 la= st year, and they just concatenate-and-hash the two shared secrets. Their t= hreat model doesn't care about pseudorandomness so they can send ML-KEM mat= erial in the clear, but the combiner shape is probably a reasonable referen= ce for ours. /jonas > On May 6, 2026, at 12:15=E2=80=AFPM, Olaoluwa Osuntokun wrote: >=20 > Hi Ethan,=20 >=20 > That's a great question.=20 >=20 > First, I don't speak for Bitcoin Core by any means (btcd has also impleme= nted > BIP 324 FWIW). Based on past observed behavior, they typically prefer to = keep > dependencies slim. Many years ago there was a concerted push to remove op= enssl > as a dependency from the project. So I would imagine the idea of rolling = out > full blown TLS 1.3 might encounter some resistance. >=20 > In terms of cryptography, BIP 324 as defined uses secp256k1. TLS 1.3 as > specified doesn't support secp256k1 within the set of supported cipher su= ites. >=20 > If ensuring that BIP 324 continues to implement an oblivious KEM is a key > requirement, then TLS 1.3 doesn't fit the bill. >=20 > Regarding a hybrid PQ KEM, there exists an IETF to add a new key agreemen= t > suite to TLS 1.3: https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-m= lkem/. > Only secp256+384(r1) and x25519 are supported as elliptic curves in this = draft. >=20 > One additional aspect is that today BIP 324 doesn't implement authenticat= ion at > all, you only get confidentiality. TLS 1.3 would mean introducing certifi= cates > in some fashion, thereby coupling concerns from the original PoV of Bip 3= 24. >=20 > BIP 324 also includes as section in the BIP detailing the rationale of BI= P 324 > over a more general purpose protocol (mentions some of the points above): > https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#:~:text=3D= Why%20not%20use%20a%20general%2Dpurpose%20transport%20encryption%20protocol= %3F. >=20 >=20 > -- Laolu >=20 >=20 >=20 > On Tue, May 5, 2026 at 2:18=E2=80=AFPM Ethan Heilman > wrote: >> Thanks Laolu for thinking through making PQ BIP 324 and writing this up. >>=20 >> Reading through what you wrote made me what wonder, why not use this as = an opportunity to move to TLS 1.3? >>=20 >> What's the case against using TLS 1.3 for PQ P2P connection encryption? = Is there some functionality that TLS 1.3 is lacking that we really want? I= s the case against solely to not have TLS 1.3 as a complex dependency in bi= tcoin-core? >>=20 >> The advantages of TLS 1.3: >>=20 >> 1. Make Bitcoin P2P connections blend in with all the other TLS connecti= ons. This isn't strong privacy, you can distinguish TLS encrypted Bitcoin t= raffic via timing and size, but it reduces accidents where a firewall sees = an unknown protocol and blocks it. >>=20 >> 2. Use of QUIC for faster relay, oblivious HTTP and QUIC tunnels-in-tunn= els for private relay and similar protocols. >>=20 >> 3. Lots of eyeballs on TLS 1.3, we don't need to build or maintain it. >>=20 >>=20 >> On Tue, May 5, 2026, 00:41 Olaoluwa Osuntokun > wrote: >>> Hi y'all,=20 >>>=20 >>> In case you weren't already tired of all the recent dev list chatter re= post >>> quantum cryptography, here's another! >>>=20 >>> When the topic of Bitcoin transitioning to a post quantum world is brou= ght up, >>> the discussion typically focuses on the consensus layer re swapping out >>> vulnerable signature schemes. However, the consensus layer isn't the on= ly area >>> of Bitcoin that relies in cryptography that would be broken in the face= of a >>> powerful quantum computer! That's right, I'm talking about BIP 324, the= peer to >>> peer encryption BIP for Bitcoin. >>>=20 >>> Like everything else on the Internet today, BIP 324 uses ECDH to allow = two >>> connecting peers to derive a shared secret known only to them, which is= then >>> used to encrypt all traffic between them. As ECDH relies on Elliptic Cu= rve >>> cryptography, a future quantum computer would be able to eavesdrop on a= p2p >>> handshake transcript, then derive the underlying private keys to the ep= hemeral >>> ECDH public key, permitting it to decrypt all traffic. It's actually wo= rse than >>> that, as today adversaries can collect all encrypted p2p Bitcoin traffi= c, with >>> the hope of being able to decrypt it all at a future date. This is comm= only >>> referred to as the: "harvest, decrypt later" (HNDL) strategy [11]. >>>=20 >>> Compared to a consensus change, which requires widespread market agreem= ent, and >>> coordination to achieve, upgrading BIP 324 to be post quantum resistant= is a >>> much lower hanging fruit worthy of pursing immediately. >>>=20 >>> Last week I starting thinking a bit about this topic, brushing up on th= e latest >>> literature/techniques, and stumbled onto a few key design questions. Th= e goal >>> of this post isn't to propose a new concrete p2p encryption BIP, instea= d I want >>> to start discussion on the various design tradeoffs that came up as I w= as >>> researching this p2p encryption transition. >>>=20 >>> ## PQ BIP 324 Design Questions >>>=20 >>> 1. Do we want to pursue a hybrid KEM (key encapsulation mechanism), or = go with >>> a pure PQ KEM? >>>=20 >>> 2. Is it still a key requirement that the initial handshake be >>> indistinguishable from a random byte string? >>>=20 >>> 2a. If yes to the above, then should we go with classical-then-pq-up= grade, >>> or a one shot hybrid oblivious KEM. >>>=20 >>>=20 >>> ## A Brief Intro to KEMs + ML-KEM >>>=20 >>> First, let's introduce the new primitive we have to work with: ML-KEM >>> (Module-Lattice-Based Key-Encapsulation Mechanism) [1][2]. As it says o= n the >>> tin, ML-KEM is a lattice based Key-Encapsulation Mechanism. The phrase = KEM >>> might sound unfamiliar with those comfortable with ECDH, but ECDH is ac= tually a >>> KEM itself. >>>=20 >>> A KEM has 3 algorithms: >>> * KeyGen() -> {sk, pk} >>> * Generates a public/private secret key pair >>>=20 >>> * Encaps(pub) -> {secret, capsule} >>> * Generates a new secret value, and a "capsule", which only the ho= lder of >>> pub can use to obtain the secret value. >>>=20 >>> * Decaps(priv, capsule) -> secret >>> * Uses the private key to extract the secret from the capsule >>>=20 >>>=20 >>> If you squint a bit, then you'll see that ECDH is a KEM, and a rather e= legant >>> one at that: >>> * KeyGen() -> {k, k*G} >>> * Normal EC key generation.=20 >>>=20 >>> * Encaps(pub) -> {capsule =3D x*G, secret =3D pub*x} >>> * The core ECDH routine. The ephemeral public key is actually the >>> "capsule". The resulting secret is the ECDH output with the rem= ote >>> party's KEM public key and the local secret. >>>=20 >>> * Decaps(priv, capsule) -> secret =3D priv * capsule >>> * The receiver completes the key exchange using the ephemeral pub= lic key >>> and their own private key. >>>=20 >>> ECIES is another flavor of EC based KEM. >>>=20 >>> One thing worth noting is that AFAICT, so far in the NIST PQC world [4]= , there is >>> no known non-interactive key exchange protocol like we enjoy today with= ECDH. >>> IIUC, the reason is that lattice based schemes derived from the LWE [3] >>> problem, whose security is predicated on using "noise" to hide a secret= value. >>> For these cryptosystems, usually a type of "hint" is sent to make every= thing >>> work out nicely like in ECDH. However, in the stricter non-interactive = setting >>> (no messages sent), this doesn't map cleanly. >>>=20 >>> As a result, ML-KEM looks more like a hybrid encryption protocol (Alice >>> encrypts a shared secret to bob using asymmetric lattice crypto). >>>=20 >>> ## To Hybrid KEM, Or Not to Hybrid KEM >>>=20 >>> This brings us to our first design question.... >>>=20 >>> Should we use a hybrid KEM or a pure post quantum one?=20 >>>=20 >>> A hybrid KEM would keep the existing ECDH, _also_ do ML-KEM, then secur= ely >>> combine (there's some subtlety there, see [6][7]) the resulting in a >>> final secret value for encryption. A hybrid KEM is attractive as an enc= ryption >>> channel derived from such a KEM is secure if _any_ of the combined sche= mes are >>> secure. This permits schemes to hedge a bit, as hey, maybe the PQ stuff= is >>> actually broken in the future but ECDH isn't. If it's the other way aro= und, >>> then your encryption scheme is still secure. >>>=20 >>> ### Pure ML-KEM P2P Encrypted Handshake >>>=20 >>> If we opt to not use a hybrid scheme, then the Elligator layer can be d= ropped >>> all together. Instead, the 1.1 KB (ML-KEM-768) encapsulation keys are s= ent, >>> keeping the trailing garbage+terminator in tact.=20 >>>=20 >>> The initial handshake would look something like:=20 >>> * Alice -> Bob: alice_encaps || initiator_garbage >>> * Alice derives an encapsulation key, and sends it to Bob. >>>=20 >>> * Bob -> Alice: ml_kem_capsule || responder_garbage || responder_garba= ge_terminator || first_encrypted_packet >>> * Bob uses Alice's encapsulation key to encapsulate a random secret,= and >>> sends it over to Alice. He can also encrypt the first message at t= his >>> point. >>>=20 >>> * Alice -> Bob: initiator_garbage_terminator || first_encrypted_packet >>> * Alice de-encapsulates the shared secret, and can now also start to= encrypt >>> messages. >>>=20 >>> We'd then replace `v2_ecdh` with something like a `v3_mlkem` that deriv= es the >>> final shared secret based on the sent/received transcript up until that= point: >>> * `sha256_tagged("bip324_ml_kem", ml_kem_secret, alice_encaps, ml_kem= _capsule)` >>>=20 >>> ### Hybrid ML-KEM P2P Encrypted Handshake >>>=20 >>> If we want to use a hybrid combiner, then along side the normal ellswif= t keys, >>> the ML-KEM-768 encap key is also sent: >>>=20 >>> * Alice -> Bob: ellswift_alice || alice_encaps || initiator_garbage >>> * Bob -> Alice: ellswift_bob || ml_kem_capsule || responder_garbage ||= responder_garbage_terminator || first_encrypted_packet >>> * Alice -> Bob: initiator_garbage_terminator || first_encrypted_packet >>>=20 >>> Then following guidelines of [7], we'd then replace `v2_ecdh` with some= thing >>> like `v3_hybrid_shared_secret`: >>> * `sha256_tagged("bip324_ellswift_xonly_ecdh_mlkem_768", ml_kem_ss, e= cdh_point_x32, alice_encaps, ml_kem_capsule, ellswift_alice, ellswift_bob)` >>>=20 >>> ## PQ/Hybrid Obfuscated KEMs >>>=20 >>> At this point, those that are familiar with BIP 324 will recognize that= both >>> the pure PQ and hybrid versions renders the ElligatorSwift usage pretty= much >>> useless. ElligatorSwift encodes a 32-byte public key as a 64-byte value= which >>> is indistinguishable from a uniformly distributed bitstream. In a bubbl= e, this >>> means that the initial BIP 324 handshake to a 3rd party observer just l= ooks >>> like random bytes. However, with the introduction of ML-KEM, the ML-KEM >>> encapsulation key is sent in plaintext over the wire. An ML-KEM key has >>> identifiable structure, as it's a giant vector of polynomial coefficien= ts mod >>> 3329, which is easily recognizable over the wire. >>>=20 >>> Luckily, there's an ML-KEM analogue to ElligatorSwift, called Kemeleon >>> [8][9][10]! In a similar fashion to ElligatorSwift, it takes an ML-KEM = public >>> key, then encodes it as one giant integer, utilizing rejection sampling= . >>> Kemeleon applies this mapping both to the encapsulation keys, and also = the >>> capsule ciphertext that encrypts the shared secrets. The ML-KEM keys en= d up >>> being a bit smaller, while the ciphertexts map to a larger value. Anoth= er >>> tradeoff is that the Kemeleon key generation is ~3x slower than normal = ML-KEM >>> generation. >>>=20 >>> One thing to note here is that Kemeleon's "looks random" property isn't= quite >>> on the same footing as ElligatorSwift's. ElligatorSwift is statisticall= y >>> indistinguishable from random, since every 512-bit string is a valid en= coding. >>> Kemeleon's indistinguishability is computational, resting on a Module-L= WE >>> style assumption. So if you naively concatenate an ElligatorSwift key a= nd a >>> Kemeleon key, the pair is only as obfuscated as the weakest visible hal= f. This >>> asymmetry is what motivates the OEINC construction discussed below. >>>=20 >>> This brings us to our second design question.... >>>=20 >>> Do we still want to ensure that the BIP-324 handshake looks identical t= o a >>> pseudorandom bytestream from the very first message? >>>=20 >>> Assuming yes, then AFAICT, we have two classes of options here:=20 >>> 1. Retain the existing BIP-324 outer ElligatorSwift handshake, but us= e ML-KEM >>> within that initial encrypted transport to upgrade to a PQ shared = secret. >>>=20 >>> 2. Use the Outer Encrypts Inner Nested Combiner (OEINC - "OINK") comb= iner >>> from [8]. >>>=20 >>> 3. Attempt to adapt Drivel from [8] into the Bitcoin p2p setting. >>>=20 >>> ### Classical Encrypted Channel Upgrades to PQ >>>=20 >>> With the first option, we simply use one KEM right after the other. So = BIP 324 >>> v2 would be mostly unchanged, then we _upgrade_ to BIP 324 v3 within v2= .=20 >>>=20 >>> A sketch of this would be something like: >>> * Phase 0: normal BIP 324 handshake >>> * Phase 1: negotiation of PQ KEM scheme over the encrypted handshake >>> * Can be optional, if we just pick a set PQ KEM scheme. >>> * Before this point, no Bitcoin p2p message should be sent, as the= channel >>> isn't PQC protected yet. >>> * Phase 2: do normal ML-KEM within the ElligatorSwift derived encrypt= ed >>> transport >>> 1. Alice sends the encapsulation key >>> 2. Bob derives a secrets, encrypts it using the encapsulation key >>> 3. Both sides then derive a PQ shared secret, ss_PQ >>> * Phase 3: both sides use a hybrid combiner like sketched out above t= o derive >>> a new set of transport keys >>> * Phase 4: both sides rekey, switching over to a new the transport ke= ys >>>=20 >>> The upside of this option is that the outer part of BIP 324 remains unc= hanged, >>> then with another round trip, we're able to upgrade the encryption keys= to PQ >>> hybrid security. The downside is that the very first messages sent aren= 't PQ >>> from the start, but a PQ adversary wouldn't be able to decrypt the actu= al >>> Bitcoin p2p messages (as we wait to send those until the upgrade). The >>> handshake still looks like just random bytes. >>>=20 >>> ### Outer Encrypts Inner Nested Combiner >>>=20 >>> For the second option, [8] (with talk video [9] and slides [10]) descri= bes an >>> OEINC scheme where the outer KEM >>> encrypts the inner KEM, wherein the KEM ciphertext of an inner KEM is e= ncrypted >>> using a shared secret derived from the outer KEM. The two KEM ciphertex= ts and >>> the two derived keys are then used alongside a hybrid combiner to deriv= e a >>> final shared secret.=20 >>>=20 >>> Unlike the classical-then-pq-upgrade that establishes a classical chann= el, then >>> uses that to upgrade to pq channel, OEINC is a special hybrid combiner = that >>> achieves a similar output but in one swoop. It defines a special KEM, w= hich can >>> then be used as the KEM in the very first handshake I sketched out. >>>=20 >>> A sketch of this KEM looks something like: >>> * Setup: >>> * The outer KEM is BIP 324's ElligatorSwift-encoded secp256k1 DHKEM= . >>> * It serves as the outer KEM because its on-wire encoding is >>> statistically indistinguishable from random. >>> * The inner KEM is ML-Kemeleon. >>>=20 >>> * KeyGen(): >>> * (kem_secret_outer, kem_pubkey_outer) =3D outKEM.Gen() >>> * (kem_secret_inner, kem_pubkey_inner) =3D inKEM.Gen() >>> * combined_pubkey =3D (kem_pubkey_outer, kem_pubkey_inner) >>> * combined_secret =3D (kem_secret_outer, kem_secret_inner) >>>=20 >>> * Encaps(combined_pubkey): >>> * (shared_secret_outer, capsule_outer) =3D outKEM.Encap(kem_pubkey_= outer) >>> * (encrypt_key_1, encrypt_key_2) =3D KDF(shared_secret_outer) >>> * (shared_secret_inner, capsule_inner) =3D inKEM.Encap(kem_pubkey_i= nner) >>> * encrypted_capsule_inner =3D encrypt(encrypt_key_1, capsule_inner) >>> * combined_capsule =3D capsule_outer || encrypted_capsule_inner >>> * combined_shared_secret =3D combine(encrypt_key_2, shared_secret_i= nner, combined_capsule) >>>=20 >>> * Decaps(combined_secret, combined_capsule): >>> * (capsule_outer, encrypted_capsule_inner) =3D combined_capsule >>> * shared_secret_outer =3D outKEM.Decaps(kem_secret_outer, capsule_o= uter) >>> * (encrypt_key_1, encrypt_key_2) =3D KDF(shared_secret_outer) >>> * capsule_inner =3D decrypt(encrypt_key_1, encrypted_capsule_inner) >>> * shared_secret_inner =3D inKEM.Decaps(kem_secret_inner, capsule_in= ner) >>> * combined_shared_secret =3D combine(encrypt_key_2, shared_secret_i= nner, combined_capsule) >>>=20 >>>=20 >>> This is done over just sending the two encapsulated secrets plainly as = I >>> outlined above in order to achieve a stronger security notion. The issu= e with >>> this though is that though ciphertext uniformity (the encapsulated secr= ets) is >>> achieved, the two public keys sent are randomly looking, but not in a u= niform >>> manner. In practice, this might not really matter much AFAICT (a theore= tical >>> adversary would be able to distinguish the Elligator half from the Keme= leon >>> half). >>>=20 >>> ### Drivel: PQ-Obfuscated Authentication >>>=20 >>> The biggest issue with Drivel as a fit for BIP 324 is that it expects t= he >>> initiator to already know a long term static public key for the respond= er. In >>> the case of BIP 324, only ephemeral keys are exchanged, so there's no l= ong >>> term public keys known to either side. >>>=20 >>> To get around this, we could extend BIP 155 (or make a new one likely, = given >>> size limits) to include a signed OKEM key. However then that would intr= oduce >>> authentication into the combined set, which explicitly wasn't a design = goal >>> of BIP 324. >>>=20 >>> With that caveat in mind, here's the construction itself. Drivel [8] co= mbines >>> the OEINC scheme with another layer that out-of-the-box assumes an asym= metric >>> protocol within a set client and server. The client uses an existing OE= INC >>> KEM public key published by the server to then encrypt a fresh new ephe= meral >>> KEM. >>>=20 >>> -----=20 >>>=20 >>> So there we have it. Before drafting a concrete v3 transport, we need t= o >>> decide if we want a hybrid KEM, or are fine with a pure PQ KEM. Then we= need to >>> decide if we want to attempt to maintain the current quality where the = p2p >>> handshake transcript is indistinguishable from random. If yes, then tha= t forces >>> another series of decisions re how to construct/compose an oblivious KE= M from >>> available primitives. >>>=20 >>> At a glance, the route of classical-then-pq-upgrade seems to be the sim= plest. >>> BIP 324 stays as is, then we run ML-KEM within that. The ML-KEM keys ar= e >>> encrypted, so there's no need to sprinkle in the layer of Kemeleon. >>>=20 >>> If we want a nice combined protocol, then we should investigate the OEI= NC >>> route. It's more data to send as part of the initial handshake, but we = still >>> keep ElligatorSwift and use that as the outer KEM. >>>=20 >>> If for some reason we're concerned with a future adversary gaining a >>> distinguisher for Kemeleon, then maybe we need to bite the bullet and a= lso >>> roll out a full blown PQ authentication protocol along side everything. >>>=20 >>> One thing worth flagging for any of the byte-0 designs (where PQ materi= al is >>> sent in the clear on the very first flight, like the hybrid and OEINC s= ketches >>> above): ML-KEM-768 makes the responder do real work before it can decid= e if a >>> connection is even legit. Today, the responder only needs the first 64 = bytes >>> of an ElligatorSwift share before it can derive the shared secret. With >>> ML-KEM-768, the responder has to read and validate a 1184 byte encapsul= ation >>> key before running Encaps, and FIPS 203 mandates input checks on every = Encaps >>> and Decaps. In a permissionless P2P network, that's a meaningful change= in >>> inbound DoS surface, and probably calls for stricter handshake byte lim= its, >>> tighter timeouts, and possibly some form of stateless cookie/puzzle if >>> handshake floods become a real problem. The classical-then-pq-upgrade p= ath >>> sidesteps most of this since the PQ material only shows up after the v2 >>> channel is up. >>>=20 >>> With all that said, after the above design decisions are addressed, the= re >>> aren't too many concrete blockers here w.r.t rolling this out. Of cours= e the >>> development (eg: selecting/creating a library for ML-KEM and maybe >>> ML-Kemeleon), and upgrade will take some time. But unlike the consensus >>> layer, p2p encryption doesn't require the widespread market agreement t= hat an >>> actual soft fork does. BIP 324 is a much shorter walk to PQ than the co= nsensus >>> layer, and serves as a sort of PQ warm up before the bigger soft fork i= s >>> tackled.=20 >>>=20 >>>=20 >>> -- Laolu >>>=20 >>> [1]: https://en.wikipedia.org/wiki/ML-KEM >>> [2]: https://csrc.nist.gov/pubs/fips/203/final >>> [3]: https://en.wikipedia.org/wiki/Learning_with_errors >>> [4]: This statement ignores Isogeny based crypto, and also SWOOSH [5] a= s it requires 200 KB pubkeys >>> [5]: https://eprint.iacr.org/2023/271 >>> [6]: https://eprint.iacr.org/2018/024 >>> [7]: https://eprint.iacr.org/2020/1364 >>> [8]: https://eprint.iacr.org/2024/1086 >>> [9]: https://www.youtube.com/watch?v=3DCvFCYUq5rGg >>> [10]: https://csrc.nist.gov/csrc/media/Presentations/2025/kemeleon/imag= es-media/kemeleon.pdf >>> [11]: https://en.wikipedia.org/wiki/Harvest_now,_decrypt_later >>>=20 >>> --=20 >>> You received this message because you are subscribed to the Google Grou= ps "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/bitcoin= dev/CAO3Pvs9U3prZJiDs0Ns7LSA07R8hM-GQou_FcTZZz-JUQpUYHw%40mail.gmail.com . >=20 >=20 > --=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/CAO3Pvs8i%3DpLP30nRh_iyjSRJXne19wNezmQmo%3DJAk8%2BE4uJPhg%40mail.gmail.co= m . --=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/= 547ADFCA-2BB1-4E16-A26A-C92262EBBD84%40gmail.com. --Apple-Mail=_254B20D0-F06A-456B-A09A-C2CF54EBE9CD Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset="UTF-8"
Thanks for writing this up L= aolu.

I think option 1 (classical-then-PQ-upgrade)= is probably the right path, mostly because it keeps the byte-0 pseudorando= mness property without needing Kemeleon or any new obfuscation primitive.

If the ML-KEM exchange happens inside the already-e= stablished v2 ChaCha20Poly1305 channel, then to a present-day classical obs= erver the bytes should still look random,... the inner PQ handshake is just= more ciphertext. A future QC adversary doing harvest-now-decrypt-later wou= ld break the outer ECDH eventually, but I think they'd then still have to b= reak ML-KEM-768 to get the v3 transport keys, which is kind of the whole po= int. So we'd probably get hybrid security against the QC threat and also ke= ep the property that today's wire bytes are indistinguishable from random.<= /div>

That said, I'm not sure how far we should really t= ake the pseudorandomness argument,... traffic shape (packet sizes, timings,= query/response patterns) probably already reveals quite a bit about what's= going on, so the byte-content randomness is only one part of the picture.<= /div>

The extra round trip is probably fine given how lo= ng Bitcoin P2P connections live. The DoS angle you flagged might also be sm= aller in option 1, since the responder still commits after 64 bytes and not= after a 1184-byte ML-KEM key,... though I haven't thought hard about wethe= r there are other DoS vectors the inner upgrade introduces.

<= /div>
On Ethan's TLS 1.3 suggestionm,... I don't think it really fits. = Apart from the dependency cost (which we deliberately kept low in BIP 324),= TLS has it's own fingerprint, which would probably undo the censorship-res= istance angle. And it bundles authentication with encryption, which we expl= icitly decoupled.

One thing worth looking at: Open= SSH (whose chacha20-poly1305 construction we drew from originally) shipped = mlkem768x25519-sha256 as default in 10.0 last year, and they just concatena= te-and-hash the two shared secrets. Their threat model doesn't care about p= seudorandomness so they can send ML-KEM material in the clear, but the comb= iner shape is probably a reasonable reference for ours.

/jonas

On May 6, 2026, a= t 12:15=E2=80=AFPM, Olaoluwa Osuntokun <laolu32@gmail.com> wrote:
Hi Ethan, 

That's a great question. 

First, I don't speak for Bitcoin Co= re by any means (btcd has also implemented
BIP 324 FWIW). Based on past = observed behavior, they typically prefer to keep
dependencies slim. Many= years ago there was a concerted push to remove openssl
as a dependency = from the project. So I would imagine the idea of rolling out
full blown = TLS 1.3 might encounter some resistance.

In terms of cryptography, B= IP 324 as defined uses secp256k1. TLS 1.3 as
specified doesn't support s= ecp256k1 within the set of supported cipher suites.

If ensuring that= BIP 324 continues to implement an oblivious KEM is a key
requirement, t= hen TLS 1.3 doesn't fit the bill.

Regarding a hybrid PQ KEM, there e= xists an IETF to add a new key agreement
suite to TLS 1.3: https://datatracker.ietf.org/doc/draft-i= etf-tls-ecdhe-mlkem/.
Only secp256+384(r1) and x25519 are supported = as elliptic curves in this draft.

One additional aspect is that toda= y BIP 324 doesn't implement authentication at
all, you only get confiden= tiality. TLS 1.3 would mean introducing certificates
in some fashion, th= ereby coupling concerns from the original PoV of Bip 324.

BIP 324 al= so includes as section in the BIP detailing the rationale of BIP 324
ove= r a more general purpose protocol (mentions some of the points above):
<= a href=3D"https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#:~= :text=3DWhy%20not%20use%20a%20general%2Dpurpose%20transport%20encryption%20= protocol%3F">https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki= #:~:text=3DWhy%20not%20use%20a%20general%2Dpurpose%20transport%20encryption= %20protocol%3F.


-- Laolu



On Tue, May 5, 2026 at 2:18= =E2=80=AFPM Ethan Heilman <eth3rs@gm= ail.com> wrote:
Thanks Laolu for thinking through making PQ BIP 324 an= d writing this up.

Reading through what you wrote made me what wonde= r, why not use this as an opportunity to move to TLS 1.3?

What's the= case against using TLS 1.3 for PQ P2P connection encryption? Is there some= functionality that TLS 1.3 is lacking that we really want?  Is the ca= se against solely to not have TLS 1.3 as a complex dependency in bitcoin-co= re?

The advantages of TLS 1.3:=

1. Make Bitcoin P2P con= nections blend in with all the other TLS connections. This isn't strong pri= vacy, you can distinguish TLS encrypted Bitcoin traffic via timing and size= , but it reduces accidents where a firewall sees an unknown protocol and bl= ocks it.

2. Use of QUIC = for faster relay, oblivious HTTP and QUIC tunnels-in-tunnels for private re= lay and similar protocols.

3. Lots of eyeballs on TLS 1.3= , we don't need to build or maintain it.


On Tue, May 5, 202= 6, 00:41 Olaoluwa Osuntokun <laolu32@gmail.com> wrote:
Hi y'all,&nb= sp;

In case you weren't already tired of all the recent dev l= ist chatter re post
quantum cryptography, here's another!

When th= e topic of Bitcoin transitioning to a post quantum world is brought up,
= the discussion typically focuses on the consensus layer re swapping out
= vulnerable signature schemes. However, the consensus layer isn't the only a= rea
of Bitcoin that relies in cryptography that would be broken in the f= ace of a
powerful quantum computer! That's right, I'm talking about BIP = 324, the peer to
peer encryption BIP for Bitcoin.

Like everything= else on the Internet today, BIP 324 uses ECDH to allow two
connecting p= eers to derive a shared secret known only to them, which is then
used to= encrypt all traffic between them. As ECDH relies on Elliptic Curve
cryp= tography, a future quantum computer would be able to eavesdrop on a p2p
= handshake transcript, then derive the underlying private keys to the epheme= ral
ECDH public key, permitting it to decrypt all traffic. It's actually= worse than
that, as today adversaries can collect all encrypted p2p Bit= coin traffic, with
the hope of being able to decrypt it all at a future = date. This is commonly
referred to as the: "harvest, decrypt later" (HND= L) strategy [11].

Compared to a consensus change, which requires wid= espread market agreement, and
coordination to achieve, upgrading BIP 324= to be post quantum resistant is a
much lower hanging fruit worthy of pu= rsing immediately.

Last week I starting thinking a bit about this to= pic, brushing up on the latest
literature/techniques, and stumbled onto = a few key design questions. The goal
of this post isn't to propose a new= concrete p2p encryption BIP, instead I want
to start discussion on the = various design tradeoffs that came up as I was
researching this p2p encr= yption transition.

## PQ BIP 324 Design Questions

1. Do we wa= nt to pursue a hybrid KEM (key encapsulation mechanism), or go with
&nbs= p;  a pure PQ KEM?

2. Is it still a key requirement that the in= itial handshake be
   indistinguishable from a random byte str= ing?

   2a. If yes to the above, then should we go with cl= assical-then-pq-upgrade,
   or a one shot hybrid oblivious KEM= .


## A Brief Intro to KEMs + ML-KEM

First, let's introduc= e the new primitive we have to work with: ML-KEM
(Module-Lattice-Based K= ey-Encapsulation Mechanism) [1][2]. As it says on the
tin, ML-KEM is a l= attice based Key-Encapsulation Mechanism. The phrase KEM
might sound unf= amiliar with those comfortable with ECDH, but ECDH is actually a
KEM its= elf.

A KEM has 3 algorithms:
  * KeyGen() -> {sk, pk}
     * Gen= erates a public/private secret key pair

  * Encaps(pub) -> {secret, capsule}
 = ;    * Generates a new secret value, and a "capsule", which only = the holder of
       pub can use to obtain the secre= t value.

  * = Decaps(priv, capsule) -> secret
     * Uses the privat= e key to extract the secret from the capsule


If you squint a bit= , then you'll see that ECDH is a KEM, and a rather elegant
one at that:<= br>  * KeyGen() ->= ; {k, k*G}
     &nb= sp;* Normal EC key generation.=  

  * Encaps(pub) -> {capsule =3D x*G, secret =3D pub*x}
   =   * The core ECDH r= outine. The ephemeral public key is actually the
      &n= bsp; "capsule". The resul= ting secret is the ECDH output with the remote
      &nbs= p; party's KEM public key= and the local secret.

 &= nbsp;* Decaps(priv, capsule) -> secret =3D priv * capsule
&nbs= p;     * The re= ceiver completes the key exchange using the ephemeral public key
  =       and = their own private key.

ECIES is another flavor of EC based KEM.
<= br>One thing worth noting is that AFAICT, so far in the NIST PQC world [4],= there is
no known non-interactive key exchange protocol like we enjoy t= oday with ECDH.
IIUC, the reason is that lattice based schemes derived f= rom the LWE [3]
problem, whose security is predicated on using "noise" t= o hide a secret value.
For these cryptosystems, usually a type of "hint"= is sent to make everything
work out nicely like in ECDH. However, in th= e stricter non-interactive setting
(no messages sent), this doesn't map = cleanly.

As a result, ML-KEM looks more like a hybrid encryption pro= tocol (Alice
encrypts a shared secret to bob using asymmetric lattice cr= ypto).

## To Hybrid KEM, Or Not to Hybrid KEM

This brings us = to our first design question....

Should we use a hybrid KEM or a pur= e post quantum one? 
<= br>A hybrid KEM would keep the existing ECDH, _also_ do ML-KEM, then secure= ly
combine (there's some subtlety there, see [6][7]) the resulting in a<= br>final secret value for encryption. A hybrid KEM is attractive as an encr= yption
channel derived from such a KEM is secure if _any_ of the combine= d schemes are
secure. This permits schemes to hedge a bit, as hey, maybe= the PQ stuff is
actually broken in the future but ECDH isn't. If it's t= he other way around,
then your encryption scheme is still secure.
### Pure ML-KEM P2P Encrypted Handshake

If we opt to not use a hybr= id scheme, then the Elligator layer can be dropped
all together. Instead= , the 1.1 KB (ML-KEM-768) encapsulation keys are sent,
keeping the trail= ing garbage+terminator in tact. =

The initial handshake would look something like: 
 * Alice -> Bob: alice_= encaps || initiator_garbage
    * Alice derives an encapsulation key, and sends it to B= ob.

 * Bob -> Alice: ml_kem_capsule || responder_garbage || = responder_garbage_terminator || first_encrypted_packet
   * Bo= b uses Alice's encapsulation key to encapsulate a random secret, and
&nb= sp;    sends it over to Alice. He can also encrypt the first mess= age at this
     point.

 * Alice -> Bob: i= nitiator_garbage_terminator || first_encrypted_packet
   * Ali= ce de-encapsulates the shared secret, and can now also start to encrypt
=      messages.

We'd then replace `v2_ecdh` with somet= hing like a `v3_mlkem` that derives the
final shared secret based on the= sent/received transcript up until that point:
  * `sha256_tagged("bip324_ml_kem", ml_kem_se= cret, alice_encaps, ml_kem_capsule)`

### Hybrid ML-KEM P2P Encrypted= Handshake

If we want to use a hybrid combiner, then along side the = normal ellswift keys,
the ML-KEM-768 encap key is also sent:

&nbs= p;* Alice -> Bob: ellswift_alice || alice_encaps || initiator_garbage * Bob -> Alice: ellswift_bob || ml_kem_capsule || responder_garba= ge || responder_garbage_terminator || first_encrypted_packet
 * Ali= ce -> Bob: initiator_garbage_terminator || first_encrypted_packet
Then following guidelines of [7], we'd then replace `v2_ecdh` with somethi= ng
like `v3_hybrid_shared_secret`:
  * `sha256_tagged("bip324_ellswift_xonly_ecdh_mlkem_7= 68", ml_kem_ss, ecdh_point_x32, alice_encaps, ml_kem_capsule, ellswift_alic= e, ellswift_bob)`

## PQ/Hybrid Obfuscated KEMs

At this point,= those that are familiar with BIP 324 will recognize that both
the pure = PQ and hybrid versions renders the ElligatorSwift usage pretty much
usel= ess. ElligatorSwift encodes a 32-byte public key as a 64-byte value whichis indistinguishable from a uniformly distributed bitstream. In a bubble,= this
means that the initial BIP 324 handshake to a 3rd party observer j= ust looks
like random bytes. However, with the introduction of ML-KEM, t= he ML-KEM
encapsulation key is sent in plaintext over the wire. An ML-KE= M key has
identifiable structure, as it's a giant vector of polynomial c= oefficients mod
3329, which is easily recognizable over the wire.
Luckily, there's an ML-KEM analogue to ElligatorSwift, called Kemeleon
= [8][9][10]! In a similar fashion to ElligatorSwift, it takes an ML-KEM publ= ic
key, then encodes it as one giant integer, utilizing rejection sampli= ng.
Kemeleon applies this mapping both to the encapsulation keys, and al= so the
capsule ciphertext that encrypts the shared secrets. The ML-KEM k= eys end up
being a bit smaller, while the ciphertexts map to a larger va= lue. Another
tradeoff is that the Kemeleon key generation is ~3x slower = than normal ML-KEM
generation.

One thing to note here is that Kem= eleon's "looks random" property isn't quite
on the same footing as Ellig= atorSwift's. ElligatorSwift is statistically
indistinguishable from rand= om, since every 512-bit string is a valid encoding.
Kemeleon's indisting= uishability is computational, resting on a Module-LWE
style assumption. = So if you naively concatenate an ElligatorSwift key and a
Kemeleon key, = the pair is only as obfuscated as the weakest visible half. This
asymmet= ry is what motivates the OEINC construction discussed below.

This br= ings us to our second design question....

Do we still want to ensure= that the BIP-324 handshake looks identical to a
pseudorandom bytestream= from the very first message?

Assuming yes, then AFAICT, we have two= classes of options here: 
  1. Retain the= existing BIP-324 outer ElligatorSwift handshake, but use ML-KEM
  =    within that initial encrypted transport to upgrade to a PQ sha= red secret.

  2. Use the Outer Encrypts Inner Nested Combiner (OEINC - "OINK") combiner<= br>     from [8].

  3. Attempt to adapt Drivel from [8] into the Bitcoin = p2p setting.

### Classical Encrypted Channel Upgrades to PQ

W= ith the first option, we simply use one KEM right after the other. So BIP 3= 24
v2 would be mostly unchanged, then we _upgrade_ to BIP 324 v3 within = v2. 

A sketch of t= his would be something like:
  * Phase 0: normal BIP 324 handshake
  * Phase 1: negotiation of PQ KEM scheme = over the encrypted handshake
     * Can be optional, if w= e just pick a set PQ KEM scheme.
     * Before this point= , no Bitcoin p2p message should be sent, as the channel
    &n= bsp;  isn't PQC protected yet.
  * Phase 2: do normal ML-KEM within the ElligatorSwift = derived encrypted
   &nb= sp;transport
     1. Alice sends the encapsulation= key
     2. Bob derives a secrets, encrypts it using the= encapsulation key
     3. Both sides then derive a PQ sh= ared secret, ss_PQ
  * Phase 3: both sides use a hybrid combiner like sketched out above to = derive
    a= new set of transport keys
 &= nbsp;* Phase 4: both sides rekey, switching over to a new the transp= ort keys

The upside of this option is that the outer part of BIP 324= remains unchanged,
then with another round trip, we're able to upgrade = the encryption keys to PQ
hybrid security. The downside is that the very= first messages sent aren't PQ
from the start, but a PQ adversary wouldn= 't be able to decrypt the actual
Bitcoin p2p messages (as we wait to sen= d those until the upgrade). The
handshake still looks like just random b= ytes.

### Outer Encrypts Inner Nested Combiner

For the second= option, [8] (with talk video [9] and slides [10]) describes an
OEINC sc= heme where the outer KEM
encrypts the inner KEM, wherein the KEM ciphert= ext of an inner KEM is encrypted
using a shared secret derived from the = outer KEM. The two KEM ciphertexts and
the two derived keys are then use= d alongside a hybrid combiner to derive a
final shared secret. 

Unlike the classical-then-= pq-upgrade that establishes a classical channel, then
uses that to upgra= de to pq channel, OEINC is a special hybrid combiner that
achieves a sim= ilar output but in one swoop. It defines a special KEM, which can
then b= e used as the KEM in the very first handshake I sketched out.

A sket= ch of this KEM looks something like:
  * Setup:
    * The outer KEM is BIP 324's ElligatorSwift-encoded = secp256k1 DHKEM.
       * It serves as the outer KEM= because its on-wire encoding is
         stati= stically indistinguishable from random.
    * The inner KEM is ML-Kemeleon.

&nbs= p; * KeyGen():
  =   * (kem_secret_oute= r, kem_pubkey_outer) =3D outKEM.Gen()
    * (kem_secret_inner, kem_pubkey_inner) =3D in= KEM.Gen()
    * combined_pubkey =3D (kem_pubkey_outer, kem_pubkey_inner)
  &nbs= p; * combined_secret =3D = (kem_secret_outer, kem_secret_inner)

  * Encaps(combined_pubkey):
    * (shared_secret_outer, capsul= e_outer) =3D outKEM.Encap(kem_pubkey_outer)
    * (encrypt_key_1, encrypt_key_2) =3D KD= F(shared_secret_outer)
    * (shared_secret_inner, capsule_inner) =3D inKEM.Encap(kem_p= ubkey_inner)
    * encrypted_capsule_inner =3D encrypt(encrypt_key_1, capsule_inner)    * combined= _capsule =3D capsule_outer || encrypted_capsule_inner
    
* combined_shared_secret =3D = combine(encrypt_key_2, shared_secret_inner, combined_capsule)

 =  * Decaps(combined_secret= , combined_capsule):
   =  * (capsule_outer, encrypted_capsule_inner) =3D combined_capsul= e
    * shar= ed_secret_outer =3D outKEM.Decaps(kem_secret_outer, capsule_outer)
 = ;   * (encrypt_key_1= , encrypt_key_2) =3D KDF(shared_secret_outer)
    * capsule_inner =3D decrypt(encrypt= _key_1, encrypted_capsule_inner)
    * shared_secret_inner =3D inKEM.Decaps(kem_secret_= inner, capsule_inner)
    * combined_shared_secret =3D combine(encrypt_key_2, shared_se= cret_inner, combined_capsule)


This is done over just sending the= two encapsulated secrets plainly as I
outlined above in order to achiev= e a stronger security notion. The issue with
this though is that though = ciphertext uniformity (the encapsulated secrets) is
achieved, the two pu= blic keys sent are randomly looking, but not in a uniform
manner. In pra= ctice, this might not really matter much AFAICT (a theoretical
adversary= would be able to distinguish the Elligator half from the Kemeleon
half)= .

### Drivel: PQ-Obfuscated Authentication

The biggest issue = with Drivel as a fit for BIP 324 is that it expects the
initiator to alr= eady know a long term static public key for the responder. In
the case o= f BIP 324, only ephemeral keys are exchanged, so there's no long
term pu= blic keys known to either side.

To get around this, we could extend = BIP 155 (or make a new one likely, given
size limits) to include a signe= d OKEM key. However then that would introduce
authentication into the co= mbined set, which explicitly wasn't a design goal
of BIP 324.

Wit= h that caveat in mind, here's the construction itself. Drivel [8] combines<= br>the OEINC scheme with another layer that out-of-the-box assumes an asymm= etric
protocol within a set client and server. The client uses an existi= ng OEINC
KEM public key published by the server to then encrypt a fresh = new ephemeral
KEM.

-----&nb= sp;

So there we have it. Before drafting a concrete v3 transp= ort, we need to
decide if we want a hybrid KEM, or are fine with a pure = PQ KEM. Then we need to
decide if we want to attempt to maintain the cur= rent quality where the p2p
handshake transcript is indistinguishable fro= m random. If yes, then that forces
another series of decisions re how to= construct/compose an oblivious KEM from
available primitives.

At= a glance, the route of classical-then-pq-upgrade seems to be the simplest.=
BIP 324 stays as is, then we run ML-KEM within that. The ML-KEM keys ar= e
encrypted, so there's no need to sprinkle in the layer of Kemeleon.
If we want a nice combined protocol, then we should investigate the OE= INC
route. It's more data to send as part of the initial handshake, but = we still
keep ElligatorSwift and use that as the outer KEM.

If fo= r some reason we're concerned with a future adversary gaining a
distingu= isher for Kemeleon, then maybe we need to bite the bullet and also
roll = out a full blown PQ authentication protocol along side everything.

O= ne thing worth flagging for any of the byte-0 designs (where PQ material is=
sent in the clear on the very first flight, like the hybrid and OEINC s= ketches
above): ML-KEM-768 makes the responder do real work before it ca= n decide if a
connection is even legit. Today, the responder only needs = the first 64 bytes
of an ElligatorSwift share before it can derive the s= hared secret. With
ML-KEM-768, the responder has to read and validate a = 1184 byte encapsulation
key before running Encaps, and FIPS 203 mandates= input checks on every Encaps
and Decaps. In a permissionless P2P networ= k, that's a meaningful change in
inbound DoS surface, and probably calls= for stricter handshake byte limits,
tighter timeouts, and possibly some= form of stateless cookie/puzzle if
handshake floods become a real probl= em. The classical-then-pq-upgrade path
sidesteps most of this since the = PQ material only shows up after the v2
channel is up.

With all th= at said, after the above design decisions are addressed, there
aren't to= o many concrete blockers here w.r.t rolling this out. Of course the
deve= lopment (eg: selecting/creating a library for ML-KEM and maybe
ML-Kemele= on), and upgrade will take some time. But unlike the consensus
layer, p2= p encryption doesn't require the widespread market agreement that an
act= ual soft fork does. BIP 324 is a much shorter walk to PQ than the consensus=
layer, and serves as a sort of PQ warm up before the bigger soft fork i= s
tackled. 


-- Laolu

[1]: https://en.wikipedia.org/wiki/ML-KEM<= /a>
[2]: 
https://csrc.nist.gov/pubs/fips/203/final
[3]: https://en.wikiped= ia.org/wiki/Learning_with_errors
[4]: This statement ignores Isogeny= based crypto, and also SWOOSH [5] as it requires 200 KB pubkeys
[5]: 
https://eprint.iacr.= org/2023/271
[6]: = https://eprint.iacr.org/2018/024
[7]: https://eprint.iacr.org/2020/1364[8]: https://epr= int.iacr.org/2024/1086
[9]:&nb= sp;https://www.youtube.com/watch?v=3DCvFCYUq5rGg=
[10]: https://csrc.nist.gov/csr= c/media/Presentations/2025/kemeleon/images-media/kemeleon.pdf
[11]:<= span class=3D"Apple-converted-space"> 
https://en.wikipedia.org/wiki/Harvest_now,_decrypt_later

-- 
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 discussi= on visit https://groups.google.com/d/msgid/b= itcoindev/CAO3Pvs9U3prZJiDs0Ns7LSA07R8hM-GQou_FcTZZz-JUQpUYHw%40mail.gmail.= com.

-- 
You received this mes= sage because you are subscribed to the Google Groups "Bitcoin Development M= ailing 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&nb= sp;https://groups.google.com/d/msgid= /bitcoindev/CAO3Pvs8i%3DpLP30nRh_iyjSRJXne19wNezmQmo%3DJAk8%2BE4uJPhg%40mai= l.gmail.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/547AD= FCA-2BB1-4E16-A26A-C92262EBBD84%40gmail.com.
--Apple-Mail=_254B20D0-F06A-456B-A09A-C2CF54EBE9CD--