Delivery-date: Sat, 21 Dec 2024 14:04:25 -0800
Received: from mail-qv1-f56.google.com ([209.85.219.56])
	by mail.fairlystable.org with esmtps  (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
	(Exim 4.94.2)
	(envelope-from <bitcoindev+bncBCL7RHHJZYJBBXXWTS5QMGQE7ERPXDQ@googlegroups.com>)
	id 1tP7aB-0007rZ-Vn
	for bitcoindev@gnusha.org; Sat, 21 Dec 2024 14:04:25 -0800
Received: by mail-qv1-f56.google.com with SMTP id 6a1803df08f44-6d92f0737besf43747586d6.1
        for <bitcoindev@gnusha.org>; Sat, 21 Dec 2024 14:04:23 -0800 (PST)
ARC-Seal: i=2; a=rsa-sha256; t=1734818657; cv=pass;
        d=google.com; s=arc-20240605;
        b=lJJvm3YpKndT82fK2F7szDlI7636xAg4ZknONCxktKUY1dQeR0bgTbcwSVTDL3QKw0
         l1sORR+PvGJUqilCs2BmNmIi2yzskSsKJjY0VE4xEVQq2LvsTaqaqLPcmaSP4co45NRb
         Fb1He5ZL8OSdr36FOcXXMtXQS3vJPb/4KbOF7ZNH5EAsHEu94b5pDZojRM+1Q/z0HBDl
         RyQtXiO5S6ILpbpFdOyRToqhBZUT8f4naY6btwYxIzrhJy/W558GgR0nYtplbVbaFkqq
         2ZHKJgctW6gMBal9iiQzcGClJ+8yzF/TTtuR6tkMty2eKNBPMev4DPOZQ14Qv/X+VgX/
         70VQ==
ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605;
        h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post
         :list-id:mailing-list:precedence:reply-to:mime-version:feedback-id
         :references:in-reply-to:message-id:subject:cc:from:to:date
         :dkim-signature;
        bh=Ae2h7701zE9zPlmROD2cDHtWG+zMJwutzmws+rtEhmg=;
        fh=vV8Gql8Zhf+qx48TZtxAb1FZ3ftgQQ+kSTMOcQzzrOo=;
        b=Xc9iT8ofxgWjJdMjhuJAGbJO9Uk9iOIIO00dbXpczA6BX4e3xjcn1NO/FKxSxdcmVO
         3+5DAKenTi2/tI2qA2sI3CBwXhiDmU7BCSKf/U9ZAD00lCSNT89tZG7aiNFD69TOupFS
         dVI/fvfL5xJqpwunaqAn4akpWwGoAmPPSsiXlhCBlTOya7ZoVzzgVhVNl6k8p0hq5+Em
         qJOmyjF9goeFkToQJtjgowR1fn+vPqUa7wg3CQy/k7YltJAPLXiELgC0/ScsKzeDR+M7
         T5B44oaTXyezRKzSYo8NxTiD438zFFmlTSHKb9dN6tXhs1ZhtuN1DtGW7gd6pzJro1V9
         yy2w==;
        darn=gnusha.org
ARC-Authentication-Results: i=2; gmr-mx.google.com;
       dkim=pass header.i=@proton.me header.s=protonmail header.b=K3nxNkrP;
       spf=pass (google.com: domain of conduition@proton.me designates 185.70.43.16 as permitted sender) smtp.mailfrom=conduition@proton.me;
       dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlegroups.com; s=20230601; t=1734818657; x=1735423457; darn=gnusha.org;
        h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post
         :list-id:mailing-list:precedence:reply-to
         :x-original-authentication-results:x-original-sender:mime-version
         :feedback-id:references:in-reply-to:message-id:subject:cc:from:to
         :date:from:to:cc:subject:date:message-id:reply-to;
        bh=Ae2h7701zE9zPlmROD2cDHtWG+zMJwutzmws+rtEhmg=;
        b=C3OkrkmNiyMZX7PpKq9A7diu0uZUuI36WvBXyn6ENKNe+Ozgv3Jtf7SQ2OqvDte5Z6
         LmLx+qhx1byKV5RZ4gScXoeazvimG3x0Up/OVcakeL3fRIC9WijvlhDO3mVOIp4/0U8H
         1mEVOX8Ez9OF7bFzUVX8DRULUaW1qE/Gh8SvSjIyQxyqcpgRWvVEleJLcbCNE01ujVB+
         SFv77q1QHBufG6D8LGaJvkSUTiZqEU9MMmekQoljhAGF3LdS2xc1eNtUNzA2xiBS6kvB
         oOfGDsidaGgD0lgS0eMS93VOmKq0KUURO7QRX3jmgzJZrVVsPCJxLqdZDaXn6opHyzF+
         +M5g==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20230601; t=1734818657; x=1735423457;
        h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post
         :list-id:mailing-list:precedence:reply-to
         :x-original-authentication-results:x-original-sender:mime-version
         :feedback-id:references:in-reply-to:message-id:subject:cc:from:to
         :date:x-beenthere:x-gm-message-state:from:to:cc:subject:date
         :message-id:reply-to;
        bh=Ae2h7701zE9zPlmROD2cDHtWG+zMJwutzmws+rtEhmg=;
        b=kJSYvwcEoSueI5ZTbSzyGOncU4ohdHNVrTh2K/cbO5jHhIg135Ehuksld1L53tp43b
         SOmhh3emJzzIgP5xmPCJ5K/6hm4UOvNCPT41RFFndXWKuLkkUcM2oyx2QAE7AlS8tN/G
         7CDBChi2XpA6D9r8RudbWCDfC6iCh+pnMl2Mu1qH5XmTAak7i3QLvusSAOzgJ6BNuVNR
         7xl1F0Y0sufHe+u+7PMQ6yLJYF6OHgNJN5wOYaBp4cH1qsh9tro53p75G2+hsZ40Xgj6
         wu8+0Msdb173W9VEXE0vP2UR1wRjTw8BDxQAAVVihLSzO7xeBy2N/GA5RtoADZi9j/au
         c2ZQ==
X-Forwarded-Encrypted: i=2; AJvYcCXtKiIG1laUGob65P4/gQKd3KgFZtAG/ES9zoT7rnePxPuaHPIo4fJF08C4p5qD6aHSyjxpnvjsZo5U@gnusha.org
X-Gm-Message-State: AOJu0YyU5zvJoyWtxftNhJzmNP02Ry6oUDSYUmmbuWa6Rn8t3n77mUfN
	X+NZjIofzRy7SyVHC9AKblTr3JlUjw5748XDU+RAbkgq2nVubbwG
X-Google-Smtp-Source: AGHT+IFUNVB0fIvy9lRjkFBDVGg3GA1CWp5jOhno5YUCRvKldcSKmt64w3wih/DvlzZX8vBXw3ys5A==
X-Received: by 2002:a05:6214:124c:b0:6d8:b2f2:bcb8 with SMTP id 6a1803df08f44-6dd233207b0mr115416836d6.8.1734818657164;
        Sat, 21 Dec 2024 14:04:17 -0800 (PST)
X-BeenThere: bitcoindev@googlegroups.com
Received: by 2002:ad4:480c:0:b0:6d9:832:c74c with SMTP id 6a1803df08f44-6dd15481938ls43416936d6.1.-pod-prod-03-us;
 Sat, 21 Dec 2024 14:04:14 -0800 (PST)
X-Received: by 2002:a05:620a:2948:b0:7b6:cf48:ed5 with SMTP id af79cd13be357-7b9ba7168edmr1243277185a.7.1734818654506;
        Sat, 21 Dec 2024 14:04:14 -0800 (PST)
Received: by 2002:a05:620a:1258:b0:7b6:d72a:7c26 with SMTP id af79cd13be357-7b9ab36d14ems85a;
        Sat, 21 Dec 2024 13:52:40 -0800 (PST)
X-Received: by 2002:a05:6512:3ba4:b0:53e:3a43:9245 with SMTP id 2adb3069b0e04-542295404f9mr2504047e87.28.1734817958516;
        Sat, 21 Dec 2024 13:52:38 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1734817958; cv=none;
        d=google.com; s=arc-20240605;
        b=FHKB2+msgpLG3YLh4RvJc0od+bG9PCK/ci1xo32rnOP40LAZXHEmfRwObq52QTd/mb
         GhcPFt4BppGt0pyXVBuhph9mYzHLzaonMBx8mFBF+8us7SK79AEed5YeY979jIayupYm
         ETWgUDXQEg4JDSHNo9UMkqmUHHoba55EcTJFSH/T2CYgli8ErYmBXQe/kHwz14eEcYf8
         yoAmSO5P5TL8W2rv3WQld9MAjt0KMmIu2K/DPzxMMdKIpHD/nB+On1Qvg4dr96ILveSh
         yHCZXog1F2tH1UuXiz97U5PW4ewtTX9Jk/votGaDX47HIy6GGpnfrkaLpf74u2+ecwRe
         XbUw==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605;
        h=mime-version:feedback-id:references:in-reply-to:message-id:subject
         :cc:from:to:date:dkim-signature;
        bh=/QiPUfMjOGBBtMETb9i6D8kz9c5nYtIL7jh7qJL9ihg=;
        fh=+67N2uHR2MfeB757DuDnNuhtYMQ1l3OX1mrsWyqvKgo=;
        b=ImS+4+VgJyB+V3hIWHcwLrI5nCieSlymUyktVhTWCXtwbyCKA/5lMlP+4aWVD4KVsA
         fAqlQ2o39emM0spi5vZDfuTzvaYdDRgC+NERSwV4QKxTKgMG17EtJPePgihMzEG18Xm9
         XEZBFA3ZARB+wXZbHyNIjMcnygsgMr7rgb6gNPbSHuZwfu2lJI1LbgPUG4UUqrvVkT6W
         v/ljszzMyZUmuPxhcfgdR+JUD72y0qozWqKgPKuTFly7isr54Eo1S8rgkguKqTvCuy+X
         vXcoBl9cnsfds00MELZzxUlzhtY0plEWO1gpORDgGbPmRZkBx5pZronQjfjv8nmfvfUr
         XNGA==;
        dara=google.com
ARC-Authentication-Results: i=1; gmr-mx.google.com;
       dkim=pass header.i=@proton.me header.s=protonmail header.b=K3nxNkrP;
       spf=pass (google.com: domain of conduition@proton.me designates 185.70.43.16 as permitted sender) smtp.mailfrom=conduition@proton.me;
       dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me
Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch. [185.70.43.16])
        by gmr-mx.google.com with ESMTPS id 2adb3069b0e04-542235fdc30si162367e87.5.2024.12.21.13.52.38
        for <bitcoindev@googlegroups.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Sat, 21 Dec 2024 13:52:38 -0800 (PST)
