Aqua ProtocolAqua Protocol
Aqua Protocol
Aqua ProtocolAqua

Documentation

Welcome to Aqua ProtocolQuick StartDevelopment GuideVersion v4 (beta)
Use Cases
Document VerificationIdentity AttestationAqua Protocol Use CasesSupply Chain Tracking
Development Tools
Aqua CLIAqua SDKAquafier API
Schema Reference
Aqua TreeFile IndexAqua Protocol Schema Reference
Revision Types
Link RevisionObject RevisionAqua Protocol RevisionsSignature RevisionTemplate RevisionWitness Revision

Documentation

Welcome to Aqua ProtocolQuick StartDevelopment GuideVersion v4 (beta)
Use Cases
Document VerificationIdentity AttestationAqua Protocol Use CasesSupply Chain Tracking
Development Tools
Aqua CLIAqua SDKAquafier API
Schema Reference
Aqua TreeFile IndexAqua Protocol Schema Reference
Revision Types
Link RevisionObject RevisionAqua Protocol RevisionsSignature RevisionTemplate RevisionWitness Revision
Docs
Schema Reference
Revision
Witness Revision

Witness Revision

Schema specification for Witness Revisions in Aqua Protocol v4

9 min read

Witness Revision

A Witness Revision provides cryptographic proof that a revision existed at a specific point in time. It anchors revision hashes to external systems like blockchains (Ethereum), decentralized networks (Nostr), or Trusted Timestamping Authorities (TSA). This creates an immutable, verifiable timestamp that cannot be backdated.

Overview

Witness revisions provide:

  • Timestamping: Cryptographic proof of when a revision existed
  • Immutability: Blockchain or TSA anchoring prevents backdating
  • Verifiability: Anyone can verify the witness independently
  • Batch Efficiency: Multiple revisions can be witnessed in a single transaction via Merkle trees
  • Decentralization: Uses public blockchains or decentralized networks

Schema Structure

Common Fields

FieldTypeRequiredDescription
previous_revisionstringYesHash reference to the revision being witnessed
revision_typestringYesAlways "witness" for witness revisions
noncestringYesRandom 16-byte hex string for uniqueness
local_timestampnumberYesUnix timestamp when the witness was created locally
versionstringYesProtocol version: "https://aqua-protocol.org/docs/v4/schema"
methodstringYesCanonicalization method: "scalar" (typical) or "tree"
hash_typestringYesHash algorithm: "FIPS_202-SHA3-256"
witnessobjectYesWitness value object containing proof details

Witness Value Object

The witness field contains details about the witnessing transaction:

FieldTypeRequiredDescription
merkle_proofarrayYesArray of hex strings forming the Merkle proof path
sender_account_addressstringYesAddress that submitted the witness transaction
transaction_hashstringYesTransaction hash on the blockchain or network
smart_contract_addressstringYesAddress of the witness contract (or endpoint URL)
networkstringYesNetwork identifier: "mainnet", "sepolia", "holesky", "tsa", or "nostr"
merkle_rootstringYesRoot hash of the Merkle tree stored on-chain
timestampnumberYesUnix timestamp from the blockchain/network

Network Types

1. Ethereum Networks

Mainnet

  • Network: "mainnet"
  • Purpose: Production witnessing on Ethereum mainnet
  • Cost: Higher gas fees
  • Security: Maximum security and permanence

Sepolia (Testnet)

  • Network: "sepolia"
  • Purpose: Testing and development
  • Cost: Free testnet ETH
  • Security: Testnet only, subject to resets

Holesky (Testnet)

  • Network: "holesky"
  • Purpose: Testing and development
  • Cost: Free testnet ETH
  • Security: Testnet only, newer Ethereum testnet

2. Trusted Timestamping Authority (TSA)

  • Network: "tsa"
  • Purpose: RFC 3161 compliant timestamping
  • Provider: DigiCert or other TSA services
  • Verification: Via TSA public certificates

3. Nostr

  • Network: "nostr"
  • Purpose: Decentralized social network timestamping
  • Verification: Via Nostr relays and events
  • Cost: Typically free

Example

Ethereum Witness (Sepolia)

Code
json
1{
2 "previous_revision": "0x3f8a7b2c9d1e4f5a6b8c0d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a",
3 "revision_type": "witness",
4 "nonce": "0x7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f",
5 "local_timestamp": 1704067200,
6 "version": "https://aqua-protocol.org/docs/v4/schema",
7 "method": "scalar",
8 "hash_type": "FIPS_202-SHA3-256",
9 "witness": {
10 "merkle_proof": [
11 "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
12 "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
13 "0x567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234"
14 ],
15 "sender_account_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb8",
16 "transaction_hash": "0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
17 "smart_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3",
18 "network": "sepolia",
19 "merkle_root": "0xa3bf4f1b2b0b822cd15d6c15b0f00a089f86d081884c7d659a2feaa0c55ad015",
20 "timestamp": 1704067250
21 }
22}

