پروتکلی برای ساختن شبکهای قابل اعتماد، بر پایهی خودِ واقعیِ ما
پروتکل، در یک صفحه
یک پروتکل، نه یک سکو: قالبهای باز و بردارهای آزمون مشترک که هر پیادهسازی میتواند خودش را با آنها بسنجد.
امروز یک پیادهسازی هست، در پایتون و در مرورگر. آزمون واقعیِ این قالبها یک پیادهسازی دوم و مستقل است. بردارهای پایین برای هماناند.
هر کس 3P خودش (نود) را اجرا میکند. دفترش روی رایانهی خودش میماند. کارت چیزی است که خودش تصمیم میگیرد نشان دهد: بستهای امضاشده از چند یادداشت، از یک چهره، که خودش منقضی میشود. هویت با گم شدن کلید از بین نمیرود. یک سازمان میتواند یک یادداشت را با کلیدی که روی دامنهی خودش منتشر کرده تأیید کند. دستیارها از راه MCP وصل میشوند و برای هر کار اجازهی جداگانه لازم دارند.
قالبها
هر شیء شناسهی قالبش را با خود دارد. هر کدام به پروندهای پیوند دارد که آن را دقیق تعریف میکند: یک پروندهی بردار آزمون مشترک (ورودیها با خروجی دقیقی که هر بررسیکننده باید بدهد) یا یک JSON Schema.
| قالب | برای چیست | تعریف در |
|---|---|---|
3p.card/1 | کارت: یادداشتهایی از یک چهره، با امضای خود آدم، که خودش منقضی میشود. | vectors.json |
3p.identity/1 | آغاز یک هویت: کلید نخست، و کلید بازیابی که با اثر انگشتش از همان اول تعهد شده است. | chains.json |
3p.rotate/1 | هویت را به کلید تازه میبرد. کلید قدیم امضا میکند و کلید تازه میپذیرد. | chains.json |
3p.recover/1 | کلید گمشده یا دزدیدهشده را با امضای کلید بازیابیِ کاغذی جایگزین میکند. آن کلید فقط کلید عوض میکند و هرگز کارت امضا نمیکند. | chains.json |
3p.salience/1 | آنچه حالا مهم است: بهروزرسانیِ امضاشدهای که جای قبلی را میگیرد و خودش کهنه میشود. | salience.json |
3p.domain-keys/1 | پروندهی کلید یک سازمان، در https://<domain>/.well-known/3p-keys.json. | پروندهی نمایشیِ همین سایت · امضای تأیید |
3p.countersign/1 | امضای یک سازمان روی اثر محتوای یک یادداشت، پیش از آنکه آدم کارت را امضا کند. | countersign.json |
3p.head/1 | طول یک دفتر و هشِ انتهای آن، که به کسی که میبینید نشان داده میشود تا گواهیاش کند. هش هر یادداشت نمک دارد؛ چیز خواندنیای در آن نیست. | proof_vectors.json |
3p.witness/1 | امضای کس دیگری روی انتهای دفتر شما: «این دفتر را با این طول دیدم». written_before در کارت با آن ثابت میکند یادداشتی از پیش آنجا بوده است. | proof_vectors.json |
3p.withdraw/1 | کارت منتشرشده را از دفتر جمعی پس میگیرد. | هنوز بردار مشترکی ندارد |
3p.capture/1 | یک ثبت: آنچه در لحظهی نوشتن رخ داد، و یادداشتهایی که به آن ارجاع میدهند. پایینتر را ببینید. | capture.schema.json |
| قاعده (constraint) | یک «هرگز انجام نده» یا «هرگز نگو»، آنطور که درون کارت میرود. | constraint.schema.json |
پروندههای بردار فقط نیمهی عمومیِ کلیدهای آزمون را دارند و هیچکس را شناسایی نمیکنند.
شکل متعارف
امضا روی بایتهاست، پس هر پیادهسازی باید یک شیء را به همان بایتها تبدیل کند. قاعدهها:
- کلیدها به ترتیب واحد کد UTF-16، همانطور که
sort()در جاوااسکریپت مرتب میکند. این ترتیب نقطهی کد نیست: بالای U+FFFF این دو فرق دارند (بردارkey-order-astral). - بیفاصله، و رشتهها بهصورت UTF-8 خام، هرگز با
\u. نیمفاصلههای فارسی همانطور میمانند (بردارpersian-zwnj). - بیعدد اعشاری. پایتون
1.0مینویسد و جاوااسکریپت1، پس عدد اعشاری در این دو جور دیگری امضا میشود. امضاکننده آن را رد میکند. - بیعدد صحیحِ ناامن. هر عددی بیرون از ±(253 − 1) رد میشود، چون جاوااسکریپت نمیتواند دقیق نگهش دارد.
- امضا ECDSA P-256 با SHA-256 است، روی شکل متعارف بدون
proof.sig، و بهصورتr‖sخام با base64url نوشته میشود. - Low-S. اگر
(r, s)درست باشد،(r, n − s)هم درست است و هر کسی بیکلید میتواند آن را بسازد. امضاکننده فقط شکل پایین را میدهد. بررسیکنندهها هر دو را میپذیرند، پس بایتهای امضا هرگز چیزی را شناسایی نمیکنند (بردارهایlow-sوhigh-s). - اثر محتوا شناسه است: SHA-256 شکل متعارف بدون
proof.sig. هیچکس بیکلید نمیتواند تغییرش دهد. subjectاثر انگشت RFC 7638 کلید نخستِ هویت است.
{"b":1,"a":[{"z":null,"y":true}],"_":3,"B":2}
→ {"B":2,"_":3,"a":[{"y":true,"z":null}],"b":1}
→ sha256 c75679b877c2402654baf84f2bf8d139567306febef9bcdfa4f9873a18a0b687
بررسی یک کارت
- کارت را بگیرید،
proof.sigرا بردارید و بقیه را به شکل متعارف بنویسید. - امضا را با
proof.keyبسنجید. امضای کوتاه، بلند، صفر یا بدشکل یعنی بررسیِ ناموفق، هرگز از کار افتادن. - بسنجید که کلید از طرف
subjectحرف میزند: با اثر انگشتش، یا با زنجیرهای درست از جابهجاییها و بازیابیها از کلید نخست. - تاریخها را بسنجید:
issued،expiresو تاریخ هر تغییر کلید. - برای هر امضای تأیید، پروندهی کلید آن دامنه را بگیرید و بسنجید، همانطور که در صفحهی امضای تأیید آمده است.
سه پاسخ هست و هرگز دو تا نمیشود: درست (با نامی که ذخیره کردهاید، یا امضاکنندهی ناشناس)، و نادرست.
هر کسی میتواند امضای یک کارت را در مرورگر خودش بررسی کند.
بررسیکننده به هر ورودیای پاسخ میدهد و فقط آنچه امضا شده را میپذیرد.
پیادهسازی خودتان را با بردارهای کارت، زنجیرههای هویت، امضاهای تأیید و آنچه حالا مهم است بسنجید. هر حالت ورودی را میدهد و پاسخی را که باید بدهد. بررسیکنندهی پایتون و بررسیکنندهی مرورگر، در Chromium، Firefox و WebKit، روی همین پروندهها اجرا شدهاند.
بررسیکننده در مرورگر خودتان اجرا میشود. دو جور چیز میگیرد: نمونههای همین سایت، وقتی یکی را امتحان میکنید، و پروندهی کلید هر دامنهای که کارت میگوید آن را تأیید کرده است.
رابط دستیار
دستیار با 3P یک نفر از راه MCP حرف میزند (JSON-RPC روی stdio، بینیاز به SDK). یک چهره را به نام میخواهد و فقط همان را میگیرد.
claude mcp add 3p -- python3 /absolute/path/to/mcp_server.py
دستیار تو نیست. پیش از خواندن اجازه میگیرد، و هر کار را جداگانه اجازه میدهی: خواندن، نوشتن، امضا، انتشار.
این برای دستیارهایی است که از راه 3P میآیند. نرمافزاری که با حساب خودت روی رایانهات اجرا میشود، میتواند پروندهی دفترت را مستقیم بخواند.
هر اجازه (grant) برای یک دستیار، یک چهره، چند سطح باز بودن و مدتی معیّن است، و کارهایش را نام میبرد: read، log، sign، publish. read همیشه هست؛ بقیه باید نام برده شوند.
| ابزار | چه میکند | اجازهی لازم |
|---|---|---|
list_scopes | چهرههایی که این 3P ارائه میدهد | read |
get_persona | ترجیحها، قاعدهها و زمینهی یک چهره، با خلاصهای از یادداشتهایش | read |
search_facts | جستوجو در یادداشتهای یک چهره | read |
attested_facts | فقط یادداشتهایی که کس دیگری تأییدشان کرده | read |
get_salience | آنچه حالا مهم است، در یک چهره | read |
published | آنچه منتشر شده، و اینکه زنده است، منقضی شده یا پس گرفته شده | read |
withdraw | پس گرفتن کارت منتشرشده | read: پس گرفتن همیشه فقط کمتر نشان میدهد |
log | نوشتن یادداشت با کلمات خود آدم، با نشانِ «رساندهشده به دست دستیار» | log |
correct | اصلاح یک یادداشت؛ متن قبلی نگه داشته میشود | log |
mint_packet | امضای یک کارت برای یک چهره | sign |
mint_salience | امضای بهروزرسانیِ آنچه حالا مهم است | sign |
publish | انتشار بخش بازِ یک چهره در دفتر جمعی | publish |
python3 consent.py requests # what asked, and was refused
python3 consent.py grant claude-code work --tiers public --for 1h
python3 consent.py grant claude-code work --for 8h --allow log,publish
python3 consent.py revoke 3
بیاجازهی زنده، درخواست رد میشود و برای اینکه خود آدم ببیند ثبت میشود. هر فراخوانی ثبت میشود، چه اجازه داشته باشد چه نه. private را به هیچ چیز نمیشود اجازه داد.
دستیار هرگز نمیتواند اجازهای را که دادی گستردهتر کند.
نام یک کلاینت MCP همان است که خودش میگوید. اجازه مرزی است در برابر نرمافزاری که بیپرسش کاری بکند؛ ثابت نمیکند کدام نرمافزار میپرسد.
قرارداد ثبت: 3p.capture/1
آنچه یک 3P بیرون میدهد، و آنچه ابزار دیگری (یک برنامهی ثبت، یک آینه) میتواند به آن بدهد. دو فهرست دارد:
- acts: آنچه در لحظهی ثبت رخ داد. هر کدام نوعی دارد (
typed،voice،photo،import،relayed،unrecorded)، زمانی، دستگاهی و SHA-256 محتوایش. صدا یا عکس اثر رسانهاش را دارد. واردکردن، منبعش را نام میبرد و رساندهشده، دستیار را. - facts: یادداشتها. هر کدام به یک act ارجاع میدهد و تاریخهایش، سطح باز بودنش (که از
privateشروع میشود) و برچسبهایش را دارد.
بیرون از schema، بررسیِ انطباق این را هم میسنجد: هر fact به actی در همان سند ارجاع میدهد، شناسهها یکتا هستند، و هیچ فیلدی از آینه در هیچ عمقی نیست. آینه هرگز جابهجا نمیشود.
{"format": "3p.capture/1", "exported_at": "2026-10-19T09:00:00Z",
"acts": [{"id": "act:fixture05", "kind": "relayed", "captured_at": "2026-10-16T10:00:00Z",
"device": "mcp", "relayed_by": "claude-code",
"content_sha256": "28fea5dcc347d363cc771873322e9e66b4e8e17ada0c2ac0d624c03991c2d2f0"}],
"facts": [{"id": "fact:5", "text": "Load-tested retries at 5x #work", "occurred": "2026-10-16",
"recorded": "2026-10-16T10:00:00Z", "entry_mode": "live", "act": "act:fixture05",
"share_tier": "private", "tags": []}]}
schema. این نمونه از آزمونهاست و ساختگی است.
آنچه هنوز در پروتکل نیست
- ساعت. ترتیب ثابت میشود: دفتر شما یک زنجیر است و کسانی که میبینید میتوانند گواهیاش کنند (
3p.witness/1)، پس یک یادداشت میتواند ثابت کند پیش از یک دیدار آنجا بوده، بیآنکه به ساعت یا سروری اعتماد لازم باشد. زمان دقیق ثابت نمیشود: هر تاریخی در کارت هنوز از ساعت خود امضاکننده است. اگر روزی تاریخی در حد دادگاه لازم شد، میشود بعدها هش روزانهی همه را جایی عمومی ثبت کرد. - رمزگذاری دفتر به دست خود 3P. دفتر یک پروندهی سادهی SQLite در
~/.3pاست و کلید نود پروندهای کنار آن. 3P آنها را رمزگذاری نمیکند. اگر رمزگذاری دیسکِ سیستمعاملتان (روی مک، FileVault) روشن باشد، و با مجوزهای پرونده، محافظت میشوند. - امضای تأیید با passkey برای افراد، و نگه داشتن کلید در سختافزار. طراحی شده، ساخته نشده.
- پیادهسازی دوم. همهی آنچه اینجاست فقط با خودش سنجیده شده، در پایتون و در مرورگر.