WebCrypto

:= []

Hashing via the browser's Web Crypto (crypto.subtle.digest), as effects: the digest runs asynchronously on the JS side and the hash arrives in update as a typed message.

For bytes you already have, prefer Roc's built-in Crypto module (Crypto.SHA256.hash(bytes) / Crypto.BLAKE3.hash(bytes)): it is pure, synchronous, and needs no effect round-trip. This module earns its keep where the builtin cannot go: hashing a user-picked FILE (see Attribute.on_file) whose bytes live on the browser side and never enter wasm memory, and the SHA-1/SHA-384/SHA-512 algorithms the builtin does not provide. For chunked hashing of large files (progress reporting, or a hash-of-chunk-hashes scheme), issue one digest_file_slice per chunk (the browser runs them concurrently) and hash the concatenated chunk hashes at the end.

The callback receives the raw hash bytes (20 for Sha1, 32 for Sha256, 48 for Sha384, 64 for Sha512). An EMPTY list means the digest failed (unknown file id, or the file changed on disk after being picked).

algorithm_name : Algorithm -> Str

The Web Crypto name of an algorithm ("SHA-256", ...).

digest : Algorithm, List(U8), (List(U8) -> msg) -> Effect(msg)

Hash bytes: WebCrypto.digest(Sha384, bytes, |hash| GotHash(hash)). (For Sha256, the built-in Crypto.SHA256.hash is the better tool.)

digest_file : Algorithm, U32, (List(U8) -> msg) -> Effect(msg)

Hash a user-picked file by its Attribute.FileInfo id.

digest_file_slice : Algorithm, { file : U32, start : U64, len : U64 }, (List(U8) -> msg) -> Effect(msg)

Hash a byte range of a user-picked file (len 0 means through the end). One call per chunk gives chunked hashing with progress.

to_hex : List(U8) -> Str

The conventional lowercase-hex rendering of a hash.

Algorithm : [Sha1, Sha256, Sha384, Sha512]

Web Crypto's supported digest algorithms. Sha1 is broken for collision resistance; it is here for interop with systems keyed on it, not for anything security-sensitive.