diff options
-rw-r--r-- | a2/5ccd9f2ed04e6bbc5df4c212e67938bc276315 | 831 |
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 />>=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 />>=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 />>=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 />>=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 />>=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'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'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 "<s= +pan>none of the ecash implementation are censorship resistant" 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'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.</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'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</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 <<a href = +data-email-masked rel=3D"nofollow">alice...@gmail.com</a>> 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("pubkeys")<br> if p2pk_secret.locktime and p2pk_secr= +et.locktime < 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_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 < time.time():<br> = +refund_pubkeys =3D htlc_secret.tags.get_tag_all("refund")<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("no HTLC preimage provided")<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.")<br> hashlock_pubkeys =3D htlc= +_secret.tags.get_tag_all("pubkeys")<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), "pubkeys must be unique."<br> = + if not signatures:<br> raise TransactionError("no signa= +tures in proof.")<br> if len(set(signatures)) !=3D len(signatur= +es):<br> raise TransactionError("signatures must be unique.= +")<br> n_sigs_required =3D n_sigs_required or 1<br> asse= +rt n_sigs_required > 0, "n_sigs must be positive."<br> = +assert len(signatures) >=3D n_sigs_required, f"not enough signature= +s provided: {len(signatures)} < {n_sigs_required}."<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("utf-8"),<= +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, "no valid signature provided for inpu= +t."<br> assert n_valid_sigs_per_output >=3D n_sigs_required,= + f"signature threshold not met. {n_valid_sigs_per_output} < {n_sigs= +_required}."<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("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 < time.time():<br= +> refund_pubkeys =3D p2pk_secret.tags.get_tag_all("refu= +nd")<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, "pubkeys in all proofs must match."<br> a= +ssert len(set(n_sigs_per_proof)) =3D=3D 1, "n_sigs in all proofs must = +match."<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, "no si= +gnatures in output."<br> assert len(set(p2pksigs)) =3D=3D l= +en(p2pksigs), "duplicate signatures in output."<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, "no valid signature provide= +d for output."<br> assert n_valid_sigs_per_output >=3D n= +_sigs, f"signature threshold not met. {n_valid_sigs_per_output} < {= +n_sigs}."<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&q=3Dhttps://github.com/bitcoinlayers/bitcoinl= +ayers/pull/164&source=3Dgmail&ust=3D1734907024882000&usg=3DAOvV= +aw3aVPG8X82bQmUeSO1W3TtU">https://github.com/bitcoinlayers/bitcoinlayers/pu= +ll/164</a><br><br>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.<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&q=3Dhttps://bob.c= +om/v1/auth&source=3Dgmail&ust=3D1734907024882000&usg=3DAOvVaw3o= +TrtvIJYHu1id-3npeyJ3">https://bob.com/v1/auth</a><br><br>Post Data:<br>{ <b= +r> action:"mint", <br> k1:"8278e1a48e61c261916791dabb6af76= +0488e4f01932e11fe7054f59754e3de6e"<br> signature:c568f78e4b234a5f7d8c= +3b2a679e48d1234567890abcdef<br> linkingKey:7345786068584cd33000582ba87a9dd= +f77db5377c67910ab59d7e9a5f44<br>}<br><br>Response:<br><br>HTTP/1.1 200 OK<b= +r><br>{<br> "access_token": "9876543210fedcba",<br> &= +quot;token_type": "Bearer",<br> "expires_in": 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&q=3Dhttps://github.com/cashubtc/nuts/pul= +l/198&source=3Dgmail&ust=3D1734907024882000&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&q=3Dhttps:/= +/github.com/cashubtc/nutshell/blob/main/cashu/mint/conditions.py&source= +=3Dgmail&ust=3D1734907024882000&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&q=3Dhttps://x.com/CashuBTC/status/1791001643019809146&a= +mp;source=3Dgmail&ust=3D1734907024882000&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&q= +=3Dhttps://github.com/cashubtc/nuts/pull/106&source=3Dgmail&ust=3D1= +734907024882000&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&q=3Dhttps://gi= +thub.com/cashubtc/nuts/pull/198%23issuecomment-2508706328&source=3Dgmai= +l&ust=3D1734907024882000&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&q=3Dhttps:/= +/taler.net/en/index.html&source=3Dgmail&ust=3D1734907024882000&= +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" 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&q=3Dhttps://groups.google.com/d/msgid/= +bitcoindev/27b19012-20da-46a7-8a84-f90e0070aa77n%2540googlegroups.com&s= +ource=3Dgmail&ust=3D1734907024882000&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" 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-- + |