Skip to content

Commit

Permalink
Constant expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcere committed Jul 8, 2024
1 parent 057b2bf commit ee3c92c
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/parser/cfg_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def _build_spec_for_block(self, instructions, map_instructions: Dict):
in_val = self.assignment_dict.get(assigment)
if in_val.startswith("0x"): #It is a push value
func = map_instructions.get(("PUSH",tuple([in_val])),-1)
if func == -1:
if func == -1 and in_val not in self.avoid_push:
push_name = "PUSH" if int(in_val,16) != 0 else "PUSH0"
inst_idx = instrs_idx.get(push_name, 0)
instrs_idx[push_name] = inst_idx+1
Expand Down
5 changes: 4 additions & 1 deletion src/parser/cfg_instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ def build_spec(self, out_idx, instrs_idx, map_instructions, assignments: Dict[st
instr_spec = build_custom_function_spec(op_name, input_args, self.out_args, self.builtin_args)

instrs_idx[op_name] = idx+1
map_instructions[(op_name,tuple(self.in_args))] = instr_spec
if len(self.out_args) == 1 and self.out_args[0].startswith("0x"):
map_instructions[("PUSH", tuple(self.out_args))] = instr_spec
else:
map_instructions[(op_name,tuple(self.in_args))] = instr_spec

instructions.append(instr_spec)

Expand Down
93 changes: 89 additions & 4 deletions src/parser/parser.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,77 @@
import json
from typing import Union, Dict, Any
from typing import Union, Dict, Any, List
from parser.cfg import CFG
from parser.cfg_block import CFGBlock
from parser.cfg_instruction import CFGInstruction
from parser.utils_parser import check_instruction_validity, check_block_validity
import math
import uuid


def is_hex(s):
try:
int(s, 16)
return True
except ValueError:
return False

def negate_value(hex_value: str):
return hex(2**256+~int(hex_value,16))

def is_mask(hex_value: str):
return all(digit=="f" or digit=="F" for digit in hex_value[2:])


def determine_opcodes_mask(hex_value: str) -> List[Dict]:
power_of_two = int(hex_value, 16) + 1
shift = math.log2(power_of_two)
shl_idx = uuid.uuid4()
opcodes = [
{
"op": "SHL",
"in": ["0x01", hex(int(shift))],
"out": [str(shl_idx)]
},
{
"op": "SUB",
"in": ["0x01", str(shl_idx)],
"out": [str(hex_value)]
}
]
return opcodes

def large_push_expression(hex_value: str, already: Dict) -> List[Dict]:
if hex_value in already:
return []
# print(hex_value[2:], is_mask(hex_value))
if is_mask(hex_value) and len(hex_value) > 6:
# Check if the negation has not been processed yet. If so, the corresponding
# instruction has been already included
if negate_value(hex_value) not in already:
return determine_opcodes_mask(hex_value)
negated_value = negate_value(hex_value)
if len(negated_value) < len(hex_value) and is_mask(negated_value):

if negated_value in already:
opcodes = []
previous_opcodes = already[negated_value]
in_args = [opcode["out"] for opcode in previous_opcodes if opcode["op"] == "SUB"]
assert len(in_args) == 1, "Wrong generation of push code"

else:
opcodes = determine_opcodes_mask(negated_value)
in_args = [opcode["out"] for opcode in opcodes if opcode["op"] == "SUB"]
assert len(in_args) == 1, "Wrong generation of push code"

opcodes.append({
"op": "NOT",
"in": in_args[0],
"out": [str(hex_value)]
})
return opcodes
else:
return []


def parse_instruction(ins_json: Dict[str,Any]) -> CFGInstruction:
in_arg = ins_json.get("in",-1)
Expand All @@ -21,9 +89,18 @@ def parse_instruction(ins_json: Dict[str,Any]) -> CFGInstruction:
return instruction


def parse_assignment(assignment: Dict[str, Any], assignment_dict: Dict[str, str]) -> None:
def parse_assignment(assignment: Dict[str, Any], assignment_dict: Dict[str, str], already_transformed: Dict):
instrs = []
not_representing = set()
for in_var, out_var in zip(assignment["in"], assignment["out"]):
assignment_dict[out_var] = in_var
if is_hex(in_var):
extra_instructions = large_push_expression(in_var, already_transformed)
instrs.extend(extra_instructions)
if len(extra_instructions) > 0:
already_transformed[in_var] = extra_instructions
not_representing.add(in_var)
return instrs, not_representing

def parse_block(block_json: Dict[str,Any]) -> CFGBlock:

Expand All @@ -33,17 +110,25 @@ def parse_block(block_json: Dict[str,Any]) -> CFGBlock:
block_type = block_json.get("type", -1)

check_block_validity(block_id, block_instructions, block_exit, block_type)

avoid_push = set()
list_cfg_instructions = []
assignment_dict = dict()
already_transformed = dict()
for instructions in block_instructions:
if "assignment" in instructions:
parse_assignment(instructions, assignment_dict)
subinstrs, not_repr = parse_assignment(instructions, assignment_dict, already_transformed)
avoid_push.update(not_repr)
for subinstr in subinstrs:

cfg_instruction = parse_instruction(subinstr)
list_cfg_instructions.append(cfg_instruction)

else:
cfg_instruction =parse_instruction(instructions)
list_cfg_instructions.append(cfg_instruction)

block = CFGBlock(block_id,list_cfg_instructions, block_type, assignment_dict)
block.avoid_push = avoid_push

return block_id, block, block_exit

Expand Down

0 comments on commit ee3c92c

Please sign in to comment.