From 891b6a343d974530bff3cfaf611d1235e1f727e2 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:43:18 +0100 Subject: [PATCH] chore(ci): add CI to repo (#4) --- .github/NIGHTLY_CANARY_DIED.md | 8 ++++++ .github/workflow/nightly-canary.yml | 40 ++++++++++++++++++++++++++ .github/workflow/test.yml | 44 +++++++++++++++++++++++++++++ .gitignore | 1 + out.txt | 7 ----- target/noir_sort.json | 1 - 6 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 .github/NIGHTLY_CANARY_DIED.md create mode 100644 .github/workflow/nightly-canary.yml create mode 100644 .github/workflow/test.yml create mode 100644 .gitignore delete mode 100644 out.txt delete mode 100644 target/noir_sort.json diff --git a/.github/NIGHTLY_CANARY_DIED.md b/.github/NIGHTLY_CANARY_DIED.md new file mode 100644 index 0000000..327b4f7 --- /dev/null +++ b/.github/NIGHTLY_CANARY_DIED.md @@ -0,0 +1,8 @@ +--- +title: "Tests fail on latest Nargo nightly release" +assignees: TomAFrench, kashbrti +--- + +The tests on this Noir project have started failing when using the latest nightly release of the Noir compiler. This likely means that there have been breaking changes for which this project needs to be updated to take into account. + +Check the [{{env.WORKFLOW_NAME}}]({{env.WORKFLOW_URL}}) workflow for details. diff --git a/.github/workflow/nightly-canary.yml b/.github/workflow/nightly-canary.yml new file mode 100644 index 0000000..4fd5ce1 --- /dev/null +++ b/.github/workflow/nightly-canary.yml @@ -0,0 +1,40 @@ +name: Noir Nightly Canary + +on: + schedule: + # Run a check at 9 AM UTC + - cron: "0 9 * * *" + +env: + CARGO_TERM_COLOR: always + +permissions: + issues: write + +jobs: + test: + name: Test on Nargo ${{matrix.toolchain}} + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install Nargo + uses: noir-lang/noirup@v0.1.3 + with: + toolchain: nightly + + - name: Run Noir tests + run: nargo test + + - name: Alert on dead links + uses: JasonEtco/create-an-issue@v2 + if: ${{ failure() }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WORKFLOW_NAME: ${{ github.workflow }} + WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + with: + update_existing: true + filename: .github/NIGHTLY_CANARY_DIED.md + \ No newline at end of file diff --git a/.github/workflow/test.yml b/.github/workflow/test.yml new file mode 100644 index 0000000..971fc98 --- /dev/null +++ b/.github/workflow/test.yml @@ -0,0 +1,44 @@ +name: Noir tests + +on: + push: + branches: + - main + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + test: + name: Test on Nargo ${{matrix.toolchain}} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + toolchain: [nightly, 0.36.0] + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install Nargo + uses: noir-lang/noirup@v0.1.3 + with: + toolchain: ${{ matrix.toolchain }} + + - name: Run Noir tests + run: nargo test + + format: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install Nargo + uses: noir-lang/noirup@v0.1.3 + with: + toolchain: 0.36.0 + + - name: Run formatter + run: nargo fmt --check diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1de5659 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/out.txt b/out.txt deleted file mode 100644 index 61c3c8b..0000000 --- a/out.txt +++ /dev/null @@ -1,7 +0,0 @@ -{"functions": [ - { - "acir_opcodes": 704, - "circuit_size": 4891, - "gates_per_opcode": [0,0,2,2740,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,2,1,2,0,1,0,6,1,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,6,4,1,6,1,4,1,0] - } -]} \ No newline at end of file diff --git a/target/noir_sort.json b/target/noir_sort.json deleted file mode 100644 index 3798181..0000000 --- a/target/noir_sort.json +++ /dev/null @@ -1 +0,0 @@ -{"noir_version":"0.32.0+c679f01a19b02ad2ac2287c8e699b46887f7872c","hash":16191522692318200190,"abi":{"parameters":[{"name":"x","type":{"kind":"array","length":100,"type":{"kind":"field"}},"visibility":"private"}],"return_type":null,"error_types":{}},"bytecode":"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","debug_symbols":"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","file_map":{"4":{"source":"// docs:start:eq-trait\ntrait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\nimpl Eq for Field { fn eq(self, other: Field) -> bool { self == other } }\n\nimpl Eq for u64 { fn eq(self, other: u64) -> bool { self == other } }\nimpl Eq for u32 { fn eq(self, other: u32) -> bool { self == other } }\nimpl Eq for u8 { fn eq(self, other: u8) -> bool { self == other } }\nimpl Eq for u1 { fn eq(self, other: u1) -> bool { self == other } }\n\nimpl Eq for i8 { fn eq(self, other: i8) -> bool { self == other } }\nimpl Eq for i32 { fn eq(self, other: i32) -> bool { self == other } }\nimpl Eq for i64 { fn eq(self, other: i64) -> bool { self == other } }\n\nimpl Eq for () { fn eq(_self: Self, _other: ()) -> bool { true } }\nimpl Eq for bool { fn eq(self, other: bool) -> bool { self == other } }\n\nimpl Eq for [T; N] where T: Eq {\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0 .. self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T] where T: Eq {\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n for i in 0 .. self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\nimpl Eq for (A, B) where A: Eq, B: Eq {\n fn eq(self, other: (A, B)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1)\n }\n}\n\nimpl Eq for (A, B, C) where A: Eq, B: Eq, C: Eq {\n fn eq(self, other: (A, B, C)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2)\n }\n}\n\nimpl Eq for (A, B, C, D) where A: Eq, B: Eq, C: Eq, D: Eq {\n fn eq(self, other: (A, B, C, D)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3)\n }\n}\n\nimpl Eq for (A, B, C, D, E) where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq {\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3) & self.4.eq(other.4)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\nstruct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n// docs:start:ord-trait\ntrait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else {\n if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n }\n}\n\nimpl Ord for [T; N] where T: Ord {\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0 .. self.len() {\n if result == Ordering::equal() {\n let result_i = self[i].cmp(other[i]);\n\n if result_i == Ordering::less() {\n result = result_i;\n } else if result_i == Ordering::greater() {\n result = result_i;\n }\n }\n }\n result\n }\n}\n\nimpl Ord for [T] where T: Ord {\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let mut result = self.len().cmp(other.len());\n for i in 0 .. self.len() {\n if result == Ordering::equal() {\n let result_i = self[i].cmp(other[i]);\n\n if result_i == Ordering::less() {\n result = result_i;\n } else if result_i == Ordering::greater() {\n result = result_i;\n }\n }\n }\n result\n }\n}\n\nimpl Ord for (A, B) where A: Ord, B: Ord {\n fn cmp(self, other: (A, B)) -> Ordering {\n let result = self.0.cmp(other.0);\n\n if result != Ordering::equal() {\n result\n } else {\n self.1.cmp(other.1)\n }\n }\n}\n\nimpl Ord for (A, B, C) where A: Ord, B: Ord, C: Ord {\n fn cmp(self, other: (A, B, C)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D) where A: Ord, B: Ord, C: Ord, D: Ord {\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D, E) where A: Ord, B: Ord, C: Ord, D: Ord, E: Ord {\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n if result == Ordering::equal() {\n result = self.4.cmp(other.4);\n }\n\n result\n }\n}\n\n// Compares and returns the maximum of two values.\n//\n// Returns the second argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::max(1, 2), 2);\n// assert_eq(cmp::max(2, 2), 2);\n// ```\npub fn max(v1: T, v2: T) -> T where T: Ord {\n if v1 > v2 { v1 } else { v2 }\n}\n\n// Compares and returns the minimum of two values.\n//\n// Returns the first argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::min(1, 2), 1);\n// assert_eq(cmp::min(2, 2), 2);\n// ```\npub fn min(v1: T, v2: T) -> T where T: Ord {\n if v1 > v2 { v2 } else { v1 }\n}\n\nmod cmp_tests {\n use crate::cmp::{min, max};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0 as u64, 1 as u64), 0);\n assert_eq(min(0 as u64, 0 as u64), 0);\n assert_eq(min(1 as u64, 1 as u64), 1);\n assert_eq(min(255 as u8, 0 as u8), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0 as u64, 1 as u64), 1);\n assert_eq(max(0 as u64, 0 as u64), 0);\n assert_eq(max(1 as u64, 1 as u64), 1);\n assert_eq(max(255 as u8, 0 as u8), 255);\n }\n}\n","path":"std/cmp.nr"},"23":{"source":"mod bn254;\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n pub fn to_le_bits(self: Self, bit_size: u32) -> [u1] {\n crate::assert_constant(bit_size);\n self.__to_le_bits(bit_size)\n }\n\n pub fn to_be_bits(self: Self, bit_size: u32) -> [u1] {\n crate::assert_constant(bit_size);\n self.__to_be_bits(bit_size)\n }\n\n #[builtin(to_le_bits)]\n fn __to_le_bits(self, _bit_size: u32) -> [u1] {}\n\n #[builtin(to_be_bits)]\n fn __to_be_bits(self, bit_size: u32) -> [u1] {}\n\n #[builtin(apply_range_constraint)]\n fn __assert_max_bit_size(self, bit_size: u32) {}\n\n pub fn assert_max_bit_size(self: Self, bit_size: u32) {\n crate::assert_constant(bit_size);\n assert(bit_size < modulus_num_bits() as u32);\n self.__assert_max_bit_size(bit_size);\n }\n\n pub fn to_le_bytes(self: Self, byte_size: u32) -> [u8] {\n self.to_le_radix(256, byte_size)\n }\n\n pub fn to_be_bytes(self: Self, byte_size: u32) -> [u8] {\n self.to_be_radix(256, byte_size)\n }\n\n pub fn to_le_radix(self: Self, radix: u32, result_len: u32) -> [u8] {\n crate::assert_constant(radix);\n crate::assert_constant(result_len);\n self.__to_le_radix(radix, result_len)\n }\n\n pub fn to_be_radix(self: Self, radix: u32, result_len: u32) -> [u8] {\n crate::assert_constant(radix);\n crate::assert_constant(result_len);\n self.__to_be_radix(radix, result_len)\n }\n\n // decompose `_self` into a `_result_len` vector over the `_radix` basis\n // `_radix` must be less than 256\n #[builtin(to_le_radix)]\n fn __to_le_radix(self, radix: u32, result_len: u32) -> [u8] {}\n\n #[builtin(to_be_radix)]\n fn __to_be_radix(self, radix: u32, result_len: u32) -> [u8] {}\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b = exponent.to_le_bits(32);\n\n for i in 1..33 {\n r *= r;\n r = (b[32-i] as Field) * (r * self) + (1 - b[32-i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1.\n pub fn sgn0(self) -> u1 {\n self as u1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [u1] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [u1] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n let num_bytes = (modulus_num_bits() as u32 + 7) / 8;\n let x_bytes = x.to_le_bytes(num_bytes);\n let y_bytes = y.to_le_bytes(num_bytes);\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..num_bytes {\n if (!done) {\n let x_byte = x_bytes[num_bytes - 1 - i] as u8;\n let y_byte = y_bytes[num_bytes - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n}\n\n","path":"std/field/mod.nr"},"32":{"source":"mod hash;\nmod aes128;\nmod array;\nmod slice;\nmod merkle;\nmod schnorr;\nmod ecdsa_secp256k1;\nmod ecdsa_secp256r1;\nmod eddsa;\nmod embedded_curve_ops;\nmod sha256;\nmod sha512;\nmod field;\nmod ec;\nmod unsafe;\nmod collections;\nmod compat;\nmod convert;\nmod option;\nmod string;\nmod test;\nmod cmp;\nmod ops;\nmod default;\nmod prelude;\nmod uint128;\nmod bigint;\nmod runtime;\nmod meta;\nmod append;\n\n// Oracle calls are required to be wrapped in an unconstrained function\n// Thus, the only argument to the `println` oracle is expected to always be an ident\n#[oracle(print)]\nunconstrained fn print_oracle(with_newline: bool, input: T) {}\n\nunconstrained pub fn print(input: T) {\n print_oracle(false, input);\n}\n\nunconstrained pub fn println(input: T) {\n print_oracle(true, input);\n}\n\n#[foreign(recursive_aggregation)]\npub fn verify_proof(verification_key: [Field], proof: [Field], public_inputs: [Field], key_hash: Field) {}\n\n// Asserts that the given value is known at compile-time.\n// Useful for debugging for-loop bounds.\n#[builtin(assert_constant)]\npub fn assert_constant(x: T) {}\n\n// Asserts that the given value is both true and known at compile-time\n#[builtin(static_assert)]\npub fn static_assert(predicate: bool, message: str) {}\n\n// from_field and as_field are private since they are not valid for every type.\n// `as` should be the default for users to cast between primitive types, and in the future\n// traits can be used to work with generic types.\n#[builtin(from_field)]\nfn from_field(x: Field) -> T {}\n\n#[builtin(as_field)]\nfn as_field(x: T) -> Field {}\n\npub fn wrapping_add(x: T, y: T) -> T {\n crate::from_field(crate::as_field(x) + crate::as_field(y))\n}\n\npub fn wrapping_sub(x: T, y: T) -> T {\n //340282366920938463463374607431768211456 is 2^128, it is used to avoid underflow\n crate::from_field(crate::as_field(x) + 340282366920938463463374607431768211456 - crate::as_field(y))\n}\n\npub fn wrapping_mul(x: T, y: T) -> T {\n crate::from_field(crate::as_field(x) * crate::as_field(y))\n}\n\n#[builtin(as_witness)]\npub fn as_witness(x: Field) {}\n\n","path":"std/lib.nr"},"54":{"source":"mod quicksort;\nuse crate::quicksort::quicksort::quicksort as quicksort;\nuse crate::quicksort::quicksort_explicit::quicksort as quicksort_explicit;\nuse dep::check_shuffle::check_shuffle;\n\n/**\n * Given an input array of type T, return a sorted array.\n * Type `T` must satisfy the Ord and Eq trait\n * The Eq function is used within an unconstrained function so its constraint-efficiently is not relevant\n * Note: sort_extended is likely more efficient as constraining `x < y` can typically be described\n * more efficiently than returning a boolean that describes whether `x < y`\n **/\npub fn sort(input: [T; N]) -> [T; N] where T: std::cmp::Ord + std::cmp::Eq {\n let sorted = quicksort(input);\n\n for i in 0..N - 1 {\n assert(sorted[i] <= sorted[i + 1]);\n }\n check_shuffle(input, sorted);\n sorted\n}\n\n/**\n * Given an input array of type T, return a sorted array.\n * Type `T` must satisfy the Eq trait\n * The Eq function is used within an unconstrained function so its constraint-efficiently is not relevant\n *\n * The `sortfn` parameter is a function that descibes whether, given two elements `a, b` of type T, `a <= b`\n * Note: sort_extended is likely more efficient as constraining `x < y` can typically be described\n * more efficiently than returning a boolean that describes whether `x < y`\n **/\npub fn sort_via(input: [T; N], sortfn: fn(T, T) -> bool) -> [T; N] where T: std::cmp::Eq {\n let sorted = quicksort_explicit(input, sortfn);\n\n for i in 0..N - 1 {\n assert(sortfn(sorted[i], sorted[i + 1]));\n }\n check_shuffle(input, sorted);\n sorted\n}\n\n/**\n * Given an input array of type T, return a sorted array.\n * Type `T` must satisfy the Eq trait\n * The Eq function is used within an unconstrained function so its constraint-efficiently is not relevant\n *\n * The `sortfn` parameter is a function that descibes whether, given two elements `a, b` of type T, `a <= b`\n * The `sortfn_assert` parameter is a function that *asserts* that `a <= b`\n *\n * `sortfn` is used in unconstrained functions only\n * `sortfn_assert` is used in constrained functions\n\n * Note: This is likely the most efficient sort function as constraining `x < y` can typically be described\n * more efficiently than returning a boolean that describes whether `x < y`\n **/\npub fn sort_extended(\n input: [T; N],\n sortfn: fn(T, T) -> bool,\n sortfn_assert: fn(T, T) -> ()\n) -> [T; N] where T: std::cmp::Eq {\n let sorted = quicksort_explicit(input, sortfn);\n\n for i in 0..N - 1 {\n sortfn_assert(sorted[i], sorted[i + 1]);\n }\n check_shuffle(input, sorted);\n sorted\n}\n\nmod test {\n use crate::sort;\n use crate::sort_via;\n use crate::sort_extended;\n\n fn sort_u32(a: u32, b: u32) -> bool {\n a <= b\n }\n\n // unconditional_lt will cost fewer constraints than the `<=` operator\n // as we do not need to constrain the case where `a > b`, and assign a boolean variable to the result\n fn unconditional_lt(_a: u32, _b: u32) {\n let a = _a as Field;\n let b = _b as Field;\n\n let diff = b - a;\n diff.assert_max_bit_size(32);\n }\n\n #[test]\n fn test_sort() {\n let mut arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = sort(arr);\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_via() {\n let mut arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = sort_via(arr, sort_u32);\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_extended() {\n let mut arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = sort_extended(arr, sort_u32, unconditional_lt);\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n}\n\nfn sort_u32(a: u32, b: u32) -> bool {\n a <= b\n}\n\nfn lt_u32(a: u32, b: u32) -> bool {\n a < b\n}\n// unconditional_lt will cost fewer constraints than the `<=` operator\n// as we do not need to constrain the case where `a > b`, and assign a boolean variable to the result\nfn unconditional_lt(_a: u32, _b: u32) {\n let a = _a as Field;\n let b = _b as Field;\n\n let diff = b - a;\n diff.assert_max_bit_size(32);\n}\n\nstruct TestStruct {\n a: bool,\n b: u32,\n c: Field\n}\n\nimpl std::cmp::Eq for TestStruct {\n fn eq(self, other: Self) -> bool {\n \n (self.a == other.a)\n & (self.b == other.b)\n & (self.c == other.c)\n }\n}\n\nunconstrained pub fn get_lt_predicate_f(x: Field, y: Field) -> bool {\n let a = x as u32;\n let b = y as u32;\n let r = a < b;\n r\n}\n\npub fn lt_f(x: Field, y: Field) -> bool {\n let predicate = get_lt_predicate_f(x, y);\n let delta = y as Field - x as Field;\n let lt_parameter = 2 * (predicate as Field) * delta - predicate as Field - delta;\n lt_parameter.assert_max_bit_size(32);\n\n predicate\n}\n\nfn less_than_for_test_struct(lhs: TestStruct, rhs: TestStruct) -> bool {\n let a_lt = lhs.a < rhs.a;\n let b_lt = lhs.b < rhs.b;\n let c_lt = lt_f(lhs.c, rhs.c);\n\n let a_eq = lhs.a == rhs.a;\n let b_eq = lhs.b == rhs.b;\n\n let b_flag = a_eq;\n\n let c_flag = a_eq & b_eq;\n let result = a_lt | (b_flag & b_lt) | (c_flag & c_lt);\n\n result\n}\n\nfn unconditional_lte(lhs: TestStruct, rhs: TestStruct) {\n // lhs < rhs implies:\n // a == false, b == false\n // a == false, b == true\n // a == true, b == true\n // i.e. a == true, b == false is not allowed\n assert(lhs.a as Field * (1 - rhs.a as Field) == 0);\n\n // a < b as u32 implies\n // b - a > 0\n let diff = lhs.b as Field - rhs.b as Field;\n diff.assert_max_bit_size(32);\n\n // a < b as Field (32 bit condition)\n let diff = lhs.c as Field - rhs.c as Field;\n diff.assert_max_bit_size(32);\n}\n\nglobal Num: u32 = 100;\n\n// // size 100: 7,638\n// // size 1,000: 51,738\n// // diff = 49\n// fn main2(x: [TestStruct; Num]) {\n// let sorted = sort_extended(x, less_than_for_test_struct, unconditional_lte);\n// println(f\"{sorted}\");\n// }\n\n// // size 100: 9,321\n// // size 1,000: 68,721\n// // diff = 59,400 = 66 per\n// fn main3(x: [TestStruct; Num]) {\n// let sorted = sort_via(x, less_than_for_test_struct);\n// println(f\"{sorted}\");\n// }\n\n// // size 100: 8,521\n// // size 1,000: 60,721\n// // diff = 58 per\n// // 8 gates womp\n// fn main(x: [TestStruct; Num]) {\n// let sorted = x.sort_via(less_than_for_test_struct);\n// println(f\"{sorted}\");\n// }\n\n// 6206\nfn main6(x: [u32; Num]) {\n let sorted = sort(x);\n println(f\"{sorted}\");\n}\n\n// 5340\nfn main5(x: [u32; Num]) {\n let sorted = sort_via(x, sort_u32);\n println(f\"{sorted}\");\n}\n\n// 100: 5234\n// 1,000: 27,741\n// diff = 25\nfn main9(x: [u32; Num]) {\n let sorted = sort_extended(x, sort_u32, unconditional_lt);\n println(f\"{sorted}\");\n}\n\n// 5507\nfn main3(x: [u32; Num]) {\n let sorted = x.sort();\n println(f\"{sorted}\");\n}\n\n// 100: 4461\n// 1000: 21,741\n// diff = 19\nfn main11(x: [u32; Num]) {\n let sorted = x.sort_via(lt_u32);\n println(f\"{sorted}\");\n}\n\n// 4,565\nfn main2(x: [Field; Num]) {\n let sorted = x.sort_via(lt_f);\n println(f\"{sorted}\");\n}\n\nfn unconditional_lt_f(a: Field, b: Field) {\n let diff = b - a;\n diff.assert_max_bit_size(32);\n}\n\n// 5,089\nfn main20(x: [Field; Num]) {\n let sorted = sort_via(x, lt_f);\n println(f\"{sorted}\");\n}\n\n// 5,089\nfn main(x: [Field; Num]) {\n let sorted = sort_extended(x, lt_f, unconditional_lt_f);\n println(f\"{sorted}\");\n}\n","path":"/Users/zac/noir_sort/src/main.nr"},"55":{"source":"trait Swap {\n fn swap(&mut self, i: u32, j: u32);\n}\n\nimpl Swap for [T; N] {\n fn swap(&mut self, i: u32, j: u32) {\n let temp = self[i];\n self[i] = self[j];\n self[j] = temp;\n }\n}\n\nunconstrained fn partition(arr: &mut [T; N], low: u32, high: u32) -> u32 where T: std::cmp::Ord {\n let pivot = high;\n let mut i = low;\n for j in low..high {\n if (arr[j] < arr[pivot]) {\n arr.swap(i, j);\n i += 1;\n }\n }\n arr.swap(i, pivot);\n i\n}\n\nunconstrained fn quicksort_recursive(arr: &mut [T; N], low: u32, high: u32) where T: std::cmp::Ord {\n if low < high {\n let pivot_index = partition(arr, low, high);\n if pivot_index > 0 {\n quicksort_recursive(arr, low, pivot_index - 1);\n }\n quicksort_recursive(arr, pivot_index + 1, high);\n }\n}\n\nunconstrained pub fn quicksort(_arr: [T; N]) -> [T; N] where T: std::cmp::Ord {\n let mut arr: [T; N] = _arr;\n if arr.len() <= 1 {} else {\n quicksort_recursive(&mut arr, 0, arr.len() - 1);\n }\n arr\n}\n\n","path":"/Users/zac/noir_sort/src/quicksort/quicksort.nr"},"56":{"source":"trait Swap {\n fn swap(&mut self, i: u32, j: u32);\n}\n\nimpl Swap for [T; N] {\n fn swap(&mut self, i: u32, j: u32) {\n let temp = self[i];\n self[i] = self[j];\n self[j] = temp;\n }\n}\n\nunconstrained fn partition(arr: &mut [T; N], low: u32, high: u32, sortfn: fn(T, T) -> bool) -> u32 {\n let pivot = high;\n let mut i = low;\n for j in low..high {\n if (sortfn(arr[j], arr[pivot])) {\n arr.swap(i, j);\n i += 1;\n }\n }\n arr.swap(i, pivot);\n i\n}\n\nunconstrained fn quicksort_recursive(\n arr: &mut [T; N],\n low: u32,\n high: u32,\n sortfn: fn(T, T) -> bool\n) {\n if low < high {\n let pivot_index = partition(arr, low, high, sortfn);\n if pivot_index > 0 {\n quicksort_recursive(arr, low, pivot_index - 1, sortfn);\n }\n quicksort_recursive(arr, pivot_index + 1, high, sortfn);\n }\n}\n\nunconstrained pub fn quicksort(_arr: [T; N], sortfn: fn(T, T) -> bool) -> [T; N] {\n let mut arr: [T; N] = _arr;\n if arr.len() <= 1 {} else {\n quicksort_recursive(&mut arr, 0, arr.len() - 1, sortfn);\n }\n arr\n}\n\n","path":"/Users/zac/noir_sort/src/quicksort/quicksort_explicit.nr"},"57":{"source":"unconstrained fn get_shuffle_indices(\n lhs: [T; N],\n rhs: [T; N]\n) -> [Field; N] where T: std::cmp::Eq {\n let mut shuffle_indices: [Field;N ] = [0; N];\n\n let mut shuffle_mask: [bool; N] = [false; N];\n for i in 0..N {\n let mut found = false;\n for j in 0..N {\n if (shuffle_mask[j] == false) {\n if (lhs[i] == rhs[j]) {\n found = true;\n shuffle_indices[i] = j as Field;\n shuffle_mask[j] = true;\n }\n }\n if (found) {\n break;\n }\n }\n assert(found == true, \"check_shuffle, lhs and rhs arrays do not contain equivalent values\");\n }\n\n shuffle_indices\n}\n\npub fn check_shuffle(lhs: [T; N], rhs: [T; N]) where T: std::cmp::Eq {\n let shuffle_indices = get_shuffle_indices(lhs, rhs);\n let mut index_masks: [Field; N] = [0; N];\n\n for i in 0..N {\n let idx = shuffle_indices[i];\n assert_eq(index_masks[idx], 0);\n index_masks[idx] = 1;\n let expected = rhs[idx];\n let result = lhs[i];\n assert_eq(expected, result);\n }\n}\n\nmod test {\n struct CompoundStruct {\n a: bool,\n b: Field,\n c: u64\n }\n impl std::cmp::Eq for CompoundStruct {\n fn eq(self, other: Self) -> bool {\n (self.a == other.a) & (self.b == other.b) & (self.c == other.c)\n }\n }\n\n use crate::check_shuffle;\n #[test]\n fn test_shuffle() {\n let lhs: [Field; 5] = [0, 1, 2, 3, 4];\n let rhs: [Field; 5] = [2, 0, 3, 1, 4];\n check_shuffle(lhs, rhs);\n }\n\n #[test]\n fn test_shuffle_identity() {\n let lhs: [Field; 5] = [0, 1, 2, 3, 4];\n let rhs: [Field; 5] = [0, 1, 2, 3, 4];\n check_shuffle(lhs, rhs);\n }\n\n #[test(should_fail_with = \"check_shuffle, lhs and rhs arrays do not contain equivalent values\")]\n fn test_shuffle_fail() {\n let lhs: [Field; 5] = [0, 1, 2, 3, 4];\n let rhs: [Field; 5] = [0, 1, 2, 3, 5];\n check_shuffle(lhs, rhs);\n }\n\n #[test(should_fail_with = \"check_shuffle, lhs and rhs arrays do not contain equivalent values\")]\n fn test_shuffle_duplicates() {\n let lhs: [Field; 5] = [0, 1, 2, 3, 4];\n let rhs: [Field; 5] = [0, 1, 2, 3, 3];\n check_shuffle(lhs, rhs);\n }\n\n #[test]\n fn test_shuffle_compound_struct() {\n let lhs: [CompoundStruct; 5] = [\n CompoundStruct { a: false, b: 0, c: 12345 },\n CompoundStruct { a: false, b: -100, c: 54321 },\n CompoundStruct { a: true, b: 5, c: 0xffffffffffffffff },\n CompoundStruct { a: true, b: 9814, c: 0xeeffee0011001133 },\n CompoundStruct { a: false, b: 0x155, c: 0 }\n ];\n let rhs: [CompoundStruct; 5] = [\n CompoundStruct { a: false, b: 0x155, c: 0 },\n CompoundStruct { a: false, b: 0, c: 12345 },\n CompoundStruct { a: false, b: -100, c: 54321 },\n CompoundStruct { a: true, b: 9814, c: 0xeeffee0011001133 },\n CompoundStruct { a: true, b: 5, c: 0xffffffffffffffff }\n ];\n check_shuffle(lhs, rhs);\n }\n}\n","path":"/Users/zac/noir_check_shuffle/src/lib.nr"}},"names":["main"]} \ No newline at end of file