From 82d063a1966c1591bbe46e7e78b45a715e20f42b Mon Sep 17 00:00:00 2001 From: Yanju Chen Date: Tue, 5 Mar 2024 13:20:05 -0800 Subject: [PATCH] supported new grammar and unify env creation --- README.md | 4 +- tests/environment-test.ipynb | 167 ++++++++++++++++++++++++++ tests/parser-test.ipynb | 2 +- tests/public/divz0/src/main.leo | 2 +- tests/scripts/parsing.py | 2 +- tests/scripts/test-divz.py | 2 +- tests/scripts/test-infoleak.py | 2 +- tests/scripts/test-rtcnst.py | 2 +- tests/scripts/test-unused.py | 2 +- tests/test4.ipynb | 81 ++++++------- vanguard/aleo/common.py | 2 +- vanguard/aleo/grammar/blocks.py | 48 +++++--- vanguard/aleo/grammar/instructions.py | 84 +++++++++++++ vanguard/aleo/grammar/literals.py | 42 +++++++ vanguard/aleo/grammar/misc.py | 72 ++++++++++- vanguard/aleo/grammar/types.py | 36 ++++++ vanguard/aleo/testing.py | 2 +- 17 files changed, 479 insertions(+), 73 deletions(-) create mode 100644 tests/environment-test.ipynb diff --git a/README.md b/README.md index f0c9f48..f2844ec 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ from .vanguard.aleo.detectors import detector_divz project_name = "divz0" function_name = "ex1" build_path = f"./tests/public/{project_name}/build/" -env = AleoEnvironment(build_path) # load project +env = AleoEnvironment.from_project(build_path) # load project detector_divz(env, env.main.id, function_name, readable=True) # detect ``` @@ -140,7 +140,7 @@ from vanguard.aleo.detectors import detector_divz project_name = "divz0" function_name = "ex1" build_path = f"./tests/public/{project_name}/build/" -env = AleoEnvironment(build_path) # load project +env = AleoEnvironment.from_project(build_path) # load project detector_divz(env, env.main.id, function_name, readable=True) # detect ``` diff --git a/tests/environment-test.ipynb b/tests/environment-test.ipynb new file mode 100644 index 0000000..7594ece --- /dev/null +++ b/tests/environment-test.ipynb @@ -0,0 +1,167 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "0c1a1d20-18ec-451f-a739-eddb4c4265cf", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# parsing: treasure_hunt_v006.aleo ... 0.36554503440856934s\n", + "# parsing: aleo_monopoly_workshop.aleo ... 0.1255810260772705s\n", + "# parsing: treasure_hunt_v010.aleo ... 0.24871206283569336s\n", + "# parsing: zk_sra_encryption_v0_0_2.aleo ... 0.16360116004943848s\n", + "# parsing: aleo_monopoly_workshop4.aleo ... 0.1220407485961914s\n", + "# parsing: football_game_v008.aleo ... 0.5778369903564453s\n", + "# parsing: uniswap_v5.aleo ... 0.22901225090026855s\n", + "# parsing: wheres_alex_v018.aleo ... 0.12906479835510254s\n", + "# parsing: aleo_name_service_registry_v2.aleo ... 0.2705061435699463s\n", + "# parsing: aleo_monopoly_game4.aleo ... 0.10615396499633789s\n", + "# parsing: arcane_rfq_amm_v000004.aleo ... 0.15807294845581055s\n", + "# parsing: aleo_monopoly_workshop8.aleo ... 0.17359280586242676s\n", + "# parsing: aleo_monopoly_workshop10.aleo ... 0.16000795364379883s\n", + "# parsing: football_game_v004.aleo ... 0.47535204887390137s\n", + "# parsing: who_is_dash_pash_v20203.aleo ... 0.12885785102844238s\n", + "# parsing: wheres_alex_v014.aleo ... 0.14920496940612793s\n", + "# parsing: football_game_v012.aleo ... 0.467663049697876s\n", + "# parsing: tyron_app_test1.aleo ... 0.12160015106201172s\n", + "# parsing: distrofund_private_transfer_v2.aleo ... 0.2230231761932373s\n", + "# parsing: wheres_alex_v015.aleo ... 0.12886977195739746s\n", + "# parsing: football_game_v005.aleo ... 0.5462970733642578s\n", + "# parsing: zk_deck_shuffle_v0_0_1.aleo ... 3.310209035873413s\n", + "# parsing: aleo_monopoly_workshop9.aleo ... 0.4012451171875s\n", + "# parsing: arcane_rfq_amm_v000005.aleo ... 0.14769268035888672s\n", + "# parsing: aleo_name_service_registry_v3.aleo ... 0.24764513969421387s\n", + "# parsing: wheres_the_babycat.aleo ... 0.12900996208190918s\n", + "# parsing: wheres_alex_v019.aleo ... 0.15206503868103027s\n", + "# parsing: football_game_v009.aleo ... 0.5451600551605225s\n", + "# parsing: aleo_monopoly_workshop5.aleo ... 0.1286182403564453s\n", + "# parsing: credits.aleo ... 0.07400774955749512s\n", + "# parsing: treasure_hunt_v007.aleo ... 0.3282780647277832s\n", + "# parsing: council_v0001.aleo ... 0.10122108459472656s\n", + "# parsing: arcane_rfq_amm_v000002.aleo ... 0.24701595306396484s\n", + "# parsing: aleoswap05.aleo ... 0.324937105178833s\n", + "# parsing: aleo_game_shop.aleo ... 0.14039397239685059s\n", + "# parsing: football_game_v002.aleo ... 0.32152605056762695s\n", + "# parsing: wheres_alex_v012.aleo ... 0.1226961612701416s\n", + "# parsing: aleo_store_nft.aleo ... 0.16280078887939453s\n", + "# parsing: whos_the_father_v002.aleo ... 0.15648913383483887s\n", + "# parsing: graph_coloring_v1.aleo ... 0.9867310523986816s\n", + "# parsing: whoes_the_dragon_v01.aleo ... 0.20185399055480957s\n", + "# parsing: aleo_monopoly_workshop2.aleo ... 0.11683821678161621s\n", + "# parsing: zk_bitwise_stack_v0_0_1.aleo ... 0.4006638526916504s\n", + "# parsing: distrofund_private_transfer.aleo ... 0.2171032428741455s\n", + "# parsing: wheres_luna_v020.aleo ... 0.1642930507659912s\n", + "# parsing: aleo_monopoly_workshop3.aleo ... 0.12447500228881836s\n", + "# parsing: king_of_cat_v001.aleo ... 0.12898683547973633s\n", + "# parsing: treasure_hunt_v001.aleo ... 0.2535240650177002s\n", + "# parsing: whos_the_father_v003.aleo ... 0.12888002395629883s\n", + "# parsing: graph_coloring.aleo ... 1.1264252662658691s\n", + "# parsing: wheres_alex_v013.aleo ... 0.12445330619812012s\n", + "# parsing: aleo_monopoly_game16.aleo ... 0.1283130645751953s\n", + "# parsing: arcane_rfq_amm_v000003.aleo ... 0.14718389511108398s\n", + "# parsing: zk_ml_dna_v0.aleo ... 0.15928435325622559s\n", + "# parsing: double_color_ball.aleo ... 2.7822608947753906s\n", + "# parsing: wheres_alex_v010.aleo ... 0.11071991920471191s\n", + "# parsing: lymphography_decision_tree_v1.aleo ... 0.17121195793151855s\n", + "# parsing: arcane_amm_v2_0.aleo ... 0.2006239891052246s\n", + "# parsing: zk_bitwise_stack_v0_0_3.aleo ... 0.7765522003173828s\n", + "# parsing: imma_find_alex_v01.aleo ... 0.13179302215576172s\n", + "# parsing: sklearn_mlp_mnist_1.aleo ... 0.12671494483947754s\n", + "# parsing: treasure_hunt_v002.aleo ... 0.257781982421875s\n", + "# parsing: wheres_luna_v019.aleo ... 0.12881684303283691s\n", + "# parsing: whos_the_father_v001.aleo ... 0.12896108627319336s\n", + "# parsing: treasure_hunt_v003.aleo ... 0.29941868782043457s\n", + "# parsing: zk_bitwise_stack_v0_0_2.aleo ... 0.3985929489135742s\n", + "# parsing: wheres_jojo_v008.aleo ... 0.12965607643127441s\n", + "# parsing: arcane_rfq_amm_v000001.aleo ... 0.16470789909362793s\n", + "# parsing: zk_ml_dna_1700237585_v0.aleo ... 0.15587306022644043s\n", + "# parsing: aleoswap06.aleo ... 0.3032219409942627s\n", + "# parsing: nft_store_yong.aleo ... 0.16216278076171875s\n", + "# parsing: wheres_alex_v011.aleo ... 0.10870790481567383s\n", + "# parsing: football_random_v011.aleo ... 0.4026451110839844s\n", + "# parsing: testalphav1x1.aleo ... 0.4599008560180664s\n", + "# parsing: zk_bitwise_stack_v0_0_5.aleo ... 0.9710831642150879s\n", + "# parsing: hialstestv1.aleo ... 0.3415040969848633s\n", + "# parsing: what_does_gary_do_v001.aleo ... 0.1300978660583496s\n", + "# parsing: aleo_monopoly_workshop6.aleo ... 0.150360107421875s\n", + "# parsing: treasure_hunt_v004.aleo ... 0.2849142551422119s\n", + "# parsing: zk_ml_dna_1700246715_v0.aleo ... 0.15957093238830566s\n", + "# parsing: football_game_v010.aleo ... 0.5442087650299072s\n", + "# parsing: wheres_alex_v016.aleo ... 0.12591171264648438s\n", + "# parsing: football_game_v006.aleo ... 0.5015170574188232s\n", + "# parsing: arcane_rfq_amm_v000006.aleo ... 0.17210102081298828s\n", + "# parsing: treasure_hunt_v008.aleo ... 0.2880980968475342s\n", + "# parsing: aleo_name_service_registry_v1.aleo ... 0.2518031597137451s\n", + "# parsing: treasure_hunt_v009.aleo ... 0.3172299861907959s\n", + "# parsing: lymphography_xgboost_v1.aleo ... 0.3400380611419678s\n", + "# parsing: football_game_v007.aleo ... 0.5114998817443848s\n", + "# parsing: wheres_alex_v017.aleo ... 0.12790989875793457s\n", + "# parsing: wheres_alex_probably_weeds.aleo ... 0.1284809112548828s\n", + "# parsing: treasure_hunt_v005.aleo ... 0.3078649044036865s\n", + "# parsing: zk_sra_encryption_v0_0_1.aleo ... 0.0902097225189209s\n", + "# parsing: twoalkilining.aleo ... 0.1731257438659668s\n", + "# parsing: zkhack_mnist_v2.aleo ... 0.1536550521850586s\n", + "# parsing: wheres_joe_v019.aleo ... 0.13042306900024414s\n", + "# parsing: wheres_alex_by_joey11_v1.aleo ... 0.12970590591430664s\n", + "# parsing: aleo_monopoly_workshop7.aleo ... 0.12551403045654297s\n", + "# parsing: zk_bitwise_stack_v0_0_4.aleo ... 0.7628638744354248s\n", + "# parsing: alphaswap_v1.aleo ... 0.5072779655456543s\n" + ] + } + ], + "source": [ + "import os\n", + "import time\n", + "os.chdir(\"..\")\n", + "\n", + "from vanguard.aleo.grammar import AleoEnvironment\n", + "\n", + "# for dp, _, fns in os.walk(\"tests/explorer/haruka/\"):\n", + "for dp, _, fns in os.walk(\"tests/explorer/aleo/\"):\n", + " for fn in fns:\n", + " p = os.path.abspath(os.path.join(dp, fn))\n", + " # print(f\"# parsing: {p} ... \", end=\"\")\n", + " print(f\"# parsing: {fn} ... \", end=\"\")\n", + " s = time.time()\n", + "\n", + " _env = AleoEnvironment.from_program(p)\n", + " \n", + " e = time.time()\n", + " print(f\"{e-s}s\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c75a2be4-e814-40fc-a128-8d879df646b5", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/parser-test.ipynb b/tests/parser-test.ipynb index 757bb4f..cae7e00 100644 --- a/tests/parser-test.ipynb +++ b/tests/parser-test.ipynb @@ -89,7 +89,7 @@ "lexer = AleoLexer(input_stream)\n", "stream = CommonTokenStream(lexer)\n", "parser = AleoParser(stream)\n", - "tree = parser.start()\n" + "tree = parser.start()" ] }, { diff --git a/tests/public/divz0/src/main.leo b/tests/public/divz0/src/main.leo index 7117c09..ad0976b 100644 --- a/tests/public/divz0/src/main.leo +++ b/tests/public/divz0/src/main.leo @@ -87,7 +87,7 @@ program divz0.aleo { // compilable, runnable // label: bad - const label_ex7: bool = false; + const label_ex7: bool = true; transition ex7() -> u8 { let a: u8 = 225u8; let b: u8 = 0u8; diff --git a/tests/scripts/parsing.py b/tests/scripts/parsing.py index 114a9ac..31371ec 100644 --- a/tests/scripts/parsing.py +++ b/tests/scripts/parsing.py @@ -3,6 +3,6 @@ if __name__ == "__main__": project_name = "divz0" build_path = f"./tests/public/{project_name}/build/" - env = AleoEnvironment(build_path) + env = AleoEnvironment.from_project(build_path) main = env.main print("# Done.") \ No newline at end of file diff --git a/tests/scripts/test-divz.py b/tests/scripts/test-divz.py index 4515bd8..c37c799 100644 --- a/tests/scripts/test-divz.py +++ b/tests/scripts/test-divz.py @@ -4,7 +4,7 @@ if __name__ == "__main__": project_name = "divz0" build_path = f"./tests/public/{project_name}/build/" - env = AleoEnvironment(build_path) + env = AleoEnvironment.from_project(build_path) main = env.main fid = "ex0" res, info = detector_divz(env, main.id, fid) diff --git a/tests/scripts/test-infoleak.py b/tests/scripts/test-infoleak.py index cc3deaa..9efcf91 100644 --- a/tests/scripts/test-infoleak.py +++ b/tests/scripts/test-infoleak.py @@ -4,7 +4,7 @@ if __name__ == "__main__": project_name = "infoleak0" build_path = f"./tests/public/{project_name}/build/" - env = AleoEnvironment(build_path) + env = AleoEnvironment.from_project(build_path) main = env.main fid = "ex0" diff --git a/tests/scripts/test-rtcnst.py b/tests/scripts/test-rtcnst.py index 360bfb2..1e1d464 100644 --- a/tests/scripts/test-rtcnst.py +++ b/tests/scripts/test-rtcnst.py @@ -4,7 +4,7 @@ if __name__ == "__main__": project_name = "rtcnst0" build_path = f"./tests/public/{project_name}/build/" - env = AleoEnvironment(build_path) + env = AleoEnvironment.from_project(build_path) main = env.main fid = "ex0" res, info = detector_rtcnst(env, main.id, fid) diff --git a/tests/scripts/test-unused.py b/tests/scripts/test-unused.py index 704a8d9..56cf781 100644 --- a/tests/scripts/test-unused.py +++ b/tests/scripts/test-unused.py @@ -4,7 +4,7 @@ if __name__ == "__main__": project_name = "unused0" build_path = f"./tests/public/{project_name}/build/" - env = AleoEnvironment(build_path) + env = AleoEnvironment.from_project(build_path) main = env.main fid = "ex0" diff --git a/tests/test4.ipynb b/tests/test4.ipynb index 019f7d2..bc29c2e 100644 --- a/tests/test4.ipynb +++ b/tests/test4.ipynb @@ -15,7 +15,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "b34815c6-9610-4ef1-a7d2-4ee62cd30ae7", "metadata": {}, "outputs": [], @@ -40,18 +40,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "# [debug] deploy: main.aleo\n", - "# [debug] deploy: helpers.aleo\n" + "# [debug] deploy: main.aleo\n" ] } ], "source": [ - "project_name = \"divz0\"\n", - "# project_name = \"infoleak0\"\n", + "# project_name = \"divz0\"\n", + "project_name = \"infoleak0\"\n", "# project_name = \"unused0\"\n", "# project_name = \"rtcnst0\"\n", "build_path = f\"./tests/public/{project_name}/build/\"\n", - "env = AleoEnvironment(build_path)\n", + "env = AleoEnvironment.from_project(build_path)\n", "main = env.main" ] }, @@ -73,7 +72,7 @@ } ], "source": [ - "fid = \"ex1\"\n", + "fid = \"ex5\"\n", "detector_infoleak(env, main.id, fid, readable=True)" ] }, @@ -87,7 +86,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "id": "a983f9b5-286c-4748-b2c7-b450ff0d7948", "metadata": {}, "outputs": [ @@ -96,50 +95,48 @@ "output_type": "stream", "text": [ "# [debug] deploy: main.aleo\n", - "# [debug] deploy: helpers.aleo\n", - "# [✓][test] pid: divz0.aleo, fid: ex0, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex1, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex2, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex3, expected: True, actual: True\n", - "# [✗][test] pid: divz0.aleo, fid: ex4, expected: False, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex5, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex6, expected: True, actual: True\n", - "# [✗][test] pid: divz0.aleo, fid: ex7, expected: False, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex8, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex9, expected: False, actual: False\n", - "# [✓][test] pid: divz0.aleo, fid: ex10, expected: False, actual: False\n", - "# [✓][test] pid: divz0.aleo, fid: ex11, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex12, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex13, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex14, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex15, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex16, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex17, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex18, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex19, expected: True, actual: True\n", - "# [✗][test] pid: divz0.aleo, fid: ex20, expected: True, actual: False\n", - "# [✓][test] pid: divz0.aleo, fid: ex21, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex22, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex23, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex24, expected: True, actual: True\n", - "# [✓][test] pid: divz0.aleo, fid: ex25, expected: True, actual: True\n", - "# [test] accuracy: 23/26 (0.8846)\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: False\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex6, expected: True, actual: False\n", + "# [✓][test] pid: infoleak0.aleo, fid: ex7, expected: False, actual: False\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex8, expected: True, actual: False\n", + "# [✓][test] pid: infoleak0.aleo, fid: ex9, expected: True, actual: True\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex10, expected: True, actual: False\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex11, expected: False, actual: True\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex12, expected: True, actual: False\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex13, expected: True, actual: False\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: False\n", + "# [✓][test] pid: infoleak0.aleo, fid: ex18, expected: True, actual: True\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex19, expected: True, actual: False\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex20, expected: True, actual: False\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex21, expected: True, actual: False\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex22, expected: True, actual: False\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex23, expected: True, actual: False\n", + "# [✗][test] pid: infoleak0.aleo, fid: ex24, expected: True, actual: False\n", + "# [test] accuracy: 11/25 (0.4400)\n", "# [test] confusion matrix:\n", " actual False True \n", "expected \n", - "False 2 2\n", - "True 1 21\n", + "False 2 1\n", + "True 13 9\n", "# [test] normalized confusion matrix:\n", " actual False True \n", "expected \n", - "False 0.500000 0.500000\n", - "True 0.045455 0.954545\n" + "False 0.666667 0.333333\n", + "True 0.590909 0.409091\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/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/rtcnst0/build/\", detector_rtcnst, verbose=True)\n", "# r = run_test_suite(\"./tests/public/unused0/build/\", detector_unused, verbose=True)" ] diff --git a/vanguard/aleo/common.py b/vanguard/aleo/common.py index dcb1826..bc2f038 100644 --- a/vanguard/aleo/common.py +++ b/vanguard/aleo/common.py @@ -43,7 +43,7 @@ def detect(build_path: Union[str, Path], pid: str=None, fids: List=None, detecto from .grammar import AleoEnvironment from . import detectors as dlib - env = AleoEnvironment(build_path) + env = AleoEnvironment.from_project(build_path) _detector = getattr(dlib, "detector_infoleak") if detector is None else getattr(dlib, f"detector_{detector}") prog = env.main if pid is None else env.programs[pid] diff --git a/vanguard/aleo/grammar/blocks.py b/vanguard/aleo/grammar/blocks.py index 800c84a..1c503a6 100644 --- a/vanguard/aleo/grammar/blocks.py +++ b/vanguard/aleo/grammar/blocks.py @@ -9,32 +9,50 @@ from .misc import * class AleoEnvironment(AleoNode): - def __init__(self, build_path, main_file: str="main.aleo"): - self.programs: dict[str, AleoProgram] = {} - self.main = None - self.load(build_path, main_file=main_file) - # load the entire project - def load(self, build_path: Union[str, Path], main_file: str="main.aleo"): + @staticmethod + def from_project(build_path: Union[str, Path], main_file: str="main.aleo"): + """Create an environment from a project build path""" path = build_path if isinstance(build_path, Path) else Path(build_path) + _programs = {} + # look for main.aleo and deploy print(f"# [debug] deploy: {main_file}") main_path = path / main_file main_json = aleo2json(main_path) - self.main = self.deploy(main_json) + assert main_json[0] == "start", f"Unsupported source of start, got: {main_json}" + _main = AleoProgram.from_json(main_json[1]) + _programs[_main.id] = _main + # look for imports and deploy imports_path = path / "imports" for fp_path in list(imports_path.glob("*.aleo")): print(f"# [debug] deploy: {fp_path.name}") fp_json = aleo2json(fp_path) - self.deploy(fp_json) - - # deploy a single Aleo program - def deploy(self, node: list) -> str: - assert node[0] == "start", f"Unsupported source of start, got: {node}" - p = AleoProgram.from_json(node[1]) - self.programs[p.id] = p - return p + assert fp_json[0] == "start", f"Unsupported source of start, got: {fp_json}" + fp_prog = AleoProgram.from_json(fp_json[1]) + _programs[fp_prog.id] = fp_prog + + # create environment and return + return AleoEnvironment(_programs, _main) + + @staticmethod + def from_program(main_path: Union[str, Path]): + """Create an environment from a single program, ignoring all dependencies (usually for debugging)""" + _programs = {} + + # load and deploy + main_json = aleo2json(main_path) + assert main_json[0] == "start", f"Unsupported source of start, got: {main_json}" + _main = AleoProgram.from_json(main_json[1]) + _programs[_main.id] = _main + + # create environment and return + return AleoEnvironment(_programs, _main) + + def __init__(self, programs, main): + self.programs = programs + self.main = main def resolve_function(self, pid, callee): _pid = None diff --git a/vanguard/aleo/grammar/instructions.py b/vanguard/aleo/grammar/instructions.py index cf05bc6..8bd9f55 100644 --- a/vanguard/aleo/grammar/instructions.py +++ b/vanguard/aleo/grammar/instructions.py @@ -24,6 +24,10 @@ def from_json(node): return AleoRemove.from_json(node[1]) case ["command", ["xawait", *_]]: return AleoAwait.from_json(node[1]) + case ["command", ["branch", *_]]: + return AleoBranch.from_json(node[1]) + case ["command", ["position", *_]]: + return AleoPosition.from_json(node[1]) case _: raise NotImplementedError(f"Unsupported json component, got: {node}") @@ -195,6 +199,48 @@ def __init__(self, regacc, **kwargs): def __str__(self): return f"await {self.regacc};" + +class AleoBranch(AleoCommand): + + @staticmethod + def from_json(node): + match node: + case ["branch", op, *operands, "to", label, ";"]: + assert len(operands) == 2, f"Unsupported number of operands, expected: 2, got: {len(operands)}" + _op = AleoBranchOp.from_json(op) + _operands = [ AleoOperand.from_json(p) for p in operands ] + _label = AleoLabel.from_json(label) + return AleoBranch(_op, _operands, _label) + case _: + raise NotImplementedError(f"Unsupported json component, got: {node}") + + def __init__(self, op, operands, label, **kwargs): + super().__init__(**kwargs) + self.op = op + self.operands = operands + self.label = label + + def __str__(self): + _operands = " ".join([str(p) for p in self.operands]) + return f"{self.op} {_operands} to {self.label};" + +class AleoPosition(AleoCommand): + + @staticmethod + def from_json(node): + match node: + case ["position", "position", label, ";"]: + _label = AleoLabel.from_json(label) + return AleoPosition(_label) + case _: + raise NotImplementedError(f"Unsupported json component, got: {node}") + + def __init__(self, label, **kwargs): + super().__init__(**kwargs) + self.label = label + + def __str__(self): + return f"position {self.label};" class AleoInstruction(AleoCommand): @@ -221,6 +267,8 @@ def from_json(inst): return AleoHash.from_json(inst[1]) case ["instruction", ["sign_verify", *_]]: return AleoSignVerify.from_json(inst[1]) + case ["instruction", ["commit", *_e]]: + return AleoCommit.from_json(inst[1]) case _: raise NotImplementedError(f"Unsupported json component, got: {inst}") @@ -504,6 +552,7 @@ class AleoSignVerify(AleoInstruction): def from_json(node): match node: case ["sign_verify", ["sign_verify_op", *_], *operands, "into", regacc, ";"]: + assert len(operands) == 3, f"Unsupported number of operands, expected: 3, got: {len(operands)}" _operands = [ AleoOperand.from_json(p) for p in operands ] _regacc = AleoRegisterAccess.from_json(regacc) return AleoSignVerify(_operands, _regacc) @@ -518,3 +567,38 @@ def __init__(self, operands, regacc, **kwargs): def __str__(self): _operands = " ".join([f"{p}" for p in self.operands]) return f"sign.verify {_operands} into {self.regacc};" + +class AleoCommit(AleoInstruction): + + @staticmethod + def from_json(node): + match node: + case ["commit", op, *operands, "into", regacc, "as", type, ";"]: + _op = AleoCommitOp.from_json(op) + _operands = [ AleoOperand.from_json(p) for p in operands ] + _regacc = AleoRegisterAccess.from_json(regacc) + # special parsing for types, as they don't inherit the same super class + _type = None + match type: + case ["address_type", *_]: + _type = AleoAddressType.from_json(type) + case ["field_type", *_]: + _type = AleoFieldType.from_json(type) + case ["group_type", *_]: + _type = AleoGroupType.from_json(type) + case _: + raise NotImplementedError(f"Unsupported type for commit, got: {type}") + return AleoCommit(_op, _operands, _regacc, _type) + case _: + raise NotImplementedError(f"Unsupported json component, got: {node}") + + def __init__(self, op, operands, regacc, type, **kwargs): + super().__init__(**kwargs) + self.op = op + self.operands = operands + self.regacc = regacc + self.type = type + + def __str__(self): + _operands = " ".join([f"{p}" for p in self.operands]) + return f"{self.op} {_operands} into {self.regacc} as {self.type};" \ No newline at end of file diff --git a/vanguard/aleo/grammar/literals.py b/vanguard/aleo/grammar/literals.py index 08a552e..05c2f0a 100644 --- a/vanguard/aleo/grammar/literals.py +++ b/vanguard/aleo/grammar/literals.py @@ -52,6 +52,10 @@ def from_json(node): return AleoIntegerLiteral.from_json(node[1]) case ["arithmetic_literal", ["field_literal", *_]]: return AleoFieldLiteral.from_json(node[1]) + case ["arithmetic_literal", ["group_literal", *_]]: + return AleoGroupLiteral.from_json(node[1]) + case ["arithmetic_literal", ["scalar_literal", *_]]: + return AleoScalarLiteral.from_json(node[1]) case _: raise NotImplementedError(f"Unsupported json component, got: {node}") @@ -122,6 +126,44 @@ def __init__(self, *args, **kwargs): def __str__(self): return f"{self.value}{self.type}" +class AleoGroupLiteral(AleoArithmeticLiteral): + + @staticmethod + def from_json(node): + match node: + case ["group_literal", *digits, type]: + from .types import AleoGroupType + v = int("".join(digits)) + _type =AleoGroupType.from_json(type) + return AleoGroupLiteral(v, _type) + case _: + raise NotImplementedError(f"Unsupported json component, got: {node}") + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def __str__(self): + return f"{self.value}{self.type}" + +class AleoScalarLiteral(AleoArithmeticLiteral): + + @staticmethod + def from_json(node): + match node: + case ["scalar_literal", *digits, type]: + from .types import AleoScalarType + v = int("".join(digits)) + _type =AleoScalarType.from_json(type) + return AleoScalarLiteral(v, _type) + case _: + raise NotImplementedError(f"Unsupported json component, got: {node}") + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def __str__(self): + return f"{self.value}{self.type}" + class AleoSignedLiteral(AleoIntegerLiteral): @staticmethod diff --git a/vanguard/aleo/grammar/misc.py b/vanguard/aleo/grammar/misc.py index 26b8e07..129a230 100644 --- a/vanguard/aleo/grammar/misc.py +++ b/vanguard/aleo/grammar/misc.py @@ -114,6 +114,18 @@ def __eq__(self, other): return f"{self.id}" == other else: return False + +class AleoLabel(AleoIdentifier): + # NOTE: AleoLabel is similar to AleoIdentifier and so inherits it, for now + + @staticmethod + def from_json(node): + match node: + case ["label", id]: + return AleoLabel(id) + case _: + raise NotImplementedError(f"Unsupported json component, got: {node}") + class AleoRegister(AleoNode): @@ -198,12 +210,13 @@ class AleoAccessByIndex(AleoRegisterAccessor): def from_json(node): from .literals import AleoUnsignedLiteral match node: - case ["access_by_index", "[", idx, "]"]: + # there could be only 1 digit, which should be matched to the second case not the first + case ["access_by_index", "[", idx, "]"] if isinstance(idx, list): _idx = AleoUnsignedLiteral.from_json(idx) return AleoAccessByIndex(_idx) - # case ["access_by_index", "[", *digits, "]"]: - # _idx = AleoUnsignedLiteral.from_json(["unsigned_literal"] + digits + [["unsigned_type", "u32"]]) - # return AleoAccessByIndex(_idx) + case ["access_by_index", "[", *digits, "]"]: + _idx = AleoUnsignedLiteral.from_json(["unsigned_literal"] + digits + [["unsigned_type", "u32"]]) + return AleoAccessByIndex(_idx) case _: raise NotImplementedError(f"Unsupported json component, got: {node}") @@ -509,4 +522,53 @@ def from_json(s): raise NotImplementedError(f"Unsupported json component, got: {s}") def __str__(self): - return f"hash.{self.name.lower()}" \ No newline at end of file + return f"hash.{self.name.lower()}" + +class AleoCommitOp(AleoNode, Enum): + + BHP256 = 0 + BHP512 = 1 + BHP768 = 2 + BHP1024 = 3 + + PED64 = 4 + PED128 = 5 + + @staticmethod + def from_json(s): + match s: + case ["commit_op", "commit", ".", op]: + _s = op.upper() + for p in AleoCommitOp: + if _s == p.name: + return p + raise NotImplementedError(f"Unsupported commit op, got: {op}") + case _: + raise NotImplementedError(f"Unsupported json component, got: {s}") + + def __str__(self): + return f"commit.{self.name.lower()}" + +class AleoBranchOp(AleoNode, Enum): + + NEQ = 0 + EQ = 1 + + @staticmethod + def from_json(s): + match s: + case ["branch_op", "branch", ".", "eq"]: + return AleoBranchOp.EQ + case ["branch_op", "branch", ".", "neq"]: + return AleoBranchOp.NEQ + case _: + raise NotImplementedError(f"Unsupported json component, got: {s}") + + def __str__(self): + match self.value: + case AleoBranchOp.NEQ.value: + return "branch.neq" + case AleoBranchOp.EQ.value: + return "branch.eq" + case _: + raise NotImplementedError(f"Unsupported branch op, got: {self.value}") \ No newline at end of file diff --git a/vanguard/aleo/grammar/types.py b/vanguard/aleo/grammar/types.py index 47a7fe1..be0ff4c 100644 --- a/vanguard/aleo/grammar/types.py +++ b/vanguard/aleo/grammar/types.py @@ -151,6 +151,10 @@ def from_json(node): return AleoIntegerType.from_json(node[1]) case ["arithmetic_type", ["field_type", *_]]: return AleoFieldType.from_json(node[1]) + case ["arithmetic_type", ["group_type", *_]]: + return AleoGroupType.from_json(node[1]) + case ["arithmetic_type", ["scalar_type", *_]]: + return AleoScalarType.from_json(node[1]) case _: raise NotImplementedError(f"Unsupported json component, got: {node}") @@ -196,6 +200,38 @@ def __init__(self, **kwargs): def __str__(self): return "field" +class AleoGroupType(AleoArithmeticType): + + @staticmethod + def from_json(node): + match node: + case ["group_type", "group"]: + return AleoGroupType() + case _: + raise NotImplementedError(f"Unsupported json component, got: {node}") + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def __str__(self): + return "group" + +class AleoScalarType(AleoArithmeticType): + + @staticmethod + def from_json(node): + match node: + case ["scalar_type", "scalar"]: + return AleoScalarType() + case _: + raise NotImplementedError(f"Unsupported json component, got: {node}") + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def __str__(self): + return "scalar" + class AleoSignedType(AleoIntegerType): @staticmethod diff --git a/vanguard/aleo/testing.py b/vanguard/aleo/testing.py index 997a755..98af108 100644 --- a/vanguard/aleo/testing.py +++ b/vanguard/aleo/testing.py @@ -8,7 +8,7 @@ from .grammar import AleoEnvironment def run_test_suite(build_path, detector, verbose=False): - env = AleoEnvironment(build_path) + env = AleoEnvironment.from_project(build_path) # locate the vanguard_helper function and retrieve the label info expected_labels = env.main.functions["vanguard_helper"].instructions[0].operands