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
| Layer | Technology | Purpose | Confirmation time | Cost |
|---|
| 1. Record hashing | SHA-384 (Web Crypto) | Local integrity fingerprint | Instant | None |
| 2. Hash chain | Linked list with previous-hash | Sequential tamper detection | Instant | None |
| 3. RFC 3161 timestamping | TSA-signed tokens | Legal-grade temporal proof | < 5 seconds | Bundled |
| 4. OpenTimestamps | Bitcoin blockchain anchoring | Immutable global timestamp | ~10 minutes | Free |
| 5. EVM smart contract | UniversalAnchor on Polygon | Programmable on-chain attestation | ~2 seconds | ~$0.001/tx |
Protected Record Types
The integrity system covers 19 record types across four operational domains:
| Domain | Record type | Regulatory basis |
|---|
| Safety | Safety reports | 14 CFR 5.21 |
| Safety | Investigations | 14 CFR 5.63 |
| Safety | Corrective actions (CPAs) | 14 CFR 5.65 |
| Maintenance | Work orders | 14 CFR 43.9 |
| Maintenance | Inspections | 14 CFR 91.409 |
| Maintenance | AD/SB compliance | 14 CFR 39 |
| Maintenance | Discrepancies | 14 CFR 43.11 |
| Maintenance | MEL deferrals | 14 CFR 91.213 |
| Maintenance | FAA Form 337 | 14 CFR 43.9(a) |
| Maintenance | Part install/remove | 14 CFR 91.417(a)(2) |
| Flight ops | Flight logs | 14 CFR 91.417 |
| Flight ops | eAPIS filings | 19 CFR 122.49a |
| Flight ops | Weight & balance | 14 CFR 135.63 |
| Flight ops | FRAT risk assessments | AC 120-92D |
| Flight ops | Dispatch releases | 14 CFR 135.65 |
| Crew | Training records | 14 CFR 135.323 |
| Crew | Currency checks | 14 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.
| Property | SHA-384 | SHA-256 |
|---|
| Digest size | 48 bytes (96 hex chars) | 32 bytes (64 hex chars) |
| Algorithm ID | sha2-384 | sha2-256 |
| Web Crypto name | SHA-384 | SHA-256 |
| CNSA 2.0 status | Recommended | Acceptable (legacy) |
Canonical Serialization
Before hashing, record data is serialized into a canonical form:
- All keys are sorted alphabetically.
undefined values are omitted; null values are preserved.
- The result is JSON-stringified.
- 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:
- Genesis validity: The first entry (
chainSequence: 0) must have
previousHash: null.
- Sequence contiguity: Each entry’s
chainSequence must equal
previousEntry.chainSequence + 1.
- 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:
- Verify chain linkage (structure).
- 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:
| TSA | URL | Operator |
|---|
| DigiCert | http://timestamp.digicert.com | DigiCert Inc. |
| Sectigo | http://timestamp.sectigo.com | Sectigo Limited |
| Apple | http://timestamp.apple.com/ts01 | Apple 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
| Calendar | URL |
|---|
| Pool A | https://a.pool.opentimestamps.org |
| Pool B | https://b.pool.opentimestamps.org |
| Finney | https://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
- Submission: Digest bytes are POSTed to
/digest on the calendar server.
- Pending proof: The calendar returns an incomplete proof file containing
the calendar commitment. Stored with status
pending.
- Upgrade: A background process polls the calendar server to upgrade
pending proofs once the Bitcoin block is confirmed (typically 10—60 minutes).
- 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
| Operation | Approximate cost | Records covered |
|---|
| Single anchor (V1) | ~$0.001 | 1 |
| Single anchor (V2) | ~$0.001 | 1 |
| Batch of 10 (V2) | ~$0.008 | 10 |
| Batch of 100 (V2) | ~$0.075 | 100 |
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
| Contract | Network | Chain ID | Address | Explorer |
|---|
| RecordAnchor V1 | Polygon Amoy (testnet) | 80002 | 0x86007a431A521792D4Bf459B81E85a2a85Dad627 | PolygonScan |
| UniversalAnchor V2 | Polygon Amoy (testnet) | 80002 | 0xcE42455d789624d509206FF844Ef3afCD8Ef34b8 | PolygonScan |
| UniversalAnchor V2 | Ethereum Sepolia | — | Planned | — |
| UniversalAnchor V2 | Polygon mainnet | 137 | Planned | — |
Transaction Flow
- Record hashes are batched into a Merkle tree and the root is computed.
- For V1: the root (padded to bytes32) is submitted as a single anchor call.
- For V2: one or more roots are submitted in a batch call with workspace and
record-type metadata.
- The transaction is confirmed with 1 block confirmation (60-second timeout).
- 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
| Strategy | Layers activated |
|---|
full | RFC 3161 + OpenTimestamps + EVM (default) |
rfc3161-only | RFC 3161 only |
ots-only | OpenTimestamps only |
evm-only | EVM 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
| State | Description |
|---|
| Pending | Anchor request submitted but confirmation not yet received. |
| Anchored | Anchor accepted by external system (TSA signed, OTS calendar committed, EVM tx submitted). |
| Confirmed | Sufficient confirmations received (RFC 3161: immediate; OTS: Bitcoin block mined; EVM: 1 block). |
| Verified | Independently verified by PlaneConnection’s cross-layer verification service. |
| Expired | Anchor no longer actively verifiable (e.g., TSA certificate chain expired). Historical validity preserved. |
| Failed | Anchor 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:
| Component | RFC 3161 | OTS | EVM |
|---|
| Record canonical JSON | Yes | Yes | Yes |
| SHA-384 hash | Yes | Yes | Yes |
| Hash chain position | Yes | Yes | Yes |
| RFC 3161 TST (DER bytes) | Yes | No | No |
| TSA certificate chain | Yes | No | No |
| OTS proof file | No | Yes | No |
| Bitcoin block header | No | Yes | No |
| EVM transaction hash | No | No | Yes |
| Contract address | No | No | Yes |
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.