-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add HashMap to the stdlib #4242
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a very good hashmap implementation, thank you!
My main note that is not mentioned in my comments was that I think it may be too early to introduce a Map
trait - I don't think there is need for one now when there is only one map type. Rust for example gets by without a similar trait despite having two map types so I think we can avoid the extra complexity for now.
Thank you for the feedback @jfecher! I will try to apply your notes and advises as soon as I can. |
noir_stdlib/src/collections/map.nr
Outdated
} | ||
|
||
// Get the value by key. If it does not exist, returns none(). | ||
pub fn get(self, key: K) -> Option<V> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Howdy. This is a really nice piece of work! I have some suggestions to how the performance of map
can be improved, but please don't take this as criticism; I'm very impressed with the quality of this PR.
From what I can understand, the get
method is linear-time in the size of N
due to the for
loop.
It is possible to create a map abstraction where accessing the map can be done in a constant number of constraints regardless of N
, by using a doubly-linked-list data structure.
The idea is to store the map key/values in a size-N linked list, where the list is sorted by key value (assuming the key is a field element, or is hashed into a field element).
When get
-ing a value via its key, a simple array lookup suffices if the key is present. If the key is not present, it is possible to prove that the requested key value lies between two adjacent nodes in the linked list.
A rough proof of concept is at https://gist.github.com/zac-williamson/4bee81b912471395b4e3c9b6029bad81 . It requires noir version 0.23 and is quite inefficient because of a bug in the noir compiler (#4244)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @zac-williamson, both approaches in Noir would have trade-offs. Quadratic (and linear) probing hashmaps typically rely on being mostly empty (typically >50%) so that their search is not linear. When this is true, it is more likely an elements first hash will lead to an empty spot and we still have amortized constant time. The lack of break
in Noir however means even after finding a spot we'd still be looping doing nothing. Moreover, Noir cannot dynamically resize hashmaps like other languages so we also will most likely need to panic when the map starts to become filled over a certain percentage.
For the approach of using a list for each bucket, we can emulate list with a BoundedVec
as long as we choose a maximum size for buckets, which we'll need anyway since we cannot reallocate and Noir similarly doesn't support linked lists directly. So our overall map will resemble HashMap<K, V, Len, BucketLen>
. Similar to the quadratic probing approach, we'll need to panic when the map becomes filled, but this time we'll only need to panic if the item count exceeds Len
or if the items in one bucket exceeds BucketLen
. One issue with this method is that since the overall hashmap size is separate from the bucket size, it is less clear to users how much data they can actually put in this fixed-size hashmap since it now depends on how many hash collisions there are. E.g. if the map has a fixed size of 100 and a bucket size of just 2, we can still panic (assert(false)
) if just 3 elements are inserted which happen to have the same hash (modulo 100). I think this can make the map less reliable in comparison.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow what you're saying @jfecher . It's possible to implement linked lists in Noir with constant-time access (see the gist I linked), which means the overall map does not resemble HashMap as the access time is fixed regardless of the maximum size of the map or the number of filled elements.
Building a linked list out of arrays and using the linked list to implement a map will almost always be faster than iterating over the map in linear time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow what you wrote about collisions @jfecher . I was assuming we use a cryptographic hash function with collision resistance; we can assume there won't be any collisions unless the key is identical (which can be explicitly handled). Is that not your understanding as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zac-williamson sorry for deleting my last comment - I hadn't intended for you to reply yet. I realized I needed to stop and look at your example in more detail when I saw it used unconstrained functions and looped over the current length of the map.
With regard to a cryptographic hash function, there will always be collisions in a hash map because a hash map will take a hash and perform hash % self.capacity
(to figure out which slot to insert the item into) which will lead to more collisions as the map fills regardless of the hash method used (although cryptographic hashes are still an improvement).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @zac-williamson, both approaches in Noir would have trade-offs. Quadratic (and linear) probing hashmaps typically rely on being mostly empty (typically >50%) so that their search is not linear. When this is true, it is more likely an elements first hash will lead to an empty spot and we still have amortized constant time. The lack of
break
in Noir however means even after finding a spot we'd still be looping doing nothing. Moreover, Noir cannot dynamically resize hashmaps like other languages so we also will most likely need to panic when the map starts to become filled over a certain percentage.For the approach of using a list for each bucket, we can emulate list with a
BoundedVec
as long as we choose a maximum size for buckets, which we'll need anyway since we cannot reallocate and Noir similarly doesn't support linked lists directly. So our overall map will resembleHashMap<K, V, Len, BucketLen>
. Similar to the quadratic probing approach, we'll need to panic when the map becomes filled, but this time we'll only need to panic if the item count exceedsLen
or if the items in one bucket exceedsBucketLen
. One issue with this method is that since the overall hashmap size is separate from the bucket size, it is less clear to users how much data they can actually put in this fixed-size hashmap since it now depends on how many hash collisions there are. E.g. if the map has a fixed size of 100 and a bucket size of just 2, we can still panic (assert(false)
) if just 3 elements are inserted which happen to have the same hash (modulo 100). I think this can make the map less reliable in comparison.
I think the confusion here is perhaps my misuse of the term hashmap. The object I implemented merely emulates the behaviour of a hashmap.
I don’t derive a position in the map by taking hash % array size.
instead, each hash is linked to a specific array element.
access is still O(N) but only in the unconstrained function. The part that needs to be constrained is O(1)
I wonder if we can take inspiration from @zac-williamson's proof of concept and have an unconstrained method return the final index of the key. Then in constrained code we can assert that it is correct and perform the get/insert. |
Hi guys, sorry for the delay, apparently I've got a virus. Applied new @jfecher 's review notes, fixed incorrect call from Note: I did |
It is indeed an interesting concept and shall be investigated further; now we have high-coupling reasoned by sequential execution in Noir, which complexifies (or makes question necessity of such) splitting index computation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
As @zac-williamson there is room for improvement performance-wise in the future, but as long as we don't guarantee a particular implementation in Noir we should be free to swap out the internals later. I think this is a good base for now though. I'll add some more Hash impls and documentation in a separate PR.
Looks like you have a test failure in CI:
|
Head branch was pushed to by a user without write access
Thanks for the fix, I just realized that is a new bug in master. |
Head branch was pushed to by a user without write access
Rebased with regard to current master and applied small code style fix (unused |
Hi guys, as I see this PR cannot be auto-merged due to Two in impl<K, V, N, B, H> HashMap<K, V, N, B> {
...
// Get the compile-time map capacity.
pub fn capacity(self) -> u64 {
N
}
...
// Probing scheme: quadratic function.
// We use 0.5 constant near variadic attempt and attempt^2 monomials.
// This ensures good uniformity of distribution for table sizes
// equal to prime numbers or powers of two.
fn quadratic_probe(self, hash: u64, attempt: u64) -> u64 {
(hash + (attempt + attempt * attempt) / 2) % N
}
... And one in trait BuildHasher<H> where H: Hasher{
fn build_hasher(self) -> H;
}
struct BuildHasherDefault<H>;
impl<H> BuildHasher<H> for BuildHasherDefault<H>
where
H: Hasher + Default
{
fn build_hasher(self) -> H{
H::default()
}
} Vindication to the former is that it is required to know generic Ergo I see several options on what could be done here:
What option do you think we can go along with, in order to deliver this PR's functionality? |
@NikitaMasych you can also rename |
Head branch was pushed to by a user without write access
Thank you for advice! I hoped there is something like that. |
It would be valuable if added to https://noir-lang.org/docs |
@noir-lang/developerrelations commenting to log this issue for later |
@jfecher it looks like now there are no problems with tests failing, including due to warnings - can you set auto-merge this PR or you need to put it on hold? |
@NikitaMasych queued to merge now 🙂 |
* master: (39 commits) chore: remove unwanted prints (#4419) fix: remove print from monomorphization pass (#4417) chore(ssa): Remove mem2reg run before flattening (#4415) feat: Add HashMap to the stdlib (#4242) fix!: Ban Fields in for loop indices and bitwise ops (#4376) chore: Add #[recursive] Explainer to Documentation (#4399) feat(ci): Use wasm-opt when compiling wasm packages (#4334) fix: add handling to `noir_wasm` for projects without dependencies (#4344) chore: rename parameter 'filter' to 'level' in 'init_log_level' (#4403) chore!: bump msrv to 1.73.0 (#4406) chore: fix docker test workflows (#4308) chore: Update Vec docs (#4400) feat: update error message when trying to load workspace as dependency (#4393) chore: bump webpack dependencies (#4346) fix: correct invalid brillig codegen for `EmbeddedCurvePoint.add` (#4382) chore: remove dependency on generational-arena (#4207) fix(docs): update install versions (#4396) fix: Enforce matching types of binary ops in SSA (#4391) fix(docs): Update noirjs_app for 0.23 (#4378) chore(ci): add alerts for failed publishes (#4388) ...
* master: chore(ci): prevent msrv checks from blocking PRs (#4414) feat: expose separate functions to compile programs vs contracts in `noir_wasm` (#4413) chore: do not panic when dividing by zero (#4424) chore: remove unwanted prints (#4419) fix: remove print from monomorphization pass (#4417) chore(ssa): Remove mem2reg run before flattening (#4415) feat: Add HashMap to the stdlib (#4242)
* master: (440 commits) chore: remove duplicate `parse_all` function in wasm compiler (#4411) chore(ci): prevent msrv checks from blocking PRs (#4414) feat: expose separate functions to compile programs vs contracts in `noir_wasm` (#4413) chore: do not panic when dividing by zero (#4424) chore: remove unwanted prints (#4419) fix: remove print from monomorphization pass (#4417) chore(ssa): Remove mem2reg run before flattening (#4415) feat: Add HashMap to the stdlib (#4242) fix!: Ban Fields in for loop indices and bitwise ops (#4376) chore: Add #[recursive] Explainer to Documentation (#4399) feat(ci): Use wasm-opt when compiling wasm packages (#4334) fix: add handling to `noir_wasm` for projects without dependencies (#4344) chore: rename parameter 'filter' to 'level' in 'init_log_level' (#4403) chore!: bump msrv to 1.73.0 (#4406) chore: fix docker test workflows (#4308) chore: Update Vec docs (#4400) feat: update error message when trying to load workspace as dependency (#4393) chore: bump webpack dependencies (#4346) fix: correct invalid brillig codegen for `EmbeddedCurvePoint.add` (#4382) chore: remove dependency on generational-arena (#4207) ...
* master: (45 commits) chore(docs): correct 'Edit this page' URL for dev docs (#4433) feat: Sync from aztec-packages (#4390) chore(docs): fix external contributor force push workflow (#4437) chore!: Remove empty value from bounded vec (#4431) chore: nargo fmt (#4434) feat: add poseidon2 opcode implementation for acvm/brillig, and Noir (#4398) fix: remove panic when generic array length is not resolvable (#4408) chore(ci): enforce formatting of noir code in CI (#4422) fix: correct formatting for databus visibility types (#4423) chore: remove duplicate `parse_all` function in wasm compiler (#4411) chore(ci): prevent msrv checks from blocking PRs (#4414) feat: expose separate functions to compile programs vs contracts in `noir_wasm` (#4413) chore: do not panic when dividing by zero (#4424) chore: remove unwanted prints (#4419) fix: remove print from monomorphization pass (#4417) chore(ssa): Remove mem2reg run before flattening (#4415) feat: Add HashMap to the stdlib (#4242) fix!: Ban Fields in for loop indices and bitwise ops (#4376) chore: Add #[recursive] Explainer to Documentation (#4399) feat(ci): Use wasm-opt when compiling wasm packages (#4334) ...
* master: (46 commits) feat: Sync from aztec-packages (#4438) chore(docs): correct 'Edit this page' URL for dev docs (#4433) feat: Sync from aztec-packages (#4390) chore(docs): fix external contributor force push workflow (#4437) chore!: Remove empty value from bounded vec (#4431) chore: nargo fmt (#4434) feat: add poseidon2 opcode implementation for acvm/brillig, and Noir (#4398) fix: remove panic when generic array length is not resolvable (#4408) chore(ci): enforce formatting of noir code in CI (#4422) fix: correct formatting for databus visibility types (#4423) chore: remove duplicate `parse_all` function in wasm compiler (#4411) chore(ci): prevent msrv checks from blocking PRs (#4414) feat: expose separate functions to compile programs vs contracts in `noir_wasm` (#4413) chore: do not panic when dividing by zero (#4424) chore: remove unwanted prints (#4419) fix: remove print from monomorphization pass (#4417) chore(ssa): Remove mem2reg run before flattening (#4415) feat: Add HashMap to the stdlib (#4242) fix!: Ban Fields in for loop indices and bitwise ops (#4376) chore: Add #[recursive] Explainer to Documentation (#4399) ...
# Description ## Problem\* ## Summary\* Adds docs for #4242 I've also edited the interface for `entries`, `keys`, and `values` to return `BoundedVec`s instead of arrays with optional elements. This is much more natural I think. I originally intended this for a separate PR, but I didn't want to write documentation for the old version of these functions only to immediately have to edit them afterward. ## Additional Context ## Documentation\* Check one: - [ ] No documentation needed. - [x] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --------- Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
🤖 I have created a release *beep* *boop* --- <details><summary>0.25.0</summary> ## [0.25.0](v0.24.0...v0.25.0) (2024-03-11) ### ⚠ BREAKING CHANGES * Internal as a macro (AztecProtocol/aztec-packages#4898) * reserve `unchecked` keyword ([#4432](#4432)) * Remove empty value from bounded vec ([#4431](#4431)) * Ban Fields in for loop indices and bitwise ops ([#4376](#4376)) * bump msrv to 1.73.0 ([#4406](#4406)) * **ci:** Bump MSRV to 1.72.1 and enforce that ACVM can be published using updated lockfile ([#4385](#4385)) * Restrict bit sizes ([#4235](#4235)) * move noir out of yarn-project (AztecProtocol/aztec-packages#4479) * note type ids (AztecProtocol/aztec-packages#4500) ### Features * Add eddsa_poseidon_to_pub function to stdlib with test + docs ([#4473](#4473)) ([00d2c32](00d2c32)) * Add HashMap to the stdlib ([#4242](#4242)) ([650ffc5](650ffc5)) * Add option to set max memory for bb.js ([#4227](#4227)) ([8a6b131](8a6b131)) * Add overflow and underflow checks for unsigned integers in brillig ([#4445](#4445)) ([21fc4b8](21fc4b8)) * Add poseidon2 opcode implementation for acvm/brillig, and Noir ([#4398](#4398)) ([10e8292](10e8292)) * Added cast opcode and cast calldata (AztecProtocol/aztec-packages#4423) ([78ef013](78ef013)) * Allow type aliases to reference other aliases ([#4353](#4353)) ([c44ef14](c44ef14)) * Backpropagate constants in ACIR during optimization ([#3926](#3926)) ([aad0da0](aad0da0)) * **ci:** Use wasm-opt when compiling wasm packages ([#4334](#4334)) ([e382921](e382921)) * DAP Preflight and debugger compilation options ([#4185](#4185)) ([e0ad0b2](e0ad0b2)) * Expose separate functions to compile programs vs contracts in `noir_wasm` ([#4413](#4413)) ([7cd5fdb](7cd5fdb)) * Internal as a macro (AztecProtocol/aztec-packages#4898) ([5f57ebb](5f57ebb)) * Note type ids (AztecProtocol/aztec-packages#4500) ([78ef013](78ef013)) * Restrict bit sizes ([#4235](#4235)) ([1048f81](1048f81)) * Run tests in parallel in `nargo test` ([#4484](#4484)) ([761734e](761734e)) * Skip redundant range checks in brillig ([#4460](#4460)) ([cb4c1c5](cb4c1c5)) * Sync from aztec-packages ([#4483](#4483)) ([fe8f277](fe8f277)) * Track stack frames and their variables in the debugger ([#4188](#4188)) ([ae1a9d9](ae1a9d9)) * TypeVariableKind for just Integers ([#4118](#4118)) ([c956be8](c956be8)) * Update error message when trying to load workspace as dependency ([#4393](#4393)) ([d2585e7](d2585e7)) ### Bug Fixes * **acir:** Array dynamic flatten ([#4351](#4351)) ([b2aaeab](b2aaeab)) * **acir:** Use types on dynamic arrays ([#4364](#4364)) ([ba2c541](ba2c541)) * Add `follow_bindings` to follow `Type::Alias` links ([#4521](#4521)) ([b94adb9](b94adb9)) * Add handling to `noir_wasm` for projects without dependencies ([#4344](#4344)) ([4982251](4982251)) * Allow type aliases in main ([#4505](#4505)) ([8a5359c](8a5359c)) * Ban Fields in for loop indices and bitwise ops ([#4376](#4376)) ([601fd9a](601fd9a)) * Brillig range check with consistent bit size ([#4357](#4357)) ([ea47d4a](ea47d4a)) * Build noir_codegen when publishing ([#4448](#4448)) ([cb1ceee](cb1ceee)) * Consistent bit size for truncate ([#4370](#4370)) ([dcd7a1e](dcd7a1e)) * Correct formatting for databus visibility types ([#4423](#4423)) ([cd796de](cd796de)) * Correct invalid brillig codegen for `EmbeddedCurvePoint.add` ([#4382](#4382)) ([5051ec4](5051ec4)) * **docs:** Update install versions ([#4396](#4396)) ([b283637](b283637)) * **docs:** Update noirjs_app for 0.23 ([#4378](#4378)) ([f77f702](f77f702)) * Enforce matching types of binary ops in SSA ([#4391](#4391)) ([70866ae](70866ae)) * Fix brillig slowdown when assigning arrays in loops ([#4472](#4472)) ([2a53545](2a53545)) * **flake:** Stop flake.nix removing ignored-tests.txt ([#4455](#4455)) ([ebaf05a](ebaf05a)) * Force src impl for == on slices ([#4507](#4507)) ([1691274](1691274)) * Handling of gh deps in noir_wasm ([#4499](#4499)) ([1d65370](1d65370)) * Iterative flattening pass ([#4492](#4492)) ([33c1ef7](33c1ef7)) * Noir test incorrect reporting (AztecProtocol/aztec-packages#4925) ([5f57ebb](5f57ebb)) * Only add `.nr` files to file manager ([#4380](#4380)) ([8536c7c](8536c7c)) * Remove panic when generic array length is not resolvable ([#4408](#4408)) ([00ab3db](00ab3db)) * Remove print from monomorphization pass ([#4417](#4417)) ([27c66b3](27c66b3)) * **ssa:** Handle mergers of slices returned from calls ([#4496](#4496)) ([f988d02](f988d02)) * Use correct type for numeric generics ([#4386](#4386)) ([0a1d109](0a1d109)) * Variables from trait constraints being permanently bound over when used within a trait impl ([#4450](#4450)) ([ac60ef5](ac60ef5)) ### Miscellaneous Chores * Bump msrv to 1.73.0 ([#4406](#4406)) ([b5e5c30](b5e5c30)) * **ci:** Bump MSRV to 1.72.1 and enforce that ACVM can be published using updated lockfile ([#4385](#4385)) ([2fc95d2](2fc95d2)) * Move noir out of yarn-project (AztecProtocol/aztec-packages#4479) ([78ef013](78ef013)) * Remove empty value from bounded vec ([#4431](#4431)) ([b9384fb](b9384fb)) * Reserve `unchecked` keyword ([#4432](#4432)) ([9544813](9544813)) </details> <details><summary>0.41.0</summary> ## [0.41.0](v0.40.0...v0.41.0) (2024-03-11) ### ⚠ BREAKING CHANGES * Internal as a macro (AztecProtocol/aztec-packages#4898) * move noir out of yarn-project (AztecProtocol/aztec-packages#4479) * note type ids (AztecProtocol/aztec-packages#4500) * rename bigint_neg into bigint_sub (AztecProtocol/aztec-packages#4420) * Add expression width into acir (AztecProtocol/aztec-packages#4014) * init storage macro (AztecProtocol/aztec-packages#4200) * **acir:** Move `is_recursive` flag to be part of the circuit definition (AztecProtocol/aztec-packages#4221) * Sync commits from `aztec-packages` ([#4144](#4144)) * Breaking changes from aztec-packages ([#3955](#3955)) * Rename Arithmetic opcode to AssertZero ([#3840](#3840)) * Remove unused methods on ACIR opcodes ([#3841](#3841)) * Remove partial backend feature ([#3805](#3805)) ### Features * Add bit size to const opcode (AztecProtocol/aztec-packages#4385) ([158c8ce](158c8ce)) * Add expression width into acir (AztecProtocol/aztec-packages#4014) ([158c8ce](158c8ce)) * Add instrumentation for tracking variables in debugging ([#4122](#4122)) ([c58d691](c58d691)) * Add poseidon2 opcode implementation for acvm/brillig, and Noir ([#4398](#4398)) ([10e8292](10e8292)) * Add support for overriding expression width ([#4117](#4117)) ([c8026d5](c8026d5)) * Added cast opcode and cast calldata (AztecProtocol/aztec-packages#4423) ([78ef013](78ef013)) * Allow brillig to read arrays directly from memory (AztecProtocol/aztec-packages#4460) ([158c8ce](158c8ce)) * Allow nested arrays and vectors in Brillig foreign calls (AztecProtocol/aztec-packages#4478) ([158c8ce](158c8ce)) * Allow variables and stack trace inspection in the debugger ([#4184](#4184)) ([bf263fc](bf263fc)) * **avm:** Back in avm context with macro - refactor context (AztecProtocol/aztec-packages#4438) ([158c8ce](158c8ce)) * **aztec-nr:** Initial work for aztec public vm macro (AztecProtocol/aztec-packages#4400) ([158c8ce](158c8ce)) * Aztec-packages ([#3754](#3754)) ([c043265](c043265)) * Backpropagate constants in ACIR during optimization ([#3926](#3926)) ([aad0da0](aad0da0)) * Breaking changes from aztec-packages ([#3955](#3955)) ([5be049e](5be049e)) * Evaluation of dynamic assert messages ([#4101](#4101)) ([c284e01](c284e01)) * Init storage macro (AztecProtocol/aztec-packages#4200) ([158c8ce](158c8ce)) * Internal as a macro (AztecProtocol/aztec-packages#4898) ([5f57ebb](5f57ebb)) * Note type ids (AztecProtocol/aztec-packages#4500) ([78ef013](78ef013)) * Remove range constraints from witnesses which are constrained to be constants ([#3928](#3928)) ([afe9c7a](afe9c7a)) * Remove replacement of boolean range opcodes with `AssertZero` opcodes ([#4107](#4107)) ([dac0e87](dac0e87)) * Speed up transformation of debug messages ([#3815](#3815)) ([2a8af1e](2a8af1e)) * Sync `aztec-packages` ([#4011](#4011)) ([fee2452](fee2452)) * Sync commits from `aztec-packages` ([#4068](#4068)) ([7a8f3a3](7a8f3a3)) * Sync commits from `aztec-packages` ([#4144](#4144)) ([0205d3b](0205d3b)) * Sync from aztec-packages ([#4483](#4483)) ([fe8f277](fe8f277)) ### Bug Fixes * Deserialize odd length hex literals ([#3747](#3747)) ([4000fb2](4000fb2)) * Noir test incorrect reporting (AztecProtocol/aztec-packages#4925) ([5f57ebb](5f57ebb)) * Remove panic from `init_log_level` in `acvm_js` ([#4195](#4195)) ([2e26530](2e26530)) * Return error rather instead of panicking on invalid circuit ([#3976](#3976)) ([67201bf](67201bf)) ### Miscellaneous Chores * **acir:** Move `is_recursive` flag to be part of the circuit definition (AztecProtocol/aztec-packages#4221) ([158c8ce](158c8ce)) * Move noir out of yarn-project (AztecProtocol/aztec-packages#4479) ([78ef013](78ef013)) * Remove partial backend feature ([#3805](#3805)) ([0383100](0383100)) * Remove unused methods on ACIR opcodes ([#3841](#3841)) ([9e5d0e8](9e5d0e8)) * Rename Arithmetic opcode to AssertZero ([#3840](#3840)) ([836f171](836f171)) * Rename bigint_neg into bigint_sub (AztecProtocol/aztec-packages#4420) ([158c8ce](158c8ce)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: Savio <72797635+Savio-Sou@users.noreply.github.com>
Description
This PR shall bring HashMap into the
stdlib
of Noir.Problem*
Resolves #4241
Summary*
Implementation of
HashMap
with open addressing and quadratic probing scheme. Since Noir requires knowing loop bounds (and recursive calls) at compile time,HashMap
is of fixed capacity and no dynamic resize is accomplished with regard to load factor.Furthermore, contribution includes implementation of
PedersenHasher
to be used for now. One can examine potentially better and less heavy prehash functions.I tried to conform with best practices of engineering, however since Noir is in rapid development, there are certain things which may be optimized in future, both from the code style and performance point of view.
Additional Context
I put the
PedersenHasher
among theposeidon.nr
andmimc.nr
, so one can consider moving declaration of other pedersen-related functionality there, however that would be a breaking change.Documentation*
Check one:
PR Checklist*
cargo fmt
on default settings.