Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

Setting Up a Blockchain-Based Evidence Storage System

A technical guide for developers implementing verifiable evidence storage for insurance claims using on-chain hashes, IPFS, Arweave, and smart contracts.
Chainscore © 2026
introduction
INTRODUCTION

Setting Up a Blockchain-Based Evidence Storage System

A guide to building a tamper-proof, verifiable system for storing digital evidence using blockchain technology.

A blockchain-based evidence storage system provides a cryptographically secure and immutable ledger for digital artifacts. Unlike traditional databases, a blockchain creates a permanent, timestamped record where data cannot be altered or deleted after it is committed. This is achieved by hashing the evidence data and storing the resulting digital fingerprint (or hash) on-chain, while the original file can be stored off-chain in a decentralized storage network like IPFS or Arweave. The on-chain hash serves as a verifiable proof of existence and integrity for the original file.

The core components of such a system include a smart contract to manage the registration of evidence hashes and metadata, a decentralized storage solution for the actual files, and a client application for users to submit and verify evidence. When evidence is submitted, the system calculates its hash (e.g., using SHA-256), stores the file off-chain, and records the hash, a timestamp, and a submitter identifier in a transaction on a blockchain like Ethereum, Polygon, or a purpose-built chain. This creates a public, auditable trail that is resistant to tampering by any single party.

Key advantages of this approach are provable integrity and decentralized trust. Anyone can independently verify that a piece of evidence has not been modified by re-computing its hash and checking it against the value stored on the blockchain. This eliminates reliance on a central authority's integrity. Common use cases span legal documentation, digital forensics, intellectual property timestamping, and supply chain provenance, where establishing a clear, unchangeable chain of custody is critical.

To implement this, you'll typically write a smart contract in Solidity with a function to store evidence hashes. For example, a basic function signature might be: function registerEvidence(string memory _evidenceHash, string memory _metadataURI) public. The _metadataURI could point to a JSON file on IPFS containing details like the file's original name, MIME type, and the off-chain storage location. The contract would emit an event logging this data, making it easily queryable by client applications.

When designing the system, critical considerations include data privacy (encrypting sensitive files before storage), cost efficiency (choosing a blockchain with low transaction fees for high-volume use), and long-term accessibility of the off-chain storage. It's also vital to implement a clear key management strategy for the cryptographic keys used to sign submission transactions, as losing a private key could prevent authorized updates or verification steps in the evidence lifecycle.

prerequisites
SYSTEM REQUIREMENTS

Prerequisites

Before building a blockchain-based evidence storage system, you need to establish a foundational technical environment and understand the core architectural components.

The primary prerequisite is a functional development environment for smart contract programming. This requires installing Node.js (v18 or later) and a package manager like npm or yarn. You will also need a code editor such as Visual Studio Code with Solidity extensions. The core of your system will be written in Solidity, the programming language for Ethereum Virtual Machine (EVM) compatible blockchains. Familiarity with Solidity syntax, data types, and the structure of a smart contract is essential for implementing the logic that governs evidence submission, hashing, and access control.

You must choose and connect to a blockchain network. For development and testing, a local instance using Hardhat or Foundry is recommended, as it allows for fast iteration and debugging without gas costs. You will also need a Web3 provider library, such as ethers.js (v6) or web3.js, to enable your application front-end or backend to interact with the deployed smart contracts. Setting up a wallet like MetaMask and configuring it to connect to your chosen testnet (e.g., Sepolia, Goerli) is necessary for simulating real transactions.

Understanding cryptographic primitives is non-negotiable for evidence integrity. Your system will rely heavily on cryptographic hashing (like SHA-256 or Keccak-256) to generate a unique, immutable fingerprint for each piece of evidence. You should understand the concept of a Merkle Tree for efficiently verifying the inclusion of evidence in a batch, and public-key cryptography for signing and verifying the origin of submissions. These are not just library calls; they are the mathematical bedrock of trust in your system.