Received-SPF: pass (google.com: domain of conduition@proton.me designates 185.70.43.16 as permitted sender) client-ip=185.70.43.16;
Date: Sat, 21 Dec 2024 21:52:32 +0000
To: /dev /fd0 <alicexbtong@gmail.com>
From: "'conduition' via Bitcoin Development Mailing List" <bitcoindev@googlegroups.com>
Cc: Bitcoin Development Mailing List <bitcoindev@googlegroups.com>
Subject: Re: [bitcoindev] Censorship and Privacy in Chaumian ecash implementations
Message-ID: <-LMvaPkFoIOkgwJOch3qo7y_ueGgiOSJWqdu0gpv3wSHTunca6AB14V-ZiR4IoDcvIkPTdoQeiy_JigGwl0ei2VpBj2tFyK-GFeE2gXZzXE=@proton.me>
In-Reply-To: <27b19012-20da-46a7-8a84-f90e0070aa77n@googlegroups.com>
References: <27b19012-20da-46a7-8a84-f90e0070aa77n@googlegroups.com>
Feedback-ID: 72003692:user:proton
X-Pm-Message-ID: 2a8365c532abe7b76d69b0f057c7f6043ab27a22
MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/pgp-signature"; micalg=pgp-sha512; boundary="------66d57d1edc68865a41ef4023a808c81655de91a76bd4f380e8fdb7188fd3cb87"; charset=utf-8
X-Original-Sender: conduition@proton.me
X-Original-Authentication-Results: gmr-mx.google.com;       dkim=pass
 header.i=@proton.me header.s=protonmail header.b=K3nxNkrP;       spf=pass
 (google.com: domain of conduition@proton.me designates 185.70.43.16 as
 permitted sender) smtp.mailfrom=conduition@proton.me;       dmarc=pass
 (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me
X-Original-From: conduition <conduition@proton.me>
Reply-To: conduition <conduition@proton.me>
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: -1.0 (-)

This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
--------66d57d1edc68865a41ef4023a808c81655de91a76bd4f380e8fdb7188fd3cb87
Content-Type: multipart/mixed;boundary=---------------------a155cf94aeade0a670509dcd45f46614

-----------------------a155cf94aeade0a670509dcd45f46614
Content-Type: multipart/alternative;boundary=---------------------66f9673fbf1d7758e5b1a52649812bc2

-----------------------66f9673fbf1d7758e5b1a52649812bc2
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="UTF-8"

Hi fd0,

For P2PK, the solution there seems deadly obvious: Just don't use raw unobf=
uscated Nostr keys to receive ecash. Tweak it, or use a new random key. Thi=
s is a non-issue.

As for authentication systems, yes of course KYC-backed authentication woul=
d allow censorship, but that is an optional spec which mints aren't compell=
ed to implement or use, even once the spec is finished. AFAIK no mint imple=
mentations 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 asserti=
on 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 years when perhaps some ecash mint implemen=
tations do=C2=A0implement the authentication spec as a fully-formed feature=
 ready to go...=C2=A0If a mint starts enforcing KYC, or any other badness l=
ike censoring by IP address, users are free to switch to a different non-KY=
C mint instance. At worst they might lose the money they already stored wit=
h 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 exte=
rnal authentication is inherently bad because it encourages/enables=C2=A0KY=
C in the first place, and that ecash devs should refuse to even standardize=
 any protocol which enables KYC.=C2=A0

Well I have hard news for you: Governments don't care about whether complia=
nce is "easy" or "standardized". If uncle sam wants your mint to enforce KY=
C, he won't balk just because the mint's code doesn't provide an easy way t=
o do it. He'll give you a deadline to enforce KYC on your users, and if you=
 can't prove you're compliant by then, you can kiss your business goodbye.

When faced with this choice, the ecash mint runner can either shut down the=
ir mint, or add KYC. Without an authentication system in place already, the=
 mint runner would have to implement it all themselves to enforce KYC and s=
tay in business. So ecash devs have proposed standardized auth systems whic=
h would give mint runners the option of knuckling under to KYC. I agree it =
would suck to be put to that choice, but giving them the freedom to choose =
is important and valid, and in no way compromises the integrity of other no=
n-KYC mints who perhaps operate freely in more enlightened jurisdictions.=
=C2=A0

If it's not part of the NUT standards, and mint runners need it, then someo=
ne will just fork off and add it themselves. Better to pre-empt that and ke=
ep the standards from fragmenting - that's the point of standards.=C2=A0

-c
On Saturday, December 21st, 2024 at 9:58 AM, /dev /fd0 <alicexbtong@gmail.c=
om> wrote:

> Hi Bitcoin Developers,
>=20

> This post is about a myth and some misleading things shared about ecash. =
It is possible to censor specific users and none of the ecash implementatio=
n are censorship resistant.
>=20

> # Censorship Methods in Cashu
>=20

> There are 2 ways to censor individual users in cashu:
>=20

> 1. P2PK
> 2. Authentication
>=20

> ## P2PK
>=20

> Ecash tokens issued by cashu mints can be locked using public keys so tha=
t 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 ke=
ys for it. Most users are doxxed on nostr so they can be censored based on =
their identity. Even if its linked to an anon they can be censored based on=
 their posts.
>=20

> You can find relevant code snippets in [conditions.py][1] if using nutshe=
ll for mint:
>=20

> ```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
> )
>=20

> 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 =
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
> )
>=20

> def _verify_secret_signatures(self, proof, pubkeys, signatures, n_sigs_re=
quired=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 prov=
ided: {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 not met. {n_valid_sigs_per_output} < {n_sigs_required}."
> return True
>=20

> 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
>=20

> 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 secrets_ge=
neric]
> except Exception:
> 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 for secret in p2pk_sec=
rets]):
> 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 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 =
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=
. {n_valid_sigs_per_output} < {n_sigs}."
> return True
>=20

> def _verify_output_spending_conditions(self, proofs, outputs):
> return self._verify_output_p2pk_spending_conditions(proofs, outputs)
> ```
>=20

> ## Authentication
>=20

> Mints can enforce authentication at some point and do KYC for mint, melt,=
 swap etc. Users who refuse to KYC will not be able to use or redeem their =
ecash tokens. Some of the KYCed users can be censored based on their identi=
ty. This would also affect privacy.
>=20

> gandlaf21 agrees this is possible however it is still marketed as censors=
hip resistant.
>=20

> There was some discussion about it in a pull request and supertestnet als=
o shared his thoughts: https://github.com/bitcoinlayers/bitcoinlayers/pull/=
164
>=20

> This whole debate started in May 2024 when cashu's twitter account [annou=
nced][2] that they are considering adding an authentication in the protocol=
 as it is requested by regulated entities.
