{"id":13830734,"url":"https://github.com/chjj/liburkel","last_synced_at":"2025-10-09T19:37:19.028Z","repository":{"id":54822300,"uuid":"289137111","full_name":"chjj/liburkel","owner":"chjj","description":"Authenticated key-value store (i.e. an urkel tree)","archived":false,"fork":false,"pushed_at":"2023-02-24T18:35:55.000Z","size":557,"stargazers_count":316,"open_issues_count":8,"forks_count":12,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-09T15:06:49.802Z","etag":null,"topics":["cryptography","database"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chjj.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2020-08-21T00:10:40.000Z","updated_at":"2024-12-11T01:06:35.000Z","dependencies_parsed_at":"2022-08-14T03:50:46.861Z","dependency_job_id":"e0c7790b-3636-4dbe-8dd7-580cad784c98","html_url":"https://github.com/chjj/liburkel","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chjj%2Fliburkel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chjj%2Fliburkel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chjj%2Fliburkel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chjj%2Fliburkel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chjj","download_url":"https://codeload.github.com/chjj/liburkel/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248055284,"owners_count":21040157,"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":["cryptography","database"],"created_at":"2024-08-04T10:01:06.955Z","updated_at":"2025-10-09T19:37:14.007Z","avatar_url":"https://github.com/chjj.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# Urkel\n\n![cmake](https://github.com/chjj/liburkel/workflows/cmake/badge.svg)\n\nAn optimized and cryptographically provable key-value store. Written in C.\n\n## Design\n\nThe urkel tree is implemented as a [base-2 merkelized radix tree][1]. It builds\non earlier research done by [Bram Cohen][2] and [Amaury Séchet][3] in order to\ncreate an alternative to [Ethereum's base-16 trie][4].\n\nNodes are stored in a series of append-only files for snapshotting and crash\nconsistency capabilities. Due to these presence of these features, Urkel has\nthe ability to expose a fully transactional database.\n\nUrkel is its _own_ database. This is in contrast to earlier authenticated data\nstructures which were typically implemented on top of an existing data store\nlike LevelDB.\n\nThe urkel tree is currently used in production for the [Handshake protocol][5].\n\n## Features\n\n- Transactions - Fully atomic and [transactional API][6].\n- Snapshots - Transactions can also behave as snapshots, pointing to a\n  historical root hash.\n- Iteration - Full tree iteration¹.\n- Compact Proofs - Small proof size, with proof nodes averaging ~34 bytes in\n  size.\n- History Independence - Deterministic root hash calculation regardless of\n  insertion/removal order.\n- Crash Consistency - `kill -9`'able.\n- Cross Platform - Runs on Windows XP and up, as well as any POSIX.1-2001\n  compatible OS.\n- WASM Support - Builds with both Emscripten as well as the WASI SDK.\n\n---\n\n1. Note that range iteration is not particularly useful for our use case.\n\n## Example Usage\n\n``` c\n#include \u003cassert.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003cstring.h\u003e\n#include \u003curkel.h\u003e\n\nint main(void) {\n  unsigned char key[32];\n  unsigned char val[4] = {0xde, 0xad, 0xbe, 0xef};\n  unsigned char key_out[32];\n  unsigned char val_out[1023]; /* Max size (currently). */\n  size_t val_len;\n  urkel_t *db;\n  urkel_tx_t *tx;\n\n  /* Open database. */\n  db = urkel_open(\"/path/to/db\");\n\n  assert(db != NULL);\n\n  /* Create transaction. */\n  tx = urkel_tx_create(db, NULL);\n\n  assert(tx != NULL);\n\n  /* Hash key. */\n  urkel_hash(key, \"my key\", 6);\n\n  /* Insert record. */\n  assert(urkel_tx_insert(tx, key, val, sizeof(val)));\n\n  /* Retrieve record. */\n  assert(urkel_tx_get(tx, val_out, \u0026val_len, key));\n  assert(val_len == sizeof(val));\n  assert(memcmp(val_out, val, val_len) == 0);\n\n  /* Commit transaction. */\n  assert(urkel_tx_commit(tx));\n\n  {\n    unsigned char root[32];\n    unsigned char *proof_raw;\n    size_t proof_len;\n    int exists;\n\n    /* Compute root. */\n    urkel_tx_root(tx, root);\n\n    /* Create proof. */\n    assert(urkel_tx_prove(tx, \u0026proof_raw, \u0026proof_len, key));\n\n    /* Verify proof. */\n    assert(urkel_verify(\u0026exists, val_out, \u0026val_len,\n                        proof_raw, proof_len, key, root));\n\n    /* Returns our value. */\n    assert(exists == 1);\n    assert(val_len == sizeof(val));\n    assert(memcmp(val_out, val, val_len) == 0);\n\n    urkel_free(proof_raw);\n  }\n\n  {\n    /* Create an iterator. */\n    urkel_iter_t *iter = urkel_iter_create(tx);\n    size_t i = 0;\n\n    assert(iter != NULL);\n\n    /* Iterate over our single record. */\n    while (urkel_iter_next(iter, key_out, val_out, \u0026val_len)) {\n      assert(memcmp(key_out, key, 32) == 0);\n      assert(val_len == sizeof(val));\n      assert(memcmp(val_out, val, val_len) == 0);\n      i += 1;\n    }\n\n    assert(urkel_errno == URKEL_EITEREND);\n    assert(i == 1);\n\n    urkel_iter_destroy(iter);\n  }\n\n  /* Cleanup. */\n  urkel_tx_destroy(tx);\n  urkel_close(db);\n\n  return 0;\n}\n```\n\nCompile with:\n\n``` sh\n$ cc -o example example.c -lurkel\n```\n\n## CLI Usage\n\nThe default build will provide you with an `urkel` executable. This allows\nvery simple manipulation of an urkel database from the command line.\n\n### Example\n\nData manipulation:\n\n``` sh\n$ urkel create\n$ urkel root\n0000000000000000000000000000000000000000000000000000000000000000\n$ urkel insert foo 'deadbeef' -H\n$ urkel root\n1da2776eaa254ef65aeeee1f37f61c06bac2e82e221d37da21190191218f6631\n$ urkel insert bar '01020304' -H\n$ urkel root\n497b751637ff244ab969a965f8d9dc7623f18d649d012276dfb317b0e38b9bec\n$ urkel get bar -H\n01020304\n$ urkel remove bar -H\n$ urkel root\n1da2776eaa254ef65aeeee1f37f61c06bac2e82e221d37da21190191218f6631\n$ urkel remove foo -H\n$ urkel root\n0000000000000000000000000000000000000000000000000000000000000000\n```\n\nCreating and verifying a proof:\n\n``` sh\n$ urkel root\n497b751637ff244ab969a965f8d9dc7623f18d649d012276dfb317b0e38b9bec\n$ urkel prove foo -H\n03c00100800280a6386fa1781a92e3905f718d4e0ea0d757abe962eefdd52a23d2ad6e1409fd8a0400deadbeef\n$ urkel verify foo -H \\\n  '03c00100800280a6386fa1781a92e3905f718d4e0ea0d757abe962eefdd52a23d2ad6e1409fd8a0400deadbeef' \\\n  --root '497b751637ff244ab969a965f8d9dc7623f18d649d012276dfb317b0e38b9bec'\ndeadbeef\n```\n\n### Usage\n\n```\n  Usage: urkel [options] [action] [args]\n\n  Actions:\n\n    create                create a new database\n    destroy               destroy database\n    info                  print database information\n    root                  print root hash\n    get \u003ckey\u003e             retrieve value\n    insert \u003ckey\u003e \u003cvalue\u003e  insert value\n    remove \u003ckey\u003e          remove value\n    list                  list all keys\n    prove \u003ckey\u003e           create proof\n    verify \u003ckey\u003e \u003cproof\u003e  verify proof (requires --root)\n\n  Options:\n\n    -p, --path \u003cpath\u003e     path to database (default: $URKEL_PATH)\n    -r, --root \u003chash\u003e     root hash to use for snapshots\n    -H, --hash            hash key with BLAKE2b-256\n    -h, --help            output usage information\n\n  Environment Variables:\n\n    URKEL_PATH            path to database (default: ./)\n```\n\n## Benchmarks\n\nBenchmarks were run on a high-end but consumer-grade laptop, containing a Intel\nCore i7-8550U 1.80GHz and an NVMe PCIe SSD.\n\n```\nBenchmarking insert...\n  Operations:  100000\n  Nanoseconds: 176354477\n  Seconds:     0.176354\n  Ops/Sec:     567039.758225\n  Sec/Op:      0.000002\nBenchmarking get (cached)...\n  Operations:  100000\n  Nanoseconds: 91769518\n  Seconds:     0.091770\n  Ops/Sec:     1089686.446866\n  Sec/Op:      0.000001\nBenchmarking commit...\n  Operations:  1\n  Nanoseconds: 121798848\n  Seconds:     0.121799\n  Ops/Sec:     8.210258\n  Sec/Op:      0.121799\nBenchmarking get (uncached)...\n  Operations:  100000\n  Nanoseconds: 300755918\n  Seconds:     0.300756\n  Ops/Sec:     332495.535466\n  Sec/Op:      0.000003\nBenchmarking remove...\n  Operations:  100000\n  Nanoseconds: 88950509\n  Seconds:     0.088951\n  Ops/Sec:     1124220.660727\n  Sec/Op:      0.000001\nBenchmarking commit...\n  Operations:  1\n  Nanoseconds: 30168275\n  Seconds:     0.030168\n  Ops/Sec:     33.147404\n  Sec/Op:      0.030168\nBenchmarking commit (nothing)...\n  Operations:  1\n  Nanoseconds: 24088\n  Seconds:     0.000024\n  Ops/Sec:     41514.447028\n  Sec/Op:      0.000024\nBenchmarking prove...\n  Operations:  100000\n  Nanoseconds: 327144781\n  Seconds:     0.327145\n  Ops/Sec:     305675.058286\n  Sec/Op:      0.000003\nBenchmarking verify...\n  Operations:  100000\n  Nanoseconds: 330230736\n  Seconds:     0.330231\n  Ops/Sec:     302818.572285\n  Sec/Op:      0.000003\n```\n\nPlatforms without memory-mapped file support will suffer in performance (this\nincludes Emscripten and WASI).\n\n## Contribution and License Agreement\n\nIf you contribute code to this project, you are implicitly allowing your code\nto be distributed under the MIT license. You are also implicitly verifying that\nall code is your original work. `\u003c/legalese\u003e`\n\n## License\n\n- Copyright (c) 2020, Christopher Jeffrey (MIT License).\n\nSee LICENSE for more info.\n\n[1]: https://github.com/chjj/liburkel/blob/master/doc/tree.md\n[2]: https://github.com/bramcohen/MerkleSet\n[3]: https://www.deadalnix.me/2016/09/24/introducing-merklix-tree-as-an-unordered-merkle-tree-on-steroid/\n[4]: https://eth.wiki/en/fundamentals/patricia-tree\n[5]: https://handshake.org\n[6]: https://github.com/chjj/liburkel/blob/master/doc/api.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchjj%2Fliburkel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchjj%2Fliburkel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchjj%2Fliburkel/lists"}