SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
Submission Details
Impact: high
Likelihood: high

Circuit omits one valid treasure hash and duplicates another, making one treasure impossible to claim

Author Revealed upon completion

Root + Impact

Description

  • The circuit is expected to support 10 unique treasure hashes, but ALLOWED_TREASURE_HASHES duplicates the hash for treasure 10 and omits the hash for treasure 9.

  • As a result, one legitimate treasure can never be proven or claimed.

global ALLOWED_TREASURE_HASHES: [Field; 10] = [
1505662313093145631275418581390771847921541863527840230091007112166041775502,
-7876059170207639417138377068663245559360606207000570753582208706879316183353,
-5602859741022561807370900516277986970516538128871954257532197637239594541050,
2256689276847399345359792277406644462014723416398290212952821205940959307205,
10311210168613568792124008431580767227982446451742366771285792060556636004770,
-5697637861416433807484703347699404695743570043365849280798663758395067508,
-2009295789879562882359281321158573810642695913475210803991480097462832104806,
8931814952839857299896840311953754931787080333405300398787637512717059406908,
-961435057317293580094826482786572873533235701183329831124091847635547871092,
-961435057317293580094826482786572873533235701183329831124091847635547871092
];

Risk

Likelihood:

  • This occurs deterministically for every deployment using the current circuit.

  • The hash for treasure 9 is not included in the allowed set, so a legitimate finder of treasure 9 cannot generate a proof accepted by the verifier.

Impact:

  • One of the 10 advertised treasures is permanently unclaimable.

  • This breaks the core protocol promise that all valid treasures can be claimed, and can also prevent the hunt from honestly reaching MAX_TREASURES = 10, leaving post-hunt withdrawal dependent on invalid or duplicate claims.

Proof of Concept

The PoC shows that the protocol’s expected treasure 9 hash is present in the deployment script and prover fixture source, but missing from the actual circuit allowlist. Since the verifier is generated from the circuit, any proof for treasure 9 will fail and that reward cannot be claimed by a legitimate participant.

The deployment script and prover fixture list include the expected hash for treasure 9:
// -4417726114039171734934559783368726413190541565291523767661452385022043124552
However, the circuit does not include that hash. Instead, it repeats the hash for treasure 10 twice:
-961435057317293580094826482786572873533235701183329831124091847635547871092,
-961435057317293580094826482786572873533235701183329831124091847635547871092
This can also be seen in the circuit test, which tests treasure 10 twice and skips treasure 9:
let treasures: [Field; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 10, 10];
A legitimate proof for treasure 9 would use:
treasure = 9;
treasure_hash = -4417726114039171734934559783368726413190541565291523767661452385022043124552;
But is_allowed(treasure_hash) returns false because the hash is absent from ALLOWED_TREASURE_HASHES, causing the circuit to reject:
assert(is_allowed(treasure_hash));

Recommended Mitigation

Replace the duplicated treasure 10 hash with the missing treasure 9 hash.

Also update the circuit tests to cover all 10 unique treasures:

- -961435057317293580094826482786572873533235701183329831124091847635547871092,
+ -4417726114039171734934559783368726413190541565291523767661452385022043124552,
-961435057317293580094826482786572873533235701183329831124091847635547871092
- let treasures: [Field; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 10, 10];
+ let treasures: [Field; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

Support

FAQs

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

Give us feedback!