Skip to main content
PlaneConnection’s record integrity system uses five independent layers to provide cryptographically verifiable, tamper-evident records across safety, maintenance, flight ops, and crew domains. This page documents each layer’s technical specifications, the proof lifecycle states, and the anchoring orchestration. For background on the trust model and regulatory motivation, see Record Integrity Architecture. For step-by-step verification procedures, see Verify Record Integrity.

Five-Layer Architecture Summary

LayerTechnologyPurposeConfirmation timeCost
1. Record hashingSHA-384 (Web Crypto)Local integrity fingerprintInstantNone
2. Hash chainLinked list with previous-hashSequential tamper detectionInstantNone
3. RFC 3161 timestampingTSA-signed tokensLegal-grade temporal proof< 5 secondsBundled
4. OpenTimestampsBitcoin blockchain anchoringImmutable global timestamp~10 minutesFree
5. EVM smart contractUniversalAnchor on PolygonProgrammable on-chain attestation~2 seconds~$0.001/tx

Protected Record Types

The integrity system covers 19 record types across four operational domains:
DomainRecord typeRegulatory basis
SafetySafety reports14 CFR 5.21
SafetyInvestigations14 CFR 5.63
SafetyCorrective actions (CPAs)14 CFR 5.65
MaintenanceWork orders14 CFR 43.9
MaintenanceInspections14 CFR 91.409
MaintenanceAD/SB compliance14 CFR 39
MaintenanceDiscrepancies14 CFR 43.11
MaintenanceMEL deferrals14 CFR 91.213
MaintenanceFAA Form 33714 CFR 43.9(a)
MaintenancePart install/remove14 CFR 91.417(a)(2)
Flight opsFlight logs14 CFR 91.417
Flight opseAPIS filings19 CFR 122.49a
Flight opsWeight & balance14 CFR 135.63
Flight opsFRAT risk assessmentsAC 120-92D
Flight opsDispatch releases14 CFR 135.65
CrewTraining records14 CFR 135.323
CrewCurrency checks14 CFR 61.57

Layer 1: Record Hashing

Algorithm

SHA-384 is the default hash algorithm, selected per CNSA 2.0 (Committee on National Security Systems Advisory) mandate for post-quantum crypto agility. SHA-256 is supported for backward compatibility.
PropertySHA-384SHA-256
Digest size48 bytes (96 hex chars)32 bytes (64 hex chars)
Algorithm IDsha2-384sha2-256
Web Crypto nameSHA-384SHA-256
CNSA 2.0 statusRecommendedAcceptable (legacy)

Canonical Serialization

Before hashing, record data is serialized into a canonical form:
  1. All keys are sorted alphabetically.
  2. undefined values are omitted; null values are preserved.
  3. The result is JSON-stringified.
  4. If the record has a predecessor in the chain, the previous hash is prepended with a colon separator: {previousHash}:{canonicalJSON}.
Input: { technician: "John", type: "inspection", date: "2026-03-15" }
Canonical: {"date":"2026-03-15","technician":"John","type":"inspection"}
With chain: "a1b2c3...previous_hash:{"date":"2026-03-15","technician":"John","type":"inspection"}"

Hash Result

Every hash computation returns both the hex digest and the algorithm identifier, enabling future algorithm migration without breaking verification:
interface HashResult {
  hash: string; // Lowercase hex-encoded digest
  algorithm: "sha2-384" | "sha2-256";
}

Layer 2: Hash Chain

Chain Structure

Each aircraft maintains its own hash chain — a sequential linked list where every record references the hash of its immediate predecessor.
Record 0 (genesis)        Record 1                 Record 2
┌────────────────────┐    ┌────────────────────┐    ┌────────────────────┐
│ previousHash: null │    │ previousHash: H(0) │    │ previousHash: H(1) │
│ chainSequence: 0   │    │ chainSequence: 1   │    │ chainSequence: 2   │
│ recordHash: H(0)   │    │ recordHash: H(1)   │    │ recordHash: H(2)   │
└────────────────────┘    └────────────────────┘    └────────────────────┘

Chain Verification Rules

Chain verification checks three invariants:
  1. Genesis validity: The first entry (chainSequence: 0) must have previousHash: null.
  2. Sequence contiguity: Each entry’s chainSequence must equal previousEntry.chainSequence + 1.
  3. Hash linkage: Each entry’s previousHash must equal the preceding entry’s recordHash.
A break at any position invalidates that record and all subsequent records in the chain.

Full Verification

Full verification combines chain verification with individual record re-hashing:
  1. Verify chain linkage (structure).
  2. For each record, re-compute the hash from source data and compare to the stored recordHash.
The result includes the chain length, count of records verified, count of failures, and the sequence position where the chain first breaks (if any).

Merkle Tree

For external anchoring, individual record hashes are batched into a binary Merkle tree using SHA-384:
  • Pairs of hashes are concatenated and hashed to produce parent nodes.
  • If a level has an odd number of nodes, the last node is duplicated.
  • The root of the tree is a single hash representing all records in the batch.
