diff --git a/README.md b/README.md
index 793f603..a00c70f 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,8 @@ The following libraries are required for running (different components of) the t
- [pandas](https://pandas.pydata.org/) (2.1.4+) for data analysis in test suite
- [tabulate](https://github.com/astanin/python-tabulate) (0.9.0+) for result table rendering
- Leo (**7ac50d8**) for compiling and running all benchmarks enclosed
- - The tools is tested under this version, but newer version of Lao may also work.
+ - The tools is tested under this version, but newer version of Leo may also work.
+ - Older version may not work, as there are some breaking changes of Leo project structure.
## Usage
@@ -51,7 +52,7 @@ pip uninstall vanguard
After installation, you can directly use the commandline executable `vanguard-aleo` provided:
```bash
-usage: vanguard-aleo [-h] [-b BUILD] [-p PID] [-f FIDS] [-d {divz,infoleak,rtcnst,unused}] [-v]
+usage: vanguard-aleo [-h] [-b BUILD] [-p PID] [-f FIDS] [-d {divrd,divz,downcast,emptyf,infoleak,magicv,rtcnst,susinst,unused}] [-v]
options:
-h, --help show this help message and exit
@@ -59,7 +60,7 @@ options:
project build path, default: ./
-p PID, --pid PID program id, default:
-f FIDS, --fids FIDS function ids (separated by comma, no space), default:
- -d {divz,infoleak,rtcnst,unused}, --detector {divz,infoleak,rtcnst,unused}
+ -d {divrd,divz,downcast,emptyf,infoleak,magicv,rtcnst,susinst,unused}, --detector {divrd,divz,downcast,emptyf,infoleak,magicv,rtcnst,susinst,unused}
detector to use, default: infoleak
-v, --verbose whether or not to return extra info, default: False
```
@@ -151,6 +152,11 @@ from vanguard.aleo.detectors import detector_infoleak
from vanguard.aleo.detectors import detector_rtcnst
from vanguard.aleo.detectors import detector_unused
from vanguard.aleo.detectors import detector_divz
+from vanguard.aleo.detectors import detector_emptyf
+from vanguard.aleo.detectors import detector_magicv
+from vanguard.aleo.detectors import detector_susinst
+from vanguard.aleo.detectors import detector_divrd
+from vanguard.aleo.detectors import detector_downcast
...
```
@@ -170,6 +176,9 @@ You can find examples showing Leo/Aleo vulnerabilities with comments and annotat
| rtcnst0/ | Returning constant |
| underflow0/ | Arithmetic underflow |
| unused0/ | Unused variable/signal |
+| emptyf0/ | Empty functionality |
+| magicv0/ | Magic variable |
+| susinst0/ | Suspicious instruction |
## Parser/Lexer Generation
diff --git a/pyproject.toml b/pyproject.toml
index 3689f73..75605d2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "vanguard"
-version = "0.0.4"
+version = "0.0.5"
authors = [
{ name="Yanju Chen", email="yanju@veridise.com" },
]
diff --git a/tests/public/divrd0/build/main.aleo b/tests/public/divrd0/build/main.aleo
index 74fbb71..dee5fa4 100644
--- a/tests/public/divrd0/build/main.aleo
+++ b/tests/public/divrd0/build/main.aleo
@@ -3,8 +3,8 @@ program divrd0.aleo;
function vanguard_helper:
- cast true true false true false true true into r0 as [boolean; 7u32];
- output r0 as [boolean; 7u32].private;
+ cast true true false true false true true true into r0 as [boolean; 8u32];
+ output r0 as [boolean; 8u32].private;
function ex0:
@@ -48,3 +48,8 @@ function ex6:
mul 15u8 2u8 into r0;
div r0 9u8 into r1;
output r1 as u8.private;
+
+
+function ex7:
+ div 15u8 2u8 into r0;
+ output r0 as u8.private;
diff --git a/tests/public/divrd0/src/main.leo b/tests/public/divrd0/src/main.leo
index 5150e32..a64bb2b 100644
--- a/tests/public/divrd0/src/main.leo
+++ b/tests/public/divrd0/src/main.leo
@@ -1,10 +1,10 @@
// The 'divrd0' program.
program divrd0.aleo {
- transition vanguard_helper() -> [bool; 7] {
+ transition vanguard_helper() -> [bool; 8] {
return [
label_ex0, label_ex1, label_ex2, label_ex3,
- label_ex4, label_ex5, label_ex6,
+ label_ex4, label_ex5, label_ex6, label_ex7,
];
}
@@ -69,4 +69,10 @@ program divrd0.aleo {
let b: u8 = a * 2u8 / 9u8;
return b;
}
+
+ const label_ex7: bool = true;
+ transition ex7 () -> u8 {
+ let a: u8 = 15u8 / 2u8;
+ return a;
+ }
}
diff --git a/tests/public/emptyf0/.gitignore b/tests/public/emptyf0/.gitignore
new file mode 100644
index 0000000..f721f7f
--- /dev/null
+++ b/tests/public/emptyf0/.gitignore
@@ -0,0 +1,5 @@
+.env
+*.avm
+*.prover
+*.verifier
+outputs/
diff --git a/tests/public/emptyf0/README.md b/tests/public/emptyf0/README.md
new file mode 100644
index 0000000..cb1338b
--- /dev/null
+++ b/tests/public/emptyf0/README.md
@@ -0,0 +1,13 @@
+# emptyf0.aleo
+
+## Build Guide
+
+To compile this Aleo program, run:
+```bash
+snarkvm build
+```
+
+To execute this Aleo program, run:
+```bash
+snarkvm run hello
+```
diff --git a/tests/public/emptyf0/build/main.aleo b/tests/public/emptyf0/build/main.aleo
new file mode 100644
index 0000000..69ccc85
--- /dev/null
+++ b/tests/public/emptyf0/build/main.aleo
@@ -0,0 +1,19 @@
+program emptyf0.aleo;
+
+
+
+function vanguard_helper:
+ cast true into r0 as [boolean; 1u32];
+ output r0 as [boolean; 1u32].private;
+
+
+function ex0:
+
+
+function ex1:
+ async ex1 into r0;
+ output 9u8 as u8.private;
+ output r0 as emptyf0.aleo/ex1.future;
+
+finalize ex1:
+ assert.eq true true;
diff --git a/tests/public/emptyf0/build/program.json b/tests/public/emptyf0/build/program.json
new file mode 100644
index 0000000..fa72430
--- /dev/null
+++ b/tests/public/emptyf0/build/program.json
@@ -0,0 +1,6 @@
+{
+ "program": "emptyf0.aleo",
+ "version": "0.0.0",
+ "description": "",
+ "license": "MIT"
+}
diff --git a/tests/public/emptyf0/leo.lock b/tests/public/emptyf0/leo.lock
new file mode 100644
index 0000000..c4293b3
--- /dev/null
+++ b/tests/public/emptyf0/leo.lock
@@ -0,0 +1 @@
+package = []
diff --git a/tests/public/emptyf0/program.json b/tests/public/emptyf0/program.json
new file mode 100644
index 0000000..fa72430
--- /dev/null
+++ b/tests/public/emptyf0/program.json
@@ -0,0 +1,6 @@
+{
+ "program": "emptyf0.aleo",
+ "version": "0.0.0",
+ "description": "",
+ "license": "MIT"
+}
diff --git a/tests/public/emptyf0/src/main.leo b/tests/public/emptyf0/src/main.leo
new file mode 100644
index 0000000..40bfd56
--- /dev/null
+++ b/tests/public/emptyf0/src/main.leo
@@ -0,0 +1,24 @@
+// The 'emptyf0' program.
+program emptyf0.aleo {
+ // by default, arguments without visibility are private
+ // but in finalize, they have to be public
+ transition vanguard_helper() -> [bool; 2] {
+ return [
+ label_ex0, label_ex1,
+ ];
+ }
+
+ const label_ex0: bool = true;
+ transition ex0() {
+ }
+
+ const label_ex1: bool = true;
+ transition ex1() -> u8 {
+ return 9u8 then finalize();
+ }
+ finalize ex1() {
+ assert(true);
+ }
+
+
+}
diff --git a/tests/public/magicv0/.gitignore b/tests/public/magicv0/.gitignore
new file mode 100644
index 0000000..f721f7f
--- /dev/null
+++ b/tests/public/magicv0/.gitignore
@@ -0,0 +1,5 @@
+.env
+*.avm
+*.prover
+*.verifier
+outputs/
diff --git a/tests/public/magicv0/README.md b/tests/public/magicv0/README.md
new file mode 100644
index 0000000..e01d0af
--- /dev/null
+++ b/tests/public/magicv0/README.md
@@ -0,0 +1,13 @@
+# magicv0.aleo
+
+## Build Guide
+
+To compile this Aleo program, run:
+```bash
+snarkvm build
+```
+
+To execute this Aleo program, run:
+```bash
+snarkvm run hello
+```
diff --git a/tests/public/magicv0/build/main.aleo b/tests/public/magicv0/build/main.aleo
new file mode 100644
index 0000000..6872ed3
--- /dev/null
+++ b/tests/public/magicv0/build/main.aleo
@@ -0,0 +1,15 @@
+program magicv0.aleo;
+
+
+
+function vanguard_helper:
+ cast true true into r0 as [boolean; 2u32];
+ output r0 as [boolean; 2u32].private;
+
+
+function ex0:
+ output aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc as address.private;
+
+
+function ex1:
+ output 123u8 as u8.private;
diff --git a/tests/public/magicv0/build/program.json b/tests/public/magicv0/build/program.json
new file mode 100644
index 0000000..ed151f7
--- /dev/null
+++ b/tests/public/magicv0/build/program.json
@@ -0,0 +1,6 @@
+{
+ "program": "magicv0.aleo",
+ "version": "0.0.0",
+ "description": "",
+ "license": "MIT"
+}
diff --git a/tests/public/magicv0/leo.lock b/tests/public/magicv0/leo.lock
new file mode 100644
index 0000000..c4293b3
--- /dev/null
+++ b/tests/public/magicv0/leo.lock
@@ -0,0 +1 @@
+package = []
diff --git a/tests/public/magicv0/program.json b/tests/public/magicv0/program.json
new file mode 100644
index 0000000..ed151f7
--- /dev/null
+++ b/tests/public/magicv0/program.json
@@ -0,0 +1,6 @@
+{
+ "program": "magicv0.aleo",
+ "version": "0.0.0",
+ "description": "",
+ "license": "MIT"
+}
diff --git a/tests/public/magicv0/src/main.leo b/tests/public/magicv0/src/main.leo
new file mode 100644
index 0000000..c0ce6c1
--- /dev/null
+++ b/tests/public/magicv0/src/main.leo
@@ -0,0 +1,24 @@
+// The 'magicv0' program.
+program magicv0.aleo {
+ // by default, arguments without visibility are private
+ // but in finalize, they have to be public
+ transition vanguard_helper() -> [bool; 2] {
+ return [
+ label_ex0, label_ex1,
+ ];
+ }
+
+ const label_ex0: bool = true;
+ transition ex0() -> address {
+ let a: address = aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc;
+ return a;
+ }
+
+ const label_ex1: bool = true;
+ transition ex1() -> u8 {
+ let a: u8 = 123u8;
+ return a;
+ }
+
+
+}
diff --git a/tests/public/susinst0/.gitignore b/tests/public/susinst0/.gitignore
new file mode 100644
index 0000000..f721f7f
--- /dev/null
+++ b/tests/public/susinst0/.gitignore
@@ -0,0 +1,5 @@
+.env
+*.avm
+*.prover
+*.verifier
+outputs/
diff --git a/tests/public/susinst0/README.md b/tests/public/susinst0/README.md
new file mode 100644
index 0000000..9247509
--- /dev/null
+++ b/tests/public/susinst0/README.md
@@ -0,0 +1,13 @@
+# susinst0.aleo
+
+## Build Guide
+
+To compile this Aleo program, run:
+```bash
+snarkvm build
+```
+
+To execute this Aleo program, run:
+```bash
+snarkvm run hello
+```
diff --git a/tests/public/susinst0/build/main.aleo b/tests/public/susinst0/build/main.aleo
new file mode 100644
index 0000000..a6ac725
--- /dev/null
+++ b/tests/public/susinst0/build/main.aleo
@@ -0,0 +1,21 @@
+program susinst0.aleo;
+
+
+
+function vanguard_helper:
+ cast true true true into r0 as [boolean; 3u32];
+ output r0 as [boolean; 3u32].private;
+
+
+function ex0:
+ assert.eq true true;
+
+
+function ex1:
+ add 123u8 0u8 into r0;
+ output r0 as u8.private;
+
+
+function ex2:
+ mul 123u8 1u8 into r0;
+ output r0 as u8.private;
diff --git a/tests/public/susinst0/build/program.json b/tests/public/susinst0/build/program.json
new file mode 100644
index 0000000..b9ad403
--- /dev/null
+++ b/tests/public/susinst0/build/program.json
@@ -0,0 +1,6 @@
+{
+ "program": "susinst0.aleo",
+ "version": "0.0.0",
+ "description": "",
+ "license": "MIT"
+}
diff --git a/tests/public/susinst0/leo.lock b/tests/public/susinst0/leo.lock
new file mode 100644
index 0000000..c4293b3
--- /dev/null
+++ b/tests/public/susinst0/leo.lock
@@ -0,0 +1 @@
+package = []
diff --git a/tests/public/susinst0/program.json b/tests/public/susinst0/program.json
new file mode 100644
index 0000000..b9ad403
--- /dev/null
+++ b/tests/public/susinst0/program.json
@@ -0,0 +1,6 @@
+{
+ "program": "susinst0.aleo",
+ "version": "0.0.0",
+ "description": "",
+ "license": "MIT"
+}
diff --git a/tests/public/susinst0/src/main.leo b/tests/public/susinst0/src/main.leo
new file mode 100644
index 0000000..8ebb7a6
--- /dev/null
+++ b/tests/public/susinst0/src/main.leo
@@ -0,0 +1,29 @@
+// The 'susinst0' program.
+program susinst0.aleo {
+ // by default, arguments without visibility are private
+ // but in finalize, they have to be public
+ transition vanguard_helper() -> [bool; 3] {
+ return [
+ label_ex0, label_ex1, label_ex2
+ ];
+ }
+
+ const label_ex0: bool = true;
+ transition ex0() {
+ assert(true);
+ }
+
+ const label_ex1: bool = true;
+ transition ex1() -> u8 {
+ let a: u8 = 123u8 + 0u8;
+ return a;
+ }
+
+ const label_ex2: bool = true;
+ transition ex2() -> u8 {
+ let a: u8 = 123u8 * 1u8;
+ return a;
+ }
+
+
+}
diff --git a/tests/test4.ipynb b/tests/test4.ipynb
index 1ad4284..d9ff4b6 100644
--- a/tests/test4.ipynb
+++ b/tests/test4.ipynb
@@ -26,6 +26,11 @@
"from vanguard.aleo.detectors import detector_rtcnst\n",
"from vanguard.aleo.detectors import detector_unused\n",
"from vanguard.aleo.detectors import detector_divz\n",
+ "from vanguard.aleo.detectors import detector_emptyf\n",
+ "from vanguard.aleo.detectors import detector_magicv\n",
+ "from vanguard.aleo.detectors import detector_susinst\n",
+ "from vanguard.aleo.detectors import detector_divrd\n",
+ "from vanguard.aleo.detectors import detector_downcast\n",
"\n",
"from vanguard.aleo.testing import run_test_suite"
]
@@ -46,9 +51,14 @@
],
"source": [
"# project_name = \"divz0\"\n",
- "project_name = \"infoleak0\"\n",
+ "# project_name = \"infoleak0\"\n",
"# project_name = \"unused0\"\n",
"# project_name = \"rtcnst0\"\n",
+ "# project_name = \"emptyf0\"\n",
+ "# project_name = \"magicv0\"\n",
+ "# project_name = \"susinst0\"\n",
+ "# project_name = \"divrd0\"\n",
+ "project_name = \"downcast0\"\n",
"build_path = f\"./tests/public/{project_name}/build/\"\n",
"env = AleoEnvironment.from_project(build_path)\n",
"main = env.main"
@@ -56,47 +66,57 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 6,
"id": "0dc6fcff-f8b2-44cb-8919-fda9b23c0b49",
"metadata": {},
"outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "# [debug] ret: ['{: , : }']\n",
- "# [debug] pvars: ['r0.content']\n",
- "# [debug] lines: ['output r0.content as struct_ex22.public;']\n"
- ]
- },
{
"data": {
"text/plain": [
- "(True, ['output r0.content as struct_ex22.public;'])"
+ "(True, ['cast 65530u16 into r0 as u8;'])"
]
},
- "execution_count": 8,
+ "execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "fid = \"ex22\"\n",
+ "fid = \"ex1\"\n",
"# detector_divz(env, main.id, fid, readable=True)\n",
- "detector_infoleak(env, main.id, fid, readable=True)"
+ "# detector_infoleak(env, main.id, fid, readable=True)\n",
+ "# detector_emptyf(env, main.id, fid, readable=True)\n",
+ "# detector_magicv(env, main.id, fid, readable=True)\n",
+ "# detector_susinst(env, main.id, fid, readable=True)\n",
+ "# detector_divrd(env, main.id, fid, readable=True)\n",
+ "detector_downcast(env, main.id, fid, readable=True)"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 6,
"id": "e895857f-8473-4e0e-a561-3553469ceceb",
"metadata": {},
- "outputs": [],
- "source": []
+ "outputs": [
+ {
+ "ename": "ValueError",
+ "evalue": "4 is not in list",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[6], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m,\u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mindex\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m4\u001b[39;49m\u001b[43m)\u001b[49m\n",
+ "\u001b[0;31mValueError\u001b[0m: 4 is not in list"
+ ]
+ }
+ ],
+ "source": [
+ "[1,2,3].index(4)"
+ ]
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 12,
"id": "a983f9b5-286c-4748-b2c7-b450ff0d7948",
"metadata": {},
"outputs": [
@@ -105,50 +125,32 @@
"output_type": "stream",
"text": [
"# [debug] deploy: main.aleo\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex0, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex1, expected: False, actual: False\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex2, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex3, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex4, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex5, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex6, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex7, expected: False, actual: False\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex8, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex9, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex10, expected: True, actual: True\n",
- "# [✗][test] pid: infoleak0.aleo, fid: ex11, expected: False, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex12, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex13, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex14, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex15, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex16, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex17, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex18, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex19, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex20, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex21, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex22, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex23, expected: True, actual: True\n",
- "# [✓][test] pid: infoleak0.aleo, fid: ex24, expected: False, actual: False\n",
- "# [test] accuracy: 24/25 (0.9600)\n",
+ "# [✓][test] pid: unused0.aleo, fid: ex0, expected: False, actual: False\n",
+ "# [✓][test] pid: unused0.aleo, fid: ex1, expected: True, actual: True\n",
+ "# [✓][test] pid: unused0.aleo, fid: ex2, expected: True, actual: True\n",
+ "# [✗][test] pid: unused0.aleo, fid: ex3, expected: False, actual: True\n",
+ "# [✓][test] pid: unused0.aleo, fid: ex4, expected: True, actual: True\n",
+ "# [✗][test] pid: unused0.aleo, fid: ex5, expected: False, actual: True\n",
+ "# [✓][test] pid: unused0.aleo, fid: ex6, expected: True, actual: True\n",
+ "# [test] accuracy: 5/7 (0.7143)\n",
"# [test] confusion matrix:\n",
" actual False True \n",
"expected \n",
- "False 3 1\n",
- "True 0 21\n",
+ "False 1 2\n",
+ "True 0 4\n",
"# [test] normalized confusion matrix:\n",
- " actual False True \n",
- "expected \n",
- "False 0.75 0.25\n",
- "True 0.00 1.00\n"
+ " actual False True \n",
+ "expected \n",
+ "False 0.333333 0.666667\n",
+ "True 0.000000 1.000000\n"
]
}
],
"source": [
"# r = run_test_suite(\"./tests/public/divz0/build/\", detector_divz, verbose=True)\n",
- "r = run_test_suite(\"./tests/public/infoleak0/build/\", detector_infoleak, verbose=True)\n",
+ "# r = run_test_suite(\"./tests/public/infoleak0/build/\", detector_infoleak, verbose=True)\n",
"# r = run_test_suite(\"./tests/public/rtcnst0/build/\", detector_rtcnst, verbose=True)\n",
- "# r = run_test_suite(\"./tests/public/unused0/build/\", detector_unused, verbose=True)"
+ "r = run_test_suite(\"./tests/public/unused0/build/\", detector_unused, verbose=True)"
]
},
{
diff --git a/vanguard/aleo/detectors/__init__.py b/vanguard/aleo/detectors/__init__.py
index db7ea22..9bbcda0 100644
--- a/vanguard/aleo/detectors/__init__.py
+++ b/vanguard/aleo/detectors/__init__.py
@@ -1,4 +1,9 @@
from .divz import detector_divz
from .infoleak import detector_infoleak
from .rtcnst import detector_rtcnst
-from .unused import detector_unused
\ No newline at end of file
+from .unused import detector_unused
+from .emptyf import detector_emptyf
+from .magicv import detector_magicv
+from .susinst import detector_susinst
+from .divrd import detector_divrd
+from .downcast import detector_downcast
\ No newline at end of file
diff --git a/vanguard/aleo/detectors/divrd.py b/vanguard/aleo/detectors/divrd.py
new file mode 100644
index 0000000..0515d23
--- /dev/null
+++ b/vanguard/aleo/detectors/divrd.py
@@ -0,0 +1,60 @@
+from ..grammar import *
+from ..graphs import get_dfg_edges
+
+def detector_divrd(env: AleoEnvironment, pid: str, fid: str, readable=False):
+ # initialize
+ prog: AleoProgram = env.programs[pid]
+ func: AleoFunction = prog.functions[fid]
+
+ dinsts = []
+
+ # check for statement level redundancy
+ all_insts = func.instructions + ([] if func.finalize is None else func.finalize.instructions)
+ for inst in all_insts:
+ match inst:
+ case AleoBinary() if inst.op in {AleoBinaryOp.DIV, AleoBinaryOp.DIVW}:
+ if isinstance(inst.operands[0], AleoLiteral) and isinstance(inst.operands[1], AleoLiteral):
+ # pattern 1: literal division
+ a = inst.operands[0].value
+ b = inst.operands[1].value
+ if a % b != 0:
+ dinsts.append(f"{inst}" if readable else inst)
+ else:
+ # FIXME: need to infer value, for now, just ignore
+ # dinsts.append(f"{inst}" if readable else inst)
+ pass
+
+ case _:
+ # not interested
+ pass
+
+ # pattern 2: division before multiplication
+ # FIXME: values are not tracked across transition/finalize, neither in external calls
+ # FIXME: data structures are not considered
+ div_dests = [] # tracking division destinations
+ div_lines = []
+ for inst in func.instructions:
+ match inst:
+ case AleoBinary() if inst.op in {AleoBinaryOp.DIV, AleoBinaryOp.DIVW}:
+ div_dests.append(f"{inst.regacc}")
+ div_lines.append(inst)
+ case AleoBinary() if inst.op in {AleoBinaryOp.MUL, AleoBinaryOp.MULW}:
+ ind = None
+ if f"{inst.operands[0]}" in div_dests:
+ ind = div_dests.index(f"{inst.operands[0]}")
+ elif f"{inst.operands[1]}" in div_dests:
+ ind = div_dests.index(f"{inst.operands[1]}")
+ else:
+ # do nothing
+ pass
+ if ind is not None:
+ dinsts.append(
+ (f"{div_lines[ind]}", f"{inst}") if readable else\
+ (div_lines[ind], inst)
+ )
+
+ case _:
+ # not interested
+ pass
+
+ return (len(dinsts)>0, dinsts)
\ No newline at end of file
diff --git a/vanguard/aleo/detectors/downcast.py b/vanguard/aleo/detectors/downcast.py
new file mode 100644
index 0000000..7f88033
--- /dev/null
+++ b/vanguard/aleo/detectors/downcast.py
@@ -0,0 +1,22 @@
+from ..grammar import *
+from ..graphs import get_dfg_edges
+
+def detector_downcast(env: AleoEnvironment, pid: str, fid: str, readable=False):
+ # initialize
+ prog: AleoProgram = env.programs[pid]
+ func: AleoFunction = prog.functions[fid]
+
+ dinsts = []
+
+ # check for statement level redundancy
+ all_insts = func.instructions + ([] if func.finalize is None else func.finalize.instructions)
+ for inst in all_insts:
+ match inst:
+ case AleoCast() if len(inst.operands) == 1:
+ dinsts.append(f"{inst}" if readable else inst)
+
+ case _:
+ # not interested
+ pass
+
+ return (len(dinsts)>0, dinsts)
\ No newline at end of file
diff --git a/vanguard/aleo/detectors/emptyf.py b/vanguard/aleo/detectors/emptyf.py
new file mode 100644
index 0000000..9e45515
--- /dev/null
+++ b/vanguard/aleo/detectors/emptyf.py
@@ -0,0 +1,36 @@
+from ..grammar import *
+from ..graphs import get_dfg_edges
+
+def detector_emptyf(env: AleoEnvironment, pid: str, fid: str, readable=False):
+ # initialize
+ prog: AleoProgram = env.programs[pid]
+ func: AleoFunction = prog.functions[fid]
+
+ efs = []
+
+ # check for function level redundancy
+ if len(func.instructions) == 0:
+ efs.append(f"transition {func.id}")
+
+ if func.finalize is not None:
+ if len(func.finalize.instructions) == 0:
+ efs.append(f"finalize {func.finalize.id}")
+
+ # check for statement level redundancy
+ all_insts = func.instructions + ([] if func.finalize is None else func.finalize.instructions)
+ for inst in all_insts:
+ match inst:
+ case AleoAssert():
+ g = True
+ for p in inst.operands:
+ if not isinstance(p, AleoLiteral):
+ g = False
+ break
+ if g:
+ efs.append(f"{inst}" if readable else inst)
+
+ case _:
+ # not interested
+ pass
+
+ return (len(efs)>0, efs)
\ No newline at end of file
diff --git a/vanguard/aleo/detectors/magicv.py b/vanguard/aleo/detectors/magicv.py
new file mode 100644
index 0000000..d540ffc
--- /dev/null
+++ b/vanguard/aleo/detectors/magicv.py
@@ -0,0 +1,25 @@
+from ..grammar import *
+from ..graphs import get_dfg_edges
+
+def detector_magicv(env: AleoEnvironment, pid: str, fid: str, readable=False):
+ # initialize
+ prog: AleoProgram = env.programs[pid]
+ func: AleoFunction = prog.functions[fid]
+
+ mvs = []
+
+ def mm(node):
+ match node:
+ case AleoAddressLiteral():
+ mvs.append(f"{node}" if readable else node)
+ case AleoUnsignedLiteral() | AleoSignedLiteral():
+ if node.value >= 2 or node.value <= -2:
+ mvs.append(f"{node}" if readable else node)
+ case _:
+ # not interested
+ pass
+
+ # check for magic values
+ AleoNode.visit(func, fn_pre=mm)
+
+ return (len(mvs)>0, mvs)
\ No newline at end of file
diff --git a/vanguard/aleo/detectors/susinst.py b/vanguard/aleo/detectors/susinst.py
new file mode 100644
index 0000000..d512764
--- /dev/null
+++ b/vanguard/aleo/detectors/susinst.py
@@ -0,0 +1,40 @@
+from ..grammar import *
+from ..graphs import get_dfg_edges
+
+def detector_susinst(env: AleoEnvironment, pid: str, fid: str, readable=False):
+ # initialize
+ prog: AleoProgram = env.programs[pid]
+ func: AleoFunction = prog.functions[fid]
+
+ sinsts = []
+
+ # check for statement level redundancy
+ all_insts = func.instructions + ([] if func.finalize is None else func.finalize.instructions)
+ for inst in all_insts:
+ match inst:
+ case AleoAssert():
+ if f"{inst.operands[0]}" == f"{inst.operands[1]}":
+ sinsts.append(f"{inst}" if readable else inst)
+
+ case AleoBinary():
+ match inst.op:
+ case AleoBinaryOp.ADD | AleoBinaryOp.ADDW:
+ for p in inst.operands:
+ if isinstance(p, AleoLiteral) and p.value == 0:
+ sinsts.append(f"{inst}" if readable else inst)
+ case AleoBinaryOp.SUB | AleoBinaryOp.SUBW:
+ if isinstance(inst.operands[1], AleoLiteral) and inst.operands[1].value == 0:
+ sinsts.append(f"{inst}" if readable else inst)
+ case AleoBinaryOp.MUL | AleoBinaryOp.MULW:
+ for p in inst.operands:
+ if isinstance(p, AleoLiteral) and p.value == 1:
+ sinsts.append(f"{inst}" if readable else inst)
+ case _:
+ # not interested
+ pass
+
+ case _:
+ # not interested
+ pass
+
+ return (len(sinsts)>0, sinsts)
\ No newline at end of file
diff --git a/vanguard/aleo/grammar/instructions.py b/vanguard/aleo/grammar/instructions.py
index 47e3ce8..9f998e5 100644
--- a/vanguard/aleo/grammar/instructions.py
+++ b/vanguard/aleo/grammar/instructions.py
@@ -418,6 +418,7 @@ class AleoAssert(AleoInstruction):
def from_json(node):
match node:
case ["assert", op, *operands, ";"]:
+ assert len(operands) == 2, f"Unsupported number of operands, expected: 2, got: {len(operands)}"
_op = AleoAssertOp.from_json(op)
_operands = [AleoOperand.from_json(p) for p in operands]
return AleoAssert(_op, _operands)
diff --git a/vanguard/aleo/grammar/misc.py b/vanguard/aleo/grammar/misc.py
index 27f21fd..b42a962 100644
--- a/vanguard/aleo/grammar/misc.py
+++ b/vanguard/aleo/grammar/misc.py
@@ -3,6 +3,27 @@
# primitive type of all Aleo components
class AleoNode:
+
+ @staticmethod
+ def visit(node, fn_pre=None, fn_post=None):
+ if fn_pre is not None: fn_pre(node)
+ if isinstance(node, AleoNode):
+ for p in vars(node).values():
+ AleoNode.visit(p, fn_pre=fn_pre, fn_post=fn_post)
+ elif isinstance(node, list):
+ for q in node:
+ AleoNode.visit(q, fn_pre=fn_pre, fn_post=fn_post)
+ elif isinstance(node, dict):
+ for k,v in node.items():
+ AleoNode.visit(v, fn_pre=fn_pre, fn_post=fn_post)
+ elif isinstance(node, tuple):
+ for p in node:
+ AleoNode.visit(p, fn_pre=fn_pre, fn_post=fn_post)
+ else:
+ # not interested
+ pass
+ if fn_post is not None: fn_post(node)
+
# FIXME: prevent direct initialization that is compatible with Enum child class
# NOTE: need both args and kwargs as child class also inherits Enum
def __init__(self, *args, **kwargs):