Source code for lascar.container.simulation_container

# This file is part of lascar
#
# lascar is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
#
# Copyright 2018 Manuel San Pedro, Victor Servant, Charles Guillemet, Ledger SAS - manuel.sanpedro@ledger.fr, victor.servant@ledger.fr, charles@ledger.fr

"""
simulation_container.py
"""
import numpy as np

from lascar.tools.aes import sbox, Aes
from lascar.tools.leakage_model import HammingPrecomputedModel
from .container import AbstractContainer, Trace

DEFAULT_KEY = [i for i in range(16)]


[docs]class BasicAesSimulationContainer(AbstractContainer): """ BascAesSimulationContainer is an AbstractContainer used to naively simulate traces during the first Subbyte of the first round of an AES. """ def __init__( self, number_of_traces, noise=1, key=DEFAULT_KEY, seed=1337, leakage_model="default", additional_time_samples=10, **kwargs ): """ Basic constructor: :param number_of_traces: :param noise: noise level of the simulated noise. (The noise follows a normal law with mean zero, and std=noiselevel) :param key: optional, the key used during AES first round (16 bytes) :param seed: optional, the seed used to generate values and noise (for reproductibility) :param leakage_model: optional, leakage model used (HammingWeight by default) :param additional_time_samples: optional: add dummy time samples """ if leakage_model == "default": leakage_model = HammingPrecomputedModel() self.seed = seed self.noise = noise self.leakage_model = leakage_model self.additional_time_samples = additional_time_samples self.value_dtype = np.dtype( [("plaintext", np.uint8, (16,)), ("key", np.uint8, (16,)),] ) self.key = key AbstractContainer.__init__(self, number_of_traces, **kwargs) self.logger.debug("Creating BasicAesSimulationContainer.") self.logger.debug("Noise set to %f, seed set to %d.", self.noise, self.seed) self.logger.debug("Key set to %s", str(key))
[docs] def generate_trace(self, idx): np.random.seed(seed=self.seed ^ idx) # for reproducibility value = np.zeros((), dtype=self.value_dtype) value["plaintext"] = np.random.randint(0, 256, (16,), np.uint8) value["key"] = self.key leakage = np.random.normal(0, self.noise, (16 + self.additional_time_samples,)) leakage[:16] += np.array( [ self.leakage_model(sbox[value["plaintext"][i] ^ value["key"][i]]) for i in range(16) ] ) return Trace(leakage, value)
[docs]class AesSimulationContainer(AbstractContainer): """ AesSimulationContainer is an AbstractContainer used to simulate traces during all the round function of an AES. """ def __init__( self, number_of_traces, noise=1, key=DEFAULT_KEY, seed=1337, leakage_model="default", additional_time_samples=10, **kwargs ): """ Basic constructor: :param number_of_traces: :param noise: noise level of the simulated noise. (The noise follows a normal law with mean zero, and std=noiselevel) :param key: optional, the key used during AES first round (16 bytes) :param seed: optional, the seed used to generate values and noise (for reproductibility) :param leakage_model: optional, leakage model used (HammingWeight by default) :param additional_time_samples: optional: add dummy time samples """ if leakage_model == "default": leakage_model = HammingPrecomputedModel() self.seed = seed self.noise = noise self.leakage_model = leakage_model self.additional_time_samples = additional_time_samples self.value_dtype = np.dtype( [ ("plaintext", np.uint8, (16,)), ("key", np.uint8, (len(key),)), ("ciphertext", np.uint8, (16,)), ] ) self.key = key AbstractContainer.__init__(self, number_of_traces, **kwargs) self.logger.debug("Creating AesSimulationContainer.") self.logger.debug("Noise set to %f, seed set to %d.", self.noise, self.seed) self.logger.debug("Key set to %s", str(key))
[docs] def generate_trace(self, idx): np.random.seed(seed=self.seed ^ idx) # for reproducibility value = np.zeros((), dtype=self.value_dtype) value["plaintext"] = np.random.randint(0, 256, (16,), np.uint8) value["key"] = self.key leakage = Aes.encrypt_keep_iv(value["plaintext"], Aes.key_schedule(value["key"])) value["ciphertext"] = leakage[-16:] leakage = np.array([self.leakage_model(i) for i in leakage]) # leakage model leakage = leakage + np.random.normal(0, self.noise, (len(leakage),)) # noise return Trace(leakage, value)
# class FromFunctionSimulationContainer(AbstractContainer): # """ # FromFunctionSimulationContainer is a SimulationContainer which use a function to generate its trace. # The function can handle oscilloscopes, dut, or generated data. # To use in combination with Container.export methods # """ # def __init__(self, number_of_traces, function): # """ # # :param number_of_traces: # :param function: function to generate the Traces. Must return a couple (leakage,value) # """ # AbstractContainer.__init__(self, number_of_traces) # # self._function = function # self.logger.debug('Creating ScopeDutSimulationContainer.') # # def generate_trace(self, idx): # return self._function(idx)