| *.pyc | |||||
| elmo/* | |||||
| **/__pycache__/** | |||||
| build/* | |||||
| python_elmo.egg-info/* | |||||
| *.pyc | |||||
| .DS_Store |
| recursive-include elmo/projects * | |||||
| recursive-include elmo/templates * | |||||
| recursive-exclude elmo/elmo-tool * |
| # Online ELMO | |||||
| # Python ELMO | |||||
| _Online ELMO_ is a Python library which proposes an encapsulation of the project _ELMO_. | |||||
| _Python ELMO_ is a Python library which proposes an encapsulation of the project _ELMO_. | |||||
| [MOW17] **Towards Practical Tools for Side | [MOW17] **Towards Practical Tools for Side | ||||
| Channel Aware Software Engineering : ’Grey Box’ Modelling for Instruction Leakages** | Channel Aware Software Engineering : ’Grey Box’ Modelling for Instruction Leakages** | ||||
| ## Requirements | ## Requirements | ||||
| To use _Online ELMO_, you need at least Python3.5 and the packages present in the file requirements.txt | |||||
| To use _Python ELMO_, you need at least Python3.5 and ```numpy```. | |||||
| ```bash | |||||
| pip3 install -r requirements.txt | |||||
| ``` | |||||
| The library will install and compile ELMO. So, you need the GCC compiler collection and the command/utility 'make' (for more details, see the documentation of ELMO). On Ubuntu/Debian, | |||||
| The library will install and compile ELMO. So, you need the GCC compiler collection and the command/utility 'make' (for more details, see the documentation of ELMO). On Ubuntu/Debian, | |||||
| ```bash | ```bash | ||||
| sudo apt install build-essential | sudo apt install build-essential | ||||
| ## Installation | ## Installation | ||||
| First, download _Online ELMO_. | |||||
| First, download _Python ELMO_. | |||||
| ```bash | ```bash | ||||
| git clone https://git.aprilas.fr/tfeneuil/OnlineELMO | |||||
| git clone https://git.aprilas.fr/tfeneuil/python-elmo | |||||
| ``` | ``` | ||||
| And then, install ELMO thanks to the script of installation. | And then, install ELMO thanks to the script of installation. | ||||
| ```bash | ```bash | ||||
| ./install | |||||
| python setup.py install | |||||
| ``` | ``` | ||||
| ## Usage | ## Usage | ||||
| To start a new project, you can use the following function. | To start a new project, you can use the following function. | ||||
| ```python | ```python | ||||
| from elmo_online.manage import create_simulation | |||||
| from elmo.manage import create_simulation | |||||
| create_simulation( | create_simulation( | ||||
| 'dilithium', # The (relative) path of the project | 'dilithium', # The (relative) path of the project | ||||
| 'DilithiumSimulation' # The classname of the simulation | 'DilithiumSimulation' # The classname of the simulation | ||||
| ### List all the available simulation | ### List all the available simulation | ||||
| ```python | ```python | ||||
| from elmo_online.manage import search_simulations | |||||
| from elmo.manage import search_simulations | |||||
| search_simulations('.') | search_simulations('.') | ||||
| ``` | ``` | ||||
| 'KyberNTTSimulation': <class 'KyberNTTSimulation'>} | 'KyberNTTSimulation': <class 'KyberNTTSimulation'>} | ||||
| ``` | ``` | ||||
| _Online ELMO_ offers a example project to you in the repository _projects/Examples_ of the module. This example is a project to generate traces of the execution of the NTT implemented in the cryptosystem [Kyber](https://pq-crystals.org/kyber/). | |||||
| _Python ELMO_ offers a example project to you in the repository _projects/Examples_ of the module. This example is a project to generate traces of the execution of the NTT implemented in the cryptosystem [Kyber](https://pq-crystals.org/kyber/). | |||||
| ### Use a simulation project | ### Use a simulation project | ||||
| Warning! Before using it, you have to compile your project thanks to the provided Makefile. | Warning! Before using it, you have to compile your project thanks to the provided Makefile. | ||||
| ```python | ```python | ||||
| from elmo_online.manage import get_simulation | |||||
| from elmo.manage import get_simulation | |||||
| KyberNTTSimulation = get_simulation_via_classname('KyberNTTSimulation') | KyberNTTSimulation = get_simulation_via_classname('KyberNTTSimulation') | ||||
| import numpy as np | import numpy as np | ||||
| # And now, I can draw and analyse the traces | # And now, I can draw and analyse the traces | ||||
| ``` | ``` | ||||
| ### Use a simulution project thanks to a server | |||||
| ### Use a simulation project thanks to a server | |||||
| Sometimes, it is impossible to run the simulation thanks the simple method _run_ of the project class. Indeed, sometimes the Python script is executed in the environment where _Online ELMO_ cannot launch the ELMO tool. For example, it is the case where _Online ELMO_ is used in SageMath on Windows. On Windows, SageMath installation relies on the Cygwin POSIX emulation system and it can be a problem. | |||||
| Sometimes, it is impossible to run the simulation thanks the simple method _run_ of the project class. Indeed, sometimes the Python script is executed in the environment where _Python ELMO_ cannot launch the ELMO tool. For example, it is the case where _Python ELMO_ is used in SageMath on Windows. On Windows, SageMath installation relies on the Cygwin POSIX emulation system and it can be a problem. | |||||
| To offer a solution, _Online ELMO_ can be used thanks to a link client-server. The idea is you must launch the script _run_server.py_ which will listen (by default) at port 5000 in localhost. | |||||
| To offer a solution, _Online ELMO_ can be used thanks to a link client-server. The idea is you must launch the script _run\_server.py_ which will listen (by default) at port 5000 in localhost. | |||||
| ```bash | ```bash | ||||
| python3 run_server.py | |||||
| python -m elmo run-server | |||||
| ``` | ``` | ||||
| And after, you can manipulate the projects as described in the previous section by replacing _run_ to _run_online_. | |||||
| And after, you can manipulate the projects as described in the previous section by replacing _run_ to _run\_online_. | |||||
| ```python | ```python | ||||
| from elmo_online.manage import get_simulation | |||||
| KyberNTTSimulation = get_simulation_via_classname('KyberNTTSimulation') | |||||
| from elmo.manage import get_simulation | |||||
| KyberNTTSimulation = get_simulation('KyberNTTSimulation') | |||||
| import numpy as np | import numpy as np | ||||
| Kyber512 = {'k': 2, 'n': 256} | Kyber512 = {'k': 2, 'n': 256} | ||||
| # And now, I can draw and analyse the traces | # And now, I can draw and analyse the traces | ||||
| ``` | ``` | ||||
| Warning! Using the _run_online_ method doesn't exempt you from compiling the project with the provided Makefile. | |||||
| Warning! Using the _run\_online_ method doesn't exempt you from compiling the project with the provided Makefile. | |||||
| ### Use the ELMO Engine | ### Use the ELMO Engine | ||||
| - "_**OTHER**_" for the other instructions. | - "_**OTHER**_" for the other instructions. | ||||
| ```python | ```python | ||||
| from elmo_online.engine import ELMOEngine, Instr | |||||
| from elmo.engine import ELMOEngine, Instr | |||||
| engine = ELMOEngine() | engine = ELMOEngine() | ||||
| for i in range(0, 256): | for i in range(0, 256): | ||||
| engine.add_point( | engine.add_point( |
| import os, shutil | |||||
| import re | |||||
| from .manage import create_simulation | |||||
| print('Creation of a new simulation project...') | |||||
| ### Create the repository of the projects | |||||
| global_path = 'projects' | |||||
| os.makedirs(global_path, exist_ok=True) | |||||
| ### Get the project classname | |||||
| project_classname = '' | |||||
| search = re.compile(r'[^a-zA-Z0-9_]').search | |||||
| while not project_classname: | |||||
| classname = input(' - What is the project classname? ') | |||||
| if search(classname): | |||||
| print(' > Illegal characters detected! Please enter a name with only the following characters : a-z, A-Z, 0-9, and "_".') | |||||
| else: | |||||
| project_classname = classname.strip() | |||||
| ### Get and create the project repository | |||||
| search = re.compile(r'[^a-zA-Z0-9.-_/]').search | |||||
| project_repository = '' | |||||
| while not project_repository: | |||||
| repository = input(' - What is the project repository? ') | |||||
| if search(repository): | |||||
| print('Illegal characters detected! Please enter a name with only the following characters : a-z, A-Z, 0-9, ".", "-", "_" and "/".') | |||||
| else: | |||||
| project_repository = repository | |||||
| project_path = global_path+'/'+repository | |||||
| project_path = create_simulation(project_path, classname) | |||||
| print('') | |||||
| print('Creation complete !') | |||||
| print(' - Project repository: {}'.format(project_path)) | |||||
| print(' - Project class "{}" in {}'.format(project_classname, project_path+'/projectclass.py')) | |||||
| print(' - Linker script: {}'.format(project_path+'/project.ld'))) | |||||
| print('') | |||||
| print('Please don\'t to compile the project with the present Makefile before using it!') |
| elmo-tool/* | |||||
| *.pyc |
| from .manage import * | |||||
| from .engine import * |
| import sys | |||||
| from .utils import Color | |||||
| if len(sys.argv) <= 1: | |||||
| print(Color.FAIL + 'Please enter an instruction.' + Color.ENDC) | |||||
| exit() | |||||
| command = sys.argv[1] | |||||
| if command == 'create-simulation': | |||||
| import os, shutil | |||||
| import re | |||||
| print('Creation of a new simulation project...') | |||||
| ### Create the repository of the projects | |||||
| global_path = 'projects' | |||||
| os.makedirs(global_path, exist_ok=True) | |||||
| ### Get the project classname | |||||
| project_classname = '' | |||||
| search = re.compile(r'[^a-zA-Z0-9_]').search | |||||
| while not project_classname: | |||||
| classname = input(' - What is the project classname? ') | |||||
| if search(classname): | |||||
| print(' > Illegal characters detected! Please enter a name with only the following characters : a-z, A-Z, 0-9, and "_".') | |||||
| else: | |||||
| project_classname = classname.strip() | |||||
| ### Get and create the project repository | |||||
| search = re.compile(r'[^a-zA-Z0-9.-_/]').search | |||||
| project_repository = '' | |||||
| while not project_repository: | |||||
| repository = input(' - What is the project repository? ') | |||||
| if search(repository): | |||||
| print('Illegal characters detected! Please enter a name with only the following characters : a-z, A-Z, 0-9, ".", "-", "_" and "/".') | |||||
| else: | |||||
| project_repository = repository | |||||
| project_path = global_path+'/'+repository | |||||
| from .manage import create_simulation | |||||
| project_path = create_simulation(project_path, classname) | |||||
| print('') | |||||
| print('Creation complete !') | |||||
| print(' - Project repository: {}'.format(project_path)) | |||||
| print(' - Project class "{}" in {}'.format(project_classname, project_path+'/projectclass.py')) | |||||
| print(' - Linker script: {}'.format(project_path+'/project.ld')) | |||||
| print('') | |||||
| print('Please don\'t to compile the project with the present Makefile before using it!') | |||||
| exit() | |||||
| if command == 'run-server': | |||||
| from .server.servicethread import ListeningThread | |||||
| from .executorthread import ExecutorThread | |||||
| def do_main_program(): | |||||
| global thread, stop | |||||
| thread = ListeningThread('localhost', 5000, ExecutorThread) | |||||
| thread.start() | |||||
| def program_cleanup(signum, frame): | |||||
| global thread, stop | |||||
| thread.stop() | |||||
| stop = True | |||||
| thread = None | |||||
| stop = False | |||||
| # Execute | |||||
| print("Executing...") | |||||
| do_main_program() | |||||
| print("Done ! And now, listening...") | |||||
| import signal | |||||
| signal.signal(signal.SIGINT, program_cleanup) | |||||
| signal.signal(signal.SIGTERM, program_cleanup) | |||||
| # Wait | |||||
| import time | |||||
| while not stop: | |||||
| time.sleep(1) | |||||
| exit() | |||||
| print(Color.FAIL + 'Unknown Command.' + Color.ENDC) | |||||
| exit() |
| import os | |||||
| ### Configuration of the module | |||||
| TEMPLATE_REPOSITORY = 'templates' | |||||
| PROJECTS_REPOSITORY = 'projects' | |||||
| ELMO_TOOL_REPOSITORY = 'elmo-tool' | |||||
| ELMO_EXECUTABLE_NAME = 'elmo' | |||||
| ELMO_OUTPUT_ENCODING = 'latin-1' | |||||
| ELMO_INPUT_FILE_NAME = 'input.txt' | |||||
| MODULE_PATH = os.path.dirname(os.path.abspath(__file__)) | |||||
| SEARCH_EXCLUSION_TAG = 'EXCLUDE-FROM-SIMULATION-SEARCH' |
| import os | import os | ||||
| from enum import IntEnum, unique | from enum import IntEnum, unique | ||||
| def hweight(n): | |||||
| c = 0 | |||||
| while n>0: | |||||
| c += (n & 1) | |||||
| n >>= 1 | |||||
| return c | |||||
| def hdistance(x,y): | |||||
| return hweight(x^y) | |||||
| def binary_writing(n, nb_bits=32, with_hamming=False): | |||||
| n = np.array(n) | |||||
| w, h = np.zeros((nb_bits, len(n))), np.zeros((len(n))) | |||||
| for ind in range(nb_bits): | |||||
| w[ind] = (n & 1) | |||||
| h += w[ind] | |||||
| n >>= 1 | |||||
| ind += 1 | |||||
| return (w, h) if with_hamming else w | |||||
| from .utils import binary_writing | |||||
| from .config import ELMO_TOOL_REPOSITORY | |||||
| @unique | @unique | ||||
| class Instr(IntEnum): | |||||
| class Instruction(IntEnum): | |||||
| EOR = 0 | EOR = 0 | ||||
| LSL = 1 | LSL = 1 | ||||
| STR = 2 | STR = 2 | ||||
| LDR = 3 | LDR = 3 | ||||
| MUL = 4 | MUL = 4 | ||||
| OTHER = 5 | OTHER = 5 | ||||
| # Short name for 'Instruction' class | |||||
| Instr = Instruction | |||||
| PREVIOUS = 0 | PREVIOUS = 0 | ||||
| CURRENT = 1 | CURRENT = 1 | ||||
| return coeffs | return coeffs | ||||
| def load_coefficients(self): | def load_coefficients(self): | ||||
| filename = os.path.dirname(os.path.abspath(__file__))+'/elmo/coeffs.txt' | |||||
| filename = os.path.join( | |||||
| os.path.dirname(os.path.abspath(__file__)), | |||||
| ELMO_TOOL_REPOSITORY, | |||||
| 'coeffs.txt', | |||||
| ) | |||||
| self.coefficients = None | self.coefficients = None | ||||
| with open(filename, 'r') as _file: | with open(filename, 'r') as _file: | ||||
| self.coefficients = np.array([list(map(float, line.split())) for line in _file.readlines()[:2153]]) | self.coefficients = np.array([list(map(float, line.split())) for line in _file.readlines()[:2153]]) |
| import os, shutil | |||||
| import re | |||||
| import inspect | |||||
| import subprocess | |||||
| import sys | |||||
| from os.path import join as pjoin | |||||
| from .config import ( | |||||
| TEMPLATE_REPOSITORY, | |||||
| PROJECTS_REPOSITORY, | |||||
| ELMO_TOOL_REPOSITORY, | |||||
| ELMO_EXECUTABLE_NAME, | |||||
| MODULE_PATH, | |||||
| ELMO_OUTPUT_ENCODING, | |||||
| SEARCH_EXCLUSION_TAG, | |||||
| ) | |||||
| from .project_base import SimulationProject | |||||
| from .utils import Color | |||||
| ############ GETTERS ############ | |||||
| def search_simulations_in_repository(repository, criteria=lambda x:True): | |||||
| """ Search simulation classes in the 'repository' verifying the 'criteria' | |||||
| Return a list of 'SimulationProject' subclasses | |||||
| :repository: Repository of the searched simulation classes (string) | |||||
| :criteria: Boolean function with 'SimulationProject' subclasses for input | |||||
| """ | |||||
| projects = {} | |||||
| from .utils import write | |||||
| for root, repositories, files in os.walk(repository): | |||||
| for filename in files: | |||||
| if re.fullmatch(r'.*project.*\.py', filename): | |||||
| complete_filename = pjoin(root, filename) | |||||
| # Encapsulate the project | |||||
| globals = { | |||||
| #'__builtins__': {'__build_class__': __build_class__}, | |||||
| 'SimulationProject': SimulationProject, | |||||
| 'write': write, | |||||
| } | |||||
| locals = {} | |||||
| # Read the project code | |||||
| with open(complete_filename, 'r') as _file: | |||||
| project = ''.join(_file.read()) | |||||
| if ('SimulationProject' not in project) or (SEARCH_EXCLUSION_TAG in project): | |||||
| continue # Exclude this file | |||||
| exec(project, globals, locals) | |||||
| # Extract the simulations | |||||
| for key, obj in locals.items(): | |||||
| if inspect.isclass(obj) and issubclass(obj, SimulationProject): | |||||
| if criteria(obj): | |||||
| if key in projects: | |||||
| print(Color.WARNING + \ | |||||
| 'Warning! Many simulations with the same name. ' + \ | |||||
| 'Simulation ignored: {} in {}'.format( | |||||
| key, complete_filename[len(repository)+1:]) + \ | |||||
| Color.ENDC | |||||
| ) | |||||
| else: | |||||
| obj.set_project_directory(os.path.abspath(root)) | |||||
| projects[key] = obj | |||||
| return projects | |||||
| def search_simulations_in_module(criteria=lambda x:True): | |||||
| """ Search simulation classes among the module projects verifying the 'criteria' | |||||
| Return a list of 'SimulationProject' subclasses | |||||
| :criteria: Boolean function with 'SimulationProject' subclasses for input | |||||
| """ | |||||
| projects_path = pjoin(MODULE_PATH, PROJECTS_REPOSITORY) | |||||
| return search_simulations_in_repository(projects_path, criteria) | |||||
| def search_simulations(repository='.', criteria=lambda x:True): | |||||
| """ Search simulation classes in the 'repository' and among | |||||
| the module projects verifying the 'criteria' | |||||
| Return a list of 'SimulationProject' subclasses | |||||
| :repository: Repository of the searched simulation classes (string) | |||||
| :criteria: Boolean function with 'SimulationProject' subclasses for input | |||||
| """ | |||||
| projects = search_simulations_in_repository(repository, criteria) | |||||
| module_projects = search_simulations_in_module(criteria) | |||||
| for key, project in module_projects.items(): | |||||
| if key not in projects: | |||||
| projects[key] = project | |||||
| return projects | |||||
| class SimulationNotFoundError(Exception): | |||||
| pass | |||||
| class TooManySimulationsError(Exception): | |||||
| pass | |||||
| def get_simulation(classname=None, repository='.'): | |||||
| """ Get a simulation class in the 'repository' with the specific 'classname' | |||||
| Return a subclass of 'SimulationProject' class | |||||
| :classname: Name of the searched simulation class (string, optional) | |||||
| :repository: Repository of the searched simulation class (string, optional) | |||||
| """ | |||||
| criteria = lambda x: True | |||||
| if classname is not None: | |||||
| criteria = lambda x: x.__name__ == classname.strip() | |||||
| projects = search_simulations(repository, criteria) | |||||
| if len(projects) == 1: | |||||
| return list(projects.values())[0] | |||||
| elif len(projects) < 1: | |||||
| raise SimulationNotFoundError() | |||||
| else: | |||||
| raise TooManySimulationsError() | |||||
| ############ SETTERS ############ | |||||
| def create_simulation(repository, classname, is_a_module_project=False): | |||||
| """ Create a Simulation Project. | |||||
| It builds a repository with the standard content for the project. | |||||
| Return the absolute path of the created repository | |||||
| :repository: Name of repository which will be created (string) | |||||
| :classname: Name of the Python class to manage the project (string) | |||||
| :is_a_module_project: If True and :repository: is a relative path, | |||||
| create the project among the module projects. | |||||
| """ | |||||
| # Update the repository, if necessary | |||||
| if is_a_module_project and (not os.path.isabs(repository)): | |||||
| repository = pjoin( | |||||
| MODULE_PATH, | |||||
| PROJECTS_REPOSITORY, | |||||
| repository, | |||||
| ) | |||||
| # Build the project repository | |||||
| try: | |||||
| os.makedirs(repository, exist_ok=False) | |||||
| except FileExistsError as err: | |||||
| raise FileExistsError('Error, a project with this repository already exists!') from err | |||||
| elmo_path = pjoin(MODULE_PATH, ELMO_TOOL_REPOSITORY) | |||||
| template_path = pjoin(MODULE_PATH, TEMPLATE_REPOSITORY) | |||||
| project_path = repository | |||||
| # Add standard content in the project | |||||
| files_from_ELMO = [ | |||||
| pjoin('Examples', 'elmoasmfunctions.o'), | |||||
| pjoin('Examples', 'elmoasmfunctions.s'), | |||||
| pjoin('Examples', 'elmoasmfunctionsdef.h'), | |||||
| pjoin('Examples', 'DPATraces', 'MBedAES', 'vector.o'), | |||||
| ] | |||||
| files_from_templates = [ | |||||
| 'elmoasmfunctionsdef-extension.h', | |||||
| 'Makefile', | |||||
| 'project.c' | |||||
| ] | |||||
| for filename in files_from_ELMO: | |||||
| shutil.copy(pjoin(elmo_path, filename), project_path) | |||||
| for filename in files_from_templates: | |||||
| shutil.copy(pjoin(template_path, filename), project_path) | |||||
| shutil.copy( | |||||
| pjoin(elmo_path, 'Examples', 'DPATraces', 'MBedAES', 'MBedAES.ld'), | |||||
| pjoin(project_path, 'project.ld') | |||||
| ) | |||||
| # Create the project class | |||||
| with open(pjoin(template_path, 'projectclass.txt')) as _source: | |||||
| code = ''.join(_source.readlines()) | |||||
| code = code.replace('{{PROJECTCLASSNAME}}', classname) | |||||
| with open(pjoin(project_path, 'projectclass.py'), 'w') as _dest: | |||||
| _dest.write(code) | |||||
| # Return the path of the created repository | |||||
| return os.path.abspath(project_path) | |||||
| ############ USAGE FUNCTIONS ############ | |||||
| class DontFindBinaryError(Exception): | |||||
| pass | |||||
| def execute_simulation(project): | |||||
| """ Execute a simulation of the power leakage using ELMO tool | |||||
| Return the output and the errors of the execution of ELMO tool | |||||
| :project: Subclass of 'SimulationProject' defining all the parameters of the simulation | |||||
| """ | |||||
| elmo_path = pjoin(MODULE_PATH, ELMO_TOOL_REPOSITORY) | |||||
| # Some checking before executing | |||||
| if not isinstance(project, SimulationProject): | |||||
| raise TypeError('The project is not an instance of \'SimulationProject\' class.') | |||||
| leaking_binary_path = pjoin(project.get_project_directory(), project.get_binary_path()) | |||||
| if not os.path.isfile(leaking_binary_path): | |||||
| raise BinaryNotFoundError('Binary not found. Did you compile your project?') | |||||
| if not os.path.isfile(pjoin(elmo_path, ELMO_EXECUTABLE_NAME)): | |||||
| raise Exception('Installation Error: the executable of the ELMO tool is not found.') | |||||
| # Launch generation of the traces by launching ELMO | |||||
| command = '{} "{}"'.format( | |||||
| pjoin('.', ELMO_EXECUTABLE_NAME), | |||||
| leaking_binary_path, | |||||
| ) | |||||
| process = subprocess.Popen(command, shell=True, | |||||
| cwd=elmo_path, executable='/bin/bash', | |||||
| stdout=subprocess.PIPE, stderr=subprocess.PIPE | |||||
| ) | |||||
| # Follow the generation | |||||
| output, error = b'', b'' | |||||
| num_trace = 0 | |||||
| while True: | |||||
| output_line = process.stdout.readline() | |||||
| error_line = process.stderr.readline() | |||||
| if (not output_line) and (not error_line) and (process.poll() is not None): | |||||
| break | |||||
| if error_line: | |||||
| error += error_line | |||||
| if output_line: | |||||
| output += output_line | |||||
| if 'TRACE NO' in output_line.decode(ELMO_OUTPUT_ENCODING): | |||||
| num_trace += 1 | |||||
| return_code = process.poll() | |||||
| # Treat data | |||||
| output = output.decode(ELMO_OUTPUT_ENCODING) if output else None | |||||
| error = error.decode(ELMO_OUTPUT_ENCODING) if error else None | |||||
| nb_traces = None | |||||
| nb_instructions = None | |||||
| if output: | |||||
| nb_traces = output.count('TRACE NO') | |||||
| nb_instructions_pattern = re.compile(r'\s*instructions/cy..es\s+(\d+)\s*') | |||||
| for line in output.split('\n'): | |||||
| res = nb_instructions_pattern.fullmatch(line) | |||||
| if res: | |||||
| nb_instructions = res.group(1) | |||||
| # Return results | |||||
| return { | |||||
| 'nb_traces': nb_traces, | |||||
| 'nb_instructions': nb_instructions, | |||||
| 'output': output, | |||||
| 'error': error, | |||||
| } | |||||
| import os, re | import os, re | ||||
| import socket | |||||
| from .protocol import SocketTool | |||||
| import numpy as np | import numpy as np | ||||
| def to_hex(v, nb_bits=16): | |||||
| try: | |||||
| v_hex = v.hex() | |||||
| except AttributeError: | |||||
| v_hex = hex(v)[2:] | |||||
| return '0'*(nb_bits//4-len(v_hex)) + v_hex | |||||
| def split_octet(hexstr): | |||||
| return [hexstr[i:i+2] for i in range(0, len(hexstr), 2)] | |||||
| def to_signed_hex(v, nb_bits=16): | |||||
| try: | |||||
| return split_octet(to_hex(v & (2**nb_bits-1), nb_bits=nb_bits)) | |||||
| except TypeError as err: | |||||
| raise TypeError('Error to transform a <{}> into signed hex.'.format(type(v))) from err | |||||
| def write(_input, uintXX, nb_bits=16): | |||||
| uintXX = to_signed_hex(uintXX, nb_bits=nb_bits) | |||||
| for i in range(nb_bits//8): | |||||
| _input.write(uintXX[i]+'\n') | |||||
| def write_list(_input, uint16_list): | |||||
| for uint16 in uint16_list: | |||||
| write(_input, uint16) | |||||
| from .config import MODULE_PATH, ELMO_TOOL_REPOSITORY | |||||
| from .utils import write | |||||
| class SimulationProject: | class SimulationProject: | ||||
| # TAG: EXCLUDE-FROM-SIMULATION-SEARCH | |||||
| """ Class to manage a simultion | |||||
| It contains all the parameters of the simulation and has method to use it | |||||
| """ | |||||
| _nb_bits_for_nb_challenges = 16 | _nb_bits_for_nb_challenges = 16 | ||||
| _project_directory = None | _project_directory = None | ||||
| ### Define the project | ### Define the project | ||||
| @classmethod | @classmethod | ||||
| def get_project_directory(cl): | def get_project_directory(cl): | ||||
| """ """ | |||||
| if cl._project_directory: | if cl._project_directory: | ||||
| return cl._project_directory | return cl._project_directory | ||||
| else: | else: | ||||
| return '' | return '' | ||||
| @classmethod | @classmethod | ||||
| def get_binary(cl): | |||||
| def get_binary_path(cl): | |||||
| raise NotImplementedError() | raise NotImplementedError() | ||||
| @classmethod | @classmethod | ||||
| def get_parameters_names(cl): | def get_parameters_names(cl): | ||||
| return set() | return set() | ||||
| @classmethod | |||||
| def adapt_project(cl, parameters): | |||||
| return | |||||
| def get_challenge_format(self): | def get_challenge_format(self): | ||||
| raise NotImplementedError() | raise NotImplementedError() | ||||
| ### Tools to realize the simulation of the project | ### Tools to realize the simulation of the project | ||||
| def __init__(self, challenges=None): | def __init__(self, challenges=None): | ||||
| self.elmo_folder = os.path.dirname(os.path.abspath(__file__))+'/elmo' | |||||
| self.elmo_folder = os.path.join(MODULE_PATH, ELMO_TOOL_REPOSITORY) | |||||
| self.challenges = challenges | self.challenges = challenges | ||||
| self.reset() | self.reset() | ||||
| self._complete_results = None | self._complete_results = None | ||||
| self._complete_printed_data = None | self._complete_printed_data = None | ||||
| def get_test_challenges(self): | |||||
| raise NotImplementedError() | |||||
| def get_random_challenges(self, nb_challenges): | |||||
| raise NotImplementedError() | |||||
| def set_challenges(self, challenges): | def set_challenges(self, challenges): | ||||
| self.challenges = challenges | self.challenges = challenges | ||||
| aux(format[num_part], challenge[num_part]) | aux(format[num_part], challenge[num_part]) | ||||
| def set_input(self, input): | def set_input(self, input): | ||||
| assert len(self.challenges) < 2**16, 'The number of challenges must be strictly lower than 65536. Currently, there are {} challenges.'.format(len(self.challenges)) | |||||
| write(input, len(self.challenges), nb_bits=self._nb_bits_for_nb_challenges) | |||||
| for challenge in self.challenges: | |||||
| self.set_input_for_each_challenge(input, challenge) | |||||
| if self.challenges: | |||||
| assert len(self.challenges) < (1 << self._nb_bits_for_nb_challenges), \ | |||||
| 'The number of challenges must be strictly lower than {}. Currently, there are {} challenges.'.format( | |||||
| 1 << self._nb_bits_for_nb_challenges, | |||||
| len(self.challenges), | |||||
| ) | |||||
| write(input, len(self.challenges), nb_bits=self._nb_bits_for_nb_challenges) | |||||
| for challenge in self.challenges: | |||||
| self.set_input_for_each_challenge(input, challenge) | |||||
| def run(self): | def run(self): | ||||
| self.reset() | self.reset() | ||||
| return res | return res | ||||
| def run_online(self, host='localhost', port=5000): | def run_online(self, host='localhost', port=5000): | ||||
| from .server.protocol import SocketTool | |||||
| import socket | |||||
| class TempInput: | class TempInput: | ||||
| def __init__(self): | def __init__(self): | ||||
| self._buffer = '' | self._buffer = '' |
| *.elf | *.elf | ||||
| *.list | *.list | ||||
| *.bin | |||||
| *.map | *.map | ||||
| *.d | *.d | ||||
| *.o | *.o |
| ### - get_simulation_via_classname(classname) | ### - get_simulation_via_classname(classname) | ||||
| class KyberNTTSimulation(SimulationProject): | class KyberNTTSimulation(SimulationProject): | ||||
| KYBER_K = 2 #k=2 for Kyber512 | |||||
| KYBER_N = 256 #n=256 for Kyber512 | |||||
| @classmethod | @classmethod | ||||
| def get_binary(cl): | |||||
| def get_binary_path(cl): | |||||
| return 'project.bin' | return 'project.bin' | ||||
| def __init__(self, *args, **kwargs): | def __init__(self, *args, **kwargs): | ||||
| secret = challenge | secret = challenge | ||||
| # Write the secret vector | # Write the secret vector | ||||
| for j in range(2): #k=2 for Kyber512 | |||||
| for k in range(256): #n=256 for Kyber512 | |||||
| write(input, secret[j,k]) | |||||
| for j in range(self.KYBER_K): | |||||
| for k in range(self.KYBER_N): | |||||
| write(input, secret[j,k]) | |||||
| def get_test_challenges(self): | |||||
| import numpy as np | |||||
| just_ones = np.ones((self.KYBER_K, self.KYBER_N), dtype=int) | |||||
| return [ | |||||
| 0 * just_ones, | |||||
| 1 * just_ones, | |||||
| -2 * just_ones, | |||||
| ] | |||||
| def get_random_challenges(self, nb_challenges=5): | |||||
| import numpy as np | |||||
| return [ np.random.choice( | |||||
| [-2, -1, 0, 1, 2], | |||||
| (self.KYBER_K, self.KYBER_N), | |||||
| p=[1/16, 4/16, 6/16, 4/16, 1/16], | |||||
| ) for _ in range(nb_challenges) ] |
| from servicethread import OneShotServiceThread | |||||
| from .server.servicethread import OneShotServiceThread | |||||
| import subprocess | import subprocess | ||||
| import shutil | import shutil |
| import threading | import threading | ||||
| from protocol import Protocol, ClosureException | |||||
| from .server.protocol import Protocol, ClosureException | |||||
| import socket | import socket | ||||
| ### to write an integer of 'nb_bits' bits in the 'input_file'. | ### to write an integer of 'nb_bits' bits in the 'input_file'. | ||||
| ### To get this simulation class in Python scripts, please use the functions in manage.py as | ### To get this simulation class in Python scripts, please use the functions in manage.py as | ||||
| ### - search_simulations(repository) | ### - search_simulations(repository) | ||||
| ### - get_simulation(repository, classname=None) | |||||
| ### - get_simulation_via_classname(classname) | |||||
| ### - get_simulation(repository='.', classname=None) | |||||
| class {{PROJECTCLASSNAME}}(SimulationProject): | class {{PROJECTCLASSNAME}}(SimulationProject): | ||||
| @classmethod | @classmethod | ||||
| def get_binary(cl): | |||||
| def get_binary_path(cl): | |||||
| return 'project.bin' | return 'project.bin' | ||||
| def __init__(self, *args, **kwargs): | def __init__(self, *args, **kwargs): |
| import numpy as np | |||||
| ### Binary operations | |||||
| def hweight(n): | |||||
| c = 0 | |||||
| while n>0: | |||||
| c += (n & 1) | |||||
| n >>= 1 | |||||
| return c | |||||
| def hdistance(x,y): | |||||
| return hweight(x^y) | |||||
| def binary_writing(n, nb_bits=32, with_hamming=False): | |||||
| n = np.array(n) | |||||
| w, h = np.zeros((nb_bits, len(n))), np.zeros((len(n))) | |||||
| for ind in range(nb_bits): | |||||
| w[ind] = (n & 1) | |||||
| h += w[ind] | |||||
| n >>= 1 | |||||
| ind += 1 | |||||
| return (w, h) if with_hamming else w | |||||
| ### Conversion | |||||
| def to_hex(v, nb_bits=16): | |||||
| try: | |||||
| v_hex = v.hex() | |||||
| except AttributeError: | |||||
| v_hex = hex(v)[2:] | |||||
| return '0'*(nb_bits//4-len(v_hex)) + v_hex | |||||
| def split_octet(hexstr): | |||||
| return [hexstr[i:i+2] for i in range(0, len(hexstr), 2)] | |||||
| def to_signed_hex(v, nb_bits=16): | |||||
| try: | |||||
| return split_octet(to_hex(v & ((1<<nb_bits)-1), nb_bits=nb_bits)) | |||||
| except TypeError as err: | |||||
| raise TypeError('Error to transform a <{}> into signed hex.'.format(type(v))) from err | |||||
| ### Write function | |||||
| def write(_input, uint, nb_bits=16): | |||||
| uint = to_signed_hex(uint, nb_bits=nb_bits) | |||||
| for i in range(nb_bits//8): | |||||
| _input.write(uint[i]+'\n') | |||||
| def write_list(_input, uint_list, nb_bits=16): | |||||
| for uint in uint_list: | |||||
| write(_input, uint, nb_bits=nb_bits) | |||||
| ### Print Utils | |||||
| class Color: | |||||
| HEADER = '\033[95m' | |||||
| OKBLUE = '\033[94m' | |||||
| OKCYAN = '\033[96m' | |||||
| OKGREEN = '\033[92m' | |||||
| WARNING = '\033[93m' | |||||
| FAIL = '\033[91m' | |||||
| ENDC = '\033[0m' | |||||
| BOLD = '\033[1m' | |||||
| UNDERLINE = '\033[4m' |
| #!/bin/bash | |||||
| elmo_repository="elmo" | |||||
| elmo_source="https://github.com/sca-research/ELMO.git" | |||||
| if [ -d ${elmo_repository} ]; then | |||||
| echo "ELMO tool already installed." | |||||
| else | |||||
| echo "ELMO tool NOT installed... Installing via online resources..." | |||||
| # Download the tool | |||||
| git clone --depth=1 --branch=master ${elmo_source} ${elmo_repository} | |||||
| rm -rf ./${elmo_repository}/.git | |||||
| # Compile the tool | |||||
| cd ./${elmo_repository} | |||||
| make | |||||
| cd .. | |||||
| fi |
| import os, shutil | |||||
| import re | |||||
| import inspect | |||||
| import subprocess | |||||
| def search_simulations_in_repository(repository, criteria=lambda x:True): | |||||
| """ To search simulation classes in the 'repository' verifying the 'criteria' """ | |||||
| projects = {} | |||||
| from .project_base import SimulationProject, write | |||||
| for root, repositories, files in os.walk(repository): | |||||
| for filename in files: | |||||
| if re.fullmatch(r'.*project.*\.py', filename): | |||||
| # Encapsulation the project | |||||
| complete_filename = root+'/'+filename | |||||
| globals = { | |||||
| #'__builtins__': {'__build_class__': __build_class__}, | |||||
| 'SimulationProject': SimulationProject, | |||||
| 'write': write, | |||||
| } | |||||
| locals = {} | |||||
| # Read the project code | |||||
| with open(complete_filename, 'r') as _file: | |||||
| project = '\n'.join(_file.readlines()) | |||||
| exec(project, globals, locals) | |||||
| # Extract the simulations | |||||
| for key, obj in locals.items(): | |||||
| if inspect.isclass(obj) and issubclass(obj, SimulationProject): | |||||
| if criteria(obj): | |||||
| if key in projects: | |||||
| print('Warning! Multiplie simulation with the same name. Simulation ignored: {} in {}'.format(key, complete_filename[len(repository)+1:])) | |||||
| else: | |||||
| obj.set_project_directory(os.path.abspath(root)) | |||||
| projects[key] = obj | |||||
| return projects | |||||
| def search_simulations_in_module(criteria=lambda x:True): | |||||
| module_path = os.path.dirname(os.path.abspath(__file__)) | |||||
| projects_path = module_path+'/projects' | |||||
| return search_simulations_in_repository(projects_path, criteria) | |||||
| def search_simulations(repository, criteria=lambda x:True): | |||||
| projects = search_simulations_in_repository(repository, criteria) | |||||
| module_projects = search_simulations_in_module(criteria) | |||||
| for key, project in module_projects.items(): | |||||
| if key not in projects: | |||||
| projects[key] = project | |||||
| return projects | |||||
| class SimulationNotFoundError(Exception): | |||||
| pass | |||||
| class TooManySimulationsError(Exception): | |||||
| pass | |||||
| def get_simulation(repository, classname=None): | |||||
| """ Get a simulation class in the 'repository' with the specific 'classname' """ | |||||
| criteria = lambda x: True | |||||
| if classname is not None: | |||||
| criteria = lambda x: x.__name__ == classname.strip() | |||||
| projects = search_simulations(repository, criteria) | |||||
| if len(projects) == 1: | |||||
| return list(projects.values())[0] | |||||
| elif len(projects) < 1: | |||||
| raise SimulationNotFoundError() | |||||
| else: | |||||
| raise TooManySimulationsError() | |||||
| def get_simulation_via_classname(classname): | |||||
| return get_simulation('.', classname) | |||||
| def create_simulation(repository, classname): | |||||
| """ Create a simulation class """ | |||||
| try: | |||||
| os.makedirs(repository, exist_ok=False) | |||||
| except FileExistsError as err: | |||||
| raise FileExistsError('Error, a project with this repository already exists!') from err | |||||
| module_path = os.path.dirname(os.path.abspath(__file__)) | |||||
| elmo_path = module_path+'/elmo' | |||||
| template_path = module_path+'/templates' | |||||
| project_path = repository | |||||
| ### Add contents in the project | |||||
| files_from_ELMO = [ | |||||
| 'Examples/elmoasmfunctions.o', | |||||
| 'Examples/elmoasmfunctions.s', | |||||
| 'Examples/elmoasmfunctionsdef.h', | |||||
| 'Examples/DPATraces/MBedAES/vector.o', | |||||
| ] | |||||
| files_from_templates = [ | |||||
| 'elmoasmfunctionsdef-extension.h', | |||||
| 'Makefile', | |||||
| 'project.c' | |||||
| ] | |||||
| for filename in files_from_ELMO: | |||||
| shutil.copy(elmo_path+'/'+filename, project_path) | |||||
| for filename in files_from_templates: | |||||
| shutil.copy(template_path+'/'+filename, project_path) | |||||
| shutil.copy(elmo_path+'/'+'Examples/DPATraces/MBedAES/MBedAES.ld', project_path+'/'+'project.ld') | |||||
| ### Create the project class | |||||
| with open(template_path+'/projectclass.py') as _source: | |||||
| code = ''.join(_source.readlines()) | |||||
| code = code.replace('{{PROJECTCLASSNAME}}', classname) | |||||
| with open(project_path+'/'+'projectclass.py', 'w') as _dest: | |||||
| _dest.write(code) | |||||
| return os.path.abspath(project_path) | |||||
| def execute_simulation(project, data=None): | |||||
| """ Execute a simulation with 'data' """ | |||||
| # Make the compilation | |||||
| if False: | |||||
| print('Compiling binary...') | |||||
| # Adapt the project source | |||||
| with open('binaries/Frodo/frodo-base.c', 'r') as _src_file: | |||||
| content = _src_file.read() | |||||
| with open('binaries/Frodo/frodo.c', 'w') as _dst_file: | |||||
| _dst_file.write(content.replace('%NEED_TO_FILL%', str(n))) | |||||
| # Compile the project | |||||
| make_directory = 'projects/{}/{}'.format(project.get_project_directory(), project.get_make_directory()) | |||||
| process = subprocess.Popen('make', shell=True, cwd=make_directory, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |||||
| output, error = process.communicate() | |||||
| if error and ('error' in error.decode('latin-1')): | |||||
| print("Error to compile") | |||||
| print(error) | |||||
| raise Exception() | |||||
| # Save last compilation data | |||||
| global_variables[project_name] = { | |||||
| 'last_n': n, | |||||
| } | |||||
| # Generate the trace by launching ELMO | |||||
| command = './elmo "{}/{}"'.format( | |||||
| project.get_project_directory(), | |||||
| project.get_binary() | |||||
| ) | |||||
| cwd = os.path.dirname(os.path.abspath(__file__))+'/elmo' | |||||
| process = subprocess.Popen(command, shell=True, cwd=cwd, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |||||
| output, error = process.communicate() | |||||
| output = output.decode('latin-1') if output else None | |||||
| error = error.decode('latin-1') if error else None | |||||
| nb_traces = output.count('TRACE NO') | |||||
| # Return results | |||||
| return { | |||||
| 'output': output, | |||||
| 'error': error, | |||||
| 'nb_traces': nb_traces, | |||||
| } | |||||
| numpy==1.19.1 |
| from servicethread import ListeningThread | |||||
| from executorthread import ExecutorThread | |||||
| def do_main_program(): | |||||
| global thread, stop | |||||
| thread = ListeningThread('localhost', 5000, ExecutorThread) | |||||
| thread.start() | |||||
| def program_cleanup(signum, frame): | |||||
| global thread, stop | |||||
| thread.stop() | |||||
| stop = True | |||||
| thread = None | |||||
| stop = False | |||||
| # Execute | |||||
| print("Executing...") | |||||
| do_main_program() | |||||
| print("Done ! And now, listening...") | |||||
| import signal | |||||
| signal.signal(signal.SIGINT, program_cleanup) | |||||
| signal.signal(signal.SIGTERM, program_cleanup) | |||||
| # Wait | |||||
| import time | |||||
| while not stop: | |||||
| time.sleep(1) |
| import setuptools | |||||
| from setuptools.command.build_py import build_py | |||||
| from setuptools.command.install import install | |||||
| from subprocess import check_call | |||||
| import os, shutil | |||||
| import re | |||||
| ### CONFIGURATION | |||||
| PELMO_SOURCE = 'https://github.com/ThFeneuil/python-elmo' | |||||
| ELMO_MODULE_NAME = 'elmo' | |||||
| ELMO_SOURCE = 'https://github.com/sca-research/ELMO.git' | |||||
| # Import configuration of ELMO_MODULE, | |||||
| # cannot use 'import elmo' because it can be ambiguous which module it will call | |||||
| with open(os.path.join(ELMO_MODULE_NAME, 'config.py')) as _file: | |||||
| globals = {'__file__': os.path.join( | |||||
| os.path.abspath(ELMO_MODULE_NAME), | |||||
| 'config.py' | |||||
| )} | |||||
| exec(_file.read(), globals) | |||||
| ELMO_TOOL_REPOSITORY = globals['ELMO_TOOL_REPOSITORY'] | |||||
| ELMO_INPUT_FILE_NAME = globals['ELMO_INPUT_FILE_NAME'] | |||||
| def install_elmo_tool(elmo_complete_path): | |||||
| ## Download the tool | |||||
| elmo_download_command = "git clone --depth=1 --branch=master {url} {elmo_path}".format( | |||||
| url=ELMO_SOURCE, | |||||
| elmo_path=elmo_complete_path, | |||||
| ) | |||||
| check_call(elmo_download_command.split()) | |||||
| shutil.rmtree(os.path.join(elmo_complete_path, '.git')) | |||||
| # 'test' contains a Python2 test, and it raises an error during byte-compiling | |||||
| shutil.rmtree(os.path.join(elmo_complete_path, 'test')) | |||||
| ## Setup the tool | |||||
| elmodefines_h = None | |||||
| elmodefines_h_path = os.path.join(elmo_complete_path, 'elmodefines.h') | |||||
| with open(elmodefines_h_path, 'r') as _file: | |||||
| elmodefines_lines = _file.readlines() | |||||
| for i, line in enumerate(elmodefines_lines): | |||||
| if re.match(r'\s*#define\s+DATAFILEPATH', line): | |||||
| elmodefines_lines[i] = '#define DATAFILEPATH "{}"'.format(ELMO_INPUT_FILE_NAME) | |||||
| elmodefines_h = ''.join(elmodefines_lines) | |||||
| with open(elmodefines_h_path, 'w') as _file: | |||||
| _file.write(elmodefines_h) | |||||
| # Compile the tool | |||||
| check_call("make clean".split(), cwd=elmo_complete_path) | |||||
| check_call("make".split(), cwd=elmo_complete_path) | |||||
| class PostBuildCommand(build_py): | |||||
| """ Build Command to add the ELMO installation """ | |||||
| def run(self): | |||||
| build_py.run(self) | |||||
| # ELMO Installation | |||||
| elmo_complete_path = os.path.join( | |||||
| self.build_lib, | |||||
| ELMO_MODULE_NAME, | |||||
| ELMO_TOOL_REPOSITORY, | |||||
| ) | |||||
| shutil.rmtree(elmo_complete_path, ignore_errors=True) | |||||
| install_elmo_tool(elmo_complete_path) | |||||
| if __name__ == '__main__': | |||||
| with open("README.md", "r") as fh: | |||||
| long_description = fh.read() | |||||
| setuptools.setup( | |||||
| name="python-elmo", | |||||
| version="0.0.1", | |||||
| author="Thibauld Feneuil", | |||||
| author_email="thibauld.feneuil@cryptoexperts.com", | |||||
| description="Emulator for power Leakage for the M0", | |||||
| long_description=long_description, | |||||
| long_description_content_type="text/markdown", | |||||
| url=PELMO_SOURCE, | |||||
| project_urls={ | |||||
| 'ELMO Source': ELMO_SOURCE, | |||||
| 'pELMO Source': PELMO_SOURCE, | |||||
| }, | |||||
| packages=setuptools.find_packages(), | |||||
| classifiers=[ | |||||
| "Programming Language :: Python :: 3", | |||||
| ], | |||||
| python_requires='>=3.5', | |||||
| cmdclass={ | |||||
| 'build_py': PostBuildCommand, | |||||
| }, | |||||
| install_requires=['numpy'], | |||||
| include_package_data=True, | |||||
| ) |
| import os, shutil | |||||
| from subprocess import check_call | |||||
| ### Install ELMO | |||||
| from elmo.config import ELMO_TOOL_REPOSITORY | |||||
| ELMO_SOURCE = 'https://github.com/sca-research/ELMO.git' | |||||
| elmo_complete_path = os.path.join('elmo', ELMO_TOOL_REPOSITORY) | |||||
| if not os.path.isdir(elmo_complete_path): | |||||
| from setup import install_elmo_tool | |||||
| install_elmo_tool(elmo_complete_path) | |||||
| def print_success(text): | |||||
| OKGREEN = '\033[92m' | |||||
| ENDC = '\033[0m' | |||||
| print(OKGREEN+text+ENDC) | |||||
| ######################################################### | |||||
| # TEST 1 : MANAGE A FRESH SIMULATION # | |||||
| ######################################################### | |||||
| foldername = 'test-project' | |||||
| classname = 'TestSimu' | |||||
| ### Create Simulation | |||||
| from elmo.manage import create_simulation | |||||
| shutil.rmtree('test-project', ignore_errors=True) # Clean before | |||||
| create_simulation(foldername, classname) | |||||
| assert os.path.isdir(foldername), 'Folder not created' | |||||
| ### List Available Simulations | |||||
| from elmo.manage import search_simulations | |||||
| simulations = search_simulations(foldername) | |||||
| assert classname in simulations, 'Test Simulation not found' | |||||
| ### Use a Simulation | |||||
| from elmo.manage import get_simulation | |||||
| simu = get_simulation(classname, foldername) | |||||
| shutil.rmtree(foldername) | |||||
| print_success(' - Test 1 "Manage A Fresh Simulation": Success!') | |||||
| ######################################################### | |||||
| # TEST 2 : USE ELMO ENGINE # | |||||
| ######################################################### | |||||
| ### Use the ELMO Engine | |||||
| from elmo.engine import ELMOEngine, Instr | |||||
| engine = ELMOEngine() | |||||
| for i in range(0, 256): | |||||
| engine.add_point( | |||||
| (Instr.LDR, Instr.MUL, Instr.OTHER), # Types of the previous, current and next instructions | |||||
| (0x0000, i), # Operands of the previous instructions | |||||
| (0x2BAC, i) # Operands of the current instructions | |||||
| ) | |||||
| engine.run() # Compute the power consumption of all these points | |||||
| power = engine.power # Numpy 1D array with an entry for each previous point | |||||
| engine.reset_points() # Reset the engine to study other points | |||||
| assert power.shape == (256, ) | |||||
| print_success(' - Test 2 "Use ELMO Engine": Success!') | |||||
| ######################################################### | |||||
| # TEST 3 : USE A REAL SIMULATION # | |||||
| ######################################################### | |||||
| from elmo import get_simulation | |||||
| KyberNTTSimulation = get_simulation('KyberNTTSimulation') | |||||
| simulation = KyberNTTSimulation() | |||||
| simulation.set_challenges(simulation.get_random_challenges(10)) | |||||
| res = simulation.run() | |||||
| assert not res['error'] | |||||
| assert res['nb_traces'] == 10 | |||||
| assert res['nb_instructions'] | |||||
| print_success(' - Test 3 "Use A Real Simulation": Success!') | |||||
| ######################################################### | |||||
| print_success('All seems fine!') |