Single Revision Witness

When witnessing a single revision (no batching), the Merkle proof is empty:

Code
json
1{
2 "previous_revision": "0x3f8a7b2c9d1e4f5a6b8c0d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a",
3 "revision_type": "witness",
4 "nonce": "0x9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b",
5 "local_timestamp": 1704070800,
6 "version": "https://aqua-protocol.org/docs/v4/schema",
7 "method": "scalar",
8 "hash_type": "FIPS_202-SHA3-256",
9 "witness": {
10 "merkle_proof": [],
11 "sender_account_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb8",
12 "transaction_hash": "0x8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d",
13 "smart_contract_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3",
14 "network": "mainnet",
15 "merkle_root": "0x3f8a7b2c9d1e4f5a6b8c0d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a",
16 "timestamp": 1704070850
17 }
18}

Note: When merkle_proof is empty, merkle_root equals previous_revision.

Merkle Tree Batching

To reduce costs, multiple revisions can be witnessed in a single transaction using Merkle trees.

Process

  1. Collect Revisions: Gather multiple revision hashes to witness
  2. Build Merkle Tree: Create a Merkle tree from the revision hashes
  3. Submit Root: Submit only the Merkle root to the blockchain
  4. Generate Proofs: For each revision, generate its Merkle proof
  5. Create Witnesses: Create witness revisions with proofs

Example: Witnessing 4 Revisions