The Merkle root is what gets submitted to RFC 3161, OpenTimestamps, and EVM anchors, allowing a single anchor transaction to cover many records.

Layer 3: RFC 3161 Trusted Timestamping

Protocol

RFC 3161 (IETF) defines the Time-Stamp Protocol (TSP). PlaneConnection builds DER-encoded TimeStampReq messages and submits them to accredited TSAs over HTTPS.

TSA Endpoints

Hashes are submitted to three TSAs in parallel for redundancy:
TSAURLOperator
DigiCerthttp://timestamp.digicert.comDigiCert Inc.
Sectigohttp://timestamp.sectigo.comSectigo Limited
Applehttp://timestamp.apple.com/ts01Apple Inc.
Any single successful response provides sufficient temporal proof. Having multiple TSAs protects against TSA downtime and provides independent corroboration.

TimeStampReq Structure

TimeStampReq ::= SEQUENCE {
  version        INTEGER { v1(1) },
  messageImprint SEQUENCE {
    hashAlgorithm  SEQUENCE {
      algorithm      OID (2.16.840.1.101.3.4.2.2 for SHA-384),
      parameters     NULL
    },
    hashedMessage  OCTET STRING (48 bytes for SHA-384)
  },
  certReq        BOOLEAN TRUE
}

Token Structure

