Sign in to edit tickets from this page.

← all tickets · home

BENAC-CID-DRISL-001 — Implement DASL CID v1 + DRISL canonical identity profile and migrate portable Benac identity fields

resolved bc4fa9ac-c298-454a-9f76-4f6227ca3202

created_at
2026-05-03
updated_at
2026-05-03
priority
P0
ticket_type
feature
resolved_at
2026-05-03
resolution
accepted

Body

BENAC-CID-DRISL-001 — Implement DASL CID v1 + DRISL canonical identity profile and migrate portable Benac identity fields

Priority: P0 / Foundation blocker
Type: implementation + conformance hardening
Owner: Benac kernel developer
Scope: DASL CID, raw blob CIDs, structured DRISL document CIDs, CID links, DRISL signing bytes, and migration of portable identity fields.
Non-goal: This ticket must not expand into C3 remote storage, C3 remote compute, encrypted envelopes, Web Worker isolation, or local vault work except where those surfaces need CID-shaped fields or conformance placeholders.

Summary for the developer

You need to replace the current HW1 legacy content identity layer with the current SyRS baseline:

Current repo behavior:
  bencid:v0:<domain>:sha256:<lowercase-hex>
  SHA-256 over "profile\ndomain\n" + bytes
  canonical JSON for structured identity/signing
  CID-like values serialized as plain strings

Required behavior:
  DASL CID v1 strings
  raw blob codec 0x55 for exact raw bytes
  DRISL structured codec 0x71 for canonical structured Benac objects
  SHA-256 digest type 0x12, hash size 0x20, 32-byte digest
  lowercase RFC 4648 base32 with prefix b and no padding
  canonical DRISL bytes for signed/content-addressed structured objects
  CBOR Tag 42 CID links in DRISL
  JSON projection CID links as {"$link": "b..."}

This is a foundational conformance ticket. The previous Hello World / C1 / C2-lite work remains valuable, but it is not conformant to the current generated SyRS until this lands.

Do not make the old bencid format pass the new requirements. Treat it as a legacy import/migration format only, if you support it at all.

Requirements this ticket must satisfy

Must be fully satisfied by this ticket

Must be materially upgraded by this ticket

This ticket should remove the DASL/CID/DRISL blocker for these requirements, even if other non-CID portions remain partial or out of scope:

Explicitly out of scope for this ticket

Do not implement full C3 storage/compute just because storage and compute requirements mention CIDs. For storage/compute requirements, this ticket only needs to ensure that any relevant schemas, claims, receipts, leases, vectors, and placeholder records use the correct CID vocabulary and verification semantics. Full Storage Station offers/descriptors/leases/CAS transport and full Compute Station offers/plans/leases/remote invocation remain separate tickets.

Codebase findings you must address

The current codebase is still on the legacy HW1 identity profile. The following are not acceptable for the current requirements and must be changed.

1. ContentId is currently an unchecked-ish string wrapper over legacy bencid

File: crates/benac-core/src/ids.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/ids.rs:9-11    ContentId(pub String)
crates/benac-core/src/ids.rs:29-55   parse_for_domain() validates bencid:v0:<domain>:sha256:<digest>
crates/benac-core/src/ids.rs:70-91   FromStr validates bencid:v0:<domain>:sha256:<digest>

Required change:

ContentId::parse_canonical_dasl_cid(raw: &str) -> Result<ContentId>
ContentId::from_raw_blob_bytes(bytes: &[u8]) -> ContentId
ContentId::from_drisl_bytes(bytes: &[u8]) -> ContentId
ContentId::codec(&self) -> CidCodec
ContentId::binary_dasl_cid(&self) -> &[u8]
ContentId::as_canonical_string(&self) -> &str

2. crypto.rs computes legacy domain-prefixed SHA-256 strings

File: crates/benac-core/src/crypto.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/crypto.rs:56-68   CryptoProfile { id: "benac.crypto.v0.hw1", hash: "sha256" }
crates/benac-core/src/crypto.rs:71-88   content_id(domain, bytes) => bencid:v0:<domain>:sha256:<hex>
crates/benac-core/src/crypto.rs:90-93   content_id_for_json() uses canonical_json_bytes()

Required change:

benac.crypto.v1.dasl-drisl
benac.content_identity.dasl-cid-v1
benac.canonical.drisl.v1
raw_blob_cid(bytes: &[u8]) -> ContentId;        // codec 0x55
structured_cid(value: &LogicalObject) -> ContentId; // codec 0x71 over DRISL bytes

3. canonical_json.rs is not DRISL

File: crates/benac-core/src/canonical_json.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/canonical_json.rs:3-10 canonical_json_string()/canonical_json_bytes()