For storing the evidence data itself, you must plan your off-chain storage strategy. Storing large files directly on-chain is prohibitively expensive. The standard pattern is to store the evidence file on a decentralized storage network like IPFS (InterPlanetary File System) or Arweave, which provides content-addressed storage. Your smart contract will then store only the resulting Content Identifier (CID) or hash, creating a permanent, tamper-proof link to the off-chain data. Tools like Pinata or web3.storage can simplify interacting with IPFS.

Finally, consider the system's access control and legal compliance requirements from the outset. Your smart contract must implement permissioning—for example, using OpenZeppelin's Ownable or AccessControl contracts—to restrict who can submit or verify evidence. You should also design data structures that can capture necessary metadata: timestamps (using block.timestamp), submitter identity (the msg.sender address), case identifiers, and evidence descriptions. This metadata, stored on-chain, provides the auditable context for the off-chain file hash.

key-concepts-text
CORE CONCEPTS FOR EVIDENCE STORAGE

Setting Up a Blockchain-Based Evidence Storage System

A technical guide to implementing a tamper-proof evidence ledger using blockchain primitives, focusing on data integrity, timestamping, and access control.

A blockchain-based evidence storage system uses the immutable ledger and cryptographic hashing properties of distributed networks to create a verifiable chain of custody. The core principle is to store not the evidence file itself on-chain, but a unique cryptographic fingerprint—a hash—generated from the file's contents. This hash, along with a timestamp and metadata, is permanently recorded in a transaction. Any subsequent alteration of the original file will produce a completely different hash, breaking the link to the on-chain record and proving tampering. This approach is cost-effective and scalable, as storing large files directly on a Layer 1 like Ethereum is prohibitively expensive.

The system architecture typically involves three key components: an off-chain storage layer (like IPFS, Arweave, or a secure server), a smart contract acting as the registry on-chain, and a client application for user interaction. The workflow is: 1) The evidence file is uploaded to the chosen off-chain storage, which returns a Content Identifier (CID). 2) The client computes the file's hash (e.g., using SHA-256). 3) A transaction is sent to the smart contract's registerEvidence function, storing the hash, the CID, a timestamp, and the submitter's address. The contract emits an event, creating a permanent, auditable log.

Here is a simplified example of a core smart contract function written in Solidity for an evidence registry:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract EvidenceRegistry {
    struct EvidenceRecord {
        bytes32 fileHash; // SHA-256 hash of the file
        string storageCID; // e.g., IPFS CID
        address submittedBy;
        uint256 timestamp;
    }

    mapping(bytes32 => EvidenceRecord) public records;
    event EvidenceRegistered(bytes32 indexed fileHash, address indexed submitter, uint256 timestamp);

    function registerEvidence(bytes32 _fileHash, string calldata _storageCID) external {
        require(records[_fileHash].timestamp == 0, "Evidence already registered");

        records[_fileHash] = EvidenceRecord({
            fileHash: _fileHash,
            storageCID: _storageCID,
            submittedBy: msg.sender,
            timestamp: block.timestamp
        });

        emit EvidenceRegistered(_fileHash, msg.sender, block.timestamp);
    }

    function verifyEvidence(bytes32 _fileHash, string calldata _storageCID) external view returns (bool) {
        EvidenceRecord memory record = records[_fileHash];
        return (record.timestamp > 0 && 
                keccak256(abi.encodePacked(record.storageCID)) == keccak256(abi.encodePacked(_storageCID)));
    }
}

This contract ensures each unique piece of evidence can only be registered once and provides a public verification function.

For the off-chain component, IPFS (InterPlanetary File System) is a common choice due to its content-addressed storage. When a file is added to IPFS, it generates a CID that is intrinsically linked to the file's content. The combination of the on-chain hash and the off-chain CID creates a two-layer proof: the hash guarantees integrity, and the CID enables retrieval. Alternatively, Arweave offers permanent, blockchain-backed storage in a single step, as its data is stored directly on its proof-of-access blockchain. The choice depends on required persistence, cost, and retrieval speed.

