1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
|
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 implement the authentication spec as a fully-formed f=
eature ready to go... 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 KYC in the first place, and that ecash devs should refuse=
to even standardize any protocol which enables KYC. </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. </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. </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 <alicexbt=
ong@gmail.com> 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 < 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 < 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 > 0, "n_sigs must be positive."<br> assert len(signatures) &g=
t;=3D n_sigs_required, f"not enough signatures provided: {len(signatures)} =
< {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 >=
=3D n_sigs_required, f"signature threshold not met. {n_valid_sigs_per_outpu=
t} < {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 < 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 >=3D n_sigs, f"signature threshold not met. {n_valid_sigs_per_outp=
ut} < {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" 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--
|