SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Hash Inconsistency between preset hases in ALLOWED_TREASURE_HASHES in circuit and `Prover.toml.example` settings

Root + Impact

Description

  • Hashes in circuit and in Prover.toml.exampleshould match so that each Treasure can be claimed.

  • Due to the hash mismatch, Treasure@index8 cannot be claimed.

// main.nr
global ALLOWED_TREASURE_HASHES: [Field; 10] = [
1505662313093145631275418581390771847921541863527840230091007112166041775502,
-7876059170207639417138377068663245559360606207000570753582208706879316183353,
-5602859741022561807370900516277986970516538128871954257532197637239594541050,
2256689276847399345359792277406644462014723416398290212952821205940959307205,
10311210168613568792124008431580767227982446451742366771285792060556636004770,
-5697637861416433807484703347699404695743570043365849280798663758395067508,
-2009295789879562882359281321158573810642695913475210803991480097462832104806,
8931814952839857299896840311953754931787080333405300398787637512717059406908,
-961435057317293580094826482786572873533235701183329831124091847635547871092, //Does not match Prover.toml.example
-961435057317293580094826482786572873533235701183329831124091847635547871092
];
// Prover.toml.example
treasure_hash = [
"1505662313093145631275418581390771847921541863527840230091007112166041775502",
"-7876059170207639417138377068663245559360606207000570753582208706879316183353",
"-5602859741022561807370900516277986970516538128871954257532197637239594541050",
"2256689276847399345359792277406644462014723416398290212952821205940959307205",
"10311210168613568792124008431580767227982446451742366771285792060556636004770",
"-5697637861416433807484703347699404695743570043365849280798663758395067508",
"-2009295789879562882359281321158573810642695913475210803991480097462832104806",
"8931814952839857299896840311953754931787080333405300398787637512717059406908",
"-4417726114039171734934559783368726413190541565291523767661452385022043124552", //Does not match the one in main.nr
"-961435057317293580094826482786572873533235701183329831124091847635547871092"
]

Risk

Likelihood:

  • Reason 1 : 1/10 chances

Impact:

  • Impact 1: Treasure@index8 cannot be claimed.

Proof of Concept

Whenever a participant discovers Treasure@index8, the reward cannot be claimed since the hash setting in Prover.toml does not match the setting in circuit.

Game starts...
ParticipantA discovers Treasure@index8 and compose a correct hash to claim the reward.
Claim fails since the hash setting in Prover.toml does not match the setting in circuit.

Recommended Mitigation

Replace the hash@index8 in circuit with the one in `Prover.toml.example`.

// file main.nr
global ALLOWED_TREASURE_HASHES: [Field; 10] = [
1505662313093145631275418581390771847921541863527840230091007112166041775502,
-7876059170207639417138377068663245559360606207000570753582208706879316183353,
-5602859741022561807370900516277986970516538128871954257532197637239594541050,
2256689276847399345359792277406644462014723416398290212952821205940959307205,
10311210168613568792124008431580767227982446451742366771285792060556636004770,
-5697637861416433807484703347699404695743570043365849280798663758395067508,
-2009295789879562882359281321158573810642695913475210803991480097462832104806,
8931814952839857299896840311953754931787080333405300398787637512717059406908,
- -961435057317293580094826482786572873533235701183329831124091847635547871092,
+ -4417726114039171734934559783368726413190541565291523767661452385022043124552,
-961435057317293580094826482786572873533235701183329831124091847635547871092
];
Updates

Lead Judging Commences

s3mvl4d Lead Judge 18 days ago
Submission Judgement Published
Validated
Assigned finding tags:

unclaimable treasure / bricked withdraw path

The issue stems from a mismatch between the circuit and the contract’s economic assumptions: the Solidity contract is configured for `MAX_TREASURES = 10` and only allows the owner to call `withdraw()` once `claimsCount >= MAX_TREASURES`, while the Noir circuit’s baked-in `ALLOWED_TREASURE_HASHES` array does not actually contain ten distinct treasures because one hash is duplicated and another expected hash is missing. As a result, under the intended one-claim-per-treasure design described in the README, there are only nine uniquely claimable treasures even though the system is funded and accounted as if ten rewards can be legitimately redeemed. That creates two linked consequences from the same root cause: first, one treasure is effectively unclaimable because no valid proof can ever be generated for the missing allowed hash, and second, the normal “hunt over” withdrawal path becomes bricked because honest participants can never reach ten legitimate unique claims, leaving the post-hunt fund recovery logic via `withdraw` function permanently unreachable. The owner can still intervene through the emergency path.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!