>=20

> The authentication mechanism is shared in this [pull request][3] which li=
nks each user with linkingkey and it will compromise privacy:
>=20

> ```
> POST https://bob.com/v1/auth
>=20

> Post Data:
> {
> action:"mint",
> k1:"8278e1a48e61c261916791dabb6af760488e4f01932e11fe7054f59754e3de6e"
> signature:c568f78e4b234a5f7d8c3b2a679e48d1234567890abcdef
> linkingKey:7345786068584cd33000582ba87a9ddf77db5377c67910ab59d7e9a5f44
> }
>=20

> Response:
>=20

> HTTP/1.1 200 OK
>=20

> {
> "access_token": "9876543210fedcba",
> "token_type": "Bearer",
> "expires_in": 3600
> }
> ```
>=20

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

> It uses clear and blind auth but users can still be censored with KYC bas=
ed on their identity. You can understand the details from this [comment][4]=
.
>=20

> ## Conclusion
>=20

> The authentication mechanisms shared above are not the only way mints can=
 restrict users as there is nothing in the protocol that stops mints from u=
sing a custom authentication.
>=20

> Introducing KYC in protocol is against freedom and privacy. These custodi=
al solutions might end up being another compliant ecash implementation like=
 [GNU Taler][5]. This would also make it easier for government agencies to =