Critical considerations for a production system include access control and privacy. The basic registry is public. For sensitive evidence, implement role-based permissions in the smart contract (e.g., only accredited auditors can register) or use zero-knowledge proofs (ZKPs). With ZKPs, you can prove you submitted a specific piece of evidence at a certain time without revealing the hash or metadata on-chain. Furthermore, the original files should be encrypted before being stored off-chain, with decryption keys managed via a secure key management system or shared using a protocol like Lit Protocol for conditional access.

To operationalize this, developers can use frameworks like Hardhat or Foundry for contract development, The Graph for indexing and querying registration events, and SDKs like web3.js or ethers.js for the client interface. The end result is a system where any party can independently verify that a digital artifact existed in its exact form at a specific point in time, owned by a specific entity, establishing a robust and court-admissible chain of evidence. This foundational pattern is applicable to legal documents, supply chain provenance, academic credentials, and digital media timestamping.

ARCHITECTURE

Evidence Storage Options Comparison

Comparison of on-chain, decentralized, and hybrid storage solutions for tamper-proof evidence.

FeatureOn-Chain StorageDecentralized Storage (IPFS/Arweave)Hybrid (Anchor + Storage)

Tamper-Proof Guarantee

Permanent Immutability

Storage Cost for 1GB

$10,000+

$5-50

$100-500

Retrieval Speed

< 5 sec

2-10 sec

< 5 sec

Data Redundancy

Full chain

Global P2P network

Anchor + P2P network

Censorship Resistance

High

Very High

High

Smart Contract Integration

Native

Via Content Identifiers (CIDs)

Native with CIDs

Suitable Evidence Type

Small hashes, metadata

Large files (video, docs)

Any size, optimized for verification

on-chain-hashing-implementation
TUTORIAL

Implementing On-Chain Evidence Hashing

A technical guide to creating a tamper-proof, verifiable system for storing digital evidence on a blockchain using cryptographic hashing.

On-chain evidence hashing is a method for creating an immutable, timestamped record of digital evidence without storing the full data on the blockchain. The core principle involves generating a cryptographic hash—a unique, fixed-length digital fingerprint—of your evidence file (e.g., a document, image, or video) and storing only this hash on-chain. This hash acts as a secure, verifiable proof that the evidence existed in its exact form at the time of the transaction. Popular hashing algorithms for this purpose include SHA-256 (used by Bitcoin) and Keccak-256 (used by Ethereum). Storing the hash is inexpensive and efficient, while the original file is kept off-chain in decentralized storage like IPFS or Arweave, or in a traditional system.

To implement this, you first need to prepare your evidence file. Using a library like web3.js or ethers.js, you can compute the hash client-side before any blockchain interaction. For example, in JavaScript with ethers: const fileBuffer = await file.arrayBuffer(); const hash = ethers.keccak256(new Uint8Array(fileBuffer));. This hash is a 32-byte hex string (0x...). It's crucial to note that any change to the original file, even a single pixel or character, will produce a completely different hash, making tampering immediately detectable. You should also record metadata such as the file name, MIME type, and timestamp alongside the hash for context.

The next step is committing the hash to the blockchain. You write a simple smart contract with a function to store the hash in a public mapping or array. An Ethereum Solidity example would be: mapping(address => bytes32[]) public userHashes; function storeHash(bytes32 _evidenceHash) public { userHashes[msg.sender].push(_evidenceHash); }. Calling this function creates a permanent, timestamped record on the blockchain. The associated transaction hash serves as a public proof of the submission time. For higher security and cost efficiency, consider using a Layer 2 solution like Arbitrum or Optimism, or a dedicated data availability chain like Celestia, to reduce gas fees while maintaining cryptographic guarantees.

Verification is the final and critical phase. Anyone can independently verify the integrity of the evidence by recomputing the hash of the original file and comparing it to the hash stored on-chain. If they match, it proves the file is identical to the one submitted. Your system should provide a simple verification tool. Furthermore, to establish a clear chain of custody, you can extend the smart contract to log each access or state change, signed by authorized parties. This creates an auditable trail. For real-world use, ensure compliance with data privacy regulations (like GDPR) by carefully considering what metadata is stored on the public ledger versus kept in private, permissioned systems.

