A Distributed Security Assurance Architecture for Verifiable Identity, Provenance and Access Control in Additive Manufacturing
AMTrustFabric is a distributed security assurance architecture that establishes verifiable trust across identities, signed evidence, distributed storage, and permissioned ledger operations. It is built on Hyperledger Fabric and implements a concrete, tested case study, cryptographic product anchoring and confidential-file integrity auditing to demonstrate the underlying assurance model: every privileged action must be authenticated, authorised, and independently verifiable, and no component may substitute its own self-reported state for the ledger's canonical record.
The implementation is the reference codebase for the SAM-BCADA architecture (Kumar, Epiphaniou, Maple — see Documentation); TrustFabric is the security-assurance framing this repository presents that work under.
Distributed systems built from multiple identities, services, storage nodes, and a shared ledger fail in a specific, recurring way: security holds only as long as every component behaves honestly, because nothing stops one component from self-reporting trusted state, substituting security-critical metadata, or performing a privileged ledger operation without proving it's authorised to.
Concretely, that means: a storage node claiming its data matches an audited tag instead of the ledger proving it; a verification result trusted because an already-authorized caller sent it rather than because it was cryptographically derived; a public key or identity attribute carried alongside a signature instead of bound inside it; any channel member being able to write "canonical" state because a state-changing entry point forgot to check who was calling.
TrustFabric addresses this with four structural controls rather than policy alone: verifiable identity (Fabric CA-issued attributes checked at the point of every privileged write), signed, domain-separated provenance (every security-relevant message binds the fields an attacker would want to substitute), canonical ledger state (the chain — not a peer, storage node, or caller — is the only source of truth an auditor trusts), and fail-closed verification (every error path denies rather than defaults open). Each is implemented, tested, and — where it matters most — exercised against a real Hyperledger Fabric network rather than only a mock.
flowchart LR
Client["Client / Manufacturer"] -->|"encrypt, sign, chunk<br/>(off-chain, sambcada/app/common)"| Coordinator["Coordinator<br/>(sam-bcada/app/coordinator)"]
Verifier["Verifier / Auditor"] -->|"challenge / candidate DFP"| Coordinator
Coordinator -->|"role-gated writes:<br/>CreateCryptoAnchor<br/>RecordVerificationResult<br/>StoreBlockTags / StoreAuditResult<br/>LogDownload"| Chaincode["Hyperledger Fabric Chaincode<br/>(chaincode-go — identity/role authority)"]
Chaincode -->|"authoritative writes only"| Ledger[("Canonical Ledger State<br/>(anchors, tags, verification<br/>and audit history)")]
Coordinator <-->|"store / retrieve encrypted<br/>blocks, recompute tags,<br/>answer audit challenges"| Storage["Storage Nodes<br/>(sam-bcada/app/storagenode)"]
Ledger -->|"GetCryptoAnchor<br/>GetTagsForFile<br/>GetVerificationHistory"| Verifier
Who is authoritative for what:
| Decision | Authoritative component | Not trusted for this |
|---|---|---|
| Is the caller who they claim, and do they hold the required role? | Fabric CA identity + chaincode's requireRole/cid.AssertAttributeValue |
The caller's own claim, any request parameter |
| Is a product/DFP anchor authentic? | common.VerifyProduct (the only function permitted to return AUTHENTIC) |
Any caller-supplied status string |
| What tag is a block's integrity checked against? | The chain's GetTagsForFile record |
A storage node's self-reported tag |
| Did a verification result actually come from a real check? | The chaincode's independent re-verification of the signed attestation | Caller identity/role alone |
| What is a file's current audit status? | The ledger's StoreAuditResult history, written only by the coordinator role |
Any other identity's claim |
- Fabric CA-backed identity and role validation — every privileged chaincode function checks a real X.509 certificate attribute (
role=...) viacid.AssertAttributeValue, never a request parameter. - Coordinator-only privileged ledger operations —
StoreBlockTags,StoreAuditResult, andLogDownloadare restricted torole=coordinator. - RBAC / attribute enforcement per operation —
role=manufacturer(anchor creation),role=verification-service(verification results),role=network-admin(one-time key bootstrap),role=coordinator(storage/audit/download writes) are each independently checked. - Cross-organisation trust separation — the role check is attribute-based, not MSP-based: an Org2 identity with no
coordinatorattribute is rejected exactly like an unauthorized Org1 identity. - Cryptographically bound manufacturer/verifier keys — both public keys are bound inside the signed anchor message itself, not merely stored alongside the signature.
- Deterministic canonical encoding — every signed/hashed structure uses one length-prefixed field encoder, eliminating concatenation ambiguity.
- Domain-separated signed messages — anchor messages and attestation messages carry distinct domain tags so one can never be misread as the other.
- Canonical ledger state over self-reported storage state — an auditor's trusted tag set always comes from the chain, never from a storage node's response.
- Homomorphic verifiable tags (HVT) for block-level audit proofs — each data block is tagged
Tag(dᵢ) = g^dᵢ mod N(RSA-style construction,common/hvt.go); the multiplicative homomorphismTag(dᵢ)·Tag(dⱼ) mod N = Tag(dᵢ+dⱼ)is what lets the challenge-response audit protocol (common/audit.go) aggregate proofs across many blocks and storage nodes into a single pass/fail check, without the auditor ever downloading the raw blocks. - Replay and tampering rejection — a reused verification ID, or a genuinely-signed attestation whose result field is altered after signing, is rejected.
- Fail-closed verification — every decryption, parsing, or signature-check failure path returns a denied/failed outcome, never an ambiguous success.
- Audit logging and evidence — every anchor, verification, tag, and audit action is a ledger entry queryable by an independent auditor.
TrustFabric's controls address the following attack classes, each with a passing regression test:
- Unauthorized ledger writes — any identity without the required role attempting a privileged write.
- Identity/role misuse — an identity with one role attempting an operation gated on a different role.
- Public-key substitution — a manufacturer or verifier public key altered after the anchor was signed.
- Metadata substitution — anchor fields changed independently of the signature that should cover them.
- Storage-node self-reporting — a storage node (or anyone else) asserting a tag or audit result the ledger didn't authorize.
- Tampered attestations — a genuinely-signed verification result whose outcome is altered after signing.
- Replay attempts — resubmission of a previously accepted verification attestation.
- Cross-organisation unauthorized access — an identity from a different Fabric organisation attempting a privileged operation without the required attribute.
- Integrity failures across trust boundaries — any point where one component could substitute its own state for another's authoritative record.
This list reflects what the implementation actually defends against and has been tested against — it is not a general-purpose threat catalogue, and claims here are scoped to what's below in Security Assurance and Verification.
This is not a design claim — it is what has actually been run, in this repository, and passed.
- Both Go modules (
sam-bcada/app,sam-bcada/chaincode-go) build cleanly. go vetclean on both modules.gofmtclean on both modules.- All unit tests pass on both modules.
go test -racepasses on theappmodule (the concurrent coordinator/storage-node paths).chaincode-gohas 15 tests, including 11 access-control tests covering every role-gated function.- The production
cid.AssertAttributeValuepath is tested with genuine Fabric-CA-style X.509 certificates carrying the real attribute extension (OID1.2.3.4.5.6.7.8.1) — not a re-implementation of the check, the actual code path. - A real Hyperledger Fabric 2.5.16 / Fabric CA 1.5.17 two-organisation network was brought up, the actual chaincode deployed, and torn down again — not simulated.
- 21/21 live Fabric integration scenarios passed, including an Org2 cross-organisation authorization rejection, unauthorized
LogDownload/StoreBlockTags/StoreAuditResultrejection, and the full anchor-creation-through-verification-history flow. - Regression coverage is in place for every resolved finding (see below) — tampered-attestation rejection, canonical-tag trust boundary, bound-key substitution, and unauthorized privileged-write rejection all have dedicated tests, both fast (mocked) and live (real network).
- Reproducible evidence log:
sam-bcada/evidence/SR5_LIVE_FABRIC_TEST_RUN.log.
GitHub-hosted fast CI observed and passing. Run 32587558163 executed the TrustFabric CI workflow on GitHub's own infrastructure — both the app and chaincode-go jobs (gofmt, build, vet, test, race) passed. This is no longer a local-only claim.
Live Fabric integration on GitHub Actions is still pending. The TrustFabric Fabric Integration workflow runs the same setup.sh/test.sh/teardown.sh suite that passed 21/21 locally (see above), but it is triggered manually or on a weekly schedule, not on push, and has not yet been observed running inside GitHub Actions. Treat that specific workflow as not-yet-observed until a run is recorded — everything else in this section already is.
Canonical-state trust boundary. An audit's trusted tag values now come exclusively from the ledger, never from a storage node's own response — closing a path where a dishonest storage node could otherwise redefine what its own data was being checked against.
Cryptographic provenance binding. Manufacturer and verifier public keys are now bound inside the signed anchor payload itself, alongside a domain-separation tag, so substituting either key — or replaying an anchor signature in a different message context — is cryptographically detectable rather than merely policy-discouraged.
Privileged ledger authorization. The chaincode's storage-tag, audit-result, and download-logging entry points now enforce Fabric CA role attributes, closing a gap where any channel-authenticated identity — regardless of role — could previously write directly to ledger state that downstream verification treats as authoritative.
(Internally tracked as SR-2, SR-6, and the F1/SR-1 trust-boundary fixes — see SECURITY_REVIEW.md for the full technical writeup of each.)
| Assurance property | Verification |
|---|---|
| Build correctness | PASS |
Static analysis (go vet) |
PASS |
| Unit tests | PASS |
| Race detection | PASS |
| Role authorization | PASS |
| Cross-org authorization | PASS |
| Cryptographic substitution rejection | PASS |
| Tampered attestation rejection | PASS |
| Replay rejection | PASS |
| Live Fabric deployment | 21/21 PASS |
| GitHub-hosted CI (fast suite) | PASS (run 32587558163) |
| GitHub-hosted live Fabric integration | Pending until observed |
Two independent Go modules — run each from its own directory.
# app module (coordinator, storage node, shared crypto/common code)
cd sam-bcada/app
go build ./...
go vet ./...
go test ./...
go test -race -count=1 ./...# chaincode-go module (the Fabric smart contract)
cd sam-bcada/chaincode-go
go build ./...
go vet ./...
go test ./...
go test -race -count=1 ./...Requires Docker and the official Fabric binaries/test-network (see sam-bcada/integration/fabric/env.sh for path assumptions).
cd sam-bcada/integration/fabric
./setup.sh # brings up a 2-org Fabric network, registers role-attributed
# identities, deploys the chaincode
./test.sh # runs the full scenario suite against the live chaincode
./teardown.sh # tears the network down and cleans generated state.github/workflows/sam-bcada-ci.yml("TrustFabric CI") — fast feedback:gofmt,go build,go vet,go test,go test -racefor both Go modules, on every push/PR touching either module. Observed passing on GitHub Actions: run 32587558163..github/workflows/sam-bcada-fabric-integration.yml("TrustFabric Fabric Integration") — the live-network suite above, run via manual dispatch and a weekly schedule rather than on every commit, since a full Fabric network spin-up is far heavier than the fast suite. Not yet triggered on GitHub Actions — passed locally (21/21), pending a GitHub-hosted run.
Workflow files keep their existing names (sam-bcada-*.yml) to avoid unnecessary Actions-history churn; their display names were updated to TrustFabric.
Carried over honestly from the security review rather than hidden:
- HKDF domain separation (accepted design limitation).
EncryptToPublicKey's HKDFinfostring is shared between two use cases; not exploitable today because the ephemeral-key salt makes every derived key unique regardless, but flagged for anyone extending the scheme. MemoryChainClienttest-double parity (accepted design limitation). The in-memory chain client used by the app module's unit tests does not enforce the samecoordinator-role gate the real chaincode does for storage/audit writes — each has exactly one already-trusted internal caller today, so the gap is disclosed rather than exploitable.- GitHub-hosted live Fabric integration unobserved. The fast CI workflow has run on GitHub Actions and passed (see Security Assurance and Verification); the live-network workflow has not yet been triggered on GitHub's infrastructure, only run locally in this development environment.
- Physical sensing is out of scope. DFP acquisition (
Scan(PFP)) is accepted as an opaque byte input at the API boundary; no physical fingerprinting hardware or algorithm is implemented or claimed.
This project is not presented as production-certified, formally verified, or penetration-tested. It is a tested reference architecture with reproducible, disclosed evidence for the properties listed above — no more, no less.
TrustFabric is a distributed security-assurance architecture, not an AI system — but the architectural questions it answers are the same ones that determine whether an LLM or agentic system is safe to operate: explicit trust boundaries, workload identity, least privilege, tool/action authorization, authoritative versus self-reported state, provenance, cryptographic evidence, human/audit review, fail-closed controls, and reproducible verification evidence.
A useful mapping:
User → AI Agent → Tool/API → External System
Identity → Coordinator → Chaincode → Storage → Ledger/Verifier
In both architectures, the question that determines whether the system is actually secure is the same: who is trusted, what authority does each component have, which evidence is authoritative, and what happens when a component is compromised or wrong? TrustFabric answers that question concretely, with tests, for a distributed ledger system — the same discipline applies directly to agent-tool authorization, MCP server trust boundaries, and provenance of AI-generated or AI-retrieved evidence.
SECURITY_REVIEW.md— full findings (SR-1 through SR-6), threat analysis, and resolution status.VERIFICATION_REPORT.md— milestone-by-milestone independent verification, including this repository's live-network evidence.IMPLEMENTATION_GAP_ANALYSIS.md— manuscript-to-code gap tracking from first implementation through the current hardening pass.MANUSCRIPT_IMPLEMENTATION_MATRIX.md— step-by-step mapping from the source manuscript's algorithms to this codebase, including every documented ambiguity/engineering decision.sam-bcada/evidence/— raw logs from actual live-Fabric verification runs.
The implementation follows the algorithms described in:
Kumar, M., Epiphaniou, G., & Maple, C. (2025). Securing additive manufacturing with blockchain-based cryptographic anchoring and dual-lock integrity auditing. Computers in Industry, 173, 104395.
@article{kumar2025securing,
title={Securing additive manufacturing with blockchain-based cryptographic anchoring and dual-lock integrity auditing},
author={Kumar, Mahender and Epiphaniou, Gregory and Maple, Carsten},
journal={Computers in Industry},
volume={173},
pages={104395},
year={2025},
publisher={Elsevier}
}Full publication list: Google Scholar.