target other mints that do not comply.
>=20

> [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
>=20

> /dev/fd0
> floppy disk guy
>=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/27b19012-20da-46a7-8a84-f90e0070aa77n%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/=
-LMvaPkFoIOkgwJOch3qo7y_ueGgiOSJWqdu0gpv3wSHTunca6AB14V-ZiR4IoDcvIkPTdoQeiy=
_JigGwl0ei2VpBj2tFyK-GFeE2gXZzXE%3D%40proton.me.

-----------------------66f9673fbf1d7758e5b1a52649812bc2
Content-Type: multipart/related;boundary=---------------------80fdf0bb4bab8bd30c54666135c5ed69

-----------------------80fdf0bb4bab8bd30c54666135c5ed69
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div style=3D"font-family: Arial, sans-serif; font-size: 14px;">Hi fd0,</di=
v><div style=3D"font-family: Arial, sans-serif; font-size: 14px;"><br></div=
><div style=3D"font-family: Arial, sans-serif; font-size: 14px;"><span styl=
e=3D"display: inline !important; background-color: rgb(255, 255, 255);">For=
 P2PK, the solution there seems deadly obvious: Just don't use raw unobfusc=
ated Nostr keys to receive ecash. Tweak it, or use a new random key. This i=
s a non-issue.</span><br></div><div style=3D"font-family: Arial, sans-serif=
; font-size: 14px;"><br></div><div style=3D"font-family: Arial, sans-serif;=
 font-size: 14px;">As for authentication systems, yes of course KYC-backed =
authentication would allow censorship, but that is an optional spec which m=
ints aren't compelled to implement or use, even once the spec is finished. =
AFAIK no mint implementations have this system in code yet, so it's not eve=
n a feature at this point: just a proposed NUT document, sitting in draft s=
tatus. Your assertion that "<span>none of the ecash implementation are cens=
orship resistant" is a blatantly 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-family: Arial, sans-serif; font-size: 14px;">E=
ven if we fast forward several years when perhaps <i>some</i> ecash mint im=
plementations do&nbsp;implement the authentication spec as a fully-formed f=
eature ready to go...&nbsp;If a mint starts enforcing KYC, or any other bad=
ness like censoring by IP address, users are free to switch to a different =
non-KYC mint instance. At worst they might lose the money they already stor=
ed with the compromised mint, which is always a risk to keep in mind with e=
cash.</div><div style=3D"font-family: Arial, sans-serif; font-size: 14px;">=
<span><br></span></div><div style=3D"font-family: Arial, sans-serif; font-s=
ize: 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 fe=
ature spec like external authentication is inherently bad because it encour=
ages/enables&nbsp;KYC in the first place, and that ecash devs should refuse=
 to even standardize any protocol which enables KYC.&nbsp;</div><div style=
=3D"font-family: Arial, sans-serif; font-size: 14px;"><br></div><div style=
=3D"font-family: Arial, sans-serif; font-size: 14px;">Well I have hard news=
 for you: Governments don't care about whether compliance is "easy" or "sta=
ndardized". If uncle sam wants your mint 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 y=
ou a deadline to enforce KYC on your users, and if you can't prove you're c=
ompliant by then, you can kiss your business goodbye.</div><div style=3D"fo=
nt-family: Arial, sans-serif; font-size: 14px;"><br></div><div style=3D"fon=
t-family: Arial, sans-serif; font-size: 14px;">When faced with this choice,=
 the ecash mint runner can either shut down their mint, or add KYC. Without=
 an authentication system in place already, the mint runner would have to i=
mplement it all themselves to enforce KYC and stay in business. So ecash de=
vs have proposed standardized auth systems which would give mint runners th=
e <i>option</i> of knuckling under to KYC. I agree it would suck to be put =
to that choice, but giving them the freedom to choose is important and vali=
d, and in no way compromises the integrity of other non-KYC mints who perha=
ps operate freely in more enlightened jurisdictions.&nbsp;</div><div style=
=3D"font-family: Arial, sans-serif; font-size: 14px;"><br></div><div style=
=3D"font-family: Arial, sans-serif; font-size: 14px;">If it's not part of t=
he NUT standards, and mint runners need it, then someone will just fork off=
 and add it themselves. Better to pre-empt that and keep the standards from=
 fragmenting - that's the point of standards.&nbsp;</div><div style=3D"font=
-family: Arial, sans-serif; font-size: 14px;"><br></div><div style=3D"font-=
family: Arial, sans-serif; font-size: 14px;">-c</div><div class=3D"protonma=
il_quote">
        On Saturday, December 21st, 2024 at 9:58 AM, /dev /fd0 &lt;alicexbt=
ong@gmail.com&gt; wrote:<br>
        <blockquote class=3D"protonmail_quote" 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("pubkeys")<br>        if p2pk_secret.locktime and p2pk_secret.locktim=
e &lt; time.time():<br>            refund_pubkeys =3D p2pk_secret.tags.get_=
tag_all("refund")<br>            if not refund_pubkeys:<br>                =
return True<br>            return self._verify_secret_signatures(<br>      =
          proof, refund_pubkeys, proof.p2pksigs, 1<br>            )<br>    =
    return self._verify_secret_signatures(<br>            proof, pubkeys, p=
roof.p2pksigs, p2pk_secret.n_sigs<br>        )<br><br>    def _verify_htlc_=
spending_conditions(self, proof, secret):<br>        if SecretKind(secret.k=
ind) !=3D SecretKind.HTLC:<br>            return True<br>        htlc_secre=
t =3D HTLCSecret.from_secret(secret)<br>        if htlc_secret.locktime and=
 htlc_secret.locktime &lt; time.time():<br>            refund_pubkeys =3D h=
tlc_secret.tags.get_tag_all("refund")<br>            if refund_pubkeys:<br>=
                return self._verify_secret_signatures(<br>                 =
   proof, refund_pubkeys, proof.p2pksigs, 1<br>                )<br>       =
     return True<br>        assert proof.htlcpreimage, TransactionError("no=
 HTLC preimage provided")<br>        if not hashlib.sha256(bytes.fromhex(pr=
oof.htlcpreimage)).digest() =3D=3D bytes.fromhex(htlc_secret.data):<br>    =
        raise TransactionError("HTLC preimage does not match.")<br>        =