ipfs-integration-steps
IMMUTABLE STORAGE

Storing Evidence Files on IPFS

Learn how to use the InterPlanetary File System (IPFS) to create a tamper-proof, decentralized evidence storage system for legal documents, forensic data, and digital records.

The InterPlanetary File System (IPFS) provides a foundational layer for decentralized evidence storage by using content-addressing. When you add a file to IPFS, it is split into chunks, cryptographically hashed, and given a unique identifier called a Content Identifier (CID). This CID is derived from the file's content; any change to the file produces a completely different CID. This property ensures data integrity—you can always verify that the evidence retrieved matches the original file by recalculating its hash and comparing it to the CID.

To store evidence, you first need to run an IPFS node. You can use the Kubo command-line client or a programmatic library like js-ipfs or Helia. The basic workflow involves adding a file to your local node, which pins it, making it available on the network. For example, using the IPFS CLI: ipfs add evidence_document.pdf. This command returns the CID, which is your permanent, immutable reference to that exact file. This CID, not a location-based URL, is what you would record on-chain or in a log.

For a robust evidence system, persistence is critical. Files on IPFS are only retained while at least one node on the network is pinning them. To prevent evidence from being garbage-collected, you must ensure it is pinned. You can use a pinning service like Pinata, web3.storage, or Filebase for reliable, long-term storage. These services run dedicated IPFS nodes that guarantee your data remains accessible. For maximum decentralization and redundancy, consider using the IPFS Cluster protocol to coordinate pinning across multiple independent nodes.

Integrating IPFS with a blockchain like Ethereum creates a verifiable audit trail. A common pattern is to store the evidence file's CID and a timestamp in a smart contract or on-chain transaction. For instance, a DocumentRegistry contract could have a function registerEvidence(string memory cid) that emits an event. This creates an immutable, timestamped record on the blockchain that points to the content-addressable evidence on IPFS. Anyone can later use the on-chain CID to fetch and verify the file from the decentralized network.

When building a full application, use the IPFS HTTP API or client libraries. Here's a Node.js example using the official ipfs-http-client to add a file and log its CID:

javascript
import { create } from 'ipfs-http-client';
const ipfs = create({ url: 'http://localhost:5001' });
const file = new Blob(['Evidence content']);
const added = await ipfs.add(file);
console.log('Stored with CID:', added.path);

The returned CID (e.g., QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco) is your proof. Always pair this with a pinning strategy for production systems.

Consider encryption for sensitive evidence before uploading to IPFS. Since IPFS is a public peer-to-peer network, storing plaintext confidential data is a security risk. Encrypt the file client-side using a library like libsodium and store the encryption key securely offline or manage it via a decentralized identity protocol. The encrypted file gets its own CID, which you store on-chain. This maintains privacy while still leveraging IPFS for immutable, decentralized storage. The system's integrity is preserved because any alteration to the encrypted blob would also change its CID, breaking the chain of custody.

arweave-integration-steps
USING ARWEAVE FOR PERMANENT STORAGE

Setting Up a Blockchain-Based Evidence Storage System

A technical guide to building an immutable, tamper-proof evidence ledger using Arweave's permanent data storage protocol.

Arweave provides a foundational protocol for permanent data storage by leveraging a novel blockchain structure called blockweave. Unlike traditional blockchains that only store transaction data, Arweave's blockweave stores data itself, making it ideal for archiving digital evidence. This permanence is guaranteed through the endowment model, where a one-time payment covers storage costs for at least 200 years. For evidence systems, this creates an immutable, timestamped, and publicly verifiable record that cannot be altered or deleted, establishing a high-integrity chain of custody.

To interact with Arweave, you'll need an Arweave wallet and the arweave-js SDK. First, generate a wallet keyfile using the command npx arweave-mine wallet or via the Arweave Wallet browser extension. This JSON Web Key (JWK) file is your private key and must be secured. Initialize the SDK in your Node.js project to create a transaction for uploading data. The core object is the transaction, which bundles your data, a reward for miners, and tags for metadata.