Required change:

null
boolean
integer
string
array
map with string keys only
CID links
floating point numbers
non-string map keys
unsupported CBOR tags
unsupported simple values
indefinite-length strings/arrays/maps
trailing bytes
concatenated objects
non-canonical ordering on decode if decode validation is implemented
malformed CID links
malformed CBOR Tag 42 payloads
{ "$link": "b..." }

must encode in canonical DRISL as CBOR Tag 42 over a byte string:

0x00 || binary_dasl_cid

Example required vector:

raw bytes:        hello
raw blob CID:     bafkreibm6jg3ux5qumhcn2b3flc3tyu6dmlb4xa7u5bf44yegnrjhc4yeq
Tag 42 DRISL hex: d82a582500015512202cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

Also include the empty raw blob vector:

raw bytes:    empty byte sequence
raw blob CID: bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku

4. Package identity currently uses canonical JSON and manually clears claim_refs

File: crates/benac-core/src/package.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/package.rs:97-103 PackageManifest::content_id()

Required change:

Package canonical payload contains package behavior: object_type, schema_version, package metadata, schemas, interfaces, implementations, artifact CIDs, requested capabilities, fixtures.
Package bundle/capsule/import envelope contains external claim references.

5. Implementation identity is incomplete

File: crates/benac-core/src/package.rs and fixture generation in crates/benac-fixtures/src/hello_world.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/package.rs:23-28 PackageImplementation
crates/benac-fixtures/src/hello_world.rs:95-128 schema/implementation content IDs generated with content_id_for_json()

Required change:

object_type = implementation_snapshot
schema_version
package_cid
implementation_entry_id
implementation_type
artifact_cids, if any
runtime_requirements
schema-defined role fields
schema-defined parameters
implementation_cid
artifact/blob_cid

6. Descriptor identity currently uses canonical JSON

File: crates/benac-core/src/descriptor.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/descriptor.rs:39-43 DescriptorSnapshot::content_id()

Required change:

7. Logical documents currently mix operational _id with canonical identity

File: crates/benac-core/src/document.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/document.rs:18-35 LogicalDocument::new()
crates/benac-core/src/document.rs:38-64 LogicalDocument::from_value()
crates/benac-core/src/document.rs:70-73 LogicalDocument::content_id()
crates/benac-core/src/document.rs:75-90 LogicalDocument::to_value() includes _id

Required change:

LogicalDocument::canonical_payload_value() -> serde_json::Value
LogicalDocument::structured_cid() -> ContentId
LogicalDocument::to_couch_projection() -> serde_json::Value

8. Blob identity currently hashes raw bytes with a Benac domain prefix

File: crates/benac-core/src/blob.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/blob.rs:16-21 BlobRecord::from_bytes()
crates/benac-core/src/blob.rs:29-40 verify_blob_bytes()

Required change:

9. Capsule integrity currently uses legacy document IDs and blob IDs

File: crates/benac-core/src/capsule.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/capsule.rs:51-56 Capsule::content_id_without_integrity_field()
crates/benac-core/src/capsule.rs:125-195 Capsule::verify_integrity_manifest()
crates/benac-core/src/capsule.rs:199-224 document_content_id()

Required change:

object_cids
blob_cids
capsule_cid
root_refs as CID links
hello-world.benac-capsule.json
apps/pwa/public/fixtures/hello-world.benac-capsule.json

Both generated capsules must contain no bencid: values.

10. Signed claims currently sign canonical JSON and use weak target binding

File: crates/benac-core/src/claim.rs

Current behavior:

Relevant current lines:

crates/benac-core/src/claim.rs:31-39 signing_envelope()
crates/benac-core/src/claim.rs:41-45 content_id()
crates/benac-core/src/claim.rs:47-66 verify()
crates/benac-fixtures/src/hello_world.rs:982-1002 signed_claim_for_package()

Required change:

target_cid
target_cid_codec
target_object_type or target_role
target_schema_or_profile

11. Conformance currently rewards the wrong behavior

Files:

crates/benac-conformance/src/hello_world_suite.rs
crates/benac-conformance/src/replication_lite_suite.rs

Current behavior:

Relevant current lines:

crates/benac-conformance/src/hello_world_suite.rs:39-52 canonical_json/domain_separated_hash/blob legacy checks
crates/benac-conformance/src/replication_lite_suite.rs:565-610 bencid prefix checks

Required change:

