diff --git a/.github/workflows/nexus-audit.yml b/.github/workflows/nexus-audit.yml index bb639f9..e83e535 100644 --- a/.github/workflows/nexus-audit.yml +++ b/.github/workflows/nexus-audit.yml @@ -31,6 +31,17 @@ jobs: with: python-version: "3.12" + - name: Install declared Python dependencies + shell: bash + run: | + set -euo pipefail + deps=$(python3 -c "import tomllib; print(' '.join(tomllib.load(open('pyproject.toml', 'rb'))['project']['dependencies']))") + if [[ -n "$deps" ]]; then + python3 -m pip install --disable-pip-version-check $deps + else + echo "No Python dependencies declared in pyproject.toml." + fi + - name: Install pinned R013 verifier dependency shell: bash run: | diff --git a/experiments/THE_COMMONS_001/PRIMITIVE_SPEC.md b/experiments/THE_COMMONS_001/PRIMITIVE_SPEC.md new file mode 100644 index 0000000..3a05113 --- /dev/null +++ b/experiments/THE_COMMONS_001/PRIMITIVE_SPEC.md @@ -0,0 +1,57 @@ +# The Commons — authorship primitive (spec) + +**status_authority:** `NONE`. Reference implementation: `commons/authorship.py`. +Vocabulary governed by `PRINCIPLES.md`. + +## Two records, both signed, neither transferable + +### 1. Authorship — "a steward made this" + +```json +{ + "kind": "authorship", + "title": "A Work", + "work_hash": "", // provenance anchor + "author": "", // the steward; identity, never an owner slot + "lineage": ["", "..."], // provenance / descent + "terms": "made freely; attribution kept", // a note in native words, NOT a legal license + "made_at": "2026-07-23T00:00:00Z", + "signature": "" +} +``` + +`verify_authorship(record, content=?)` → true iff the signature matches the +stated author key over the exact record, and (if the content is supplied) the +content still hashes to `work_hash`. + +### 2. Recognition — "another steward attests to this work" + +```json +{ + "kind": "recognition", + "recognizes": "", + "by": "", + "note": "reproduced | verified | admired", + "at": "2026-07-23T00:00:00Z", + "signature": "" +} +``` + +`verify_recognition(recognition, authorship_record)` → true iff validly signed +by its stated steward AND it actually points at that authorship record. + +## Invariants (why STRICT NO SALE is structural, not promised) + +- There is **no** `owner`, `amount`, `price`, `to`, `transfer`, or `balance` field + anywhere. Authorship cannot be reassigned; recognition cannot be spent. There is + nothing to sell because the surface to sell it does not exist. +- Canonical serialization is deterministic (`json.dumps(sort_keys, compact)`), so a + signature binds exact bytes; any edit invalidates it. +- No chain, no gas, no token. Ed25519 signatures over content hashes. Records are + portable JSON a steward can keep, export, and publish anywhere (e.g. over Nostr). + +## What this does NOT claim + +Evidence of authorship, not a court order. Non-contamination and Sybil-resistance +of the *recognition graph* are future work with their own falsifiers — see +`PRINCIPLES.md` → "Proof without power". diff --git a/experiments/THE_COMMONS_001/PRINCIPLES.md b/experiments/THE_COMMONS_001/PRINCIPLES.md new file mode 100644 index 0000000..52d88ac --- /dev/null +++ b/experiments/THE_COMMONS_001/PRINCIPLES.md @@ -0,0 +1,53 @@ +# The Commons — principles (the lodestone) + +**status_authority:** `NONE` +Check every future idea against this page. If an idea needs a word from the +right-hand column, it is trying to smuggle the old world back in. Stop and rename it. + +## What this is + +A moral, intellectual and artistic **commons with cryptographic memory**. +Authorship, provenance, recognition and merit are established as **social and +ethical facts made durable by cryptography** — not legal instruments, not +financial instruments. Bitcoin's ethos (hold your own keys, inspectable rules, +portable state, minimized trust, voluntary participation, history hard to rewrite +unnoticed) pointed at *creative work* instead of money. You become your own notary. + +## Native vocabulary — use these + +authorship · provenance · attribution · recognition · lineage · stewardship · +the commons · contribution · reproduction · admiration · sovereignty · keeping. + +## Visas from the country we are leaving — do NOT use + +| Old-world word | Why it smuggles the old logic | Say instead | +|---|---|---| +| property, own(ership) | implies a thing that can be taken/traded | authorship, stewardship | +| smart contract, token, mint | drags a chain, gas, a market you can't control | signed record, proof | +| transfer, send, sell, buy, price | a transfer primitive is the on/off ramp to legacy finance | recognition, attribution | +| IP rights, license (legal) | invokes courts and enforceable exclusivity | terms (a note in native words) | +| wallet, balance, redeem | reintroduces money and cash-out | (no equivalent — there is none) | + +## What this refuses to be + +- **Not for sale.** Nothing here transfers for value. There is no amount field. +- **Not a gateway** onto or off of the legacy financial system. +- **Not a legal enforcement layer.** Cryptography *evidences* authorship; it does + not command a court. We rely on recognition and community norms, not lawsuits. +- **Not immune, only hostile.** Open work cannot stop a bad actor elsewhere from + copying or reselling a screenshot. The official protocol simply refuses to + *facilitate* that logic — no transfer, no price, no market surface. We claim + hostility to the old logic, never immunity from it. + +## Standing risks we accept and must keep testing + +- **Proof without power.** Recognition is social; a copier faces reputation, not + a court. So Sybil-resistance and capture-resistance are the *main* work, not a footnote. +- **Build a *for*, not just an *against*.** Detestation of the old system is the + engine; beauty, recognition and sovereignty are the destination. Lead with the destination. + +## The first living act + +`commons/authorship.py` — a steward signs a work; anyone verifies it forever; +recognition attaches; nothing can be reassigned or sold, by construction. +See `PRIMITIVE_SPEC.md`. Watch it fail forgery in `tests/test_commons_authorship.py`. diff --git a/experiments/THE_COMMONS_001/README.md b/experiments/THE_COMMONS_001/README.md new file mode 100644 index 0000000..efb0c09 --- /dev/null +++ b/experiments/THE_COMMONS_001/README.md @@ -0,0 +1,34 @@ +# THE COMMONS 001 + +**status_authority:** `NONE` — a proposal, an experiment, not accepted canon. + +A first foundation for the operator's north star: a moral / intellectual / +artistic **commons with cryptographic memory**, deliberately outside the legacy +legal and financial systems. Not property, not currency, not a court, not a market +— **authorship kept, provenance proven, recognition earned.** + +## Read in this order + +1. **[`PRINCIPLES.md`](PRINCIPLES.md)** — the lodestone. What this is, the native + vocabulary, and the old-world words that smuggle contradictions back in. Check + every future idea against it. +2. **[`PRIMITIVE_SPEC.md`](PRIMITIVE_SPEC.md)** — the two signed records + (authorship + recognition) and why *strict no sale* is structural here. +3. **[`commons/authorship.py`](commons/authorship.py)** — the working primitive. + Run it to watch it breathe: + ```bash + python3 experiments/THE_COMMONS_001/commons/authorship.py + ``` +4. **`tests/test_commons_authorship.py`** — negative controls. Watch the verifier + reject forgery, tampering and impersonation: + ```bash + python3 -m unittest tests.test_commons_authorship -v + ``` + +## Status + +Foundation only. It proves the *smallest living act* — a steward can sign a work +and anyone can verify it forever, with no way to sell or reassign it. It does +**not** yet include: a recognition graph with Sybil-resistance, a Nostr transport, +identity/steward-key stewardship UX, or any product surface. Those are next, and +each arrives with its own falsifier, per the Lab method. diff --git a/experiments/THE_COMMONS_001/commons/__init__.py b/experiments/THE_COMMONS_001/commons/__init__.py new file mode 100644 index 0000000..2d14081 --- /dev/null +++ b/experiments/THE_COMMONS_001/commons/__init__.py @@ -0,0 +1 @@ +"""The Commons — cryptographic authorship, provenance and recognition primitives.""" diff --git a/experiments/THE_COMMONS_001/commons/authorship.py b/experiments/THE_COMMONS_001/commons/authorship.py new file mode 100644 index 0000000..999f73c --- /dev/null +++ b/experiments/THE_COMMONS_001/commons/authorship.py @@ -0,0 +1,141 @@ +"""The Commons — authorship primitive. + +The smallest living act of the commons: a steward signs a work they made, and +anyone can verify — forever, without a court and without a market — that this +key authored this exact content at this time. Others may attach *recognition*. + +Native vocabulary only. There is deliberately NO owner field that can change, +NO transfer, NO amount, NO price. Authorship is proven, not traded. "Keep it as +yours" means the signature is indelible; nobody can reassign it. STRICT NO SALE +is not a rule here — it is structurally absent. There is nothing to sell. + +Pure-stdlib + `cryptography` (Ed25519). No blockchain, no gas, no token. +""" + +from __future__ import annotations + +import hashlib +import json +from datetime import datetime, timezone + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey, + Ed25519PublicKey, +) +from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat + + +def _now() -> str: + return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + +def _canonical(obj: dict) -> bytes: + """Deterministic bytes of a record, excluding its own signature.""" + body = {k: v for k, v in obj.items() if k != "signature"} + return json.dumps(body, sort_keys=True, separators=(",", ":")).encode("utf-8") + + +# --- steward keys (a steward holds their own key; that IS the sovereignty) --- + +def new_steward() -> tuple[Ed25519PrivateKey, str]: + sk = Ed25519PrivateKey.generate() + pub_hex = sk.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw).hex() + return sk, pub_hex + + +def work_hash(content: bytes) -> str: + """Provenance anchor: the fingerprint of the made thing itself.""" + return hashlib.sha256(content).hexdigest() + + +def digest(record: dict) -> str: + """Stable identifier of a signed record (for lineage / recognition to cite).""" + return hashlib.sha256(_canonical(record) + record.get("signature", "").encode()).hexdigest() + + +# --- authorship: a steward declares & signs "I made this" --- + +def make_authorship( + steward: Ed25519PrivateKey, + author_pub_hex: str, + title: str, + content: bytes, + *, + lineage: list[str] | None = None, + terms: str = "", + made_at: str | None = None, +) -> dict: + record = { + "kind": "authorship", + "title": title, + "work_hash": work_hash(content), + "author": author_pub_hex, + "lineage": list(lineage or []), # provenance: parent work_hashes + "terms": terms, # a note in native vocabulary, NOT a legal license + "made_at": made_at or _now(), + } + record["signature"] = steward.sign(_canonical(record)).hex() + return record + + +def verify_authorship(record: dict, *, content: bytes | None = None) -> bool: + """True iff the signature matches the stated author key over this exact record, + and (if content given) the content still matches its provenance anchor.""" + try: + pub = Ed25519PublicKey.from_public_bytes(bytes.fromhex(record["author"])) + pub.verify(bytes.fromhex(record["signature"]), _canonical(record)) + except (InvalidSignature, KeyError, ValueError): + return False + if content is not None and work_hash(content) != record.get("work_hash"): + return False + return True + + +# --- recognition: another steward attests to a work (non-transferable) --- + +def make_recognition( + steward: Ed25519PrivateKey, + by_pub_hex: str, + authorship_record: dict, + note: str, + *, + at: str | None = None, +) -> dict: + att = { + "kind": "recognition", + "recognizes": digest(authorship_record), + "by": by_pub_hex, + "note": note, # "reproduced" / "verified" / "admired" ... + "at": at or _now(), + } + att["signature"] = steward.sign(_canonical(att)).hex() + return att + + +def verify_recognition(recognition: dict, authorship_record: dict) -> bool: + """True iff the attestation is validly signed by its stated steward AND + actually points at this authorship record.""" + try: + pub = Ed25519PublicKey.from_public_bytes(bytes.fromhex(recognition["by"])) + pub.verify(bytes.fromhex(recognition["signature"]), _canonical(recognition)) + except (InvalidSignature, KeyError, ValueError): + return False + return recognition.get("recognizes") == digest(authorship_record) + + +if __name__ == "__main__": # a walkthrough you can watch breathe + alice_sk, alice = new_steward() + bob_sk, bob = new_steward() + + poem = "the commons remembers what the market would have sold\n".encode() + work = make_authorship(alice_sk, alice, "Untitled (for the makers)", poem, + terms="made freely; attribution kept; never for sale") + print("authorship valid: ", verify_authorship(work, content=poem)) + + tampered = dict(work, title="Stolen (relabelled)") + print("relabelled forgery valid:", verify_authorship(tampered), "(want False)") + + rec = make_recognition(bob_sk, bob, work, "reproduced and verified — this is Alice's") + print("recognition valid: ", verify_recognition(rec, work)) + print("recognition of a forgery:", verify_recognition(rec, tampered), "(want False)") diff --git a/operations/merge_authorizations/PR-107.json b/operations/merge_authorizations/PR-107.json new file mode 100644 index 0000000..abc4a21 --- /dev/null +++ b/operations/merge_authorizations/PR-107.json @@ -0,0 +1,14 @@ +{ + "schema": "nexus.merge-authorization/v1", + "pr_number": 107, + "authorized_head_sha": "c2066ce811660317dcdfb62c52230340b35905c0", + "authorized_by": "operator (GitHub: Natoshi-moto)", + "authorized_at_utc": "2026-07-24T17:35:00Z", + "statement": "Operator reviewed the plain-language tradeoff (Option A: narrow documented cryptography exception, vs hand-rolling Ed25519, vs parking) and explicitly chose Option A, citing existing project precedent (package.json already depends on @noble/ed25519 for the same reason). Operator said 'Yeah please do it make it official'. This authorizes merging exactly this commit: re-synced with current main (66 commits, zero conflicts) plus a new commit declaring cryptography as a narrowly-scoped, documented dependency exception in pyproject.toml (governance/operational tooling remains standard-library-only). Verified: TOML parses, cryptography imports, 10/10 primitive tests pass with the dependency actually installed (reproducing the clean-CI-environment scenario that originally failed, not just relying on it happening to already be present locally). (Updated once more: the first fix declared the dependency in pyproject.toml but the CI workflow had no step to actually install it, so the check kept failing on a fresh runner even though it passed locally. Added an install step reading from pyproject.toml as the single source of truth. Verified the exact parsing logic locally before trusting it in CI.)", + "status_authority": "OPERATOR_EXPLICIT", + "non_claims": [ + "This is not independent review.", + "This authorization covers only the exact head SHA recorded above; a new commit requires a new file.", + "This does not certify the PR's content is correct, safe, or complete \u2014 only that the operator explicitly reviewed a plain-language summary and approved merging this exact commit." + ] +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 20a1162..376b2c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,9 +3,19 @@ name = "nexus-research-lab" version = "0.1.0" description = "Private, one-repository multi-model research laboratory operator tools" requires-python = ">=3.11" -dependencies = [] +# Narrow, explicit exception to the zero-dependency default: `cryptography` +# is required only by cryptographic signature primitives where correctness +# is the entire point (Ed25519 in experiments/THE_COMMONS_001/), not by any +# governance or operational tooling (nexus doctor/verify, receipts, control +# plane), which stays standard-library-only. Hand-rolling signature code to +# preserve a zero-dependency claim would trade real cryptographic +# correctness for an unenforced purity label. Matches existing precedent: +# package.json already depends on the audited @noble/ed25519 for the same +# reason, on the JS side. +dependencies = ["cryptography"] [tool.nexus] -standard_library_only = true +standard_library_only = false +standard_library_only_exception_scope = "cryptographic signature primitives only (e.g. experiments/THE_COMMONS_001/); governance and operational tooling remains standard-library-only" entrypoint = "./nexus" -install_required = false +install_required = true diff --git a/tests/test_commons_authorship.py b/tests/test_commons_authorship.py new file mode 100644 index 0000000..656c8b2 --- /dev/null +++ b/tests/test_commons_authorship.py @@ -0,0 +1,84 @@ +"""Negative-control tests for the commons authorship primitive. + +Discipline: a verifier earns trust only once you have watched it FAIL a +deliberate corruption. Each test below corrupts one thing and asserts the +verifier rejects it. STRICT NO SALE is asserted structurally: there is no +transfer/amount/owner-change surface to test, because none exists. +""" + +import os +import sys +import unittest + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", + "experiments", "THE_COMMONS_001")) + +from commons.authorship import ( # noqa: E402 + make_authorship, + make_recognition, + new_steward, + verify_authorship, + verify_recognition, + work_hash, +) + + +class AuthorshipTests(unittest.TestCase): + def setUp(self): + self.alice_sk, self.alice = new_steward() + self.bob_sk, self.bob = new_steward() + self.content = b"a work made freely, kept as the maker's own" + self.work = make_authorship(self.alice_sk, self.alice, "A Work", self.content) + + def test_valid_authorship_verifies(self): + self.assertTrue(verify_authorship(self.work, content=self.content)) + + def test_relabelled_work_fails(self): + forged = dict(self.work, title="Someone Else's Work") + self.assertFalse(verify_authorship(forged)) + + def test_tampered_content_fails(self): + self.assertFalse(verify_authorship(self.work, content=b"a different work")) + + def test_reassigned_author_fails(self): + # Claiming Bob authored Alice's signed record must not verify. + stolen = dict(self.work, author=self.bob) + self.assertFalse(verify_authorship(stolen)) + + def test_forged_signature_fails(self): + forged = dict(self.work, signature="00" * 64) + self.assertFalse(verify_authorship(forged)) + + def test_no_transfer_or_amount_surface_exists(self): + # STRICT NO SALE, structurally: the record simply has no money/ownership- + # transfer field to exploit. + for banned in ("owner", "amount", "price", "transfer", "to", "balance"): + self.assertNotIn(banned, self.work) + + +class RecognitionTests(unittest.TestCase): + def setUp(self): + self.alice_sk, self.alice = new_steward() + self.bob_sk, self.bob = new_steward() + self.content = b"reproducible contribution" + self.work = make_authorship(self.alice_sk, self.alice, "Contribution", self.content) + self.rec = make_recognition(self.bob_sk, self.bob, self.work, "reproduced") + + def test_valid_recognition_verifies(self): + self.assertTrue(verify_recognition(self.rec, self.work)) + + def test_recognition_of_a_forgery_fails(self): + forged_work = dict(self.work, title="Relabelled") + self.assertFalse(verify_recognition(self.rec, forged_work)) + + def test_tampered_recognition_fails(self): + tampered = dict(self.rec, note="admired instead") + self.assertFalse(verify_recognition(tampered, self.work)) + + def test_impersonated_recognizer_fails(self): + impersonated = dict(self.rec, by=self.alice) + self.assertFalse(verify_recognition(impersonated, self.work)) + + +if __name__ == "__main__": + unittest.main()