Structuring your evidence data correctly is critical. Each piece of evidence should be uploaded as a Data Transaction. Use transaction tags to add searchable metadata like "App-Name": "Evidence-Ledger", "Evidence-Type": "document", and a custom "Case-ID". The actual evidence file (e.g., a PDF, image, or JSON log) is set as the transaction's data field. Here's a basic code snippet for creating and posting a transaction:

javascript
import Arweave from 'arweave';
const arweave = Arweave.init({});
const data = JSON.stringify({ content: 'Evidence data...' });
const transaction = await arweave.createTransaction({ data }, jwk);
transaction.addTag('App-Name', 'Evidence-Ledger');
transaction.addTag('Content-Type', 'application/json');
await arweave.transactions.sign(transaction, jwk);
await arweave.transactions.post(transaction);

The returned transaction ID is your permanent, immutable reference.

For retrieving evidence, you query the Arweave network using the GraphQL endpoint at https://arweave.net/graphql. You can search by transaction ID or filter by the tags you applied during upload. Fetching the data is straightforward: arweave.transactions.getData(txId, { decode: true, string: true }). This immutability is key for evidence; once confirmed, the data and its metadata are permanently woven into the blockweave. Any attempt to alter the data would break the cryptographic links to subsequent blocks, making tampering evident.

Implementing a robust system requires additional considerations. For large files, use Arweave Bundles (via ardrive) to batch transactions. To manage access control, encrypt sensitive evidence client-side before upload and manage decryption keys separately. You should also implement a local database to index your Arweave transaction IDs with internal case management data. For public verification, you can build a simple front-end that allows anyone to input a transaction ID to view the immutable evidence and its provenance, leveraging the permanence of the Arweave protocol.

building-audit-trail-smart-contract
TUTORIAL

Building the Audit Trail Smart Contract

This guide walks through creating a Solidity smart contract for a tamper-proof evidence storage system on Ethereum-compatible blockchains.

An audit trail smart contract provides an immutable, timestamped ledger for storing digital evidence. Unlike a traditional database, data written to a public blockchain like Ethereum or a Layer 2 like Arbitrum is cryptographically secured and cannot be altered after confirmation. This makes it ideal for use cases requiring provable data integrity, such as legal document notarization, supply chain provenance, and regulatory compliance logs. The core principle is simple: each piece of evidence is recorded as a transaction, creating a permanent, verifiable chain of custody.

We'll build a basic contract using Solidity. Start by defining the contract structure and a struct to represent an evidence entry. Each entry should include essential metadata: a unique identifier, the evidence creator's address, a content hash (like a SHA-256 hash of the file), a timestamp, and a descriptive tag. Storing the raw file on-chain is prohibitively expensive, so we follow the standard pattern of storing only the cryptographic hash on-chain, with the actual file stored off-chain in decentralized storage like IPFS or Arweave.

The primary function is storeEvidence(bytes32 _contentHash, string memory _tag). This function should:

  1. Generate a unique ID for the entry.
  2. Create a new Evidence struct populated with msg.sender, the _contentHash, the current block timestamp (block.timestamp), and the _tag.
  3. Store the struct in a mapping, e.g., mapping(uint256 => Evidence) public evidenceLog.
  4. Emit an event like EvidenceStored(uint256 id, address indexed creator, bytes32 contentHash) for off-chain monitoring.

This function must be public or external and will require a gas fee to execute.

To verify evidence, we add a view function: verifyEvidence(uint256 _id, bytes32 _contentHash) public view returns (bool). It fetches the stored evidence record and compares its hash with the provided _contentHash. A match confirms the off-chain file is identical to the one originally submitted. For enhanced security, consider implementing access control using OpenZeppelin's Ownable or AccessControl libraries to restrict the storeEvidence function to authorized addresses, preventing spam and ensuring log integrity.

