From 975c8d89088e6982a854e642b236c0966426a2d5 Mon Sep 17 00:00:00 2001 From: Yanju Chen Date: Wed, 6 Mar 2024 01:07:16 -0800 Subject: [PATCH] new infoleak with infra changes - new infoleak detector based on abstract interpretation - new abstract interpretation shared lib - added support for instantiation of struct/record with abstract function - supported more new grammar - fixed some test suite labeling - updated divz detector - updated parser for priority of operand_preset and cast_destination - other small fixes --- README.md | 12 +- pyproject.toml | 2 +- tests/environment-test.ipynb | 200 +++++----- tests/public/infoleak0/build/main.aleo | 2 +- tests/public/infoleak0/src/main.leo | 4 +- tests/test4.ipynb | 60 +-- vanguard/aleo/abstract.py | 84 ++++ vanguard/aleo/detectors/divz.py | 145 +++---- vanguard/aleo/detectors/infoleak.py | 411 ++++++++++++++++++-- vanguard/aleo/detectors/legacy/infoleak0.py | 47 +++ vanguard/aleo/grammar/blocks.py | 79 ++-- vanguard/aleo/grammar/instructions.py | 2 +- vanguard/aleo/grammar/misc.py | 38 +- vanguard/aleo/parser/AleoParser.g4 | 4 +- vanguard/aleo/parser/AleoParser.interp | 2 +- vanguard/aleo/parser/AleoParser.py | 38 +- 16 files changed, 816 insertions(+), 314 deletions(-) create mode 100644 vanguard/aleo/abstract.py create mode 100644 vanguard/aleo/detectors/legacy/infoleak0.py diff --git a/README.md b/README.md index f2844ec..793f603 100644 --- a/README.md +++ b/README.md @@ -93,14 +93,14 @@ options: This will produce the following output: ``` - | id | program | function | detector | result | info | - |------|----------------|------------|------------|----------|----------------| - | 0 | infoleak0.aleo | ex0 | infoleak | unsafe | [('r0', 'r0')] | - | 1 | infoleak0.aleo | ex1 | infoleak | safe | [] | - | 2 | infoleak0.aleo | ex2 | infoleak | unsafe | [('r0', 'r1')] | + | id | program | function | detector | result | info | + |------|----------------|------------|------------|----------|----------------------| + | 0 | infoleak0.aleo | ex0 | infoleak | unsafe | ['output r0 as u8;'] | + | 1 | infoleak0.aleo | ex1 | infoleak | safe | [] | + | 2 | infoleak0.aleo | ex2 | infoleak | unsafe | ['output r1 as i8;'] | ``` - where the info column provides more information about the detected vulnerability. For example, in function `ex0` there's information leakage from variable `r0` to `r0` (direct returning of input), and in `ex2` from `r0` to `r1`. + where the info column provides more information about the detected vulnerability. For example, in function `ex0` there's information leakage of `r0` via output command. ### Calling from Source diff --git a/pyproject.toml b/pyproject.toml index f85fa3a..3689f73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "vanguard" -version = "0.0.3" +version = "0.0.4" authors = [ { name="Yanju Chen", email="yanju@veridise.com" }, ] diff --git a/tests/environment-test.ipynb b/tests/environment-test.ipynb index 7594ece..798cb77 100644 --- a/tests/environment-test.ipynb +++ b/tests/environment-test.ipynb @@ -10,106 +10,106 @@ "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" + "# parsing: treasure_hunt_v006.aleo ... 0.34779787063598633s\n", + "# parsing: aleo_monopoly_workshop.aleo ... 0.12547612190246582s\n", + "# parsing: treasure_hunt_v010.aleo ... 0.2432699203491211s\n", + "# parsing: zk_sra_encryption_v0_0_2.aleo ... 0.16161203384399414s\n", + "# parsing: aleo_monopoly_workshop4.aleo ... 0.11990594863891602s\n", + "# parsing: football_game_v008.aleo ... 0.5488848686218262s\n", + "# parsing: uniswap_v5.aleo ... 0.2239542007446289s\n", + "# parsing: wheres_alex_v018.aleo ... 0.12740397453308105s\n", + "# parsing: aleo_name_service_registry_v2.aleo ... 0.24753427505493164s\n", + "# parsing: aleo_monopoly_game4.aleo ... 0.12900400161743164s\n", + "# parsing: arcane_rfq_amm_v000004.aleo ... 0.1556079387664795s\n", + "# parsing: aleo_monopoly_workshop8.aleo ... 0.18530797958374023s\n", + "# parsing: aleo_monopoly_workshop10.aleo ... 0.16002297401428223s\n", + "# parsing: football_game_v004.aleo ... 0.4669189453125s\n", + "# parsing: who_is_dash_pash_v20203.aleo ... 0.1273338794708252s\n", + "# parsing: wheres_alex_v014.aleo ... 0.14441990852355957s\n", + "# parsing: football_game_v012.aleo ... 0.45942187309265137s\n", + "# parsing: tyron_app_test1.aleo ... 0.11498069763183594s\n", + "# parsing: distrofund_private_transfer_v2.aleo ... 0.19888782501220703s\n", + "# parsing: wheres_alex_v015.aleo ... 0.12262892723083496s\n", + "# parsing: football_game_v005.aleo ... 0.5159265995025635s\n", + "# parsing: zk_deck_shuffle_v0_0_1.aleo ... 3.3427340984344482s\n", + "# parsing: aleo_monopoly_workshop9.aleo ... 0.40294814109802246s\n", + "# parsing: arcane_rfq_amm_v000005.aleo ... 0.14778709411621094s\n", + "# parsing: aleo_name_service_registry_v3.aleo ... 0.24942994117736816s\n", + "# parsing: wheres_the_babycat.aleo ... 0.13100290298461914s\n", + "# parsing: wheres_alex_v019.aleo ... 0.15442514419555664s\n", + "# parsing: football_game_v009.aleo ... 0.5510199069976807s\n", + "# parsing: aleo_monopoly_workshop5.aleo ... 0.12297701835632324s\n", + "# parsing: credits.aleo ... 0.07080316543579102s\n", + "# parsing: treasure_hunt_v007.aleo ... 0.32471489906311035s\n", + "# parsing: council_v0001.aleo ... 0.11010289192199707s\n", + "# parsing: arcane_rfq_amm_v000002.aleo ... 0.2603728771209717s\n", + "# parsing: aleoswap05.aleo ... 0.31355762481689453s\n", + "# parsing: aleo_game_shop.aleo ... 0.1441662311553955s\n", + "# parsing: football_game_v002.aleo ... 0.32427000999450684s\n", + "# parsing: wheres_alex_v012.aleo ... 0.12132596969604492s\n", + "# parsing: aleo_store_nft.aleo ... 0.16173624992370605s\n", + "# parsing: whos_the_father_v002.aleo ... 0.1543598175048828s\n", + "# parsing: graph_coloring_v1.aleo ... 1.006282091140747s\n", + "# parsing: whoes_the_dragon_v01.aleo ... 0.20656824111938477s\n", + "# parsing: aleo_monopoly_workshop2.aleo ... 0.11718130111694336s\n", + "# parsing: zk_bitwise_stack_v0_0_1.aleo ... 0.4026181697845459s\n", + "# parsing: distrofund_private_transfer.aleo ... 0.21562480926513672s\n", + "# parsing: wheres_luna_v020.aleo ... 0.16715312004089355s\n", + "# parsing: aleo_monopoly_workshop3.aleo ... 0.1257779598236084s\n", + "# parsing: king_of_cat_v001.aleo ... 0.1271648406982422s\n", + "# parsing: treasure_hunt_v001.aleo ... 0.24799370765686035s\n", + "# parsing: whos_the_father_v003.aleo ... 0.12563395500183105s\n", + "# parsing: graph_coloring.aleo ... 1.125340223312378s\n", + "# parsing: wheres_alex_v013.aleo ... 0.1239628791809082s\n", + "# parsing: aleo_monopoly_game16.aleo ... 0.1281447410583496s\n", + "# parsing: arcane_rfq_amm_v000003.aleo ... 0.15100908279418945s\n", + "# parsing: zk_ml_dna_v0.aleo ... 0.16376709938049316s\n", + "# parsing: double_color_ball.aleo ... 2.8149960041046143s\n", + "# parsing: wheres_alex_v010.aleo ... 0.11389803886413574s\n", + "# parsing: lymphography_decision_tree_v1.aleo ... 0.17242002487182617s\n", + "# parsing: arcane_amm_v2_0.aleo ... 0.19998979568481445s\n", + "# parsing: zk_bitwise_stack_v0_0_3.aleo ... 0.7781190872192383s\n", + "# parsing: imma_find_alex_v01.aleo ... 0.12848210334777832s\n", + "# parsing: sklearn_mlp_mnist_1.aleo ... 0.14882493019104004s\n", + "# parsing: treasure_hunt_v002.aleo ... 0.23104190826416016s\n", + "# parsing: wheres_luna_v019.aleo ... 0.1290280818939209s\n", + "# parsing: whos_the_father_v001.aleo ... 0.12782502174377441s\n", + "# parsing: treasure_hunt_v003.aleo ... 0.295212984085083s\n", + "# parsing: zk_bitwise_stack_v0_0_2.aleo ... 0.412182092666626s\n", + "# parsing: wheres_jojo_v008.aleo ... 0.13227605819702148s\n", + "# parsing: arcane_rfq_amm_v000001.aleo ... 0.17067408561706543s\n", + "# parsing: zk_ml_dna_1700237585_v0.aleo ... 0.15897893905639648s\n", + "# parsing: aleoswap06.aleo ... 0.3017849922180176s\n", + "# parsing: nft_store_yong.aleo ... 0.16585206985473633s\n", + "# parsing: wheres_alex_v011.aleo ... 0.11071419715881348s\n", + "# parsing: football_random_v011.aleo ... 0.3941667079925537s\n", + "# parsing: testalphav1x1.aleo ... 0.4517788887023926s\n", + "# parsing: zk_bitwise_stack_v0_0_5.aleo ... 0.9719009399414062s\n", + "# parsing: hialstestv1.aleo ... 0.3391139507293701s\n", + "# parsing: what_does_gary_do_v001.aleo ... 0.13190793991088867s\n", + "# parsing: aleo_monopoly_workshop6.aleo ... 0.14983606338500977s\n", + "# parsing: treasure_hunt_v004.aleo ... 0.2787461280822754s\n", + "# parsing: zk_ml_dna_1700246715_v0.aleo ... 0.15949177742004395s\n", + "# parsing: football_game_v010.aleo ... 0.5402669906616211s\n", + "# parsing: wheres_alex_v016.aleo ... 0.1281871795654297s\n", + "# parsing: football_game_v006.aleo ... 0.5075030326843262s\n", + "# parsing: arcane_rfq_amm_v000006.aleo ... 0.17911505699157715s\n", + "# parsing: treasure_hunt_v008.aleo ... 0.29166197776794434s\n", + "# parsing: aleo_name_service_registry_v1.aleo ... 0.25179481506347656s\n", + "# parsing: treasure_hunt_v009.aleo ... 0.3150472640991211s\n", + "# parsing: lymphography_xgboost_v1.aleo ... 0.33880114555358887s\n", + "# parsing: football_game_v007.aleo ... 0.5076649188995361s\n", + "# parsing: wheres_alex_v017.aleo ... 0.13222599029541016s\n", + "# parsing: wheres_alex_probably_weeds.aleo ... 0.13173818588256836s\n", + "# parsing: treasure_hunt_v005.aleo ... 0.3213942050933838s\n", + "# parsing: zk_sra_encryption_v0_0_1.aleo ... 0.09100961685180664s\n", + "# parsing: twoalkilining.aleo ... 0.176069974899292s\n", + "# parsing: zkhack_mnist_v2.aleo ... 0.1515669822692871s\n", + "# parsing: wheres_joe_v019.aleo ... 0.12791705131530762s\n", + "# parsing: wheres_alex_by_joey11_v1.aleo ... 0.12585806846618652s\n", + "# parsing: aleo_monopoly_workshop7.aleo ... 0.12298393249511719s\n", + "# parsing: zk_bitwise_stack_v0_0_4.aleo ... 0.7650339603424072s\n", + "# parsing: alphaswap_v1.aleo ... 0.519434928894043s\n" ] } ], diff --git a/tests/public/infoleak0/build/main.aleo b/tests/public/infoleak0/build/main.aleo index ef2d16b..b41631e 100644 --- a/tests/public/infoleak0/build/main.aleo +++ b/tests/public/infoleak0/build/main.aleo @@ -46,7 +46,7 @@ mapping account_ex11: value as u8.public; function vanguard_helper: - cast true false true true true true true false true true true false true true true true true true true true true true true true true into r0 as [boolean; 25u32]; + cast true false true true true true true false true true true false true true true true true true true true true true true true false into r0 as [boolean; 25u32]; output r0 as [boolean; 25u32].private; diff --git a/tests/public/infoleak0/src/main.leo b/tests/public/infoleak0/src/main.leo index 5a7b9c3..89958a2 100644 --- a/tests/public/infoleak0/src/main.leo +++ b/tests/public/infoleak0/src/main.leo @@ -291,8 +291,8 @@ program infoleak0.aleo { // record leak // compilable, runnable - // label: bad - const label_ex24: bool = true; + // label: good (actual input record has all public fields) + const label_ex24: bool = false; record rec_ex24 { public owner: address, public data: u8, diff --git a/tests/test4.ipynb b/tests/test4.ipynb index bc29c2e..1ad4284 100644 --- a/tests/test4.ipynb +++ b/tests/test4.ipynb @@ -56,23 +56,33 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 8, "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": [ - "(False, [])" + "(True, ['output r0.content as struct_ex22.public;'])" ] }, - "execution_count": 4, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "fid = \"ex5\"\n", + "fid = \"ex22\"\n", + "# detector_divz(env, main.id, fid, readable=True)\n", "detector_infoleak(env, main.id, fid, readable=True)" ] }, @@ -86,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 8, "id": "a983f9b5-286c-4748-b2c7-b450ff0d7948", "metadata": {}, "outputs": [ @@ -100,37 +110,37 @@ "# [✓][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: 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: 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: False\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: False\n", - "# [✗][test] pid: infoleak0.aleo, fid: ex13, expected: True, actual: False\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: False\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: 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] 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] confusion matrix:\n", " actual False True \n", "expected \n", - "False 2 1\n", - "True 13 9\n", + "False 3 1\n", + "True 0 21\n", "# [test] normalized confusion matrix:\n", - " actual False True \n", - "expected \n", - "False 0.666667 0.333333\n", - "True 0.590909 0.409091\n" + " actual False True \n", + "expected \n", + "False 0.75 0.25\n", + "True 0.00 1.00\n" ] } ], diff --git a/vanguard/aleo/abstract.py b/vanguard/aleo/abstract.py new file mode 100644 index 0000000..af6f699 --- /dev/null +++ b/vanguard/aleo/abstract.py @@ -0,0 +1,84 @@ +from typing import Callable + +from .grammar import * + +class AleoAbstractType(AleoType): + def __init__(self, **kwargs): + super().__init__(**kwargs) + def __str__(self): + return "$" + +class AleoAbstractLiteral(AleoLiteral): + + def __init__(self, value, type = AleoAbstractType()): + super().__init__(value, type) + # need to turn on manually + # if turned on, this can be treated as both a singleton and a collection + # this will be used in "completely unknown (including type)" situation + self.auto_typing = False + self.auto_value_generator = None + + # once enabled, there's no way back + def enable_auto_typing(self, vgen: Callable): + self.auto_typing = True + self.auto_value_generator = vgen + + def __str__(self): + return f"{self.type}{self.value}" + + def __getitem__(self, key): + if self.auto_typing: + return self.auto_value_generator(key) + else: + raise AttributeError() + + def __setitem__(self, key, value): + if self.auto_typing: + pass + else: + raise AttributeError() + +# unary abstract operator generator +def absop1(ltab): + # ltab: look-up table + # construct function + def do(a: AleoAbstractLiteral): + r = set() + for a0 in a.value: + if a0 in ltab.keys(): + r.update(ltab[a0]) + return AleoAbstractLiteral(r) + # return the function + return do + +# binary abstract operator generator +def absop2(ltab): + # ltab: look-up table + # construct function + def do(a: AleoAbstractLiteral, b: AleoAbstractLiteral): + r = set() + for a0 in a.value: + if a0 in ltab.keys(): + for b0 in b.value: + if b0 in ltab[a0].keys(): + r.update(ltab[a0][b0]) + return AleoAbstractLiteral(r) + # return the function + return do + +# ternary abstract operator generator +def absop3(ltab): + # ltab: look-up table + # construct function + def do(a: AleoAbstractLiteral, b: AleoAbstractLiteral, c: AleoAbstractLiteral): + r = set() + for a0 in a.value: + if a0 in ltab.keys(): + for b0 in b.value: + if b0 in ltab[a0].keys(): + for c0 in c.value: + if c0 in ltab[a0][b0].keys(): + r.update(ltab[a0][b0][c0]) + return AleoAbstractLiteral(r) + # return the function + return do \ No newline at end of file diff --git a/vanguard/aleo/detectors/divz.py b/vanguard/aleo/detectors/divz.py index 14f4b02..335a8a9 100644 --- a/vanguard/aleo/detectors/divz.py +++ b/vanguard/aleo/detectors/divz.py @@ -3,6 +3,7 @@ from collections import defaultdict from ..grammar import * +from ..abstract import AleoAbstractLiteral, absop2 class AbsDom(Enum): NEG = -1 @@ -18,87 +19,58 @@ def NPINT(): return {AbsDom.NEG, AbsDom.ZERO} # non-positive int def ALLBOOL(): return {AbsDom.FALSE, AbsDom.TRUE} def BOT(): return set() -class AleoAbstractType(AleoType): - def __init__(self, **kwargs): - super().__init__(**kwargs) - def __str__(self): - return "$" - -class AleoAbstractLiteral(AleoLiteral): - - @staticmethod - def abs(node): - _type = AleoAbstractType() - match node: - case AleoAddressLiteral(): - return AleoAbstractLiteral(AbsDom.BOT(), _type) - case AleoBooleanLiteral(): - if node.value: - return AleoAbstractLiteral({AbsDom.TRUE}, _type) - else: - return AleoAbstractLiteral({AbsDom.FALSE}, _type) - case AleoFieldLiteral() | AleoUnsignedLiteral() | AleoSignedLiteral(): - if node.value == 0: - return AleoAbstractLiteral({AbsDom.ZERO}, _type) - elif node.value > 0: - return AleoAbstractLiteral({AbsDom.POS}, _type) - else: - return AleoAbstractLiteral({AbsDom.NEG}, _type) - case _: - raise NotImplementedError(f"Unsupported literal, got: {node}") - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def __str__(self): - return f"{self.type}{self.value}" - -def absop(ltab): - # ltab: look-up table - # construct function - def do(a: AleoAbstractLiteral, b: AleoAbstractLiteral): - r = set() - for a0 in a.value: - if a0 in ltab.keys(): - for b0 in b.value: - if b0 in ltab[a0].keys(): - r.update(ltab[a0][b0]) - return AleoAbstractLiteral(r, AleoAbstractType()) - # return the function - return do +# define and load abstract function +def abs(node): + match node: + case AleoAddressLiteral(): + return AleoAbstractLiteral(AbsDom.BOT()) + case AleoBooleanLiteral(): + if node.value: + return AleoAbstractLiteral({AbsDom.TRUE}) + else: + return AleoAbstractLiteral({AbsDom.FALSE}) + case AleoFieldLiteral() | AleoUnsignedLiteral() | AleoSignedLiteral(): + if node.value == 0: + return AleoAbstractLiteral({AbsDom.ZERO}) + elif node.value > 0: + return AleoAbstractLiteral({AbsDom.POS}) + else: + return AleoAbstractLiteral({AbsDom.NEG}) + case _: + raise NotImplementedError(f"Unsupported literal, got: {node}, type: {type(node)}") # load class attribute -AleoAbstractLiteral.ops = { +absops = { # binary operators - AleoBinaryOp.ADD: absop({ + AleoBinaryOp.ADD: absop2({ AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.ZERO: {AbsDom.NEG}, AbsDom.POS: AbsDom.ALLINT() }, AbsDom.ZERO: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.ZERO: {AbsDom.ZERO}, AbsDom.POS: {AbsDom.POS} }, AbsDom.POS: { AbsDom.NEG: AbsDom.ALLINT(), AbsDom.ZERO: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, }), - AleoBinaryOp.ADDW: absop({ + AleoBinaryOp.ADDW: absop2({ AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.ZERO: {AbsDom.NEG}, AbsDom.POS: AbsDom.ALLINT() }, AbsDom.ZERO: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.ZERO: {AbsDom.ZERO}, AbsDom.POS: {AbsDom.POS} }, AbsDom.POS: { AbsDom.NEG: AbsDom.ALLINT(), AbsDom.ZERO: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, }), # AleoBinaryOp.SUB: lambda: 1/0, # AleoBinaryOp.SUBW: lambda: 1/0, - AleoBinaryOp.MUL: absop({ + AleoBinaryOp.MUL: absop2({ AbsDom.NEG: { AbsDom.NEG: {AbsDom.POS}, AbsDom.ZERO: {AbsDom.ZERO}, AbsDom.POS: {AbsDom.NEG} }, AbsDom.ZERO: { AbsDom.NEG: {AbsDom.ZERO}, AbsDom.ZERO: {AbsDom.ZERO}, AbsDom.POS: {AbsDom.ZERO} }, AbsDom.POS: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.ZERO: {AbsDom.ZERO}, AbsDom.POS: {AbsDom.POS} }, }), - AleoBinaryOp.MULW: absop({ + AleoBinaryOp.MULW: absop2({ AbsDom.NEG: { AbsDom.NEG: {AbsDom.POS}, AbsDom.ZERO: {AbsDom.ZERO}, AbsDom.POS: {AbsDom.NEG} }, AbsDom.ZERO: { AbsDom.NEG: {AbsDom.ZERO}, AbsDom.ZERO: {AbsDom.ZERO}, AbsDom.POS: {AbsDom.ZERO} }, AbsDom.POS: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.ZERO: {AbsDom.ZERO}, AbsDom.POS: {AbsDom.POS} }, }), - AleoBinaryOp.DIV: absop({ + AleoBinaryOp.DIV: absop2({ AbsDom.NEG: { AbsDom.NEG: {AbsDom.POS}, AbsDom.ZERO: set(), AbsDom.POS: {AbsDom.NEG} }, AbsDom.ZERO: { AbsDom.NEG: {AbsDom.ZERO}, AbsDom.ZERO: set(), AbsDom.POS: {AbsDom.ZERO} }, AbsDom.POS: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.ZERO: set(), AbsDom.POS: {AbsDom.POS} }, }), - AleoBinaryOp.DIVW: absop({ + AleoBinaryOp.DIVW: absop2({ AbsDom.NEG: { AbsDom.NEG: {AbsDom.POS}, AbsDom.ZERO: set(), AbsDom.POS: {AbsDom.NEG} }, AbsDom.ZERO: { AbsDom.NEG: {AbsDom.ZERO}, AbsDom.ZERO: set(), AbsDom.POS: {AbsDom.ZERO} }, AbsDom.POS: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.ZERO: set(), AbsDom.POS: {AbsDom.POS} }, @@ -118,7 +90,7 @@ def do(a: AleoAbstractLiteral, b: AleoAbstractLiteral): # AleoBinaryOp.NAND: lambda: 1/0, # AleoBinaryOp.NOR: lambda: 1/0, # AleoBinaryOp.GT: lambda: 1/0, - AleoBinaryOp.GTE: absop({ + AleoBinaryOp.GTE: absop2({ AbsDom.NEG: { AbsDom.NEG: AbsDom.ALLBOOL(), AbsDom.ZERO: {AbsDom.FALSE}, AbsDom.POS: {AbsDom.FALSE} }, AbsDom.ZERO: { AbsDom.NEG: {AbsDom.TRUE}, AbsDom.ZERO: {AbsDom.TRUE}, AbsDom.POS: {AbsDom.FALSE} }, AbsDom.POS: { AbsDom.NEG: {AbsDom.TRUE}, AbsDom.ZERO: {AbsDom.TRUE}, AbsDom.POS: AbsDom.ALLBOOL() }, @@ -127,14 +99,14 @@ def do(a: AleoAbstractLiteral, b: AleoAbstractLiteral): # AleoBinaryOp.LTE: lambda: 1/0, # is operators - AleoIsOp.NEQ: absop({ + AleoIsOp.NEQ: absop2({ AbsDom.NEG: { AbsDom.NEG: AbsDom.ALLBOOL(), AbsDom.ZERO: {AbsDom.TRUE}, AbsDom.POS: {AbsDom.TRUE} }, AbsDom.ZERO: { AbsDom.NEG: {AbsDom.TRUE}, AbsDom.ZERO: {AbsDom.FALSE}, AbsDom.POS: {AbsDom.TRUE} }, AbsDom.POS: { AbsDom.NEG: {AbsDom.TRUE}, AbsDom.ZERO: {AbsDom.TRUE}, AbsDom.POS: AbsDom.ALLBOOL() }, AbsDom.FALSE:{ AbsDom.FALSE: {AbsDom.FALSE}, AbsDom.TRUE: {AbsDom.TRUE} }, AbsDom.TRUE: { AbsDom.FALSE: {AbsDom.TRUE}, AbsDom.TRUE: {AbsDom.FALSE} }, }), - AleoIsOp.EQ: absop({ + AleoIsOp.EQ: absop2({ AbsDom.NEG: { AbsDom.NEG: AbsDom.ALLBOOL(), AbsDom.ZERO: {AbsDom.FALSE}, AbsDom.POS: {AbsDom.FALSE} }, AbsDom.ZERO: { AbsDom.NEG: {AbsDom.FALSE}, AbsDom.ZERO: {AbsDom.TRUE}, AbsDom.POS: {AbsDom.FALSE} }, AbsDom.POS: { AbsDom.NEG: {AbsDom.FALSE}, AbsDom.ZERO: {AbsDom.FALSE}, AbsDom.POS: AbsDom.ALLBOOL() }, @@ -148,10 +120,12 @@ def a(node): case AleoAbstractLiteral(): return node case AleoLiteral(): - return AleoAbstractLiteral.abs(node) - case [*_]: + return abs(node) + case [*items]: # collection, directly return since each element should've been visited already - return node + return [ a(p) for p in node ] + case {**items}: + return { k : a(v) for k,v in node.items() } case _: raise NotImplementedError(f"Can't wrap a non-literal, got: {node}") @@ -194,12 +168,9 @@ def visitor(pid, fid, inps: list, finalize=False): # detect if inst.op in {AleoBinaryOp.DIV, AleoBinaryOp.DIVW}: if AbsDom.ZERO in av1.value: - if readable: - lines.append(f"{inst}") - else: - lines.append(inst) + lines.append(f"{inst}" if readable else inst) # compute - ao = AleoAbstractLiteral.ops[inst.op](av0, av1) + ao = absops[inst.op](av0, av1) env.mset(pid, inst.regacc, ao, ctx=ctx) case AleoTernary(): @@ -207,7 +178,7 @@ def visitor(pid, fid, inps: list, finalize=False): av1 = a(env.mget(pid, inst.operands[1], ctx=ctx)) av2 = a(env.mget(pid, inst.operands[2], ctx=ctx)) # compute - ao = AleoAbstractLiteral(set(), AleoAbstractType()) + ao = AleoAbstractLiteral(set()) if AbsDom.TRUE in av0.value: ao.value.update(av1.value) if AbsDom.FALSE in av0.value: @@ -221,7 +192,7 @@ def visitor(pid, fid, inps: list, finalize=False): case AleoCall(): # collect parameters - params = [ env.mget(pid, p, ctx=ctx) for p in inst.operands ] + params = [ a(env.mget(pid, p, ctx=ctx)) for p in inst.operands ] # locate function (_pid, _fid) = env.resolve_function(pid, inst.callee) # dispatch @@ -237,7 +208,7 @@ def visitor(pid, fid, inps: list, finalize=False): assert inst.callee == fid, \ f"Async id doesn't match function id, expected: {fid}, got: {inst.callee}" # collect parameters - params = [ env.mget(pid, p, ctx=ctx) for p in inst.operands ] + params = [ a(env.mget(pid, p, ctx=ctx)) for p in inst.operands ] # locate function (_pid, _fid) = env.resolve_function(pid, inst.callee) # dispatch @@ -249,12 +220,23 @@ def visitor(pid, fid, inps: list, finalize=False): case AleoSet(): _src = a(env.mget(pid, inst.src, ctx=ctx)) + # FIXME: if source is dict (record/struct) or list (array), + # you can't perform simple merge, but replace; + # otherwise, merge # collect all possible values of mapping - _map = env.mget(pid, inst.id, ctx=None) # mapping, don't abstract - _vv = set([p.value for p in _map.values()]) | _src.value # merge existing - _ss = AleoAbstractLiteral(_vv, AleoAbstractType()) + _map = a(env.mget(pid, inst.id, ctx=ctx)) + _ss = None + match _src: + case AleoAbstractLiteral(): + _vv = set([p.value for p in _map.values()]) | _src.value # merge existing + _ss = AleoAbstractLiteral(_vv) + case [*items] | {**items}: + # dict/list, can't simply merge, then just replace + _ss = _src + case _: + raise NotImplementedError(f"Unsupported source of set, got: {inst}") # set mapping as defaultdict - env.mset(pid, inst.id, defaultdict(lambda: _ss), ctx=None) + env.mset(pid, inst.id, defaultdict(lambda: _ss), ctx=ctx) case AleoCast(): avs = [ a(env.mget(pid, p, ctx=ctx)) for p in inst.operands ] @@ -267,19 +249,14 @@ def visitor(pid, fid, inps: list, finalize=False): _pid = pid if type(inst.dest) is AleoIdentifier else inst.dest.pid _id = inst.dest if type(inst.dest) is AleoIdentifier else inst.dest.id _pr = env.programs[_pid] - # NOTE: for locator, its current visibility overrrides + # NOTE: for locator, its current visibility overrides # the visibility of the location it refers to if _id.visibility == AleoModifier.RECORD: # record type specified ao = _pr.records[_id].instantiate(avs) elif _id.visibility == AleoModifier.DEFAULT: - # regular typing, first try struct, then record - if _id in _pr.structs.keys(): - ao = _pr.structs[_id].instantiate(avs) - elif _id in pr.records.keys(): - ao = _pr.records[_id].instantiate(avs) - else: - raise KeyError(f"Can't find struct/record, got: {inst.dest.id}") + # struct type + ao = _pr.structs[_id].instantiate(avs) else: raise NotImplementedError(f"Unsupported identifier modifier in cast destination, got: {inst.dest}") case AleoArrayType(): @@ -298,7 +275,7 @@ def visitor(pid, fid, inps: list, finalize=False): case AleoRandom(): # over-approximate - ao = AleoAbstractLiteral(AbsDom.ALLINT(), AleoAbstractType()) + ao = AleoAbstractLiteral(AbsDom.ALLINT()) env.mset(pid, inst.regacc, ao, ctx=ctx) case _: @@ -306,14 +283,14 @@ def visitor(pid, fid, inps: list, finalize=False): if isinstance(fn, AleoFinalize): # finalize: no output, return all bool for safe - return [AleoAbstractLiteral(AbsDom.ALLBOOL(), AleoAbstractType())] + return [AleoAbstractLiteral(AbsDom.ALLBOOL())] else: # closure/function: return return [ a(env.mget(pid, k, ctx=ctx)) for k,v in fn.outputs ] # FIXME: construct params according to types (could also be struct/record/mapping/etc.) params = [ - AleoAbstractLiteral(AbsDom.TOP(), AleoAbstractType()) + AleoAbstractLiteral(AbsDom.TOP()) for _ in range(len(func.inputs)) ] visitor(pid, fid, params) diff --git a/vanguard/aleo/detectors/infoleak.py b/vanguard/aleo/detectors/infoleak.py index b441731..3e31df3 100644 --- a/vanguard/aleo/detectors/infoleak.py +++ b/vanguard/aleo/detectors/infoleak.py @@ -1,47 +1,384 @@ -import networkx as nx +from typing import Union +from enum import Enum +from collections import defaultdict from ..grammar import * -from ..graphs import get_dfg_edges +from ..abstract import AleoAbstractLiteral, absop1, absop2 + +def abs(node): + # all will return negative if abs is EVER required + # but type checking is still required + match node: + case AleoAddressLiteral(): + return AleoAbstractLiteral({AbsDom.NEG}) + case AleoBooleanLiteral(): + return AleoAbstractLiteral({AbsDom.NEG}) + case AleoFieldLiteral() | AleoUnsignedLiteral() | AleoSignedLiteral(): + return AleoAbstractLiteral({AbsDom.NEG}) + case _: + raise NotImplementedError(f"Unsupported literal, got: {node}") +class AbsDom(Enum): + + NEG = 0 + POS = 1 # indicates private input and its flow of data + +# load class attribute +absops = { + + # binary operators + AleoBinaryOp.ADD: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.ADDW: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.SUB: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.SUBW: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.MUL: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.MULW: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.DIV: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.DIVW: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + # AleoBinaryOp.REM: lambda: 1/0, + # AleoBinaryOp.REMW: lambda: 1/0, + # AleoBinaryOp.POW: lambda: 1/0, + # AleoBinaryOp.POWW: lambda: 1/0, + # AleoBinaryOp.SHL: lambda: 1/0, + # AleoBinaryOp.SHLW: lambda: 1/0, + # AleoBinaryOp.SHR: lambda: 1/0, + # AleoBinaryOp.SHRW: lambda: 1/0, + # AleoBinaryOp.MOD: lambda: 1/0, + AleoBinaryOp.AND: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.OR: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + # AleoBinaryOp.XOR: lambda: 1/0, + # AleoBinaryOp.NAND: lambda: 1/0, + # AleoBinaryOp.NOR: lambda: 1/0, + AleoBinaryOp.GT: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.GTE: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.LT: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoBinaryOp.LTE: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + + # is operators + AleoIsOp.NEQ: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + AleoIsOp.EQ: absop2({ + AbsDom.NEG: { AbsDom.NEG: {AbsDom.NEG}, AbsDom.POS: {AbsDom.POS} }, + AbsDom.POS: { AbsDom.NEG: {AbsDom.POS}, AbsDom.POS: {AbsDom.POS} }, + }), + + # unary operators + AleoUnaryOp.ABS: absop1({ + AbsDom.NEG: {AbsDom.NEG}, + AbsDom.POS: {AbsDom.POS}, + }), + AleoUnaryOp.NOT: absop1({ + AbsDom.NEG: {AbsDom.NEG}, + AbsDom.POS: {AbsDom.POS}, + }), +} + +# abstract wrapper +def a(node): + match node: + # NOTE: match abstract literal first, before concrete literal + case AleoAbstractLiteral(): + return node + case AleoLiteral(): + return abs(node) + case [*items]: + # collection, directly return since each element should've been visited already + return [ a(p) for p in node ] + case {**items}: + return { k : a(v) for k,v in node.items() } + case _: + raise NotImplementedError(f"Can't wrap a non-literal, got: {node}") + +# check whether a value contains POS +def tainted(node): + match node: + case AleoAbstractLiteral(): + return AbsDom.POS in node.value + case [*items]: + return any([ tainted(p) for p in node ]) + case {**items}: + return any([ tainted(p) for p in node.values() ]) + case _: + raise NotImplementedError(f"Unsupported value type for tainted, got: {node}, type: {type(node)}") def detector_infoleak(env: AleoEnvironment, pid: str, fid: str, readable=False): # initialize prog: AleoProgram = env.programs[pid] func: AleoFunction = prog.functions[fid] - edges = get_dfg_edges(env, pid, fid, hash=False) - # special edge a -> a so that direct returning of a variable is accounted - for k,v in func.inputs: - edges.append((k, k)) - - # DEBUG - # for p in edges: - # print(f"{p[0]} -> {p[1]}") - - prv_inps = [k for k,v in func.inputs if v.visibility in {AleoModifier.PRIVATE, AleoModifier.DEFAULT}] - pub_outs = [k for k,v in func.outputs if v.visibility==AleoModifier.PUBLIC] - - G = nx.DiGraph() - G.add_edges_from(edges) - - paths = [] - for sig_in in prv_inps: - # print(f"# [debug] sig_in: {sig_in}") - if not G.has_node(sig_in): - # signal is not in graph, meaning it's not used - # since it's not used, it's not leaked - # this detector doesn't detect unused variable, so do nothing - continue - - for sig_out in pub_outs: - if not G.has_node(sig_out): - # output signal is not in graph, meaning it's not used - # meaning there's no leakage via this signal - continue - - if nx.has_path(G, sig_in, sig_out): - if readable: - paths.append((f"{sig_in}", f"{sig_out}")) + # store problematic instructions + pvars = [] # potentially publicized variables + lines = [] # corresponding instructions + + # FIXME: get better naming for pid and fid + def visitor(pid, fid, inps: list, finalize=False): + + # determine block + pr = env.programs[pid] + fn = None + if fid in pr.functions.keys(): + if finalize: + fn = pr.functions[fid].finalize + else: + fn = pr.functions[fid] + else: + fn = pr.closures[fid] + assert not finalize, f"Closure {fid} doesn't have a finalize block" + + assert len(fn.inputs) == len(inps), \ + f"Argument lengths mismatch, expected: {len(fn.inputs)}, got:{len(inps)}" + # create local context + ctx = { fn.inputs[i][0] : inps[i] for i in range(len(fn.inputs))} + + # interpret + for inst in fn.instructions: + # print(f"# [debug] pid: {pid}, fid: {fid}, inst: {inst}") + match inst: + + case AleoUnary(): + av = a(env.mget(pid, inst.operand, ctx=ctx)) + # compute + ao = absops[inst.op](av) + env.mset(pid, inst.regacc, ao, ctx=ctx) + + case AleoBinary() | AleoIs(): + av0 = a(env.mget(pid, inst.operands[0], ctx=ctx)) + av1 = a(env.mget(pid, inst.operands[1], ctx=ctx)) + # compute + ao = absops[inst.op](av0, av1) + env.mset(pid, inst.regacc, ao, ctx=ctx) + + case AleoTernary(): + av0 = a(env.mget(pid, inst.operands[0], ctx=ctx)) + av1 = a(env.mget(pid, inst.operands[1], ctx=ctx)) + av2 = a(env.mget(pid, inst.operands[2], ctx=ctx)) + ao = AleoAbstractLiteral(set()) + # compute + if AbsDom.POS in av0.value or AbsDom.POS in av1.value or AbsDom.POS in av2.value: + ao.value.add(AbsDom.POS) + # set + env.mset(pid, inst.regacc, ao, ctx=ctx) + + case AleoAssert() | AleoAwait(): + # no ctx change, skip + pass + + case AleoCall(): + # collect parameters + params = [ a(env.mget(pid, p, ctx=ctx)) for p in inst.operands ] + # locate function + (_pid, _fid) = env.resolve_function(pid, inst.callee) + # dispatch + outs = visitor(_pid, _fid, params) + # update ctx + assert len(outs) == len(inst.regaccs), \ + f"Lengths of return mismatch, expected: {(len(inst.regaccs))}, got: {len(outs)}" + for r,o in zip(inst.regaccs, outs): + env.mset(pid, r, o, ctx=ctx) + + case AleoAsync(): + # NOTE: async in Aleo is finalize in Leo + assert inst.callee == fid, \ + f"Async id doesn't match function id, expected: {fid}, got: {inst.callee}" + # collect parameters + params = [ a(env.mget(pid, p, ctx=ctx)) for p in inst.operands ] + # detect: finalize will publicize all its parameters + for i in range(len(params)): + if tainted(params[i]): + pvars.append(f"{inst.operands[i]}" if readable else inst.operands[i]) + lines.append(f"{inst}" if readable else inst) + # locate function + (_pid, _fid) = env.resolve_function(pid, inst.callee) + # dispatch + outs = visitor(_pid, _fid, params, finalize=True) + # update ctx + assert len(outs) == 1, \ + f"Lengths of return mismatch, expected: 1, got: {len(outs)}" + env.mset(pid, inst.regacc, outs[0], ctx=ctx) + + case AleoSet(): + _src = a(env.mget(pid, inst.src, ctx=ctx)) + # FIXME: if source is dict (record/struct) or list (array), + # you can't perform simple merge, but replace; + # otherwise, merge + # collect all possible values of mapping + _map = a(env.mget(pid, inst.id, ctx=ctx)) + _ss = None + match _src: + case AleoAbstractLiteral(): + _vv = set([p.value for p in _map.values()]) | _src.value # merge existing + _ss = AleoAbstractLiteral(_vv) + case [*items] | {**items}: + # dict/list, can't simply merge, then just replace + _ss = _src + case _: + raise NotImplementedError(f"Unsupported source of set, got: {inst}") + # set mapping as defaultdict + env.mset(pid, inst.id, defaultdict(lambda: _ss), ctx=ctx) + + case AleoCast(): + avs = [ a(env.mget(pid, p, ctx=ctx)) for p in inst.operands ] + ao = None + # NOTE: dest is about type, not register, not value, just type + match inst.dest: + # identifier with modifier + case AleoIdentifier() | AleoLocator(): + # determine internal or external program id and id + _pid = pid if type(inst.dest) is AleoIdentifier else inst.dest.pid + _id = inst.dest if type(inst.dest) is AleoIdentifier else inst.dest.id + _pr = env.programs[_pid] + # NOTE: for locator, its current visibility overrides + # the visibility of the location it refers to + if _id.visibility == AleoModifier.RECORD: + # record type specified + ao = _pr.records[_id].instantiate(avs) + elif _id.visibility == AleoModifier.DEFAULT: + # struct type + ao = _pr.structs[_id].instantiate(avs) + else: + raise NotImplementedError(f"Unsupported identifier modifier in cast destination, got: {inst.dest}") + case AleoArrayType(): + assert len(inst.dest.dim) == 1, f"Only 1d array as cast destination is supported, got: {inst.dest.dim}" + assert len(avs) == inst.dest.dim[0], f"Array lengths mismatch, expected: {inst.dest.dim}, got: {len(avs)}" + ao = avs + case AleoLiteralType(): + # NOTE: this is actually value casting, not value packing as in other cases + # FIXME: add actual casting + assert len(avs) == 1, f"When casting to literal type, only one value is allowed, got: {avs}" + ao = avs[0] + case _: + raise NotImplementedError(f"Unsupported cast destination, got: {inst.dest}") + # set + env.mset(pid, inst.regacc, ao, ctx=ctx) + + case AleoRandom(): + # NOTE: we assume random won't easily hit the same info being tracked + ao = AleoAbstractLiteral({AbsDom.NEG}) + env.mset(pid, inst.regacc, ao, ctx=ctx) + + case AleoHash1() | AleoSignVerify(): + # compute + # this operator removes any flows of target data + ao = AleoAbstractLiteral({AbsDom.NEG}) + env.mset(pid, inst.regacc, ao, ctx=ctx) + + case AleoContains(): + # id is mapping, not interested + av = a(env.mget(pid, inst.operand, ctx=ctx)) + ao = AleoAbstractLiteral(set()) + if AbsDom.POS in av.value: + ao.value.add(AbsDom.POS) + else: + ao.value.add(AbsDom.NEG) + env.mset(pid, inst.regacc, ao, ctx=ctx) + + case AleoGet() | AleoGetOrUse(): + # NOTE: operand can be both literal or var, so we give up reasoning here + # since we give up, we lose track of types, so we need to turn on auto_typing + ao = AleoAbstractLiteral({AbsDom.NEG, AbsDom.POS}) + ao.enable_auto_typing(lambda x:AleoAbstractLiteral({AbsDom.NEG, AbsDom.POS})) + env.mset(pid, inst.regacc, ao, ctx=ctx) + + case AleoRemove(): + # give up + pass + + case _: + raise NotImplementedError(f"Unsupported instruction, got: {inst}, type: {type(inst)}") + + if isinstance(fn, AleoFinalize): + # FIXME: we assume status of finalize execution doesn't leak (though it could still be possible) + return [AleoAbstractLiteral({AbsDom.NEG})] + else: + # closure/function: return + rets = [ a(env.mget(pid, k, ctx=ctx)) for k,v in fn.outputs ] + # detect: output instruction can explicitly change the visibility + for i in range(len(fn.outputs)): + k, v = fn.outputs[i] + if tainted(rets[i]) and v.visibility == AleoModifier.PUBLIC: + pvars.append(f"{k}" if readable else k) + lines.append(f"output {k} as {v};") + return rets + + def av_constructor(vtype): + ao = None + match vtype: + + case AleoLiteralType(): + _av = {AbsDom.POS} if vtype.visibility in {AleoModifier.PRIVATE, AleoModifier.DEFAULT} else {AbsDom.NEG} + return AleoAbstractLiteral(_av) + case AleoIdentifier() | AleoLocator(): + # determine internal or external program id and id + _pid = pid if type(vtype) is AleoIdentifier else vtype.pid + _id = vtype if type(vtype) is AleoIdentifier else vtype.id + _pr = env.programs[_pid] + if _id.visibility == AleoModifier.RECORD: + # record type, use value constructor mode + ao = _pr.records[_id].instantiate(av_constructor) + elif _id.visibility in {AleoModifier.PRIVATE, AleoModifier.DEFAULT}: + # struct type, use value constructor mode + ao = _pr.structs[_id].instantiate(av_constructor) else: - paths.append((sig_in, sig_out)) + raise NotImplementedError(f"Unsupported type for av constructor, got: {vtype}, type: {type(vtype)}, visibility: {_id.visibility}") + case AleoArrayType(): + assert len(vtype.dim) == 1, f"Only 1d array is supported, got: {vtype.dim}" + _avs = [ av_constructor(vtype.btype) for _ in range(vtype.dim[0]) ] + return _avs - return (len(paths)>0, paths) \ No newline at end of file + case _: + raise NotImplementedError(f"Unsupported type for input constructor, got: {vtype}, type: {type(vtype)}") + + return ao + + params = [ + av_constructor(v) + for k,v in func.inputs + ] + ret = visitor(pid, fid, params) + # print(f"# [debug] ret: {[str(p) for p in ret]}") + # print(f"# [debug] pvars: {pvars}") + # print(f"# [debug] lines: {lines}") + return (len(lines)>0, lines) \ No newline at end of file diff --git a/vanguard/aleo/detectors/legacy/infoleak0.py b/vanguard/aleo/detectors/legacy/infoleak0.py new file mode 100644 index 0000000..e8cd991 --- /dev/null +++ b/vanguard/aleo/detectors/legacy/infoleak0.py @@ -0,0 +1,47 @@ +import networkx as nx + +from ...grammar import * +from ...graphs import get_dfg_edges + +def detector_infoleak(env: AleoEnvironment, pid: str, fid: str, readable=False): + # initialize + prog: AleoProgram = env.programs[pid] + func: AleoFunction = prog.functions[fid] + + edges = get_dfg_edges(env, pid, fid, hash=False) + # special edge a -> a so that direct returning of a variable is accounted + for k,v in func.inputs: + edges.append((k, k)) + + # DEBUG + # for p in edges: + # print(f"{p[0]} -> {p[1]}") + + prv_inps = [k for k,v in func.inputs if v.visibility in {AleoModifier.PRIVATE, AleoModifier.DEFAULT}] + pub_outs = [k for k,v in func.outputs if v.visibility==AleoModifier.PUBLIC] + + G = nx.DiGraph() + G.add_edges_from(edges) + + paths = [] + for sig_in in prv_inps: + # print(f"# [debug] sig_in: {sig_in}") + if not G.has_node(sig_in): + # signal is not in graph, meaning it's not used + # since it's not used, it's not leaked + # this detector doesn't detect unused variable, so do nothing + continue + + for sig_out in pub_outs: + if not G.has_node(sig_out): + # output signal is not in graph, meaning it's not used + # meaning there's no leakage via this signal + continue + + if nx.has_path(G, sig_in, sig_out): + if readable: + paths.append((f"{sig_in}", f"{sig_out}")) + else: + paths.append((sig_in, sig_out)) + + return (len(paths)>0, paths) \ No newline at end of file diff --git a/vanguard/aleo/grammar/blocks.py b/vanguard/aleo/grammar/blocks.py index 1c503a6..00d2c09 100644 --- a/vanguard/aleo/grammar/blocks.py +++ b/vanguard/aleo/grammar/blocks.py @@ -1,4 +1,4 @@ -from typing import Any, Union +from typing import Any, Union, Callable from pathlib import Path from ..common import aleo2json @@ -75,22 +75,18 @@ def resolve_function(self, pid, callee): def mget(self, pid: str, id: Union[AleoRegister, AleoRegisterAccess], ctx: dict=None): match id: - case AleoRegister() | AleoIdentifier(): - # flat - if ctx is None or id not in ctx.keys(): - return self.programs[pid].mem[id] - else: - return ctx[id] + case AleoRegister(): + assert ctx is not None, f"Context can't be None when accessing register" + return ctx[id] + + case AleoIdentifier(): + return self.programs[pid].mem[id] case AleoRegisterAccess(): # potentially nested # determine the base - base = None - if ctx is None or id.reg not in ctx.keys(): - # NOTE: check first layer, if not matched, proceed at ctx - base = self.programs[pid].mem[id.reg] - else: - base = ctx[id.reg] + assert ctx is not None, f"Context can't be None when accessing register" + base = ctx[id.reg] # walk down the path for p in id.accs: match p: @@ -106,6 +102,10 @@ def mget(self, pid: str, id: Union[AleoRegister, AleoRegisterAccess], ctx: dict= case AleoLiteral(): return id + # FIXME: return something + case AleoOperandPreset(): + return AleoUnsignedLiteral.from_json(["unsigned_literal", "6", "5", "4", "3", ["unsigned_type", "u32"]]) + case _: raise NotImplementedError(f"Unsupported type of id, got: {id} of type {type(id)}") @@ -113,29 +113,22 @@ def mget(self, pid: str, id: Union[AleoRegister, AleoRegisterAccess], ctx: dict= def mset(self, pid: str, id: Union[AleoRegister, AleoRegisterAccess], val: AleoLiteral, ctx: dict=None): match id: - case AleoRegister() | AleoIdentifier(): - # flat - if ctx is None or id not in ctx.keys(): - self.programs[pid].mem[id] = val - else: - ctx[id] = val + case AleoRegister(): + assert ctx is not None, f"Context can't be None when accessing register" + ctx[id] = val + + case AleoIdentifier(): + self.programs[pid].mem[id] = val case AleoRegisterAccess() if len(id.accs) == 0: - # no accessor, same as single register - if ctx is None or id not in ctx.keys(): - self.programs[pid].mem[id.reg] = val - else: - ctx[id.reg] = val + assert ctx is not None, f"Context can't be None when accessing register" + ctx[id.reg] = val case AleoRegisterAccess(): # potentially nested # determine the last but one base - lbobase = None - if ctx is None or id.reg not in ctx.keys(): - # NOTE: check first layer, if not matched, proceed at ctx - lbobase = self.programs[pid].mem[id.reg] - else: - lbobase = ctx[id.reg] + assert ctx is not None, f"Context can't be None when accessing register" + lbobase = ctx[id.reg] # walk down the path, with the last one left for p in id.accs[:-1]: match p: @@ -274,9 +267,18 @@ def __str__(self): _fields = "\n".join([f"{_iden}{k} as {v};" for k,v in self.fields.items()]) return f"{_id}\n{_fields}" - def instantiate(self, params: list): + def instantiate(self, params: Union[list, Callable]): + # NOTE: params can be a collection of values (used in interpretation) + # or a value constructor (used for input construction) _keys = list(self.fields.keys()) - return { _keys[i] : params[i] for i in range(len(_keys)) } + _vals = list(self.fields.values()) + if isinstance(params, list): + assert len(_keys) == len(params), f"Numbers of parameters mismatch, expected: {len(_keys)}, got: {len(params)}" + return { _keys[i] : params[i] for i in range(len(_keys)) } + elif callable(params): + return { _keys[i] : params(_vals[i]) for i in range(len(_keys)) } + else: + raise NotImplementedError(f"Unsupported parameters for struct instantiation, got: {params}") class AleoMapping(AleoNode): @@ -338,9 +340,18 @@ def __str__(self): _fields = "\n".join([f"{_iden}{k} as {v};" for k,v in self.fields.items()]) return f"{_id}\n{_fields}" - def instantiate(self, params: list): + def instantiate(self, params: Union[list, Callable]): + # NOTE: params can be a collection of values (used in interpretation) + # or a value constructor (used for input construction) _keys = list(self.fields.keys()) - return { _keys[i] : params[i] for i in range(len(_keys)) } + _vals = list(self.fields.values()) + if isinstance(params, list): + assert len(_keys) == len(params), f"Numbers of parameters mismatch, expected: {len(_keys)}, got: {len(params)}" + return { _keys[i] : params[i] for i in range(len(_keys)) } + elif callable(params): + return { _keys[i] : params(_vals[i]) for i in range(len(_keys)) } + else: + raise NotImplementedError(f"Unsupported parameters for record instantiation, got: {params}") class AleoFunction(AleoNode): diff --git a/vanguard/aleo/grammar/instructions.py b/vanguard/aleo/grammar/instructions.py index 8bd9f55..47e3ce8 100644 --- a/vanguard/aleo/grammar/instructions.py +++ b/vanguard/aleo/grammar/instructions.py @@ -137,7 +137,7 @@ def __init__(self, id, operand, regacc, **kwargs): self.regacc = regacc def __str__(self): - return f"get {self.id} [{self.operand}] into {self.regacc};" + return f"get {self.id}[{self.operand}] into {self.regacc};" class AleoGetOrUse(AleoCommand): diff --git a/vanguard/aleo/grammar/misc.py b/vanguard/aleo/grammar/misc.py index 129a230..27f21fd 100644 --- a/vanguard/aleo/grammar/misc.py +++ b/vanguard/aleo/grammar/misc.py @@ -277,6 +277,8 @@ class AleoOperand(AleoNode): @staticmethod def from_json(node): match node: + case ["operand", ["operand_preset", *_]]: + return AleoOperandPreset.from_json(node[1]) case ["operand", ["literal", *_]]: from .literals import AleoLiteral return AleoLiteral.from_json(node[1]) @@ -571,4 +573,38 @@ def __str__(self): case AleoBranchOp.EQ.value: return "branch.eq" case _: - raise NotImplementedError(f"Unsupported branch op, got: {self.value}") \ No newline at end of file + raise NotImplementedError(f"Unsupported branch op, got: {self.value}") + +class AleoOperandPreset(AleoNode, Enum): + + CALLER = 0 + SIGNER = 1 + GROUPGEN = 2 + BLOCKHEIGHT = 3 + + @staticmethod + def from_json(s): + match s: + case ["operand_preset", "self", ".", "caller"]: + return AleoOperandPreset.CALLER + case ["operand_preset", "self", ".", "signer"]: + return AleoOperandPreset.SIGNER + case ["operand_preset", "group", "::", "GEN"]: + return AleoOperandPreset.GROUPGEN + case ["operand_preset", "block", ".", "height"]: + return AleoOperandPreset.BLOCKHEIGHT + case _: + raise NotImplementedError(f"Unsupported json component, got: {s}") + + def __str__(self): + match self.value: + case AleoOperandPreset.CALLER.value: + return "self.caller" + case AleoOperandPreset.SIGNER.value: + return "self.signer" + case AleoOperandPreset.GROUPGEN.value: + return "group::GEN" + case AleoOperandPreset.BLOCKHEIGHT.value: + return "block.height" + case _: + raise NotImplementedError(f"Unsupported operand preset, got: {self.value}") \ No newline at end of file diff --git a/vanguard/aleo/parser/AleoParser.g4 b/vanguard/aleo/parser/AleoParser.g4 index 76fa5b6..11b8e45 100644 --- a/vanguard/aleo/parser/AleoParser.g4 +++ b/vanguard/aleo/parser/AleoParser.g4 @@ -96,12 +96,12 @@ register_accessor : access_by_field | access_by_index ; access_by_field : DOT identifier ; access_by_index : LB unsigned_literal RB | LB DIGITS RB ; -operand : literal | register_access | program_id | operand_preset ; +operand : operand_preset | literal | register_access | program_id ; operand_preset : GROUP CC GEN | SELF DOT ( SIGNER | CALLER ) | BLOCK DOT HEIGHT ; tuple : identifier AS plaintext_type SC ; entry : identifier AS entry_type SC ; locator : program_id SLASH identifier ; -cast_destination : register_type | locator | destination_group ; +cast_destination : destination_group | register_type | locator ; destination_group : GROUP DOT ( X | Y ) ; unary_op : ABS ( DOT W )? | DOUBLE | INV | NEG | NOT | SQUARE | SQRT ; diff --git a/vanguard/aleo/parser/AleoParser.interp b/vanguard/aleo/parser/AleoParser.interp index e4c9235..e0decbb 100644 --- a/vanguard/aleo/parser/AleoParser.interp +++ b/vanguard/aleo/parser/AleoParser.interp @@ -345,4 +345,4 @@ identifier atn: -[4, 1, 119, 896, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 1, 0, 1, 0, 1, 1, 5, 1, 202, 8, 1, 10, 1, 12, 1, 205, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 215, 8, 1, 11, 1, 12, 1, 216, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 4, 6, 243, 8, 6, 11, 6, 12, 6, 244, 1, 7, 1, 7, 1, 7, 1, 7, 5, 7, 251, 8, 7, 10, 7, 12, 7, 254, 9, 7, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 260, 8, 8, 10, 8, 12, 8, 263, 9, 8, 1, 8, 4, 8, 266, 8, 8, 11, 8, 12, 8, 267, 1, 8, 5, 8, 271, 8, 8, 10, 8, 12, 8, 274, 9, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 292, 8, 11, 10, 11, 12, 11, 295, 9, 11, 1, 11, 5, 11, 298, 8, 11, 10, 11, 12, 11, 301, 9, 11, 1, 11, 5, 11, 304, 8, 11, 10, 11, 12, 11, 307, 9, 11, 1, 11, 3, 11, 310, 8, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 5, 14, 328, 8, 14, 10, 14, 12, 14, 331, 9, 14, 1, 14, 5, 14, 334, 8, 14, 10, 14, 12, 14, 337, 9, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 355, 8, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 5, 22, 403, 8, 22, 10, 22, 12, 22, 406, 9, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 415, 8, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 445, 8, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 489, 8, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 503, 8, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 3, 34, 518, 8, 34, 1, 34, 1, 34, 1, 35, 1, 35, 3, 35, 524, 8, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 4, 37, 536, 8, 37, 11, 37, 12, 37, 537, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 3, 38, 549, 8, 38, 1, 38, 5, 38, 552, 8, 38, 10, 38, 12, 38, 555, 9, 38, 1, 38, 1, 38, 4, 38, 559, 8, 38, 11, 38, 12, 38, 560, 3, 38, 563, 8, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 5, 39, 570, 8, 39, 10, 39, 12, 39, 573, 9, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 3, 40, 583, 8, 40, 1, 41, 3, 41, 586, 8, 41, 1, 41, 1, 41, 1, 41, 1, 42, 3, 42, 592, 8, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 3, 43, 599, 8, 43, 1, 44, 3, 44, 602, 8, 44, 1, 44, 1, 44, 1, 44, 1, 45, 3, 45, 608, 8, 45, 1, 45, 1, 45, 1, 45, 1, 46, 3, 46, 614, 8, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 623, 8, 47, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 53, 1, 53, 3, 53, 637, 8, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 3, 57, 649, 8, 57, 1, 58, 1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 661, 8, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 3, 63, 672, 8, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 3, 64, 683, 8, 64, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 694, 8, 66, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 706, 8, 68, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1, 74, 1, 74, 5, 74, 723, 8, 74, 10, 74, 12, 74, 726, 9, 74, 1, 75, 1, 75, 3, 75, 730, 8, 75, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 3, 77, 742, 8, 77, 1, 78, 1, 78, 1, 78, 1, 78, 3, 78, 748, 8, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 3, 79, 759, 8, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 3, 83, 778, 8, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 3, 85, 787, 8, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 3, 85, 795, 8, 85, 1, 86, 1, 86, 1, 86, 3, 86, 800, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 805, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 810, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 815, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 820, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 825, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 830, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 835, 8, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 3, 86, 847, 8, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 3, 92, 872, 8, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 3, 96, 890, 8, 96, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 0, 0, 99, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 0, 9, 1, 0, 103, 104, 1, 0, 12, 16, 1, 0, 20, 21, 1, 0, 25, 26, 1, 0, 68, 69, 1, 0, 74, 79, 1, 0, 74, 88, 1, 0, 80, 82, 2, 0, 9, 113, 115, 116, 923, 0, 198, 1, 0, 0, 0, 2, 203, 1, 0, 0, 0, 4, 218, 1, 0, 0, 0, 6, 222, 1, 0, 0, 0, 8, 228, 1, 0, 0, 0, 10, 233, 1, 0, 0, 0, 12, 238, 1, 0, 0, 0, 14, 246, 1, 0, 0, 0, 16, 255, 1, 0, 0, 0, 18, 275, 1, 0, 0, 0, 20, 281, 1, 0, 0, 0, 22, 287, 1, 0, 0, 0, 24, 311, 1, 0, 0, 0, 26, 317, 1, 0, 0, 0, 28, 323, 1, 0, 0, 0, 30, 338, 1, 0, 0, 0, 32, 354, 1, 0, 0, 0, 34, 356, 1, 0, 0, 0, 36, 365, 1, 0, 0, 0, 38, 374, 1, 0, 0, 0, 40, 384, 1, 0, 0, 0, 42, 393, 1, 0, 0, 0, 44, 400, 1, 0, 0, 0, 46, 418, 1, 0, 0, 0, 48, 422, 1, 0, 0, 0, 50, 429, 1, 0, 0, 0, 52, 444, 1, 0, 0, 0, 54, 446, 1, 0, 0, 0, 56, 452, 1, 0, 0, 0, 58, 459, 1, 0, 0, 0, 60, 467, 1, 0, 0, 0, 62, 474, 1, 0, 0, 0, 64, 479, 1, 0, 0, 0, 66, 492, 1, 0, 0, 0, 68, 506, 1, 0, 0, 0, 70, 523, 1, 0, 0, 0, 72, 525, 1, 0, 0, 0, 74, 533, 1, 0, 0, 0, 76, 545, 1, 0, 0, 0, 78, 566, 1, 0, 0, 0, 80, 582, 1, 0, 0, 0, 82, 585, 1, 0, 0, 0, 84, 591, 1, 0, 0, 0, 86, 598, 1, 0, 0, 0, 88, 601, 1, 0, 0, 0, 90, 607, 1, 0, 0, 0, 92, 613, 1, 0, 0, 0, 94, 622, 1, 0, 0, 0, 96, 624, 1, 0, 0, 0, 98, 626, 1, 0, 0, 0, 100, 628, 1, 0, 0, 0, 102, 630, 1, 0, 0, 0, 104, 632, 1, 0, 0, 0, 106, 636, 1, 0, 0, 0, 108, 638, 1, 0, 0, 0, 110, 640, 1, 0, 0, 0, 112, 642, 1, 0, 0, 0, 114, 648, 1, 0, 0, 0, 116, 650, 1, 0, 0, 0, 118, 652, 1, 0, 0, 0, 120, 654, 1, 0, 0, 0, 122, 660, 1, 0, 0, 0, 124, 662, 1, 0, 0, 0, 126, 671, 1, 0, 0, 0, 128, 682, 1, 0, 0, 0, 130, 684, 1, 0, 0, 0, 132, 693, 1, 0, 0, 0, 134, 695, 1, 0, 0, 0, 136, 705, 1, 0, 0, 0, 138, 707, 1, 0, 0, 0, 140, 710, 1, 0, 0, 0, 142, 714, 1, 0, 0, 0, 144, 716, 1, 0, 0, 0, 146, 718, 1, 0, 0, 0, 148, 720, 1, 0, 0, 0, 150, 729, 1, 0, 0, 0, 152, 731, 1, 0, 0, 0, 154, 741, 1, 0, 0, 0, 156, 747, 1, 0, 0, 0, 158, 758, 1, 0, 0, 0, 160, 760, 1, 0, 0, 0, 162, 765, 1, 0, 0, 0, 164, 770, 1, 0, 0, 0, 166, 777, 1, 0, 0, 0, 168, 779, 1, 0, 0, 0, 170, 794, 1, 0, 0, 0, 172, 846, 1, 0, 0, 0, 174, 848, 1, 0, 0, 0, 176, 852, 1, 0, 0, 0, 178, 856, 1, 0, 0, 0, 180, 860, 1, 0, 0, 0, 182, 864, 1, 0, 0, 0, 184, 868, 1, 0, 0, 0, 186, 873, 1, 0, 0, 0, 188, 877, 1, 0, 0, 0, 190, 881, 1, 0, 0, 0, 192, 889, 1, 0, 0, 0, 194, 891, 1, 0, 0, 0, 196, 893, 1, 0, 0, 0, 198, 199, 3, 2, 1, 0, 199, 1, 1, 0, 0, 0, 200, 202, 3, 4, 2, 0, 201, 200, 1, 0, 0, 0, 202, 205, 1, 0, 0, 0, 203, 201, 1, 0, 0, 0, 203, 204, 1, 0, 0, 0, 204, 206, 1, 0, 0, 0, 205, 203, 1, 0, 0, 0, 206, 207, 5, 92, 0, 0, 207, 208, 3, 140, 70, 0, 208, 214, 5, 5, 0, 0, 209, 215, 3, 6, 3, 0, 210, 215, 3, 12, 6, 0, 211, 215, 3, 14, 7, 0, 212, 215, 3, 16, 8, 0, 213, 215, 3, 22, 11, 0, 214, 209, 1, 0, 0, 0, 214, 210, 1, 0, 0, 0, 214, 211, 1, 0, 0, 0, 214, 212, 1, 0, 0, 0, 214, 213, 1, 0, 0, 0, 215, 216, 1, 0, 0, 0, 216, 214, 1, 0, 0, 0, 216, 217, 1, 0, 0, 0, 217, 3, 1, 0, 0, 0, 218, 219, 5, 93, 0, 0, 219, 220, 3, 140, 70, 0, 220, 221, 5, 5, 0, 0, 221, 5, 1, 0, 0, 0, 222, 223, 5, 94, 0, 0, 223, 224, 3, 196, 98, 0, 224, 225, 5, 7, 0, 0, 225, 226, 3, 8, 4, 0, 226, 227, 3, 10, 5, 0, 227, 7, 1, 0, 0, 0, 228, 229, 5, 95, 0, 0, 229, 230, 5, 9, 0, 0, 230, 231, 3, 130, 65, 0, 231, 232, 5, 5, 0, 0, 232, 9, 1, 0, 0, 0, 233, 234, 5, 96, 0, 0, 234, 235, 5, 9, 0, 0, 235, 236, 3, 130, 65, 0, 236, 237, 5, 5, 0, 0, 237, 11, 1, 0, 0, 0, 238, 239, 5, 97, 0, 0, 239, 240, 3, 196, 98, 0, 240, 242, 5, 7, 0, 0, 241, 243, 3, 160, 80, 0, 242, 241, 1, 0, 0, 0, 243, 244, 1, 0, 0, 0, 244, 242, 1, 0, 0, 0, 244, 245, 1, 0, 0, 0, 245, 13, 1, 0, 0, 0, 246, 247, 5, 16, 0, 0, 247, 248, 3, 196, 98, 0, 248, 252, 5, 7, 0, 0, 249, 251, 3, 162, 81, 0, 250, 249, 1, 0, 0, 0, 251, 254, 1, 0, 0, 0, 252, 250, 1, 0, 0, 0, 252, 253, 1, 0, 0, 0, 253, 15, 1, 0, 0, 0, 254, 252, 1, 0, 0, 0, 255, 256, 5, 98, 0, 0, 256, 257, 3, 196, 98, 0, 257, 261, 5, 7, 0, 0, 258, 260, 3, 18, 9, 0, 259, 258, 1, 0, 0, 0, 260, 263, 1, 0, 0, 0, 261, 259, 1, 0, 0, 0, 261, 262, 1, 0, 0, 0, 262, 265, 1, 0, 0, 0, 263, 261, 1, 0, 0, 0, 264, 266, 3, 52, 26, 0, 265, 264, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 265, 1, 0, 0, 0, 267, 268, 1, 0, 0, 0, 268, 272, 1, 0, 0, 0, 269, 271, 3, 20, 10, 0, 270, 269, 1, 0, 0, 0, 271, 274, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 17, 1, 0, 0, 0, 274, 272, 1, 0, 0, 0, 275, 276, 5, 99, 0, 0, 276, 277, 3, 146, 73, 0, 277, 278, 5, 9, 0, 0, 278, 279, 3, 136, 68, 0, 279, 280, 5, 5, 0, 0, 280, 19, 1, 0, 0, 0, 281, 282, 5, 100, 0, 0, 282, 283, 3, 156, 78, 0, 283, 284, 5, 9, 0, 0, 284, 285, 3, 136, 68, 0, 285, 286, 5, 5, 0, 0, 286, 21, 1, 0, 0, 0, 287, 288, 5, 101, 0, 0, 288, 289, 3, 196, 98, 0, 289, 293, 5, 7, 0, 0, 290, 292, 3, 24, 12, 0, 291, 290, 1, 0, 0, 0, 292, 295, 1, 0, 0, 0, 293, 291, 1, 0, 0, 0, 293, 294, 1, 0, 0, 0, 294, 299, 1, 0, 0, 0, 295, 293, 1, 0, 0, 0, 296, 298, 3, 52, 26, 0, 297, 296, 1, 0, 0, 0, 298, 301, 1, 0, 0, 0, 299, 297, 1, 0, 0, 0, 299, 300, 1, 0, 0, 0, 300, 305, 1, 0, 0, 0, 301, 299, 1, 0, 0, 0, 302, 304, 3, 26, 13, 0, 303, 302, 1, 0, 0, 0, 304, 307, 1, 0, 0, 0, 305, 303, 1, 0, 0, 0, 305, 306, 1, 0, 0, 0, 306, 309, 1, 0, 0, 0, 307, 305, 1, 0, 0, 0, 308, 310, 3, 28, 14, 0, 309, 308, 1, 0, 0, 0, 309, 310, 1, 0, 0, 0, 310, 23, 1, 0, 0, 0, 311, 312, 5, 99, 0, 0, 312, 313, 3, 146, 73, 0, 313, 314, 5, 9, 0, 0, 314, 315, 3, 128, 64, 0, 315, 316, 5, 5, 0, 0, 316, 25, 1, 0, 0, 0, 317, 318, 5, 100, 0, 0, 318, 319, 3, 156, 78, 0, 319, 320, 5, 9, 0, 0, 320, 321, 3, 128, 64, 0, 321, 322, 5, 5, 0, 0, 322, 27, 1, 0, 0, 0, 323, 324, 5, 102, 0, 0, 324, 325, 3, 196, 98, 0, 325, 329, 5, 7, 0, 0, 326, 328, 3, 30, 15, 0, 327, 326, 1, 0, 0, 0, 328, 331, 1, 0, 0, 0, 329, 327, 1, 0, 0, 0, 329, 330, 1, 0, 0, 0, 330, 335, 1, 0, 0, 0, 331, 329, 1, 0, 0, 0, 332, 334, 3, 32, 16, 0, 333, 332, 1, 0, 0, 0, 334, 337, 1, 0, 0, 0, 335, 333, 1, 0, 0, 0, 335, 336, 1, 0, 0, 0, 336, 29, 1, 0, 0, 0, 337, 335, 1, 0, 0, 0, 338, 339, 5, 99, 0, 0, 339, 340, 3, 146, 73, 0, 340, 341, 5, 9, 0, 0, 341, 342, 3, 132, 66, 0, 342, 343, 5, 5, 0, 0, 343, 31, 1, 0, 0, 0, 344, 355, 3, 34, 17, 0, 345, 355, 3, 36, 18, 0, 346, 355, 3, 38, 19, 0, 347, 355, 3, 40, 20, 0, 348, 355, 3, 42, 21, 0, 349, 355, 3, 44, 22, 0, 350, 355, 3, 46, 23, 0, 351, 355, 3, 48, 24, 0, 352, 355, 3, 50, 25, 0, 353, 355, 3, 52, 26, 0, 354, 344, 1, 0, 0, 0, 354, 345, 1, 0, 0, 0, 354, 346, 1, 0, 0, 0, 354, 347, 1, 0, 0, 0, 354, 348, 1, 0, 0, 0, 354, 349, 1, 0, 0, 0, 354, 350, 1, 0, 0, 0, 354, 351, 1, 0, 0, 0, 354, 352, 1, 0, 0, 0, 354, 353, 1, 0, 0, 0, 355, 33, 1, 0, 0, 0, 356, 357, 5, 27, 0, 0, 357, 358, 3, 196, 98, 0, 358, 359, 5, 3, 0, 0, 359, 360, 3, 156, 78, 0, 360, 361, 5, 4, 0, 0, 361, 362, 5, 10, 0, 0, 362, 363, 3, 148, 74, 0, 363, 364, 5, 5, 0, 0, 364, 35, 1, 0, 0, 0, 365, 366, 5, 28, 0, 0, 366, 367, 3, 196, 98, 0, 367, 368, 5, 3, 0, 0, 368, 369, 3, 156, 78, 0, 369, 370, 5, 4, 0, 0, 370, 371, 5, 10, 0, 0, 371, 372, 3, 148, 74, 0, 372, 373, 5, 5, 0, 0, 373, 37, 1, 0, 0, 0, 374, 375, 3, 190, 95, 0, 375, 376, 3, 196, 98, 0, 376, 377, 5, 3, 0, 0, 377, 378, 3, 156, 78, 0, 378, 379, 5, 4, 0, 0, 379, 380, 3, 156, 78, 0, 380, 381, 5, 10, 0, 0, 381, 382, 3, 148, 74, 0, 382, 383, 5, 5, 0, 0, 383, 39, 1, 0, 0, 0, 384, 385, 5, 30, 0, 0, 385, 386, 3, 156, 78, 0, 386, 387, 5, 10, 0, 0, 387, 388, 3, 196, 98, 0, 388, 389, 5, 3, 0, 0, 389, 390, 3, 156, 78, 0, 390, 391, 5, 4, 0, 0, 391, 392, 5, 5, 0, 0, 392, 41, 1, 0, 0, 0, 393, 394, 5, 31, 0, 0, 394, 395, 3, 196, 98, 0, 395, 396, 5, 3, 0, 0, 396, 397, 3, 156, 78, 0, 397, 398, 5, 4, 0, 0, 398, 399, 5, 5, 0, 0, 399, 43, 1, 0, 0, 0, 400, 404, 3, 188, 94, 0, 401, 403, 3, 156, 78, 0, 402, 401, 1, 0, 0, 0, 403, 406, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 404, 405, 1, 0, 0, 0, 405, 407, 1, 0, 0, 0, 406, 404, 1, 0, 0, 0, 407, 408, 5, 10, 0, 0, 408, 409, 3, 148, 74, 0, 409, 414, 5, 9, 0, 0, 410, 415, 3, 114, 57, 0, 411, 415, 3, 116, 58, 0, 412, 415, 3, 120, 60, 0, 413, 415, 3, 118, 59, 0, 414, 410, 1, 0, 0, 0, 414, 411, 1, 0, 0, 0, 414, 412, 1, 0, 0, 0, 414, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 417, 5, 5, 0, 0, 417, 45, 1, 0, 0, 0, 418, 419, 5, 34, 0, 0, 419, 420, 3, 194, 97, 0, 420, 421, 5, 5, 0, 0, 421, 47, 1, 0, 0, 0, 422, 423, 3, 186, 93, 0, 423, 424, 3, 156, 78, 0, 424, 425, 3, 156, 78, 0, 425, 426, 5, 11, 0, 0, 426, 427, 3, 194, 97, 0, 427, 428, 5, 5, 0, 0, 428, 49, 1, 0, 0, 0, 429, 430, 5, 35, 0, 0, 430, 431, 3, 148, 74, 0, 431, 432, 5, 5, 0, 0, 432, 51, 1, 0, 0, 0, 433, 445, 3, 54, 27, 0, 434, 445, 3, 56, 28, 0, 435, 445, 3, 58, 29, 0, 436, 445, 3, 60, 30, 0, 437, 445, 3, 62, 31, 0, 438, 445, 3, 64, 32, 0, 439, 445, 3, 70, 35, 0, 440, 445, 3, 72, 36, 0, 441, 445, 3, 74, 37, 0, 442, 445, 3, 76, 38, 0, 443, 445, 3, 78, 39, 0, 444, 433, 1, 0, 0, 0, 444, 434, 1, 0, 0, 0, 444, 435, 1, 0, 0, 0, 444, 436, 1, 0, 0, 0, 444, 437, 1, 0, 0, 0, 444, 438, 1, 0, 0, 0, 444, 439, 1, 0, 0, 0, 444, 440, 1, 0, 0, 0, 444, 441, 1, 0, 0, 0, 444, 442, 1, 0, 0, 0, 444, 443, 1, 0, 0, 0, 445, 53, 1, 0, 0, 0, 446, 447, 3, 170, 85, 0, 447, 448, 3, 156, 78, 0, 448, 449, 5, 10, 0, 0, 449, 450, 3, 148, 74, 0, 450, 451, 5, 5, 0, 0, 451, 55, 1, 0, 0, 0, 452, 453, 3, 172, 86, 0, 453, 454, 3, 156, 78, 0, 454, 455, 3, 156, 78, 0, 455, 456, 5, 10, 0, 0, 456, 457, 3, 148, 74, 0, 457, 458, 5, 5, 0, 0, 458, 57, 1, 0, 0, 0, 459, 460, 5, 36, 0, 0, 460, 461, 3, 156, 78, 0, 461, 462, 3, 156, 78, 0, 462, 463, 3, 156, 78, 0, 463, 464, 5, 10, 0, 0, 464, 465, 3, 148, 74, 0, 465, 466, 5, 5, 0, 0, 466, 59, 1, 0, 0, 0, 467, 468, 3, 174, 87, 0, 468, 469, 3, 156, 78, 0, 469, 470, 3, 156, 78, 0, 470, 471, 5, 10, 0, 0, 471, 472, 3, 148, 74, 0, 472, 473, 5, 5, 0, 0, 473, 61, 1, 0, 0, 0, 474, 475, 3, 176, 88, 0, 475, 476, 3, 156, 78, 0, 476, 477, 3, 156, 78, 0, 477, 478, 5, 5, 0, 0, 478, 63, 1, 0, 0, 0, 479, 480, 3, 178, 89, 0, 480, 481, 3, 156, 78, 0, 481, 482, 3, 156, 78, 0, 482, 483, 5, 10, 0, 0, 483, 484, 3, 148, 74, 0, 484, 488, 5, 9, 0, 0, 485, 489, 3, 116, 58, 0, 486, 489, 3, 108, 54, 0, 487, 489, 3, 110, 55, 0, 488, 485, 1, 0, 0, 0, 488, 486, 1, 0, 0, 0, 488, 487, 1, 0, 0, 0, 489, 490, 1, 0, 0, 0, 490, 491, 5, 5, 0, 0, 491, 65, 1, 0, 0, 0, 492, 493, 3, 180, 90, 0, 493, 494, 3, 156, 78, 0, 494, 495, 5, 10, 0, 0, 495, 496, 3, 148, 74, 0, 496, 502, 5, 9, 0, 0, 497, 503, 3, 114, 57, 0, 498, 503, 3, 116, 58, 0, 499, 503, 3, 120, 60, 0, 500, 503, 3, 124, 62, 0, 501, 503, 3, 196, 98, 0, 502, 497, 1, 0, 0, 0, 502, 498, 1, 0, 0, 0, 502, 499, 1, 0, 0, 0, 502, 500, 1, 0, 0, 0, 502, 501, 1, 0, 0, 0, 503, 504, 1, 0, 0, 0, 504, 505, 5, 5, 0, 0, 505, 67, 1, 0, 0, 0, 506, 507, 3, 182, 91, 0, 507, 508, 3, 156, 78, 0, 508, 509, 3, 156, 78, 0, 509, 510, 5, 10, 0, 0, 510, 511, 3, 148, 74, 0, 511, 517, 5, 9, 0, 0, 512, 518, 3, 114, 57, 0, 513, 518, 3, 116, 58, 0, 514, 518, 3, 120, 60, 0, 515, 518, 3, 124, 62, 0, 516, 518, 3, 196, 98, 0, 517, 512, 1, 0, 0, 0, 517, 513, 1, 0, 0, 0, 517, 514, 1, 0, 0, 0, 517, 515, 1, 0, 0, 0, 517, 516, 1, 0, 0, 0, 518, 519, 1, 0, 0, 0, 519, 520, 5, 5, 0, 0, 520, 69, 1, 0, 0, 0, 521, 524, 3, 66, 33, 0, 522, 524, 3, 68, 34, 0, 523, 521, 1, 0, 0, 0, 523, 522, 1, 0, 0, 0, 524, 71, 1, 0, 0, 0, 525, 526, 3, 192, 96, 0, 526, 527, 3, 156, 78, 0, 527, 528, 3, 156, 78, 0, 528, 529, 3, 156, 78, 0, 529, 530, 5, 10, 0, 0, 530, 531, 3, 148, 74, 0, 531, 532, 5, 5, 0, 0, 532, 73, 1, 0, 0, 0, 533, 535, 3, 184, 92, 0, 534, 536, 3, 156, 78, 0, 535, 534, 1, 0, 0, 0, 536, 537, 1, 0, 0, 0, 537, 535, 1, 0, 0, 0, 537, 538, 1, 0, 0, 0, 538, 539, 1, 0, 0, 0, 539, 540, 5, 10, 0, 0, 540, 541, 3, 148, 74, 0, 541, 542, 5, 9, 0, 0, 542, 543, 3, 166, 83, 0, 543, 544, 5, 5, 0, 0, 544, 75, 1, 0, 0, 0, 545, 548, 5, 40, 0, 0, 546, 549, 3, 164, 82, 0, 547, 549, 3, 196, 98, 0, 548, 546, 1, 0, 0, 0, 548, 547, 1, 0, 0, 0, 549, 553, 1, 0, 0, 0, 550, 552, 3, 156, 78, 0, 551, 550, 1, 0, 0, 0, 552, 555, 1, 0, 0, 0, 553, 551, 1, 0, 0, 0, 553, 554, 1, 0, 0, 0, 554, 562, 1, 0, 0, 0, 555, 553, 1, 0, 0, 0, 556, 558, 5, 10, 0, 0, 557, 559, 3, 148, 74, 0, 558, 557, 1, 0, 0, 0, 559, 560, 1, 0, 0, 0, 560, 558, 1, 0, 0, 0, 560, 561, 1, 0, 0, 0, 561, 563, 1, 0, 0, 0, 562, 556, 1, 0, 0, 0, 562, 563, 1, 0, 0, 0, 563, 564, 1, 0, 0, 0, 564, 565, 5, 5, 0, 0, 565, 77, 1, 0, 0, 0, 566, 567, 5, 41, 0, 0, 567, 571, 3, 196, 98, 0, 568, 570, 3, 156, 78, 0, 569, 568, 1, 0, 0, 0, 570, 573, 1, 0, 0, 0, 571, 569, 1, 0, 0, 0, 571, 572, 1, 0, 0, 0, 572, 574, 1, 0, 0, 0, 573, 571, 1, 0, 0, 0, 574, 575, 5, 10, 0, 0, 575, 576, 3, 148, 74, 0, 576, 577, 5, 5, 0, 0, 577, 79, 1, 0, 0, 0, 578, 583, 3, 94, 47, 0, 579, 583, 3, 96, 48, 0, 580, 583, 3, 98, 49, 0, 581, 583, 3, 100, 50, 0, 582, 578, 1, 0, 0, 0, 582, 579, 1, 0, 0, 0, 582, 580, 1, 0, 0, 0, 582, 581, 1, 0, 0, 0, 583, 81, 1, 0, 0, 0, 584, 586, 5, 8, 0, 0, 585, 584, 1, 0, 0, 0, 585, 586, 1, 0, 0, 0, 586, 587, 1, 0, 0, 0, 587, 588, 5, 114, 0, 0, 588, 589, 3, 104, 52, 0, 589, 83, 1, 0, 0, 0, 590, 592, 5, 8, 0, 0, 591, 590, 1, 0, 0, 0, 591, 592, 1, 0, 0, 0, 592, 593, 1, 0, 0, 0, 593, 594, 5, 114, 0, 0, 594, 595, 3, 102, 51, 0, 595, 85, 1, 0, 0, 0, 596, 599, 3, 82, 41, 0, 597, 599, 3, 84, 42, 0, 598, 596, 1, 0, 0, 0, 598, 597, 1, 0, 0, 0, 599, 87, 1, 0, 0, 0, 600, 602, 5, 8, 0, 0, 601, 600, 1, 0, 0, 0, 601, 602, 1, 0, 0, 0, 602, 603, 1, 0, 0, 0, 603, 604, 5, 114, 0, 0, 604, 605, 3, 108, 54, 0, 605, 89, 1, 0, 0, 0, 606, 608, 5, 8, 0, 0, 607, 606, 1, 0, 0, 0, 607, 608, 1, 0, 0, 0, 608, 609, 1, 0, 0, 0, 609, 610, 5, 114, 0, 0, 610, 611, 3, 110, 55, 0, 611, 91, 1, 0, 0, 0, 612, 614, 5, 8, 0, 0, 613, 612, 1, 0, 0, 0, 613, 614, 1, 0, 0, 0, 614, 615, 1, 0, 0, 0, 615, 616, 5, 114, 0, 0, 616, 617, 3, 112, 56, 0, 617, 93, 1, 0, 0, 0, 618, 623, 3, 86, 43, 0, 619, 623, 3, 88, 44, 0, 620, 623, 3, 90, 45, 0, 621, 623, 3, 92, 46, 0, 622, 618, 1, 0, 0, 0, 622, 619, 1, 0, 0, 0, 622, 620, 1, 0, 0, 0, 622, 621, 1, 0, 0, 0, 623, 95, 1, 0, 0, 0, 624, 625, 5, 112, 0, 0, 625, 97, 1, 0, 0, 0, 626, 627, 5, 113, 0, 0, 627, 99, 1, 0, 0, 0, 628, 629, 7, 0, 0, 0, 629, 101, 1, 0, 0, 0, 630, 631, 5, 105, 0, 0, 631, 103, 1, 0, 0, 0, 632, 633, 5, 106, 0, 0, 633, 105, 1, 0, 0, 0, 634, 637, 3, 102, 51, 0, 635, 637, 3, 104, 52, 0, 636, 634, 1, 0, 0, 0, 636, 635, 1, 0, 0, 0, 637, 107, 1, 0, 0, 0, 638, 639, 5, 107, 0, 0, 639, 109, 1, 0, 0, 0, 640, 641, 5, 17, 0, 0, 641, 111, 1, 0, 0, 0, 642, 643, 5, 108, 0, 0, 643, 113, 1, 0, 0, 0, 644, 649, 3, 106, 53, 0, 645, 649, 3, 108, 54, 0, 646, 649, 3, 110, 55, 0, 647, 649, 3, 112, 56, 0, 648, 644, 1, 0, 0, 0, 648, 645, 1, 0, 0, 0, 648, 646, 1, 0, 0, 0, 648, 647, 1, 0, 0, 0, 649, 115, 1, 0, 0, 0, 650, 651, 5, 109, 0, 0, 651, 117, 1, 0, 0, 0, 652, 653, 5, 110, 0, 0, 653, 119, 1, 0, 0, 0, 654, 655, 5, 111, 0, 0, 655, 121, 1, 0, 0, 0, 656, 661, 3, 114, 57, 0, 657, 661, 3, 116, 58, 0, 658, 661, 3, 120, 60, 0, 659, 661, 3, 118, 59, 0, 660, 656, 1, 0, 0, 0, 660, 657, 1, 0, 0, 0, 660, 658, 1, 0, 0, 0, 660, 659, 1, 0, 0, 0, 661, 123, 1, 0, 0, 0, 662, 663, 5, 3, 0, 0, 663, 664, 3, 126, 63, 0, 664, 665, 5, 5, 0, 0, 665, 666, 3, 84, 42, 0, 666, 667, 5, 4, 0, 0, 667, 125, 1, 0, 0, 0, 668, 672, 3, 122, 61, 0, 669, 672, 3, 124, 62, 0, 670, 672, 3, 196, 98, 0, 671, 668, 1, 0, 0, 0, 671, 669, 1, 0, 0, 0, 671, 670, 1, 0, 0, 0, 672, 127, 1, 0, 0, 0, 673, 674, 3, 126, 63, 0, 674, 675, 3, 138, 69, 0, 675, 683, 1, 0, 0, 0, 676, 677, 3, 196, 98, 0, 677, 678, 3, 138, 69, 0, 678, 683, 1, 0, 0, 0, 679, 680, 3, 164, 82, 0, 680, 681, 3, 138, 69, 0, 681, 683, 1, 0, 0, 0, 682, 673, 1, 0, 0, 0, 682, 676, 1, 0, 0, 0, 682, 679, 1, 0, 0, 0, 683, 129, 1, 0, 0, 0, 684, 685, 3, 126, 63, 0, 685, 686, 3, 138, 69, 0, 686, 131, 1, 0, 0, 0, 687, 688, 3, 126, 63, 0, 688, 689, 3, 138, 69, 0, 689, 694, 1, 0, 0, 0, 690, 691, 3, 164, 82, 0, 691, 692, 3, 138, 69, 0, 692, 694, 1, 0, 0, 0, 693, 687, 1, 0, 0, 0, 693, 690, 1, 0, 0, 0, 694, 133, 1, 0, 0, 0, 695, 696, 3, 126, 63, 0, 696, 697, 3, 138, 69, 0, 697, 135, 1, 0, 0, 0, 698, 699, 3, 164, 82, 0, 699, 700, 3, 138, 69, 0, 700, 706, 1, 0, 0, 0, 701, 702, 3, 196, 98, 0, 702, 703, 3, 138, 69, 0, 703, 706, 1, 0, 0, 0, 704, 706, 3, 126, 63, 0, 705, 698, 1, 0, 0, 0, 705, 701, 1, 0, 0, 0, 705, 704, 1, 0, 0, 0, 706, 137, 1, 0, 0, 0, 707, 708, 5, 1, 0, 0, 708, 709, 7, 1, 0, 0, 709, 139, 1, 0, 0, 0, 710, 711, 3, 142, 71, 0, 711, 712, 5, 1, 0, 0, 712, 713, 3, 144, 72, 0, 713, 141, 1, 0, 0, 0, 714, 715, 3, 196, 98, 0, 715, 143, 1, 0, 0, 0, 716, 717, 3, 196, 98, 0, 717, 145, 1, 0, 0, 0, 718, 719, 5, 115, 0, 0, 719, 147, 1, 0, 0, 0, 720, 724, 3, 146, 73, 0, 721, 723, 3, 150, 75, 0, 722, 721, 1, 0, 0, 0, 723, 726, 1, 0, 0, 0, 724, 722, 1, 0, 0, 0, 724, 725, 1, 0, 0, 0, 725, 149, 1, 0, 0, 0, 726, 724, 1, 0, 0, 0, 727, 730, 3, 152, 76, 0, 728, 730, 3, 154, 77, 0, 729, 727, 1, 0, 0, 0, 729, 728, 1, 0, 0, 0, 730, 151, 1, 0, 0, 0, 731, 732, 5, 1, 0, 0, 732, 733, 3, 196, 98, 0, 733, 153, 1, 0, 0, 0, 734, 735, 5, 3, 0, 0, 735, 736, 3, 84, 42, 0, 736, 737, 5, 4, 0, 0, 737, 742, 1, 0, 0, 0, 738, 739, 5, 3, 0, 0, 739, 740, 5, 114, 0, 0, 740, 742, 5, 4, 0, 0, 741, 734, 1, 0, 0, 0, 741, 738, 1, 0, 0, 0, 742, 155, 1, 0, 0, 0, 743, 748, 3, 80, 40, 0, 744, 748, 3, 148, 74, 0, 745, 748, 3, 140, 70, 0, 746, 748, 3, 158, 79, 0, 747, 743, 1, 0, 0, 0, 747, 744, 1, 0, 0, 0, 747, 745, 1, 0, 0, 0, 747, 746, 1, 0, 0, 0, 748, 157, 1, 0, 0, 0, 749, 750, 5, 17, 0, 0, 750, 751, 5, 6, 0, 0, 751, 759, 5, 18, 0, 0, 752, 753, 5, 19, 0, 0, 753, 754, 5, 1, 0, 0, 754, 759, 7, 2, 0, 0, 755, 756, 5, 22, 0, 0, 756, 757, 5, 1, 0, 0, 757, 759, 5, 23, 0, 0, 758, 749, 1, 0, 0, 0, 758, 752, 1, 0, 0, 0, 758, 755, 1, 0, 0, 0, 759, 159, 1, 0, 0, 0, 760, 761, 3, 196, 98, 0, 761, 762, 5, 9, 0, 0, 762, 763, 3, 126, 63, 0, 763, 764, 5, 5, 0, 0, 764, 161, 1, 0, 0, 0, 765, 766, 3, 196, 98, 0, 766, 767, 5, 9, 0, 0, 767, 768, 3, 134, 67, 0, 768, 769, 5, 5, 0, 0, 769, 163, 1, 0, 0, 0, 770, 771, 3, 140, 70, 0, 771, 772, 5, 2, 0, 0, 772, 773, 3, 196, 98, 0, 773, 165, 1, 0, 0, 0, 774, 778, 3, 136, 68, 0, 775, 778, 3, 164, 82, 0, 776, 778, 3, 168, 84, 0, 777, 774, 1, 0, 0, 0, 777, 775, 1, 0, 0, 0, 777, 776, 1, 0, 0, 0, 778, 167, 1, 0, 0, 0, 779, 780, 5, 17, 0, 0, 780, 781, 5, 1, 0, 0, 781, 782, 7, 3, 0, 0, 782, 169, 1, 0, 0, 0, 783, 786, 5, 42, 0, 0, 784, 785, 5, 1, 0, 0, 785, 787, 5, 24, 0, 0, 786, 784, 1, 0, 0, 0, 786, 787, 1, 0, 0, 0, 787, 795, 1, 0, 0, 0, 788, 795, 5, 43, 0, 0, 789, 795, 5, 44, 0, 0, 790, 795, 5, 45, 0, 0, 791, 795, 5, 46, 0, 0, 792, 795, 5, 47, 0, 0, 793, 795, 5, 48, 0, 0, 794, 783, 1, 0, 0, 0, 794, 788, 1, 0, 0, 0, 794, 789, 1, 0, 0, 0, 794, 790, 1, 0, 0, 0, 794, 791, 1, 0, 0, 0, 794, 792, 1, 0, 0, 0, 794, 793, 1, 0, 0, 0, 795, 171, 1, 0, 0, 0, 796, 799, 5, 49, 0, 0, 797, 798, 5, 1, 0, 0, 798, 800, 5, 24, 0, 0, 799, 797, 1, 0, 0, 0, 799, 800, 1, 0, 0, 0, 800, 847, 1, 0, 0, 0, 801, 804, 5, 50, 0, 0, 802, 803, 5, 1, 0, 0, 803, 805, 5, 24, 0, 0, 804, 802, 1, 0, 0, 0, 804, 805, 1, 0, 0, 0, 805, 847, 1, 0, 0, 0, 806, 809, 5, 51, 0, 0, 807, 808, 5, 1, 0, 0, 808, 810, 5, 24, 0, 0, 809, 807, 1, 0, 0, 0, 809, 810, 1, 0, 0, 0, 810, 847, 1, 0, 0, 0, 811, 814, 5, 52, 0, 0, 812, 813, 5, 1, 0, 0, 813, 815, 5, 24, 0, 0, 814, 812, 1, 0, 0, 0, 814, 815, 1, 0, 0, 0, 815, 847, 1, 0, 0, 0, 816, 819, 5, 53, 0, 0, 817, 818, 5, 1, 0, 0, 818, 820, 5, 24, 0, 0, 819, 817, 1, 0, 0, 0, 819, 820, 1, 0, 0, 0, 820, 847, 1, 0, 0, 0, 821, 824, 5, 54, 0, 0, 822, 823, 5, 1, 0, 0, 823, 825, 5, 24, 0, 0, 824, 822, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 847, 1, 0, 0, 0, 826, 829, 5, 55, 0, 0, 827, 828, 5, 1, 0, 0, 828, 830, 5, 24, 0, 0, 829, 827, 1, 0, 0, 0, 829, 830, 1, 0, 0, 0, 830, 847, 1, 0, 0, 0, 831, 834, 5, 56, 0, 0, 832, 833, 5, 1, 0, 0, 833, 835, 5, 24, 0, 0, 834, 832, 1, 0, 0, 0, 834, 835, 1, 0, 0, 0, 835, 847, 1, 0, 0, 0, 836, 847, 5, 57, 0, 0, 837, 847, 5, 58, 0, 0, 838, 847, 5, 59, 0, 0, 839, 847, 5, 60, 0, 0, 840, 847, 5, 61, 0, 0, 841, 847, 5, 62, 0, 0, 842, 847, 5, 63, 0, 0, 843, 847, 5, 64, 0, 0, 844, 847, 5, 65, 0, 0, 845, 847, 5, 66, 0, 0, 846, 796, 1, 0, 0, 0, 846, 801, 1, 0, 0, 0, 846, 806, 1, 0, 0, 0, 846, 811, 1, 0, 0, 0, 846, 816, 1, 0, 0, 0, 846, 821, 1, 0, 0, 0, 846, 826, 1, 0, 0, 0, 846, 831, 1, 0, 0, 0, 846, 836, 1, 0, 0, 0, 846, 837, 1, 0, 0, 0, 846, 838, 1, 0, 0, 0, 846, 839, 1, 0, 0, 0, 846, 840, 1, 0, 0, 0, 846, 841, 1, 0, 0, 0, 846, 842, 1, 0, 0, 0, 846, 843, 1, 0, 0, 0, 846, 844, 1, 0, 0, 0, 846, 845, 1, 0, 0, 0, 847, 173, 1, 0, 0, 0, 848, 849, 5, 67, 0, 0, 849, 850, 5, 1, 0, 0, 850, 851, 7, 4, 0, 0, 851, 175, 1, 0, 0, 0, 852, 853, 5, 70, 0, 0, 853, 854, 5, 1, 0, 0, 854, 855, 7, 4, 0, 0, 855, 177, 1, 0, 0, 0, 856, 857, 5, 71, 0, 0, 857, 858, 5, 1, 0, 0, 858, 859, 7, 5, 0, 0, 859, 179, 1, 0, 0, 0, 860, 861, 5, 72, 0, 0, 861, 862, 5, 1, 0, 0, 862, 863, 7, 6, 0, 0, 863, 181, 1, 0, 0, 0, 864, 865, 5, 73, 0, 0, 865, 866, 5, 1, 0, 0, 866, 867, 7, 7, 0, 0, 867, 183, 1, 0, 0, 0, 868, 871, 5, 89, 0, 0, 869, 870, 5, 1, 0, 0, 870, 872, 5, 90, 0, 0, 871, 869, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 185, 1, 0, 0, 0, 873, 874, 5, 91, 0, 0, 874, 875, 5, 1, 0, 0, 875, 876, 7, 4, 0, 0, 876, 187, 1, 0, 0, 0, 877, 878, 5, 32, 0, 0, 878, 879, 5, 1, 0, 0, 879, 880, 5, 33, 0, 0, 880, 189, 1, 0, 0, 0, 881, 882, 5, 28, 0, 0, 882, 883, 5, 1, 0, 0, 883, 884, 5, 29, 0, 0, 884, 191, 1, 0, 0, 0, 885, 886, 5, 37, 0, 0, 886, 887, 5, 1, 0, 0, 887, 890, 5, 38, 0, 0, 888, 890, 5, 39, 0, 0, 889, 885, 1, 0, 0, 0, 889, 888, 1, 0, 0, 0, 890, 193, 1, 0, 0, 0, 891, 892, 5, 116, 0, 0, 892, 195, 1, 0, 0, 0, 893, 894, 7, 8, 0, 0, 894, 197, 1, 0, 0, 0, 62, 203, 214, 216, 244, 252, 261, 267, 272, 293, 299, 305, 309, 329, 335, 354, 404, 414, 444, 488, 502, 517, 523, 537, 548, 553, 560, 562, 571, 582, 585, 591, 598, 601, 607, 613, 622, 636, 648, 660, 671, 682, 693, 705, 724, 729, 741, 747, 758, 777, 786, 794, 799, 804, 809, 814, 819, 824, 829, 834, 846, 871, 889] \ No newline at end of file +[4, 1, 119, 896, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 1, 0, 1, 0, 1, 1, 5, 1, 202, 8, 1, 10, 1, 12, 1, 205, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 215, 8, 1, 11, 1, 12, 1, 216, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 4, 6, 243, 8, 6, 11, 6, 12, 6, 244, 1, 7, 1, 7, 1, 7, 1, 7, 5, 7, 251, 8, 7, 10, 7, 12, 7, 254, 9, 7, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 260, 8, 8, 10, 8, 12, 8, 263, 9, 8, 1, 8, 4, 8, 266, 8, 8, 11, 8, 12, 8, 267, 1, 8, 5, 8, 271, 8, 8, 10, 8, 12, 8, 274, 9, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 292, 8, 11, 10, 11, 12, 11, 295, 9, 11, 1, 11, 5, 11, 298, 8, 11, 10, 11, 12, 11, 301, 9, 11, 1, 11, 5, 11, 304, 8, 11, 10, 11, 12, 11, 307, 9, 11, 1, 11, 3, 11, 310, 8, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 5, 14, 328, 8, 14, 10, 14, 12, 14, 331, 9, 14, 1, 14, 5, 14, 334, 8, 14, 10, 14, 12, 14, 337, 9, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 355, 8, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 5, 22, 403, 8, 22, 10, 22, 12, 22, 406, 9, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 415, 8, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 445, 8, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 489, 8, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 503, 8, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 3, 34, 518, 8, 34, 1, 34, 1, 34, 1, 35, 1, 35, 3, 35, 524, 8, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 4, 37, 536, 8, 37, 11, 37, 12, 37, 537, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 3, 38, 549, 8, 38, 1, 38, 5, 38, 552, 8, 38, 10, 38, 12, 38, 555, 9, 38, 1, 38, 1, 38, 4, 38, 559, 8, 38, 11, 38, 12, 38, 560, 3, 38, 563, 8, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 5, 39, 570, 8, 39, 10, 39, 12, 39, 573, 9, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 3, 40, 583, 8, 40, 1, 41, 3, 41, 586, 8, 41, 1, 41, 1, 41, 1, 41, 1, 42, 3, 42, 592, 8, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 3, 43, 599, 8, 43, 1, 44, 3, 44, 602, 8, 44, 1, 44, 1, 44, 1, 44, 1, 45, 3, 45, 608, 8, 45, 1, 45, 1, 45, 1, 45, 1, 46, 3, 46, 614, 8, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 623, 8, 47, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 53, 1, 53, 3, 53, 637, 8, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 3, 57, 649, 8, 57, 1, 58, 1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 661, 8, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 3, 63, 672, 8, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 3, 64, 683, 8, 64, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 694, 8, 66, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 706, 8, 68, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1, 74, 1, 74, 5, 74, 723, 8, 74, 10, 74, 12, 74, 726, 9, 74, 1, 75, 1, 75, 3, 75, 730, 8, 75, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 3, 77, 742, 8, 77, 1, 78, 1, 78, 1, 78, 1, 78, 3, 78, 748, 8, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 3, 79, 759, 8, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 3, 83, 778, 8, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 3, 85, 787, 8, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 3, 85, 795, 8, 85, 1, 86, 1, 86, 1, 86, 3, 86, 800, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 805, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 810, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 815, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 820, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 825, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 830, 8, 86, 1, 86, 1, 86, 1, 86, 3, 86, 835, 8, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 3, 86, 847, 8, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 3, 92, 872, 8, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 3, 96, 890, 8, 96, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 0, 0, 99, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 0, 9, 1, 0, 103, 104, 1, 0, 12, 16, 1, 0, 20, 21, 1, 0, 25, 26, 1, 0, 68, 69, 1, 0, 74, 79, 1, 0, 74, 88, 1, 0, 80, 82, 2, 0, 9, 113, 115, 116, 923, 0, 198, 1, 0, 0, 0, 2, 203, 1, 0, 0, 0, 4, 218, 1, 0, 0, 0, 6, 222, 1, 0, 0, 0, 8, 228, 1, 0, 0, 0, 10, 233, 1, 0, 0, 0, 12, 238, 1, 0, 0, 0, 14, 246, 1, 0, 0, 0, 16, 255, 1, 0, 0, 0, 18, 275, 1, 0, 0, 0, 20, 281, 1, 0, 0, 0, 22, 287, 1, 0, 0, 0, 24, 311, 1, 0, 0, 0, 26, 317, 1, 0, 0, 0, 28, 323, 1, 0, 0, 0, 30, 338, 1, 0, 0, 0, 32, 354, 1, 0, 0, 0, 34, 356, 1, 0, 0, 0, 36, 365, 1, 0, 0, 0, 38, 374, 1, 0, 0, 0, 40, 384, 1, 0, 0, 0, 42, 393, 1, 0, 0, 0, 44, 400, 1, 0, 0, 0, 46, 418, 1, 0, 0, 0, 48, 422, 1, 0, 0, 0, 50, 429, 1, 0, 0, 0, 52, 444, 1, 0, 0, 0, 54, 446, 1, 0, 0, 0, 56, 452, 1, 0, 0, 0, 58, 459, 1, 0, 0, 0, 60, 467, 1, 0, 0, 0, 62, 474, 1, 0, 0, 0, 64, 479, 1, 0, 0, 0, 66, 492, 1, 0, 0, 0, 68, 506, 1, 0, 0, 0, 70, 523, 1, 0, 0, 0, 72, 525, 1, 0, 0, 0, 74, 533, 1, 0, 0, 0, 76, 545, 1, 0, 0, 0, 78, 566, 1, 0, 0, 0, 80, 582, 1, 0, 0, 0, 82, 585, 1, 0, 0, 0, 84, 591, 1, 0, 0, 0, 86, 598, 1, 0, 0, 0, 88, 601, 1, 0, 0, 0, 90, 607, 1, 0, 0, 0, 92, 613, 1, 0, 0, 0, 94, 622, 1, 0, 0, 0, 96, 624, 1, 0, 0, 0, 98, 626, 1, 0, 0, 0, 100, 628, 1, 0, 0, 0, 102, 630, 1, 0, 0, 0, 104, 632, 1, 0, 0, 0, 106, 636, 1, 0, 0, 0, 108, 638, 1, 0, 0, 0, 110, 640, 1, 0, 0, 0, 112, 642, 1, 0, 0, 0, 114, 648, 1, 0, 0, 0, 116, 650, 1, 0, 0, 0, 118, 652, 1, 0, 0, 0, 120, 654, 1, 0, 0, 0, 122, 660, 1, 0, 0, 0, 124, 662, 1, 0, 0, 0, 126, 671, 1, 0, 0, 0, 128, 682, 1, 0, 0, 0, 130, 684, 1, 0, 0, 0, 132, 693, 1, 0, 0, 0, 134, 695, 1, 0, 0, 0, 136, 705, 1, 0, 0, 0, 138, 707, 1, 0, 0, 0, 140, 710, 1, 0, 0, 0, 142, 714, 1, 0, 0, 0, 144, 716, 1, 0, 0, 0, 146, 718, 1, 0, 0, 0, 148, 720, 1, 0, 0, 0, 150, 729, 1, 0, 0, 0, 152, 731, 1, 0, 0, 0, 154, 741, 1, 0, 0, 0, 156, 747, 1, 0, 0, 0, 158, 758, 1, 0, 0, 0, 160, 760, 1, 0, 0, 0, 162, 765, 1, 0, 0, 0, 164, 770, 1, 0, 0, 0, 166, 777, 1, 0, 0, 0, 168, 779, 1, 0, 0, 0, 170, 794, 1, 0, 0, 0, 172, 846, 1, 0, 0, 0, 174, 848, 1, 0, 0, 0, 176, 852, 1, 0, 0, 0, 178, 856, 1, 0, 0, 0, 180, 860, 1, 0, 0, 0, 182, 864, 1, 0, 0, 0, 184, 868, 1, 0, 0, 0, 186, 873, 1, 0, 0, 0, 188, 877, 1, 0, 0, 0, 190, 881, 1, 0, 0, 0, 192, 889, 1, 0, 0, 0, 194, 891, 1, 0, 0, 0, 196, 893, 1, 0, 0, 0, 198, 199, 3, 2, 1, 0, 199, 1, 1, 0, 0, 0, 200, 202, 3, 4, 2, 0, 201, 200, 1, 0, 0, 0, 202, 205, 1, 0, 0, 0, 203, 201, 1, 0, 0, 0, 203, 204, 1, 0, 0, 0, 204, 206, 1, 0, 0, 0, 205, 203, 1, 0, 0, 0, 206, 207, 5, 92, 0, 0, 207, 208, 3, 140, 70, 0, 208, 214, 5, 5, 0, 0, 209, 215, 3, 6, 3, 0, 210, 215, 3, 12, 6, 0, 211, 215, 3, 14, 7, 0, 212, 215, 3, 16, 8, 0, 213, 215, 3, 22, 11, 0, 214, 209, 1, 0, 0, 0, 214, 210, 1, 0, 0, 0, 214, 211, 1, 0, 0, 0, 214, 212, 1, 0, 0, 0, 214, 213, 1, 0, 0, 0, 215, 216, 1, 0, 0, 0, 216, 214, 1, 0, 0, 0, 216, 217, 1, 0, 0, 0, 217, 3, 1, 0, 0, 0, 218, 219, 5, 93, 0, 0, 219, 220, 3, 140, 70, 0, 220, 221, 5, 5, 0, 0, 221, 5, 1, 0, 0, 0, 222, 223, 5, 94, 0, 0, 223, 224, 3, 196, 98, 0, 224, 225, 5, 7, 0, 0, 225, 226, 3, 8, 4, 0, 226, 227, 3, 10, 5, 0, 227, 7, 1, 0, 0, 0, 228, 229, 5, 95, 0, 0, 229, 230, 5, 9, 0, 0, 230, 231, 3, 130, 65, 0, 231, 232, 5, 5, 0, 0, 232, 9, 1, 0, 0, 0, 233, 234, 5, 96, 0, 0, 234, 235, 5, 9, 0, 0, 235, 236, 3, 130, 65, 0, 236, 237, 5, 5, 0, 0, 237, 11, 1, 0, 0, 0, 238, 239, 5, 97, 0, 0, 239, 240, 3, 196, 98, 0, 240, 242, 5, 7, 0, 0, 241, 243, 3, 160, 80, 0, 242, 241, 1, 0, 0, 0, 243, 244, 1, 0, 0, 0, 244, 242, 1, 0, 0, 0, 244, 245, 1, 0, 0, 0, 245, 13, 1, 0, 0, 0, 246, 247, 5, 16, 0, 0, 247, 248, 3, 196, 98, 0, 248, 252, 5, 7, 0, 0, 249, 251, 3, 162, 81, 0, 250, 249, 1, 0, 0, 0, 251, 254, 1, 0, 0, 0, 252, 250, 1, 0, 0, 0, 252, 253, 1, 0, 0, 0, 253, 15, 1, 0, 0, 0, 254, 252, 1, 0, 0, 0, 255, 256, 5, 98, 0, 0, 256, 257, 3, 196, 98, 0, 257, 261, 5, 7, 0, 0, 258, 260, 3, 18, 9, 0, 259, 258, 1, 0, 0, 0, 260, 263, 1, 0, 0, 0, 261, 259, 1, 0, 0, 0, 261, 262, 1, 0, 0, 0, 262, 265, 1, 0, 0, 0, 263, 261, 1, 0, 0, 0, 264, 266, 3, 52, 26, 0, 265, 264, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 265, 1, 0, 0, 0, 267, 268, 1, 0, 0, 0, 268, 272, 1, 0, 0, 0, 269, 271, 3, 20, 10, 0, 270, 269, 1, 0, 0, 0, 271, 274, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 17, 1, 0, 0, 0, 274, 272, 1, 0, 0, 0, 275, 276, 5, 99, 0, 0, 276, 277, 3, 146, 73, 0, 277, 278, 5, 9, 0, 0, 278, 279, 3, 136, 68, 0, 279, 280, 5, 5, 0, 0, 280, 19, 1, 0, 0, 0, 281, 282, 5, 100, 0, 0, 282, 283, 3, 156, 78, 0, 283, 284, 5, 9, 0, 0, 284, 285, 3, 136, 68, 0, 285, 286, 5, 5, 0, 0, 286, 21, 1, 0, 0, 0, 287, 288, 5, 101, 0, 0, 288, 289, 3, 196, 98, 0, 289, 293, 5, 7, 0, 0, 290, 292, 3, 24, 12, 0, 291, 290, 1, 0, 0, 0, 292, 295, 1, 0, 0, 0, 293, 291, 1, 0, 0, 0, 293, 294, 1, 0, 0, 0, 294, 299, 1, 0, 0, 0, 295, 293, 1, 0, 0, 0, 296, 298, 3, 52, 26, 0, 297, 296, 1, 0, 0, 0, 298, 301, 1, 0, 0, 0, 299, 297, 1, 0, 0, 0, 299, 300, 1, 0, 0, 0, 300, 305, 1, 0, 0, 0, 301, 299, 1, 0, 0, 0, 302, 304, 3, 26, 13, 0, 303, 302, 1, 0, 0, 0, 304, 307, 1, 0, 0, 0, 305, 303, 1, 0, 0, 0, 305, 306, 1, 0, 0, 0, 306, 309, 1, 0, 0, 0, 307, 305, 1, 0, 0, 0, 308, 310, 3, 28, 14, 0, 309, 308, 1, 0, 0, 0, 309, 310, 1, 0, 0, 0, 310, 23, 1, 0, 0, 0, 311, 312, 5, 99, 0, 0, 312, 313, 3, 146, 73, 0, 313, 314, 5, 9, 0, 0, 314, 315, 3, 128, 64, 0, 315, 316, 5, 5, 0, 0, 316, 25, 1, 0, 0, 0, 317, 318, 5, 100, 0, 0, 318, 319, 3, 156, 78, 0, 319, 320, 5, 9, 0, 0, 320, 321, 3, 128, 64, 0, 321, 322, 5, 5, 0, 0, 322, 27, 1, 0, 0, 0, 323, 324, 5, 102, 0, 0, 324, 325, 3, 196, 98, 0, 325, 329, 5, 7, 0, 0, 326, 328, 3, 30, 15, 0, 327, 326, 1, 0, 0, 0, 328, 331, 1, 0, 0, 0, 329, 327, 1, 0, 0, 0, 329, 330, 1, 0, 0, 0, 330, 335, 1, 0, 0, 0, 331, 329, 1, 0, 0, 0, 332, 334, 3, 32, 16, 0, 333, 332, 1, 0, 0, 0, 334, 337, 1, 0, 0, 0, 335, 333, 1, 0, 0, 0, 335, 336, 1, 0, 0, 0, 336, 29, 1, 0, 0, 0, 337, 335, 1, 0, 0, 0, 338, 339, 5, 99, 0, 0, 339, 340, 3, 146, 73, 0, 340, 341, 5, 9, 0, 0, 341, 342, 3, 132, 66, 0, 342, 343, 5, 5, 0, 0, 343, 31, 1, 0, 0, 0, 344, 355, 3, 34, 17, 0, 345, 355, 3, 36, 18, 0, 346, 355, 3, 38, 19, 0, 347, 355, 3, 40, 20, 0, 348, 355, 3, 42, 21, 0, 349, 355, 3, 44, 22, 0, 350, 355, 3, 46, 23, 0, 351, 355, 3, 48, 24, 0, 352, 355, 3, 50, 25, 0, 353, 355, 3, 52, 26, 0, 354, 344, 1, 0, 0, 0, 354, 345, 1, 0, 0, 0, 354, 346, 1, 0, 0, 0, 354, 347, 1, 0, 0, 0, 354, 348, 1, 0, 0, 0, 354, 349, 1, 0, 0, 0, 354, 350, 1, 0, 0, 0, 354, 351, 1, 0, 0, 0, 354, 352, 1, 0, 0, 0, 354, 353, 1, 0, 0, 0, 355, 33, 1, 0, 0, 0, 356, 357, 5, 27, 0, 0, 357, 358, 3, 196, 98, 0, 358, 359, 5, 3, 0, 0, 359, 360, 3, 156, 78, 0, 360, 361, 5, 4, 0, 0, 361, 362, 5, 10, 0, 0, 362, 363, 3, 148, 74, 0, 363, 364, 5, 5, 0, 0, 364, 35, 1, 0, 0, 0, 365, 366, 5, 28, 0, 0, 366, 367, 3, 196, 98, 0, 367, 368, 5, 3, 0, 0, 368, 369, 3, 156, 78, 0, 369, 370, 5, 4, 0, 0, 370, 371, 5, 10, 0, 0, 371, 372, 3, 148, 74, 0, 372, 373, 5, 5, 0, 0, 373, 37, 1, 0, 0, 0, 374, 375, 3, 190, 95, 0, 375, 376, 3, 196, 98, 0, 376, 377, 5, 3, 0, 0, 377, 378, 3, 156, 78, 0, 378, 379, 5, 4, 0, 0, 379, 380, 3, 156, 78, 0, 380, 381, 5, 10, 0, 0, 381, 382, 3, 148, 74, 0, 382, 383, 5, 5, 0, 0, 383, 39, 1, 0, 0, 0, 384, 385, 5, 30, 0, 0, 385, 386, 3, 156, 78, 0, 386, 387, 5, 10, 0, 0, 387, 388, 3, 196, 98, 0, 388, 389, 5, 3, 0, 0, 389, 390, 3, 156, 78, 0, 390, 391, 5, 4, 0, 0, 391, 392, 5, 5, 0, 0, 392, 41, 1, 0, 0, 0, 393, 394, 5, 31, 0, 0, 394, 395, 3, 196, 98, 0, 395, 396, 5, 3, 0, 0, 396, 397, 3, 156, 78, 0, 397, 398, 5, 4, 0, 0, 398, 399, 5, 5, 0, 0, 399, 43, 1, 0, 0, 0, 400, 404, 3, 188, 94, 0, 401, 403, 3, 156, 78, 0, 402, 401, 1, 0, 0, 0, 403, 406, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 404, 405, 1, 0, 0, 0, 405, 407, 1, 0, 0, 0, 406, 404, 1, 0, 0, 0, 407, 408, 5, 10, 0, 0, 408, 409, 3, 148, 74, 0, 409, 414, 5, 9, 0, 0, 410, 415, 3, 114, 57, 0, 411, 415, 3, 116, 58, 0, 412, 415, 3, 120, 60, 0, 413, 415, 3, 118, 59, 0, 414, 410, 1, 0, 0, 0, 414, 411, 1, 0, 0, 0, 414, 412, 1, 0, 0, 0, 414, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 417, 5, 5, 0, 0, 417, 45, 1, 0, 0, 0, 418, 419, 5, 34, 0, 0, 419, 420, 3, 194, 97, 0, 420, 421, 5, 5, 0, 0, 421, 47, 1, 0, 0, 0, 422, 423, 3, 186, 93, 0, 423, 424, 3, 156, 78, 0, 424, 425, 3, 156, 78, 0, 425, 426, 5, 11, 0, 0, 426, 427, 3, 194, 97, 0, 427, 428, 5, 5, 0, 0, 428, 49, 1, 0, 0, 0, 429, 430, 5, 35, 0, 0, 430, 431, 3, 148, 74, 0, 431, 432, 5, 5, 0, 0, 432, 51, 1, 0, 0, 0, 433, 445, 3, 54, 27, 0, 434, 445, 3, 56, 28, 0, 435, 445, 3, 58, 29, 0, 436, 445, 3, 60, 30, 0, 437, 445, 3, 62, 31, 0, 438, 445, 3, 64, 32, 0, 439, 445, 3, 70, 35, 0, 440, 445, 3, 72, 36, 0, 441, 445, 3, 74, 37, 0, 442, 445, 3, 76, 38, 0, 443, 445, 3, 78, 39, 0, 444, 433, 1, 0, 0, 0, 444, 434, 1, 0, 0, 0, 444, 435, 1, 0, 0, 0, 444, 436, 1, 0, 0, 0, 444, 437, 1, 0, 0, 0, 444, 438, 1, 0, 0, 0, 444, 439, 1, 0, 0, 0, 444, 440, 1, 0, 0, 0, 444, 441, 1, 0, 0, 0, 444, 442, 1, 0, 0, 0, 444, 443, 1, 0, 0, 0, 445, 53, 1, 0, 0, 0, 446, 447, 3, 170, 85, 0, 447, 448, 3, 156, 78, 0, 448, 449, 5, 10, 0, 0, 449, 450, 3, 148, 74, 0, 450, 451, 5, 5, 0, 0, 451, 55, 1, 0, 0, 0, 452, 453, 3, 172, 86, 0, 453, 454, 3, 156, 78, 0, 454, 455, 3, 156, 78, 0, 455, 456, 5, 10, 0, 0, 456, 457, 3, 148, 74, 0, 457, 458, 5, 5, 0, 0, 458, 57, 1, 0, 0, 0, 459, 460, 5, 36, 0, 0, 460, 461, 3, 156, 78, 0, 461, 462, 3, 156, 78, 0, 462, 463, 3, 156, 78, 0, 463, 464, 5, 10, 0, 0, 464, 465, 3, 148, 74, 0, 465, 466, 5, 5, 0, 0, 466, 59, 1, 0, 0, 0, 467, 468, 3, 174, 87, 0, 468, 469, 3, 156, 78, 0, 469, 470, 3, 156, 78, 0, 470, 471, 5, 10, 0, 0, 471, 472, 3, 148, 74, 0, 472, 473, 5, 5, 0, 0, 473, 61, 1, 0, 0, 0, 474, 475, 3, 176, 88, 0, 475, 476, 3, 156, 78, 0, 476, 477, 3, 156, 78, 0, 477, 478, 5, 5, 0, 0, 478, 63, 1, 0, 0, 0, 479, 480, 3, 178, 89, 0, 480, 481, 3, 156, 78, 0, 481, 482, 3, 156, 78, 0, 482, 483, 5, 10, 0, 0, 483, 484, 3, 148, 74, 0, 484, 488, 5, 9, 0, 0, 485, 489, 3, 116, 58, 0, 486, 489, 3, 108, 54, 0, 487, 489, 3, 110, 55, 0, 488, 485, 1, 0, 0, 0, 488, 486, 1, 0, 0, 0, 488, 487, 1, 0, 0, 0, 489, 490, 1, 0, 0, 0, 490, 491, 5, 5, 0, 0, 491, 65, 1, 0, 0, 0, 492, 493, 3, 180, 90, 0, 493, 494, 3, 156, 78, 0, 494, 495, 5, 10, 0, 0, 495, 496, 3, 148, 74, 0, 496, 502, 5, 9, 0, 0, 497, 503, 3, 114, 57, 0, 498, 503, 3, 116, 58, 0, 499, 503, 3, 120, 60, 0, 500, 503, 3, 124, 62, 0, 501, 503, 3, 196, 98, 0, 502, 497, 1, 0, 0, 0, 502, 498, 1, 0, 0, 0, 502, 499, 1, 0, 0, 0, 502, 500, 1, 0, 0, 0, 502, 501, 1, 0, 0, 0, 503, 504, 1, 0, 0, 0, 504, 505, 5, 5, 0, 0, 505, 67, 1, 0, 0, 0, 506, 507, 3, 182, 91, 0, 507, 508, 3, 156, 78, 0, 508, 509, 3, 156, 78, 0, 509, 510, 5, 10, 0, 0, 510, 511, 3, 148, 74, 0, 511, 517, 5, 9, 0, 0, 512, 518, 3, 114, 57, 0, 513, 518, 3, 116, 58, 0, 514, 518, 3, 120, 60, 0, 515, 518, 3, 124, 62, 0, 516, 518, 3, 196, 98, 0, 517, 512, 1, 0, 0, 0, 517, 513, 1, 0, 0, 0, 517, 514, 1, 0, 0, 0, 517, 515, 1, 0, 0, 0, 517, 516, 1, 0, 0, 0, 518, 519, 1, 0, 0, 0, 519, 520, 5, 5, 0, 0, 520, 69, 1, 0, 0, 0, 521, 524, 3, 66, 33, 0, 522, 524, 3, 68, 34, 0, 523, 521, 1, 0, 0, 0, 523, 522, 1, 0, 0, 0, 524, 71, 1, 0, 0, 0, 525, 526, 3, 192, 96, 0, 526, 527, 3, 156, 78, 0, 527, 528, 3, 156, 78, 0, 528, 529, 3, 156, 78, 0, 529, 530, 5, 10, 0, 0, 530, 531, 3, 148, 74, 0, 531, 532, 5, 5, 0, 0, 532, 73, 1, 0, 0, 0, 533, 535, 3, 184, 92, 0, 534, 536, 3, 156, 78, 0, 535, 534, 1, 0, 0, 0, 536, 537, 1, 0, 0, 0, 537, 535, 1, 0, 0, 0, 537, 538, 1, 0, 0, 0, 538, 539, 1, 0, 0, 0, 539, 540, 5, 10, 0, 0, 540, 541, 3, 148, 74, 0, 541, 542, 5, 9, 0, 0, 542, 543, 3, 166, 83, 0, 543, 544, 5, 5, 0, 0, 544, 75, 1, 0, 0, 0, 545, 548, 5, 40, 0, 0, 546, 549, 3, 164, 82, 0, 547, 549, 3, 196, 98, 0, 548, 546, 1, 0, 0, 0, 548, 547, 1, 0, 0, 0, 549, 553, 1, 0, 0, 0, 550, 552, 3, 156, 78, 0, 551, 550, 1, 0, 0, 0, 552, 555, 1, 0, 0, 0, 553, 551, 1, 0, 0, 0, 553, 554, 1, 0, 0, 0, 554, 562, 1, 0, 0, 0, 555, 553, 1, 0, 0, 0, 556, 558, 5, 10, 0, 0, 557, 559, 3, 148, 74, 0, 558, 557, 1, 0, 0, 0, 559, 560, 1, 0, 0, 0, 560, 558, 1, 0, 0, 0, 560, 561, 1, 0, 0, 0, 561, 563, 1, 0, 0, 0, 562, 556, 1, 0, 0, 0, 562, 563, 1, 0, 0, 0, 563, 564, 1, 0, 0, 0, 564, 565, 5, 5, 0, 0, 565, 77, 1, 0, 0, 0, 566, 567, 5, 41, 0, 0, 567, 571, 3, 196, 98, 0, 568, 570, 3, 156, 78, 0, 569, 568, 1, 0, 0, 0, 570, 573, 1, 0, 0, 0, 571, 569, 1, 0, 0, 0, 571, 572, 1, 0, 0, 0, 572, 574, 1, 0, 0, 0, 573, 571, 1, 0, 0, 0, 574, 575, 5, 10, 0, 0, 575, 576, 3, 148, 74, 0, 576, 577, 5, 5, 0, 0, 577, 79, 1, 0, 0, 0, 578, 583, 3, 94, 47, 0, 579, 583, 3, 96, 48, 0, 580, 583, 3, 98, 49, 0, 581, 583, 3, 100, 50, 0, 582, 578, 1, 0, 0, 0, 582, 579, 1, 0, 0, 0, 582, 580, 1, 0, 0, 0, 582, 581, 1, 0, 0, 0, 583, 81, 1, 0, 0, 0, 584, 586, 5, 8, 0, 0, 585, 584, 1, 0, 0, 0, 585, 586, 1, 0, 0, 0, 586, 587, 1, 0, 0, 0, 587, 588, 5, 114, 0, 0, 588, 589, 3, 104, 52, 0, 589, 83, 1, 0, 0, 0, 590, 592, 5, 8, 0, 0, 591, 590, 1, 0, 0, 0, 591, 592, 1, 0, 0, 0, 592, 593, 1, 0, 0, 0, 593, 594, 5, 114, 0, 0, 594, 595, 3, 102, 51, 0, 595, 85, 1, 0, 0, 0, 596, 599, 3, 82, 41, 0, 597, 599, 3, 84, 42, 0, 598, 596, 1, 0, 0, 0, 598, 597, 1, 0, 0, 0, 599, 87, 1, 0, 0, 0, 600, 602, 5, 8, 0, 0, 601, 600, 1, 0, 0, 0, 601, 602, 1, 0, 0, 0, 602, 603, 1, 0, 0, 0, 603, 604, 5, 114, 0, 0, 604, 605, 3, 108, 54, 0, 605, 89, 1, 0, 0, 0, 606, 608, 5, 8, 0, 0, 607, 606, 1, 0, 0, 0, 607, 608, 1, 0, 0, 0, 608, 609, 1, 0, 0, 0, 609, 610, 5, 114, 0, 0, 610, 611, 3, 110, 55, 0, 611, 91, 1, 0, 0, 0, 612, 614, 5, 8, 0, 0, 613, 612, 1, 0, 0, 0, 613, 614, 1, 0, 0, 0, 614, 615, 1, 0, 0, 0, 615, 616, 5, 114, 0, 0, 616, 617, 3, 112, 56, 0, 617, 93, 1, 0, 0, 0, 618, 623, 3, 86, 43, 0, 619, 623, 3, 88, 44, 0, 620, 623, 3, 90, 45, 0, 621, 623, 3, 92, 46, 0, 622, 618, 1, 0, 0, 0, 622, 619, 1, 0, 0, 0, 622, 620, 1, 0, 0, 0, 622, 621, 1, 0, 0, 0, 623, 95, 1, 0, 0, 0, 624, 625, 5, 112, 0, 0, 625, 97, 1, 0, 0, 0, 626, 627, 5, 113, 0, 0, 627, 99, 1, 0, 0, 0, 628, 629, 7, 0, 0, 0, 629, 101, 1, 0, 0, 0, 630, 631, 5, 105, 0, 0, 631, 103, 1, 0, 0, 0, 632, 633, 5, 106, 0, 0, 633, 105, 1, 0, 0, 0, 634, 637, 3, 102, 51, 0, 635, 637, 3, 104, 52, 0, 636, 634, 1, 0, 0, 0, 636, 635, 1, 0, 0, 0, 637, 107, 1, 0, 0, 0, 638, 639, 5, 107, 0, 0, 639, 109, 1, 0, 0, 0, 640, 641, 5, 17, 0, 0, 641, 111, 1, 0, 0, 0, 642, 643, 5, 108, 0, 0, 643, 113, 1, 0, 0, 0, 644, 649, 3, 106, 53, 0, 645, 649, 3, 108, 54, 0, 646, 649, 3, 110, 55, 0, 647, 649, 3, 112, 56, 0, 648, 644, 1, 0, 0, 0, 648, 645, 1, 0, 0, 0, 648, 646, 1, 0, 0, 0, 648, 647, 1, 0, 0, 0, 649, 115, 1, 0, 0, 0, 650, 651, 5, 109, 0, 0, 651, 117, 1, 0, 0, 0, 652, 653, 5, 110, 0, 0, 653, 119, 1, 0, 0, 0, 654, 655, 5, 111, 0, 0, 655, 121, 1, 0, 0, 0, 656, 661, 3, 114, 57, 0, 657, 661, 3, 116, 58, 0, 658, 661, 3, 120, 60, 0, 659, 661, 3, 118, 59, 0, 660, 656, 1, 0, 0, 0, 660, 657, 1, 0, 0, 0, 660, 658, 1, 0, 0, 0, 660, 659, 1, 0, 0, 0, 661, 123, 1, 0, 0, 0, 662, 663, 5, 3, 0, 0, 663, 664, 3, 126, 63, 0, 664, 665, 5, 5, 0, 0, 665, 666, 3, 84, 42, 0, 666, 667, 5, 4, 0, 0, 667, 125, 1, 0, 0, 0, 668, 672, 3, 122, 61, 0, 669, 672, 3, 124, 62, 0, 670, 672, 3, 196, 98, 0, 671, 668, 1, 0, 0, 0, 671, 669, 1, 0, 0, 0, 671, 670, 1, 0, 0, 0, 672, 127, 1, 0, 0, 0, 673, 674, 3, 126, 63, 0, 674, 675, 3, 138, 69, 0, 675, 683, 1, 0, 0, 0, 676, 677, 3, 196, 98, 0, 677, 678, 3, 138, 69, 0, 678, 683, 1, 0, 0, 0, 679, 680, 3, 164, 82, 0, 680, 681, 3, 138, 69, 0, 681, 683, 1, 0, 0, 0, 682, 673, 1, 0, 0, 0, 682, 676, 1, 0, 0, 0, 682, 679, 1, 0, 0, 0, 683, 129, 1, 0, 0, 0, 684, 685, 3, 126, 63, 0, 685, 686, 3, 138, 69, 0, 686, 131, 1, 0, 0, 0, 687, 688, 3, 126, 63, 0, 688, 689, 3, 138, 69, 0, 689, 694, 1, 0, 0, 0, 690, 691, 3, 164, 82, 0, 691, 692, 3, 138, 69, 0, 692, 694, 1, 0, 0, 0, 693, 687, 1, 0, 0, 0, 693, 690, 1, 0, 0, 0, 694, 133, 1, 0, 0, 0, 695, 696, 3, 126, 63, 0, 696, 697, 3, 138, 69, 0, 697, 135, 1, 0, 0, 0, 698, 699, 3, 164, 82, 0, 699, 700, 3, 138, 69, 0, 700, 706, 1, 0, 0, 0, 701, 702, 3, 196, 98, 0, 702, 703, 3, 138, 69, 0, 703, 706, 1, 0, 0, 0, 704, 706, 3, 126, 63, 0, 705, 698, 1, 0, 0, 0, 705, 701, 1, 0, 0, 0, 705, 704, 1, 0, 0, 0, 706, 137, 1, 0, 0, 0, 707, 708, 5, 1, 0, 0, 708, 709, 7, 1, 0, 0, 709, 139, 1, 0, 0, 0, 710, 711, 3, 142, 71, 0, 711, 712, 5, 1, 0, 0, 712, 713, 3, 144, 72, 0, 713, 141, 1, 0, 0, 0, 714, 715, 3, 196, 98, 0, 715, 143, 1, 0, 0, 0, 716, 717, 3, 196, 98, 0, 717, 145, 1, 0, 0, 0, 718, 719, 5, 115, 0, 0, 719, 147, 1, 0, 0, 0, 720, 724, 3, 146, 73, 0, 721, 723, 3, 150, 75, 0, 722, 721, 1, 0, 0, 0, 723, 726, 1, 0, 0, 0, 724, 722, 1, 0, 0, 0, 724, 725, 1, 0, 0, 0, 725, 149, 1, 0, 0, 0, 726, 724, 1, 0, 0, 0, 727, 730, 3, 152, 76, 0, 728, 730, 3, 154, 77, 0, 729, 727, 1, 0, 0, 0, 729, 728, 1, 0, 0, 0, 730, 151, 1, 0, 0, 0, 731, 732, 5, 1, 0, 0, 732, 733, 3, 196, 98, 0, 733, 153, 1, 0, 0, 0, 734, 735, 5, 3, 0, 0, 735, 736, 3, 84, 42, 0, 736, 737, 5, 4, 0, 0, 737, 742, 1, 0, 0, 0, 738, 739, 5, 3, 0, 0, 739, 740, 5, 114, 0, 0, 740, 742, 5, 4, 0, 0, 741, 734, 1, 0, 0, 0, 741, 738, 1, 0, 0, 0, 742, 155, 1, 0, 0, 0, 743, 748, 3, 158, 79, 0, 744, 748, 3, 80, 40, 0, 745, 748, 3, 148, 74, 0, 746, 748, 3, 140, 70, 0, 747, 743, 1, 0, 0, 0, 747, 744, 1, 0, 0, 0, 747, 745, 1, 0, 0, 0, 747, 746, 1, 0, 0, 0, 748, 157, 1, 0, 0, 0, 749, 750, 5, 17, 0, 0, 750, 751, 5, 6, 0, 0, 751, 759, 5, 18, 0, 0, 752, 753, 5, 19, 0, 0, 753, 754, 5, 1, 0, 0, 754, 759, 7, 2, 0, 0, 755, 756, 5, 22, 0, 0, 756, 757, 5, 1, 0, 0, 757, 759, 5, 23, 0, 0, 758, 749, 1, 0, 0, 0, 758, 752, 1, 0, 0, 0, 758, 755, 1, 0, 0, 0, 759, 159, 1, 0, 0, 0, 760, 761, 3, 196, 98, 0, 761, 762, 5, 9, 0, 0, 762, 763, 3, 126, 63, 0, 763, 764, 5, 5, 0, 0, 764, 161, 1, 0, 0, 0, 765, 766, 3, 196, 98, 0, 766, 767, 5, 9, 0, 0, 767, 768, 3, 134, 67, 0, 768, 769, 5, 5, 0, 0, 769, 163, 1, 0, 0, 0, 770, 771, 3, 140, 70, 0, 771, 772, 5, 2, 0, 0, 772, 773, 3, 196, 98, 0, 773, 165, 1, 0, 0, 0, 774, 778, 3, 168, 84, 0, 775, 778, 3, 136, 68, 0, 776, 778, 3, 164, 82, 0, 777, 774, 1, 0, 0, 0, 777, 775, 1, 0, 0, 0, 777, 776, 1, 0, 0, 0, 778, 167, 1, 0, 0, 0, 779, 780, 5, 17, 0, 0, 780, 781, 5, 1, 0, 0, 781, 782, 7, 3, 0, 0, 782, 169, 1, 0, 0, 0, 783, 786, 5, 42, 0, 0, 784, 785, 5, 1, 0, 0, 785, 787, 5, 24, 0, 0, 786, 784, 1, 0, 0, 0, 786, 787, 1, 0, 0, 0, 787, 795, 1, 0, 0, 0, 788, 795, 5, 43, 0, 0, 789, 795, 5, 44, 0, 0, 790, 795, 5, 45, 0, 0, 791, 795, 5, 46, 0, 0, 792, 795, 5, 47, 0, 0, 793, 795, 5, 48, 0, 0, 794, 783, 1, 0, 0, 0, 794, 788, 1, 0, 0, 0, 794, 789, 1, 0, 0, 0, 794, 790, 1, 0, 0, 0, 794, 791, 1, 0, 0, 0, 794, 792, 1, 0, 0, 0, 794, 793, 1, 0, 0, 0, 795, 171, 1, 0, 0, 0, 796, 799, 5, 49, 0, 0, 797, 798, 5, 1, 0, 0, 798, 800, 5, 24, 0, 0, 799, 797, 1, 0, 0, 0, 799, 800, 1, 0, 0, 0, 800, 847, 1, 0, 0, 0, 801, 804, 5, 50, 0, 0, 802, 803, 5, 1, 0, 0, 803, 805, 5, 24, 0, 0, 804, 802, 1, 0, 0, 0, 804, 805, 1, 0, 0, 0, 805, 847, 1, 0, 0, 0, 806, 809, 5, 51, 0, 0, 807, 808, 5, 1, 0, 0, 808, 810, 5, 24, 0, 0, 809, 807, 1, 0, 0, 0, 809, 810, 1, 0, 0, 0, 810, 847, 1, 0, 0, 0, 811, 814, 5, 52, 0, 0, 812, 813, 5, 1, 0, 0, 813, 815, 5, 24, 0, 0, 814, 812, 1, 0, 0, 0, 814, 815, 1, 0, 0, 0, 815, 847, 1, 0, 0, 0, 816, 819, 5, 53, 0, 0, 817, 818, 5, 1, 0, 0, 818, 820, 5, 24, 0, 0, 819, 817, 1, 0, 0, 0, 819, 820, 1, 0, 0, 0, 820, 847, 1, 0, 0, 0, 821, 824, 5, 54, 0, 0, 822, 823, 5, 1, 0, 0, 823, 825, 5, 24, 0, 0, 824, 822, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 847, 1, 0, 0, 0, 826, 829, 5, 55, 0, 0, 827, 828, 5, 1, 0, 0, 828, 830, 5, 24, 0, 0, 829, 827, 1, 0, 0, 0, 829, 830, 1, 0, 0, 0, 830, 847, 1, 0, 0, 0, 831, 834, 5, 56, 0, 0, 832, 833, 5, 1, 0, 0, 833, 835, 5, 24, 0, 0, 834, 832, 1, 0, 0, 0, 834, 835, 1, 0, 0, 0, 835, 847, 1, 0, 0, 0, 836, 847, 5, 57, 0, 0, 837, 847, 5, 58, 0, 0, 838, 847, 5, 59, 0, 0, 839, 847, 5, 60, 0, 0, 840, 847, 5, 61, 0, 0, 841, 847, 5, 62, 0, 0, 842, 847, 5, 63, 0, 0, 843, 847, 5, 64, 0, 0, 844, 847, 5, 65, 0, 0, 845, 847, 5, 66, 0, 0, 846, 796, 1, 0, 0, 0, 846, 801, 1, 0, 0, 0, 846, 806, 1, 0, 0, 0, 846, 811, 1, 0, 0, 0, 846, 816, 1, 0, 0, 0, 846, 821, 1, 0, 0, 0, 846, 826, 1, 0, 0, 0, 846, 831, 1, 0, 0, 0, 846, 836, 1, 0, 0, 0, 846, 837, 1, 0, 0, 0, 846, 838, 1, 0, 0, 0, 846, 839, 1, 0, 0, 0, 846, 840, 1, 0, 0, 0, 846, 841, 1, 0, 0, 0, 846, 842, 1, 0, 0, 0, 846, 843, 1, 0, 0, 0, 846, 844, 1, 0, 0, 0, 846, 845, 1, 0, 0, 0, 847, 173, 1, 0, 0, 0, 848, 849, 5, 67, 0, 0, 849, 850, 5, 1, 0, 0, 850, 851, 7, 4, 0, 0, 851, 175, 1, 0, 0, 0, 852, 853, 5, 70, 0, 0, 853, 854, 5, 1, 0, 0, 854, 855, 7, 4, 0, 0, 855, 177, 1, 0, 0, 0, 856, 857, 5, 71, 0, 0, 857, 858, 5, 1, 0, 0, 858, 859, 7, 5, 0, 0, 859, 179, 1, 0, 0, 0, 860, 861, 5, 72, 0, 0, 861, 862, 5, 1, 0, 0, 862, 863, 7, 6, 0, 0, 863, 181, 1, 0, 0, 0, 864, 865, 5, 73, 0, 0, 865, 866, 5, 1, 0, 0, 866, 867, 7, 7, 0, 0, 867, 183, 1, 0, 0, 0, 868, 871, 5, 89, 0, 0, 869, 870, 5, 1, 0, 0, 870, 872, 5, 90, 0, 0, 871, 869, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 185, 1, 0, 0, 0, 873, 874, 5, 91, 0, 0, 874, 875, 5, 1, 0, 0, 875, 876, 7, 4, 0, 0, 876, 187, 1, 0, 0, 0, 877, 878, 5, 32, 0, 0, 878, 879, 5, 1, 0, 0, 879, 880, 5, 33, 0, 0, 880, 189, 1, 0, 0, 0, 881, 882, 5, 28, 0, 0, 882, 883, 5, 1, 0, 0, 883, 884, 5, 29, 0, 0, 884, 191, 1, 0, 0, 0, 885, 886, 5, 37, 0, 0, 886, 887, 5, 1, 0, 0, 887, 890, 5, 38, 0, 0, 888, 890, 5, 39, 0, 0, 889, 885, 1, 0, 0, 0, 889, 888, 1, 0, 0, 0, 890, 193, 1, 0, 0, 0, 891, 892, 5, 116, 0, 0, 892, 195, 1, 0, 0, 0, 893, 894, 7, 8, 0, 0, 894, 197, 1, 0, 0, 0, 62, 203, 214, 216, 244, 252, 261, 267, 272, 293, 299, 305, 309, 329, 335, 354, 404, 414, 444, 488, 502, 517, 523, 537, 548, 553, 560, 562, 571, 582, 585, 591, 598, 601, 607, 613, 622, 636, 648, 660, 671, 682, 693, 705, 724, 729, 741, 747, 758, 777, 786, 794, 799, 804, 809, 814, 819, 824, 829, 834, 846, 871, 889] \ No newline at end of file diff --git a/vanguard/aleo/parser/AleoParser.py b/vanguard/aleo/parser/AleoParser.py index 1d7122d..a140826 100644 --- a/vanguard/aleo/parser/AleoParser.py +++ b/vanguard/aleo/parser/AleoParser.py @@ -278,8 +278,8 @@ def serializedATN(): 5,1,0,0,732,733,3,196,98,0,733,153,1,0,0,0,734,735,5,3,0,0,735,736, 3,84,42,0,736,737,5,4,0,0,737,742,1,0,0,0,738,739,5,3,0,0,739,740, 5,114,0,0,740,742,5,4,0,0,741,734,1,0,0,0,741,738,1,0,0,0,742,155, - 1,0,0,0,743,748,3,80,40,0,744,748,3,148,74,0,745,748,3,140,70,0, - 746,748,3,158,79,0,747,743,1,0,0,0,747,744,1,0,0,0,747,745,1,0,0, + 1,0,0,0,743,748,3,158,79,0,744,748,3,80,40,0,745,748,3,148,74,0, + 746,748,3,140,70,0,747,743,1,0,0,0,747,744,1,0,0,0,747,745,1,0,0, 0,747,746,1,0,0,0,748,157,1,0,0,0,749,750,5,17,0,0,750,751,5,6,0, 0,751,759,5,18,0,0,752,753,5,19,0,0,753,754,5,1,0,0,754,759,7,2, 0,0,755,756,5,22,0,0,756,757,5,1,0,0,757,759,5,23,0,0,758,749,1, @@ -287,8 +287,8 @@ def serializedATN(): 196,98,0,761,762,5,9,0,0,762,763,3,126,63,0,763,764,5,5,0,0,764, 161,1,0,0,0,765,766,3,196,98,0,766,767,5,9,0,0,767,768,3,134,67, 0,768,769,5,5,0,0,769,163,1,0,0,0,770,771,3,140,70,0,771,772,5,2, - 0,0,772,773,3,196,98,0,773,165,1,0,0,0,774,778,3,136,68,0,775,778, - 3,164,82,0,776,778,3,168,84,0,777,774,1,0,0,0,777,775,1,0,0,0,777, + 0,0,772,773,3,196,98,0,773,165,1,0,0,0,774,778,3,168,84,0,775,778, + 3,136,68,0,776,778,3,164,82,0,777,774,1,0,0,0,777,775,1,0,0,0,777, 776,1,0,0,0,778,167,1,0,0,0,779,780,5,17,0,0,780,781,5,1,0,0,781, 782,7,3,0,0,782,169,1,0,0,0,783,786,5,42,0,0,784,785,5,1,0,0,785, 787,5,24,0,0,786,784,1,0,0,0,786,787,1,0,0,0,787,795,1,0,0,0,788, @@ -5997,6 +5997,10 @@ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): super().__init__(parent, invokingState) self.parser = parser + def operand_preset(self): + return self.getTypedRuleContext(AleoParser.Operand_presetContext,0) + + def literal(self): return self.getTypedRuleContext(AleoParser.LiteralContext,0) @@ -6009,10 +6013,6 @@ def program_id(self): return self.getTypedRuleContext(AleoParser.Program_idContext,0) - def operand_preset(self): - return self.getTypedRuleContext(AleoParser.Operand_presetContext,0) - - def getRuleIndex(self): return AleoParser.RULE_operand @@ -6038,25 +6038,25 @@ def operand(self): if la_ == 1: self.enterOuterAlt(localctx, 1) self.state = 743 - self.literal() + self.operand_preset() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) self.state = 744 - self.register_access() + self.literal() pass elif la_ == 3: self.enterOuterAlt(localctx, 3) self.state = 745 - self.program_id() + self.register_access() pass elif la_ == 4: self.enterOuterAlt(localctx, 4) self.state = 746 - self.operand_preset() + self.program_id() pass @@ -6346,6 +6346,10 @@ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): super().__init__(parent, invokingState) self.parser = parser + def destination_group(self): + return self.getTypedRuleContext(AleoParser.Destination_groupContext,0) + + def register_type(self): return self.getTypedRuleContext(AleoParser.Register_typeContext,0) @@ -6354,10 +6358,6 @@ def locator(self): return self.getTypedRuleContext(AleoParser.LocatorContext,0) - def destination_group(self): - return self.getTypedRuleContext(AleoParser.Destination_groupContext,0) - - def getRuleIndex(self): return AleoParser.RULE_cast_destination @@ -6383,19 +6383,19 @@ def cast_destination(self): if la_ == 1: self.enterOuterAlt(localctx, 1) self.state = 774 - self.register_type() + self.destination_group() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) self.state = 775 - self.locator() + self.register_type() pass elif la_ == 3: self.enterOuterAlt(localctx, 3) self.state = 776 - self.destination_group() + self.locator() pass