{"id":13768765,"url":"https://github.com/olehmisar/nodash","last_synced_at":"2025-05-10T23:31:50.426Z","repository":{"id":246413706,"uuid":"821057293","full_name":"olehmisar/nodash","owner":"olehmisar","description":"A Swiss knife for Noir","archived":false,"fork":false,"pushed_at":"2025-04-18T17:52:49.000Z","size":42,"stargazers_count":11,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-19T06:37:07.960Z","etag":null,"topics":["library","noir-lang","utility","zero-knowledge"],"latest_commit_sha":null,"homepage":"","language":"Noir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/olehmisar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2024-06-27T18:12:31.000Z","updated_at":"2025-04-18T17:52:52.000Z","dependencies_parsed_at":"2024-06-27T21:39:49.360Z","dependency_job_id":"d425322e-0c4a-4904-b1f1-11fd0dafaafc","html_url":"https://github.com/olehmisar/nodash","commit_stats":null,"previous_names":["olehmisar/nodash"],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olehmisar%2Fnodash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olehmisar%2Fnodash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olehmisar%2Fnodash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olehmisar%2Fnodash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/olehmisar","download_url":"https://codeload.github.com/olehmisar/nodash/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253497297,"owners_count":21917683,"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":["library","noir-lang","utility","zero-knowledge"],"created_at":"2024-08-03T16:01:25.531Z","updated_at":"2025-05-10T23:31:50.416Z","avatar_url":"https://github.com/olehmisar.png","language":"Noir","funding_links":[],"categories":["Libraries","Get Coding"],"sub_categories":["Data Type Manipulation","Libraries"],"readme":"# Nodash - Lodash for Noir\n\nNodash is a utility library for [Noir](https://github.com/noir-lang/noir) language.\n\n## Installation\n\nPut this into your Nargo.toml.\n\n```toml\nnodash = { git = \"https://github.com/olehmisar/nodash/\", tag = \"v0.41.2\" }\n```\n\n## Docs\n\n### `sqrt`\n\n```rs\nuse nodash::sqrt;\n\nassert(sqrt(4 as u64) == 2);\n\n// it floors the result\nassert(sqrt(8 as u64) == 2);\n```\n\n### `clamp`\n\n```rs\nuse nodash::clamp;\n\n// if too small, return min\nassert(clamp(1 as u64, 2 as u64, 3 as u64) == 2 as u64);\n// if too big, return max\nassert(clamp(4 as u64, 1 as u64, 3 as u64) == 3 as u64);\n// if in range, return value\nassert(clamp(2 as u64, 1 as u64, 3 as u64) == 2 as u64);\n```\n\n### `div_ceil`\n\nCalculates `a / b` rounded up to the nearest integer.\n\n```rs\nuse nodash::div_ceil;\n\nassert(div_ceil(10 as u64, 3) == 4);\n```\n\n### Hashes\n\nHash functions can either accept a `[T; N]` or a `BoundedVec\u003cT, N\u003e` (if technically possible).\n\n#### `poseidon2`\n\n```rs\nuse nodash::poseidon2;\n\n// hashes the whole array\nlet hash = poseidon2([10, 20]);\n// hashes elements up to the length (in this case, 2)\nlet hash = poseidon2(BoundedVec::from_parts([10, 20, 0], 2));\n```\n\n#### `pedersen`\n\n```rs\nuse nodash::pedersen;\n\nlet hash = pedersen([10, 20]);\n```\n\n#### `sha256`\n\nsha256 is expensive to compute in Noir, so use [poseidon2](#poseidon2) where possible.\n\n```rs\nuse nodash::sha256;\n\nlet hash = sha256([10, 20]);\n// or\nlet hash = sha256(BoundedVec::from_parts([10, 20, 0], 2));\n```\n\n#### `keccak256`\n\nkeccak256 is expensive to compute in Noir, so use [poseidon2](#poseidon2) where possible.\n\n```rs\nuse nodash::keccak256;\n\nlet hash = keccak256([10, 20]);\n// or\nlet hash = keccak256(BoundedVec::from_parts([10, 20, 0], 2));\n```\n\n### `solidity::encode_with_selector`\n\nEquivalent to `abi.encodeWithSelector` in Solidity.\n\n```rs\nuse nodash::solidity::encode_with_selector;\n\nlet selector: u32 = 0xa9059cbb; // transfer(address,uint256)\nlet args: [Field; 2] = [\n  0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045, // address\n  123 // uint256\n];\nlet encoded = encode_with_selector(selector, args);\n// typeof encoded: [u8; 68]\n```\n\n### `field_to_hex`\n\nConverts a `Field` to a hex string (without `0x` prefix).\n\n```rs\nlet my_hash = 0x0d67824fead966192029093a3aa5c719f2b80262c4f14a5c97c5d70e4b27f2bf;\nlet expected = \"0d67824fead966192029093a3aa5c719f2b80262c4f14a5c97c5d70e4b27f2bf\";\nassert_eq(field_to_hex(my_hash), expected);\n```\n\n### `str_to_u64`\n\nConverts a string to a `u64`.\n\n```rs\nuse nodash::str_to_u64;\n\nassert(str_to_u64(\"02345678912345678912\") == 02345678912345678912);\n```\n\n### `try_from`\n\nFail-able conversion.\n\n```rs\nuse nodash::TryFrom;\n\nassert(u8::try_from(123) == 123);\nu8::try_from(256); // runtime error\n\nassert(u128::try_from(123) == 123);\n```\n\n### `ord`\n\nReturns the ASCII code of a single character.\n\n```rs\nuse nodash::ord;\n\nassert(ord(\"a\") == 97);\n```\n\n### `ArrayExtensions`\n\n#### `slice\u003cL\u003e(start: u32) -\u003e [T; L]`\n\nReturns a slice of the array, starting at `start` and ending at `start + L`. Panics if `start + L` is out of bounds.\n\n```rs\nuse nodash::ArrayExtensions;\n\nassert([1, 2, 3, 4, 5].slice::\u003c3\u003e(1) == [2, 3, 4]);\n```\n\n#### `pad_start`\n\nPads the start of the array with a value.\n\n```rs\nuse nodash::ArrayExtensions;\n\nassert([1, 2, 3].pad_start::\u003c5\u003e(0) == [0, 0, 1, 2, 3]);\n```\n\n#### `pad_end`\n\nPads the end of the array with a value.\n\n```rs\nuse nodash::ArrayExtensions;\n\nassert([1, 2, 3].pad_end::\u003c5\u003e(0) == [1, 2, 3, 0, 0]);\n```\n\n#### `enumerate`\n\nReturns an array of tuples, where each tuple contains the index and the value of the array element.\n\n```rs\nuse nodash::ArrayExtensions;\n\nassert([\"a\", \"b\", \"c\"].enumerate() == [(0, \"a\"), (1, \"b\"), (2, \"c\")]);\n```\n\n### `pack_bytes`\n\nPacks `[u8; N]` into `[Field; N / 31 + 1]`. Useful, if you need to get a hash over bytes. I.e., `pedersen_hash(pack_bytes(bytes))` will be MUCH cheaper than `pedersen_hash(bytes)`.\n\n```rs\nuse nodash::pack_bytes;\n\nlet bytes: [u8; 32] = [0; 32];\nlet packed = pack_bytes(bytes);\n```\n\n### Validate `main` function inputs\n\n`fn main` inputs are not validated by Noir. For example, you have a `U120` struct like this:\n\n```rs\nstruct U120 {\n    inner: Field,\n}\n\nimpl U120 {\n    fn new(inner: Field) -\u003e Self {\n        inner.assert_max_bit_size::\u003c120\u003e();\n        Self { inner }\n    }\n}\n```\n\nYou then can create instances of `U120` with `U120::new(123)`. If you pass a value that is larger than 2^120 to `U120::new`, you will get a runtime error because we assert the max bit size of `Field` in `U120::new`.\n\nHowever, Noir does not check the validity of `U120` fields when passed to a `fn main` function. For example, for this circuit\n\n```rs\nfn main(a: U120) {\n    // do something with a\n}\n```\n\n...you can pass any arbitrary value to `a` from JavaScript and it will NOT fail in Noir when `main` is executed:\n\n```js\n// this succeeds but it shouldn't!\nawait noir.execute({\n  a: {\n    inner: 2n ** 120n + 1n,\n  },\n});\n```\n\nTo fix this, you can use the `validate_inputs` attribute on the `main` function:\n\n```rs\nuse nodash::{validate_inputs, ValidateInput};\n\n// this attribute checks that `U120` is within the range via `ValidateInput` trait\n#[validate_inputs]\nfn main(a: U120) {\n    // do something with a\n}\n\nimpl ValidateInput for U120 {\n    fn validate(self) {\n        // call the `new` function that asserts the max bit size\n        U120::new(self.inner);\n    }\n}\n```\n\nNow, if you pass a value that is larger than 2^120 to `a` in JavaScript, you will get a runtime error:\n\n```js\n// runtime error: \"Assertion failed: call to assert_max_bit_size\"\nawait noir.execute({\n  a: {\n    inner: 2n ** 120n + 1n,\n  },\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folehmisar%2Fnodash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Folehmisar%2Fnodash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folehmisar%2Fnodash/lists"}