Skip to content

Commit

Permalink
added multiple new detectors
Browse files Browse the repository at this point in the history
- detector_emptyf
- detector_magicv
- detector_susinst
- detector_divrd
- detector_downcast
chyanju committed Mar 13, 2024
1 parent 975c8d8 commit 8a504ac
Showing 34 changed files with 519 additions and 62 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
- <u>Leo (**7ac50d8**) for compiling and running all benchmarks enclosed</u>
- 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,15 +52,15 @@ 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
-b BUILD, --build BUILD
project build path, default: ./
-p PID, --pid PID program id, default: <project main entrance>
-f FIDS, --fids FIDS function ids (separated by comma, no space), default: <all functions of project>
-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

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "vanguard"
version = "0.0.4"
version = "0.0.5"
authors = [
{ name="Yanju Chen", email="[email protected]" },
]
9 changes: 7 additions & 2 deletions tests/public/divrd0/build/main.aleo
Original file line number Diff line number Diff line change
@@ -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;
10 changes: 8 additions & 2 deletions tests/public/divrd0/src/main.leo
Original file line number Diff line number Diff line change
@@ -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;
}
}
5 changes: 5 additions & 0 deletions tests/public/emptyf0/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.env
*.avm
*.prover
*.verifier
outputs/
13 changes: 13 additions & 0 deletions tests/public/emptyf0/README.md
Original file line number Diff line number Diff line change
@@ -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
```
19 changes: 19 additions & 0 deletions tests/public/emptyf0/build/main.aleo
Original file line number Diff line number Diff line change
@@ -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;
6 changes: 6 additions & 0 deletions tests/public/emptyf0/build/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"program": "emptyf0.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT"
}
1 change: 1 addition & 0 deletions tests/public/emptyf0/leo.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package = []
6 changes: 6 additions & 0 deletions tests/public/emptyf0/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"program": "emptyf0.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT"
}
24 changes: 24 additions & 0 deletions tests/public/emptyf0/src/main.leo
Original file line number Diff line number Diff line change
@@ -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);
}


}
5 changes: 5 additions & 0 deletions tests/public/magicv0/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.env
*.avm
*.prover
*.verifier
outputs/
13 changes: 13 additions & 0 deletions tests/public/magicv0/README.md
Original file line number Diff line number Diff line change
@@ -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
```
15 changes: 15 additions & 0 deletions tests/public/magicv0/build/main.aleo
Original file line number Diff line number Diff line change
@@ -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;
6 changes: 6 additions & 0 deletions tests/public/magicv0/build/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"program": "magicv0.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT"
}
1 change: 1 addition & 0 deletions tests/public/magicv0/leo.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package = []
6 changes: 6 additions & 0 deletions tests/public/magicv0/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"program": "magicv0.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT"
}
24 changes: 24 additions & 0 deletions tests/public/magicv0/src/main.leo
Original file line number Diff line number Diff line change
@@ -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;
}


}
5 changes: 5 additions & 0 deletions tests/public/susinst0/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.env
*.avm
*.prover
*.verifier
outputs/
13 changes: 13 additions & 0 deletions tests/public/susinst0/README.md
Original file line number Diff line number Diff line change
@@ -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
```
21 changes: 21 additions & 0 deletions tests/public/susinst0/build/main.aleo
Original file line number Diff line number Diff line change
@@ -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;
6 changes: 6 additions & 0 deletions tests/public/susinst0/build/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"program": "susinst0.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT"
}
1 change: 1 addition & 0 deletions tests/public/susinst0/leo.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package = []
6 changes: 6 additions & 0 deletions tests/public/susinst0/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"program": "susinst0.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT"
}
29 changes: 29 additions & 0 deletions tests/public/susinst0/src/main.leo
Original file line number Diff line number Diff line change
@@ -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;
}


}
108 changes: 55 additions & 53 deletions tests/test4.ipynb
Original file line number Diff line number Diff line change
@@ -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,57 +51,72 @@
],
"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"
]
},
{
"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: ['{<vanguard.aleo.grammar.misc.AleoIdentifier object at 0x120ad4e30>: <vanguard.aleo.abstract.AleoAbstractLiteral object at 0x120a55fa0>, <vanguard.aleo.grammar.misc.AleoIdentifier object at 0x120ad4e90>: <vanguard.aleo.abstract.AleoAbstractLiteral object at 0x120a57e30>}']\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)"
]
},
{
7 changes: 6 additions & 1 deletion vanguard/aleo/detectors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from .divz import detector_divz
from .infoleak import detector_infoleak
from .rtcnst import detector_rtcnst
from .unused import detector_unused
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
60 changes: 60 additions & 0 deletions vanguard/aleo/detectors/divrd.py
Original file line number Diff line number Diff line change
@@ -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)
22 changes: 22 additions & 0 deletions vanguard/aleo/detectors/downcast.py
Original file line number Diff line number Diff line change
@@ -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)
36 changes: 36 additions & 0 deletions vanguard/aleo/detectors/emptyf.py
Original file line number Diff line number Diff line change
@@ -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)
25 changes: 25 additions & 0 deletions vanguard/aleo/detectors/magicv.py
Original file line number Diff line number Diff line change
@@ -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)
40 changes: 40 additions & 0 deletions vanguard/aleo/detectors/susinst.py
Original file line number Diff line number Diff line change
@@ -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)
1 change: 1 addition & 0 deletions vanguard/aleo/grammar/instructions.py
Original file line number Diff line number Diff line change
@@ -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)
21 changes: 21 additions & 0 deletions vanguard/aleo/grammar/misc.py
Original file line number Diff line number Diff line change
@@ -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):

0 comments on commit 8a504ac

Please sign in to comment.