Deploy the contract to a testnet like Sepolia or Goerli using a framework like Hardhat or Foundry. After deployment, you can interact with it via a frontend dApp or directly through block explorers. The complete, immutable history of all EvidenceStored events is publicly queryable. This creates a trust-minimized system where any party can independently verify the existence and integrity of any piece of evidence at a specific point in time, without relying on a central authority's database logs.

BLOCKCHAIN VS. TRADITIONAL CLOUD

Cost Analysis: Storing 1MB of Evidence

Comparison of estimated costs and characteristics for storing a 1MB digital evidence file for one year.

Cost FactorArweave (Permanent)Filecoin (Long-Term)AWS S3 (Standard)

One-Time Storage Fee

$0.02

$0.001 - $0.005

$0.023 / month

Retrieval / Access Fee

$0.01 per GB

$0.01 - $0.02 per retrieval

$0.09 per GB

Data Durability Guarantee

200 years

Contract-based (1-5 years)

99.999999999% (11 nines)

Immutable Proof of Storage

Decentralized / Censorship-Resistant

Estimated 1-Year Total Cost

$0.03

$0.01 - $0.03

$0.28

Primary Use Case

Permanent, verifiable archive

Cost-effective long-term storage

Frequent access, centralized control

DEVELOPER TROUBLESHOOTING

Frequently Asked Questions

Common technical questions and solutions for implementing a secure, on-chain evidence storage system.

The optimal chain depends on your specific requirements for cost, security, and throughput. For high-value, permanent records, Ethereum Mainnet offers maximum security and decentralization, though transaction fees are high. Layer 2 solutions like Arbitrum or Optimism provide Ethereum-level security with significantly lower costs, ideal for frequent submissions. For pure data storage, Filecoin or Arweave are purpose-built for decentralized file storage, where you would store the file and anchor its cryptographic hash (e.g., a CID) on a smart contract chain. Polygon PoS is a popular, low-cost EVM chain for prototyping. Always prioritize chains with proven security and robust tooling over the absolute lowest fees.

conclusion-next-steps
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have now configured the core components for a decentralized evidence storage system. This guide covered the essential steps from smart contract design to frontend integration.

The system you've built leverages immutable on-chain storage for cryptographic hashes and decentralized off-chain storage for the actual evidence files. This hybrid approach balances security with cost-efficiency. The EvidenceRegistry smart contract acts as a tamper-proof ledger, recording the fileHash (e.g., from IPFS or Arweave), timestamp, and submitter address for each piece of evidence. This creates a permanent, verifiable record that the file existed at a specific point in time and has not been altered.

For production deployment, several critical next steps are required. First, conduct a thorough security audit of your smart contracts using tools like Slither or MythX, and consider a professional audit from firms like OpenZeppelin or ConsenSys Diligence. Second, implement a robust access control and governance model, potentially using multi-signature wallets or a DAO framework like OpenZeppelin Governor to manage sensitive operations. Third, establish a clear data retention policy and pruning mechanism for your off-chain storage to manage long-term costs and compliance.

To extend the system's functionality, consider integrating zero-knowledge proofs (ZKPs) for privacy-preserving verification using libraries like Circom or SnarkJS. You could also add oracle services like Chainlink to fetch and attest to real-world data points (e.g., timestamps from an authoritative source, notary signatures). For higher throughput, explore Layer 2 solutions such as Arbitrum or Optimism to reduce transaction fees and latency for evidence submissions.

The primary use cases for this architecture are legal evidence logging, supply chain provenance, and academic research integrity. For example, a law firm could use it to create an immutable chain of custody for digital evidence, while a manufacturer could log quality inspection reports at every stage of production. The system's trustlessness removes the need for a single, potentially corruptible, central authority.

Finally, maintain and monitor your deployment. Use blockchain explorers like Etherscan for on-chain transaction tracking and monitoring services like Tenderly or Alchemy for smart contract alerts. Keep your dependencies (e.g., web3.js, ethers.js, IPFS client) updated. The complete code examples from this guide are available in the Chainscore Labs GitHub repository for further reference and community collaboration.