Skip to content

Commit e7a67d2

Browse files
Merge pull request #8 from quantumpipes/security-and-chain-verification
2 parents 8a40f2b + 74c1478 commit e7a67d2

File tree

8 files changed

+405
-16
lines changed

8 files changed

+405
-16
lines changed

CHANGELOG.md

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1313

1414
## [1.2.0] - 2026-03-08
1515

16-
Protocol-first restructure, TypeScript implementation, finalized URI scheme, and full CapsuleType conformance.
16+
Protocol-first restructure, TypeScript implementation, finalized URI scheme, full CapsuleType conformance, Security Considerations in spec, cryptographic chain verification, and 11-framework compliance directory.
1717

1818
### Changed
1919

@@ -24,19 +24,30 @@ Protocol-first restructure, TypeScript implementation, finalized URI scheme, and
2424
- Protocol documentation at `docs/` (language-agnostic)
2525
- Python-specific docs at `reference/python/docs/`
2626
- No `pyproject.toml` at repo root — the repo is a protocol, not a package
27+
- **Compliance restructured into per-framework directory**`docs/compliance.md` replaced by `docs/compliance/` with individual documents per framework and a README index.
2728

2829
### Added
2930

30-
- **`capsule://` URI scheme (Active)** — content-addressable references to Capsule records via their SHA3-256 hash. Spec at `spec/uri-scheme.md`, finalized from Draft to Active. Supports hash references (`capsule://sha3_<hash>`), chain references (`capsule://chain/42`), ID references, and fragment syntax into the 6 sections. Includes URI conformance vectors at `conformance/uri-fixtures.json`.
31-
- **TypeScript reference implementation**full CPS-conformant implementation at `reference/typescript/`: Capsule model with factories, canonical JSON serializer (CPS Section 2 with float-path handling), SHA3-256 hashing, Ed25519 seal/verify, and chain verification. Passes all 16 golden fixtures. 101 tests, 100% coverage (v8). Uses `@noble/hashes` ^2.0.1, `@noble/ed25519` ^3.0.0, vitest ^4.0.0, TypeScript ^5.9.0. Node.js >= 20.19.0.
32-
- **Implementor's Guide** (`docs/implementors-guide.md`) — step-by-step instructions for building a conformant CPS implementation in any language, with language-specific pitfalls for TypeScript, Go, and Rust.
33-
- **Why Capsules** (`docs/why-capsules.md`) — the case for cryptographic AI memory, aimed at decision-makers and architects.
34-
- **URI scheme security considerations**`spec/uri-scheme.md` includes: URI injection validation, resolution trust model, denial-of-service mitigations, fragment path traversal safety, no ambient authority principle.
31+
- **Security Considerations in CPS spec** (`spec/README.md` Section 7) — documents what CPS provides (integrity, authenticity, non-repudiation, ordering, quantum resistance) and what it does not (confidentiality, truthfulness, availability, identity binding). Covers signer key compromise, chain truncation, verification levels, replay, and timestamp trust.
32+
- **Cryptographic chain verification**`chain.verify(verify_content=True)` recomputes SHA3-256 from content and compares to stored hash. `chain.verify(seal=seal_instance)` also verifies Ed25519 signatures. Both Python and TypeScript implementations. Default structural-only behavior is unchanged (backward compatible).
33+
- **11-framework compliance directory** (`docs/compliance/`) — per-framework regulatory mappings: NIST SP 800-53, NIST AI RMF, EU AI Act, SOC 2, ISO 27001, HIPAA, GDPR, PCI DSS, FedRAMP, FINRA, CMMC. Each document maps protocol-level capabilities to specific controls and lists complementary controls outside the protocol's scope.
34+
- **NIST RFI submission archive** (`nist-submission/`) — exact artifacts submitted to NIST (Docket NIST-2025-0035), SHA-256 checksums, and README with normative/informative classification.
35+
- **`capsule://` URI scheme (Active)**content-addressable references to Capsule records via their SHA3-256 hash. Spec at `spec/uri-scheme.md`, finalized from Draft to Active. Supports hash references (`capsule://sha3_<hash>`), chain references (`capsule://chain/42`), ID references, and fragment syntax into the 6 sections.
3536
- **URI conformance vectors** (`conformance/uri-fixtures.json`) — 10 valid and 11 invalid URI parsing test vectors for cross-language URI parser verification.
37+
- **TypeScript reference implementation** — full CPS-conformant implementation at `reference/typescript/`: Capsule model with factories, canonical JSON serializer (CPS Section 2 with float-path handling), SHA3-256 hashing, Ed25519 seal/verify, and chain verification with `verifyContent` option. Passes all 16 golden fixtures. 101 tests, 100% coverage (v8). Uses `@noble/hashes` ^2.0.1, `@noble/ed25519` ^3.0.0, vitest ^4.0.0, TypeScript ^5.9.0. Node.js >= 20.19.0.
38+
- **TypeScript release workflow** (`.github/workflows/typescript-release.yaml`) — npm publish with provenance on version tags, gated by conformance tests.
3639
- **`vault` golden fixture** — conformance suite now covers all 8 CapsuleTypes (16 total fixtures, up from 15). The `vault_secret` fixture tests secret rotation with policy-based authority.
37-
- **Protocol structure tests** (`reference/python/tests/test_protocol_structure.py`) — guards the protocol-first layout, spec completeness, conformance suite integrity, TypeScript type alignment with spec, markdown link resolution, CI configuration, and root-level file requirements.
40+
- **Implementor's Guide** (`docs/implementors-guide.md`) — step-by-step instructions for building a conformant CPS implementation in any language, with URI parsing section and language-specific pitfalls.
41+
- **Why Capsules** (`docs/why-capsules.md`) — the case for cryptographic AI memory.
42+
- **Protocol structure tests** — guards the protocol-first layout, spec completeness (including Security Considerations), conformance suite integrity, URI vectors, compliance directory, TypeScript alignment, markdown links, CI configuration, and root-level files.
3843
- **Dependabot for TypeScript** — npm dependency updates for `reference/typescript/`.
3944

