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 ) 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 ; 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 To: Bitcoin Development Mailing List 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: X-Google-Group-Id: 786775582512 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , 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 =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,

>=C2=A0 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

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.

>=C2=A0 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 "none of the ecash implementation are c= ensorship resistant" is a blatantly false statement bereft of fact or depth= .

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.

The false statements exis= t in cashu docs with misleading things about censorship resistance.
>=C2=A0 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.

This is already described = in my post.

>=C2=A0 So ecash devs have proposed= standardized auth systems which would give mint runners the=C2=A0option=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 />
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.
>=C2=A0 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

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.

[1]:=C2=A0https://conduition.io/cryptogr= aphy/ecash-dlc/

/dev/fd0
floppy disk guy

On Su= nday, December 22, 2024 at 3:34:17=E2=80=AFAM UTC+5:30 conduition wrote:
Hi fd0,

For P2PK, the solution there seems deadl= y obvious: Just don't use raw unobfuscated Nostr keys to receive ecash.= Tweak it, or use a new random key. This is a non-issue.

As for authentication sy= stems, yes of course KYC-backed authentication would allow censorship, but = that is an optional spec which mints aren'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's not even a feature at this point: just a p= roposed NUT document, sitting in draft status. Your assertion that "none of the ecash implementation are censorship resistant" is a bl= atantly false statement bereft of fact or depth.

Even if we fast forward several year= s when perhaps some 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.

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
Well I h= ave hard news for you: Governments don't care about whether compliance = is "easy" or "standardized". If uncle sam wants your mi= nt to enforce KYC, he won't balk just because the mint's code doesn= 't provide an easy way to do it. He'll give you a deadline to enfor= ce KYC on your users, and if you can't prove you're compliant by th= en, you can kiss your business goodbye.

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 option 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

If it'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's the po= int of standards.=C2=A0

-c
On Saturday, December 21st, 2024 at 9:58 AM, /dev /fd0 <alice...@gmail.com> wrote:
Hi Bitcoin Developers,

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.

# Censorship Methods in Cashu

There are 2 ways to ce= nsor individual users in cashu:

1. P2PK
2. Authentication

= ## P2PK

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.

You can find relevant code snippets in [c= onditions.py][1] if using nutshell for mint:

