Abstract
A Multi-Layer Security Framework for Edge-Based Smart Parking with Lightweight Hash Chain Integrity Verification and Cloud Anchoring
Abstract
Smart parking systems have emerged as a critical component of intelligent transportation infrastructure, enabling real-time monitoring of parking occupancy to reduce traffic congestion and improve urban mobility. However, existing systems predominantly transmit raw video data to centralised cloud servers without integrity guarantees, rendering them vulnerable to adversarial manipulation such as frame injection, replay attacks, metadata tampering, and physical sensor spoofing. These vulnerabilities undermine the trustworthiness of parking data, which is increasingly used for automated enforcement, billing, and urban planning decisions.
This thesis proposes and evaluates a three-layer security framework for an edge-based smart parking detection system deployed on an NVIDIA Jetson Nano developer kit. The first layer employs Canny edge detection with manually defined polygon regions of interest (ROI) to classify parking slot occupancy from a live RTSP camera stream. The second layer applies edge-local processing with data minimisation on the integrity path: the integrity mechanism transmits only cryptographic hashes and detection metadata to the cloud, requiring no visual content for verification. Uploading the JPEG frames themselves to a private, access-controlled S3 bucket is a configurable operational feature (enabled in this deployment to support the live dashboard, audit, and ground-truth labelling), on which the integrity guarantees do not depend. The third layer — the primary contribution of this thesis — implements a lightweight SHA-256 hash chain that records every captured frame as a cryptographically linked block, providing verifiable proof of the integrity and chronological order of the parking video record. Cloud anchoring to AWS DynamoDB provides an independent timestamp reference that extends integrity guarantees beyond the local device.
The framework was evaluated through fourteen experiments comprising ten tamper detection experiments (E1–E10) and four performance benchmarks (P1–P4), with a minimum of 30 independent trials per completed experiment to satisfy Central Limit Theorem requirements for parametric statistical analysis. Tamper detection experiments assessed the system's ability to detect frame modification, frame deletion, frame injection, metadata tampering, hash record alteration, replay attacks, chain rewrite attempts, feed substitution, timestamp manipulation, and physical sensor spoofing. Performance benchmarks measured security overhead (CPU and RAM), hash throughput, verification time scaling, and long-duration operational stability. [PENDING: E10 physical sensor spoofing field data are scheduled — update this abstract once complete; see SONNET_TASK_PLAN.md T3.3.]
Results demonstrate that the proposed hash chain achieves a detection rate of 100% for experiments E1–E5 and E8–E9, confirming complete detection of cryptographic-layer, feed-substitution, and timestamp-manipulation attacks. Replay attack detection (E6) achieves 53.3% (16/30) overall: scenarios that alter block metadata without recomputing the block hash are always detected by local self-integrity verification, while scenarios that recompute the hash after replay evade local detection — a limitation discussed in relation to the cloud anchor's independent timestamp record. Chain rewrite time (E7) grows linearly with the number of rewritten blocks (0.49 ms at K=10 to 39.6 ms at K=1,000), confirming the computational deterrent against large-scale tampering even though local rewrites are, by design, undetectable through self-verification alone — motivating the cloud-anchored checkpoint as a second line of defence. Hash throughput (P2) reaches 12,160.7 hashes per second on the Jetson Nano, confirming that the cryptographic layer does not introduce a processing bottleneck. Verification time scaling (P3) is confirmed to be O(n) with R² = 0.9998. Security overhead (P1) shows no statistically significant increase in CPU utilisation (t(29) = 1.99, p = 0.056), and a 24-hour stability test (P4; 23.2 hours between first and last samples, following an initial 4.85-hour pilot run) revealed no memory leak (RAM drift +0.63 MB over the run, slope 0.0133 MB/sample) and no CPU drift (CPU mean 0.58%, SD 0.25). The system demonstrates that a lightweight, consensus-free hash chain with cloud anchoring can provide robust video stream integrity guarantees on resource-constrained edge devices without compromising detection performance, while minimising the data placed on the integrity path.
Keywords: smart parking, edge computing, lightweight hash chain, blockchain-inspired integrity verification, cloud anchoring, Canny edge detection, NVIDIA Jetson Nano, AWS DynamoDB, tamper detection, data minimisation
Chapter 1 — Introduction
Not yet written.
This chapter has not been drafted. It is shown here so the table of contents reflects the true state of the thesis rather than omitting the gap.
Chapter 2 — Literature Review
Not yet written.
This chapter has not been drafted. It is shown here so the table of contents reflects the true state of the thesis rather than omitting the gap.
Chapter 3 — Methodology
Chapter 3: Methodology
3.1 Overview of Proposed Framework
This chapter describes the methodology adopted to design and implement a multi-layered security framework for an edge-based smart parking detection system. The proposed framework integrates three distinct layers: a computer vision layer for parking occupancy detection, an edge-local processing layer with data minimisation on the integrity path, and a lightweight, blockchain-inspired hash chain layer for video stream integrity verification. Together, these layers form a cohesive system deployed on an NVIDIA Jetson Nano developer kit, a resource-constrained edge computing device capable of real-time inference and local data processing.
The primary motivation for this framework arises from the vulnerability of conventional parking detection systems to data manipulation. In existing systems, video feeds and detection results are transmitted to cloud servers without integrity guarantees, making them susceptible to adversarial attacks such as frame injection, replay attacks, and metadata tampering. The proposed framework addresses these vulnerabilities by anchoring each captured frame to a cryptographic hash chain, ensuring that any modification to the video record is detectable.
Figure 3.1 illustrates the overall system architecture and the flow of data across all three layers.
RTSP Camera (IP Camera)
|
v
[Layer 1: Canny Edge Detection]
- Capture frame every 5 seconds
- Define ROI polygons per parking slot
- Detect: empty / occupied
|
v
[Layer 2: Edge-Local Processing + Data Minimisation]
- Encode frame to JPEG (locally)
- Compute SHA-256 frame hash
- Store raw frame on Jetson Nano
|
v
[Layer 3: Lightweight Hash Chain]
- Build Block (hash + detection result + metadata)
- Append to local hash chain (SQLite)
- Auto-checkpoint to AWS DynamoDB every 10 blocks
- Upload detection status + hash to cloud (checkpoint path: hash + status only)
Figure 3.1: Three-layer system architecture of the proposed parking security framework.
3.1.1 Threat Model
To scope the security guarantees evaluated in this thesis, an explicit threat model is defined. The model assumes an adversary with the following capabilities:
- Read/write access to stored artefacts on the edge device: the adversary can read, modify, delete, or insert entries in the local hash chain database (
chain.db) and in locally stored JPEG frames, as if they had gained filesystem access to the Jetson Nano (e.g., through physical access, a compromised SSH credential, or an unpatched local service). - Network man-in-the-middle (MITM) capability: the adversary can intercept or modify data in transit between the edge device and the cloud (e.g., forged or replayed status updates), within the bounds of standard TLS-protected AWS SDK connections.
- Physical camera substitution or obstruction: the adversary can substitute the live RTSP feed with a pre-recorded or static feed, or physically obstruct/decorate the camera's field of view (evaluated under E8 and E10 respectively).
The following are explicitly out of scope for this thesis and are not defended against by the proposed framework:
- Independent compromise of the AWS account or operator credentials — that is, an adversary who obtains cloud write access by means other than compromising the edge device, such as a leaked operator access key or a misconfigured account policy. Securing operator-side credential management is treated as a standard cloud-security operational concern, not a research contribution of this work.
- Compromise of the running detection process itself. If an adversary gains the ability to execute arbitrary code within the running
parking_detector.pyprocess (e.g., via a supply-chain attack on a Python dependency), they could forge valid blocks before they are hashed, since the hash chain protects data after capture, not the integrity of the capture pipeline itself. - Denial-of-service attacks against the RTSP camera, the Jetson Nano, or AWS availability.
A qualification on the boundary between these two scopes. The in-scope and out-of-scope capabilities above are not fully separable in the system as deployed. The edge device must hold IAM credentials permitting PutItem on the parking_blockchain table in order to upload checkpoints at all, so an adversary who achieves the in-scope capability of device write access thereby also inherits cloud write access — not through an independent compromise of the AWS account, but as a direct consequence of a capability this model admits. Combined with two implementation properties (checkpoint uploads are unconditional overwrites, and the anchored_at field is device-generated; see §3.5.6), this means the cloud anchor as evaluated in this thesis provides no guarantee against the very adversary the model places in scope. This is stated here rather than deferred because it materially qualifies the results reported in Chapter 5: the analysis in §5.4.3 and the hardening specified in §5.4.5 follow directly from it. Making the boundary hold requires the checkpoint store to be append-only under a service identity the device does not possess, and the anchoring time to be server-derived; both are specified in §5.4.5 and are the immediate next step for this work.
This threat model directly motivates the ten tamper-detection experiments (E1–E10, §3.6.3): each experiment instantiates one concrete attack within the in-scope capabilities above, applied to a copy of the hash chain, allowing the detection rate and latency of the proposed framework to be measured against a realistic adversary rather than an unbounded one.
3.2 Hardware and Software Environment
3.2.1 Edge Device
The system runs on an NVIDIA Jetson Nano Developer Kit, a single-board computer designed for edge AI applications. Table 3.1 summarises the hardware specifications of the device used in this study.
| Component | Specification |
|---|---|
| CPU | ARM Cortex-A57 (Quad-core, 1.43 GHz) |
| GPU | NVIDIA Maxwell (128 CUDA cores) |
| RAM | 4 GB LPDDR4 |
| Storage | 128 GB eMMC |
| OS | Ubuntu 18.04 LTS |
| Python | 3.8 |
Table 3.1: Hardware specifications of the NVIDIA Jetson Nano Developer Kit.
The Jetson Nano was selected for its balance between computational capability and power efficiency, making it suitable for continuous long-term deployment in a parking facility environment.
3.2.2 Camera
An IP camera with RTSP (Real-Time Streaming Protocol) support is used to capture the parking lot footage. The camera is mounted at an elevated angle to provide a bird's-eye view of the monitored parking area. The RTSP stream is accessed at a resolution of 1020×600 pixels, which provides sufficient detail for edge detection while minimising processing overhead on the Jetson Nano.
3.2.3 Cloud Infrastructure
AWS (Amazon Web Services) is used as the cloud backend for the system. Two DynamoDB tables are provisioned:
parking_frames— stores detection status, frame hash, block index, and S3 URI per captured frame.parking_blockchain— stores cloud anchor checkpoints (block hash, frame hash, timestamp) for integrity verification.
An S3 bucket (parking-detection-frames) stores the JPEG frames uploaded from the Jetson Nano.
3.2.4 Software Stack
| Library | Version | Purpose |
|---|---|---|
| OpenCV | 4.11.0 | Frame capture, Canny detection, ROI masking |
| NumPy | 1.24.4 | Array operations |
| boto3 | 1.37.15 | AWS S3 and DynamoDB integration |
| SciPy | 1.10.1 | Statistical analysis (t-test, regression) |
| Matplotlib | 3.7.5 | Chart generation |
| psutil | 7.2.2 | CPU and RAM monitoring |
| SQLite3 | Built-in | Local hash chain persistence |
| hashlib | Built-in | SHA-256 cryptographic hashing |
Table 3.2: Software dependencies and their roles in the system.
3.3 Layer 1 — Parking Occupancy Detection
3.3.1 Region of Interest (ROI) Definition
Before the detection system can operate, the parking slots within the camera's field of view must be defined. This is accomplished using a custom interactive tool (roi_selector.py) that displays a live frame from the RTSP stream and allows the operator to manually trace polygon boundaries around each parking slot using mouse clicks.
The ROI definition process is as follows:
- The operator runs
roi_selector.py, which connects to the RTSP stream and captures a single reference frame. - The operator left-clicks to mark corner points of each parking slot polygon.
- A right-click completes the current polygon and begins the next.
- Upon pressing
s, all polygon coordinates are saved torois.json.
A total of 14 parking slots were defined for this study. Each polygon is stored as a list of (x, y) coordinate pairs in JSON format. This approach allows ROI definitions to be updated whenever the camera position changes without modifying the detection code.
3.3.2 Canny Edge Detection
Canny edge detection was selected as the occupancy detection algorithm for the following reasons:
- Computational efficiency — Canny operates on CPU without requiring GPU acceleration, leaving the Jetson Nano GPU available for other tasks.
- Robustness to lighting variation — the Gaussian smoothing step in Canny reduces sensitivity to minor lighting changes between day and night.
- No training data required — unlike deep learning approaches (e.g., YOLO), Canny does not require a labelled dataset, making it practical for rapid deployment.
The detection process for each frame is as follows:
- For each ROI polygon, a binary mask is applied to isolate the parking slot region.
- The masked region is converted to grayscale.
- Canny edge detection is applied with
Threshold1 = 100andThreshold2 = 200. - The number of non-zero (edge) pixels within the mask is counted.
- If the edge pixel count exceeds 300, the slot is classified as occupied; otherwise, it is classified as empty.
The threshold values (100, 200) and the pixel count threshold were determined empirically through calibration trials on the target parking area. The pixel count threshold was initially set at 500 but was revised downward to 300 during deployment after observing that the higher threshold missed vehicles that produced fewer detectable edges under certain lighting and occlusion conditions.
# Simplified detection logic (from parking_detector.py)
for polygon in rois:
mask = np.zeros(frame.shape[:2], dtype=np.uint8)
cv2.fillPoly(mask, [np.array(polygon, np.int32)], 255)
masked = cv2.bitwise_and(frame, frame, mask=mask)
gray = cv2.cvtColor(masked, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200)
status = "occupied" if np.count_nonzero(edges) > 300 else "empty"
3.3.3 Frame Capture Strategy
Frames are captured from the RTSP stream at a fixed interval of 5 seconds rather than only upon status change. This design decision was made for the following reasons:
- Continuous integrity monitoring: capturing every 5 seconds eliminates temporal gaps in the hash chain. A status-change-only approach would leave potentially long intervals during which the video feed could be substituted without detection.
- Sufficient responsiveness: a 5-second interval is adequate for detecting parking events, as vehicles typically take 10–30 seconds to enter or exit a slot.
- Predictable chain growth: fixed-interval capture ensures the hash chain grows at a consistent rate of approximately 720 blocks per hour, which facilitates performance benchmarking.
3.4 Layer 2 — Edge-Local Processing with Data Minimisation
3.4.1 Data Minimisation on the Integrity Path
Layer 2 applies data minimisation to the integrity path: parking occupancy is classified locally on the Jetson Nano, and the integrity mechanism (Layer 3's hash chain and its DynamoDB checkpoints) uploads only derived data — no visual content is required to verify integrity. The data uploaded on this integrity path are limited to:
- SHA-256 hash of the JPEG-encoded frame
- Detection status (empty/occupied) for each parking slot
- Timestamp and block index
Frame images themselves are uploaded to cloud storage over a separate, configurable operational channel (§4.3.2, UPLOAD_FRAMES_TO_S3), enabled in this deployment to support the live dashboard, audit, and ground-truth labelling; the integrity guarantees are independent of it and hold identically when it is disabled.
This design means that the integrity checkpoint path stored in DynamoDB carries no visual content, so no raw video footage can be reconstructed from the checkpoint records alone. When the operational frame-upload channel is enabled, the frame images themselves reside in a private, access-controlled S3 bucket under the operator's control (§4.3.2).
3.4.2 Frame Hashing
Upon capture, each frame is JPEG-encoded and its SHA-256 hash is computed locally before any transmission:
_, buf = cv2.imencode(".jpg", frame)
frame_bytes = buf.tobytes()
frame_hash = hashlib.sha256(frame_bytes).hexdigest()
The resulting hash is a 64-character hexadecimal string that uniquely identifies the frame content. Any modification to the frame — even a single pixel — will produce a completely different hash value, making tampering detectable.
3.5 Layer 3 — Lightweight Hash Chain for Integrity Verification
This layer constitutes the primary contribution of this thesis. A lightweight hash chain is implemented to provide cryptographic proof of the integrity and chronological order of all captured parking frames.
3.5.1 Block Structure
Each block in the chain encapsulates the following fields:
| Field | Type | Description |
|---|---|---|
block_index |
Integer | Sequential position in the chain |
timestamp |
String (ISO 8601) | UTC time of block creation |
frame_hash |
String (hex) | SHA-256 hash of the captured frame |
detection_result |
Dict | Parking status per slot |
device_id |
String | Identifier of the Jetson Nano device |
previous_hash |
String (hex) | Hash of the preceding block |
block_hash |
String (hex) | SHA-256 hash of all above fields |
Table 3.3: Fields of a single block in the hash chain.
The block_hash is computed as follows:
payload = json.dumps({
"block_index": self.block_index,
"timestamp": self.timestamp,
"frame_hash": self.frame_hash,
"detection_result": self.detection_result,
"device_id": self.device_id,
"previous_hash": self.previous_hash,
}, sort_keys=True).encode()
self.block_hash = hashlib.sha256(payload).hexdigest()
Using sort_keys=True ensures that the JSON serialisation is deterministic regardless of dictionary insertion order, guaranteeing consistent hash values.
3.5.2 Genesis Block
The chain is initialised with a genesis block (block index 0), which serves as the immutable anchor of the chain. Its previous_hash and frame_hash are set to a string of 64 zeros, signifying the start of the chain. No frame data is associated with the genesis block.
3.5.3 Chain Construction
For each captured frame, a new block is appended to the chain:
- Compute
frame_hash= SHA-256(JPEG bytes) - Retrieve
previous_hashfrom the tip of the chain - Instantiate a new
Blockwith all fields - Compute
block_hash= SHA-256(all fields) - Append to in-memory chain
- Persist to SQLite database (
chain.db) - If
block_index % 10 == 0, upload checkpoint to DynamoDB
3.5.4 Chain Verification
The integrity of the hash chain is verified by iterating over all blocks and checking two conditions for each block i:
- Self-integrity:
block.block_hash == SHA-256(block fields)— detects any modification to the block's own content. - Chain linkage:
block.previous_hash == chain[i-1].block_hash— detects deletion, insertion, or reordering of blocks.
If either condition fails, the verification returns (False, i, elapsed_ms), where i is the index of the first compromised block. This O(n) verification algorithm is empirically characterised in Experiment P3.
3.5.5 SQLite Persistence
All blocks are persisted to a local SQLite database (chain.db) via the ChainStorage class. SQLite was selected over alternative storage solutions for the following reasons:
- Zero configuration — no server required; the database is a single file.
- Low overhead — minimal CPU and RAM consumption on the resource-constrained Jetson Nano.
- Durability — blocks survive system reboots and power interruptions.
- Portability — the database file can be transferred to a PC for offline analysis.
3.5.6 Cloud Anchor via AWS DynamoDB
To extend the integrity guarantee beyond the local device, a cloud anchor mechanism is implemented. Every 10 blocks, the current block's hash is uploaded to AWS DynamoDB as a checkpoint. This serves two purposes:
- Tamper evidence across reboots: if an attacker gains physical access to the Jetson Nano and modifies
chain.db, the cloud checkpoints will not match the reconstructed chain. - Timestamp anchoring: the DynamoDB record includes an
anchored_atfield recording when the checkpoint was uploaded, intended as a time reference independent of the block's own self-reportedtimestampfield.
The cloud verification process (verify_against_cloud()) compares every locally stored checkpoint block against its DynamoDB record and reports any hash mismatches.
Implementation qualification. The anchored_at value is generated on the edge device (datetime.utcnow() in CloudAnchor.upload_checkpoint()) and written as an ordinary item attribute; DynamoDB does not timestamp items on the server side automatically. In the configuration evaluated in this thesis, anchored_at is therefore not independent of an adversary who controls the device, and the second purpose above holds only against an adversary who can alter the local chain but not the upload path. Obtaining a genuinely device-independent time reference requires deriving it from the cloud service rather than the client — for example the server-set LastModified attribute of an object written to Amazon S3, the ApproximateCreationDateTime field of a DynamoDB Streams record, or an AWS CloudTrail event time. The consequences of this limitation for the replay results are analysed in §5.2.6, and the corresponding hardening is set out in §5.4.5.
3.6 Experiment Design
3.6.1 Statistical Framework
All experiments in this study follow a CLT-compliant design with n ≥ 30 independent trials per experiment. This sample size ensures that the sampling distribution of the mean approaches normality by the Central Limit Theorem, enabling the use of parametric statistical tests and 95% confidence intervals.
All results are reported in the following format:
Mean = X unit (SD = Y, 95% CI [A, B], n = 30)
where the confidence interval is computed as:
$CI = \bar{x} \pm 1.96 \times \frac{s}{\sqrt{n}}$
3.6.2 Baseline Chain
Before conducting tamper detection experiments (E1–E10), a clean baseline chain of 1,000 blocks is established by running capture_baseline.py. This script captures one frame every 5 seconds from the RTSP stream and appends each frame to a dedicated baseline chain stored in baseline_chain.db. The chain is verified intact before each experiment trial to ensure a clean starting state.
3.6.3 Tamper Detection Experiments (E1–E10)
Ten tamper detection experiments are designed to evaluate the system's ability to detect nine categories of adversarial attack plus physical sensor spoofing. Each experiment applies a specific attack to a clean chain copy and measures the detection rate and detection latency.
| Exp | Attack Type | n | Primary Metric | Target |
|---|---|---|---|---|
| E1 | Frame modification | 30 | Detection rate (%) | 100% |
| E2 | Frame deletion | 30 | Detection rate (%) | 100% |
| E3 | Frame injection | 30 | Detection rate (%) | 100% |
| E4 | Metadata tampering | 30 | Detection rate (%) | 100% |
| E5 | Hash record alteration | 30 | Detection rate (%) | 100% |
| E6 | Replay attack | 30 | Detection rate (%) | >95% |
| E7 | Chain rewrite | 30 | Rewrite time (ms) | <1000ms |
| E8 | Feed substitution | 30 | Detection rate (%) | >90% |
| E9 | Timestamp manipulation | 30 | Detection rate (%) | >95% |
| E10 | Physical spoofing | 30 | False positive rate (%) | Analysis |
Table 3.4: Summary of tamper detection experiments.
For each experiment, detection rate and 95% confidence interval are computed using the Wilson score interval, which is appropriate for proportion data:
$CI = \frac{\hat{p} + \frac{z^2}{2n} \pm z\sqrt{\frac{\hat{p}(1-\hat{p})}{n} + \frac{z^2}{4n^2}}}{1 + \frac{z^2}{n}}$
3.6.4 Performance Benchmark Experiments (P1–P4)
Four performance benchmarks characterise the computational overhead and long-term stability of the proposed system.
P1 — Security Overhead: A paired design is used in which 30 one-minute intervals are measured with and without the hash chain pipeline active. CPU usage (%), RAM consumption (MB), and frame rate (FPS) are recorded for each interval. A paired t-test is applied to test whether the overhead is statistically significant (α = 0.05). The target overhead threshold is less than 15% CPU.
P2 — Hash Throughput: The SHA-256 hashing throughput of the Jetson Nano is measured by hashing 1,000 simulated frames per iteration across 30 iterations. The target is to demonstrate that the hashing rate exceeds 100 hashes per second, confirming that the cryptographic layer does not introduce a processing bottleneck.
P3 — Verification Time Scaling: The chain verification time is measured across five chain lengths (100, 500, 1,000, 5,000, and 10,000 blocks) with 6 runs each (30 total). Linear regression is applied to the (chain length, verification time) pairs to demonstrate O(n) time complexity. An R² value of ≥ 0.95 is used as the criterion for confirming linear scaling.
P4 — 24-Hour Stability: The system is run continuously for 24 hours with samples collected every 48 minutes (30 samples total). CPU usage, RAM consumption, chain length, and chain validity are recorded at each sample point. Linear regression of RAM over time is used to detect memory leaks; a slope of less than 1 MB per sample is used as the stability criterion.
3.7 Summary
This chapter presented the methodology for a three-layer parking security framework deployed on an NVIDIA Jetson Nano. Layer 1 employs Canny edge detection with manually defined polygon ROIs for parking occupancy classification. Layer 2 applies edge-local processing with data minimisation on the integrity path, so that the integrity mechanism transmits only cryptographic hashes and detection results to the cloud, while frame-image upload to a private S3 bucket is a separate, configurable operational feature the framework does not depend on. Layer 3, the primary contribution of this thesis, implements a lightweight SHA-256 hash chain with SQLite persistence and AWS DynamoDB cloud anchoring to provide verifiable integrity guarantees over the parking video record.
The experiment design follows CLT-compliant methodology with n ≥ 30 trials per experiment, encompassing 10 tamper detection experiments (E1–E10) and 4 performance benchmarks (P1–P4), totalling a minimum of 420 independent measurements. Chapter 4 presents the implementation details of the system, followed by experimental results in Chapter 5.
Chapter 4 — Implementation
Chapter 4: Implementation
4.1 Overview
This chapter describes the implementation of the three-layer parking security framework on the NVIDIA Jetson Nano. The discussion covers the hardware setup, software configuration, implementation of each system component, AWS cloud integration, and the complete operational pipeline. Code excerpts are provided where relevant to illustrate key implementation decisions.
4.2 Hardware Setup
4.2.1 Jetson Nano Configuration
The NVIDIA Jetson Nano Developer Kit was configured with Ubuntu 18.04 LTS and Python 3.8. Remote access is enabled via SSH over a Tailscale VPN tunnel, allowing secure access from any network without exposing the device to the public internet. The device operates continuously (24/7) with the --restart unless-stopped Docker policy applied where applicable.
Network connectivity is provided via Wi-Fi, and the device is assigned the Tailscale IP address 100.90.53.23. All parking security scripts reside in the ~/parking_security/ directory with the following structure:
~/parking_security/
├── parking_detector.py # Main detection + hash chain pipeline
├── blockchain.py # Block, HashChain, ChainStorage
├── cloud_anchor.py # AWS DynamoDB checkpoint
├── performance_monitor.py # CPU/RAM/GPU monitoring
├── roi_selector.py # Interactive ROI definition tool
├── rois.json # 14 parking slot ROI coordinates
├── tamper_simulator.py # 6 attack simulation functions
├── run_tamper_experiments.py # E1–E7 experiment runner
├── run_advanced_experiments.py # E8–E10 experiment runner
├── benchmark_hash.py # P2 hash throughput benchmark
├── benchmark_chain.py # P3 verification scaling benchmark
├── run_P1_overhead.py # P1 security overhead
├── run_P4_stability.py # P4 24hr stability test
├── capture_baseline.py # 1,000-frame baseline chain capture
├── run_all.py # Master experiment runner
├── generate_report.py # Chart generation
├── statistical_analysis.py # Statistical functions
├── generate_master_table.py # Master results table
├── setup_dynamodb.py # DynamoDB table provisioning
├── smoke_test.py # End-to-end pipeline verification
├── requirements.txt # Python dependencies
├── data/ # Experiment CSVs, chain.db
├── frames/ # Locally stored JPEG frames
├── logs/ # System and experiment logs
└── figures/ # Generated chart PNGs
Figure 4.1: Directory structure of the parking security system.
4.2.2 Camera Installation
The IP camera is mounted at an elevated position overlooking the monitored parking area. The camera streams footage via RTSP at a resolution of 1020×600 pixels. The stream is accessible within the local network at:
rtsp://admin:<REDACTED>@10.207.200.224:554/stream1
The Jetson Nano connects to the RTSP stream using OpenCV's VideoCapture with the CAP_FFMPEG backend, which provides hardware-accelerated decoding on the Jetson platform.
4.3 AWS Cloud Setup
4.3.1 DynamoDB Table Provisioning
Two DynamoDB tables are created using setup_dynamodb.py. Both tables use on-demand (pay-per-request) billing mode, eliminating the need to provision fixed read/write capacity units.
| Table | Partition Key | Purpose |
|---|---|---|
parking_frames |
frame_id (String) |
Detection status + frame hash per captured frame |
parking_blockchain |
block_index (String) |
Cloud anchor checkpoints |
Table creation is idempotent — running setup_dynamodb.py multiple times will not duplicate tables. The script waits for each table to reach ACTIVE status before proceeding.
4.3.2 S3 Bucket
An S3 bucket named parking-detection-frames stores the JPEG frames uploaded from the Jetson Nano. Frames are stored under the prefix frames/ with the filename format YYYYMMDD_HHMMSSffffff.jpg, where the filename encodes the capture timestamp with microsecond precision. This frame upload is a configurable operational feature (UPLOAD_FRAMES_TO_S3), enabled in this deployment to support the live dashboard, audit, and ground-truth labelling; the hash chain integrity mechanism does not depend on it and operates identically with it disabled, since integrity verification uses only the cryptographic hashes and detection metadata on the checkpoint path (§3.4.1).
4.3.3 AWS Credentials
AWS credentials are configured on the Jetson Nano using the AWS CLI:
aws configure
The credentials are stored in ~/.aws/credentials and accessed by the boto3 library at runtime. No credentials are hardcoded in any script.
4.4 ROI Definition
Before the detection system can operate, parking slot boundaries must be defined. This is performed once using roi_selector.py:
cd ~/parking_security
python3 roi_selector.py
The tool captures a reference frame from the RTSP stream and displays it in an interactive window. The operator traces each parking slot boundary by left-clicking corner points and right-clicking to complete each polygon. The completed ROIs are saved to rois.json.
A total of 14 parking slots were defined for this study. Figure 4.2 shows an example of the ROI polygon overlay on a reference frame.
[Insert screenshot of roi_selector.py with polygon overlays here]
The rois.json file stores coordinates in the following format:
[
[[182, 191], [175, 232], [144, 235], [153, 195], [181, 191]],
[[185, 229], [190, 190], [222, 184], [216, 221], [185, 227]],
...
]
4.5 Hash Chain Implementation
4.5.1 Block Dataclass
The Block dataclass (defined in blockchain.py) encapsulates all fields of a single chain entry. The block_hash field is automatically computed upon instantiation via __post_init__:
@dataclass
class Block:
block_index: int
timestamp: str
frame_hash: str
detection_result: dict
device_id: str
previous_hash: str
block_hash: str = field(init=False)
def __post_init__(self):
self.block_hash = self.compute_hash()
def compute_hash(self) -> str:
payload = json.dumps({
"block_index": self.block_index,
"timestamp": self.timestamp,
"frame_hash": self.frame_hash,
"detection_result": self.detection_result,
"device_id": self.device_id,
"previous_hash": self.previous_hash,
}, sort_keys=True).encode()
return hashlib.sha256(payload).hexdigest()
4.5.2 HashChain Class
The HashChain class manages the in-memory chain and coordinates block creation, persistence, and cloud checkpointing:
def add_block(self, frame_bytes: bytes, detection_result: dict) -> Block:
fhash = hash_frame(frame_bytes)
prev = self.chain[-1].block_hash
block = Block(
block_index=len(self.chain),
timestamp=datetime.utcnow().isoformat(),
frame_hash=fhash,
detection_result=detection_result,
device_id=DEVICE_ID,
previous_hash=prev,
)
self.chain.append(block)
self.storage.save_block(block)
# Auto-checkpoint to cloud every 10 blocks
if self.cloud_anchor and block.block_index % CHECKPOINT_INTERVAL == 0:
self.cloud_anchor.upload_checkpoint(block)
return block
4.5.3 SQLite Persistence
The ChainStorage class persists all blocks to a local SQLite database. The schema consists of a single blocks table with seven columns corresponding to the Block fields. The block_index serves as the primary key, ensuring each block position is unique. Blocks are retrieved in ascending order by block_index during chain reload.
4.5.4 Chain Verification
The verify_chain() method performs O(n) verification with timing:
def verify_chain(self) -> Tuple[bool, Optional[int], float]:
t0 = time.perf_counter()
for i in range(1, len(self.chain)):
curr = self.chain[i]
prev = self.chain[i - 1]
if curr.block_hash != curr.compute_hash():
elapsed = (time.perf_counter() - t0) * 1000
return False, i, elapsed
if curr.previous_hash != prev.block_hash:
elapsed = (time.perf_counter() - t0) * 1000
return False, i, elapsed
elapsed = (time.perf_counter() - t0) * 1000
return True, None, elapsed
The method returns a three-tuple: a boolean validity flag, the index of the first compromised block (or None if valid), and the total verification time in milliseconds.
4.6 Main Detection Pipeline
4.6.1 System Initialisation
When parking_detector.py is launched, the following initialisation sequence is performed:
- Required directories (
frames/,logs/,data/) are created if absent. - A
ChainStorageinstance opens (or creates)chain.db. - A
HashChaininstance loads the existing chain fromchain.db, or creates the genesis block if the chain is empty. - A
CloudAnchorinstance connects to the DynamoDBparking_blockchaintable. - A
PerformanceMonitorinstance starts a background thread sampling CPU, RAM, and GPU metrics every 10 seconds. - ROI polygons are loaded from
rois.json. - The RTSP stream is opened via
cv2.VideoCapture.
4.6.2 Per-Frame Processing Loop
The main loop runs continuously until the operator presses q. For each captured frame, the following steps are executed:
1. Read frame from RTSP stream
2. Check elapsed time since last capture
└─ If < 5 seconds: skip processing, check keyboard only
3. Detect parking status per ROI slot (Canny)
4. Encode frame to JPEG bytes
5. frame_hash = SHA-256(JPEG bytes)
6. block = chain.add_block(frame_bytes, detection_result)
└─ Saves to chain.db
└─ Auto-checkpoint to DynamoDB if block_index % 10 == 0
7. Upload JPEG frame to S3
8. Save detection status + hash to DynamoDB (parking_frames)
9. Draw ROI overlays on frame and display
10. PerformanceMonitor.tick() — update FPS counter
4.6.3 Keyboard Controls
The following keyboard controls are available during system operation:
| Key | Action |
|---|---|
v |
Verify local chain integrity; reports result and elapsed time |
c |
Verify chain against DynamoDB cloud checkpoints |
i |
Display chain info (length, tip hash) |
s |
Manually upload current block as cloud checkpoint |
q |
Safe quit — stops monitor, releases camera, closes windows |
4.6.4 Performance Monitoring
The PerformanceMonitor class runs as a daemon thread, sampling the following metrics every 10 seconds and appending rows to a timestamped CSV file:
| Metric | Source |
|---|---|
| CPU usage (%) | psutil.cpu_percent() |
| CPU temperature (°C) | tegrastats |
| RAM usage (MB) | psutil.Process.memory_info().rss |
| GPU usage (%) | tegrastats (GR3D_FREQ) |
| GPU temperature (°C) | tegrastats |
| FPS | Frame counter ÷ elapsed time |
| Chain length | len(chain.chain) |
The tegrastats utility is a Jetson-specific command-line tool that exposes hardware telemetry including GPU frequency and thermal sensor readings. It is invoked as a subprocess and its output is parsed using regular expressions.
4.7 Cloud Anchor Implementation
The CloudAnchor class (defined in cloud_anchor.py) implements two operations:
Upload checkpoint: uploads a minimal record to DynamoDB containing block_index, block_hash, frame_hash, timestamp, device_id, and anchored_at (server-side timestamp). Raw frame data is never included.
Verify against cloud: retrieves all stored checkpoints from DynamoDB and compares each block_hash against the corresponding local chain block. A mismatch indicates that either the local chain or the cloud record has been tampered with.
def verify_against_cloud(self, chain) -> dict:
mismatches = []
for block in chain.chain:
item = self.table.get_item(
Key={"block_index": str(block.block_index)}
).get("Item")
if item and item["block_hash"] != block.block_hash:
mismatches.append({
"block_index": block.block_index,
"local_hash": block.block_hash,
"cloud_hash": item["block_hash"],
})
return {"verdict": "VALID" if not mismatches else "TAMPERED",
"mismatches": len(mismatches)}
4.8 System Verification
Upon completion of the implementation, an end-to-end smoke test (smoke_test.py) was executed on the Jetson Nano to verify that all components function correctly without requiring a live camera connection. The test comprises 10 subtests covering module imports, block hashing, chain construction and verification, tamper detection, SQLite persistence, all six attack simulations, statistical functions, GPU monitoring, and the master table generator.
All 10 tests passed, confirming that the implementation is functionally complete and ready for experiment execution.
Smoke Test Results: 10/10 passed
All tests passed. Pipeline ready.
4.9 Summary
This chapter presented the complete implementation of the three-layer parking security framework. The hardware setup consists of a Jetson Nano connected to an IP camera over RTSP and to AWS cloud services via the boto3 SDK. The hash chain layer is implemented as a local, blockchain-inspired hash chain persisted in SQLite, with periodic checkpoints uploaded to DynamoDB for cloud-anchored integrity verification. The main detection pipeline integrates all three layers into a single continuous loop with keyboard controls for real-time chain inspection. Chapter 5 presents the results of the experimental evaluation (E1–E10, P1–P4).
Chapter 5 — Results and Discussion
Chapter 5: Results and Discussion
5.1 Overview
This chapter presents the results obtained from experiments conducted to evaluate the proposed three-layer parking security framework. The experiments are organised into three categories: tamper detection experiments (E1–E10), which assess the system's ability to detect adversarial attacks on the hash chain; performance benchmark experiments (P1–P4), which characterise the computational overhead and long-term operational stability of the system; and two control experiments (N1–N2) added to qualify the detection results — a negative-control arm establishing the false positive rate of each detection mechanism (§5.2.11), and a cost-equivalent baseline comparing the hash chain against direct per-frame anchoring (§5.4.4). Experiments E1–E9 and P1–P3 were conducted on the NVIDIA Jetson Nano with a minimum of 30 independent trials per experiment to satisfy Central Limit Theorem requirements. Results are reported as mean ± standard deviation with 95% confidence intervals unless stated otherwise. Two interval conventions are used, chosen to match each result's underlying statistical test: single-sample and independent-sample continuous measures (e.g., E1–E9 latencies, P2, P3) use the normal-approximation interval \bar{x} \pm 1.96 \times s/\sqrt{n}; the paired-comparison measures in P1 use the t-distribution interval \bar{x} \pm t_{0.025,29} \times s/\sqrt{n} (with t_{0.025,29} = 2.045) to remain consistent with the paired t-test used to assess significance; detection-rate proportions (E1–E10) use the Wilson score interval.
Status note: P4 (stability) now reports the full 24-hour protocol described in Chapter 3 §3.6.4 (23.2 h between first and last samples), following an initial 4.85-hour pilot run reported alongside it for comparison. E10 (physical sensor spoofing) has not yet been conducted — a field session at the car park is scheduled (T3.3). §5.2.10 is marked accordingly and must be completed before this chapter is treated as final.
5.2 Tamper Detection Experiments
5.2.1 E1 — Frame Modification
Frame modification attacks were simulated by altering the stored frame hash to reflect a modified version of the original frame. Three sub-types were tested: single-pixel modification, ten-pixel modification, and Gaussian noise injection, with 10 trials each (n = 30 total).
Table 5.1: E1 Frame Modification Detection Results
| Sub-type | Trials | Detected | Detection Rate (%) | 95% CI | Mean Latency (ms) | SD |
|---|---|---|---|---|---|---|
| 1-pixel modification | 10 | 10 | 100.0 | [72.25, 100.0] | 13.56 | 11.32 |
| 10-pixel modification | 10 | 10 | 100.0 | [72.25, 100.0] | 16.93 | 13.14 |
| Gaussian noise | 10 | 10 | 100.0 | [72.25, 100.0] | 17.96 | 9.87 |
| Combined | 30 | 30 | 100.0 | [88.65, 100.0] | 16.15 | 11.28 |
Target: 100% detection rate — MET
Discussion: All 30 trials were detected with no false negatives, confirming that the hash chain's self-integrity check (recomputing block_hash and comparing against the stored value) catches any frame-hash substitution regardless of the magnitude of the underlying modification it represents. Because the attack is implemented at the hash level (the stored frame_hash is replaced with the hash of different random bytes rather than an actually re-encoded JPEG — see §3.5.1/§4.5.1), the three sub-types are cryptographically equivalent in terms of detectability; the differences in mean latency across sub-types (13.6–18.0 ms) reflect only where in the 1,000-block chain the tampered block happened to fall (verification is O(n) and stops at the first invalid block), not any difference in detection difficulty.
5.2.2 E2 — Frame Deletion
Frame deletion attacks were simulated by removing a block from the chain at three positions: beginning (block index 35), middle (block index 503), and end (block index 964), with 10 trials each (n = 30 total).
Table 5.2: E2 Frame Deletion Detection Results
| Position | Trials | Detected | Detection Rate (%) | 95% CI | Mean Latency (ms) | SD |
|---|---|---|---|---|---|---|
| Beginning (idx 35) | 10 | 10 | 100.0 | [72.25, 100.0] | 1.69 | 0.15 |
| Middle (idx 503) | 10 | 10 | 100.0 | [72.25, 100.0] | 20.31 | 0.29 |
| End (idx 964) | 10 | 10 | 100.0 | [72.25, 100.0] | 38.49 | 0.21 |
| Combined | 30 | 30 | 100.0 | [88.65, 100.0] | 20.16 | 15.28 |
Target: 100% detection rate — MET. As expected, deletions near the beginning of the chain are detected fastest (mean 1.69 ms) and deletions near the end are detected slowest (mean 38.49 ms), consistent with O(n) verification that halts at the first broken link.
Discussion: Deletion breaks the previous_hash linkage between the block preceding and the block following the deleted entry, which is caught deterministically on the first verification pass. The very low within-position standard deviations (0.15–0.29 ms) confirm that detection latency for a fixed deletion position is highly reproducible — latency is governed almost entirely by the position of the break in the chain, not by system-level noise.
5.2.3 E3 — Frame Injection
Frame injection attacks were simulated by inserting a fabricated block at three positions in the chain: beginning (index 29), middle (index 525), and end (index 967), with 10 trials each (n = 30 total).
Table 5.3: E3 Frame Injection Detection Results
| Position | Trials | Detected | Detection Rate (%) | 95% CI | Mean Latency (ms) | SD |
|---|---|---|---|---|---|---|
| Beginning (idx 29) | 10 | 10 | 100.0 | [72.25, 100.0] | 1.36 | 0.17 |
| Middle (idx 525) | 10 | 10 | 100.0 | [72.25, 100.0] | 21.19 | 0.94 |
| End (idx 967) | 10 | 10 | 100.0 | [72.25, 100.0] | 38.14 | 0.16 |
| Combined | 30 | 30 | 100.0 | [88.65, 100.0] | 20.23 | 15.29 |
Target: 100% detection rate — MET
Discussion: An injected block, even one whose own block_hash is internally self-consistent, breaks the chain linkage for the block that originally followed the injection point (its previous_hash no longer matches the injected block's block_hash), so injection is detected with the same mechanism and position-dependent latency profile as deletion (§5.2.2). The near-identical latency pattern across E2 and E3 (both governed by O(n) traversal to the break point) is expected given they share the same underlying verification algorithm.
5.2.4 E4 — Metadata Tampering
Metadata tampering attacks were simulated by modifying three block fields: timestamp, detection result, and device ID, with 10 trials each (n = 30 total).
Table 5.4: E4 Metadata Tampering Detection Results
| Tamper Type | Trials | Detected | Detection Rate (%) | 95% CI | Mean Latency (ms) | SD |
|---|---|---|---|---|---|---|
| Timestamp | 10 | 10 | 100.0 | [72.25, 100.0] | 21.25 | 12.73 |
| Detection result | 10 | 10 | 100.0 | [72.25, 100.0] | 14.46 | 12.07 |
| Device ID | 10 | 10 | 100.0 | [72.25, 100.0] | 19.58 | 11.31 |
| Combined | 30 | 30 | 100.0 | [88.65, 100.0] | 18.43 | 11.99 |
Target: 100% detection rate — MET
Discussion: Because block_hash is computed over all block fields (block_index, timestamp, frame_hash, detection_result, device_id, previous_hash; see §3.5.1), any modification to a single field — however minor — invalidates the self-integrity check identically regardless of which field was altered. This is a direct structural consequence of the block hash design and explains why detection rate is uniformly 100% across all three sub-types.
5.2.5 E5 — Hash Record Alteration
Hash record alteration attacks were simulated by modifying the stored block_hash value using three methods: single-character change, random hash replacement, and adjacent hash swap, with 10 trials each (n = 30 total).
Table 5.5: E5 Hash Record Alteration Detection Results
| Alteration Type | Trials | Detected | Detection Rate (%) | 95% CI | Mean Latency (ms) | SD |
|---|---|---|---|---|---|---|
| Single-character change | 10 | 10 | 100.0 | [72.25, 100.0] | 25.15 | 12.02 |
| Random replacement | 10 | 10 | 100.0 | [72.25, 100.0] | 18.27 | 12.19 |
| Adjacent swap | 10 | 10 | 100.0 | [72.25, 100.0] | 17.40 | 11.53 |
| Combined | 30 | 30 | 100.0 | [88.65, 100.0] | 20.27 | 12.03 |
Target: 100% detection rate — MET
Discussion: Direct tampering with the stored block_hash is the most fundamental attack against the hash chain's self-integrity mechanism, and — as expected by construction — is detected with certainty: any stored block_hash that does not equal the recomputed hash of its own fields is flagged, whether the alteration is a single character, a full random replacement, or a swap with an adjacent block's hash (the swap still fails because block_hash is bound to that specific block's other fields).
5.2.6 E6 — Replay Attack
Replay attacks were simulated across four scenarios with varying combinations of original/updated timestamps and original/recomputed hashes (n = 30 total: Scenario A = 8, B = 8, C = 7, D = 7).
Table 5.6: E6 Replay Attack Detection Results
| Scenario | Description | Trials | Detected | Detection Rate (%) | 95% CI | Mean Latency (ms) | SD |
|---|---|---|---|---|---|---|---|
| A | Original timestamp + original hash | 8 | 8 | 100.0 | [67.56, 100.0] | 41.96 | 5.51 |
| B | Updated timestamp + original hash | 8 | 8 | 100.0 | [67.56, 100.0] | 39.58 | 0.53 |
| C | Original timestamp + recomputed hash | 7 | 0 | 0.0 | [0.00, 35.43] | 39.91 | 0.73 |
| D | Updated timestamp + recomputed hash | 7 | 0 | 0.0 | [0.00, 35.43] | 39.40 | 0.31 |
| Combined | 30 | 16 | 53.3 | [36.14, 69.77] | 40.25 | 2.94 |
Target: >95% detection rate — NOT MET. Combined detection rate of 53.3% falls substantially short of the target.
Discussion: This is the weakest result in the tamper-detection suite, and its cause is fully explained by the two-part local verification algorithm (§3.5.4, §4.5.4): verify_chain() checks only (1) self-integrity — whether a block's stored block_hash equals the hash recomputed from its own fields — and (2) chain linkage — whether a block's previous_hash equals the preceding block's block_hash. In Scenarios A and B, the replayed block retains its original block_hash while its block_index and previous_hash are updated to append it at the tip of the chain; this breaks self-integrity (the stored hash no longer matches the new field values) and is therefore always detected (16/16 across A+B). In Scenarios C and D, the attacker recomputes block_hash after modifying the block, producing a block that is internally self-consistent and correctly linked — indistinguishable, by local verification alone, from a legitimately appended block. These scenarios are therefore never detected locally (0/14 across C+D), and Scenario D (updated timestamp + recomputed hash) represents a fully successful replay against the local hash chain in isolation.
This result is not a flaw unique to this implementation; it is an inherent limitation of any purely local, content-addressed hash chain, which has no mechanism to verify when a block was genuinely created versus when it was replayed — timestamps are self-reported fields, not independently verified events. Closing it requires a time reference the attacker does not control, which is the role the cloud anchor (§3.5.6) is intended to play.
An important correction to that argument as currently implemented. The anchored_at value stored with each DynamoDB checkpoint is generated on the edge device by CloudAnchor.upload_checkpoint(), not by the cloud service (§3.5.6). It is therefore not independent of an adversary who holds the device-write capability that the threat model (§3.1.1) places in scope: such an adversary can alter the local chain, re-upload the affected checkpoints, and set anchored_at to any value. Against the adversary this thesis defines, the anchor as deployed consequently provides no independent timestamp evidence, and Scenarios B and D are not recoverable by the mechanism described above. This is a limitation of the evaluated configuration rather than of anchoring as an approach: a server-derived anchoring time (§3.5.6) placed in an append-only checkpoint store would restore the property, and is specified as required hardening in §5.4.5. Until that hardening is implemented and re-evaluated, the honest statement of this result is that E6 Scenarios C and D are undetected, and no compensating mechanism in the current system detects them — 53.3% is the framework's replay detection rate as built, not a local-only figure that cloud verification would improve. Hardening local detection of Scenario C/D-style replays (e.g., via a monotonic sequence counter or per-session nonce independent of block_index) is identified as future work (§6.4).
5.2.7 E7 — Chain Rewrite Attempt
Chain rewrite attacks were simulated by rewriting K blocks from the end of a 1,000-block chain, with 6 trials each for K = 10, 50, 100, 500, 1,000 (n = 30 total).
Table 5.7: E7 Chain Rewrite Time Results
| K (blocks rewritten) | Trials | Mean Rewrite Time (ms) | SD | Mean Post-Rewrite Verify Time (ms) | Detected (local) |
|---|---|---|---|---|---|
| 10 | 6 | 0.49 | 0.06 | 39.36 | 0/6 |
| 50 | 6 | 2.43 | 0.57 | 39.19 | 0/6 |
| 100 | 6 | 4.35 | 0.29 | 39.00 | 0/6 |
| 500 | 6 | 20.17 | 0.46 | 38.79 | 0/6 |
| 1,000 | 6 | 39.58 | 0.48 | 38.72 | 0/6 |
| Combined mean | 30 | 13.40 | 15.09 | — | 0/30 |
Linear Regression (Rewrite Time vs K):
| Parameter | Value |
|---|---|
| Slope (ms/block) | 0.0393 |
| Intercept (ms) | 0.351 |
| R² | 0.9992 |
| Interpretation | Rewrite time scales linearly with the number of rewritten blocks (R² = 0.9992), consistent with the O(n) cost of recomputing SHA-256 hashes sequentially down the chain. |
Target: Rewrite time < 1,000 ms for K = 10 — MET by three orders of magnitude (0.49 ms). Local detection rate: 0% by design (see Discussion).
Discussion: The 0/30 local detection rate is expected and is not a failure of the hash chain design — it demonstrates the fundamental limit of self-verification against an adversary with write access to the entire chain (in scope under the threat model, §3.1.1). An attacker who can rewrite blocks and their hashes can trivially reconstruct an internally consistent chain: attack_chain_rewrite() recomputes each block's previous_hash and block_hash sequentially from the point of tampering onward, so verify_chain() — which only checks internal consistency — passes on the rewritten chain (post-rewrite verify time ≈ 38.7–39.4 ms, indistinguishable from a clean chain of the same length). This is the central motivation for the cloud anchor mechanism (§3.5.6): because checkpoints are uploaded to an independent DynamoDB table at the time each block was originally created, a rewritten chain's blocks will no longer match their corresponding cloud-anchored block_hash values, and verify_against_cloud() will report a mismatch even though local verify_chain() reports the chain as valid. The linear growth in rewrite time (0.039 ms/block) — consistent with the P3 verification-time slope of 0.040 ms/block (§5.3.3), as both operations perform one SHA-256 computation per block — means that rewriting a large historical span remains computationally cheap on this hardware (≈ 40 ms for 1,000 blocks), reinforcing that computational cost alone is not a meaningful deterrent at this scale and that cloud anchoring, not rewrite latency, is what provides the actual security guarantee against this attack class.
5.2.8 E8 — Feed Substitution
Feed substitution attacks were simulated by replacing the last 20 frames with repeated identical hashes, across three time periods: morning, afternoon, and night (10 trials each, n = 30 total).
Table 5.8: E8 Feed Substitution Detection Results
| Time Period | Trials | Detected | Detection Rate (%) | 95% CI | Max Repeat Count | Mean Post-Detection Verify Time (ms) | SD |
|---|---|---|---|---|---|---|---|
| Morning | 10 | 10 | 100.0 | [72.25, 100.0] | 20 | 38.85 | 0.39 |
| Afternoon | 10 | 10 | 100.0 | [72.25, 100.0] | 20 | 38.97 | 0.31 |
| Night | 10 | 10 | 100.0 | [72.25, 100.0] | 20 | 39.03 | 0.46 |
| Combined | 30 | 30 | 100.0 | [88.65, 100.0] | 20 | 38.95 | 0.39 |
Target: >90% detection rate — MET
Discussion: The last 20 frames of each 1,000-block chain were substituted with a repeated identical frame_hash, simulating a static or replayed camera feed. Detection is performed by a repeated-hash frequency scan (run_advanced_experiments.py, run_E8()): the algorithm counts occurrences of each distinct frame_hash across the chain and flags the chain as suspicious whenever any hash value repeats more than 5 times (threshold max_repeat > 5); all 30 trials produced a max_repeat of 20, far exceeding this threshold. This scan is independent of, and not caught by, verify_chain()'s self-integrity/linkage checks — a substituted feed with identical repeated hashes still produces a structurally valid, correctly self-consistent chain. The reported "latency" column is therefore not the repeated-hash scan's own runtime, but the elapsed time of the subsequent full-chain verify_chain() pass run alongside it for logging purposes (≈ 39 ms, consistent with traversing a full 1,000-block chain per P3's scaling result, §5.3.3). The uniform detection across all three simulated time periods indicates the mechanism is time-of-day independent, as expected since the attack is purely hash-pattern-driven.
Scope of this result. Because frame_hash is a SHA-256 digest of the JPEG-encoded frame bytes, two frames produce the same frame_hash only if they are byte-identical. This experiment therefore measures detection of exact frame replay — an adversary re-submitting the same encoded frame repeatedly, which is what a naive looped or frozen feed produces. It does not measure detection of a visually static feed that is still being freshly encoded: in live operation, successive frames of an unchanging scene differ in sensor noise and JPEG quantisation, so their digests differ and max_repeat would not rise. An adversary who substitutes the camera with a display showing a static image, or who re-encodes a looped recording rather than replaying identical bytes, would evade this particular scan while remaining within the in-scope capability of feed substitution (§3.1.1). The 100% figure reported here should accordingly be read as complete detection of byte-identical replay under the synthetic chain construction used in E1–E7 (§3.6.2), not as a general feed-substitution detection rate. Detecting perceptually rather than cryptographically repeated content would require a perceptual digest (e.g. a perceptual hash with a Hamming-distance threshold) in place of, or alongside, the cryptographic frame hash, and is identified as future work (§6.4).
5.2.9 E9 — Timestamp Manipulation
Timestamp manipulation attacks were simulated by altering block timestamps in three ways: shifting forward 24 hours, shifting backward 24 hours, and setting a random historical date, with 10 trials each (n = 30 total).
Table 5.9: E9 Timestamp Manipulation Detection Results
| Manipulation Type | Trials | Detected (gap heuristic) | Detection Rate (%) | 95% CI | Chain Self-Integrity Valid | Mean Latency (ms) | SD |
|---|---|---|---|---|---|---|---|
| Clock forward (+24 hr) | 10 | 10 | 100.0 | [72.25, 100.0] | 0/10 | 13.45 | 10.83 |
| Clock backward (−24 hr) | 10 | 10 | 100.0 | [72.25, 100.0] | 0/10 | 16.90 | 13.00 |
| Random date | 10 | 10 | 100.0 | [72.25, 100.0] | 0/10 | 18.07 | 9.98 |
| Combined | 30 | 30 | 100.0 | [88.65, 100.0] | 0/30 | 16.14 | 11.12 |
Target: >95% detection rate — MET
Discussion: E9's recorded detected outcome is produced by a timestamp-gap heuristic (run_advanced_experiments.py, run_E9()), which scans consecutive blocks and flags a manipulation whenever the gap between adjacent timestamps exceeds one hour — this is a purpose-built detector for temporal anomalies, distinct from verify_chain()'s self-integrity/linkage checks used throughout E1–E5. Because timestamp is also one of the fields covered by block_hash (§3.5.1), the attack is independently caught by self-integrity verification as well: the chain_valid column recorded alongside the gap-heuristic result is 0 (invalid) in all 30 trials, confirming that verify_chain() on its own would also flag every manipulated chain. E9 is therefore detected redundantly by two independent mechanisms, which is a stronger result than E4's timestamp sub-type (self-integrity only) and should not be attributed to self-integrity checking alone. This is a materially different (and easier) detection case than the replay scenarios in E6, where the attacker also recomputes block_hash after altering the timestamp, defeating self-integrity — but E9's gap heuristic would still not, on its own, catch the more sophisticated E6 Scenario D replay, since a single replayed block need not introduce a large timestamp gap relative to its neighbours.
5.2.10 E10 — Physical Sensor Spoofing
⚠️ NOT YET CONDUCTED.
E10_physical_spoofing_template.csvcurrently contains only the trial template (6 object types × 5 repetitions = 30 planned trials) with no recorded data. A field session at the monitored car park is scheduled (seeSONNET_TASK_PLAN.mdT3.3) to physically place each object in an empty monitored slot and record the system's detection verdict. This section will be completed once that data is collected — do not report results for E10 until then.
Planned protocol: six object types will be tested with 5 trials each (n = 30 total): white poster, dark tape car outline, cardboard box, reflective surface, plastic bag, and tree branch debris.
Table 5.10: E10 Physical Spoofing False Positive Results (pending)
| Object Type | Trials | False Positives | False Positive Rate (%) | Notes |
|---|---|---|---|---|
| White poster | 5 | — | — | pending field session |
| Dark tape car outline | 5 | — | — | pending field session |
| Cardboard box | 5 | — | — | pending field session |
| Reflective surface | 5 | — | — | pending field session |
| Plastic bag | 5 | — | — | pending field session |
| Tree branch debris | 5 | — | — | pending field session |
| Combined | 30 | — | — | pending field session |
Note: E10 assesses Layer 1 detection algorithm limitations, not hash chain integrity. The hash chain records all detection results faithfully regardless of detection accuracy — this demonstrates that data integrity guarantees are independent of detection quality, i.e. even a false detection outcome is immutably and verifiably recorded rather than silently altered.
Discussion: (to be completed after the field session)
5.2.11 N1 — Negative Controls (False Positive Rate)
Every experiment in §5.2.1–§5.2.9 reports a true positive rate: how often each mechanism fires when tampering is present. Reported alone, such rates are uninterpretable — a detector that returned "tampered" unconditionally would also score 100% on all of them. A negative-control arm was therefore run to establish the corresponding false positive rate.
Thirty untampered 1,000-block chains were constructed by the same build_test_chain() routine used throughout E1–E7, and each of the three detection mechanisms exercised in this chapter was run against them without any attack applied. Any mechanism firing on such a chain constitutes a false positive.
Table 5.11: N1 Negative Control Results (n = 30 clean chains)
| Detection mechanism | Used by | False positives | FP rate (%) | 95% CI |
|---|---|---|---|---|
Self-integrity + linkage (verify_chain()) |
E1–E7 | 0 / 30 | 0.0 | [0.00, 11.35] |
Repeated-hash frequency scan (max_repeat > 5) |
E8 | 0 / 30 | 0.0 | [0.00, 11.35] |
| Timestamp-gap heuristic (gap > 3,600 s) | E9 | 0 / 30 | 0.0 | [0.00, 11.35] |
Target: 0% false positive rate — MET for all three mechanisms.
Discussion: No mechanism produced a single false positive across 30 clean chains. Two diagnostic columns recorded alongside the verdicts confirm the detectors were genuinely exercised rather than failing silently: observed_max_repeat was 1 in every trial (no frame_hash recurs in a chain built from independent random payloads, so the E8 scan had a real distribution to examine and correctly found nothing), and break_index was empty in every trial (the full chain was traversed to completion without encountering a mismatch). The detection rates reported in §5.2.1–§5.2.9 are therefore attributable to the mechanisms discriminating between tampered and untampered chains, not to an indiscriminate verifier.
A secondary consistency check emerges from the latency data. Verification of a clean 1,000-block chain averaged 39.93 ms, against the 39.35 ms measured independently for the same chain length in P3 (§5.3.3). The agreement is expected — an untampered chain offers no early exit, so verification must traverse every block — and the fact that two separately executed experiments converge on the same figure is corroborating evidence that both are measuring the intended quantity.
One limitation should be stated rather than glossed. build_test_chain() appends blocks in a tight loop, so adjacent timestamps in these control chains differ by well under a second and the largest observed gap was approximately 3 s, far below the 3,600 s threshold. The timestamp-gap control therefore demonstrates that the heuristic does not misfire, but on chains that could not plausibly have triggered it. This is not a defect of the control so much as a property inherited from the synthetic construction used by E9 itself: the control matches the experiment it qualifies, and no stronger claim is made from it. In deployment the capture interval is 5 s (§3.3.3), still two orders of magnitude below the threshold, so the same conclusion holds there — but a control run against genuinely long-interval data would be a stronger test and is left as future work.
5.2.12 Summary of Tamper Detection Results
Table 5.12: Summary of All Tamper Detection Experiments
| Exp | Attack Type | n | Detection Rate (%) | 95% CI | FP Rate (N1) | Target | Met? |
|---|---|---|---|---|---|---|---|
| E1 | Frame modification | 30 | 100.0 | [88.65, 100.0] | 0.0 | 100% | ✅ |
| E2 | Frame deletion | 30 | 100.0 | [88.65, 100.0] | 0.0 | 100% | ✅ |
| E3 | Frame injection | 30 | 100.0 | [88.65, 100.0] | 0.0 | 100% | ✅ |
| E4 | Metadata tampering | 30 | 100.0 | [88.65, 100.0] | 0.0 | 100% | ✅ |
| E5 | Hash alteration | 30 | 100.0 | [88.65, 100.0] | 0.0 | 100% | ✅ |
| E6 | Replay attack | 30 | 53.3 | [36.14, 69.77] | 0.0 | >95% | ❌ (limitation — see §5.2.6) |
| E7 | Chain rewrite | 30 | 0.0 (local) | — | 0.0 | <1000ms rewrite time | ⚠️ Latency target met; local detection 0% by design — see §5.2.7 and the anchoring caveat in §5.4.3 |
| E8 | Feed substitution | 30 | 100.0 | [88.65, 100.0] | 0.0 | >90% | ✅ |
| E9 | Timestamp manipulation | 30 | 100.0 | [88.65, 100.0] | 0.0 | >95% | ✅ |
| E10 | Physical spoofing | — | pending | — | — | Analysis only | ⏳ pending field session |
FP Rate column is the false positive rate of the mechanism underlying each experiment, measured in N1 (§5.2.11) over 30 untampered chains; 95% CI [0.00, 11.35] in every case.
[Insert Figure 5.1 — Bar chart of detection rates E1–E9 here, generated via
generate_report.py]
5.3 Performance Benchmark Experiments
5.3.1 P1 — Security Overhead
The security overhead introduced by the hash chain pipeline was measured using a paired design with 30 one-minute intervals each with and without the hash chain pipeline active.
Table 5.13: P1 Security Overhead Results
| Metric | Without Hash Chain | With Hash Chain | Overhead | 95% CI (t-based, df=29) | t-statistic (df=29) | p-value |
|---|---|---|---|---|---|---|
| CPU (%) | 11.62 | 3.63 | −7.99 | [−16.21, +0.22] | −1.989 | 0.0562 |
| ΔRAM (MB) | 0.00 | 0.06 | +0.06 | [−0.05, +0.17] | 1.152 | n.s. |
| FPS | 19.95 | 14.64 | −5.30 | [−5.79, −4.82] | −22.44 | <0.001 |
ΔRAM values are the change in resident memory measured over each one-minute interval (not absolute RAM footprint), which is why the without-hash-chain baseline is 0.00 MB; the metric captures memory growth attributable to the pipeline during the interval.
The FPS Overhead column is computed from raw (unrounded) per-trial data, not from the rounded means shown in this table; it will not exactly equal 19.95 − 14.64 due to display rounding.
Target: CPU overhead < 15% — MET (and not statistically distinguishable from zero). Paired t-test (α = 0.05).
Discussion: The CPU overhead result (mean −7.99%, 95% CI [−16.21, +0.22], p = 0.0562) is not statistically significant at α = 0.05 — note that the confidence interval spans zero, consistent with the non-significant p-value. The negative point estimate should not be interpreted as the hash chain pipeline reducing CPU usage; rather, the high trial-to-trial variance (SD = 22.0 percentage points, larger in magnitude than the mean itself) reflects background CPU load fluctuation on the Jetson Nano (e.g., from tegrastats sampling, RTSP decode jitter, or the OS scheduler) that swamps any consistent overhead the hash chain pipeline might introduce. The safest and most defensible conclusion is that no statistically significant CPU overhead was detected, which is itself a strong result for the framework's practicality on resource-constrained hardware. RAM overhead is negligible in absolute terms (+0.06 MB, CI spans zero) and also not statistically significant. The FPS reduction (−5.30 fps, 95% CI [−5.79, −4.82], p < 0.001) is statistically significant — the CI excludes zero — and practically the most relevant cost of the framework; most of this reduction is attributable to the per-frame JPEG encoding, SHA-256 hashing, and S3/DynamoDB upload calls in the main loop (§4.6.2) rather than the hash chain's verify/add_block operations alone, which §5.3.2 shows to be sub-millisecond at this chain length. It is important to note that this FPS metric measures the internal frame-processing rate of the benchmark loop (how fast the pipeline can process frames back-to-back), not the deployed system's capture cadence, which is fixed at one frame every 5 seconds (0.2 fps) by design (§3.3.3); since even the reduced 14.64 fps processing rate is roughly 73× faster than the 0.2 fps capture demand, this reduction has no effect on the deployed system's ability to keep up with its capture schedule.
5.3.2 P2 — Hash Throughput
SHA-256 hashing throughput was measured over 30 iterations of 1,000 frames each on the Jetson Nano.
Table 5.14: P2 Hash Throughput Results
| Metric | Value |
|---|---|
| n | 30 |
| Mean (hashes/sec) | 12,160.71 |
| SD | 38.20 |
| 95% CI | [12,147.04, 12,174.38] |
| Min | 12,037.43 |
| Max | 12,204.76 |
Target: >100 hashes/second — MET, exceeded by two orders of magnitude.
[Insert Figure 5.2 — Histogram of hash throughput distribution here, generated via
generate_report.py]
Discussion: At a sustained throughput of ~12,161 hashes/second (≈ 0.082 ms/hash), SHA-256 hashing is not a meaningful bottleneck relative to the 5-second frame capture interval (§3.3.3) — hashing a single frame consumes roughly 0.0016% of the time budget between captures. This confirms that the cryptographic layer (Layer 3) does not constrain the achievable frame rate; the FPS reduction observed in P1 (§5.3.1) is attributable to other pipeline stages (JPEG encoding, network I/O), not hashing.
5.3.3 P3 — Verification Time Scaling
Chain verification time was measured across five chain lengths (100, 500, 1,000, 5,000, 10,000 blocks) with 6 runs each (n = 30 total).
Table 5.15: P3 Verification Time by Chain Length
| Chain Length | Runs | Mean (ms) | SD |
|---|---|---|---|
| 100 | 6 | 3.995 | 0.145 |
| 500 | 6 | 19.548 | 0.273 |
| 1,000 | 6 | 39.352 | 0.409 |
| 5,000 | 6 | 203.491 | 1.806 |
| 10,000 | 6 | 398.003 | 1.448 |
Table 5.16: P3 Linear Regression Results
| Parameter | Value |
|---|---|
| Slope (ms/block) | 0.03993 |
| Intercept (ms) | 0.296 |
| R² | 0.9998 |
| Scaling | Confirmed O(n) — verification time grows linearly with chain length |
Target: R² ≥ 0.95 to confirm O(n) scaling — MET (R² = 0.9998)
[Insert Figure 5.3 — Scatter plot with regression line here, generated via
generate_report.py]
Discussion: The near-perfect linear fit (R² = 0.9998) confirms that verify_chain() scales as O(n), consistent with its single-pass sequential design (§3.5.4/§4.5.4). At 0.0399 ms/block, verifying the live production chain — which had exceeded 211,860 blocks as of 2026-04-29 (see §5.4.2) — would take approximately 8.5 seconds, a practically acceptable cost even at that scale, though this motivates the chain-archiving discussion in the Limitations (§5.4.5) for indefinitely long deployments.
5.3.4 P4 — Operational Stability
An initial 4.85-hour pilot run (2026-04-13, 07:46–12:37; 30 samples at 10-minute intervals) was conducted first to sanity-check the measurement protocol, followed by the full 24-hour protocol described in §3.6.4 (30 samples at a 48-minute interval, run window 2026-07-03 10:05 UTC → 2026-07-04 09:19 UTC, first-to-last-sample span 23.22 hours). The full-duration run was executed against an isolated test database (data/p4_chain_24h.db), leaving the live production chain untouched. Both runs are reported below; the 24-hour run is the confirmatory result.
Table 5.17a: P4 Stability Results — Initial Pilot Run (4.85 hours)
| Metric | Mean | SD | Min | Max | Slope (per sample) | Verdict |
|---|---|---|---|---|---|---|
| CPU (%) | 0.49 | 0.23 | 0.10 | 1.00 | −0.0106 %/sample | Stable |
| RAM (MB) | 29.61 | 0.05 | 29.42 | 29.62 | +0.0025 MB/sample | Stable |
| Chain length | 11 → 301 (+290 over run) | — | 11 | 301 | — | Chain grew as expected |
| Chain valid (%) | 100 | — | — | — | — | All 30 samples valid |
Table 5.17b: P4 Stability Results — Full 24-Hour Confirmation Run (23.22 h)
| Metric | Mean | SD | Min | Max | Slope (per sample) | Verdict |
|---|---|---|---|---|---|---|
| CPU (%) | 0.58 | 0.25 | 0.3 | 1.2 | +0.0145 %/sample | Stable |
| RAM (MB) | 29.90 | 0.14 | 29.54 | 30.17 | +0.0133 MB/sample | Stable |
| Chain length | 11 → 301 (+290 over run) | — | 11 | 301 | — | Chain grew as expected |
| Chain valid (%) | 100 | — | — | — | — | All 30 samples valid |
Chain growth in both runs reflects the stability protocol appending 10 synthetic blocks per sample (30 samples → +290 blocks, from an initial 11), not live camera traffic; the isolated test database (
data/p4_chain_24h.db) was used precisely so this synthetic growth never touched the production chain.
Table 5.18: P4 RAM Trend Analysis (24-Hour Run)
| Parameter | Value |
|---|---|
| Slope (MB/sample) | 0.0133 |
| Total drift | +0.63 MB over 23.22 h (last sample minus first sample) |
| Verdict | Stable — no evidence of memory leak; drift is roughly two orders of magnitude below the leak criterion (< 1 MB/sample) |
Target: RAM slope < 1 MB/sample (no memory leak) — MET for both the 4.85-hour pilot and the full 24-hour confirmation run. All 60 samples across both runs valid.
[Insert Figure 5.4 — RAM and CPU trend over the 24-hour run, generated via
generate_report.py]
Discussion: The full 24-hour run confirms the trend observed in the initial pilot: CPU usage remained low and stable (mean 0.58%, SD 0.25, slope +0.0145%/sample) and RAM usage showed only a small, slightly positive drift (mean 29.90 MB, total drift +0.63 MB over 23.22 hours, slope +0.0133 MB/sample) — two orders of magnitude below the 1 MB/sample leak criterion. The chain grew from 11 to 301 blocks and remained valid at every one of the 30 sampled points; per-sample chain verification time grew from 0.60 ms to 14.16 ms as chain length increased, consistent with the O(n) scaling established in P3 (§5.3.3). Taken together with the pilot run, these results provide confirmatory evidence — not merely a preliminary indication — that the framework exhibits no memory leak and no meaningful CPU drift under continuous operation over a full-day window.
5.4 Overall Discussion
5.4.1 Hash Chain Integrity Effectiveness
Across the nine tamper-detection experiments conducted to date (E1–E9), the framework achieved 100% detection for seven of nine attack classes (E1–E5, E8, E9), with the two exceptions being mechanistically well understood rather than unexplained failures. E6 (replay, 53.3%) and E7 (chain rewrite, 0% local) both fail for the same underlying reason: local self-verification can only detect inconsistency within the chain's own stored fields, and an adversary capable of recomputing hashes after tampering (in scope under the threat model, §3.1.1) can always produce a locally self-consistent — but substantively fraudulent — chain. This is not a defect specific to this implementation; it is the fundamental limitation of any hash-chain-only integrity scheme, and it is precisely why the cloud anchor (Layer 3's secondary mechanism, §3.5.6) exists: an independently timestamped, externally stored checkpoint cannot be altered by an adversary who has compromised only the edge device. E6 and E7 together constitute the strongest evidence in this thesis for why cloud anchoring is a necessary component of the framework rather than an optional enhancement — without it, both attack classes would go completely undetected.
5.4.2 Edge Device Suitability
The performance results (P1–P3) collectively indicate that the Jetson Nano is well suited to sustaining this framework: no statistically significant CPU overhead was detected (P1), hash throughput exceeds the frame-capture demand by roughly four orders of magnitude (P2), and verification time scales linearly and remains sub-second even at tens of thousands of blocks (P3). Beyond the controlled benchmark experiments, the system's live deployment provides additional longitudinal evidence of edge-device suitability: as of 2026-04-29, the production chain had accumulated over 211,860 blocks (with the AWS parking_blockchain table holding approximately 25,923 checkpoint records and parking_frames approximately 259,229 detection records), reflecting weeks of continuous unattended operation. This scale of accumulated data — arising from ordinary operation rather than a synthetic benchmark — corroborates the P1–P3 findings under real-world conditions, though it should be noted that not every block in the live chain corresponds to a genuine camera frame; a subset of early blocks originated from the initial 4.85-hour P4 pilot test, which was (in hindsight) run against the live database rather than an isolated test database — a practice corrected for the full 24-hour P4 confirmation run (§5.3.4), which used an isolated test database (data/p4_chain_24h.db) and left the production chain untouched.
5.4.3 Cloud Anchor Contribution
The cloud anchor's contribution cannot be directly quantified from the local-only detection rates reported in §5.2, since verify_against_cloud() results were not included in the E6/E7 experiment runs analysed above (this is identified as a gap for a follow-up experiment, see §6.4). Architecturally, an externally held checkpoint is the only remaining source of ground truth against attack classes that are structurally undetectable by local verification — E6 Scenarios C/D and all of E7 — because it is the only record the local adversary does not author.
That argument, however, requires the external record to actually be external to the adversary, and in the configuration evaluated here it is not. The edge device necessarily holds IAM credentials permitting PutItem on the parking_blockchain table, so the device-write capability that §3.1.1 places in scope also confers cloud-write capability. Two implementation properties then remove the anchor's remaining value against that adversary: CloudAnchor.upload_checkpoint() issues an unconditional put_item, so existing checkpoints can be overwritten rather than only appended; and anchored_at is device-generated (§3.5.6), so the recorded anchoring time can be set arbitrarily. An adversary who rewrites the local chain and then re-uploads the corresponding checkpoints produces a local chain and a cloud record that agree, and verify_against_cloud() reports no mismatch. The cloud anchor's necessity as an architectural component therefore stands, but its sufficiency as implemented does not, and no detection claim against E6 C/D or E7 can be supported by the current deployment. The hardening required to make the argument hold — and the experiments that would then be able to test it — are specified in §5.4.5.
5.4.4 N2 — Chain Structure versus Direct Anchoring
A natural challenge to the framework's design is whether the hash chain earns its place at all: if the cloud anchor is what ultimately provides external ground truth (§5.4.3), why not discard the chain and upload each frame's hash to DynamoDB as an independent record? Experiment N2 was designed to answer this as a measurement rather than an argument.
The comparison must be normalised by cost, because the intuitive answer is wrong. It is tempting to claim that independent per-frame records cannot detect deletion — but if each record carries its block_index, a deleted frame leaves a gap in the anchored index sequence, and scanning for such gaps is trivial. The distinction only appears once both schemes are constrained to the same cloud-write budget. Both were therefore allocated one write per ten frames, matching the deployed checkpoint interval (§3.5.6): 100 writes per 1,000-block chain.
- Chain scheme: every tenth block's
block_hashis anchored. The nine intervening blocks are covered transitively, because each block'sprevious_hashbinds its predecessor up to the next anchor. - Direct scheme: no linkage. Records are independent
(block_index, frame_hash)pairs, and the same budget buys coverage of only one frame in ten. The other nine have no cloud record of any kind.
Deletion and injection were then applied identically to both schemes, at a uniformly random target index, with 30 trials per attack per scheme.
Table 5.19: N2 Detection at Equal Cloud-Write Budget (100 writes per 1,000 frames)
| Attack | Scheme | Detected | Detection Rate (%) | 95% CI |
|---|---|---|---|---|
| Deletion | Chain | 30 / 30 | 100.0 | [88.65, 100.0] |
| Deletion | Direct | 2 / 30 | 6.7 | [1.85, 21.32] |
| Injection | Chain | 30 / 30 | 100.0 | [88.65, 100.0] |
| Injection | Direct | 0 / 30 | 0.0 | [0.00, 11.35] |
Discussion: At equal cost the chain detects every tampering event; direct anchoring detects 6.7% of deletions and none of the injections. The mechanism behind those figures is confirmed by the per-trial records rather than merely asserted. Both deletions the direct scheme did catch had target_was_anchored = 1, and every deletion that landed on an anchored index was caught (2 of 2) — the scheme detects tampering precisely at the one-in-ten indices it records, and is blind everywhere else. With targets drawn uniformly, 2 of 30 is consistent with the expected one-in-ten rate.
Injection is detected at 0% by the direct scheme even when the target index is anchored, which is a genuine property rather than an artefact: a duplicated block_index collides within a per-index record set, and independent records carry no notion of how many blocks should lie between two anchors. The chain has that notion implicitly, because linkage must be continuous.
The correct statement of the chain's value is therefore neither "the chain detects deletion and direct anchoring does not" (false) nor "the chain is more secure" (unquantified), but rather: the chain provides deletion and reordering coverage over all frames at 1/N of the anchoring cost, where N is the checkpoint interval. Independent anchoring can match that coverage only by anchoring every frame — a tenfold increase in cloud writes, which at the live deployment's scale would mean roughly 259,000 records instead of the approximately 25,900 checkpoints actually stored (§5.4.2). The chain is, in effect, a compression mechanism that lets one cloud write vouch for N frames.
Two caveats bound the claim. The deletion and injection operations used here are simplified index-level manipulations applied identically to both schemes — deliberately, since a fair comparison requires the same tampering to reach both — and are not the attack_frame_deletion()/attack_frame_injection() routines used in E2/E3; the rates in Table 5.19 are therefore comparable within this experiment and should not be read against Tables 5.2 and 5.3. Second, this experiment measures detection coverage at equal cost, not resistance to the credential-inheriting adversary discussed in §5.4.3; that limitation applies to both schemes equally, since both depend on cloud records the device can currently overwrite.
5.4.5 Limitations
- Detection accuracy of Layer 1 (Canny-based occupancy classification) depends on lighting conditions, camera angle, and the empirically calibrated pixel-count threshold (revised from 500 to 300 during deployment, §3.3.2); a dedicated accuracy evaluation against manually labelled ground truth is a separate, scheduled activity (
SONNET_TASK_PLAN.mdT3.2) not covered by this chapter. - Canny thresholds require recalibration if the camera is repositioned or lighting conditions change substantially.
- Physical spoofing (E10, pending) cannot be prevented by the hash chain layer by design — the hash chain records whatever Layer 1 reports faithfully, regardless of whether that report reflects genuine occupancy; this is a deliberate separation of concerns between detection accuracy and data integrity, not a flaw.
- The cloud anchor provides no guarantee against this thesis's own primary adversary, as currently implemented. Replay attacks with recomputed hashes (E6 Scenarios C/D) and chain rewrite attacks (E7) are undetectable through local verification alone, so mitigating them depends entirely on the cloud checkpoint record. However, because the edge device holds IAM credentials permitting
PutItem, an adversary with the in-scope device-write capability (§3.1.1) inherits cloud-write capability; becauseupload_checkpoint()issues an unconditionalput_item, that adversary can overwrite existing checkpoints; and becauseanchored_atis device-generated, they can also control the recorded anchoring time (§5.4.3). This is the most significant limitation identified in this work. Three changes are required to close it, and are proposed as the immediate next step rather than as open-ended future work: (i) make the checkpoint store append-only, so that a previously written checkpoint cannot be overwritten by any holder of the device's credentials — noting that a client-side DynamoDBConditionExpressionis insufficient, since an adversary holding the credentials can simply omit it, and the constraint must therefore be enforced by the storage service itself (for example Amazon S3 Object Lock with versioning, using governance mode during development and compliance mode in production) or by mediating writes through a separate service identity the device does not possess; (ii) derive the anchoring time server-side (S3LastModified, DynamoDB StreamsApproximateCreationDateTime, or CloudTrail event time) so that it is not device-authored; and (iii) pin verification to the earliest stored version of each checkpoint, since under object versioning an adversary retainingPutObjectcan still write a later version, and a verifier reading only the newest one would read the forgery. E6 and E7 should then be re-run under the hardened configuration; only those results could support a claim that the anchor detects these attack classes. - Separately from the above, detection also depends on the checkpoint interval (currently every 10 blocks) — an attacker who tampers with blocks between two checkpoints and restores consistency before the next checkpoint upload could evade even a correctly hardened anchor. Characterising this tamper window as a function of the anchoring interval is proposed as a dedicated experiment (§6.4).
- The cloud anchor requires network connectivity; prolonged offline operation would delay checkpoint uploads and correspondingly widen the window of undetected local-only tampering described above.
- Chain verification time grows linearly with chain length (P3); at the live chain's current scale (>200,000 blocks), full verification takes on the order of several seconds, which is acceptable today but would require periodic archiving or checkpoint-based partial verification for indefinitely long deployments.
- E10 (physical spoofing) results in this chapter are incomplete as of this draft (see status note in §5.2.10) and must be finalised before submission.
5.5 Summary
This chapter presented results from nine completed tamper detection experiments (E1–E9), four completed performance benchmarks (P1–P4, including P4's full 24-hour confirmation run alongside its initial 4.85-hour pilot), two control experiments (N1 negative controls, N2 anchoring baseline), and a not-yet-conducted E10. The hash chain achieved 100% detection for seven of nine tested attack classes, with the two exceptions (E6 replay with recomputed hashes, and E7 chain rewrite) both stemming from the same well-understood structural limitation of local-only verification. Cloud anchoring is the architecturally correct response to both, but as implemented it does not close them: the edge device holds the credentials that write the checkpoints and generates their timestamps, so it provides no guarantee against the very adversary the threat model places in scope (§5.4.3). Making the checkpoint store append-only under a separate service identity, with server-derived anchoring times, is accordingly the immediate next step rather than optional hardening (§5.4.5). Performance benchmarks show no statistically significant CPU overhead, hash throughput exceeding the 100 hashes/second design target by roughly two orders of magnitude, confirmed O(n) verification scaling, and no memory leak or CPU drift over a full 24-hour operational window (23.2 h between first and last samples), together supporting the suitability of the proposed framework for continuous deployment on resource-constrained edge devices. The control experiments qualify these findings in two ways: no detection mechanism produced a false positive across 30 untampered chains (N1), so the reported detection rates reflect genuine discrimination rather than an indiscriminate verifier; and at an equal cloud-write budget the chain detected 100% of deletions and injections against 6.7% and 0% respectively for independent per-frame anchoring (N2), quantifying what the chain structure contributes over direct anchoring at the same cost. Chapter 6 presents the conclusions drawn from these findings — to be finalised once the E10 field session and Layer 1 accuracy evaluation are complete — and directions for future research.
Chapter 6 — Conclusion and Future Work
Not yet written.
This chapter has not been drafted. It is shown here so the table of contents reflects the true state of the thesis rather than omitting the gap.