From 17614dcda5ad720c6b3d1dfad6c21553e6d10801 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 1 Sep 2026 13:36:57 -0500 Subject: [PATCH] docs: update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b30cfc9..2b32537 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The storage is designed around direct random-access offset writing. As data chun This approach makes file assembly basically instant. Finalizing a file takes less than 1 ms and operates with O(1) time complexity because the server only needs to atomically rename `upload.part` to its destination name using `File.Move`. This eliminates the need for background worker services, disk-copying loops, or complex progress-tracking channels between the server and client. -To guarantee end-to-end data integrity across parallel chunk transmissions, the program uses a two-tiered SHA-256 verification model alongside deterministic session hashing: +The program uses a two-tiered SHA-256 verification model alongside deterministic session hashing to provide end-to-end data integrity across parallel chunk transmissions: - **Per-Chunk Verification**: On the client, SHA-256 hashes are calculated lazily for each chunk right before transmission using `crypto.subtle.digest`. Upon receipt, the server streams the chunk payload, independently computes its SHA-256 digest, and validates it against the client's hash using constant-time byte comparison (`CryptographicOperations.FixedTimeEquals`). Once validated, the chunk is written to disk alongside a `{index}-{hash}.done` marker file. - **Composite End-to-End File Verification**: When all chunks finish uploading, the client orders the individual chunk hashes, joins them into a comma-separated string (`hash_0,hash_1,..., hash_n-1`), and computes a final composite SHA-256 hash. When `/Files/{fileId}/complete` is invoked, the server independently recalculates the composite hash from its stored `.done` marker files. The atomic `File.Move` rename executes only if the composite hashes match, guaranteeing that no chunks were corrupted, omitted, or reassembled out of sequence.