{"id":15564078,"url":"https://github.com/dahlia/json-hash","last_synced_at":"2025-06-20T17:34:08.247Z","repository":{"id":49951269,"uuid":"446508602","full_name":"dahlia/json-hash","owner":"dahlia","description":"JCS (JSON Canonicalization Scheme), JSON digests, and JSON Merkle hashes","archived":false,"fork":false,"pushed_at":"2024-03-10T17:12:34.000Z","size":54,"stargazers_count":14,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-06-11T00:57:00.831Z","etag":null,"topics":["canonicalization","deno","hash","jcs","json","merkle-tree","normalization","typescript"],"latest_commit_sha":null,"homepage":"https://deno.land/x/json_hash","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dahlia.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-10T16:55:50.000Z","updated_at":"2024-02-04T13:18:37.000Z","dependencies_parsed_at":"2024-10-23T12:06:50.793Z","dependency_job_id":null,"html_url":"https://github.com/dahlia/json-hash","commit_stats":{"total_commits":25,"total_committers":1,"mean_commits":25.0,"dds":0.0,"last_synced_commit":"2f5a2e863a4b4a8905958d6ff53e72d82f0072c3"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/dahlia/json-hash","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dahlia%2Fjson-hash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dahlia%2Fjson-hash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dahlia%2Fjson-hash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dahlia%2Fjson-hash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dahlia","download_url":"https://codeload.github.com/dahlia/json-hash/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dahlia%2Fjson-hash/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260988090,"owners_count":23093444,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["canonicalization","deno","hash","jcs","json","merkle-tree","normalization","typescript"],"created_at":"2024-10-02T16:36:01.778Z","updated_at":"2025-06-20T17:34:03.233Z","avatar_url":"https://github.com/dahlia.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- deno-fmt-ignore-file --\u003e\n\nJSON Hash\n=========\n\n[![Latest version][Tag badge]][Deno module]\n[![LGPL 3.0][License badge]](./LICENSE)\n[![Deno Doc (API references)][Deno Doc badge]][Deno Doc]\n[![GitHub Actions][GitHub Actions status badge]][GitHub Actions]\n[![Codecov][Codecov badge]][Codecov]\n\nThis [Deno][][^1] package contains several utilities to deal JSON data with\ncryptography.  See the below sections for details.\n\n[^1]: It is open to expand its target runtimes including [web browsers in\n      particular][1].\n\n[Tag badge]: https://img.shields.io/github/v/tag/dahlia/json-hash\n[Deno module]: https://deno.land/x/json_hash\n[License badge]: https://img.shields.io/github/license/dahlia/json-hash\n[Deno Doc]: https://doc.deno.land/https://deno.land/x/json_hash/mod.ts\n[Deno Doc badge]: https://img.shields.io/badge/api-deno%20doc-blue\n[GitHub Actions]: https://github.com/dahlia/json-hash/actions/workflows/test.yaml\n[GitHub Actions status badge]: https://github.com/dahlia/json-hash/actions/workflows/test.yaml/badge.svg\n[Codecov badge]: https://codecov.io/gh/dahlia/json-hash/branch/main/graph/badge.svg?token=rCNDUvONJv\n[Codecov]: https://codecov.io/gh/dahlia/json-hash\n[Deno]: https://deno.land/\n[1]: https://github.com/dahlia/json-hash/issues/2\n\n\n[*canon.ts*][canon.ts]: JSON normalizer compliant with JCS\n----------------------------------------------------------\n\nCryptographic operations like hashing and signing need the data to be\nexpressed in an invariant format so that the operations are reliably\nrepeatable.  Even if two messages are similar, only a single byte of difference\ncauses totally different digests or signatures.\n\nHowever, JSON allows stylistic freedom on their representations.\nFor example, the following representations all encodes the same JSON entity:\n\n~~~ jsonl\n{ \"foo\": \"bar\", \"baz\": [1, 2, 3] }\n{ \"baz\": [1, 2, 3], \"foo\": \"bar\" }\n{\"foo\":\"bar\",\"baz\":[1,2,3]}\n{ \"\\u0066\\u006f\\u006f\": \"\\u0062\\u0061\\u0072\", \"\\u0062\\u0061\\u007a\": [1, 2, 3] }\n~~~~\n\nIn order to hash or sign JSON data, they should be normalized first.\nThat's why JSON Canonicalization Scheme (JCS) was proposed in [RFC 8785].\nJCS allows only a single representation for each possible JSON entity.\nFor example, the JSON entity the above multiple representations encode can\nbe represented into only the below single form:\n\n~~~ json\n{\"baz\":[1,2,3],\"foo\":\"bar\"}\n~~~\n\nThe [*canon.ts*][canon.ts] module implements JCS, which completely complies\nwith [RFC 8785].  Here's some example:\n\n~~~ typescript\nimport { canonicalize } from \"https://deno.land/x/json_hash/canon.ts\";\nimport { assertEquals } from \"https://deno.land/std/testing/asserts.ts\";\n\nassertEquals(\n  canonicalize({ foo: \"bar\", baz: [1, 2, 3] }),\n  canonicalize({\n    \"\\x62\\x61\\x7a\": [1, 2, 3],\n    \"\\x66\\x6f\\x6f\": \"\\x62\\x61\\x72\",\n  }),\n);\n~~~\n\n[canon.ts]: https://doc.deno.land/https://deno.land/x/json_hash/canon.ts\n[RFC 8785]: https://tools.ietf.org/html/rfc8785\n\n\n[*digest.ts*][digest.ts]: Hashing JSON entities\n-----------------------------------------------\n\nThis module is a thin wrapper around the above `canonicalize()` function and\nthe curated collection of cryptographic hash algorithms:\n\n~~~~ typescript\nimport { digest } from \"https://deno.land/x/json_hash/digest.ts\";\nimport { toHex } from \"https://deno.land/x/json_hash/hex.ts\";\n\nconst data = { foo: \"bar\", baz: [ 1, 2, 3 ]};\nconst hash: Uint8Array = await digest(\"BLAKE3\", data);\nconsole.log(toHex(hash));\n// dec9c1a89be824103c812b7ace381263335cd6f421a4d0f4dd407a4d3335189c\n~~~~\n\nThe `digest()` function guarantees that it will return the equivalent hash\ndigest (in `Uint8Array`) for the same hash algorithm and the equivalent JSON\nentity.  It means you don't have to care about the order of how object keys\noccurs or how characters in string are encoded.\n\nAlso note that the above example uses [BLAKE3], which is unsupported by\nWeb Crypto API (as of January 2022).  Powered by Deno's [std/crypto] module,\nwhich is baked into Web Assembly, it provides much wider range of hash\nalgorithms than Web Crypto API.\n\n[digest.ts]: https://doc.deno.land/https://deno.land/x/json_hash/digest.ts\n[BLAKE3]: https://github.com/BLAKE3-team/BLAKE3\n[std/crypto]: https://deno.land/std@0.120.0/crypto#supported-algorithms\n\n\n[*merkle.ts*][merkle.ts]: Dealing JSON with Merkle tree\n-------------------------------------------------------\n\nIf you need to track changes of large JSON trees this module could help you.\nIt provides `merkle()` function and `MerkleHash\u003cT\u003e` class which enables you to\nbuild [Merkle tree]s.\n\nUnlike `digest()` function from *digest.ts* module, `merkle()` function doesn't\ndigest the entire JSON data at once, but digests each small entity of the tree\nand digests them recursively.  For example:\n\n~~~ typescript\nimport { MerkleHash, merkle } from \"https://deno.land/x/json_hash/merkle.ts\";\nimport { assert } from \"https://deno.land/std/testing/asserts.ts\";\n\nconst a: MerkleHash\u003c\"BLAKE3\"\u003e = await merkle(\"BLAKE3\", [1, 2, 3]);\nconst b: MerkleHash\u003c\"BLAKE3\"\u003e = await merkle(\"BLAKE3\", [\n  await merkle(\"BLAKE3\", 1),\n  await merkle(\"BLAKE3\", 2),\n  await merkle(\"BLAKE3\", 3),\n]);\nassert(a.equals(b));\n\nconst c: MerkleHash\u003c\"BLAKE3\"\u003e = await merkle(\n  \"BLAKE3\",\n  { foo: \"bar\", baz: [1, 2, 3] }\n);\nconst d: MerkleHash\u003c\"BLAKE3\"\u003e = await merkle(\n  \"BLAKE3\",\n  { foo: await merkle(\"BLAKE3\", \"bar\"), baz: a }\n);\nassert(c.equals(d));\n\nconst e = await merkle(\"BLAKE3\", c);\nassert(e.equals(c));\n~~~\n\nNote that `merkle()` returns `MerkleHash\u003cT\u003e` (instead of `Uint8Array`),\nand also takes a JSON tree mixed with `MerkleHash\u003cT\u003e` values.  In this module,\nsuch mixed trees are called `MerkleTree\u003cT\u003e`.[^2]  The `merkle()` function\nbehaves like below:\n\n -  `merkle()` derives `MerkleHash\u003cT\u003e` from `MerkleTree\u003cT\u003e`.\n -  `merkle()` makes no distinction between a `MerkleTree\u003cT\u003e` and\n    `MerkleHash\u003cT\u003e` derived from the same tree.\n\nIn other words, the idea this module implements is very simple: hierarchical\nhash verification of JSON trees.  If you still don't get it well I recommend\nyou to read *[Diving into Merkle Trees]* by Pedro Tavares.\n\n[^2]: It is a compiled-time abstract type, and the type parameter `T` represents\n      the hash algorithm, which corresponds to `MerkleHash\u003cT\u003e`'s type parameter.\n\n[merkle.ts]: https://doc.deno.land/https://deno.land/x/json_hash/digest.ts\n[Merkle tree]: https://en.wikipedia.org/wiki/Merkle_tree\n[Diving into Merkle Trees]: https://ordep.dev/posts/diving-into-merkle-trees\n\n\n[*mod.ts*][Deno doc]: Façade\n----------------------------\n\nThis module re-exports everything in the above files.\n\nSee also [Deno Doc] for the complete API references.\n\n\nChangelog\n---------\n\nSee [CHANGES.md](CHANGES.md) file.\n\n\nLicense\n-------\n\nDistributed under [LGPL 3.0] or later.\n\n[LGPL 3.0]: https://www.gnu.org/licenses/lgpl-3.0.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdahlia%2Fjson-hash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdahlia%2Fjson-hash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdahlia%2Fjson-hash/lists"}