summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author/dev /fd0 <alicexbtong@gmail.com>2024-12-21 15:03:32 -0800
committerbitcoindev <bitcoindev@googlegroups.com>2024-12-21 15:26:01 -0800
commitb390d970fea22134a3e1e2e356cded5599a590d5 (patch)
tree2c714319f794ef0432f939b09c4c7d5cdfc3723e
parentf54d666183c9f233b395a7a85e1bf1fdeb15deca (diff)
downloadpi-bitcoindev-master.tar.gz
pi-bitcoindev-master.zip
Re: [bitcoindev] Censorship and Privacy in Chaumian ecash implementationsHEADmaster
-rw-r--r--a2/5ccd9f2ed04e6bbc5df4c212e67938bc276315831
1 files changed, 831 insertions, 0 deletions
diff --git a/a2/5ccd9f2ed04e6bbc5df4c212e67938bc276315 b/a2/5ccd9f2ed04e6bbc5df4c212e67938bc276315
new file mode 100644
index 000000000..9c36d6044
--- /dev/null
+++ b/a2/5ccd9f2ed04e6bbc5df4c212e67938bc276315
@@ -0,0 +1,831 @@
+Delivery-date: Sat, 21 Dec 2024 15:26:01 -0800
+Received: from mail-yw1-f184.google.com ([209.85.128.184])
+ by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ (Exim 4.94.2)
+ (envelope-from <bitcoindev+bncBCU2P6FJ3EBBB7U4TW5QMGQE3SLVLGA@googlegroups.com>)
+ id 1tP8r9-0000U8-Fl
+ for bitcoindev@gnusha.org; Sat, 21 Dec 2024 15:26:01 -0800
+Received: by mail-yw1-f184.google.com with SMTP id 00721157ae682-6eeeb850458sf24256377b3.2
+ for <bitcoindev@gnusha.org>; Sat, 21 Dec 2024 15:25:59 -0800 (PST)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=googlegroups.com; s=20230601; t=1734823553; x=1735428353; darn=gnusha.org;
+ h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post
+ :list-id:mailing-list:precedence:x-original-sender:mime-version
+ :subject:references:in-reply-to:message-id:to:from:date:sender:from
+ :to:cc:subject:date:message-id:reply-to;
+ bh=9Vge0CgLz9kxIYtlbiO/kZOsZdvfWhRleoTgTZt1vjw=;
+ b=j6bjE6HkXyO0vXSo4KhuojE0WBir63XC4IAxHjUbho+arULnH8qzQBK8a/SIxEs/3V
+ RY1JOq8JBlGhGtnMUiElAE8+JCYBH9c6I/AiD+aKWs9yfJBEl2i+Pv1FKVgKUCAs4wNJ
+ HTkYH4KtiAaqna3J5NbUF2iz6fPPATgfU4+k8+kjp6mjrrpAVNfYaF/0obR34Ojo+gwb
+ MguUz43D/7kSJI8HaM+fu+uDKPDs7PF8s+1UktHGBW379Ga2NQCsxn+0QWQjY9/vuroP
+ wRFrIxeWoBrgc8ljNl37XsoGtAsH2v0S2NGvp4ZNyo5nAs12itslDG83ddc9lzmM38QF
+ cAeg==
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=gmail.com; s=20230601; t=1734823553; x=1735428353; darn=gnusha.org;
+ h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post
+ :list-id:mailing-list:precedence:x-original-sender:mime-version
+ :subject:references:in-reply-to:message-id:to:from:date:from:to:cc
+ :subject:date:message-id:reply-to;
+ bh=9Vge0CgLz9kxIYtlbiO/kZOsZdvfWhRleoTgTZt1vjw=;
+ b=C0bOGR3osVbh+lDBtRvWjbXlds56QmHCLiTwmNiFC3ayLi7PsMJTi7/xM0Vo4qkoCu
+ AfMVq+S1ZOxIM83gbFyluPviyGSCqWLVvYbMPw+WA6mKdEMkBA3xpEk5PuK5ZGK/287s
+ 5jetoAdv24aHUH1MypLoOHQkNjDIvOlJE5fXIRk6bt42CNdQvg48HkoQEbRUoWu2L825
+ YrYHSIzXkot9ywLXpvCBXvl/Z+VIsdnOBLbaAOP1DtQdVYGc+++6q/OtPObaXEsCcdzu
+ Bc0ahxv/qrqbYkhthsgA3hL1fLOwd1mmpYtf6vPgIWAB9m59pSjBOH3n4s5Vuyrg7QhP
+ 90QA==
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=1e100.net; s=20230601; t=1734823553; x=1735428353;
+ h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post
+ :list-id:mailing-list:precedence:x-original-sender:mime-version
+ :subject:references:in-reply-to:message-id:to:from:date:x-beenthere
+ :x-gm-message-state:sender:from:to:cc:subject:date:message-id
+ :reply-to;
+ bh=9Vge0CgLz9kxIYtlbiO/kZOsZdvfWhRleoTgTZt1vjw=;
+ b=K0htrNkuxVglvu8tlDVxkBNAkg9NzNU/nCi1GfbwLUzDUeYP53c4a+vGI1zMvCTxxP
+ 4Wr09c5T/R0oRTqTKb9g80bwsJKN/paFdcPTC3L1TbPdgRHqOE0SgN1WsV8oBvmPb8Rg
+ fkyRgveSnJt7IhwZJWl+wXBsDxj0yWSVosOUjhWXLDEMsStA0qFWQVoRFxrtm5Lt+99X
+ AjjzxDTBBfTpu50Uvd1jC/17PlkY4iAkIL7olwGpE3Y/ald22tHo7NSdT5bbNkf2gSxE
+ TfbaPYGHzMfZ7w61AaK5qGHBkLlgr+BneapkPPZU1lvEUOqMg38Sj+/o8Jxs4a5nUpso
+ 4HXw==
+Sender: bitcoindev@googlegroups.com
+X-Forwarded-Encrypted: i=1; AJvYcCVEmMwTLkh7rGVStBYkkqXFDz8+nWWLBWJleb8xLebZrR6lCB6OGAYbRHL2mCDfBjRuYtVmlnCznmjW@gnusha.org
+X-Gm-Message-State: AOJu0Yx53R2FMuvOlOUTz9VT+8bI706F3yfGlny2uCARxjexfAHKnsFl
+ j2eK71TSlNPX6fZC9D+O/dwW+SzkVfRgKXzoQp2T9aibAoYr4taN
+X-Google-Smtp-Source: AGHT+IHknBD48PsCQR70cOFSsieq4U9baH2oSaUSStC+o8cmXcCRCxVRzJdpMu+fW5IwWH3G+XBzxw==
+X-Received: by 2002:a05:6902:10ce:b0:e39:80cd:cac1 with SMTP id 3f1490d57ef6-e538c40245bmr6320300276.49.1734823552664;
+ Sat, 21 Dec 2024 15:25:52 -0800 (PST)
+X-BeenThere: bitcoindev@googlegroups.com
+Received: by 2002:a25:ad4f:0:b0:e30:e1d9:fe2c with SMTP id 3f1490d57ef6-e5375fdb21dls536144276.1.-pod-prod-03-us;
+ Sat, 21 Dec 2024 15:25:50 -0800 (PST)
+X-Received: by 2002:a05:690c:4986:b0:6ee:6c7d:4888 with SMTP id 00721157ae682-6f3f8144f76mr65359887b3.22.1734823550019;
+ Sat, 21 Dec 2024 15:25:50 -0800 (PST)
+Received: by 2002:a0d:d202:0:b0:6ef:7d10:5a2f with SMTP id 00721157ae682-6f3f56f322bms7b3;
+ Sat, 21 Dec 2024 15:03:34 -0800 (PST)
+X-Received: by 2002:a05:690c:620c:b0:6ee:65ae:2184 with SMTP id 00721157ae682-6f3f8239147mr63264727b3.37.1734822213374;
+ Sat, 21 Dec 2024 15:03:33 -0800 (PST)
+Date: Sat, 21 Dec 2024 15:03:32 -0800 (PST)
+From: /dev /fd0 <alicexbtong@gmail.com>
+To: Bitcoin Development Mailing List <bitcoindev@googlegroups.com>
+Message-Id: <51eb0cc8-c9e0-4a50-9928-461f5f13264en@googlegroups.com>
+In-Reply-To: <-LMvaPkFoIOkgwJOch3qo7y_ueGgiOSJWqdu0gpv3wSHTunca6AB14V-ZiR4IoDcvIkPTdoQeiy_JigGwl0ei2VpBj2tFyK-GFeE2gXZzXE=@proton.me>
+References: <27b19012-20da-46a7-8a84-f90e0070aa77n@googlegroups.com>
+ <-LMvaPkFoIOkgwJOch3qo7y_ueGgiOSJWqdu0gpv3wSHTunca6AB14V-ZiR4IoDcvIkPTdoQeiy_JigGwl0ei2VpBj2tFyK-GFeE2gXZzXE=@proton.me>
+Subject: Re: [bitcoindev] Censorship and Privacy in Chaumian ecash implementations
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="----=_Part_192402_838158198.1734822212929"
+X-Original-Sender: alicexbtong@gmail.com
+Precedence: list
+Mailing-list: list bitcoindev@googlegroups.com; contact bitcoindev+owners@googlegroups.com
+List-ID: <bitcoindev.googlegroups.com>
+X-Google-Group-Id: 786775582512
+List-Post: <https://groups.google.com/group/bitcoindev/post>, <mailto:bitcoindev@googlegroups.com>
+List-Help: <https://groups.google.com/support/>, <mailto:bitcoindev+help@googlegroups.com>
+List-Archive: <https://groups.google.com/group/bitcoindev
+List-Subscribe: <https://groups.google.com/group/bitcoindev/subscribe>, <mailto:bitcoindev+subscribe@googlegroups.com>
+List-Unsubscribe: <mailto:googlegroups-manage+786775582512+unsubscribe@googlegroups.com>,
+ <https://groups.google.com/group/bitcoindev/subscribe>
+X-Spam-Score: -0.5 (/)
+
+------=_Part_192402_838158198.1734822212929
+Content-Type: multipart/alternative;
+ boundary="----=_Part_192403_1051169886.1734822212929"
+
+------=_Part_192403_1051169886.1734822212929
+Content-Type: text/plain; charset="UTF-8"
+Content-Transfer-Encoding: quoted-printable
+
+Hi conduition,
+
+> For P2PK, the solution there seems deadly obvious: Just don't use raw=20
+unobfuscated Nostr keys to receive ecash. Tweak it, or use a new random=20
+key. This is a non-issue
+
+This is an issue at present. I hope you fix it as you seem to be=20
+[involved][1] in cashu development. The workarounds that you suggested will=
+=20
+still allow a **specific** key to be censored.
+
+> As for authentication systems, yes of course KYC-backed authentication=
+=20
+would allow censorship, but that is an optional spec which mints aren't=20
+compelled to implement or use, even once the spec is finished. AFAIK no=20
+mint implementations have this system in code yet, so it's not even a=20
+feature at this point: just a proposed NUT document, sitting in draft=20
+status. Your assertion that "none of the ecash implementation are=20
+censorship resistant" is a blatantly false statement bereft of fact or=20
+depth.
+
+Being optional does not matter. It is **possible** for a mint to use=20
+authentication which is the whole point of this mailing list post. It is=20
+true that none of the ecash implementations are censorship resistant. Just=
+=20
+because censorship isn't implemented yet by mints does not mean the=20
+protocol is censorship resistant.
+
+The false statements exist in cashu docs with misleading things about=20
+censorship resistance.
+
+> At worst they might lose the money they already stored with the=20
+compromised mint, which is always a risk to keep in mind with ecash.
+
+This is already described in my post.
+
+> So ecash devs have proposed standardized auth systems which would give=
+=20
+mint runners the *option* of knuckling under to KYC. I agree it would suck=
+=20
+to be put to that choice, but giving them the freedom to choose is=20
+important and valid, and in no way compromises the integrity of other=20
+non-KYC mints who perhaps operate freely in more enlightened jurisdictions.=
+=20
+
+Standardizing KYC in the protocol is the opposite of freedom and privacy.=
+=20
+Jurisdictions do not matter if a mint is large enough to be attacked by the=
+=20
+government agencies. There are enough examples for it.
+
+> If it's not part of the NUT standards, and mint runners need it, then=20
+someone will just fork off and add it themselves. Better to pre-empt that=
+=20
+and keep the standards from fragmenting - that's the point of standards.=20
+
+There are ways to avoid any kind of authentication and KYC in the protocol.=
+=20
+If someone still forks then it won't remain cashu protocol. However, I=20
+won't waste my time explaining it because the goal seem to be helping=20
+regulated entities to use cashu.
+
+[1]: https://conduition.io/cryptography/ecash-dlc/
+
+/dev/fd0
+floppy disk guy
+
+On Sunday, December 22, 2024 at 3:34:17=E2=80=AFAM UTC+5:30 conduition wrot=
+e:
+
+> Hi fd0,
+>
+> For P2PK, the solution there seems deadly obvious: Just don't use raw=20
+> unobfuscated Nostr keys to receive ecash. Tweak it, or use a new random=
+=20
+> key. This is a non-issue.
+>
+> As for authentication systems, yes of course KYC-backed authentication=20
+> would allow censorship, but that is an optional spec which mints aren't=
+=20
+> compelled to implement or use, even once the spec is finished. AFAIK no=
+=20
+> mint implementations have this system in code yet, so it's not even a=20
+> feature at this point: just a proposed NUT document, sitting in draft=20
+> status. Your assertion that "none of the ecash implementation are=20
+> censorship resistant" is a blatantly false statement bereft of fact or=20
+> depth.
+>
+> Even if we fast forward several years when perhaps *some* ecash mint=20
+> implementations do implement the authentication spec as a fully-formed=20
+> feature ready to go... If a mint starts enforcing KYC, or any other badne=
+ss=20
+> like censoring by IP address, users are free to switch to a different=20
+> non-KYC mint instance. At worst they might lose the money they already=20
+> stored with the compromised mint, which is always a risk to keep in mind=
+=20
+> with ecash.
+>
+> Your argument seems to be that introducing an opt-in feature spec like=20
+> external authentication is inherently bad because it encourages/enables K=
+YC=20
+> in the first place, and that ecash devs should refuse to even standardize=
+=20
+> any protocol which enables KYC.=20
+>
+> Well I have hard news for you: Governments don't care about whether=20
+> compliance is "easy" or "standardized". If uncle sam wants your mint to=
+=20
+> enforce KYC, he won't balk just because the mint's code doesn't provide a=
+n=20
+> easy way to do it. He'll give you a deadline to enforce KYC on your users=
+,=20
+> and if you can't prove you're compliant by then, you can kiss your busine=
+ss=20
+> goodbye.
+>
+> When faced with this choice, the ecash mint runner can either shut down=
+=20
+> their mint, or add KYC. Without an authentication system in place already=
+,=20
+> the mint runner would have to implement it all themselves to enforce KYC=
+=20
+> and stay in business. So ecash devs have proposed standardized auth syste=
+ms=20
+> which would give mint runners the *option* of knuckling under to KYC. I=
+=20
+> agree it would suck to be put to that choice, but giving them the freedom=
+=20
+> to choose is important and valid, and in no way compromises the integrity=
+=20
+> of other non-KYC mints who perhaps operate freely in more enlightened=20
+> jurisdictions.=20
+>
+> If it's not part of the NUT standards, and mint runners need it, then=20
+> someone will just fork off and add it themselves. Better to pre-empt that=
+=20
+> and keep the standards from fragmenting - that's the point of standards.=
+=20
+>
+> -c
+> On Saturday, December 21st, 2024 at 9:58 AM, /dev /fd0 <alice...@gmail.co=
+m>=20
+> wrote:
+>
+> Hi Bitcoin Developers,
+>
+> This post is about a myth and some misleading things shared about ecash.=
+=20
+> It is possible to censor specific users and none of the ecash=20
+> implementation are censorship resistant.
+>
+> # Censorship Methods in Cashu
+>
+> There are 2 ways to censor individual users in cashu:
+>
+> 1. P2PK
+> 2. Authentication
+>
+> ## P2PK
+>
+> Ecash tokens issued by cashu mints can be locked using public keys so tha=
+t=20
+> it can only be redeemed by the user who owns the private key for it. This=
+=20
+> links ecash with specific public keys and most implementation use nostr=
+=20
+> keys for it. Most users are doxxed on nostr so they can be censored based=
+=20
+> on their identity. Even if its linked to an anon they can be censored bas=
+ed=20
+> on their posts.
+>
+> You can find relevant code snippets in [conditions.py][1] if using=20
+> nutshell for mint:
+>
+> ```python
+> class LedgerSpendingConditions:
+> def _verify_p2pk_spending_conditions(self, proof, secret):
+> if SecretKind(secret.kind) !=3D SecretKind.P2PK:
+> return True
+> p2pk_secret =3D P2PKSecret.from_secret(secret)
+> pubkeys =3D [p2pk_secret.data] + p2pk_secret.tags.get_tag_all("pubkeys")
+> if p2pk_secret.locktime and p2pk_secret.locktime < time.time():
+> refund_pubkeys =3D p2pk_secret.tags.get_tag_all("refund")
+> if not refund_pubkeys:
+> return True
+> return self._verify_secret_signatures(
+> proof, refund_pubkeys, proof.p2pksigs, 1
+> )
+> return self._verify_secret_signatures(
+> proof, pubkeys, proof.p2pksigs, p2pk_secret.n_sigs
+> )
+>
+> def _verify_htlc_spending_conditions(self, proof, secret):
+> if SecretKind(secret.kind) !=3D SecretKind.HTLC:
+> return True
+> htlc_secret =3D HTLCSecret.from_secret(secret)
+> if htlc_secret.locktime and htlc_secret.locktime < time.time():
+> refund_pubkeys =3D htlc_secret.tags.get_tag_all("refund")
+> if refund_pubkeys:
+> return self._verify_secret_signatures(
+> proof, refund_pubkeys, proof.p2pksigs, 1
+> )
+> return True
+> assert proof.htlcpreimage, TransactionError("no HTLC preimage provided")
+> if not hashlib.sha256(bytes.fromhex(proof.htlcpreimage)).digest() =3D=3D=
+=20
+> bytes.fromhex(htlc_secret.data):
+> raise TransactionError("HTLC preimage does not match.")
+> hashlock_pubkeys =3D htlc_secret.tags.get_tag_all("pubkeys")
+> if not hashlock_pubkeys:
+> return True
+> return self._verify_secret_signatures(
+> proof, hashlock_pubkeys, proof.htlcsigs or [], htlc_secret.n_sigs
+> )
+>
+> def _verify_secret_signatures(self, proof, pubkeys, signatures,=20
+> n_sigs_required=3D1):
+> assert len(set(pubkeys)) =3D=3D len(pubkeys), "pubkeys must be unique."
+> if not signatures:
+> raise TransactionError("no signatures in proof.")
+> if len(set(signatures)) !=3D len(signatures):
+> raise TransactionError("signatures must be unique.")
+> n_sigs_required =3D n_sigs_required or 1
+> assert n_sigs_required > 0, "n_sigs must be positive."
+> assert len(signatures) >=3D n_sigs_required, f"not enough signatures=20
+> provided: {len(signatures)} < {n_sigs_required}."
+> n_valid_sigs_per_output =3D 0
+> for input_sig in signatures:
+> for pubkey in pubkeys:
+> if verify_schnorr_signature(
+> message=3Dproof.secret.encode("utf-8"),
+> pubkey=3DPublicKey(bytes.fromhex(pubkey), raw=3DTrue),
+> signature=3Dbytes.fromhex(input_sig),
+> ):
+> n_valid_sigs_per_output +=3D 1
+> assert n_valid_sigs_per_output, "no valid signature provided for input."
+> assert n_valid_sigs_per_output >=3D n_sigs_required, f"signature threshol=
+d=20
+> not met. {n_valid_sigs_per_output} < {n_sigs_required}."
+> return True
+>
+> def _verify_input_spending_conditions(self, proof):
+> try:
+> secret =3D Secret.deserialize(proof.secret)
+> except Exception:
+> return True
+> if SecretKind(secret.kind) =3D=3D SecretKind.P2PK:
+> return self._verify_p2pk_spending_conditions(proof, secret)
+> if SecretKind(secret.kind) =3D=3D SecretKind.HTLC:
+> return self._verify_htlc_spending_conditions(proof, secret)
+> return True
+>
+> def _verify_output_p2pk_spending_conditions(self, proofs, outputs):
+> try:
+> secrets_generic =3D [Secret.deserialize(p.secret) for p in proofs]
+> p2pk_secrets =3D [P2PKSecret.from_secret(secret) for secret in=20
+> secrets_generic]
+> except Exception:
+> return True
+> if not all([SecretKind(secret.kind) =3D=3D SecretKind.P2PK for secret in=
+=20
+> p2pk_secrets]):
+> return True
+> if not all([secret.sigflag =3D=3D SigFlags.SIG_ALL for secret in=20
+> p2pk_secrets]):
+> return True
+> pubkeys_per_proof =3D [
+> [p2pk_secret.data] + p2pk_secret.tags.get_tag_all("pubkeys")
+> for p2pk_secret in p2pk_secrets
+> ]
+> n_sigs_per_proof =3D [p2pk_secret.n_sigs for p2pk_secret in p2pk_secrets]
+> for p2pk_secret in p2pk_secrets:
+> if p2pk_secret.locktime and p2pk_secret.locktime < time.time():
+> refund_pubkeys =3D p2pk_secret.tags.get_tag_all("refund")
+> if refund_pubkeys:
+> pubkeys_per_proof.append(refund_pubkeys)
+> n_sigs_per_proof.append(1)
+> if not pubkeys_per_proof:
+> return True
+> assert len({tuple(pubs_output) for pubs_output in pubkeys_per_proof}) =3D=
+=3D=20
+> 1, "pubkeys in all proofs must match."
+> assert len(set(n_sigs_per_proof)) =3D=3D 1, "n_sigs in all proofs must ma=
+tch."
+> pubkeys =3D pubkeys_per_proof[0]
+> n_sigs =3D n_sigs_per_proof[0] or 1
+> for output in outputs:
+> p2pksigs =3D output.p2pksigs
+> assert p2pksigs, "no signatures in output."
+> assert len(set(p2pksigs)) =3D=3D len(p2pksigs), "duplicate signatures in=
+=20
+> output."
+> n_valid_sigs_per_output =3D 0
+> for sig in p2pksigs:
+> for pubkey in pubkeys:
+> if verify_schnorr_signature(
+> message=3Dbytes.fromhex(output.B_),
+> pubkey=3DPublicKey(bytes.fromhex(pubkey), raw=3DTrue),
+> signature=3Dbytes.fromhex(sig),
+> ):
+> n_valid_sigs_per_output +=3D 1
+> assert n_valid_sigs_per_output, "no valid signature provided for output."
+> assert n_valid_sigs_per_output >=3D n_sigs, f"signature threshold not met=
+.=20
+> {n_valid_sigs_per_output} < {n_sigs}."
+> return True
+>
+> def _verify_output_spending_conditions(self, proofs, outputs):
+> return self._verify_output_p2pk_spending_conditions(proofs, outputs)
+> ```
+>
+> ## Authentication
+>
+> Mints can enforce authentication at some point and do KYC for mint, melt,=
+=20
+> swap etc. Users who refuse to KYC will not be able to use or redeem their=
+=20
+> ecash tokens. Some of the KYCed users can be censored based on their=20
+> identity. This would also affect privacy.
+>
+> gandlaf21 agrees this is possible however it is still marketed as=20
+> censorship resistant.=20
+>
+> There was some discussion about it in a pull request and supertestnet als=
+o=20
+> shared his thoughts:=20
+> https://github.com/bitcoinlayers/bitcoinlayers/pull/164
+>
+> This whole debate started in May 2024 when cashu's twitter account=20
+> [announced][2] that they are considering adding an authentication in the=
+=20
+> protocol as it is requested by regulated entities.
+>
+> The authentication mechanism is shared in this [pull request][3] which=20
+> links each user with linkingkey and it will compromise privacy:
+>
+> ```
+> POST https://bob.com/v1/auth
+>
+> Post Data:
+> {=20
+> action:"mint",=20
+> k1:"8278e1a48e61c261916791dabb6af760488e4f01932e11fe7054f59754e3de6e"
+> signature:c568f78e4b234a5f7d8c3b2a679e48d1234567890abcdef
+> linkingKey:7345786068584cd33000582ba87a9ddf77db5377c67910ab59d7e9a5f44
+> }
+>
+> Response:
+>
+> HTTP/1.1 200 OK
+>
+> {
+> "access_token": "9876543210fedcba",
+> "token_type": "Bearer",
+> "expires_in": 3600
+> }
+> ```
+>
+> This pull request was closed last week and a new authentication mechanism=
+=20
+> is proposed: https://github.com/cashubtc/nuts/pull/198
+>
+> It uses clear and blind auth but users can still be censored with KYC=20
+> based on their identity. You can understand the details from this=20
+> [comment][4].
+>
+> ## Conclusion
+>
+> The authentication mechanisms shared above are not the only way mints can=
+=20
+> restrict users as there is nothing in the protocol that stops mints from=
+=20
+> using a custom authentication.
+>
+> Introducing KYC in protocol is against freedom and privacy. These=20
+> custodial solutions might end up being another compliant ecash=20
+> implementation like [GNU Taler][5]. This would also make it easier for=20
+> government agencies to target other mints that do not comply.
+>
+> [1]:=20
+> https://github.com/cashubtc/nutshell/blob/main/cashu/mint/conditions.py
+> [2]: https://x.com/CashuBTC/status/1791001643019809146
+> [3]: https://github.com/cashubtc/nuts/pull/106
+> [4]: https://github.com/cashubtc/nuts/pull/198#issuecomment-2508706328
+> [5]: https://taler.net/en/index.html
+>
+> /dev/fd0
+> floppy disk guy
+>
+> --=20
+> You received this message because you are subscribed to the Google Groups=
+=20
+> "Bitcoin Development Mailing List" group.
+> To unsubscribe from this group and stop receiving emails from it, send an=
+=20
+> email to bitcoindev+...@googlegroups.com.
+> To view this discussion visit=20
+> https://groups.google.com/d/msgid/bitcoindev/27b19012-20da-46a7-8a84-f90e=
+0070aa77n%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/=
+51eb0cc8-c9e0-4a50-9928-461f5f13264en%40googlegroups.com.
+
+------=_Part_192403_1051169886.1734822212929
+Content-Type: text/html; charset="UTF-8"
+Content-Transfer-Encoding: quoted-printable
+
+Hi conduition,<br /><br />&gt;=C2=A0
+
+<span style=3D"font-family: Arial, sans-serif;">For P2PK, the solution ther=
+e seems deadly obvious: Just don't use raw unobfuscated Nostr keys to recei=
+ve ecash. Tweak it, or use a new random key. This is a non-issue<br /></spa=
+n><br />This is an issue at present. I hope you fix it as you seem to be [i=
+nvolved][1] in cashu development. The workarounds that you suggested will s=
+till allow a **specific** key to be censored.<br /><br />&gt;=C2=A0
+
+<span style=3D"font-family: Arial, sans-serif;">As for authentication syste=
+ms, yes of course KYC-backed authentication would allow censorship, but tha=
+t is an optional spec which mints aren't compelled to implement or use, eve=
+n once the spec is finished. AFAIK no mint implementations have this system=
+ in code yet, so it's not even a feature at this point: just a proposed NUT=
+ document, sitting in draft status. Your assertion that "</span><span style=
+=3D"font-family: Arial, sans-serif;">none of the ecash implementation are c=
+ensorship resistant" is a blatantly false statement bereft of fact or depth=
+.<br /></span><br />Being optional does not matter. It is **possible** for =
+a mint to use authentication which is the whole point of this mailing list =
+post. It is true that none of the ecash implementations are censorship resi=
+stant. Just because censorship isn't implemented yet by mints does not mean=
+ the protocol is censorship resistant.<br /><br />The false statements exis=
+t in cashu docs with misleading things about censorship resistance.<br /><b=
+r />&gt;=C2=A0
+
+<span style=3D"font-family: Arial, sans-serif;">At worst they might lose th=
+e money they already stored with the compromised mint, which is always a ri=
+sk to keep in mind with ecash.<br /></span><br />This is already described =
+in my post.<br /><br />&gt;=C2=A0
+
+<span style=3D"font-family: Arial, sans-serif;">So ecash devs have proposed=
+ standardized auth systems which would give mint runners the=C2=A0</span><i=
+ style=3D"font-family: Arial, sans-serif;">option</i><span style=3D"font-fa=
+mily: Arial, sans-serif;">=C2=A0of knuckling under to KYC. I agree it would=
+ suck to be put to that choice, but giving them the freedom to choose is im=
+portant and valid, and in no way compromises the integrity of other non-KYC=
+ mints who perhaps operate freely in more enlightened jurisdictions.=C2=A0<=
+br /></span><br />Standardizing KYC in the protocol is the opposite of free=
+dom and privacy. Jurisdictions do not matter if a mint is large enough to b=
+e attacked by the government agencies. There are enough examples for it.<br=
+ /><br />&gt;=C2=A0
+
+<span style=3D"font-family: Arial, sans-serif;">If it's not part of the NUT=
+ standards, and mint runners need it, then someone will just fork off and a=
+dd it themselves. Better to pre-empt that and keep the standards from fragm=
+enting - that's the point of standards.=C2=A0<br /></span><br />There are w=
+ays to avoid any kind of authentication and KYC in the protocol. If someone=
+ still forks then it won't remain cashu protocol. However, I won't waste my=
+ time explaining it because the goal seem to be helping regulated entities =
+to use cashu.<div><br /></div><div>[1]:=C2=A0https://conduition.io/cryptogr=
+aphy/ecash-dlc/<br /><br />/dev/fd0<div>floppy disk guy<br /><br /></div></=
+div><div class=3D"gmail_quote"><div dir=3D"auto" class=3D"gmail_attr">On Su=
+nday, December 22, 2024 at 3:34:17=E2=80=AFAM UTC+5:30 conduition wrote:<br=
+/></div><blockquote class=3D"gmail_quote" style=3D"margin: 0 0 0 0.8ex; bor=
+der-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><div style=3D"f=
+ont-family:Arial,sans-serif;font-size:14px">Hi fd0,</div><div style=3D"font=
+-family:Arial,sans-serif;font-size:14px"><br></div><div style=3D"font-famil=
+y:Arial,sans-serif;font-size:14px"><span style=3D"display:inline!important;=
+background-color:rgb(255,255,255)">For P2PK, the solution there seems deadl=
+y obvious: Just don&#39;t use raw unobfuscated Nostr keys to receive ecash.=
+ Tweak it, or use a new random key. This is a non-issue.</span><br></div><d=
+iv style=3D"font-family:Arial,sans-serif;font-size:14px"><br></div><div sty=
+le=3D"font-family:Arial,sans-serif;font-size:14px">As for authentication sy=
+stems, yes of course KYC-backed authentication would allow censorship, but =
+that is an optional spec which mints aren&#39;t compelled to implement or u=
+se, even once the spec is finished. AFAIK no mint implementations have this=
+ system in code yet, so it&#39;s not even a feature at this point: just a p=
+roposed NUT document, sitting in draft status. Your assertion that &quot;<s=
+pan>none of the ecash implementation are censorship resistant&quot; is a bl=
+atantly false statement bereft of fact or depth.</span></div><div style=3D"=
+font-family:Arial,sans-serif;font-size:14px"><br></div><div style=3D"font-f=
+amily:Arial,sans-serif;font-size:14px">Even if we fast forward several year=
+s when perhaps <i>some</i> ecash mint implementations do=C2=A0implement the=
+ authentication spec as a fully-formed feature ready to go...=C2=A0If a min=
+t starts enforcing KYC, or any other badness like censoring by IP address, =
+users are free to switch to a different non-KYC mint instance. At worst the=
+y might lose the money they already stored with the compromised mint, which=
+ is always a risk to keep in mind with ecash.</div><div style=3D"font-famil=
+y:Arial,sans-serif;font-size:14px"><span><br></span></div><div style=3D"fon=
+t-family:Arial,sans-serif;font-size:14px"><span></span></div><div style=3D"=
+font-family:Arial,sans-serif;font-size:14px">Your argument seems to be that=
+ introducing an opt-in feature spec like external authentication is inheren=
+tly bad because it encourages/enables=C2=A0KYC in the first place, and that=
+ ecash devs should refuse to even standardize any protocol which enables KY=
+C.=C2=A0</div><div style=3D"font-family:Arial,sans-serif;font-size:14px"><b=
+r></div><div style=3D"font-family:Arial,sans-serif;font-size:14px">Well I h=
+ave hard news for you: Governments don&#39;t care about whether compliance =
+is &quot;easy&quot; or &quot;standardized&quot;. If uncle sam wants your mi=
+nt to enforce KYC, he won&#39;t balk just because the mint&#39;s code doesn=
+&#39;t provide an easy way to do it. He&#39;ll give you a deadline to enfor=
+ce KYC on your users, and if you can&#39;t prove you&#39;re compliant by th=
+en, you can kiss your business goodbye.</div><div style=3D"font-family:Aria=
+l,sans-serif;font-size:14px"><br></div><div style=3D"font-family:Arial,sans=
+-serif;font-size:14px">When faced with this choice, the ecash mint runner c=
+an either shut down their mint, or add KYC. Without an authentication syste=
+m in place already, the mint runner would have to implement it all themselv=
+es to enforce KYC and stay in business. So ecash devs have proposed standar=
+dized auth systems which would give mint runners the <i>option</i> of knuck=
+ling under to KYC. I agree it would suck to be put to that choice, but givi=
+ng them the freedom to choose is important and valid, and in no way comprom=
+ises the integrity of other non-KYC mints who perhaps operate freely in mor=
+e enlightened jurisdictions.=C2=A0</div><div style=3D"font-family:Arial,san=
+s-serif;font-size:14px"><br></div><div style=3D"font-family:Arial,sans-seri=
+f;font-size:14px">If it&#39;s not part of the NUT standards, and mint runne=
+rs need it, then someone will just fork off and add it themselves. Better t=
+o pre-empt that and keep the standards from fragmenting - that&#39;s the po=
+int of standards.=C2=A0</div><div style=3D"font-family:Arial,sans-serif;fon=
+t-size:14px"><br></div><div style=3D"font-family:Arial,sans-serif;font-size=
+:14px">-c</div><div></div><div>
+ On Saturday, December 21st, 2024 at 9:58 AM, /dev /fd0 &lt;<a href =
+data-email-masked rel=3D"nofollow">alice...@gmail.com</a>&gt; wrote:<br>
+ </div><div><blockquote type=3D"cite">
+ Hi Bitcoin Developers,<br><br>This post is about a myth and som=
+e misleading things shared about ecash. It is possible to censor specific u=
+sers and none of the ecash implementation are censorship resistant.<br><div=
+><br></div><div># Censorship Methods in Cashu<br><br>There are 2 ways to ce=
+nsor individual users in cashu:<br><br>1. P2PK<br>2. Authentication<br><br>=
+## P2PK<br><br>Ecash tokens issued by cashu mints can be locked using publi=
+c keys so that it can only be redeemed by the user who owns the private key=
+ for it. This links ecash with specific public keys and most implementation=
+ use nostr keys for it. Most users are doxxed on nostr so they can be censo=
+red based on their identity. Even if its linked to an anon they can be cens=
+ored based on their posts.<br><br>You can find relevant code snippets in [c=
+onditions.py][1] if using nutshell for mint:<br><br>```python<br>class Ledg=
+erSpendingConditions:<br> def _verify_p2pk_spending_conditions(self, pro=
+of, secret):<br> if SecretKind(secret.kind) !=3D SecretKind.P2PK:<br=
+> return True<br> p2pk_secret =3D P2PKSecret.from_secret(=
+secret)<br> pubkeys =3D [p2pk_secret.data] + p2pk_secret.tags.get_ta=
+g_all(&quot;pubkeys&quot;)<br> if p2pk_secret.locktime and p2pk_secr=
+et.locktime &lt; time.time():<br> refund_pubkeys =3D p2pk_secret=
+.tags.get_tag_all(&quot;refund&quot;)<br> if not refund_pubkeys:=
+<br> return True<br> return self._verify_secret_s=
+ignatures(<br> proof, refund_pubkeys, proof.p2pksigs, 1<br> =
+ )<br> return self._verify_secret_signatures(<br> =
+ proof, pubkeys, proof.p2pksigs, p2pk_secret.n_sigs<br> )<br><br> =
+ def _verify_htlc_spending_conditions(self, proof, secret):<br> if=
+ SecretKind(secret.kind) !=3D SecretKind.HTLC:<br> return True<b=
+r> htlc_secret =3D HTLCSecret.from_secret(secret)<br> if htlc=
+_secret.locktime and htlc_secret.locktime &lt; time.time():<br> =
+refund_pubkeys =3D htlc_secret.tags.get_tag_all(&quot;refund&quot;)<br> =
+ if refund_pubkeys:<br> return self._verify_secret_si=
+gnatures(<br> proof, refund_pubkeys, proof.p2pksigs, 1<b=
+r> )<br> return True<br> assert proof.htlc=
+preimage, TransactionError(&quot;no HTLC preimage provided&quot;)<br> =
+ if not hashlib.sha256(bytes.fromhex(proof.htlcpreimage)).digest() =3D=3D =
+bytes.fromhex(htlc_secret.data):<br> raise TransactionError(&quo=
+t;HTLC preimage does not match.&quot;)<br> hashlock_pubkeys =3D htlc=
+_secret.tags.get_tag_all(&quot;pubkeys&quot;)<br> if not hashlock_pu=
+bkeys:<br> return True<br> return self._verify_secret_sig=
+natures(<br> proof, hashlock_pubkeys, proof.htlcsigs or [], htlc=
+_secret.n_sigs<br> )<br><br> def _verify_secret_signatures(self, =
+proof, pubkeys, signatures, n_sigs_required=3D1):<br> assert len(set=
+(pubkeys)) =3D=3D len(pubkeys), &quot;pubkeys must be unique.&quot;<br> =
+ if not signatures:<br> raise TransactionError(&quot;no signa=
+tures in proof.&quot;)<br> if len(set(signatures)) !=3D len(signatur=
+es):<br> raise TransactionError(&quot;signatures must be unique.=
+&quot;)<br> n_sigs_required =3D n_sigs_required or 1<br> asse=
+rt n_sigs_required &gt; 0, &quot;n_sigs must be positive.&quot;<br> =
+assert len(signatures) &gt;=3D n_sigs_required, f&quot;not enough signature=
+s provided: {len(signatures)} &lt; {n_sigs_required}.&quot;<br> n_va=
+lid_sigs_per_output =3D 0<br> for input_sig in signatures:<br> =
+ for pubkey in pubkeys:<br> if verify_schnorr_signature=
+(<br> message=3Dproof.secret.encode(&quot;utf-8&quot;),<=
+br> pubkey=3DPublicKey(bytes.fromhex(pubkey), raw=3DTrue=
+),<br> signature=3Dbytes.fromhex(input_sig),<br> =
+ ):<br> n_valid_sigs_per_output +=3D 1<br> =
+ assert n_valid_sigs_per_output, &quot;no valid signature provided for inpu=
+t.&quot;<br> assert n_valid_sigs_per_output &gt;=3D n_sigs_required,=
+ f&quot;signature threshold not met. {n_valid_sigs_per_output} &lt; {n_sigs=
+_required}.&quot;<br> return True<br><br> def _verify_input_spend=
+ing_conditions(self, proof):<br> try:<br> secret =3D Secr=
+et.deserialize(proof.secret)<br> except Exception:<br> re=
+turn True<br> if SecretKind(secret.kind) =3D=3D SecretKind.P2PK:<br>=
+ return self._verify_p2pk_spending_conditions(proof, secret)<br>=
+ if SecretKind(secret.kind) =3D=3D SecretKind.HTLC:<br> r=
+eturn self._verify_htlc_spending_conditions(proof, secret)<br> retur=
+n True<br><br> def _verify_output_p2pk_spending_conditions(self, proofs,=
+ outputs):<br> try:<br> secrets_generic =3D [Secret.deser=
+ialize(p.secret) for p in proofs]<br> p2pk_secrets =3D [P2PKSecr=
+et.from_secret(secret) for secret in secrets_generic]<br> except Exc=
+eption:<br> return True<br> if not all([SecretKind(secret=
+.kind) =3D=3D SecretKind.P2PK for secret in p2pk_secrets]):<br> =
+return True<br> if not all([secret.sigflag =3D=3D SigFlags.SIG_ALL f=
+or secret in p2pk_secrets]):<br> return True<br> pubkeys_=
+per_proof =3D [<br> [p2pk_secret.data] + p2pk_secret.tags.get_ta=
+g_all(&quot;pubkeys&quot;)<br> for p2pk_secret in p2pk_secrets<b=
+r> ]<br> n_sigs_per_proof =3D [p2pk_secret.n_sigs for p2pk_se=
+cret in p2pk_secrets]<br> for p2pk_secret in p2pk_secrets:<br> =
+ if p2pk_secret.locktime and p2pk_secret.locktime &lt; time.time():<br=
+> refund_pubkeys =3D p2pk_secret.tags.get_tag_all(&quot;refu=
+nd&quot;)<br> if refund_pubkeys:<br> pubk=
+eys_per_proof.append(refund_pubkeys)<br> n_sigs_per_proo=
+f.append(1)<br> if not pubkeys_per_proof:<br> return True=
+<br> assert len({tuple(pubs_output) for pubs_output in pubkeys_per_p=
+roof}) =3D=3D 1, &quot;pubkeys in all proofs must match.&quot;<br> a=
+ssert len(set(n_sigs_per_proof)) =3D=3D 1, &quot;n_sigs in all proofs must =
+match.&quot;<br> pubkeys =3D pubkeys_per_proof[0]<br> n_sigs =
+=3D n_sigs_per_proof[0] or 1<br> for output in outputs:<br> =
+ p2pksigs =3D output.p2pksigs<br> assert p2pksigs, &quot;no si=
+gnatures in output.&quot;<br> assert len(set(p2pksigs)) =3D=3D l=
+en(p2pksigs), &quot;duplicate signatures in output.&quot;<br> n_=
+valid_sigs_per_output =3D 0<br> for sig in p2pksigs:<br> =
+ for pubkey in pubkeys:<br> if verify_schnorr_sig=
+nature(<br> message=3Dbytes.fromhex(output.B_),<br> =
+ pubkey=3DPublicKey(bytes.fromhex(pubkey), raw=3DTrue=
+),<br> signature=3Dbytes.fromhex(sig),<br> =
+ ):<br> n_valid_sigs_per_output +=3D 1<br> =
+ assert n_valid_sigs_per_output, &quot;no valid signature provide=
+d for output.&quot;<br> assert n_valid_sigs_per_output &gt;=3D n=
+_sigs, f&quot;signature threshold not met. {n_valid_sigs_per_output} &lt; {=
+n_sigs}.&quot;<br> return True<br><br> def _verify_output_spendin=
+g_conditions(self, proofs, outputs):<br> return self._verify_output_=
+p2pk_spending_conditions(proofs, outputs)<br>```<br><br>## Authentication<b=
+r><br>Mints can enforce authentication at some point and do KYC for mint, m=
+elt, swap etc. Users who refuse to KYC will not be able to use or redeem th=
+eir ecash tokens. Some of the KYCed users can be censored based on their id=
+entity. This would also affect privacy.<br><br>gandlaf21 agrees this is pos=
+sible however it is still marketed as censorship resistant. <br><br>There w=
+as some discussion about it in a pull request and supertestnet also shared =
+his thoughts: <a href=3D"https://github.com/bitcoinlayers/bitcoinlayers/pul=
+l/164" target=3D"_blank" rel=3D"nofollow" data-saferedirecturl=3D"https://w=
+ww.google.com/url?hl=3Den&amp;q=3Dhttps://github.com/bitcoinlayers/bitcoinl=
+ayers/pull/164&amp;source=3Dgmail&amp;ust=3D1734907024882000&amp;usg=3DAOvV=
+aw3aVPG8X82bQmUeSO1W3TtU">https://github.com/bitcoinlayers/bitcoinlayers/pu=
+ll/164</a><br><br>This whole debate started in May 2024 when cashu&#39;s tw=
+itter account [announced][2] that they are considering adding an authentica=
+tion in the protocol as it is requested by regulated entities.<br><br>The a=
+uthentication mechanism is shared in this [pull request][3] which links eac=
+h user with linkingkey and it will compromise privacy:<br><br>```<br>POST <=
+a href=3D"https://bob.com/v1/auth" target=3D"_blank" rel=3D"nofollow" data-=
+saferedirecturl=3D"https://www.google.com/url?hl=3Den&amp;q=3Dhttps://bob.c=
+om/v1/auth&amp;source=3Dgmail&amp;ust=3D1734907024882000&amp;usg=3DAOvVaw3o=
+TrtvIJYHu1id-3npeyJ3">https://bob.com/v1/auth</a><br><br>Post Data:<br>{ <b=
+r> action:&quot;mint&quot;, <br> k1:&quot;8278e1a48e61c261916791dabb6af76=
+0488e4f01932e11fe7054f59754e3de6e&quot;<br> signature:c568f78e4b234a5f7d8c=
+3b2a679e48d1234567890abcdef<br> linkingKey:7345786068584cd33000582ba87a9dd=
+f77db5377c67910ab59d7e9a5f44<br>}<br><br>Response:<br><br>HTTP/1.1 200 OK<b=
+r><br>{<br> &quot;access_token&quot;: &quot;9876543210fedcba&quot;,<br> &=
+quot;token_type&quot;: &quot;Bearer&quot;,<br> &quot;expires_in&quot;: 360=
+0<br>}<br>```<br><br>This pull request was closed last week and a new authe=
+ntication mechanism is proposed: <a href=3D"https://github.com/cashubtc/nut=
+s/pull/198" target=3D"_blank" rel=3D"nofollow" data-saferedirecturl=3D"http=
+s://www.google.com/url?hl=3Den&amp;q=3Dhttps://github.com/cashubtc/nuts/pul=
+l/198&amp;source=3Dgmail&amp;ust=3D1734907024882000&amp;usg=3DAOvVaw1srbMVH=
+PtK1qi3EzcmZn1H">https://github.com/cashubtc/nuts/pull/198</a><br><br>It us=
+es clear and blind auth but users can still be censored with KYC based on t=
+heir identity. You can understand the details from this [comment][4].<br><b=
+r>## Conclusion<br><br>The authentication mechanisms shared above are not t=
+he only way mints can restrict users as there is nothing in the protocol th=
+at stops mints from using a custom authentication.<br><br>Introducing KYC i=
+n protocol is against freedom and privacy. These custodial solutions might =
+end up being another compliant ecash implementation like [GNU Taler][5]. Th=
+is would also make it easier for government agencies to target other mints =
+that do not comply.<br><br>[1]: <a href=3D"https://github.com/cashubtc/nuts=
+hell/blob/main/cashu/mint/conditions.py" target=3D"_blank" rel=3D"nofollow"=
+ data-saferedirecturl=3D"https://www.google.com/url?hl=3Den&amp;q=3Dhttps:/=
+/github.com/cashubtc/nutshell/blob/main/cashu/mint/conditions.py&amp;source=
+=3Dgmail&amp;ust=3D1734907024882000&amp;usg=3DAOvVaw0ysBnDUr4ArG3xaDT7ZX20"=
+>https://github.com/cashubtc/nutshell/blob/main/cashu/mint/conditions.py</a=
+><br>[2]: <a href=3D"https://x.com/CashuBTC/status/1791001643019809146" tar=
+get=3D"_blank" rel=3D"nofollow" data-saferedirecturl=3D"https://www.google.=
+com/url?hl=3Den&amp;q=3Dhttps://x.com/CashuBTC/status/1791001643019809146&a=
+mp;source=3Dgmail&amp;ust=3D1734907024882000&amp;usg=3DAOvVaw3wmjyBTXGk8ipm=
+GufUDG2c">https://x.com/CashuBTC/status/1791001643019809146</a><br>[3]: <a =
+href=3D"https://github.com/cashubtc/nuts/pull/106" target=3D"_blank" rel=3D=
+"nofollow" data-saferedirecturl=3D"https://www.google.com/url?hl=3Den&amp;q=
+=3Dhttps://github.com/cashubtc/nuts/pull/106&amp;source=3Dgmail&amp;ust=3D1=
+734907024882000&amp;usg=3DAOvVaw1WcmgB1AU6XK2nlkPYS3m1">https://github.com/=
+cashubtc/nuts/pull/106</a><br>[4]: <a href=3D"https://github.com/cashubtc/n=
+uts/pull/198#issuecomment-2508706328" target=3D"_blank" rel=3D"nofollow" da=
+ta-saferedirecturl=3D"https://www.google.com/url?hl=3Den&amp;q=3Dhttps://gi=
+thub.com/cashubtc/nuts/pull/198%23issuecomment-2508706328&amp;source=3Dgmai=
+l&amp;ust=3D1734907024882000&amp;usg=3DAOvVaw1s4K7aDIcwlCLsuExsq73I">https:=
+//github.com/cashubtc/nuts/pull/198#issuecomment-2508706328</a><br>[5]: <a =
+href=3D"https://taler.net/en/index.html" target=3D"_blank" rel=3D"nofollow"=
+ data-saferedirecturl=3D"https://www.google.com/url?hl=3Den&amp;q=3Dhttps:/=
+/taler.net/en/index.html&amp;source=3Dgmail&amp;ust=3D1734907024882000&amp;=
+usg=3DAOvVaw3H5Pad3n2SlM2ZOQ6k4cwY">https://taler.net/en/index.html</a><br>=
+<br>/dev/fd0<br>floppy disk guy</div>
+
+<p></p></blockquote></div><div><blockquote type=3D"cite">
+
+-- <br>
+You received this message because you are subscribed to the Google Groups &=
+quot;Bitcoin Development Mailing List&quot; group.<br>
+To unsubscribe from this group and stop receiving emails from it, send an e=
+mail to <a href rel=3D"noreferrer nofollow noopener" data-email-masked>bitc=
+oindev+...@googlegroups.com</a>.<br>
+To view this discussion visit <a href=3D"https://groups.google.com/d/msgid/=
+bitcoindev/27b19012-20da-46a7-8a84-f90e0070aa77n%40googlegroups.com" rel=3D=
+"noreferrer nofollow noopener" target=3D"_blank" data-saferedirecturl=3D"ht=
+tps://www.google.com/url?hl=3Den&amp;q=3Dhttps://groups.google.com/d/msgid/=
+bitcoindev/27b19012-20da-46a7-8a84-f90e0070aa77n%2540googlegroups.com&amp;s=
+ource=3Dgmail&amp;ust=3D1734907024882000&amp;usg=3DAOvVaw3gWNMKyQN7bAEutVee=
+zX0z">https://groups.google.com/d/msgid/bitcoindev/27b19012-20da-46a7-8a84-=
+f90e0070aa77n%40googlegroups.com</a>.<br>
+
+ </blockquote><br>
+ </div></blockquote></div>
+
+<p></p>
+
+-- <br />
+You received this message because you are subscribed to the Google Groups &=
+quot;Bitcoin Development Mailing List&quot; group.<br />
+To unsubscribe from this group and stop receiving emails from it, send an e=
+mail to <a href=3D"mailto:bitcoindev+unsubscribe@googlegroups.com">bitcoind=
+ev+unsubscribe@googlegroups.com</a>.<br />
+To view this discussion visit <a href=3D"https://groups.google.com/d/msgid/=
+bitcoindev/51eb0cc8-c9e0-4a50-9928-461f5f13264en%40googlegroups.com?utm_med=
+ium=3Demail&utm_source=3Dfooter">https://groups.google.com/d/msgid/bitcoind=
+ev/51eb0cc8-c9e0-4a50-9928-461f5f13264en%40googlegroups.com</a>.<br />
+
+------=_Part_192403_1051169886.1734822212929--
+
+------=_Part_192402_838158198.1734822212929--
+