```python
class Ledg= erSpendingConditions:
def _verify_p2pk_spending_conditions(self, pro= of, 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_ta= g_all("pubkeys")
if p2pk_secret.locktime and p2pk_secr= et.locktime < time.time():
refund_pubkeys =3D p2pk_secret= .tags.get_tag_all("refund")
if not refund_pubkeys:=
return True
return self._verify_secret_s= ignatures(
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_si= gnatures(
proof, refund_pubkeys, proof.p2pksigs, 1 )
return True
assert proof.htlc= preimage, TransactionError("no HTLC preimage provided")
= if not hashlib.sha256(bytes.fromhex(proof.htlcpreimage)).digest() =3D=3D = bytes.fromhex(htlc_secret.data):
raise TransactionError(&quo= t;HTLC preimage does not match.")
hashlock_pubkeys =3D htlc= _secret.tags.get_tag_all("pubkeys")
if not hashlock_pu= bkeys:
return True
return self._verify_secret_sig= natures(
proof, hashlock_pubkeys, proof.htlcsigs or [], htlc= _secret.n_sigs
)

def _verify_secret_signatures(self, = proof, pubkeys, signatures, n_sigs_required=3D1):
assert len(set= (pubkeys)) =3D=3D len(pubkeys), "pubkeys must be unique."
= if not signatures:
raise TransactionError("no signa= tures in proof.")
if len(set(signatures)) !=3D len(signatur= es):
raise TransactionError("signatures must be unique.= ")
n_sigs_required =3D n_sigs_required or 1
asse= rt n_sigs_required > 0, "n_sigs must be positive."
= assert len(signatures) >=3D n_sigs_required, f"not enough signature= s provided: {len(signatures)} < {n_sigs_required}."
n_va= lid_sigs_per_output =3D 0
for input_sig in signatures:
= for pubkey in pubkeys:
if verify_schnorr_signature= (
message=3Dproof.secret.encode("utf-8"),<= br> 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 inpu= t."
assert n_valid_sigs_per_output >=3D n_sigs_required,= f"signature threshold not met. {n_valid_sigs_per_output} < {n_sigs= _required}."
return True

def _verify_input_spend= ing_conditions(self, proof):
try:
secret =3D Secr= et.deserialize(proof.secret)
except Exception:
re= turn 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:
r= eturn self._verify_htlc_spending_conditions(proof, secret)
retur= n True

def _verify_output_p2pk_spending_conditions(self, proofs,= outputs):
try:
secrets_generic =3D [Secret.deser= ialize(p.secret) for p in proofs]
p2pk_secrets =3D [P2PKSecr= et.from_secret(secret) for secret in secrets_generic]
except Exc= eption:
return True
if not all([SecretKind(secret= .kind) =3D=3D SecretKind.P2PK for secret in p2pk_secrets]):
= return True
if not all([secret.sigflag =3D=3D SigFlags.SIG_ALL f= or secret in p2pk_secrets]):
return True
pubkeys_= per_proof =3D [
[p2pk_secret.data] + p2pk_secret.tags.get_ta= g_all("pubkeys")
for p2pk_secret in p2pk_secrets ]
n_sigs_per_proof =3D [p2pk_secret.n_sigs for p2pk_se= cret 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("refu= nd")
if refund_pubkeys:
pubk= eys_per_proof.append(refund_pubkeys)
n_sigs_per_proo= f.append(1)
if not pubkeys_per_proof:
return True=
assert len({tuple(pubs_output) for pubs_output in pubkeys_per_p= roof}) =3D=3D 1, "pubkeys in all proofs must match."
a= ssert len(set(n_sigs_per_proof)) =3D=3D 1, "n_sigs in all proofs must = match."
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 si= gnatures in output."
assert len(set(p2pksigs)) =3D=3D l= en(p2pksigs), "duplicate signatures in output."
n_= valid_sigs_per_output =3D 0
for sig in p2pksigs:
= for pubkey in pubkeys:
if verify_schnorr_sig= nature(
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 provide= d for output."
assert n_valid_sigs_per_output >=3D n= _sigs, f"signature threshold not met. {n_valid_sigs_per_output} < {= n_sigs}."
return True

def _verify_output_spendin= g_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, 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.

gandlaf21 agrees this is pos= sible however it is still marketed as censorship resistant.

There w= as some discussion about it in a pull request and supertestnet also shared = his thoughts: https://github.com/bitcoinlayers/bitcoinlayers/pu= ll/164

This whole debate started in May 2024 when cashu's tw= itter account [announced][2] that they are considering adding an authentica= tion in the protocol as it is requested by regulated entities.

The a= uthentication mechanism is shared in this [pull request][3] which links eac= h user with linkingkey and it will compromise privacy:

```
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&q=3Dhttps://bob.c= om/v1/auth&source=3Dgmail&ust=3D1734907024882000&usg=3DAOvVaw3o= TrtvIJYHu1id-3npeyJ3">https://bob.com/v1/auth

Post Data:
{ action:"mint",
k1:"8278e1a48e61c261916791dabb6af76= 0488e4f01932e11fe7054f59754e3de6e"
signature:c568f78e4b234a5f7d8c= 3b2a679e48d1234567890abcdef
linkingKey:7345786068584cd33000582ba87a9dd= f77db5377c67910ab59d7e9a5f44
}

Response:

HTTP/1.1 200 OK
{
"access_token": "9876543210fedcba",
&= quot;token_type": "Bearer",
"expires_in": 360= 0
}
```

This pull request was closed last week and a new authe= ntication mechanism is proposed: https://github.com/cashubtc/nuts/pull/198

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].
## Conclusion

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.

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.

[1]: 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

--
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 bitc= oindev+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/27b19012-20da-46a7-8a84-= f90e0070aa77n%40googlegroups.com.

--
You received this message because you are subscribed to the Google Groups &= quot;Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoind= ev+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/bitcoind= ev/51eb0cc8-c9e0-4a50-9928-461f5f13264en%40googlegroups.com.
------=_Part_192403_1051169886.1734822212929-- ------=_Part_192402_838158198.1734822212929--