45+
### Security
46+
47+
- `chain.verify()` now supports cryptographic verification (`verify_content=True`, `seal=`) in addition to structural-only checks. Structural verification alone trusts stored hash values; cryptographic verification recomputes from content.
48+
- Hash computation in chain verification uses the canonical `compute_hash()` function (Python) and `computeHash(toDict())` (TypeScript) to prevent divergence from the sealing path.
49+
- Spec Section 7 explicitly documents non-goals: no confidentiality, no content truthfulness, no availability guarantees, no identity binding.
50+
4051
### Updated
4152

4253
- **Python dependencies** — pytest >=9.0.0, pytest-asyncio >=1.0.0, ruff >=0.15.0, mypy >=1.19.0, sqlalchemy >=2.0.48, asyncpg >=0.31.0, liboqs-python >=0.14.1.

docs/architecture.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,12 +248,21 @@ Capsule #0 Capsule #1 Capsule #2
248248

249249
### Chain Verification
250250

251-
`chain.verify()` walks every Capsule in sequence order and checks:
251+
`chain.verify()` supports two verification levels:
252+
253+
**Structural** (default, fast): walks every Capsule in sequence order and checks:
252254

253255
1. Sequence numbers are consecutive: 0, 1, 2, ...
254256
2. Each Capsule's `previous_hash` matches the previous Capsule's `hash`
255257
3. The genesis Capsule (sequence 0) has `previous_hash = None`
256258

259+
**Cryptographic** (`verify_content=True`): everything above, plus:
260+
261+
4. Recomputes SHA3-256 from content and compares to stored hash
262+
5. Optionally verifies Ed25519 signatures (when `seal=` is provided)
263+
264+
Structural verification trusts stored hash values. Cryptographic verification catches storage-level tampering where an attacker modifies content without the signing key. See [CPS Section 7.5](../spec/README.md) for the security rationale.
265+
257266
If any check fails, the result includes the Capsule ID where the chain broke and the number of Capsules verified before the break.
258267

259268
### Multi-Tenant Chains

docs/implementors-guide.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,28 @@ Seal fields (`hash`, `signature`, `signature_pq`, `signed_at`, `signed_by`) are
116116

117117
## Step 6: Chain Verification
118118

