File size: 2,151 Bytes
0865492
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fileHash = fileHash;
exports.hmac = hmac;
exports.verificationHash = verificationHash;
const blake3_jit_1 = require("@huggingface/blake3-jit");
const xorb_hash_js_1 = require("./xorb-hash.js");
const ZERO_KEY = new Uint8Array(32);
const VERIFICATION_KEY = new Uint8Array([
    127, 24, 87, 214, 206, 86, 237, 102, 18, 127, 249, 19, 231, 165, 195, 243, 164, 205, 38, 213, 181, 219, 73, 230,
    65, 36, 152, 127, 40, 251, 148, 195,
]);
const fileHasher = blake3_jit_1.Hasher.newKeyed(ZERO_KEY);
const verificationHasher = blake3_jit_1.Hasher.newKeyed(VERIFICATION_KEY);
/**
 * file_hash = hmac(xorb_hash(chunks), zero_key)
 *
 * Matches Rust's `merklehash::file_hash` which calls
 * `file_hash_with_salt(chunks, &[0; 32])`.
 */
function fileHash(chunks) {
    // Empty input short-circuits to the all-zero MerkleHash, matching Rust's
    // `file_hash_with_salt` (`if chunks.is_empty() { return MerkleHash::default(); }`).
    // Without this we'd return `hmac(0, zero_key)`, which the CAS shard validation rejects
    // for empty files with "file reconstruction does not produce this hash".
    if (chunks.length === 0) {
        return new Uint8Array(32);
    }
    const xorb = (0, xorb_hash_js_1.xorbHash)(chunks);
    return fileHasher.reset().update(xorb).finalize(32);
}
/**
 * HMAC: blake3_keyed_hash(key_bytes, hash_bytes)
 *
 * Both inputs are 32-byte Uint8Arrays.
 * Matches Rust's `DataHash::hmac`.
 *
 * Uses a fresh hasher per call since the key varies.
 */
function hmac(hash, key) {
    return blake3_jit_1.Hasher.newKeyed(key).update(hash).finalize(32);
}
/**
 * Verification hash for a range of chunk hashes.
 * Concatenates all 32-byte hashes and applies blake3_keyed_hash
 * with VERIFICATION_KEY.
 *
 * Matches Rust's `chunk_verification::range_hash_from_chunks`.
 */
function verificationHash(chunkHashes) {
    const combined = new Uint8Array(chunkHashes.length * 32);
    for (let i = 0; i < chunkHashes.length; i++) {
        combined.set(chunkHashes[i], i * 32);
    }
    return verificationHasher.reset().update(combined).finalize(32);
}