dasl_cid_raw_blob_vectors
dasl_cid_structured_drisl_vectors
dasl_cid_rejection_vectors
drisl_canonicalization_vectors
drisl_json_projection_vectors
drisl_cid_link_tag42_vectors
couch_projection_excludes_operational_metadata
signed_claim_drisl_signature_vectors
package_cid_unchanged_by_external_claims
implementation_snapshot_cid_vectors
capsule_integrity_uses_object_and_blob_cids
replication_verifies_structured_payload_cids
legacy_bencid_rejected_in_portable_records

Implementation plan

Phase 1 — Add DASL CID module

Create:

crates/benac-core/src/cid.rs

Required constants:

const DASL_CID_VERSION: u8 = 0x01;
const DASL_CODEC_RAW: u8 = 0x55;
const DASL_CODEC_DRISL: u8 = 0x71;
const DASL_HASH_SHA2_256: u8 = 0x12;
const DASL_HASH_SIZE_SHA2_256: u8 = 0x20;
const DASL_CID_BINARY_LEN: usize = 36;

Use exact binary layout:

[ version, codec, hash_type, hash_size, 32-byte_digest ]

For current baseline values, each field is one byte. Reject anything else unless a future extension profile is added.

Use lowercase RFC 4648 base32, no padding, with string prefix b.

Add required tests:

raw_blob_cid_hello_vector
raw_blob_cid_empty_vector
cid_parser_rejects_uppercase
cid_parser_rejects_padding
cid_parser_rejects_wrong_prefix
cid_parser_rejects_wrong_version
cid_parser_rejects_unsupported_codec
cid_parser_rejects_unsupported_hash_type
cid_parser_rejects_wrong_hash_size
cid_parser_rejects_truncated_binary
cid_parser_rejects_trailing_binary
cid_parser_round_trips_canonical_string

Mandatory raw vectors:

hello -> bafkreibm6jg3ux5qumhcn2b3flc3tyu6dmlb4xa7u5bf44yegnrjhc4yeq
empty -> bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku

Note: if your computed hello vector differs, stop and check the binary layout/base32 implementation before changing the expected vector.

Phase 2 — Add DRISL canonical encoder/validator

Create:

crates/benac-core/src/drisl.rs

Implement canonical encoding from Benac logical JSON projections first. A dedicated DrislValue enum is acceptable if it prevents ambiguity.

Required behavior:

Add required tests:

drisl_same_logical_map_same_bytes_despite_json_key_order
drisl_map_order_is_canonical
drisl_rejects_float
drisl_rejects_non_string_map_key_if_decode_path_supports_it
drisl_rejects_trailing_bytes
drisl_rejects_unsupported_tag
drisl_cid_link_uses_cbor_tag_42
drisl_rejects_malformed_cid_link
drisl_excludes_couch_metadata_from_logical_payload

Mandatory CID-link Tag 42 vector:

JSON projection:
  {"$link":"bafkreibm6jg3ux5qumhcn2b3flc3tyu6dmlb4xa7u5bf44yegnrjhc4yeq"}

DRISL bytes hex:
  d82a582500015512202cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

Phase 3 — Replace portable content identity APIs

Refactor:

crates/benac-core/src/crypto.rs
crates/benac-core/src/ids.rs
crates/benac-core/src/blob.rs
crates/benac-core/src/document.rs
crates/benac-core/src/package.rs
crates/benac-core/src/descriptor.rs
crates/benac-core/src/capsule.rs
crates/benac-core/src/claim.rs
crates/benac-core/src/invocation.rs
crates/benac-core/src/evidence.rs
crates/benac-core/src/effect.rs
crates/benac-core/src/audit.rs
crates/benac-core/src/auth.rs
crates/benac-core/src/trust.rs
crates/benac-core/src/capability.rs
crates/benac-core/src/station_profile.rs
crates/benac-core/src/replication.rs

Rules:

Phase 4 — Rename portable fields to CID vocabulary in new schema versions

For new portable schema versions, use CID terminology. Legacy field aliases may exist only for migration/import compatibility.

Required examples:

content_id                    -> cid, object_cid, or role-specific *_cid
package_content_id             -> package_cid
blob_content_id                -> blob_cid
implementation_content_id      -> implementation_cid
selected_implementation_content_id -> selected_implementation_cid
descriptor_content_id          -> descriptor_snapshot_cid
request_content_id             -> request_cid
output_content_id              -> output_cid
document_ids                   -> object_cids or document_cids
blob_ids                       -> blob_cids
capsule_content_id             -> capsule_cid
target_content_id              -> target_cid inside typed target reference

Portable JSON projection of references must use:

{ "$link": "b..." }

Couch _id may remain a string because it is operational metadata, but it must not be canonical payload.

Phase 5 — Regenerate Hello World package/capsule/trace fixtures

Update:

