*.pyc | |||||
elmo/* |
# ELMO Online | |||||
ELMO Online is a Python library which proposes an encapsulation of the binary project ELMO. | |||||
[MOW17] **Towards Practical Tools for Side | |||||
Channel Aware Software Engineering : ’Grey Box’ Modelling for Instruction Leakages** | |||||
by _David McCann, Elisabeth Oswald et Carolyn Whitnall_. | |||||
https://www.usenix.org/conference/ | |||||
usenixsecurity17/technical-sessions/presentation/mccann. | |||||
**ELMO GitHub**: https://github.com/sca-research/ELMO |
import numpy as np | |||||
import os | |||||
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 | |||||
PREVIOUS = 0 | |||||
CURRENT = 1 | |||||
SUBSEQUENT = 2 | |||||
class ELMOEngine: | |||||
def __init__(self): | |||||
self.load_coefficients() | |||||
self.reset_points() | |||||
def _extract_data(self, nb): | |||||
coeffs = self.coefficients[self.pos:self.pos+nb] | |||||
self.pos += nb | |||||
return coeffs | |||||
def load_coefficients(self): | |||||
filename = os.path.dirname(os.path.abspath(__file__))+'/elmo/coeffs.txt' | |||||
self.coefficients = None | |||||
with open(filename, 'r') as _file: | |||||
self.coefficients = np.array([list(map(float, line.split())) for line in _file.readlines()[:2153]]) | |||||
if self.coefficients is None: | |||||
raise IOError('Problem to read the coefficients.') | |||||
self.pos = 0 | |||||
self.constant = np.squeeze(self._extract_data(1)) | |||||
self.PrvInstr = self._extract_data(4) | |||||
self.SubInstr = self._extract_data(4) | |||||
self.Operand1 = self._extract_data(32) | |||||
self.Operand2 = self._extract_data(32) | |||||
self.BitFlip1 = self._extract_data(32) | |||||
self.BitFlip2 = self._extract_data(32) | |||||
self.HWOp1PrvInstr = self._extract_data(4) | |||||
self.HWOp2PrvInstr = self._extract_data(4) | |||||
self.HDOp1PrvInstr = self._extract_data(4) | |||||
self.HDOp2PrvInstr = self._extract_data(4) | |||||
self.HWOp1SubInstr = self._extract_data(4) | |||||
self.HWOp2SubInstr = self._extract_data(4) | |||||
self.HDOp1SubInstr = self._extract_data(4) | |||||
self.HDOp2SubInstr = self._extract_data(4) | |||||
self.Operand1_bitinteractions = self._extract_data(496) | |||||
self.Operand2_bitinteractions = self._extract_data(496) | |||||
self.BitFlip1_bitinteractions = self._extract_data(496) | |||||
self.BitFlip2_bitinteractions = self._extract_data(496) | |||||
def reset_points(self): | |||||
self.points = [] | |||||
self.power = None | |||||
def add_point(self, triplet, previous_ops, current_ops): | |||||
self.points.append((triplet, previous_ops, current_ops)) | |||||
def _dot(self, a, b): | |||||
return np.sum(a * b, axis=0) | |||||
def calculate_point(self, triplet, previous_ops, current_ops, debug=False): | |||||
nb_points = triplet.shape[1] | |||||
instructiontype = triplet[CURRENT] | |||||
instructiontype = instructiontype % 5 # Type 5 = Instruction was not profiled | |||||
# Previous | |||||
previous_instruction_typedec = triplet[PREVIOUS] | |||||
previous_instruction_type = np.zeros((5, nb_points)) | |||||
for i in range(nb_points): | |||||
if previous_instruction_typedec[i] < 5: | |||||
previous_instruction_type[previous_instruction_typedec[i],i] = 1 | |||||
# Current | |||||
(current_op1_binary, hw_op1) = binary_writing(current_ops[0], with_hamming=True) | |||||
(current_op2_binary, hw_op2) = binary_writing(current_ops[1], with_hamming=True) | |||||
(current_op1_bitflip, hd_op1) = binary_writing(previous_ops[0] ^ current_ops[0], with_hamming=True) | |||||
(current_op2_bitflip, hd_op2) = binary_writing(previous_ops[1] ^ current_ops[1], with_hamming=True) | |||||
current_instruction_typedec = instructiontype | |||||
current_instruction_type = np.zeros((5, nb_points)) | |||||
for i in range(nb_points): | |||||
if triplet[CURRENT,i] < 5: | |||||
current_instruction_type[current_instruction_typedec[i],i] = 1 | |||||
# Subsequent | |||||
subsequent_instruction_typedec = triplet[SUBSEQUENT] | |||||
subsequent_instruction_type = np.zeros((5, nb_points)) | |||||
for i in range(nb_points): | |||||
if subsequent_instruction_typedec[i] < 5: | |||||
subsequent_instruction_type[subsequent_instruction_typedec[i],i] = 1 | |||||
# Component variables | |||||
PrvInstr_data = self._dot( previous_instruction_type[1:], self.PrvInstr[:,instructiontype] ) | |||||
SubInstr_data = self._dot( subsequent_instruction_type[1:], self.SubInstr[:,instructiontype] ) | |||||
Operand1_data = self._dot( current_op1_binary, self.Operand1[:,instructiontype] ) | |||||
Operand2_data = self._dot( current_op2_binary, self.Operand2[:,instructiontype] ) | |||||
BitFlip1_data = self._dot( current_op1_bitflip, self.BitFlip1[:,instructiontype] ) | |||||
BitFlip2_data = self._dot( current_op2_bitflip, self.BitFlip2[:,instructiontype] ) | |||||
HWOp1PrvInstr_data = hw_op1 * self._dot(previous_instruction_type[1:], self.HWOp1PrvInstr[:,instructiontype]) | |||||
HWOp2PrvInstr_data = hw_op2 * self._dot(previous_instruction_type[1:], self.HWOp2PrvInstr[:,instructiontype]) | |||||
HDOp1PrvInstr_data = hd_op1 * self._dot(previous_instruction_type[1:], self.HDOp1PrvInstr[:,instructiontype]) | |||||
HDOp2PrvInstr_data = hd_op2 * self._dot(previous_instruction_type[1:], self.HDOp2PrvInstr[:,instructiontype]) | |||||
HWOp1SubInstr_data = hw_op1 * self._dot(subsequent_instruction_type[1:], self.HWOp1SubInstr[:,instructiontype]) | |||||
HWOp2SubInstr_data = hw_op2 * self._dot(subsequent_instruction_type[1:], self.HWOp2SubInstr[:,instructiontype]) | |||||
HDOp1SubInstr_data = hd_op1 * self._dot(subsequent_instruction_type[1:], self.HDOp1SubInstr[:,instructiontype]) | |||||
HDOp2SubInstr_data = hd_op2 * self._dot(subsequent_instruction_type[1:], self.HDOp2SubInstr[:,instructiontype]) | |||||
Operand1_bitinteractions_data = np.zeros((nb_points)) | |||||
Operand2_bitinteractions_data = np.zeros((nb_points)) | |||||
BitFlip1_bitinteractions_data = np.zeros((nb_points)) | |||||
BitFlip2_bitinteractions_data = np.zeros((nb_points)) | |||||
count = 0 | |||||
for i in range(32): | |||||
for j in range(i+1,32): | |||||
Operand1_bitinteractions_data += self.Operand1_bitinteractions[count,instructiontype] * current_op1_binary[i] * current_op1_binary[j] | |||||
Operand2_bitinteractions_data += self.Operand2_bitinteractions[count,instructiontype] * current_op2_binary[i] * current_op2_binary[j] | |||||
BitFlip1_bitinteractions_data += self.BitFlip1_bitinteractions[count,instructiontype] * current_op1_bitflip[i] * current_op1_bitflip[j] | |||||
BitFlip2_bitinteractions_data += self.BitFlip2_bitinteractions[count,instructiontype] * current_op2_bitflip[i] * current_op2_bitflip[j] | |||||
count += 1 | |||||
power = self.constant[instructiontype] \ | |||||
+ PrvInstr_data + SubInstr_data \ | |||||
+ Operand1_data + Operand2_data \ | |||||
+ BitFlip1_data + BitFlip2_data \ | |||||
+ HWOp1PrvInstr_data + HWOp2PrvInstr_data \ | |||||
+ HDOp1PrvInstr_data + HDOp2PrvInstr_data \ | |||||
+ HWOp1SubInstr_data + HWOp2SubInstr_data \ | |||||
+ HDOp1SubInstr_data + HDOp2SubInstr_data \ | |||||
+ Operand1_bitinteractions_data + Operand2_bitinteractions_data \ | |||||
+ BitFlip1_bitinteractions_data + BitFlip2_bitinteractions_data | |||||
for i in range(nb_points): | |||||
if triplet[CURRENT,i] == 5: | |||||
power[i] = self.constant[triplet[CURRENT,i]] | |||||
if debug: | |||||
print([self.constant[instructiontype], \ | |||||
PrvInstr_data, SubInstr_data, \ | |||||
Operand1_data, Operand2_data, \ | |||||
BitFlip1_data, BitFlip2_data, \ | |||||
HWOp1PrvInstr_data, HWOp2PrvInstr_data, \ | |||||
HDOp1PrvInstr_data, HDOp2PrvInstr_data, \ | |||||
HWOp1SubInstr_data, HWOp2SubInstr_data, \ | |||||
HDOp1SubInstr_data, HDOp2SubInstr_data, \ | |||||
Operand1_bitinteractions_data, Operand2_bitinteractions_data, \ | |||||
BitFlip1_bitinteractions_data, BitFlip2_bitinteractions_data]) | |||||
return power | |||||
def run(self): | |||||
nb_points = len(self.points) | |||||
triplet = np.array([p[0] for p in self.points]).T # shape = (3, nb_points) | |||||
previous_ops = np.array([p[1] for p in self.points]).T # shape = (2, nb_points) | |||||
current_ops = np.array([p[2] for p in self.points]).T # shape = (2, nb_points) | |||||
self.power = self.calculate_point(triplet, previous_ops, current_ops) | |||||
def oneshot_point(self, triplet, previous_ops, current_ops): | |||||
self.reset_points() | |||||
self.add_point(triplet, previous_ops, current_ops) | |||||
self.run() | |||||
return self.power |
from servicethread import OneShotServiceThread | |||||
import subprocess | |||||
import shutil | |||||
from project_reader import ProjectReader | |||||
global_variables = {} | |||||
class ExecutorThread(OneShotServiceThread): | |||||
def __init__(self, ip, port, clientsocket, **kwargs): | |||||
super().__init__(ip, port, clientsocket) | |||||
self.projects = kwargs['projects'] if 'projects' in kwargs else None | |||||
def execute(self): | |||||
projects = self.projects | |||||
if project is None: | |||||
reader = ProjectReader() | |||||
projects = {sc.get_project_label(): sc for sc in reader.get_project_classes()} | |||||
print('Warning: need to research the projects.') | |||||
else: | |||||
print('Already have projects') | |||||
data = self.protocol.get_data() | |||||
self.protocol.please_assert(data) | |||||
self.protocol.please_assert('project' in data) | |||||
self.protocol.please_assert(data['project'] in projects) | |||||
self.protocol.send_ack() | |||||
# Get the project | |||||
project = projects[data['project']] | |||||
# 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 ../projects/{}/{}'.format(project.get_project_directory(), project.get_binary()) | |||||
process = subprocess.Popen(command, shell=True, cwd='elmo_online/elmo/', executable='/bin/bash', stdout=subprocess.PIPE) | |||||
output, error = process.communicate() | |||||
# Send results | |||||
self.protocol.send_data({ | |||||
'output': output.decode('latin-1') if output else None, | |||||
'error': error.decode('latin-1') if error else None, | |||||
}) | |||||
self.protocol.close() |
from .project_reader import Project | |||||
reader = ProjectReader() | |||||
projects = reader.get_projects() | |||||
for key, project in projects.items(): | |||||
globals()[key] = project |
from servicethread import PermanentServiceThread | |||||
import socket | |||||
class ListeningThread(PermanentServiceThread): | |||||
def __init__(self, host, port, threadclass, **kwargs): | |||||
super().__init__() | |||||
self.hostname = host | |||||
self.port = port | |||||
self.threadclass = threadclass | |||||
self.kwargs = kwargs | |||||
def execute(self): | |||||
self.tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||||
self.tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |||||
self.tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) | |||||
# self.tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_ATTACH_REUSEPORT_CBPF, 1) | |||||
self.tcpsock.bind((self.hostname, self.port)) | |||||
self.tcpsock.listen(5) | |||||
print('[port][%s] Listening' % self.port) | |||||
while self.is_running(): | |||||
try: | |||||
(clientsocket, (ip, port)) = self.tcpsock.accept() | |||||
print('[port][{}] Accepted: {} <=> {}'.format( | |||||
self.port, | |||||
clientsocket.getsockname(), | |||||
clientsocket.getpeername(), | |||||
)) | |||||
newthread = self.threadclass(ip, port, clientsocket, **self.kwargs) | |||||
newthread.start() | |||||
except socket.timeout: | |||||
pass | |||||
def stop(self): | |||||
super().stop() | |||||
clientsocker = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||||
clientsocker.connect( (self.hostname, self.port) ) | |||||
self.tcpsock.close() | |||||
print('[port][%s] Stop listening' % self.port) |
import os, re | |||||
import socket | |||||
from protocol import SocketTool | |||||
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): | |||||
return split_octet(to_hex(v & (2**nb_bits-1), nb_bits=nb_bits)) | |||||
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) | |||||
def launch_simulation(quiet=False, **kwargs): | |||||
try: | |||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||||
s.connect(('localhost', 5000)) | |||||
SocketTool.send_data(s, kwargs) | |||||
if not SocketTool.get_ack(s): | |||||
raise RuntimeError("The request has been refused !") | |||||
else: | |||||
data = SocketTool.get_data(s) | |||||
if data['error'] and not quiet: | |||||
raise Exception("The simulation return an error") | |||||
return data['output'], data['error'] | |||||
s.close() | |||||
except IOError: | |||||
raise RuntimeError("The connection refused. Has the ELMO server been switch on ?") | |||||
class SimulationProject: | |||||
_nb_bits_for_nb_challenges = 16 | |||||
_project_directory = None | |||||
### Define the project | |||||
@classmethod | |||||
def get_project_directory(cl): | |||||
if cl._project_directory: | |||||
return cl._project_directory | |||||
else: | |||||
raise NotImplementedError() | |||||
@classmethod | |||||
def set_project_directory(cl, project_directory): | |||||
cl._project_directory = project_directory | |||||
@classmethod | |||||
def get_project_label(cl): | |||||
return cl.get_project_directory() | |||||
@classmethod | |||||
def get_make_directory(cl): | |||||
return '' | |||||
@classmethod | |||||
def get_binary(cl): | |||||
raise NotImplementedError() | |||||
@classmethod | |||||
def get_parameters_names(cl): | |||||
return set() | |||||
@classmethod | |||||
def adapt_project(cl, parameters): | |||||
return | |||||
def get_challenge_format(self): | |||||
raise NotImplementedError() | |||||
### Tools to realize the simulation of the project | |||||
def __init__(self, challenges=None): | |||||
self.elmo_folder = os.path.dirname(os.path.abspath(__file__))+'/elmo' | |||||
self.challenges = challenges | |||||
self.is_executed = False | |||||
def set_challenges(self, challenges): | |||||
self.challenges = challenges | |||||
def get_writable_input_file(self): | |||||
return open('{}/input.txt'.format(self.elmo_folder), 'w') | |||||
def set_input_for_each_challenge(self, input, challenge): | |||||
format = self.get_challenge_format() | |||||
def aux(sizes, data): | |||||
if len(sizes) == 0: | |||||
write(input, data) | |||||
else: | |||||
assert len(data) == sizes[0], 'Incorrect format for challenge. Get {} instead of {}'.format(len(data), sizes[0]) | |||||
for i in range(sizes[0]): | |||||
aux(sizes[1:], data[i]) | |||||
for num_part in range(len(format)): | |||||
aux(format[num_part], challenge[num_part]) | |||||
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) | |||||
def run(self): | |||||
with open('{}/input.txt'.format(self.elmo_folder), 'w') as _input: | |||||
self.set_input(_input) | |||||
launch_simulation(project=self.get_project_label(), quiet=False) | |||||
self.is_executed = True | |||||
def get_asmtrace_filename(self): | |||||
return '{}/output/asmoutput/asmtrace00001.txt'.format(self.elmo_folder) | |||||
def get_indexes_of(self, condition): | |||||
with open(self.get_asmtrace_filename(), 'r') as _file: | |||||
asmtrace = _file.readlines() | |||||
return [i for i, instr in enumerate(asmtrace) if condition(instr)] | |||||
def get_number_of_traces(self): | |||||
return len(self.challenges) | |||||
def get_results(self, only_filenames=False, reorganise=None, indexes=None): | |||||
assert self.is_executed | |||||
nb_traces = self.get_number_of_traces() | |||||
trace_filenames = [] | |||||
for filename in os.listdir('{}/output/traces/'.format(self.elmo_folder)): | |||||
if re.search(r'^trace\d+\.trc$', filename): | |||||
trace_filenames.append('{}/output/traces/{}'.format(self.elmo_folder, filename)) | |||||
if len(trace_filenames) >= nb_traces: | |||||
break | |||||
assert len(trace_filenames) == nb_traces | |||||
results = trace_filenames | |||||
if not only_filenames: | |||||
for i in range(len(results)): | |||||
with open(results[i], 'r') as _file: | |||||
if indexes is not None: | |||||
results[i] = list(map(float, _file.readlines()[indexes])) | |||||
else: | |||||
results[i] = list(map(float, _file.readlines())) | |||||
if reorganise is not None: | |||||
results = reorganise(results) | |||||
return results | |||||
def get_traces(self, reorganise=None, indexes=None): | |||||
results = self.get_results(only_filenames=False, reorganise=reorganise,indexes=indexes) | |||||
nb_traces = self.get_number_of_traces() | |||||
trace_length = len(results[0]) | |||||
traces = np.zeros((nb_traces, trace_length)) | |||||
for i in range(nb_traces): | |||||
traces[i,:] = results[i] | |||||
if reorganise is not None: | |||||
traces = reorganise(traces) | |||||
return traces | |||||
def get_printed_data(self): | |||||
with open('{}/output/printdata.txt'.format(self.elmo_folder), 'r') as _file: | |||||
data = list(map(lambda x: int(x, 16), _file.readlines())) | |||||
nb_traces = self.get_number_of_traces() | |||||
nb_data_per_trace = len(data) // nb_traces | |||||
return [data[nb_data_per_trace*i:nb_data_per_trace*(i+1)] for i in range(nb_traces)] | |||||
def analyse_operands(self, num_line, num_trace=1): | |||||
num_str = str(num_trace) | |||||
num_str = '0'*(5-len(num_str)) + num_str | |||||
operands_filename = self.elmo_folder + '/output/operands/operands{}.txt'.format(num_str) | |||||
trace_filename = self.elmo_folder + '/output/traces/trace0000{}.trc'.format(num_trace) | |||||
is_multiple = (type(num_line) is list) | |||||
if not is_multiple: | |||||
num_line = [num_line] | |||||
output = [{}]*len(num_line) | |||||
with open(operands_filename, 'r') as _file: | |||||
lines = _file.readlines() | |||||
for i, num in enumerate(num_line): | |||||
line = lines[num].split() | |||||
data = list(map(int, line[0:7])) | |||||
output[i]['previous'] = data[0:2] | |||||
output[i]['current'] = data[2:4] | |||||
output[i]['triplet'] = data[4:7] | |||||
output[i]['other'] = list(map(float, line[7:])) | |||||
with open(trace_filename, 'r') as _file: | |||||
lines = _file.readlines() | |||||
for i, num in enumerate(num_line): | |||||
line = lines[num] | |||||
output[i]['power'] = float(line) | |||||
return output if is_multiple else output[0] | |||||
from project_base import SimulationProject | |||||
import os, re | |||||
import inspect | |||||
PROJECTS_REPOSITORY = 'projects' | |||||
class ProjectReader: | |||||
def __init__(self): | |||||
pass | |||||
def get_projects(self): | |||||
projects = {} | |||||
for root, repositories, files in os.walk(PROJECTS_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, | |||||
} | |||||
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.item(): | |||||
if inspect.isclass(obj) and issubclass(obj, SimulationProject): | |||||
if key in projects: | |||||
print('Warning! Multiplie simulation with the same name. Simulation ignored: {} in {}'.format(key, complete_filename[len(PROJECTS_REPOSITORY)+1:])) | |||||
else: | |||||
obj.set_project_directory(root[len(PROJECTS_REPOSITORY)+1:]) | |||||
projects[key] = obj | |||||
return projects | |||||
def get_project_classes(self): | |||||
return self.get_projects().values() |
* | |||||
!.gitignore | |||||
!elmoasmfunctions* |
## | |||||
## University of Bristol – Open Access Software Licence | |||||
## Copyright (c) 2016, The University of Bristol, a chartered | |||||
## corporation having Royal Charter number RC000648 and a charity | |||||
## (number X1121) and its place of administration being at Senate | |||||
## House, Tyndall Avenue, Bristol, BS8 1TH, United Kingdom. | |||||
## All rights reserved | |||||
## | |||||
## Redistribution and use in source and binary forms, with or without | |||||
## modification, are permitted provided that the following conditions | |||||
## are met: | |||||
## | |||||
## 1. Redistributions of source code must retain the above copyright | |||||
## notice, this list of conditions and the following disclaimer. | |||||
## | |||||
## 2. Redistributions in binary form must reproduce the above | |||||
## copyright notice, this list of conditions and the following | |||||
## disclaimer in the documentation and/or other materials provided | |||||
## with the distribution. | |||||
## | |||||
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||||
## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||||
## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |||||
## FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |||||
## COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||||
## INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
## (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||||
## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||||
## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||||
## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||||
## OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
## | |||||
## Any use of the software for scientific publications or commercial | |||||
## purposes should be reported to the University of Bristol | |||||
## (OSI-notifications@bristol.ac.uk and quote reference 2668). This is | |||||
## for impact and usage monitoring purposes only. | |||||
## | |||||
## Enquiries about further applications and development opportunities | |||||
## are welcome. Please contact elisabeth.oswald@bristol.ac.uk | |||||
## | |||||
.syntax unified | |||||
.text | |||||
.thumb | |||||
.func starttrigger | |||||
.global starttrigger | |||||
starttrigger: | |||||
push {r0-r7} | |||||
movs r4, #0xE0 | |||||
lsls r4, #24 | |||||
movs r5, #0x04 | |||||
eors r4, r5 | |||||
movs r5, #1 | |||||
str r5, [r4, #0] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func endtrigger | |||||
.global endtrigger | |||||
endtrigger: | |||||
push {r0-r7} | |||||
movs r4, #0xE0 | |||||
lsls r4, #24 | |||||
movs r5, #0x04 | |||||
eors r4, r5 | |||||
movs r5, #0 | |||||
str r5, [r4, #0] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func readbyte | |||||
.global readbyte | |||||
readbyte: | |||||
push {r0-r7} | |||||
movs r4, #0xE1 | |||||
lsls r4, #24 | |||||
ldr r1, [r4, #0] | |||||
strb r1, [r0, #0] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func LoadN | |||||
.global LoadN | |||||
LoadN: | |||||
push {r0-r7} | |||||
movs r4, #0xE1 | |||||
lsls r4, #24 | |||||
movs r5, #0x10 | |||||
eors r4, r5 | |||||
ldr r1, [r4, #0] | |||||
str r1, [r0, #0] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func randbyte | |||||
.global randbyte | |||||
randbyte: | |||||
push {r0-r7} | |||||
movs r4, #0xE1 | |||||
lsls r4, #24 | |||||
movs r5, #0x04 | |||||
eors r4, r5 | |||||
ldr r1, [r4, #0] | |||||
strb r1, [r0, #0] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func getstart | |||||
.global getstart | |||||
getstart: | |||||
push {r0-r7} | |||||
movs r4, #0xE1 | |||||
lsls r4, #24 | |||||
movs r5, #0x08 | |||||
eors r4, r5 | |||||
ldr r1, [r4, #0] | |||||
str r1, [r0, #0] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func getruncount | |||||
.global getruncount | |||||
getruncount: | |||||
push {r0-r7} | |||||
movs r4, #0xE1 | |||||
lsls r4, #24 | |||||
movs r5, #0x0C | |||||
eors r4, r5 | |||||
ldr r1, [r4, #0] | |||||
str r1, [r0, #0] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func printbyte | |||||
.global printbyte | |||||
printbyte: | |||||
push {r0-r7} | |||||
movs r4, #0xE0 | |||||
lsls r4, #24 | |||||
ldrb r5, [r0] | |||||
str r5, [r4] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func endprogram | |||||
.global endprogram | |||||
endprogram: | |||||
push {r0-r7} | |||||
movs r4, #0xF0 | |||||
lsls r4, #24 | |||||
movs r5, #0 | |||||
str r5, [r4] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func initialisemaskflow | |||||
.global initialisemaskflow | |||||
# Takes address of key as input (r0) | |||||
initialisemaskflow: | |||||
push {r0-r7} | |||||
movs r4, #0xE0 | |||||
lsls r4, #24 | |||||
movs r5, #0x40 | |||||
eors r4, r5 | |||||
str r0, [r4] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func resetmaskflow | |||||
.global resetmaskflow | |||||
resetmaskflow: | |||||
push {r0-r7} | |||||
movs r4, #0xE0 | |||||
lsls r4, #24 | |||||
movs r5, #0x42 | |||||
eors r4, r5 | |||||
movs r5, #0 | |||||
str r5, [r4] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func setmaskflowstart | |||||
.global setmaskflowstart | |||||
# Takes r0 as start number | |||||
setmaskflowstart: | |||||
push {r0-r7} | |||||
movs r4, #0xE0 | |||||
lsls r4, #24 | |||||
movs r5, #0x44 | |||||
eors r4, r5 | |||||
str r0, [r4] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc | |||||
.func resetdatafile | |||||
.global resetdatafile | |||||
resetdatafile: | |||||
push {r0-r7} | |||||
movs r4, #0xE0 | |||||
lsls r4, #24 | |||||
movs r5, #0x46 | |||||
eors r4, r5 | |||||
movs r5, #0 | |||||
str r5, [r4] | |||||
pop {r0-r7} | |||||
bx lr | |||||
.endfunc |
/* | |||||
* University of Bristol – Open Access Software Licence | |||||
* Copyright (c) 2016, The University of Bristol, a chartered | |||||
* corporation having Royal Charter number RC000648 and a charity | |||||
* (number X1121) and its place of administration being at Senate | |||||
* House, Tyndall Avenue, Bristol, BS8 1TH, United Kingdom. | |||||
* All rights reserved | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* 2. Redistributions in binary form must reproduce the above | |||||
* copyright notice, this list of conditions and the following | |||||
* disclaimer in the documentation and/or other materials provided | |||||
* with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||||
* OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
* | |||||
* Any use of the software for scientific publications or commercial | |||||
* purposes should be reported to the University of Bristol | |||||
* (OSI-notifications@bristol.ac.uk and quote reference 2668). This is | |||||
* for impact and usage monitoring purposes only. | |||||
* | |||||
* Enquiries about further applications and development opportunities | |||||
* are welcome. Please contact elisabeth.oswald@bristol.ac.uk | |||||
*/ | |||||
extern void starttrigger(void); | |||||
extern void endtrigger(void); | |||||
extern void randbyte(unsigned char * pointer); | |||||
extern void LoadN(void* addr); | |||||
extern void readbyte(unsigned char * pointer); | |||||
extern void printbyte(unsigned char * pointer); | |||||
extern void endprogram(void); | |||||
extern void getstart(unsigned int * pointer); | |||||
extern void getruncount(unsigned int * pointer); | |||||
extern void initialisemaskflow(unsigned char * pointer); | |||||
extern void resetmaskflow(void); | |||||
extern void setmaskflowstart(unsigned int start); | |||||
extern void resetdatafile(void); |
import os | |||||
import json | |||||
class ClosureException(Exception): | |||||
pass | |||||
# https://stackoverflow.com/questions/20007319/how-to-do-a-large-text-file-transfer-in-python | |||||
class SocketTool: | |||||
@classmethod | |||||
def convert_to_bytes(cl, no): | |||||
result = bytearray() | |||||
result.append(no & 255) | |||||
for i in range(3): | |||||
no = no >> 8 | |||||
result.append(no & 255) | |||||
return result | |||||
@classmethod | |||||
def bytes_to_number(cl, b): | |||||
import sys | |||||
b = b if (sys.version_info > (3, 0)) else map(ord, b) | |||||
res = 0 | |||||
for i in range(4): | |||||
res += b[i] << (i*8) | |||||
return res | |||||
@classmethod | |||||
def send_file(cl, s, filename, mode='rb'): | |||||
length = os.path.getsize(filename) | |||||
s.send(cl.convert_to_bytes(length)) # has to be 4 bytes | |||||
with open(filename, mode) as infile: | |||||
d = infile.read(1024*64) # We send by pack of 64 ko | |||||
while d: | |||||
s.send(d) | |||||
d = infile.read(1024*64) | |||||
@classmethod | |||||
def get_file(cl, s): | |||||
size = s.recv(4) # assuming that the size won't be bigger then 1GB | |||||
size = cl.bytes_to_number(size) | |||||
current_size = 0 | |||||
buffer = b'' | |||||
while current_size < size: | |||||
data = s.recv(1024*64) | |||||
if not data: | |||||
break | |||||
if len(data) + current_size > size: | |||||
data = data[:size-current_size] # trim additional data | |||||
buffer += data | |||||
# you can stream here to disk | |||||
current_size += len(data) | |||||
# you have entire file in memory | |||||
return buffer | |||||
@classmethod | |||||
def send_data(cl, s, data): | |||||
data = json.dumps(data) | |||||
data = data.encode('utf-8') | |||||
s.send(cl.convert_to_bytes(len(data))) # has to be 4 bytes | |||||
s.send(data) | |||||
@classmethod | |||||
def get_data(cl, s): | |||||
import sys | |||||
exception_class = json.decoder.JSONDecodeError if (sys.version_info > (3, 0)) else ValueError | |||||
try: | |||||
size = s.recv(4) | |||||
if not size: | |||||
return None | |||||
size = cl.bytes_to_number(size) | |||||
data = s.recv(size) | |||||
data = data.decode('utf-8') | |||||
data = json.loads(data) | |||||
return data | |||||
except exception_class: | |||||
return None | |||||
@classmethod | |||||
def send_ack(cl, s, positive=True): | |||||
data = 'OK' if positive else 'NO' | |||||
s.send(data.encode('ascii')) | |||||
@classmethod | |||||
def get_ack(cl, s): | |||||
data = s.recv(2).decode('ascii') | |||||
return (data == 'OK') | |||||
class Protocol: | |||||
def __init__(self, clientsocket): | |||||
self.clientsocket = clientsocket | |||||
def send_file(self, filename, mode='rb'): | |||||
SocketTool.send_file(self.clientsocket, filename, mode) | |||||
def get_file(self): | |||||
return SocketTool.get_file(self.clientsocket) | |||||
def send_data(self, data): | |||||
SocketTool.send_data(self.clientsocket, data) | |||||
def get_data(self): | |||||
return SocketTool.get_data(self.clientsocket) | |||||
def send_ack(self, positive=True): | |||||
SocketTool.send_ack(self.clientsocket, positive) | |||||
def send_nack(self, positive=True): | |||||
SocketTool.send_ack(self.clientsocket, not positive) | |||||
def get_ack(self): | |||||
return SocketTool.get_ack(self.clientsocket) | |||||
def please_assert(self, condition): | |||||
if not condition: | |||||
self.send_nack() | |||||
self.clientsocket.close() | |||||
raise ClosureException | |||||
def get_object_or_nack(self, model, **kwargs): | |||||
try: | |||||
return model.objects.get(**kwargs) | |||||
except model.DoesNotExist: | |||||
self.send_nack() | |||||
self.clientsocket.close() | |||||
raise ClosureException | |||||
def close(self): | |||||
self.clientsocket.close() |
elmo_repository="elmo" | |||||
elmo_source="https://github.com/sca-research/ELMO.git" | |||||
echo "====== ELMO Online ======" | |||||
if [ -d ${elmo_repository} ]; then | |||||
echo " - ELMO tool already installed." | |||||
else | |||||
# 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 | |||||
#current_directory=${PWD##*/} | |||||
#echo " - Current directory: ${current_directory}" | |||||
echo | |||||
#cd .. | |||||
#python3 -m ${current_directory}.run_server | |||||
python3 run_server.py |
from listeningthread import ListeningThread | |||||
from executorthread import ExecutorThread | |||||
def do_main_program(projects): | |||||
global thread, stop | |||||
thread = ListeningThread('localhost', 5000, ExecutorThread, projects=projects) | |||||
thread.start() | |||||
def program_cleanup(signum, frame): | |||||
global thread, stop | |||||
thread.stop() | |||||
stop = True | |||||
thread = None | |||||
stop = False | |||||
# Information | |||||
from project_reader import ProjectReader | |||||
reader = ProjectReader() | |||||
projects = {sc.get_project_label(): sc for sc in reader.get_project_classes()} | |||||
print('Available projects: %s' % list(projects.keys())) | |||||
print('') | |||||
# Execute | |||||
print("Executing...") | |||||
do_main_program(projects) | |||||
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 threading | |||||
from protocol import Protocol, ClosureException | |||||
class ServiceThread(threading.Thread): | |||||
def run(self): | |||||
self.execute() | |||||
def execute(self): | |||||
# Method where the service runs | |||||
pass | |||||
class OneShotServiceThread(ServiceThread): | |||||
def __init__(self, ip, port, clientsocket): | |||||
threading.Thread.__init__(self) | |||||
self.ip = ip | |||||
self.port = port | |||||
self.clientsocket = clientsocket | |||||
self.protocol = Protocol(clientsocket) | |||||
def run(self): | |||||
try: | |||||
self.execute() | |||||
except ClosureException: | |||||
return | |||||
def execute(self): | |||||
# Method where the service runs | |||||
pass | |||||
class PermanentServiceThread(ServiceThread): | |||||
def __init__(self): | |||||
threading.Thread.__init__(self) | |||||
self._is_running = True | |||||
def is_running(self): | |||||
return self._is_running | |||||
def stop(self): | |||||
self._is_running = False | |||||