hashlock_pubkeys =3D htlc_secret.tags.get_tag_all("pubkeys")<br>        if =
not hashlock_pubkeys:<br>            return True<br>        return self._ve=
rify_secret_signatures(<br>            proof, hashlock_pubkeys, proof.htlcs=
igs or [], htlc_secret.n_sigs<br>        )<br><br>    def _verify_secret_si=
gnatures(self, proof, pubkeys, signatures, n_sigs_required=3D1):<br>       =
 assert len(set(pubkeys)) =3D=3D len(pubkeys), "pubkeys must be unique."<br=
>        if not signatures:<br>            raise TransactionError("no signa=
tures in proof.")<br>        if len(set(signatures)) !=3D len(signatures):<=
br>            raise TransactionError("signatures must be unique.")<br>    =
    n_sigs_required =3D n_sigs_required or 1<br>        assert n_sigs_requi=
red &gt; 0, "n_sigs must be positive."<br>        assert len(signatures) &g=
t;=3D n_sigs_required, f"not enough signatures provided: {len(signatures)} =
&lt; {n_sigs_required}."<br>        n_valid_sigs_per_output =3D 0<br>      =
  for input_sig in signatures:<br>            for pubkey in pubkeys:<br>   =
             if verify_schnorr_signature(<br>                    message=3D=
proof.secret.encode("utf-8"),<br>                    pubkey=3DPublicKey(byt=
es.fromhex(pubkey), raw=3DTrue),<br>                    signature=3Dbytes.f=
romhex(input_sig),<br>                ):<br>                    n_valid_sig=
s_per_output +=3D 1<br>        assert n_valid_sigs_per_output, "no valid si=
gnature provided for input."<br>        assert n_valid_sigs_per_output &gt;=
=3D n_sigs_required, f"signature threshold not met. {n_valid_sigs_per_outpu=
t} &lt; {n_sigs_required}."<br>        return True<br><br>    def _verify_i=
nput_spending_conditions(self, proof):<br>        try:<br>            secre=
t =3D Secret.deserialize(proof.secret)<br>        except Exception:<br>    =
        return True<br>        if SecretKind(secret.kind) =3D=3D SecretKind=