119+
Implementations SHOULD support two verification levels (see [CPS Section 7.5](../spec/README.md)):
120+
121+
**Structural** (fast):
122+
119123
```
120124
1. Load all Capsules in sequence order
121125
2. Verify sequence numbers are consecutive: 0, 1, 2, ...
122126
3. Verify genesis (sequence 0) has previous_hash = null
123127
4. For each subsequent Capsule, verify previous_hash = hash of previous Capsule
124128
```
125129

130+
**Cryptographic** (thorough):
131+
132+
```
133+
All structural checks, plus:
134+
5. For each Capsule, recompute SHA3-256 from content via to_dict() + canonicalize()
135+
6. Compare recomputed hash to stored hash (detects storage-level tampering)
136+
7. Optionally verify Ed25519 signature on each Capsule
137+
```
138+
139+
Structural verification trusts stored hash values. Cryptographic verification catches content tampering where the attacker does not have the signing key.
140+
126141
---
127142

128143
## Step 7: Conformance Testing

reference/python/src/qp_capsule/chain.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
from dataclasses import dataclass
2424
from typing import TYPE_CHECKING
2525

26+
from qp_capsule.seal import compute_hash
27+
2628
if TYPE_CHECKING:
2729
from qp_capsule.capsule import Capsule
2830
from qp_capsule.protocol import CapsuleStorageProtocol
@@ -88,21 +90,36 @@ async def add(self, capsule: Capsule, tenant_id: str | None = None) -> Capsule:
8890

8991
return capsule
9092

91-
async def verify(self, tenant_id: str | None = None) -> ChainVerificationResult:
93+
async def verify(
94+
self,
95+
tenant_id: str | None = None,
96+
*,
97+
verify_content: bool = False,
98+
seal: Seal | None = None,
99+
) -> ChainVerificationResult:
92100
"""
93101
Verify the entire chain integrity.
94102
95-
Checks:
103+
Structural checks (always):
96104
1. Sequence numbers are consecutive (0, 1, 2, ...)
97105
2. Each Capsule's previous_hash matches the previous Capsule's hash
98106
3. First Capsule has previous_hash = None
99107
108+
Cryptographic checks (when verify_content=True or seal is provided):
109+
4. Recompute SHA3-256 from content and compare to stored hash
110+
5. Verify Ed25519 signature (requires seal)
111+
100112
Args:
101113
tenant_id: If provided, verify only this tenant's chain
114+
verify_content: If True, recompute hashes from content
115+
seal: If provided, also verify Ed25519 signatures (implies verify_content)
102116
103117
Returns:
104118
ChainVerificationResult with validity and error details
105119
"""
120+
if seal is not None:
121+
verify_content = True
122+
106123
capsules = await self.storage.get_all_ordered(tenant_id=tenant_id)
107124

108125
if not capsules:
@@ -120,7 +137,6 @@ async def verify(self, tenant_id: str | None = None) -> ChainVerificationResult:
120137

121138
# Check previous_hash
122139
if i == 0:
123-
# First Capsule should have no previous
124140
if capsule.previous_hash is not None:
125141
return ChainVerificationResult(
126142
valid=False,
@@ -129,7 +145,6 @@ async def verify(self, tenant_id: str | None = None) -> ChainVerificationResult:
129145
capsules_verified=0,
130146
)
131147
else:
132-
# Subsequent Capsules should link to previous
133148
expected_prev = capsules[i - 1].hash
134149
if capsule.previous_hash != expected_prev:
135150
return ChainVerificationResult(
@@ -139,6 +154,24 @@ async def verify(self, tenant_id: str | None = None) -> ChainVerificationResult:
139154
capsules_verified=i,
140155
)
141156

157+
if verify_content:
158+
computed = compute_hash(capsule.to_dict())
159+
if computed != capsule.hash:
160+
return ChainVerificationResult(
161+
valid=False,
162+
error=f"Content hash mismatch at sequence {i}",
163+
broken_at=str(capsule.id),
164+
capsules_verified=i,
165+
)
166+
167+
if seal is not None and not seal.verify(capsule):
168+
return ChainVerificationResult(
169+
valid=False,
170+
error=f"Signature verification failed at sequence {i}",
171+
broken_at=str(capsule.id),
172+
capsules_verified=i,
173+
)
174+
142175
return ChainVerificationResult(
143176
valid=True,
144177
capsules_verified=len(capsules),

0 commit comments

Comments
 (0)