[{"data":1,"prerenderedAt":895},["ShallowReactive",2],{"navigation_docs":3,"-guide-custom":148,"-guide-custom-surround":890},[4,40],{"title":5,"path":6,"stem":7,"children":8,"icon":39},"Guide","\u002Fguide","1.guide\u002F01.index",[9,11,15,19,23,27,31,35],{"title":10,"path":6,"stem":7},"Getting Started",{"title":12,"path":13,"stem":14},"Hashing","\u002Fguide\u002Fhashing","1.guide\u002F02.hashing",{"title":16,"path":17,"stem":18},"HMAC and verify","\u002Fguide\u002Fverify","1.guide\u002F03.verify",{"title":20,"path":21,"stem":22},"Salted KDFs","\u002Fguide\u002Fkdf","1.guide\u002F04.kdf",{"title":24,"path":25,"stem":26},"CLI","\u002Fguide\u002Fcli","1.guide\u002F05.cli",{"title":28,"path":29,"stem":30},"Agents","\u002Fguide\u002Fagents","1.guide\u002F06.agents",{"title":32,"path":33,"stem":34},"Custom algorithms","\u002Fguide\u002Fcustom","1.guide\u002F07.custom",{"title":36,"path":37,"stem":38},"Playground","\u002Fguide\u002Fplayground","1.guide\u002F08.playground","i-lucide-book-open",{"title":41,"path":42,"stem":43,"children":44,"icon":147},"Algorithms","\u002Falgorithms","2.algorithms\u002F00.index",[45,47,51,55,59,63,67,71,75,79,83,87,91,95,99,103,107,111,115,119,123,127,131,135,139,143],{"title":46,"path":42,"stem":43},"Every algorithm",{"title":48,"path":49,"stem":50},"SHA-256","\u002Falgorithms\u002Fsha256","2.algorithms\u002F01.sha256",{"title":52,"path":53,"stem":54},"SHA-384","\u002Falgorithms\u002Fsha384","2.algorithms\u002F02.sha384",{"title":56,"path":57,"stem":58},"SHA-512","\u002Falgorithms\u002Fsha512","2.algorithms\u002F03.sha512",{"title":60,"path":61,"stem":62},"SHA-512Half","\u002Falgorithms\u002Fsha512-half","2.algorithms\u002F04.sha512-half",{"title":64,"path":65,"stem":66},"SHA3-256","\u002Falgorithms\u002Fsha3-256","2.algorithms\u002F05.sha3-256",{"title":68,"path":69,"stem":70},"SHA3-512","\u002Falgorithms\u002Fsha3-512","2.algorithms\u002F06.sha3-512",{"title":72,"path":73,"stem":74},"Keccak-256","\u002Falgorithms\u002Fkeccak256","2.algorithms\u002F07.keccak256",{"title":76,"path":77,"stem":78},"BLAKE2b","\u002Falgorithms\u002Fblake2b","2.algorithms\u002F08.blake2b",{"title":80,"path":81,"stem":82},"BLAKE2b-256","\u002Falgorithms\u002Fblake2b-256","2.algorithms\u002F09.blake2b-256",{"title":84,"path":85,"stem":86},"BLAKE2b-224","\u002Falgorithms\u002Fblake2b-224","2.algorithms\u002F10.blake2b-224",{"title":88,"path":89,"stem":90},"BLAKE2s","\u002Falgorithms\u002Fblake2s","2.algorithms\u002F11.blake2s",{"title":92,"path":93,"stem":94},"BLAKE3","\u002Falgorithms\u002Fblake3","2.algorithms\u002F12.blake3",{"title":96,"path":97,"stem":98},"BLAKE-256","\u002Falgorithms\u002Fblake256","2.algorithms\u002F13.blake256",{"title":100,"path":101,"stem":102},"RIPEMD-160","\u002Falgorithms\u002Fripemd160","2.algorithms\u002F14.ripemd160",{"title":104,"path":105,"stem":106},"HASH160","\u002Falgorithms\u002Fhash160","2.algorithms\u002F15.hash160",{"title":108,"path":109,"stem":110},"HASH256","\u002Falgorithms\u002Fhash256","2.algorithms\u002F16.hash256",{"title":112,"path":113,"stem":114},"MD5","\u002Falgorithms\u002Fmd5","2.algorithms\u002F17.md5",{"title":116,"path":117,"stem":118},"SHA-1","\u002Falgorithms\u002Fsha1","2.algorithms\u002F18.sha1",{"title":120,"path":121,"stem":122},"SHA-0","\u002Falgorithms\u002Fsha0","2.algorithms\u002F19.sha0",{"title":124,"path":125,"stem":126},"CRC-32","\u002Falgorithms\u002Fcrc32","2.algorithms\u002F20.crc32",{"title":128,"path":129,"stem":130},"CRC-16\u002FXMODEM","\u002Falgorithms\u002Fcrc16-xmodem","2.algorithms\u002F21.crc16-xmodem",{"title":132,"path":133,"stem":134},"xxHash (XXH64)","\u002Falgorithms\u002Fxxhash","2.algorithms\u002F22.xxhash",{"title":136,"path":137,"stem":138},"FNV-1a (64-bit)","\u002Falgorithms\u002Ffnv1a","2.algorithms\u002F23.fnv1a",{"title":140,"path":141,"stem":142},"scrypt","\u002Falgorithms\u002Fscrypt","2.algorithms\u002F24.scrypt",{"title":144,"path":145,"stem":146},"PBKDF2","\u002Falgorithms\u002Fpbkdf2","2.algorithms\u002F25.pbkdf2","i-lucide-library",{"id":149,"title":32,"body":150,"description":883,"extension":884,"links":885,"meta":886,"navigation":261,"path":33,"seo":888,"stem":34,"__hash__":889},"docs\u002F1.guide\u002F07.custom.md",{"type":151,"value":152,"toc":876},"minimark",[153,158,167,216,220,223,589,602,606,617,803,806,810,832,836,872],[154,155,157],"h2",{"id":156},"three-base-classes","Three base classes",[159,160,161,162,166],"p",{},"Every built-in is a class with a static ",[163,164,165],"code",{},"key",", and yours is the same shape. Pick the base by what you need:",[168,169,170,184,200],"ul",{},[171,172,173,179,180,183],"li",{},[174,175,176],"strong",{},[163,177,178],{},"FixedHash"," for a fixed-length digest. You write ",[163,181,182],{},"digest(bytes)",", it does the encodings, the result object, the error wrapping, and refuses an HMAC key.",[171,185,186,191,192,195,196,199],{},[174,187,188],{},[163,189,190],{},"BlockHash"," for a fixed-length digest built on an incremental ",[163,193,194],{},"Hasher",". You write ",[163,197,198],{},"hasher()",", and HMAC over its blocks comes for free.",[171,201,202,207,208,211,212,215],{},[174,203,204],{},[163,205,206],{},"Hash"," for anything else, like a KDF with its own options. You write ",[163,209,210],{},"info()"," and ",[163,213,214],{},"hash()"," yourself.",[154,217,219],{"id":218},"a-fixed-digest","A fixed digest",[159,221,222],{},"FNV-1a in 32 bits, plain TypeScript, so it runs anywhere the library does:",[224,225,231],"pre",{"className":226,"code":227,"filename":228,"language":229,"meta":230,"style":230},"language-ts shiki shiki-themes hashes hashes hashes","import { FixedHash, create, register } from \"@agntn\u002Fhashes\";\n\nclass Fnv1a32 extends FixedHash {\n  static readonly key = \"fnv1a-32\";\n  protected readonly about = {\n    label: \"FNV-1a (32-bit)\",\n    description: \"FNV-1a 32-bit, for hash tables\",\n    family: \"non-cryptographic\",\n    digestLength: 4,\n  } as const;\n\n  protected digest(bytes: Uint8Array): Uint8Array {\n    let hash = 0x811c9dc5;\n    for (const byte of bytes) hash = Math.imul(hash ^ byte, 0x01000193);\n    const out = new Uint8Array(4);\n    new DataView(out.buffer).setUint32(0, hash >>> 0);\n    return out;\n  }\n}\n\nregister(Fnv1a32);\ncreate(\"fnv1a-32\").hash(\"a\").digest; \u002F\u002F \"e40c292c\"\ncreate(\"fnv1a-32\").hash(\"a\", { key: \"k\" }); \u002F\u002F throws, fnv1a-32 has no HMAC mode\n","fnv1a-32.ts","ts","",[163,232,233,256,263,279,299,315,327,338,349,355,369,374,400,414,452,471,495,504,510,516,521,530,560],{"__ignoreMap":230},[234,235,238,242,246,249,253],"span",{"class":236,"line":237},"line",1,[234,239,241],{"class":240},"skH_V","import",[234,243,245],{"class":244},"s38Sx"," { FixedHash, create, register } ",[234,247,248],{"class":240},"from",[234,250,252],{"class":251},"shU9J"," \"@agntn\u002Fhashes\"",[234,254,255],{"class":244},";\n",[234,257,259],{"class":236,"line":258},2,[234,260,262],{"emptyLinePlaceholder":261},true,"\n",[234,264,266,269,273,276],{"class":236,"line":265},3,[234,267,268],{"class":240},"class",[234,270,272],{"class":271},"sK71F"," Fnv1a32",[234,274,275],{"class":240}," extends",[234,277,278],{"class":244}," FixedHash {\n",[234,280,282,285,288,291,294,297],{"class":236,"line":281},4,[234,283,284],{"class":240},"  static",[234,286,287],{"class":240}," readonly",[234,289,290],{"class":244}," key ",[234,292,293],{"class":240},"=",[234,295,296],{"class":251}," \"fnv1a-32\"",[234,298,255],{"class":244},[234,300,302,305,307,310,312],{"class":236,"line":301},5,[234,303,304],{"class":240},"  protected",[234,306,287],{"class":240},[234,308,309],{"class":244}," about ",[234,311,293],{"class":240},[234,313,314],{"class":244}," {\n",[234,316,318,321,324],{"class":236,"line":317},6,[234,319,320],{"class":244},"    label: ",[234,322,323],{"class":251},"\"FNV-1a (32-bit)\"",[234,325,326],{"class":244},",\n",[234,328,330,333,336],{"class":236,"line":329},7,[234,331,332],{"class":244},"    description: ",[234,334,335],{"class":251},"\"FNV-1a 32-bit, for hash tables\"",[234,337,326],{"class":244},[234,339,341,344,347],{"class":236,"line":340},8,[234,342,343],{"class":244},"    family: ",[234,345,346],{"class":251},"\"non-cryptographic\"",[234,348,326],{"class":244},[234,350,352],{"class":236,"line":351},9,[234,353,354],{"class":244},"    digestLength: 4,\n",[234,356,358,361,364,367],{"class":236,"line":357},10,[234,359,360],{"class":244},"  } ",[234,362,363],{"class":240},"as",[234,365,366],{"class":240}," const",[234,368,255],{"class":244},[234,370,372],{"class":236,"line":371},11,[234,373,262],{"emptyLinePlaceholder":261},[234,375,377,379,382,385,388,391,394,396,398],{"class":236,"line":376},12,[234,378,304],{"class":240},[234,380,381],{"class":271}," digest",[234,383,384],{"class":244},"(bytes",[234,386,387],{"class":240},":",[234,389,390],{"class":271}," Uint8Array",[234,392,393],{"class":244},")",[234,395,387],{"class":240},[234,397,390],{"class":271},[234,399,314],{"class":244},[234,401,403,406,409,411],{"class":236,"line":402},13,[234,404,405],{"class":240},"    let",[234,407,408],{"class":244}," hash ",[234,410,293],{"class":240},[234,412,413],{"class":244}," 0x811c9dc5;\n",[234,415,417,420,423,426,429,432,435,437,440,443,446,449],{"class":236,"line":416},14,[234,418,419],{"class":240},"    for",[234,421,422],{"class":244}," (",[234,424,425],{"class":240},"const",[234,427,428],{"class":244}," byte ",[234,430,431],{"class":240},"of",[234,433,434],{"class":244}," bytes) hash ",[234,436,293],{"class":240},[234,438,439],{"class":244}," Math.",[234,441,442],{"class":271},"imul",[234,444,445],{"class":244},"(hash ",[234,447,448],{"class":240},"^",[234,450,451],{"class":244}," byte, 0x01000193);\n",[234,453,455,458,461,463,466,468],{"class":236,"line":454},15,[234,456,457],{"class":240},"    const",[234,459,460],{"class":244}," out ",[234,462,293],{"class":240},[234,464,465],{"class":240}," new",[234,467,390],{"class":271},[234,469,470],{"class":244},"(4);\n",[234,472,474,477,480,483,486,489,492],{"class":236,"line":473},16,[234,475,476],{"class":240},"    new",[234,478,479],{"class":271}," DataView",[234,481,482],{"class":244},"(out.buffer).",[234,484,485],{"class":271},"setUint32",[234,487,488],{"class":244},"(0, hash ",[234,490,491],{"class":240},">>>",[234,493,494],{"class":244}," 0);\n",[234,496,498,501],{"class":236,"line":497},17,[234,499,500],{"class":240},"    return",[234,502,503],{"class":244}," out;\n",[234,505,507],{"class":236,"line":506},18,[234,508,509],{"class":244},"  }\n",[234,511,513],{"class":236,"line":512},19,[234,514,515],{"class":244},"}\n",[234,517,519],{"class":236,"line":518},20,[234,520,262],{"emptyLinePlaceholder":261},[234,522,524,527],{"class":236,"line":523},21,[234,525,526],{"class":271},"register",[234,528,529],{"class":244},"(Fnv1a32);\n",[234,531,533,536,539,542,545,548,550,553,556],{"class":236,"line":532},22,[234,534,535],{"class":271},"create",[234,537,538],{"class":244},"(",[234,540,541],{"class":251},"\"fnv1a-32\"",[234,543,544],{"class":244},").",[234,546,547],{"class":271},"hash",[234,549,538],{"class":244},[234,551,552],{"class":251},"\"a\"",[234,554,555],{"class":244},").digest; ",[234,557,559],{"class":558},"scIB-","\u002F\u002F \"e40c292c\"\n",[234,561,563,565,567,569,571,573,575,577,580,583,586],{"class":236,"line":562},23,[234,564,535],{"class":271},[234,566,538],{"class":244},[234,568,541],{"class":251},[234,570,544],{"class":244},[234,572,547],{"class":271},[234,574,538],{"class":244},[234,576,552],{"class":251},[234,578,579],{"class":244},", { key: ",[234,581,582],{"class":251},"\"k\"",[234,584,585],{"class":244}," }); ",[234,587,588],{"class":558},"\u002F\u002F throws, fnv1a-32 has no HMAC mode\n",[159,590,591,594,595,597,598,601],{},[163,592,593],{},"about"," is everything ",[163,596,210],{}," reports besides the name, the options and HMAC support. Add ",[163,599,600],{},"securityNote"," if there's something a user should know before trusting it.",[154,603,605],{"id":604},"borrowing-from-nodecrypto","Borrowing from node:crypto",[159,607,608,609,612,613,616],{},"On Node you can wrap what ",[163,610,611],{},"node:crypto"," already has. The library itself doesn't import ",[163,614,615],{},"node:*",", your file can:",[224,618,621],{"className":226,"code":619,"filename":620,"language":229,"meta":230,"style":230},"import { createHash } from \"node:crypto\";\nimport { FixedHash, register } from \"@agntn\u002Fhashes\";\n\nclass Sha224 extends FixedHash {\n  static readonly key = \"sha224\";\n  protected readonly about = {\n    label: \"SHA-224\",\n    description: \"SHA-2 family 224-bit hash\",\n    family: \"cryptographic\",\n    digestLength: 28,\n  } as const;\n\n  protected digest(bytes: Uint8Array): Uint8Array {\n    return createHash(\"sha224\").update(bytes).digest();\n  }\n}\n\nregister(Sha224);\n","sha224.ts",[163,622,623,637,650,654,665,680,692,701,710,719,724,734,738,758,784,788,792,796],{"__ignoreMap":230},[234,624,625,627,630,632,635],{"class":236,"line":237},[234,626,241],{"class":240},[234,628,629],{"class":244}," { createHash } ",[234,631,248],{"class":240},[234,633,634],{"class":251}," \"node:crypto\"",[234,636,255],{"class":244},[234,638,639,641,644,646,648],{"class":236,"line":258},[234,640,241],{"class":240},[234,642,643],{"class":244}," { FixedHash, register } ",[234,645,248],{"class":240},[234,647,252],{"class":251},[234,649,255],{"class":244},[234,651,652],{"class":236,"line":265},[234,653,262],{"emptyLinePlaceholder":261},[234,655,656,658,661,663],{"class":236,"line":281},[234,657,268],{"class":240},[234,659,660],{"class":271}," Sha224",[234,662,275],{"class":240},[234,664,278],{"class":244},[234,666,667,669,671,673,675,678],{"class":236,"line":301},[234,668,284],{"class":240},[234,670,287],{"class":240},[234,672,290],{"class":244},[234,674,293],{"class":240},[234,676,677],{"class":251}," \"sha224\"",[234,679,255],{"class":244},[234,681,682,684,686,688,690],{"class":236,"line":317},[234,683,304],{"class":240},[234,685,287],{"class":240},[234,687,309],{"class":244},[234,689,293],{"class":240},[234,691,314],{"class":244},[234,693,694,696,699],{"class":236,"line":329},[234,695,320],{"class":244},[234,697,698],{"class":251},"\"SHA-224\"",[234,700,326],{"class":244},[234,702,703,705,708],{"class":236,"line":340},[234,704,332],{"class":244},[234,706,707],{"class":251},"\"SHA-2 family 224-bit hash\"",[234,709,326],{"class":244},[234,711,712,714,717],{"class":236,"line":351},[234,713,343],{"class":244},[234,715,716],{"class":251},"\"cryptographic\"",[234,718,326],{"class":244},[234,720,721],{"class":236,"line":357},[234,722,723],{"class":244},"    digestLength: 28,\n",[234,725,726,728,730,732],{"class":236,"line":371},[234,727,360],{"class":244},[234,729,363],{"class":240},[234,731,366],{"class":240},[234,733,255],{"class":244},[234,735,736],{"class":236,"line":376},[234,737,262],{"emptyLinePlaceholder":261},[234,739,740,742,744,746,748,750,752,754,756],{"class":236,"line":402},[234,741,304],{"class":240},[234,743,381],{"class":271},[234,745,384],{"class":244},[234,747,387],{"class":240},[234,749,390],{"class":271},[234,751,393],{"class":244},[234,753,387],{"class":240},[234,755,390],{"class":271},[234,757,314],{"class":244},[234,759,760,762,765,767,770,772,775,778,781],{"class":236,"line":416},[234,761,500],{"class":240},[234,763,764],{"class":271}," createHash",[234,766,538],{"class":244},[234,768,769],{"class":251},"\"sha224\"",[234,771,544],{"class":244},[234,773,774],{"class":271},"update",[234,776,777],{"class":244},"(bytes).",[234,779,780],{"class":271},"digest",[234,782,783],{"class":244},"();\n",[234,785,786],{"class":236,"line":454},[234,787,509],{"class":244},[234,789,790],{"class":236,"line":473},[234,791,515],{"class":244},[234,793,794],{"class":236,"line":497},[234,795,262],{"emptyLinePlaceholder":261},[234,797,798,800],{"class":236,"line":506},[234,799,526],{"class":271},[234,801,802],{"class":244},"(Sha224);\n",[159,804,805],{},"That one won't run in a browser, of course. The built-ins do, which is how this site works.",[154,807,809],{"id":808},"registering","Registering",[159,811,812,815,816,818,819,821,822,821,825,821,828,831],{},[163,813,814],{},"register(Class)"," puts the class under its ",[163,817,165],{},", replacing any algorithm with the same key and dropping its cached instance. After that ",[163,820,535],{},", ",[163,823,824],{},"has",[163,826,827],{},"algorithms",[163,829,830],{},"resolveAlgorithm"," and every tool executor see it. Importing the package registers nothing by itself. The built-ins seed the registry on first use, so importing mutates no shared state.",[154,833,835],{"id":834},"options-of-your-own","Options of your own",[159,837,838,839,211,842,844,845,848,849,852,853,856,857,860,861,863,864,867,868,871],{},"An option besides ",[163,840,841],{},"encoding",[163,843,165],{}," goes in ",[163,846,847],{},"info().options",", like xxHash's ",[163,850,851],{},"seed",". That one declaration is what the tool executors check ",[163,854,855],{},"parameters"," against, so ",[163,858,859],{},"parameters: { seed }"," reaches your digest and a name you didn't declare is refused. The built-ins' options become CLI flags the same way. ",[163,862,178],{}," takes them as a protected ",[163,865,866],{},"options"," array and passes the values into ",[163,869,870],{},"digest(bytes, options)",".",[873,874,875],"style",{},"html pre.shiki code .skH_V, html code.shiki .skH_V{--shiki-light:var(--shiki-token-keyword);--shiki-default:var(--shiki-token-keyword);--shiki-dark:var(--shiki-token-keyword)}html pre.shiki code .s38Sx, html code.shiki .s38Sx{--shiki-light:var(--ui-text-highlighted);--shiki-default:var(--ui-text-highlighted);--shiki-dark:var(--ui-text-highlighted)}html pre.shiki code .shU9J, html code.shiki .shU9J{--shiki-light:var(--shiki-token-string);--shiki-default:var(--shiki-token-string);--shiki-dark:var(--shiki-token-string)}html pre.shiki code .sK71F, html code.shiki .sK71F{--shiki-light:var(--shiki-token-function);--shiki-default:var(--shiki-token-function);--shiki-dark:var(--shiki-token-function)}html pre.shiki code .scIB-, html code.shiki .scIB-{--shiki-light:var(--shiki-token-comment);--shiki-default:var(--shiki-token-comment);--shiki-dark:var(--shiki-token-comment)}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":230,"searchDepth":258,"depth":258,"links":877},[878,879,880,881,882],{"id":156,"depth":258,"text":157},{"id":218,"depth":258,"text":219},{"id":604,"depth":258,"text":605},{"id":808,"depth":258,"text":809},{"id":834,"depth":258,"text":835},"Extend FixedHash or BlockHash or Hash and register the class. The CLI and the tools see it too","md",null,{"icon":887},"i-lucide-plus",{"title":32,"description":883},"Y_LyCYJhprkWdrBqKuMh6VSARmEvJ81jzp36IZobSzs",[891,893],{"title":28,"path":29,"stem":30,"description":892,"children":-1},"The same hash tools over MCP and Pi and OMP and the AI SDK. What they take and what they refuse and what the model reads back",{"title":36,"path":37,"stem":38,"description":894,"children":-1},"The page behind hashes.agntn.dev\u002Fplayground runs the library in your browser. What it does and what it won't",1790683656173]