crates/benac-fixtures/src/hello_world.rs
apps/pwa/public/fixtures/hello-world.benac-capsule.json
hello-world.benac-capsule.json

The regenerated Hello World capsule must:

Phase 6 — Migrate PWA/CLI persistence cautiously

Update:

apps/pwa/src/indexeddb_persistence.rs
apps/station-cli/src/persistence.rs
apps/station-cli/src/sync.rs
apps/pwa/src/station_runtime.rs
apps/pwa/src/sync_client.rs

Rules:

Phase 7 — Update conformance and acceptance tests

Update:

crates/benac-conformance/src/hello_world_suite.rs
crates/benac-conformance/src/replication_lite_suite.rs
apps/station-cli/tests/end_to_end.rs
apps/station-cli/tests/sync_end_to_end.rs
apps/pwa/src/ui/* tests

Required conformance result:

The suite must fail against the current legacy bencid/canonical JSON implementation.
The suite must pass only after DASL CID + DRISL are actually used.

Required grep gates:

# Portable artifacts must not contain old content IDs.
! rg 'bencid:v0' hello-world.benac-capsule.json apps/pwa/public/fixtures/hello-world.benac-capsule.json

# New conformance tests must not reward old bencid prefix behavior.
! rg 'starts_with\("bencid:v0' crates/benac-conformance crates/benac-core crates/benac-fixtures

# canonical_json may remain only for explicitly named legacy/debug paths, not identity/signing.
rg 'canonical_json_(bytes|string)' crates apps packages

Any remaining canonical_json_* result must be justified in comments as UI/debug/legacy migration only. It must not be used by content identity or signature verification.

Acceptance criteria

This ticket is done only when all of the following are true.

Identity and encoding

Package/capsule/invocation

Replication

Conformance and regression

Evidence to attach to ticket closeout

Attach a closeout report with:

1. Commit SHA.
2. PWA bundle name.
3. Cargo fmt/clippy/test output.
4. Conformance suite output and check count.
5. Raw CID vectors including hello and empty bytes.
6. DRISL vectors including CID-link Tag 42 vector.
7. Package/implementation/descriptor/blob/capsule CID examples from regenerated Hello World.
8. Grep output proving no portable fixture contains bencid:v0.
9. Import/approve/declarative/WASM invocation output from CLI.
10. Import/approve/declarative/WASM invocation output from PWA or Playwright.
11. Replication test output proving DRISL CID verification and foreign authority inactivity.

No-go conditions

Reject the patch if any of these are true:

Suggested dependency additions

You may add small, well-maintained Rust dependencies if they reduce risk:

data-encoding = "2"   # RFC 4648 base32 encode/decode; enforce lowercase/no padding at wrapper level
ciborium = "0.2"       # CBOR primitives, if useful

Do not rely on a generic CBOR serializer to be canonical unless the code proves canonical ordering/minimal encoding. If generic CBOR support does not guarantee DRISL canonical bytes, write the small deterministic encoder manually.

Developer note

This is a compatibility break from HW1. That is okay. The right outcome is not to preserve old identifiers forever; the right outcome is to migrate the kernel to the generated SyRS baseline. Legacy bencid can be read for migration if necessary, but it must not be accepted as satisfying DASL CID / DRISL conformance.

Proposed resolution

Iteration 5 (commit b8dab41) closes the wasm blob_cid canonical-binding gap. PackageImplementation::validate_artifact_binding is now enforced at three gates (PackageManifest::validate_value schema gate, Capsule::validate_and_inspect import gate, BrowserStationRuntime::invocation_input runtime gate). The WASM executor reads the executable artifact CID from implementation.artifact_cids[0] (not blob_cid). approve_no_risk_hello_world derives the local_blob_read_exact grant scope from artifact_cids of wasm_abi.v0 implementations. The denied-status enum classifies benac.error.implementation_artifact_mismatch. The end-to-end blob-substitution attack regression rejects with the verbatim message 'wasm blob_cid must exactly match artifact_cids[0]'. Conformance: 62/62 (was 55/55). Total green: 338 (workspace 131 + gravitational_lens 145 + conformance 62) plus fmt + clippy + grep gates. Deployed at https://benac.benac.dev/ with PWA bundle benac-pwa-4d18cfb2a790135b.js; live capsule byte-identical to in-tree (validator is gate code, fixture unchanged); 0 bencid:v0, 26 $link projections; live wasm impl shape confirms blob_cid == artifact_cids[0]. Closeout evidence: docs/reports/cid-drisl-closeout.md.

History (18 events)

Sign in as a human to drive this ticket from the page, or use the MCP tools.

← all tickets · home