Skip to content
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

nargo test: error: Could not determine loop bound at compile-time #2417

Closed
0xPhaze opened this issue Aug 23, 2023 · 0 comments · Fixed by #2420
Closed

nargo test: error: Could not determine loop bound at compile-time #2417

0xPhaze opened this issue Aug 23, 2023 · 0 comments · Fixed by #2420
Labels
bug Something isn't working

Comments

@0xPhaze
Copy link

0xPhaze commented Aug 23, 2023

Aim

Compiling the following circuit works.

main.nr

use dep::std;

global DEPTH: Field = 4;

fn hash(left: [u8; 32], right: [u8; 32]) -> [u8; 32] {
  let mut concat: [u8; 64] = [0; 64];

  for i in 0..32 {
    concat[i] = left[i];
  }

  for i in 0..32 {
    concat[i + 32] = right[i];
  }

  std::hash::keccak256(concat, 64)
}

fn get_node(nodes: [u8; 32 * DEPTH], index: Field) -> [u8; 32] {
  let mut out: [u8; 32] = [0; 32];

  for i in 0..32 {
    out[i] = nodes[i + index * 32];
  }

  out
}

fn compute_merkle_root(key: [u1; 256], leaf: [u8; 32], nodes: [u8; 32 * DEPTH]) -> [u8; 32] {
  // Start with the `leaf` node.
  let mut root: [u8; 32] = leaf;

  for i in 0..DEPTH {
    let n = get_node(nodes, i);
    let z = zeros(i);

    // Hash current node `root` with left provided node `nodes[i]`
    let mut left = n;
    let mut right = root;

    // Or hash it with right zero subtree `zeros(i)`,
    // depending on `key`s i-th least-significant bit.
    if (key[255 - i] == 0) {
      left = root;
      right = z;
    } 

    root = hash(left, right);
  }

  root
}

/// Main circuit.
fn main(
  receiver: pub Field,
  key: [u1; 256],
  nullifier: pub [u8; 32],
  secret: [u8; 32],
  nodes: [u8; 32 * DEPTH],
  root: pub [u8; 32],
) {
  // Compute `leaf` using `nullifier` and `secret`.
  let leaf: [u8; 32] = hash(nullifier, secret);

  // Ensure `leaf` is included in the merkle tree.
  assert(compute_merkle_root(key, leaf, nodes) == root);

  // Tie `receiver` into proof.
  assert(receiver != 0);
}

#[test]
fn test_main() {
  let key       = [0; 256];
  let nullifier = [0x00 as u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88];
  let secret    = [0x00 as u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37];
  let nodes     = [0; 32 * DEPTH];
  let leaf      = hash(nullifier, secret);
  let c_root    = compute_merkle_root(key, leaf, nodes);
}

fn zeros(level: Field) -> [u8; 32] {
  let mut out: [u8; 32] = [0; 32];

  for _ in 0..(level + 1) {
    out = hash(out, out);
  }

  out
}

#[test]
fn test_zeros() {
  assert(zeros(0) == [0xad,0x32,0x28,0xb6,0x76,0xf7,0xd3,0xcd,0x42,0x84,0xa5,0x44,0x3f,0x17,0xf1,0x96,0x2b,0x36,0xe4,0x91,0xb3,0x0a,0x40,0xb2,0x40,0x58,0x49,0xe5,0x97,0xba,0x5f,0xb5]);
  assert(zeros(1) == [0xb4,0xc1,0x19,0x51,0x95,0x7c,0x6f,0x8f,0x64,0x2c,0x4a,0xf6,0x1c,0xd6,0xb2,0x46,0x40,0xfe,0xc6,0xdc,0x7f,0xc6,0x07,0xee,0x82,0x06,0xa9,0x9e,0x92,0x41,0x0d,0x30]);
  assert(zeros(2) == [0x21,0xdd,0xb9,0xa3,0x56,0x81,0x5c,0x3f,0xac,0x10,0x26,0xb6,0xde,0xc5,0xdf,0x31,0x24,0xaf,0xba,0xdb,0x48,0x5c,0x9b,0xa5,0xa3,0xe3,0x39,0x8a,0x04,0xb7,0xba,0x85]);
  assert(zeros(3) == [0xe5,0x87,0x69,0xb3,0x2a,0x1b,0xea,0xf1,0xea,0x27,0x37,0x5a,0x44,0x09,0x5a,0x0d,0x1f,0xb6,0x64,0xce,0x2d,0xd3,0x58,0xe7,0xfc,0xbf,0xb7,0x8c,0x26,0xa1,0x93,0x44]);
  assert(zeros(4) == [0x0e,0xb0,0x1e,0xbf,0xc9,0xed,0x27,0x50,0x0c,0xd4,0xdf,0xc9,0x79,0x27,0x2d,0x1f,0x09,0x13,0xcc,0x9f,0x66,0x54,0x0d,0x7e,0x80,0x05,0x81,0x11,0x09,0xe1,0xcf,0x2d]);
}

however when running the tests, I get

nargo test 
[cashcash] Running 2 test functions
[cashcash] Testing test_main... error: Could not determine loop bound at compile-time
    ┌─ /Users/lain/git/zkcamp/cashcash/circuits/src/main.nr:115:16
    │
115 │   for _ in 0..(level + 1) {
    │                ---------
    │
    = Call stack:
      1. /Users/lain/git/zkcamp/cashcash/circuits/src/main.nr:115:16

[cashcash] Testing test_zeros... ok
Error: [cashcash] 1 test failed

Location:
    crates/nargo_cli/src/cli/mod.rs:79:5

Expected Behavior

Based on @TomAFrench's comment in #2410 this should be supported. And it works, but just not for the test.

There's nothing really special about recursion, your version should work as well (and is cleaner). I can compile yours with the same behaviour so I think you may have been calling it with a non-constant input.

I'm not sure if this is in a release yet but you can add the assert_constant function to check to make sure you're calling with a constant input.

fn zeros(level: Field) -> [u8; 32] {
  std::assert_constant(level)
  let mut out: [u8; 32] = [0; 32];

  for _ in 0..(level + 1) {
    out = hash(out, out);
  }

Originally posted by @TomAFrench in #2410 (comment)

To Reproduce

  1. noirup -n
  2. nargo test

Installation Method

Binary

Nargo Version

nargo 0.10.3 (git version hash: 707685c, is dirty: false)

Additional Context

No response

Would you like to submit a PR for this Issue?

No

Support Needs

No response

@0xPhaze 0xPhaze added the bug Something isn't working label Aug 23, 2023
@github-project-automation github-project-automation bot moved this to 📋 Backlog in Noir Aug 23, 2023
@github-project-automation github-project-automation bot moved this from 📋 Backlog to ✅ Done in Noir Aug 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

1 participant