Revision Hashes: - Rev1: 0xaaaa... - Rev2: 0xbbbb... - Rev3: 0xcccc... - Rev4: 0xdddd... Merkle Tree: Root / \ H12 H34 / \ / \ Rev1 Rev2 Rev3 Rev4 Submit to blockchain: Root hash only Witness for Rev1: merkle_proof: [H12's sibling (Rev2), H12's parent's sibling (H34)] merkle_root: Root

Proof Verification

To verify a revision was witnessed:

  1. Start with revision hash
  2. Apply Merkle proof hashes (sibling hashes)
  3. Compute up the tree to get root
  4. Verify computed root matches merkle_root
  5. Verify merkle_root is on blockchain at transaction_hash

Validation Rules

A Witness Revision is valid if:

  1. Structure: Contains all required fields with correct types
  2. Revision Type: The revision_type is exactly "witness"
  3. Previous Revision: References a valid existing revision
  4. Network: One of the supported network values
  5. Timestamp Consistency:
    • witness.timestamp should be close to local_timestamp
    • Both should be reasonable (not far in future)
  6. Merkle Proof: If present, must be valid array of hex strings
  7. Transaction Verification: The transaction_hash exists on the specified network
  8. Merkle Root Verification: If batched, Merkle proof must lead to merkle_root
  9. On-Chain Verification: The merkle_root is stored at the smart_contract_address in the transaction
  10. Address Format: All addresses must be valid hex strings

Witness Smart Contract

Ethereum Contract Interface

The witness contract typically has a method like:

Code
solidity
1function witness(bytes32 merkleRoot) public returns (bool)

Verification Process

  1. Query blockchain for transaction at transaction_hash
  2. Verify transaction called the smart_contract_address
  3. Extract the witnessed value (merkle_root) from transaction data
  4. Verify it matches the merkle_root in the witness revision
  5. Check transaction timestamp matches timestamp field

Common Use Cases

1. Document Notarization

Document Object → Signature → Witness (Ethereum)

Proves the document existed and was signed at a specific time.

2. Batch Processing

100 Documents → Compute Hashes → Build Merkle Tree → Single Witness Transaction

Economical witnessing of many documents at once.

3. Legal Evidence

Evidence Object → Signature (Parties) → Witness (Mainnet)

Creates tamper-proof timestamp for legal proceedings.

4. Supply Chain

Shipment Event → Witness (Every checkpoint) → Audit Trail

Immutable record of supply chain events.

5. Credential Issuance

VC Issuance → Signature (Issuer) → Witness (Public verification)

Publicly verifiable credential issuance timestamps.

Timestamp Interpretation

local_timestamp

  • Created by client when preparing witness revision
  • Not trusted (can be manipulated)
  • Used for user display and rough ordering

witness.timestamp

  • Provided by blockchain/TSA
  • Trusted (immutable on-chain)
  • Authoritative time proof
  • Should be used for verification and legal purposes

Best Practice: Always use witness.timestamp for critical timestamp verification.

Cost Considerations

Ethereum

NetworkCostWhen to Use
Mainnet~$5-50 per transactionProduction, legal, high-value
SepoliaFree (testnet)Development, testing
HoleskyFree (testnet)Development, testing

Gas Optimization: Batch multiple witnesses into one transaction using Merkle trees.

TSA

  • Typically $0.10-1.00 per timestamp
  • Good for compliance requirements
  • RFC 3161 standard

Nostr

  • Free (decentralized network)
  • Lower trust than blockchain
  • Good for social proof

Implementation Notes

Creating a Witness Revision

  1. Identify the revision(s) to witness
  2. Choose network (mainnet, sepolia, etc.)
  3. If batching, build Merkle tree
  4. Submit transaction to blockchain
  5. Wait for transaction confirmation
  6. Extract transaction details
  7. Generate Merkle proofs (if batched)
  8. Create witness revision(s)

Verifying a Witness Revision

Single Revision (No Batching)

1. Verify merkle_proof is empty 2. Verify merkle_root equals previous_revision 3. Query blockchain for transaction_hash 4. Verify transaction exists and is confirmed 5. Extract witnessed value from transaction 6. Verify it matches merkle_root 7. Check transaction timestamp

Batched Revision

1. Verify merkle_proof is non-empty 2. Compute Merkle root using proof and previous_revision 3. Verify computed root matches merkle_root 4. Query blockchain for transaction_hash 5. Verify merkle_root is stored on-chain 6. Validate transaction timestamp

Error Handling

Common issues and solutions:

IssueSolution
Transaction not foundWait longer (may not be confirmed yet)
Wrong networkCheck transaction on correct network
Merkle proof invalidRegenerate proof from original tree
Timestamp mismatchCheck blockchain time vs local time
Gas estimation failedCheck wallet balance and gas price

Security Considerations

1. Network Selection

  • Use mainnet for production/legal purposes
  • Use testnets only for development
  • Consider compliance requirements

2. Confirmation Depth

  • Wait for sufficient confirmations (6+ for mainnet)
  • More confirmations = higher security
  • Balance security vs speed requirements

3. Merkle Proof Storage

  • Store proofs securely
  • Without proof, batched witness can't be verified
  • Consider proof backup strategies

4. Timestamp Trust

  • Trust blockchain timestamp over local_timestamp
  • Account for block time variability
  • Consider block reorganizations

5. Cost Management

  • Batch witnesses to reduce costs
  • Monitor gas prices
  • Use appropriate network for use case

Advanced Topics

Multi-Network Witnessing

Witness the same revision on multiple networks for redundancy:

Object → Signature → Witness (Ethereum) → Witness (Nostr) → Witness (TSA)

Each witness provides independent proof.

Periodic Re-Witnessing

For long-term preservation, periodically re-witness important revisions:

2024: Object → Witness (Mainnet) 2025: Link to Object → Witness (Mainnet) 2026: Link to 2025 → Witness (Mainnet)

Cross-Chain Verification

Witness on multiple blockchains for increased trust:

Object → Witness (Ethereum Mainnet) → Witness (Polygon) → Witness (Arbitrum)

Relationship with Other Revisions

  • Object Revisions: Primary target for witnessing
  • Signature Revisions: Often witnessed after signing
  • Link Revisions: Can be witnessed to prove connection timestamp
  • Template Revisions: Rarely witnessed (they're standalone)

See Also

  • Object Revision - What typically gets witnessed
  • Signature Revision - Often combined with witnessing
  • RFC 3161 - Timestamping - TSA standard
  • Ethereum Smart Contracts - On-chain witnessing
  • Merkle Trees - Batch witnessing structure
Edit this pageReport an issue
Previous
Template Revision

Documentation

  • Getting Started
  • API Reference

Community

  • GitHub
  • Discord

Copyright © 2024 Aqua. All rights reserved.

On this page

OverviewSchema StructureCommon FieldsWitness Value ObjectNetwork Types1. Ethereum Networks2. Trusted Timestamping Authority (TSA)3. NostrExampleEthereum Witness (Sepolia)Single Revision WitnessMerkle Tree BatchingProcessExample: Witnessing 4 RevisionsProof VerificationValidation RulesWitness Smart ContractEthereum Contract InterfaceVerification ProcessCommon Use Cases1. Document Notarization2. Batch Processing3. Legal Evidence4. Supply Chain5. Credential IssuanceTimestamp Interpretationlocal_timestampwitness.timestampCost ConsiderationsEthereumTSANostrImplementation NotesCreating a Witness RevisionVerifying a Witness RevisionError HandlingSecurity Considerations1. Network Selection2. Confirmation Depth3. Merkle Proof Storage4. Timestamp Trust5. Cost ManagementAdvanced TopicsMulti-Network WitnessingPeriodic Re-WitnessingCross-Chain VerificationRelationship with Other RevisionsSee Also