.P2PK:<br>            return self._verify_p2pk_spending_conditions(proof, s=
ecret)<br>        if SecretKind(secret.kind) =3D=3D SecretKind.HTLC:<br>   =
         return self._verify_htlc_spending_conditions(proof, secret)<br>   =
     return True<br><br>    def _verify_output_p2pk_spending_conditions(sel=
f, proofs, outputs):<br>        try:<br>            secrets_generic =3D [Se=
cret.deserialize(p.secret) for p in proofs]<br>            p2pk_secrets =3D=
 [P2PKSecret.from_secret(secret) for secret in secrets_generic]<br>        =
except Exception:<br>            return True<br>        if not all([SecretK=
ind(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 for secret in p2pk_secrets]):<br>            return True<br>      =
  pubkeys_per_proof =3D [<br>            [p2pk_secret.data] + p2pk_secret.t=
ags.get_tag_all("pubkeys")<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("refund")<=
br>                if refund_pubkeys:<br>                    pubkeys_per_pr=
oof.append(refund_pubkeys)<br>                    n_sigs_per_proof.append(1=
)<br>        if not pubkeys_per_proof:<br>            return True<br>      =
  assert len({tuple(pubs_output) for pubs_output in pubkeys_per_proof}) =3D=
=3D 1, "pubkeys in all proofs must match."<br>        assert len(set(n_sigs=
_per_proof)) =3D=3D 1, "n_sigs in all proofs must match."<br>        pubkey=
s =3D pubkeys_per_proof[0]<br>        n_sigs =3D n_sigs_per_proof[0] or 1<b=
r>        for output in outputs:<br>            p2pksigs =3D output.p2pksig=
s<br>            assert p2pksigs, "no signatures in output."<br>           =
 assert len(set(p2pksigs)) =3D=3D len(p2pksigs), "duplicate signatures in o=
utput."<br>            n_valid_sigs_per_output =3D 0<br>            for sig=
 in p2pksigs:<br>                for pubkey in pubkeys:<br>                =
    if verify_schnorr_signature(<br>                        message=3Dbytes=
.fromhex(output.B_),<br>                        pubkey=3DPublicKey(bytes.fr=
omhex(pubkey), raw=3DTrue),<br>                        signature=3Dbytes.fr=
omhex(sig),<br>                    ):<br>                        n_valid_si=
gs_per_output +=3D 1<br>            assert n_valid_sigs_per_output, "no val=
id signature provided for output."<br>            assert n_valid_sigs_per_o=
utput &gt;=3D n_sigs, f"signature threshold not met. {n_valid_sigs_per_outp=
ut} &lt; {n_sigs}."<br>        return True<br><br>    def _verify_output_sp=
ending_conditions(self, proofs, outputs):<br>        return self._verify_ou=
tput_p2pk_spending_conditions(proofs, outputs)<br>```<br><br>## Authenticat=
ion<br><br>Mints can enforce authentication at some point and do KYC for mi=
nt, melt, swap etc. Users who refuse to KYC will not be able to use or rede=
em their ecash tokens. Some of the KYCed users can be censored based on the=
ir identity. This would also affect privacy.<br><br>gandlaf21 agrees this i=
s possible however it is still marketed as censorship resistant. <br><br>Th=
ere was some discussion about it in a pull request and supertestnet also sh=
ared his thoughts: https://github.com/bitcoinlayers/bitcoinlayers/pull/164<=
br><br>This whole debate started in May 2024 when cashu's twitter account [=
announced][2] that they are considering adding an authentication in the pro=
tocol as it is requested by regulated entities.<br><br>The authentication m=
echanism is shared in this [pull request][3] which links each user with lin=
kingkey and it will compromise privacy:<br><br>```<br>POST https://bob.com/=
v1/auth<br><br>Post Data:<br>{ <br>  action:"mint", <br>  k1:"8278e1a48e61c=
261916791dabb6af760488e4f01932e11fe7054f59754e3de6e"<br>  signature:c568f78=
e4b234a5f7d8c3b2a679e48d1234567890abcdef<br>  linkingKey:7345786068584cd330=
00582ba87a9ddf77db5377c67910ab59d7e9a5f44<br>}<br><br>Response:<br><br>HTTP=
/1.1 200 OK<br><br>{<br>  "access_token": "9876543210fedcba",<br>  "token_t=
ype": "Bearer",<br>  "expires_in": 3600<br>}<br>```<br><br>This pull reques=
t was closed last week and a new authentication mechanism is proposed: http=
s://github.com/cashubtc/nuts/pull/198<br><br>It uses clear and blind auth b=
ut users can still be censored with KYC based on their identity. You can un=
derstand the details from this [comment][4].<br><br>## Conclusion<br><br>Th=
e authentication mechanisms shared above are not the only way mints can res=
trict users as there is nothing in the protocol that stops mints from using=
 a custom authentication.<br><br>Introducing KYC in protocol is against fre=
edom and privacy. These custodial solutions might end up being another comp=
liant ecash implementation like [GNU Taler][5]. This would also make it eas=
ier for government agencies to target other mints that do not comply.<br><b=
r>[1]: https://github.com/cashubtc/nutshell/blob/main/cashu/mint/conditions=
.py<br>[2]: https://x.com/CashuBTC/status/1791001643019809146<br>[3]: https=
://github.com/cashubtc/nuts/pull/106<br>[4]: https://github.com/cashubtc/nu=
ts/pull/198#issuecomment-2508706328<br>[5]: https://taler.net/en/index.html=
<br><br>/dev/fd0<br>floppy disk guy</div>

<p></p>

-- <br>
You received this message because you are subscribed to the Google Groups "=
Bitcoin Development Mailing List" 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" rel=3D"n=
oreferrer nofollow noopener">bitcoindev+unsubscribe@googlegroups.com</a>.<b=
r>
To view this discussion visit <a href=3D"https://groups.google.com/d/msgid/=
bitcoindev/27b19012-20da-46a7-8a84-f90e0070aa77n%40googlegroups.com" target=
=3D"_blank" rel=3D"noreferrer nofollow noopener">https://groups.google.com/=
d/msgid/bitcoindev/27b19012-20da-46a7-8a84-f90e0070aa77n%40googlegroups.com=
</a>.<br>

        </blockquote><br>
    </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/-LMvaPkFoIOkgwJOch3qo7y_ueGgiOSJWqdu0gpv3wSHTunca6AB14V-ZiR4IoDc=
vIkPTdoQeiy_JigGwl0ei2VpBj2tFyK-GFeE2gXZzXE%3D%40proton.me?utm_medium=3Dema=
il&utm_source=3Dfooter">https://groups.google.com/d/msgid/bitcoindev/-LMvaP=
kFoIOkgwJOch3qo7y_ueGgiOSJWqdu0gpv3wSHTunca6AB14V-ZiR4IoDcvIkPTdoQeiy_JigGw=
l0ei2VpBj2tFyK-GFeE2gXZzXE%3D%40proton.me</a>.<br />

-----------------------80fdf0bb4bab8bd30c54666135c5ed69--
-----------------------66f9673fbf1d7758e5b1a52649812bc2--
-----------------------a155cf94aeade0a670509dcd45f46614
Content-Type: application/pgp-keys; filename="publickey - conduition@proton.me - 0x474891AD.asc"; name="publickey - conduition@proton.me - 0x474891AD.asc"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="publickey - conduition@proton.me - 0x474891AD.asc"; name="publickey - conduition@proton.me - 0x474891AD.asc"

LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tCgp4ak1FWkRub0tSWUpLd1lCQkFI
YVJ3OEJBUWRBcnBZYWFjZDgwcXdocmNaQW9VbW9NSHNWS21iZWlPZUEKcFhXbk1ybFdPZkxOSzJO
dmJtUjFhWFJwYjI1QWNISnZkRzl1TG0xbElEeGpiMjVrZFdsMGFXOXVRSEJ5CmIzUnZiaTV0WlQ3
Q2pBUVFGZ29BUGdXQ1pEbm9LUVFMQ1FjSUNaQjRLV3p0aFBhenhRTVZDQW9FRmdBQwpBUUlaQVFL
YkF3SWVBUlloQkVkSWthMENNdHJMZGcxM2EzZ3BiTzJFOXJQRkFBQTZhQUVBM1RmNHdqSVoKYnox
K0diS0h4K09WQytNUXlVdi84RStoWUpjTE5QZnA0NEFBLzNiak5OTXN4WHdJTGZEM0xManNVVWFo
CitBV2JyblVjVUFqQ2R1d3hUT01LempnRVpEbm9LUklLS3dZQkJBR1hWUUVGQVFFSFFDSXYxZW5J
MU5MbAo3Zm55RzlVWk1wQ3ZsdG5vc0JrTmhQUVZxT3BXL3RKSkF3RUlCOEo0QkJnV0NBQXFCWUpr
T2VncENaQjQKS1d6dGhQYXp4UUtiREJZaEJFZElrYTBDTXRyTGRnMTNhM2dwYk8yRTlyUEZBQUFR
TFFEL2NCR2kwUDdwCkZTTkl2N1B6OVpkeUNVQjhzTy90dWZkV3NjQkNZK2ZMYTV3QkFNK0hTL3Jp
S014RGt0TkhLakRGc2EvUgpEVDFxUGNBYXZCaXc2dDZ4Ti9jRgo9Y3d5eAotLS0tLUVORCBQR1Ag
UFVCTElDIEtFWSBCTE9DSy0tLS0tCg==
-----------------------a155cf94aeade0a670509dcd45f46614--

--------66d57d1edc68865a41ef4023a808c81655de91a76bd4f380e8fdb7188fd3cb87
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: ProtonMail

wnUEARYKACcFgmdnOJEJkHgpbO2E9rPFFiEER0iRrQIy2st2DXdreCls7YT2
s8UAAIqWAP9HU3pxAD0+m0fbfUcv3t9etWUV3OxSFQLYugXtz8auTgD9H0bg
imMKuZJO4QQ1cfcqPV3q3viJ8Hntzr7biB8hWQQ=
=cFW/
-----END PGP SIGNATURE-----


--------66d57d1edc68865a41ef4023a808c81655de91a76bd4f380e8fdb7188fd3cb87--