Evidence Record Smart Contract
6 minute read
Evidence Record Smart Contract
The EvidenceRecord smart contract represents a core component for recording cryptographic proofs of quotes within Youseddit’s distributed ledger infrastructure. It facilitates linking quotes to their original context (stored off-chain) while maintaining GDPR compliance. The broader YouSeddit concept involves creating a verifiable conversation chain on the ledger, where each initiator and response quote potentially receives its own entry, linking back to the previous turn in the conversation.
Contract Overview
This specific EvidenceRecord contract example focuses on recording evidence for a response quote, linking its hash (responseQuoteHash) to the hash of the full encrypted exchange (fullExchangeHash) stored off-chain (e.g., on IPFS via storagePointer).
Important Note on Chaining: To realize the full concept of a verifiable conversation chain, the YouSeddit system (potentially using variations or extensions of this contract, or managing links off-chain) must ensure:
- Both initiator and response quotes ideally receive distinct ledger entries.
- Each ledger entry (or its associated C2PA manifest) contains a verifiable reference (e.g., transaction hash) to the ledger entry of the immediately preceding quote in the conversation flow.
- The C2PA manifest generated for any quote robustly encodes this backward link, allowing context traversal.
This contract provides the mechanism to anchor a quote (primarily the response) to its full context; the explicit on-ledger chaining requires further architectural definition or is managed via C2PA references generated off-chain.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract EvidenceRecord {
// Struct to hold evidence record data
struct Evidence {
bytes32 fullExchangeHash; // SHA-256 hash of the complete encrypted email exchange (initiator + response)
string storagePointer; // IPFS CID pointing to the encrypted exchange file
address owner; // Owner of the evidence record (typically the source/interviewee providing the response quote)
uint256 timestamp; // When the evidence was recorded
bool isPublished; // Whether this response quote is approved for publication
}
// Mapping from response quote hash to evidence record
mapping(bytes32 => Evidence) public evidenceRecords;
// Events
event EvidenceRecorded(bytes32 indexed responseQuoteHash, bytes32 fullExchangeHash, string storagePointer, address owner);
event QuotePublicationStatusChanged(bytes32 indexed responseQuoteHash, bool isPublished);
/**
* @dev Record a new evidence entry linking a response quote to the full exchange
* @param responseQuoteHash Hash of the specific response quote text
* @param fullExchangeHash Hash of the complete encrypted email exchange file
* @param storagePointer IPFS CID pointing to the encrypted exchange file
*/
function recordEvidence(
bytes32 responseQuoteHash,
bytes32 fullExchangeHash,
string memory storagePointer
) public {
// Ensure this response quote hash hasn't been recorded before
require(evidenceRecords[responseQuoteHash].timestamp == 0, "This response quote hash is already recorded");
// Create and store the evidence record
evidenceRecords[responseQuoteHash] = Evidence({
fullExchangeHash: fullExchangeHash,
storagePointer: storagePointer,
owner: msg.sender,
timestamp: block.timestamp,
isPublished: false
});
emit EvidenceRecorded(responseQuoteHash, fullExchangeHash, storagePointer, msg.sender);
}
/**
* @dev Change the publication status of a response quote
* @param responseQuoteHash Hash of the specific response quote text
* @param publishedStatus New publication status
*/
function setPublishedStatus(bytes32 responseQuoteHash, bool publishedStatus) public {
// Ensure the response quote record exists
require(evidenceRecords[responseQuoteHash].timestamp > 0, "Evidence record does not exist");
// Ensure only the owner can change the status
require(evidenceRecords[responseQuoteHash].owner == msg.sender, "Only the owner can change publication status");
evidenceRecords[responseQuoteHash].isPublished = publishedStatus;
emit QuotePublicationStatusChanged(responseQuoteHash, publishedStatus);
}
/**
* @dev Retrieve evidence record for a response quote hash
* @param responseQuoteHash Hash of the specific response quote text
* @return The evidence record
*/
function getEvidence(bytes32 responseQuoteHash) public view returns (
bytes32 fullExchangeHash,
string memory storagePointer,
address owner,
uint256 timestamp,
bool isPublished
) {
Evidence storage evidence = evidenceRecords[responseQuoteHash];
// Ensure the response quote record exists
require(evidence.timestamp > 0, "Evidence record does not exist");
return (
evidence.fullExchangeHash,
evidence.storagePointer,
evidence.owner,
evidence.timestamp,
evidence.isPublished
);
}
/**
* @dev Check if a response quote is approved for publication
* @param responseQuoteHash Hash of the specific response quote text
* @return Whether the response quote is published
*/
function isQuotePublished(bytes32 responseQuoteHash) public view returns (bool) {
// Ensure the response quote record exists
require(evidenceRecords[responseQuoteHash].timestamp > 0, "Evidence record does not exist");
return evidenceRecords[responseQuoteHash].isPublished;
}
}
Key Features
Data Structure
The Evidence struct contains:
fullExchangeHash: SHA-256 hash of the complete encrypted email exchange file (initiator + response)storagePointer: IPFS CID pointing to the encrypted exchange fileowner: Address of the evidence record owner (typically the source/interviewee)timestamp: When the evidence was recorded on the distributed ledgerisPublished: Whether this response quote is approved for publication
Core Functions
recordEvidence
Records an evidence entry for a quote (typically the response quote), linking its hash to the hash of the full encrypted email exchange and its IPFS location. To support chaining, the off-chain system calling this function must handle the recording of the preceding quote and ensure the appropriate backward link is included in the C2PA manifest.
function recordEvidence(
bytes32 responseQuoteHash,
bytes32 fullExchangeHash,
string memory storagePointer
) public
- responseQuoteHash: SHA-256 hash of the specific plaintext response quote
- fullExchangeHash: SHA-256 hash of the complete encrypted email exchange file
- storagePointer: IPFS CID pointing to the encrypted exchange file
setPublishedStatus
Allows the owner (source/interviewee) to control whether a specific response quote is approved for publication.
function setPublishedStatus(bytes32 responseQuoteHash, bool publishedStatus) public
- responseQuoteHash: Hash of the specific response quote text
- publishedStatus: New publication status (true/false)
getEvidence
Retrieves the complete evidence record for a specific response quote hash.
function getEvidence(bytes32 responseQuoteHash) public view returns (
bytes32 fullExchangeHash,
string memory storagePointer,
address owner,
uint256 timestamp,
bool isPublished
)
isSnippetPublished
Checks if a specific response quote is approved for publication.
function isQuotePublished(bytes32 responseQuoteHash) public view returns (bool)
Event Emissions
EvidenceRecorded
Emitted when a new evidence record is created.
event EvidenceRecorded(bytes32 indexed responseQuoteHash, bytes32 fullExchangeHash, string storagePointer, address owner)
SnippetPublicationStatusChanged
Emitted when the publication status of a response quote is changed.
event QuotePublicationStatusChanged(bytes32 indexed responseQuoteHash, bool isPublished)
Usage Flow
-
Record Each Turn (Conceptual Flow):
- Turn 1 (Initiator): Journalist sends initiator quote. System processes it, records it on the ledger (obtaining
TxID_Initiator1), and generates its C2PA manifest. - Turn 2 (Response): Source sends response quote. System processes the exchange, records the response quote using
recordEvidence(obtainingTxID_Response1), and generates its C2PA manifest. Crucially, this C2PA manifest must include a verifiable link back toTxID_Initiator1. TherecordEvidencecall anchors the response to the full exchange context (fullExchangeHash,storagePointer). - Turn 3 (Initiator): Journalist sends another initiator quote. System records it (obtaining
TxID_Initiator2) and generates its C2PA manifest, which must link back toTxID_Response1. - …and so on for the entire conversation.
- Turn 1 (Initiator): Journalist sends initiator quote. System processes it, records it on the ledger (obtaining
-
Authorization Control: The source/interviewee (owner) uses
setPublishedStatusto control publication authorization for their specific response quotes recorded via this contract. -
Verification: Publishers/readers use the C2PA manifest of any quote. The manifest allows verification of the quote itself against its ledger entry (
TxID_Current) and enables tracing the conversation backward by following the embedded link to the previous quote’s ledger entry (TxID_Previous). ThegetEvidencefunction can retrieve the full context hash and IPFS pointer associated with a specific recorded quote hash. -
Publication Check: Media outlets use
isQuotePublishedfor specific response quotes recorded via this contract. -
Authorization Control: The source/interviewee (owner) can call
setPublishedStatusto control whether their specific response quote is authorized for publication. -
Verification: Publishers and readers can call
getEvidenceusing the hash of a response quote to retrieve the evidence record, including the hash of the full exchange, which can be used (with appropriate access) to verify its authenticity and context. -
Publication Check: Media outlets can call
isQuotePublishedto verify whether a specific response quote is authorized for publication by the source.
GDPR Compliance
This smart contract design supports GDPR compliance by:
- Storing only cryptographic hashes and metadata on-chain, not personal data
- Keeping the full exchange content encrypted and off-chain on IPFS
- Allowing content owners to control publication status
- Providing a verifiable chain of custody for the conversation (via C2PA manifests linking preceding ledger entries) without exposing sensitive content directly on-chain.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.