Time-Stamp Token (CMS SignedData)
├── TSTInfo
│   ├── version
│   ├── policy (TSA's timestamping policy OID)
│   ├── messageImprint
│   │   ├── hashAlgorithm: SHA-384
│   │   └── hashedMessage: <48-byte hash>
│   ├── serialNumber
│   ├── genTime: <UTC timestamp, millisecond precision>
│   ├── nonce
│   └── tsa: <TSA Distinguished Name>
└── SignerInfo (TSA signature over TSTInfo)

Verification

openssl ts -verify \
  -in timestamp.tsr \
  -data record_canonical.json \
  -CAfile tsa_ca_chain.pem

Layer 4: OpenTimestamps (Bitcoin Anchoring)

Protocol

OpenTimestamps aggregates hashes into a Merkle tree and anchors the root in a Bitcoin transaction’s OP_RETURN output. This provides the strongest immutability guarantee — rewriting a Bitcoin anchor requires controlling 51% of the Bitcoin network’s hash power.

Calendar Servers

CalendarURL
Pool Ahttps://a.pool.opentimestamps.org
Pool Bhttps://b.pool.opentimestamps.org
Finneyhttps://finney.calendar.eternitywall.com

Digest Requirements

OTS calendars require exactly 32-byte (SHA-256) digests. When the record uses SHA-384, the hex string is first re-hashed with SHA-256 to produce the required 32 bytes before submission.

Proof Lifecycle

  1. Submission: Digest bytes are POSTed to /digest on the calendar server.
  2. Pending proof: The calendar returns an incomplete proof file containing the calendar commitment. Stored with status pending.
  3. Upgrade: A background process polls the calendar server to upgrade pending proofs once the Bitcoin block is confirmed (typically 10—60 minutes).
  4. Complete proof: The upgraded proof contains the full Merkle path from the record hash to the Bitcoin block header. Status becomes confirmed.

Verification

pip install opentimestamps-client
ots verify record_canonical.json.ots -f record_canonical.json
Or verify online at opentimestamps.org.

Layer 5: EVM Smart Contract

PlaneConnection has deployed two generations of anchor contracts. Both are live and referenced by existing proofs.

RecordAnchor V1

The original anchor contract — a minimal Solidity contract that stores bytes32 Merkle roots with timestamps. No access control; gas cost is the economic gate.
contract RecordAnchor {
  struct Anchor {
    bytes32 merkleRoot;
    uint256 timestamp;
    address sender;
  }

  mapping(bytes32 => Anchor) public anchors;

  event Anchored(
    bytes32 indexed merkleRoot,
    address indexed sender,
    uint256 timestamp
  );

  function anchor(bytes32 merkleRoot) external {
    anchors[merkleRoot] = Anchor(merkleRoot, block.timestamp, msg.sender);
    emit Anchored(merkleRoot, msg.sender, block.timestamp);
  }

  function getAnchor(bytes32 merkleRoot)
    external view returns (Anchor memory)
  {
    return anchors[merkleRoot];
  }
}

UniversalAnchor V2

The current-generation anchor contract extends V1 with batch anchoring, workspace and record-type scoping, access control, and an emergency pause mechanism. Key features:
  • Batch anchoring. Anchor hundreds of Merkle roots in a single transaction, dramatically reducing gas costs for high-volume operators.
  • Workspace scoping. Each anchor is associated with a workspace identifier, enabling efficient per-operator querying and audit filtering.
  • Record-type classification. Anchors carry a record-type tag (e.g., safety_report, work_order, flight_log), enabling domain-specific verification queries.
  • Ownable access control. Only authorized addresses can submit anchors, preventing unauthorized writes.
  • Pausable emergency stop. The contract owner can pause anchoring in an emergency without redeploying, then resume when the issue is resolved.

Gas Cost Comparison

OperationApproximate costRecords covered
Single anchor (V1)~$0.0011
Single anchor (V2)~$0.0011
Batch of 10 (V2)~$0.00810
Batch of 100 (V2)~$0.075100
Batch anchoring means a busy Part 135 operation generating dozens of records per day can anchor them all for less than a penny per record. The per-record cost decreases as batch size increases.

Deployed Addresses

ContractNetworkChain IDAddressExplorer
RecordAnchor V1Polygon Amoy (testnet)800020x86007a431A521792D4Bf459B81E85a2a85Dad627PolygonScan
UniversalAnchor V2Polygon Amoy (testnet)800020xcE42455d789624d509206FF844Ef3afCD8Ef34b8PolygonScan
UniversalAnchor V2Ethereum SepoliaPlanned
UniversalAnchor V2Polygon mainnet137Planned

Transaction Flow

  1. Record hashes are batched into a Merkle tree and the root is computed.
  2. For V1: the root (padded to bytes32) is submitted as a single anchor call.
  3. For V2: one or more roots are submitted in a batch call with workspace and record-type metadata.
  4. The transaction is confirmed with 1 block confirmation (60-second timeout).
  5. The transaction hash, block number, and gas used are stored alongside the records.

Verification

Block explorer: Search the transaction hash on PolygonScan (Amoy). The Anchored event log shows the Merkle root, sender, and block timestamp. For V2 batch transactions, each root in the batch emits a separate event with its workspace and record-type tags. Programmatic: Query the contract’s getAnchor function (V1) or getAnchor with workspace filtering (V2) using any Ethereum-compatible client library. The returned struct contains the Merkle root, timestamp, and sender address.

Anchor Orchestrator

The anchor orchestrator coordinates all three external layers in parallel. A failure in one layer does not block the others.

Strategies

StrategyLayers activated
fullRFC 3161 + OpenTimestamps + EVM (default)
rfc3161-onlyRFC 3161 only
ots-onlyOpenTimestamps only
evm-onlyEVM only
Individual layers can also be skipped regardless of strategy.

Result

The orchestrator returns a result containing:
  • The Merkle root that was anchored.
  • The hash algorithm used.
  • An array of layer results (one per activated layer), each with success/failure status and layer-specific tokens, proofs, or transaction data.
  • The anchoredAt timestamp.
  • A flag indicating whether every activated layer succeeded.

Proof Lifecycle States

StateDescription
PendingAnchor request submitted but confirmation not yet received.
AnchoredAnchor accepted by external system (TSA signed, OTS calendar committed, EVM tx submitted).
ConfirmedSufficient confirmations received (RFC 3161: immediate; OTS: Bitcoin block mined; EVM: 1 block).
VerifiedIndependently verified by PlaneConnection’s cross-layer verification service.
ExpiredAnchor no longer actively verifiable (e.g., TSA certificate chain expired). Historical validity preserved.
FailedAnchor submission failed and could not be retried. Record is still protected by other layers.

State Transitions

              ┌──────────┐
  [Record     │          │
   saved]────►│ Pending  │
              │          │
              └─────┬────┘
                    │ anchor accepted

              ┌──────────┐
              │ Anchored │
              └─────┬────┘
                    │ confirmations received

              ┌──────────┐
              │Confirmed │
              └─────┬────┘
                    │ verification service confirms

              ┌──────────┐         ┌─────────┐
              │ Verified │────────►│ Expired │
              └──────────┘  cert   └─────────┘
                            expiry

Cross-Layer Verification

A periodic verification process compares the canonical record hash against hashes stored in each anchor layer. If any layer’s hash disagrees with the base hash, the record is flagged as inconsistent and a tamper alert is generated. The check processes up to 500 anchored records per run. Records without any anchor layers are skipped. The result includes counts of checked, consistent, and inconsistent records, plus human-readable alerts for each discrepancy.

Proof Bundle Contents

When you export a proof bundle from PlaneConnection, it contains the following for each included record:
ComponentRFC 3161OTSEVM
Record canonical JSONYesYesYes
SHA-384 hashYesYesYes
Hash chain positionYesYesYes
RFC 3161 TST (DER bytes)YesNoNo
TSA certificate chainYesNoNo
OTS proof fileNoYesNo
Bitcoin block headerNoYesNo
EVM transaction hashNoNoYes
Contract addressNoNoYes

Record Integrity Architecture

Why five layers, regulatory context, and trust model design.

Verify Record Integrity

Step-by-step verification and proof bundle export guide.

Manage Work Orders

Work orders that generate records added to the hash chain.

Notification Channels

Alert configuration for hash chain break notifications.
Last modified on April 11, 2026