├── src ├── secbench-processing │ ├── secbench │ │ └── processing │ │ │ ├── oracles │ │ │ └── __init__.py │ │ │ ├── crypto │ │ │ ├── pcg32.py │ │ │ ├── __init__.py │ │ │ └── crc8.py │ │ │ ├── __init__.py │ │ │ ├── _network.py │ │ │ └── _native.py │ ├── README.md │ ├── tox.ini │ ├── setup.cfg │ ├── tests │ │ ├── test_pcg32.py │ │ ├── test_helpers.py │ │ ├── test_profiled.py │ │ ├── test_keccak.py │ │ └── test_models.py │ └── pyproject.toml ├── secbench-picoscope │ ├── secbench │ │ └── picoscope │ │ │ ├── lib │ │ │ ├── __init__.py │ │ │ └── common.py │ │ │ ├── __init__.py │ │ │ ├── types.py │ │ │ └── helpers.py │ ├── tox.ini │ ├── README.md │ ├── setup.cfg │ └── pyproject.toml ├── secbench-api │ ├── tox.ini │ ├── README.md │ ├── setup.cfg │ ├── secbench │ │ └── api │ │ │ ├── simulation │ │ │ ├── __init__.py │ │ │ ├── table.py │ │ │ └── pulser.py │ │ │ ├── backend │ │ │ ├── __init__.py │ │ │ ├── types.py │ │ │ ├── vxi11.py │ │ │ └── pyvisa.py │ │ │ ├── types.py │ │ │ ├── _utils.py │ │ │ ├── instrument │ │ │ ├── __init__.py │ │ │ ├── psu.py │ │ │ ├── types.py │ │ │ └── features.py │ │ │ ├── __init__.py │ │ │ ├── exceptions.py │ │ │ └── hooks.py │ ├── tests │ │ ├── test_core.py │ │ ├── test_pulser.py │ │ ├── test_config.py │ │ └── conftest.py │ └── pyproject.toml ├── secbench-storage │ ├── tox.ini │ ├── README.md │ ├── setup.cfg │ ├── secbench │ │ └── storage │ │ │ └── __init__.py │ └── pyproject.toml └── secbench-native │ ├── README.md │ ├── crates │ ├── secbench_processing │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── crypto.rs │ │ │ ├── errors.rs │ │ │ └── lib.rs │ ├── secbench_crypto │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── secbench_dsp │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs │ ├── pyproject.toml │ ├── src │ └── lib.rs │ └── Cargo.toml ├── secbench_logo.png ├── doc ├── _static │ ├── interpreterGear.png │ ├── secbench-logo-2023.png │ ├── secbench_arch_overview.jpg │ └── custom_basicstrap.css ├── api-reference │ ├── backend_class_diagram.png │ ├── index.rst │ ├── storage.rst │ └── picoscope.rst ├── tutorials │ ├── index.rst │ ├── configuration.md │ └── pattern_matching_alignment.md ├── glossary.rst ├── Makefile ├── installation.md └── index.rst ├── .gitignore ├── CITATION.cff ├── ci └── Jenkinsfile ├── sdk ├── patch_libudev.py └── activate.sh.in ├── PUBLICATIONS.md └── README.md /src/secbench-processing/secbench/processing/oracles/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /secbench_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CEA-Leti/secbench/HEAD/secbench_logo.png -------------------------------------------------------------------------------- /doc/_static/interpreterGear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CEA-Leti/secbench/HEAD/doc/_static/interpreterGear.png -------------------------------------------------------------------------------- /doc/_static/secbench-logo-2023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CEA-Leti/secbench/HEAD/doc/_static/secbench-logo-2023.png -------------------------------------------------------------------------------- /doc/_static/secbench_arch_overview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CEA-Leti/secbench/HEAD/doc/_static/secbench_arch_overview.jpg -------------------------------------------------------------------------------- /doc/api-reference/backend_class_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CEA-Leti/secbench/HEAD/doc/api-reference/backend_class_diagram.png -------------------------------------------------------------------------------- /doc/api-reference/index.rst: -------------------------------------------------------------------------------- 1 | .. _sec:api_reference: 2 | 3 | API Reference 4 | ============= 5 | 6 | .. toctree:: 7 | :maxdepth: 1 8 | 9 | api 10 | storage 11 | processing 12 | picoscope 13 | -------------------------------------------------------------------------------- /doc/_static/custom_basicstrap.css: -------------------------------------------------------------------------------- 1 | .py.method { 2 | border-left: 4px solid beige; 3 | padding-left: 5px; 4 | } 5 | 6 | .py.function { 7 | border-left: 4px solid lightblue; 8 | padding-left: 5px; 9 | } 10 | -------------------------------------------------------------------------------- /src/secbench-picoscope/secbench/picoscope/lib/__init__.py: -------------------------------------------------------------------------------- 1 | from .ps2000a import load_ps2000a 2 | from .ps3000a import load_ps3000a 3 | from .ps6000 import load_ps6000 4 | 5 | __all__ = ["load_ps6000", "load_ps2000a", "load_ps3000a"] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python temporary 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.eggs/ 6 | *.egg-info/ 7 | .cache/ 8 | /.coverage 9 | .pytest_cache/ 10 | .tox 11 | dist/ 12 | build/ 13 | 14 | # IDE 15 | .idea 16 | 17 | .venv/ 18 | /venv* 19 | _build/ 20 | 21 | *.hdf5 22 | report-pytest*.xml 23 | 24 | /src/secbench-native/target 25 | -------------------------------------------------------------------------------- /doc/tutorials/index.rst: -------------------------------------------------------------------------------- 1 | .. _sec:tutorials: 2 | 3 | Learning Secbench 4 | ================= 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | bench_and_discovery.md 10 | storage_walkthrough.md 11 | using_scopes.md 12 | acquisition_and_storage.md 13 | configuration.md 14 | instrument_tutorial.md 15 | pattern_matching_alignment.md 16 | -------------------------------------------------------------------------------- /src/secbench-api/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | min_version = 4.20 3 | envlist = py310,py311,py312,py313 4 | isolated_build = true 5 | 6 | [testenv] 7 | description = Running tests for {envname} 8 | deps = 9 | pytest 10 | pint 11 | commands = 12 | python -m pytest --junit-xml=report-pytest-{envname}-api.xml -o junit_suite_name=tests-{envname}-api tests 13 | -------------------------------------------------------------------------------- /src/secbench-picoscope/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | min_version = 4.20 3 | envlist = py310,py311,py312,py313 4 | isolated_build = true 5 | 6 | [testenv] 7 | description = Running tests for {envname} 8 | deps = 9 | pytest 10 | commands = 11 | python -m pytest --junit-xml=report-pytest-{envname}-picoscope.xml -o junit_suite_name=tests-{envname}-picoscope tests 12 | -------------------------------------------------------------------------------- /src/secbench-storage/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | min_version = 4.20 3 | envlist = py39,py310,py311,py312,py313 4 | isolated_build = true 5 | 6 | [testenv] 7 | description = Running tests for {envname} 8 | deps = 9 | pytest 10 | commands = 11 | python -m pytest --junit-xml=report-pytest-{envname}-storage.xml -o junit_suite_name=tests-{envname}-storage tests 12 | -------------------------------------------------------------------------------- /src/secbench-native/README.md: -------------------------------------------------------------------------------- 1 | # Secbench framework (`secbench-native` package) 2 | 3 | This project contains helpers written in Rust for use in the secbench framework. 4 | 5 | For getting started, please refer to the [documentation of the secbench framework](https://doc.secbench.fr), or the [source repository](https://github.com/CEA-Leti/secbench). 6 | 7 | This project is licensed under [CECILL-2.1](http://www.cecill.info/index.en.html) (see LICENSE). -------------------------------------------------------------------------------- /src/secbench-api/README.md: -------------------------------------------------------------------------------- 1 | # Secbench framework (`secbench-api` package) 2 | 3 | The `secbench-api` module contains API definitions and helpers for the whole secbench framework. 4 | 5 | For getting started, please refer to the [documentation of the secbench framework](https://doc.secbench.fr), or the [source repository](https://github.com/CEA-Leti/secbench). 6 | 7 | This project is licensed under [CECILL-2.1](http://www.cecill.info/index.en.html) (see LICENSE). -------------------------------------------------------------------------------- /src/secbench-picoscope/README.md: -------------------------------------------------------------------------------- 1 | # Secbench framework (`secbench-picoscope` package) 2 | 3 | The `secbench-picoscope` contains drivers for Picoscope devices compatible with `secbench-api`. 4 | 5 | For getting started, please refer to the [documentation of the secbench framework](https://doc.secbench.fr), or the [source repository](https://github.com/CEA-Leti/secbench). 6 | 7 | This project is licensed under [CECILL-2.1](http://www.cecill.info/index.en.html) (see LICENSE). -------------------------------------------------------------------------------- /src/secbench-native/crates/secbench_processing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "secbench_processing" 3 | version.workspace = true 4 | edition.workspace = true 5 | 6 | [dependencies] 7 | pyo3.workspace = true 8 | numpy.workspace = true 9 | # rayon.workspace = true 10 | num-traits.workspace = true 11 | 12 | tracing.workspace = true 13 | tracing-subscriber.workspace = true 14 | 15 | num.workspace = true 16 | 17 | secbench_crypto.workspace = true 18 | secbench_dsp.workspace = true -------------------------------------------------------------------------------- /src/secbench-processing/README.md: -------------------------------------------------------------------------------- 1 | # Secbench framework (`secbench-processing` module) 2 | 3 | The `secbench-processing` module contains implementation state-of-the-art side-channel analysis algorithms. 4 | 5 | For getting started, please refer to the [documentation of the secbench framework](https://doc.secbench.fr), or the [source repository](https://github.com/CEA-Leti/secbench). 6 | 7 | This project is licensed under [CECILL-2.1](http://www.cecill.info/index.en.html) (see LICENSE). 8 | -------------------------------------------------------------------------------- /src/secbench-storage/README.md: -------------------------------------------------------------------------------- 1 | # Secbench framework (`secbench-storage` package) 2 | 3 | The `secbench-storage` module contains implementation of secbench storage format for side-channel traces (based on HDF5). 4 | 5 | For getting started, please refer to the [documentation of the secbench framework](https://doc.secbench.fr), or the [source repository](https://github.com/CEA-Leti/secbench). 6 | 7 | This project is licensed under [CECILL-2.1](http://www.cecill.info/index.en.html) (see LICENSE). -------------------------------------------------------------------------------- /src/secbench-processing/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | min_version = 4.20 3 | envlist = py310,py311,py312,py313 4 | isolated_build = true 5 | 6 | [testenv] 7 | description = Running tests for {envname} 8 | # For testing, uncomment: 9 | # setenv = 10 | # PIP_INDEX_URL=https://test.pypi.org/simple/ 11 | # PIP_EXTRA_INDEX_URL=https://pypi.org/simple/ 12 | deps = 13 | secbench-native 14 | h5py 15 | pytest 16 | commands = 17 | python -m pytest --junit-xml=report-pytest-{envname}-api.xml -o junit_suite_name=tests-{envname}-api tests 18 | -------------------------------------------------------------------------------- /doc/glossary.rst: -------------------------------------------------------------------------------- 1 | .. _sec_glossary: 2 | 3 | Glossary 4 | ======== 5 | 6 | .. glossary:: 7 | 8 | CPA 9 | Correlation Power Analysis. An unprofiled attack strategy, where we use 10 | Pearson's Correlation to evaluate predictions on an intermediate value. 11 | 12 | DPA 13 | Differential Power Analysis. 14 | 15 | GE 16 | Guessing Entropy. 17 | 18 | LRA 19 | Linear Regression Analysis. 20 | 21 | DUT 22 | Device Under Test. 23 | 24 | SNR 25 | Signal-to-Noise Ratio. 26 | 27 | SCA 28 | Side-Channel Analysis. 29 | 30 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you find this project useful, please cite it as below." 3 | authors: 4 | - family-names: "Hiscock" 5 | given-names: "Thomas" 6 | orcid: https://orcid.org/0009-0001-5183-2291 7 | - family-names: "Maillard" 8 | given-names: "Julien" 9 | orcid: https://orcid.org/0009-0002-2267-7621 10 | - family-names: "Lecomte" 11 | given-names: "Maxime" 12 | orcid: https://orcid.org/0000-0002-9985-7586 13 | - family-names: "Malandrino-Guyot" 14 | given-names: "Lucas" 15 | - family-names: "Moran" 16 | given-names: "Antoine" 17 | title: "Secbench framework" 18 | version: 2025.02 19 | date-released: 2025-02-20 20 | -------------------------------------------------------------------------------- /ci/Jenkinsfile: -------------------------------------------------------------------------------- 1 | // Jenkinsfile for packaging secbench-native using manylinux2014 image 2 | pipeline { 3 | agent { 4 | label 'secbench-jenkins-agent-1' 5 | } 6 | options { 7 | timeout(time: 1, unit: 'HOURS') 8 | } 9 | stages { 10 | stage('build') { 11 | agent { 12 | docker { 13 | image 'secbench:v11' 14 | args '--network host -v $HOME/jenkins/cache/pip:/home/jenkins/.cache/pip -v $HOME/jenkins/cache/cargo:/home/jenkins/.cargo/registry -v $HOME/jenkins/secbench-wheels:/home/jenkins/secbench-wheels' 15 | } 16 | } 17 | steps { 18 | sh """ 19 | . /home/jenkins/.bash_profile 20 | env 21 | 22 | pushd src/secbench-native 23 | maturin build --release 24 | popd 25 | 26 | find . -name '*.whl' -exec cp -v {} /home/jenkins/secbench-wheels/ \\; 27 | """ 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/secbench-picoscope/secbench/picoscope/lib/common.py: -------------------------------------------------------------------------------- 1 | def def_symbol(lib, name, return_type, arg_types, docstring=None): 2 | c_function = getattr(lib, name) 3 | c_function.restype = return_type 4 | c_function.argtypes = arg_types 5 | if docstring is not None: 6 | c_function.__doc__ = docstring 7 | 8 | 9 | def load_libps(name: str): 10 | """ 11 | Try to find picoscope library on the current system. 12 | 13 | :param name: prefix of the library (e.g., "ps2000a", "ps6000") 14 | :returns: a handle (ctypes or windll) on the library. 15 | """ 16 | import platform 17 | 18 | system = platform.system() 19 | if system == "Linux": 20 | from ctypes import cdll 21 | 22 | lib = cdll.LoadLibrary(f"lib{name}.so.2") 23 | elif system == "Darwin": 24 | raise NotImplementedError("MacOSX is not supported yet") 25 | elif system == "Windows": 26 | from ctypes import windll 27 | from ctypes.util import find_library 28 | 29 | lib = windll.LoadLibrary(find_library(f"{name}.dll")) 30 | else: 31 | raise NotImplementedError( 32 | f"Unsupported platform for loading lib{name}: {system}" 33 | ) 34 | return lib -------------------------------------------------------------------------------- /doc/api-reference/storage.rst: -------------------------------------------------------------------------------- 1 | .. py:module:: secbench.storage 2 | 3 | .. _module-storage: 4 | 5 | Module: ``secbench.storage`` 6 | ============================ 7 | 8 | This is the API documentation for the :py:mod:`secbench.storage` module. An :ref:`interactive user-guide ` is also available. 9 | 10 | You will use mainly two classes from this module: 11 | 12 | - :py:class:`~Store`, the storage abstraction layer. A :py:class:`~Store` contains zero or more :py:class:`~Datasets`. 13 | - :py:class:`~Dataset`, which allow to access and modify datasets. 14 | 15 | Shared datasets 16 | --------------- 17 | 18 | Over the years, we accumulated several datasets from real targets. To list the datasets available use: 19 | 20 | .. code-block:: console 21 | 22 | $ secbench-db list -l 23 | 24 | From Python, you can use :py:func:`secbench.storage.load_shared_dataset`. If you need to list datasets, use :py:func:`secbench.storage.shared_datasets`. 25 | 26 | .. autofunction:: secbench.storage.load_shared_dataset 27 | 28 | .. autofunction:: secbench.storage.shared_datasets 29 | 30 | Storage types 31 | ------------- 32 | 33 | The :py:class:`Store` class is the top-level accessor for dataset. 34 | 35 | .. autoclass:: secbench.storage.Store 36 | :members: 37 | :inherited-members: 38 | :member-order: bysource 39 | 40 | Then, the :py:class:`Dataset` class is used to manage individual datasets. 41 | 42 | .. autoclass:: secbench.storage.Dataset 43 | :members: 44 | :member-order: bysource 45 | 46 | .. autoclass:: secbench.storage.DatasetRef 47 | :members: 48 | :member-order: bysource 49 | 50 | Helpers 51 | ------- 52 | 53 | .. autofunction:: secbench.storage.version 54 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | MAKEFLAGS += \ 2 | --no-builtin-rules \ 3 | --warn-undefined-variables 4 | 5 | REV := v2025.02 6 | 7 | # Inkscape 8 | INKSCAPE ?= inkscape 9 | INKSCAPE_FLAGS ?= 10 | INKSCAPE_FLAGS += --export-text-to-path 11 | INKSCAPE_VERSION_1 := $(shell inkscape --version | grep -o -E 'Inkscape 1\.[0-9]+') 12 | 13 | all_figs := 14 | 15 | # You can set these variables from the command line. 16 | SPHINXOPTS ?= 17 | SPHINXBUILD = python -msphinx 18 | SPHINXPROJ = secbench-core 19 | SOURCEDIR = . 20 | BUILDDIR = _build 21 | 22 | .PHONY: help 23 | # Put it first so that "make" without argument is like "make help". 24 | help: 25 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 26 | 27 | .PHONY: serve 28 | serve: build-html 29 | @cd $(BUILDDIR) \ 30 | && cd html \ 31 | && echo http://127.0.0.1:8000/ \ 32 | && python3 -m http.server 33 | 34 | .PHONY: figs 35 | figs: $(all_figs) 36 | 37 | # Inkscape Rules 38 | %.pdf: %.svg 39 | ifeq ($(INKSCAPE_VERSION_1),) # Inkscape < 1.0 40 | $(INKSCAPE) $(INKSCAPE_FLAGS) -D -A $@ $< 41 | else 42 | $(INKSCAPE) $(INKSCAPE_FLAGS) -D -o $@ $< 43 | endif 44 | 45 | %.png: %.svg 46 | ifeq ($(INKSCAPE_VERSION_1),) # Inkscape < 1.0 47 | $(INKSCAPE) $(INKSCAPE_FLAGS) -D -d 100 -e $@ $< 48 | else 49 | $(INKSCAPE) $(INKSCAPE_FLAGS) -D -d 100 -o $@ $< 50 | endif 51 | 52 | # Catch-all target: route all unknown targets to Sphinx using the new 53 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 54 | build-%: Makefile figs 55 | @$(SPHINXBUILD) -M $* "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) 56 | 57 | deploy: build-html 58 | touch _build/html/.nojekyll 59 | echo "doc.secbench.fr" > _build/html/CNAME 60 | ghp-import _build/html 61 | -------------------------------------------------------------------------------- /src/secbench-picoscope/setup.cfg: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | [flake8] 33 | ignore = E501,E203 -------------------------------------------------------------------------------- /src/secbench-storage/setup.cfg: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | [flake8] 33 | ignore = E501,E203 34 | max-line-length = 100 -------------------------------------------------------------------------------- /src/secbench-processing/secbench/processing/crypto/pcg32.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | from .._native import secbench_native_import 33 | 34 | Pcg32 = secbench_native_import("Pcg32") -------------------------------------------------------------------------------- /doc/api-reference/picoscope.rst: -------------------------------------------------------------------------------- 1 | .. py:module:: secbench.picoscope 2 | 3 | .. _module-picoscope: 4 | 5 | Module: ``secbench.picoscope`` 6 | ============================== 7 | 8 | The :py:mod:`secbench.picoscope` module contains drivers for `Picoscope oscilloscopes `__. 9 | 10 | This module requires Picoscope libraries to be installed. 11 | You can install the `PicoSDK `__ or simply 12 | 13 | The package requires to have in your library path: 14 | 15 | - For :py:class:`~PicoPS6000Scope`: 16 | 17 | - ``libps6000.so`` on Unix systems 18 | - ``ps6000.dll`` on Window 19 | 20 | - For :py:class:`~PicoPS2000AScope`: 21 | 22 | - ``libps2000a.so`` on Unix systems 23 | - ``ps2000a.dll`` on Window 24 | 25 | .. note:: 26 | 27 | On Linux, we recommend to set the correct permissions on the USB ports to avoid running scripts as root. 28 | You can add the following line in ``/lib/udev/rules.d/99-secbench.rules``: 29 | 30 | .. code-block:: text 31 | 32 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ce9", MODE="0660", GROUP="plugdev" 33 | 34 | Make sure you are in the ``plugdev`` group. 35 | 36 | Usage 37 | ----- 38 | 39 | Once everything is installed and a scope is connected to your computer, you 40 | should be able to load a device with: 41 | 42 | .. code-block:: python 43 | 44 | from secbench.api import get_bench 45 | 46 | bench = get_bench() 47 | scope = bench.get_scope() 48 | print(scope) 49 | 50 | The :py:mod:`secbench.api` automatically tries to import :py:mod:`secbench.picoscope` so that the devices are discoverable. 51 | 52 | Supported models 53 | ---------------- 54 | 55 | .. autoclass:: secbench.picoscope.PicoPS2000AScope 56 | 57 | .. autoclass:: secbench.picoscope.PicoPS6000Scope 58 | -------------------------------------------------------------------------------- /src/secbench-processing/setup.cfg: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | [tool:pytest] 33 | junit_family=xunit1 34 | addopts = --doctest-modules 35 | doctest_optionflags= NORMALIZE_WHITESPACE ELLIPSIS 36 | 37 | 38 | [flake8] 39 | ignore = E501,W503 -------------------------------------------------------------------------------- /src/secbench-native/crates/secbench_crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | 30 | [package] 31 | name = "secbench_crypto" 32 | version.workspace = true 33 | edition.workspace = true 34 | 35 | [dependencies] 36 | 37 | rand_core.workspace = true 38 | serde.workspace = true -------------------------------------------------------------------------------- /src/secbench-processing/secbench/processing/crypto/__init__.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | from .aes import AES, AesOps, aes_nist_key 33 | from .keccak import Keccak_f 34 | from .pcg32 import Pcg32 35 | 36 | __all__ = ["Pcg32", "aes_nist_key", "AES", "AesOps", "Keccak_f"] -------------------------------------------------------------------------------- /doc/tutorials/configuration.md: -------------------------------------------------------------------------------- 1 | (sec:configuration)= 2 | 3 | # Configuration 4 | 5 | The behavior of several components (such as {py:class}`~secbench.api.Bench` can 6 | be changed at runtime thanks to either [toml](https://toml.io/en/) 7 | configuration files or environment variables. 8 | 9 | The environment variable `SECBENCH_USER_CONFIG` can point to a list of colon 10 | separated paths to `.toml` configuration files. The first entry in the 11 | environment takes configuration over the others. 12 | 13 | For example let's say you have: 14 | 15 | ```console 16 | $ export SECBENCH_USER_CONFIG="a.toml:/home/user_a/b.to_ml"` 17 | ``` 18 | Then, configuration values will be first in file "a.toml" 19 | 20 | ## Rules 21 | 22 | To summarize, for a given configuration key (e.g., `discovery.verbose`), the 23 | value will be searched in the following order: 24 | - Environment variable (if supported) 25 | - Entry `<>.discovery.verbose` in configuration files. 26 | - Entry `discovery.verbose` 27 | 28 | ## List of Supported Options 29 | 30 | In this section, we list the configuration options supported in *Secbench*. 31 | 32 | (tab:secbench-config)= 33 | 34 | :::{table} List of Secbench Configuration options 35 | | Configuration Key | Environment Variable | Description | 36 | |-------------------|----------------------|-------------| 37 | | | `SECBENCH_USER_CONFIG` | List of colon separated `.toml` files to load | 38 | | `discovery.verbose` | `SECBENCH_DISCOVERY_VERBOSE` | Makes the device discovery more verbose (default: "false") | 39 | | `scopenet` | `SECBENCH_SCOPENET` | IP address range where to look for scopes (e.g., "192.168.1.0/26") | 40 | | `scanners.vxi11.scan_timeout` | | Timeout in seconds applied for scanning devices through network (default: 0.01) | 41 | | `scanners.vxi11.scan_verbose` | | Lists devices found on the network during discovery | 42 | | `scanners.pyvisa.backend` | `SECBENCH_SCANNERS_PYVISA_BACKEND` | Which backend is used for `pyvisa` | 43 | ::: 44 | -------------------------------------------------------------------------------- /src/secbench-api/setup.cfg: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | [tool:pytest] 33 | junit_family = xunit1 34 | 35 | [flake8] 36 | max-line-length = 88 37 | per-file-ignores = 38 | secbench/api/__init__.py: F401 39 | extend-ignore = E203,E501 40 | 41 | [pytest] 42 | doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL 43 | 44 | [mypy] 45 | disable_error_code = import-untyped -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/simulation/__init__.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | """ 32 | This namespace provides simulators for common hardware. 33 | """ 34 | 35 | from .pulser import SimulatedPulser, SimulatedPulserChannel 36 | from .scope import SimulatedScope 37 | from .table import SimulatedTable 38 | 39 | __all__ = [ 40 | "SimulatedPulser", 41 | "SimulatedPulserChannel", 42 | "SimulatedScope", 43 | "SimulatedTable", 44 | ] -------------------------------------------------------------------------------- /src/secbench-picoscope/secbench/picoscope/__init__.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | from .ps2000a import PicoPS2000AScope 33 | from .ps3000a import PicoPS3000AScope 34 | from .ps6000 import PicoPS6000Scope 35 | 36 | 37 | def version() -> str: 38 | """ 39 | Current version of the :py:mod:`secbench.picoscope` package 40 | """ 41 | from importlib.metadata import distribution 42 | 43 | return distribution("secbench-picoscope").version 44 | 45 | 46 | __all__ = ["version", "PicoPS2000AScope", "PicoPS3000AScope", "PicoPS6000Scope"] -------------------------------------------------------------------------------- /src/secbench-native/crates/secbench_crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright CEA (Commissariat à l'énergie atomique et aux 2 | // énergies alternatives) (2017-2025) 3 | // 4 | // This software is governed by the CeCILL license under French law and 5 | // abiding by the rules of distribution of free software. You can use, 6 | // modify and/ or redistribute the software under the terms of the CeCILL 7 | // license as circulated by CEA, CNRS and INRIA at the following URL 8 | // "http://www.cecill.info". 9 | // 10 | // As a counterpart to the access to the source code and rights to copy, 11 | // modify and redistribute granted by the license, users are provided only 12 | // with a limited warranty and the software's author, the holder of the 13 | // economic rights, and the successive licensors have only limited 14 | // liability. 15 | // 16 | // In this respect, the user's attention is drawn to the risks associated 17 | // with loading, using, modifying and/or developing or reproducing the 18 | // software by the user in light of its specific status of free software, 19 | // that may mean that it is complicated to manipulate, and that also 20 | // therefore means that it is reserved for developers and experienced 21 | // professionals having in-depth computer knowledge. Users are therefore 22 | // encouraged to load and test the software's suitability as regards their 23 | // requirements in conditions enabling the security of their systems and/or 24 | // data to be ensured and, more generally, to use and operate it in the 25 | // same conditions as regards security. 26 | // 27 | // The fact that you are presently reading this means that you have had 28 | // knowledge of the CeCILL license and that you accept its terms. 29 | 30 | //! Reproducible and stable models of cryptographic primitives. 31 | //! 32 | //! This module includes: 33 | //! - Pseudo Random Number Generators (PRNG) 34 | //! - Ciphers 35 | //! 36 | //! **Caution note**: These implementations are not indented for production use, 37 | //! only for simulation of RNG outputs. Please, use real-world proof 38 | //! cryptographic libraries (e.g., OpenSSL) for production systems. 39 | 40 | mod pcg32; 41 | 42 | pub use pcg32::{Pcg32, Pcg32Seed}; -------------------------------------------------------------------------------- /src/secbench-native/crates/secbench_dsp/Cargo.toml: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | 30 | [package] 31 | name = "secbench_dsp" 32 | version.workspace = true 33 | edition.workspace = true 34 | 35 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 36 | 37 | [dependencies] 38 | num-traits.workspace = true 39 | tracing.workspace = true 40 | ndarray = { workspace = true, features = ["rayon", "approx"] } 41 | realfft.workspace = true 42 | rayon.workspace = true 43 | itertools.workspace = true 44 | rand.workspace = true 45 | 46 | [dev-dependencies] 47 | ndarray-npy.workspace = true -------------------------------------------------------------------------------- /src/secbench-picoscope/secbench/picoscope/types.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | from dataclasses import dataclass 33 | 34 | from secbench.api.enums import Coupling 35 | 36 | 37 | @dataclass 38 | class ChannelState: 39 | enabled: bool 40 | range: float 41 | offset: float 42 | max_voltage: float 43 | coupling: Coupling = Coupling.dc 44 | 45 | 46 | @dataclass 47 | class TimebaseInfo: 48 | timebase_id: int 49 | time_interval: float 50 | time_units: str 51 | max_samples: int 52 | segment_id: int 53 | 54 | 55 | @dataclass 56 | class VerticalRange: 57 | volts: float 58 | api_code: int 59 | user_str: str = "" -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/backend/__init__.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | # flake8: noqa 33 | 34 | from .pyvisa import PyVisaBackend, PyVisaDiscoverableMixin 35 | from .serial import SerialBackend, SerialDiscoverableMixin 36 | from .types import Backend 37 | from .usbtmc import USBTMCBackend, USBTMCDiscoverableMixin 38 | from .vxi11 import VXIBackend, VXIDiscoverableMixin 39 | 40 | __all__ = [ 41 | "Backend", 42 | "PyVisaBackend", 43 | "PyVisaDiscoverableMixin", 44 | "SerialBackend", 45 | "SerialDiscoverableMixin", 46 | "USBTMCBackend", 47 | "USBTMCDiscoverableMixin", 48 | "VXIBackend", 49 | "VXIDiscoverableMixin", 50 | ] -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/types.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | from __future__ import annotations 32 | 33 | from dataclasses import dataclass 34 | from typing import Union 35 | 36 | from typing_extensions import TypeAlias 37 | 38 | JSON: TypeAlias = Union[dict[str, "JSON"], list["JSON"], str, int, float, bool, None] 39 | 40 | 41 | @dataclass 42 | class Location: 43 | x: float 44 | y: float 45 | z: float 46 | 47 | def get_xyz(self): 48 | """ 49 | Return x, y, z coordinates as a 3-tuple. 50 | """ 51 | return self.x, self.y, self.z 52 | 53 | def get_xy(self): 54 | """ 55 | Return x, y as a 2-tuple. 56 | """ 57 | return self.x, self.y -------------------------------------------------------------------------------- /src/secbench-native/crates/secbench_dsp/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright CEA (Commissariat à l'énergie atomique et aux 2 | // énergies alternatives) (2017-2025) 3 | // 4 | // This software is governed by the CeCILL license under French law and 5 | // abiding by the rules of distribution of free software. You can use, 6 | // modify and/ or redistribute the software under the terms of the CeCILL 7 | // license as circulated by CEA, CNRS and INRIA at the following URL 8 | // "http://www.cecill.info". 9 | // 10 | // As a counterpart to the access to the source code and rights to copy, 11 | // modify and redistribute granted by the license, users are provided only 12 | // with a limited warranty and the software's author, the holder of the 13 | // economic rights, and the successive licensors have only limited 14 | // liability. 15 | // 16 | // In this respect, the user's attention is drawn to the risks associated 17 | // with loading, using, modifying and/or developing or reproducing the 18 | // software by the user in light of its specific status of free software, 19 | // that may mean that it is complicated to manipulate, and that also 20 | // therefore means that it is reserved for developers and experienced 21 | // professionals having in-depth computer knowledge. Users are therefore 22 | // encouraged to load and test the software's suitability as regards their 23 | // requirements in conditions enabling the security of their systems and/or 24 | // data to be ensured and, more generally, to use and operate it in the 25 | // same conditions as regards security. 26 | // 27 | // The fact that you are presently reading this means that you have had 28 | // knowledge of the CeCILL license and that you accept its terms. 29 | 30 | //! # Secbench signal processing tools 31 | //! 32 | //! This crate contains optimized implementation of signal processing tools. The functions 33 | //! available are tune for use in a side-channel analysis context. 34 | //! 35 | //! ## Feature flags 36 | //! 37 | //! By default, both `ndarray` and `batching` are enabled. 38 | //! - `ndarray`: Enable supports for the `ndarray` crate. 39 | //! - `batching`: Enable support for parallel processing of signals. Also enables `ndarray`. 40 | //! 41 | 42 | pub mod fft; 43 | pub mod multi_condmean; 44 | pub mod sliding; 45 | mod traits; 46 | 47 | pub use traits::{DspFloat, IntoFloat, Transform1D, Transform2D}; 48 | 49 | pub use multi_condmean::{CondMeanVar, CondMeanVarP}; -------------------------------------------------------------------------------- /src/secbench-processing/tests/test_pcg32.py: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | 30 | import numpy as np 31 | import pytest 32 | 33 | from secbench.processing import secbench_native_installed 34 | from secbench.processing.crypto import Pcg32 35 | 36 | secbench_ffi_testcase = pytest.mark.skipif( 37 | not secbench_native_installed(), reason="secbench_ffi package is not installed" 38 | ) 39 | 40 | 41 | @secbench_ffi_testcase 42 | @pytest.mark.parametrize("state", [10, 24, 0xDEADAAA]) 43 | @pytest.mark.parametrize("inc", [98, 111, 3]) 44 | def test_pcg32(state, inc): 45 | rng = Pcg32(state, inc) 46 | samples = np.array([rng.generate() for _ in range(10)], dtype=np.uint64) 47 | 48 | rng_2 = Pcg32(state, inc) 49 | dst = np.zeros(10, dtype=np.uint64) 50 | rng_2.fill(dst) 51 | np.testing.assert_equal(samples, dst) -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/simulation/table.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | import logging 32 | 33 | from ..instrument import Table 34 | from ..types import Location 35 | 36 | logger = logging.getLogger(__name__) 37 | 38 | 39 | class SimulatedTable(Table): 40 | _MOVE_DELAY_DEFAULT = 0 41 | 42 | def __init__(self): 43 | super().__init__() 44 | self._location = None 45 | self._x = 0 46 | self._y = 0 47 | self._z = 0 48 | 49 | def move_absolute(self, x=None, y=None, z=None): 50 | logger.debug(f"moving to ({x}, {y}, {z})") 51 | if x: 52 | self._x = x 53 | if y: 54 | self._y = y 55 | if z: 56 | self._z = z 57 | 58 | def location(self) -> Location: 59 | return Location(self._x, self._y, self._z) 60 | 61 | def location_absolute(self) -> Location: 62 | return self.location() -------------------------------------------------------------------------------- /src/secbench-processing/secbench/processing/__init__.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | """ 33 | This package contains algorithms for side-channel analysis. 34 | """ 35 | 36 | from .helpers import ( 37 | InvalidInputError, 38 | ) 39 | 40 | 41 | def version() -> str: 42 | """ 43 | Current version of the :py:mod:`secbench.processing` package 44 | """ 45 | from importlib.metadata import distribution 46 | 47 | return distribution("secbench-processing").version 48 | 49 | 50 | def secbench_native_installed() -> bool: 51 | """ 52 | Return true if the :py:mod:`secbench_native` package is installed. 53 | """ 54 | try: 55 | import secbench_native 56 | 57 | _ = secbench_native.version() 58 | except ImportError: 59 | return False 60 | return True 61 | 62 | 63 | __all__ = [ 64 | "version", 65 | "secbench_native_installed", 66 | "InvalidInputError", 67 | ] -------------------------------------------------------------------------------- /src/secbench-native/crates/secbench_processing/src/crypto.rs: -------------------------------------------------------------------------------- 1 | // Copyright CEA (Commissariat à l'énergie atomique et aux 2 | // énergies alternatives) (2017-2025) 3 | // 4 | // This software is governed by the CeCILL license under French law and 5 | // abiding by the rules of distribution of free software. You can use, 6 | // modify and/ or redistribute the software under the terms of the CeCILL 7 | // license as circulated by CEA, CNRS and INRIA at the following URL 8 | // "http://www.cecill.info". 9 | // 10 | // As a counterpart to the access to the source code and rights to copy, 11 | // modify and redistribute granted by the license, users are provided only 12 | // with a limited warranty and the software's author, the holder of the 13 | // economic rights, and the successive licensors have only limited 14 | // liability. 15 | // 16 | // In this respect, the user's attention is drawn to the risks associated 17 | // with loading, using, modifying and/or developing or reproducing the 18 | // software by the user in light of its specific status of free software, 19 | // that may mean that it is complicated to manipulate, and that also 20 | // therefore means that it is reserved for developers and experienced 21 | // professionals having in-depth computer knowledge. Users are therefore 22 | // encouraged to load and test the software's suitability as regards their 23 | // requirements in conditions enabling the security of their systems and/or 24 | // data to be ensured and, more generally, to use and operate it in the 25 | // same conditions as regards security. 26 | // 27 | // The fact that you are presently reading this means that you have had 28 | // knowledge of the CeCILL license and that you accept its terms. 29 | 30 | use numpy::{PyArray1, PyArrayMethods}; 31 | use pyo3::prelude::*; 32 | 33 | use secbench_crypto as sb; 34 | 35 | #[pyclass] 36 | #[derive(Clone)] 37 | pub struct Pcg32 { 38 | inner: sb::Pcg32, 39 | } 40 | 41 | #[pymethods] 42 | impl Pcg32 { 43 | #[new] 44 | pub fn new(state: u64, inc: u64) -> PyResult { 45 | let seed = sb::Pcg32Seed::from_state_inc(state, inc); 46 | Ok(Pcg32 { 47 | inner: sb::Pcg32::new(seed), 48 | }) 49 | } 50 | 51 | pub fn generate(&mut self) -> PyResult { 52 | Ok(self.inner.generate()) 53 | } 54 | 55 | pub fn fill(&mut self, dst: &Bound>) -> PyResult<()> { 56 | let mut dst_view = unsafe { dst.as_array_mut() }; 57 | dst_view.iter_mut().for_each(|x| *x = self.inner.generate()); 58 | Ok(()) 59 | } 60 | } -------------------------------------------------------------------------------- /src/secbench-picoscope/secbench/picoscope/helpers.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | import ctypes 33 | from enum import Enum 34 | 35 | from .error import pico_check 36 | 37 | 38 | def make_enum(name, fields): 39 | mappings = {} 40 | for i, f in enumerate(fields): 41 | mappings[i] = f 42 | return Enum(name, mappings) 43 | 44 | 45 | def pico_enumerate_serial(ps_enumerate_handle): 46 | from .error import PicoscopeApiError 47 | 48 | try: 49 | count = ctypes.c_int16(0) 50 | serial_len = ctypes.c_int16(4096) 51 | serial_buff = (ctypes.c_int8 * serial_len.value)() 52 | pico_check( 53 | ps_enumerate_handle( 54 | ctypes.byref(count), serial_buff, ctypes.byref(serial_len) 55 | ) 56 | ) 57 | 58 | serial_ids = bytes(serial_buff[: serial_len.value - 1]).decode() 59 | for serial_num in serial_ids.split(","): 60 | yield (serial_num,) 61 | except PicoscopeApiError: 62 | pass -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/_utils.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | from typing import Type 32 | 33 | 34 | def leaf_subclasses(base_class: Type, exclude_base_class: bool = True) -> set[Type]: 35 | """ 36 | Recursively find all leaf subclasses of a given base class. 37 | 38 | This function explores the subclass hierarchy starting from the given 39 | ``base_class`` and collects all leaf subclasses (i.e., subclasses that do not 40 | have any further subclasses). 41 | 42 | :param base_class: The base class from which to start the exploration. 43 | :param exclude_base_class: If True, the base class itself will be excluded from the result set. 44 | Default is True. 45 | 46 | :returns: A set containing all leaf subclasses of the given base class. 47 | """ 48 | found = set() 49 | 50 | def explore(cls): 51 | if cls in found: 52 | return 53 | subs = cls.__subclasses__() 54 | if subs: 55 | for sub in subs: 56 | explore(sub) 57 | else: 58 | found.add(cls) 59 | 60 | explore(base_class) 61 | if exclude_base_class: 62 | found -= {base_class} 63 | return found -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/instrument/__init__.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | from .afg import Afg, AfgChannel 33 | from .features import HasScreenShot, HasSetupStorage, HasWaveformStorage 34 | from .psu import PowerSupply, PowerSupplyChannel 35 | from .pulser import ( 36 | EMPulseParams, 37 | EMPulser, 38 | GlitchParams, 39 | LaserParams, 40 | LaserPulser, 41 | Pulser, 42 | PulserChannel, 43 | VGlitchPulser, 44 | ) 45 | from .scope import Scope, ScopeAnalogChannel 46 | from .table import Table 47 | from .types import InstrumentMixin, QueryWriteInstrument, RawInstrument, WriteManyMixin 48 | 49 | __all__ = [ 50 | "Afg", 51 | "AfgChannel", 52 | "HasScreenShot", 53 | "HasSetupStorage", 54 | "HasWaveformStorage", 55 | "InstrumentMixin", 56 | "PowerSupply", 57 | "PowerSupplyChannel", 58 | "Pulser", 59 | "PulserChannel", 60 | "QueryWriteInstrument", 61 | "RawInstrument", 62 | "EMPulseParams", 63 | "EMPulser", 64 | "LaserParams", 65 | "GlitchParams", 66 | "EMPulser", 67 | "LaserPulser", 68 | "VGlitchPulser", 69 | "Scope", 70 | "ScopeAnalogChannel", 71 | "Table", 72 | "WriteManyMixin", 73 | ] -------------------------------------------------------------------------------- /doc/installation.md: -------------------------------------------------------------------------------- 1 | (sec:installation)= 2 | 3 | # Installation 4 | 5 | For users that want to use *Secbench* in their project, the *Secbench* Python 6 | packages can be installed through `pip`: 7 | 8 | ```console 9 | $ pip install secbench-api secbench-storage secbench-picoscope secbench-native secbench-processing 10 | ``` 11 | 12 | You can install packages individually if you do not need all modules. 13 | 14 | The minimum Python version supported is 3.10 (some packages may work on older Python versions, but are not tested anymore). 15 | 16 | ```{note} 17 | *Secbench* is mainly used on Linux. However, since the packages are 18 | pure-Python, they should work on other OSes. 19 | ``` 20 | 21 | If you plan to use Picoscope oscilloscope, they are some additional setup to be 22 | performed, as explained in {py:mod}`secbench.picoscope` module documentation. 23 | 24 | ## Developers 25 | 26 | ### Secbench SDK installation 27 | 28 | For people that want to develop *Secbench*, build the documentation or try the 29 | example notebooks, we have a script (for Linux) that creates a Python virtual 30 | environment using [miniforge](https://github.com/conda-forge/miniforge), and 31 | install all packages in development mode and some extra dependencies. 32 | This installation method has little pre-requisites and should work out of the box. 33 | 34 | First, clone the repository: 35 | 36 | ```console 37 | $ git clone https://github.com/CEA-Leti/secbench.git 38 | ``` 39 | 40 | Run the installation script. 41 | 42 | ```{warning} 43 | The following command-line will install the Secbench SDK in the directory `~/tools/secbench_sdk`. 44 | Feel free to use another directory on your computer (it will be created if the directory does not exists). 45 | ``` 46 | 47 | ```console 48 | $ ./sdk/setup.sh -p ~/tools/secbench_sdk 49 | ``` 50 | 51 | ```{note} 52 | It is safe to re-run the previous command line, it will update packages. 53 | ``` 54 | 55 | Then, you will need to activate the environment to set the environment variables: 56 | ```console 57 | source ~/tools/secbench_sdk/activate 58 | ``` 59 | 60 | ### Installation in a Python virtual environment 61 | 62 | It is also possible to install packages in development mode in an existing Python 63 | [virtual environment](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#create-and-use-virtual-environments). 64 | 65 | If you do not have a virtual environment, create it (here we use the directory `.venv`, feel free to change it): 66 | 67 | ```console 68 | $ python3 -m venv .venv 69 | $ ./.venv/bin/pip install --upgrade pip 70 | ``` 71 | 72 | To install Secbench packages in the environment, simply run: 73 | 74 | ```console 75 | $ pip install -e ./src/secbench-api -e ./src/secbench-storage -e ./src/secbench-picoscope -e ./src/secbench-processing -e ./src/secbench-native 76 | ``` 77 | -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/backend/types.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | import abc 33 | 34 | 35 | class Backend(abc.ABC): 36 | """ 37 | Interface of a communication backend for SCPI instruments. 38 | """ 39 | 40 | def set_timeout(self, secs: float) -> None: 41 | """ 42 | Set timeout for blocking operations. (optional) 43 | """ 44 | return 45 | 46 | def flush(self) -> None: 47 | """ 48 | Ensure all pending commands were sent to the instrument. 49 | """ 50 | return 51 | 52 | @abc.abstractmethod 53 | def close(self) -> None: 54 | """ 55 | Force closing of the backend. 56 | """ 57 | pass 58 | 59 | @abc.abstractmethod 60 | def write(self, cmds: str) -> None: 61 | pass 62 | 63 | @abc.abstractmethod 64 | def query(self, cmds: str) -> str: 65 | """ 66 | Perform a query. 67 | 68 | Return a stripped string. 69 | """ 70 | pass 71 | 72 | @abc.abstractmethod 73 | def query_raw(self, cmds: str, size: int) -> bytes: 74 | """ 75 | Perform a device query. 76 | 77 | Return the data returned by the device "as this". 78 | """ 79 | pass -------------------------------------------------------------------------------- /src/secbench-native/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | 30 | [project] 31 | name = "secbench_native" 32 | version = "0.2.3" 33 | description = "Extension module containing Rust-accelerated side-channel processing tools" 34 | requires-python = ">=3.10" 35 | license = { file = "LICENSE" } 36 | authors = [ { name = "Secbench team" , email = "support@secbench.fr" } ] 37 | classifiers = [ 38 | "Programming Language :: Python :: 3", 39 | "Programming Language :: Python :: 3 :: Only", 40 | "Programming Language :: Python :: 3.10", 41 | "Programming Language :: Python :: 3.11", 42 | "Programming Language :: Python :: 3.12", 43 | "Programming Language :: Python :: 3.13", 44 | "Topic :: Security", 45 | "Topic :: Scientific/Engineering", 46 | "Intended Audience :: Developers", 47 | "Intended Audience :: Science/Research", 48 | "License :: OSI Approved :: CEA CNRS Inria Logiciel Libre License, version 2.1 (CeCILL-2.1)" 49 | ] 50 | [project.urls] 51 | "Homepage" = "https://doc.secbench.fr" 52 | "Bug Reports" = "https://github.com/CEA-Leti/secbench/issues" 53 | "Source" = "https://github.com/CEA-Leti/secbench" 54 | 55 | [build-system] 56 | requires = ["maturin>=1.0,<2.0"] 57 | build-backend = "maturin" 58 | 59 | [tool.maturin] 60 | features = ["pyo3/extension-module"] -------------------------------------------------------------------------------- /src/secbench-processing/secbench/processing/_network.py: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | 30 | from dataclasses import dataclass 31 | 32 | 33 | @dataclass 34 | class ConvLayerSpec: 35 | """ 36 | Specification of a convolution layer 37 | 38 | - kernel_count: the number filters in the convolution. 39 | - kernel_size: An integer or tuple/list of a single integer, specifying the length 40 | of the 1D convolution window. 41 | - activation: activation function used in the filter layers 42 | - pool_size: size of the average pooling windows. 43 | - pool_stride: factor by which to downscale. (e.g. 2 will halve the input). 44 | - dropout: dropout applied between the filters and the pooling (0 disables this layer) 45 | 46 | """ 47 | 48 | kernel_count: int = 10 49 | kernel_size: int = 25 50 | activation: str = "elu" 51 | pool_size: int = 20 52 | pool_stride: int = 5 53 | dropout: float = 0.2 54 | 55 | 56 | @dataclass 57 | class DenseLayerSpec: 58 | """ 59 | Specification of a dense layer. 60 | 61 | - size: number of output neurons 62 | - activation: activation function 63 | - dropout: dropout ration applied after the dense layer (0 disables this layer). 64 | 65 | """ 66 | 67 | size: int = 20 68 | activation: str = "elu" 69 | dropout: float = 0.2 -------------------------------------------------------------------------------- /src/secbench-storage/secbench/storage/__init__.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | """ 33 | The :py:mod:`secbench.storage` module provides persistent storage for 34 | side-channel analysis experimental data. 35 | """ 36 | 37 | from .dataset import Dataset, DatasetRef, Field 38 | from .store import OpenMode, Store, StoreBase, load_shared_dataset, shared_datasets 39 | 40 | __all__ = [ 41 | "Dataset", 42 | "DatasetRef", 43 | "Field", 44 | "load_shared_dataset", 45 | "OpenMode", 46 | "shared_datasets", 47 | "Store", 48 | "StoreBase", 49 | "version", 50 | ] 51 | 52 | 53 | def version() -> str: 54 | """ 55 | Current version of the module (as a string). 56 | """ 57 | from importlib.metadata import distribution 58 | 59 | return distribution("secbench-storage").version 60 | 61 | 62 | def _package_asset_content(name: str) -> str: 63 | """ 64 | Read asset from this package as an utf-8 string. 65 | 66 | This function is for internal use only. 67 | """ 68 | from importlib.resources import files 69 | 70 | return files("secbench.storage").joinpath(f"assets/{name}").read_text() 71 | 72 | 73 | def _package_has_asset(name: str) -> bool: 74 | """ 75 | Read asset from this package as an utf-8 string. 76 | 77 | This function is for internal use only. 78 | """ 79 | from importlib.resources import files 80 | 81 | return files("secbench.storage").joinpath(f"assets/{name}").is_file() -------------------------------------------------------------------------------- /sdk/patch_libudev.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | import importlib.util 32 | import re 33 | import sys 34 | from pathlib import Path 35 | 36 | 37 | def find_package_path(package_name): 38 | # Find the module spec for the package 39 | spec = importlib.util.find_spec(package_name) 40 | 41 | if spec is None: 42 | print(f"Package {package_name} not found.") 43 | return None 44 | 45 | # Get the path from the module spec 46 | package_path = spec.origin 47 | 48 | return Path(package_path) 49 | 50 | 51 | def eprint(*args, **kwargs): 52 | print(*args, file=sys.stderr, **kwargs) 53 | 54 | 55 | def main(): 56 | udev_path = find_package_path("pyudev") 57 | if udev_path is None: 58 | eprint("unable to find pyudev package location, leaving.") 59 | sys.exit(1) 60 | root = find_package_path("pyudev").parent 61 | core_file = root / "core.py" 62 | if not core_file.exists(): 63 | eprint("failed to find core.py file in pyudev, leaving.") 64 | sys.exit(1) 65 | content = core_file.read_text() 66 | replaced = re.sub( 67 | r'load_ctypes_library\("udev"', 'load_ctypes_library("libudev.so.1"', content 68 | ) 69 | if content != replaced: 70 | eprint(f"writing patched file to {core_file}.") 71 | core_file.write_text(replaced) 72 | else: 73 | eprint(f"file {core_file} is already patched.") 74 | 75 | 76 | if __name__ == "__main__": 77 | main() 78 | -------------------------------------------------------------------------------- /src/secbench-native/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright CEA (Commissariat à l'énergie atomique et aux 2 | // énergies alternatives) (2017-2025) 3 | // 4 | // This software is governed by the CeCILL license under French law and 5 | // abiding by the rules of distribution of free software. You can use, 6 | // modify and/ or redistribute the software under the terms of the CeCILL 7 | // license as circulated by CEA, CNRS and INRIA at the following URL 8 | // "http://www.cecill.info". 9 | // 10 | // As a counterpart to the access to the source code and rights to copy, 11 | // modify and redistribute granted by the license, users are provided only 12 | // with a limited warranty and the software's author, the holder of the 13 | // economic rights, and the successive licensors have only limited 14 | // liability. 15 | // 16 | // In this respect, the user's attention is drawn to the risks associated 17 | // with loading, using, modifying and/or developing or reproducing the 18 | // software by the user in light of its specific status of free software, 19 | // that may mean that it is complicated to manipulate, and that also 20 | // therefore means that it is reserved for developers and experienced 21 | // professionals having in-depth computer knowledge. Users are therefore 22 | // encouraged to load and test the software's suitability as regards their 23 | // requirements in conditions enabling the security of their systems and/or 24 | // data to be ensured and, more generally, to use and operate it in the 25 | // same conditions as regards security. 26 | // 27 | // The fact that you are presently reading this means that you have had 28 | // knowledge of the CeCILL license and that you accept its terms. 29 | 30 | use pyo3::prelude::*; 31 | 32 | #[pymodule] 33 | fn secbench_native(m: &Bound<'_, PyModule>) -> PyResult<()> { 34 | let register_submodule = |submodule: Bound<'_, PyModule>| -> PyResult<()> { 35 | m.add_submodule(&submodule)?; 36 | 37 | // HACK: Allows for importing only the submodule with `import secbench_native.something` 38 | m.py() 39 | .import_bound("sys")? 40 | .getattr("modules")? 41 | .set_item(format!("secbench_native.{}", submodule.name()?), submodule)?; 42 | Ok(()) 43 | }; 44 | 45 | // Meta stuff 46 | m.add_function(wrap_pyfunction!(version, m)?)?; 47 | m.add_function(wrap_pyfunction!(features, m)?)?; 48 | 49 | // Actual modules 50 | #[cfg(feature = "secbench_processing")] 51 | register_submodule(secbench_processing::make_secbench_processing(m.py())?)?; 52 | 53 | Ok(()) 54 | } 55 | 56 | #[pyfunction] 57 | fn version() -> (u32, u32, u32) { 58 | let major = env!("CARGO_PKG_VERSION_MAJOR").parse::().unwrap(); 59 | let minor = env!("CARGO_PKG_VERSION_MINOR").parse::().unwrap(); 60 | let patch = env!("CARGO_PKG_VERSION_PATCH").parse::().unwrap(); 61 | 62 | (major, minor, patch) 63 | } 64 | 65 | #[pyfunction] 66 | fn features() -> Vec { 67 | let mut features = Vec::new(); 68 | #[cfg(feature = "secbench_processing")] 69 | features.push("processing".into()); 70 | 71 | features 72 | } -------------------------------------------------------------------------------- /src/secbench-api/tests/test_core.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | import pytest 33 | 34 | from secbench.api import Bench 35 | from secbench.api.hooks import secbench_main 36 | 37 | 38 | def test_version(): 39 | # Check that version actually works 40 | from secbench.api import version 41 | 42 | assert version() is not None 43 | 44 | 45 | def success_hook(r): 46 | print(f"Success: {r}") 47 | 48 | 49 | def failure_hook(): 50 | print("Failed") 51 | 52 | 53 | @secbench_main(on_success=success_hook) 54 | def example_main(bench: Bench): 55 | """ 56 | Demonstrates how you can wrap a function with secbench_main 57 | """ 58 | assert isinstance(bench, Bench) 59 | return 3 60 | 61 | 62 | @secbench_main(on_failure=failure_hook, exit_on_failure=False) 63 | def example_main_fail(_bench: Bench): 64 | raise ValueError() 65 | 66 | 67 | def test_secbench_main(capsys): 68 | r = example_main() 69 | captured = capsys.readouterr() 70 | assert r == 3 71 | assert "Success: 3" in captured.out 72 | assert "Failed" not in captured.out 73 | 74 | with pytest.raises(ValueError): 75 | example_main_fail() 76 | captured = capsys.readouterr() 77 | assert "Failed" in captured.out 78 | 79 | 80 | def test_kwonly_dataclass_compat(): 81 | import sys 82 | 83 | from secbench.api.instrument.pulser import EMPulseParams 84 | 85 | if sys.version_info < (3, 10): 86 | _ = EMPulseParams(10, 2, 3, 3) 87 | else: 88 | # kw_only must be enabled for python>3.10 89 | with pytest.raises(TypeError): 90 | _ = EMPulseParams(10, 2, 3, 3) 91 | 92 | _ = EMPulseParams(delay_ns=10, width_ns=3, rise_time_ns=1, amplitude=10) -------------------------------------------------------------------------------- /src/secbench-storage/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | ### 30 | 31 | [project] 32 | name = "secbench-storage" 33 | version = "3.7.1" 34 | description = "Trace storage format based on HDF5 developped by CEA" 35 | authors = [ { name = "Secbench team" , email = "support@secbench.fr" } ] 36 | readme = "README.md" 37 | license = { file = "LICENSE" } 38 | requires-python = ">= 3.9" 39 | dependencies = [ 40 | "numpy>=1.18", 41 | "asciitree>=0.3", 42 | "h5py>=3.6", 43 | "tabulate>=0.9", 44 | "click>=8.0", 45 | ] 46 | classifiers = [ 47 | "Programming Language :: Python :: 3", 48 | "Programming Language :: Python :: 3 :: Only", 49 | "Programming Language :: Python :: 3.10", 50 | "Programming Language :: Python :: 3.11", 51 | "Programming Language :: Python :: 3.12", 52 | "Programming Language :: Python :: 3.13", 53 | "Topic :: Security", 54 | "Topic :: Scientific/Engineering", 55 | "Intended Audience :: Developers", 56 | "Intended Audience :: Science/Research", 57 | "License :: OSI Approved :: CEA CNRS Inria Logiciel Libre License, version 2.1 (CeCILL-2.1)" 58 | ] 59 | 60 | [project.urls] 61 | "Homepage" = "https://doc.secbench.fr" 62 | "Bug Reports" = "https://github.com/CEA-Leti/secbench/issues" 63 | "Source" = "https://github.com/CEA-Leti/secbench" 64 | 65 | [project.scripts] 66 | secbench-db = "secbench.storage.__main__:cli" 67 | 68 | [tool.pytest] 69 | junit_family = "xunit1" 70 | addopts = "--doctest-modules" 71 | doctest_optionflags = "NORMALIZE_WHITESPACE ELLIPSIS" 72 | 73 | [tool.mypy] 74 | ignore_missing_imports = true 75 | plugins = "numpy.typing.mypy_plugin" 76 | 77 | [build-system] 78 | requires = ["setuptools >= 61.0"] 79 | build-backend = "setuptools.build_meta" -------------------------------------------------------------------------------- /PUBLICATIONS.md: -------------------------------------------------------------------------------- 1 | # List of research work using secbench 2 | 3 | Here is a non-exhaustive list of research work at CEA in which the Secbench framework was used. 4 | If you need, [PUBLICATIONS.bib](./PUBLICATIONS.bib) contains the raw bibtex entries. 5 | 6 | - V. Cristiani, M. Lecomte, and T. Hiscock, “A Bit-Level Approach to Side Channel Based Disassembling,” in International Conference on Smart Card Research and Advanced Applications, Springer, 2019, pp. 143–158. 7 | - G. Goy, A. Loiseau, and P. Gaborit, “A new key recovery side-channel attack on HQC with chosen ciphertext,” in International Conference on Post-Quantum Cryptography, Springer, 2022, pp. 353–371. 8 | - J. Maillard, T. Hiscock, M. Lecomte, and C. Clavier, “Cache Side-Channel Attacks Through Electromagnetic Emanations of DRAM Accesses,” in Proceedings of the 21st International Conference on Security and Cryptography - SECRYPT, SciTePress, 2024, pp. 262–273. doi: 10.5220/0012813200003767. 9 | - G. Goy, A. Loiseau, and P. Gaborit, “Estimating the strength of horizontal correlation attacks in the hamming weight leakage model: A side-channel analysis on HQC KEM,” in WCC 2022: The Twelfth International Workshop on Coding and Cryptography, 2022, p. WCC 2022 paper 48. 10 | - V. Cristiani, M. Lecomte, T. Hiscock, and P. Maurine, “Fit the joint moments: how to attack any masking scheme,” IEEE Access, vol. 10, pp. 127412–127427, 2022. 11 | - S. Boussam and N. C. Albillos, “Keep It Unsupervised: Horizontal Attacks Meet Simple Classifiers,” in International Conference on Smart Card Research and Advanced Applications, Springer, 2023, pp. 213–234. 12 | - V. Cristiani, M. Lecomte, and P. Maurine, “Leakage assessment through neural estimation of the mutual information,” in Applied Cryptography and Network Security Workshops: ACNS 2020 Satellite Workshops, AIBlock, AIHWS, AIoTS, Cloud S&P, SCI, SecMT , and SiMLA, Rome, Italy, October 19–22, 2020, Proceedings 18, Springer, 2020, pp. 144–162. 13 | - C. Baisse et al., “Secret and Shared Keys Recovery on Hamming Quasi-Cyclic with SASCA,” Cryptology ePrint Archive, 2024. 14 | - J. Maillard, T. Hiscock, M. Lecomte, and C. Clavier, “Side-channel disassembly on a system-on-chip: A practical feasibility study,” Microprocessors and Microsystems, vol. 101, p. 104904, 2023. 15 | - J. Maillard, T. Hiscock, M. Lecomte, and C. Clavier, “Simulating SASCA on Keccak: Security Implications for Post-Quantum Cryptographic Schemes,” in Proceedings of the 21st International Conference on Security and Cryptography - SECRYPT, SciTePress, 2024, pp. 518–527. doi: 10.5220/0012787200003767. 16 | - G. Goy, J. Maillard, P. Gaborit, and A. Loiseau, “Single trace HQC shared key recovery with SASCA,” IACR Transactions on Cryptographic Hardware and Embedded Systems, vol. 2024, no. 2, pp. 64–87, 2024. 17 | - J. Godard, N. Aragon, P. Gaborit, A. Loiseau, and J. Maillard, “Single Trace Side-Channel Attack on the MPC-in-the-Head Framework,” Cryptology ePrint Archive, 2024. 18 | - A. Loiseau, M. Lecomte, and J. J. Fournier, “Template Attacks against ECC: practical implementation against Curve25519,” in 2020 IEEE International Symposium on Hardware Oriented Security and Trust (HOST), IEEE, 2020, pp. 13–22. 19 | - V. Cristiani, M. Lecomte, and P. Maurine, “The EVIL Machine: Encode, Visualize and Interpret the Leakage,” in Proceedings of the 38th ACM/SIGAPP Symposium on Applied Computing, 2023, pp. 1566–1575. 20 | - J. Maillard, T. Hiscock, M. Lecomte, and C. Clavier, “Towards Fine-grained Side-Channel Instruction Disassembly on a System-on-Chip,” in 2022 25th Euromicro Conference on Digital System Design (DSD), 2022, pp. 472–479. doi: 10.1109/DSD57027.2022.00069. 21 | 22 | -------------------------------------------------------------------------------- /src/secbench-picoscope/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | ### 30 | 31 | [project] 32 | name = "secbench-picoscope" 33 | version = "0.4.0" 34 | description = "Drivers for Picoscope devices, compliant with secbench-api" 35 | authors = [ { name = "Secbench team" , email = "support@secbench.fr" } ] 36 | readme = "README.md" 37 | license = { file = "LICENSE" } 38 | requires-python = ">= 3.9" 39 | dependencies = [ 40 | "secbench-api>=1.7.1", 41 | "numpy>=1.18", 42 | ] 43 | classifiers = [ 44 | "Programming Language :: Python :: 3", 45 | "Programming Language :: Python :: 3 :: Only", 46 | "Programming Language :: Python :: 3.10", 47 | "Programming Language :: Python :: 3.11", 48 | "Programming Language :: Python :: 3.12", 49 | "Programming Language :: Python :: 3.13", 50 | "Topic :: Security", 51 | "Topic :: Scientific/Engineering", 52 | "Intended Audience :: Developers", 53 | "Intended Audience :: Science/Research", 54 | "License :: OSI Approved :: CEA CNRS Inria Logiciel Libre License, version 2.1 (CeCILL-2.1)" 55 | ] 56 | 57 | [project.urls] 58 | "Homepage" = "https://doc.secbench.fr" 59 | "Bug Reports" = "https://github.com/CEA-Leti/secbench/issues" 60 | "Source" = "https://github.com/CEA-Leti/secbench" 61 | 62 | [tool.ruff.lint] 63 | select = [ 64 | # pycodestyle 65 | "E", 66 | # Pyflakes 67 | "F", 68 | # pyupgrade 69 | # "UP", 70 | # flake8-bugbear 71 | "B", 72 | # flake8-simplify 73 | "SIM", 74 | # isort 75 | "I", 76 | ] 77 | ignore = [ 78 | "E501", # Line too long. 79 | "SIM108", # Use of ternary operator. 80 | "SIM102", # Nested if: we do not think this makes better code. 81 | "SIM103", # Return condition vs. if: we do not think this makes better code in all situations. 82 | "SIM105", # Use contextlib.supress instead of try/except: we do not think this makes better code. 83 | ] 84 | 85 | [build-system] 86 | requires = ["setuptools >= 61.0"] 87 | build-backend = "setuptools.build_meta" -------------------------------------------------------------------------------- /src/secbench-processing/tests/test_helpers.py: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | ### 30 | 31 | import numpy as np 32 | import pytest 33 | 34 | from secbench.processing.helpers import MissingPackageError, add_remove, rank_of 35 | 36 | 37 | def test_rank_of(): 38 | scores = np.arange(13) 39 | for i in range(13): 40 | assert rank_of(scores, i) == 12 - i 41 | assert rank_of(scores, i, randomize=False) == 12 - i 42 | 43 | scores = np.array([3.0, 8.0, 4.0, 5.0, 4.0, 4.0, 1.0]) 44 | ranks = set() 45 | for _ in range(100): 46 | r = rank_of(scores, 2) 47 | ranks.add(r) 48 | assert ranks == {2, 3, 4} 49 | 50 | 51 | def test_add_remove(): 52 | n_samples, n_features = 10, 100 53 | xs = np.random.random((n_samples, n_features)) 54 | try: 55 | xs_tr = add_remove(xs, ratio=0.1) 56 | except MissingPackageError: 57 | pytest.skip("numba must be installed to run this test") 58 | assert xs_tr.shape == xs.shape 59 | assert xs_tr.dtype == xs.dtype 60 | assert np.sum((xs - xs_tr) ** 2) > 10 61 | 62 | 63 | def test_encode_labels(): 64 | from secbench.processing.helpers import encode_labels 65 | 66 | labels = np.array([[4, 5, 6, 7, 4], [3, 6, 5, 3, 4]], dtype=np.uint8).T 67 | 68 | # 1D case 69 | ys_encoded = encode_labels(labels[:, 0]) 70 | assert ys_encoded.ndim == 1 71 | assert len(np.unique(ys_encoded)) == 4 72 | assert np.max(ys_encoded) == 3 73 | 74 | # 2D case, independent labels 75 | ys_encoded = encode_labels(labels) 76 | assert ys_encoded.shape == labels.shape 77 | assert ys_encoded.dtype == np.uint16 78 | assert len(np.unique(ys_encoded[:, 0])) == 4 79 | assert len(np.unique(ys_encoded[:, 1])) == 4 80 | assert np.max(ys_encoded) == 3 81 | 82 | # 2D case, not independent labels 83 | ys_encoded = encode_labels(labels, indep=False) 84 | assert ys_encoded.shape == labels.shape 85 | assert len(np.unique(ys_encoded.flatten())) == 5 86 | assert np.max(ys_encoded) == 4 -------------------------------------------------------------------------------- /sdk/activate.sh.in: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | # shellcheck shell=bash 33 | 34 | 35 | # **WARNING**: this script was generated automatically by sdk/setup.sh from secbench. 36 | # It is not intended to be modified directly. 37 | 38 | # A simple script to active the shared environment from anywhere. 39 | # To use it: source 40 | function _load_secbench_sdk() { 41 | local sdk_root=@@SECBENCH_SDK_ROOT@@ 42 | local env_name=@@SECBENCH_SDK_ENV_NAME@@ 43 | local conda_root="${sdk_root}/mambaforge" 44 | 45 | if [[ -n "${SECBENCH_SDK_ENABLED:-}" ]]; then 46 | printf "info: SDK already activated. Run \"unset SECBENCH_SDK_ENABLED\" to force reload\n" >&2 47 | return 1 48 | fi 49 | 50 | if [[ ! -d "${sdk_root}" ]]; then 51 | printf "error: variable sdk_root does not seems to point to a valid directory (value=\"%s\")\n" "${sdk_root}" >&2 52 | return 1 53 | fi 54 | 55 | # shellcheck source=/dev/null 56 | source "${conda_root}/etc/profile.d/conda.sh" 57 | conda activate "${env_name}" 58 | 59 | # Ensure ~/.config/secbench/config.toml is in SECBENCH_USER_CONFIG if the 60 | # file exists. 61 | local secbench_shared_config="${HOME}/.config/secbench/config.toml" 62 | if [[ -e "${secbench_shared_config}" ]]; then 63 | local user_config=${SECBENCH_USER_CONFIG:-""} 64 | 65 | IFS=':' read -r -a config_files <<< "${user_config}" 66 | if [[ " ${config_files[@]} " =~ " ${secbench_shared_config} " ]]; then 67 | printf "info: shared configuration \"${secbench_shared_config}\" is already in SECBENCH_USER_CONFIG\n" >&2 68 | else 69 | export SECBENCH_USER_CONFIG="${user_config}:${secbench_shared_config}" 70 | fi 71 | fi 72 | 73 | export SECBENCH_SDK_ENABLED="yes" 74 | } 75 | 76 | if _load_secbench_sdk; then 77 | printf "info: environment loaded successfully!\n" >&2 78 | else 79 | printf "error: environment activation failed :(\n" >&2 80 | fi 81 | -------------------------------------------------------------------------------- /src/secbench-api/tests/test_pulser.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | import pytest 33 | 34 | from secbench.api import Bench 35 | from secbench.api.enums import Slope, TriggerSource 36 | from secbench.api.instrument import EMPulser, HasSetupStorage, Pulser 37 | 38 | _BENCH = Bench() 39 | 40 | 41 | @pytest.fixture 42 | def bench(): 43 | return _BENCH 44 | 45 | 46 | def has_pulser() -> bool: 47 | return _BENCH.get(EMPulser, required=False) is not None 48 | 49 | 50 | pytestmark = pytest.mark.skipif(not has_pulser(), reason="no pulser available") 51 | 52 | 53 | @pytest.fixture 54 | def pulser(bench): 55 | pulser = bench.get(EMPulser) 56 | yield pulser 57 | pulser.disable() 58 | del pulser 59 | 60 | 61 | def test_getters_setters(pulser: Pulser): 62 | ch = pulser.default_channel() 63 | ch.setup(delay_ns=30) 64 | assert ch.params().delay_ns == pytest.approx(30) 65 | 66 | ch.setup(width_ns=10) 67 | assert ch.params().width_ns == pytest.approx(10) 68 | 69 | ch.setup(amplitude=50) 70 | assert ch.params().amplitude == pytest.approx(50) 71 | 72 | pulser.set_output_enabled(True) 73 | assert pulser.output_enabled() 74 | pulser.set_output_enabled(False) 75 | assert not pulser.output_enabled() 76 | 77 | pulser.setup_trigger(TriggerSource.external, Slope.rising) 78 | 79 | 80 | def test_save_recall(pulser: Pulser): 81 | if not isinstance(pulser, HasSetupStorage): 82 | pytest.skip("HasSetupStorage not supported for this pulser") 83 | ch = pulser.default_channel() 84 | ch.setup(delay_ns=100, width_ns=10, amplitude=50) 85 | slot = pulser.setup_slots()[0] 86 | pulser.setup_save(slot) 87 | 88 | ch.setup(delay_ns=0, width_ns=20) 89 | pulser.setup_load(slot) 90 | assert ch.params().delay_ns == pytest.approx(100) 91 | assert ch.params().width_ns == pytest.approx(10) 92 | # WARNING: this statement can fail on the NicMax, probably due to noise on 93 | # the board. 94 | assert ch.params().amplitude == pytest.approx(50) -------------------------------------------------------------------------------- /src/secbench-native/Cargo.toml: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | 30 | [workspace] 31 | members = [ 32 | "crates/secbench_processing", 33 | "crates/secbench_crypto", 34 | "crates/secbench_dsp", 35 | ] 36 | package.version = "0.2.3" 37 | package.edition = "2021" 38 | 39 | ## NOTE: Declare every dependency used here to avoid version conflicts 40 | 41 | [workspace.dependencies] 42 | # Python bindings stuff 43 | pyo3 = { version = "0.21", features = ["abi3-py38"] } 44 | numpy = "0.21" 45 | 46 | # Common rust stuff 47 | num = "0.4" 48 | num-traits = "0.2" 49 | rand = "0.8" 50 | rand_core = "0.6" 51 | # Threading stuff 52 | rayon = "1.10" 53 | 54 | # Logs 55 | tracing = { version = "0.1", features = ["release_max_level_info"] } 56 | tracing-subscriber = { version = "0.3", features = ["env-filter"] } 57 | 58 | # Number crunching stuff 59 | ndarray = "0.15" 60 | itertools = "0.13" 61 | realfft = "3.3" 62 | fftconvolve = "0.1.1" 63 | 64 | # Serialisation 65 | serde = { version = "1.0", features = ["derive"] } 66 | serde_json = "1.0" 67 | ndarray-npy = "0.8" 68 | # hdf5 = "0.8" 69 | # hdf5-sys = { version = "0.8", features = ["static"] } 70 | 71 | # Rust-only secbench packages 72 | secbench_crypto = { path = "crates/secbench_crypto" } 73 | secbench_dsp = { path = "crates/secbench_dsp" } 74 | 75 | [profile.dev] 76 | # Use slightly better optimizations. 77 | opt-level = 1 78 | 79 | [profile.release] 80 | # debug = true 81 | # debug-assertions = true 82 | lto = true 83 | codegen-units = 1 84 | 85 | ## Here starts the bindings parts 86 | # It optionally depends on the other crates so you can enable/disable them with a feature flag 87 | 88 | [package] 89 | name = "secbench_native" 90 | version.workspace = true 91 | edition.workspace = true 92 | 93 | [lib] 94 | crate-type = ["cdylib"] 95 | 96 | [features] 97 | default = [ 98 | "secbench_processing", 99 | ] 100 | 101 | [dependencies] 102 | pyo3.workspace = true 103 | secbench_processing = { path = "crates/secbench_processing", optional = true } -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/__init__.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | from .backend import Backend 33 | from .bench import ( 34 | Bench, 35 | HardwareInfo, 36 | LibUdevScanner, 37 | SerialDeviceEntry, 38 | SerialScanner, 39 | UsbCoreScanner, 40 | UsbDeviceEntry, 41 | UserConfig, 42 | VxiDeviceEntry, 43 | VxiScanner, 44 | get_bench, 45 | ) 46 | from .discovery import Discoverable, DiscoverPolicy, discover, discover_first 47 | from .instrument.features import HasScreenShot, HasSetupStorage, HasWaveformStorage 48 | from .instrument.types import ( 49 | InstrumentMixin, 50 | QueryWriteInstrument, 51 | RawInstrument, 52 | WriteManyMixin, 53 | ) 54 | from .types import Location 55 | 56 | # NOTE: we import the module ``secbench.instruments`` (if present) to 57 | # make hardware available by default. 58 | try: 59 | import secbench.instruments # noqa: F401 60 | except ImportError: 61 | pass 62 | 63 | # NOTE: we import the module ``secbench.picoscope`` (if present) to 64 | # make hardware available by default. 65 | try: 66 | import secbench.picoscope # noqa: F401 67 | except ImportError: 68 | pass 69 | 70 | 71 | def version() -> str: 72 | """ 73 | Current version of the :py:mod:`secbench.api` package 74 | """ 75 | from importlib.metadata import distribution 76 | 77 | return distribution("secbench-api").version 78 | 79 | 80 | __all__ = [ 81 | "Backend", 82 | "Bench", 83 | "DiscoverPolicy", 84 | "Discoverable", 85 | "discover", 86 | "discover_first", 87 | "Location", 88 | "get_bench", 89 | "HardwareInfo", 90 | "HasSetupStorage", 91 | "HasWaveformStorage", 92 | "HasScreenShot", 93 | "InstrumentMixin", 94 | "QueryWriteInstrument", 95 | "SerialDeviceEntry", 96 | "SerialScanner", 97 | "UserConfig", 98 | "UsbDeviceEntry", 99 | "RawInstrument", 100 | "LibUdevScanner", 101 | "UsbCoreScanner", 102 | "VxiDeviceEntry", 103 | "VxiScanner", 104 | "WriteManyMixin", 105 | "version", 106 | ] -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/simulation/pulser.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | from __future__ import annotations 32 | 33 | from typing import Any, Mapping, Sequence 34 | 35 | from ..enums import Slope, TriggerSource 36 | from ..instrument import Pulser, PulserChannel 37 | from ..instrument.pulser import EMPulseParams 38 | 39 | 40 | class SimulatedPulserChannel(PulserChannel[EMPulseParams]): 41 | def __init__(self, parent: SimulatedPulser, name: str): 42 | super().__init__() 43 | self._name = name 44 | self._parent = parent 45 | self._enabled = False 46 | self._params = EMPulseParams( 47 | delay_ns=0, amplitude=0, width_ns=5, rise_time_ns=5 48 | ) 49 | 50 | @property 51 | def parent(self): 52 | return self._parent 53 | 54 | @classmethod 55 | def param_type(cls): 56 | return EMPulseParams 57 | 58 | @property 59 | def name(self) -> str: 60 | return self._name 61 | 62 | def set_enabled(self, enabled: bool) -> None: 63 | self._enabled = enabled 64 | 65 | def enabled(self) -> bool: 66 | return self._enabled 67 | 68 | def setup(self, **kwargs): 69 | for k, v in kwargs.items(): 70 | setattr(self._params, k, v) 71 | 72 | def _query_param(self, name: str) -> Any: 73 | return getattr(self._params, name) 74 | 75 | 76 | class SimulatedPulser(Pulser): 77 | def __init__(self): 78 | self._output_enabled = False 79 | self._channels = {"A": SimulatedPulserChannel(self, "A")} 80 | 81 | @property 82 | def description(self) -> str: 83 | return "simulated pulser" 84 | 85 | def channels(self) -> Mapping[str, PulserChannel[Any]]: 86 | return self._channels 87 | 88 | def _clear(self, pop_errors: bool) -> Sequence[str]: 89 | return [] 90 | 91 | def output_enabled(self) -> bool: 92 | return self._output_enabled 93 | 94 | def set_output_enabled(self, enabled: bool): 95 | self._output_enabled = enabled 96 | 97 | def setup_trigger( 98 | self, 99 | source: TriggerSource = TriggerSource.external, 100 | slope: Slope = Slope.rising, 101 | ): 102 | pass -------------------------------------------------------------------------------- /src/secbench-api/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | ### 30 | 31 | [project] 32 | name = "secbench-api" 33 | version = "1.8.0" 34 | description = "Common definition and interfaces used in the Secbench framework" 35 | authors = [ { name = "Secbench team" , email = "support@secbench.fr" } ] 36 | license = { file = "LICENSE" } 37 | readme = "README.md" 38 | requires-python = ">=3.8" 39 | dependencies = [ 40 | "pyserial>=3.5", 41 | "pyusb>=1.2; sys_platform=='linux' or sys_platform=='darwin'", 42 | "PyVISA>=1.11", 43 | "numpy>=1.20", 44 | "python-vxi11>=0.9", 45 | "pyudev>=0.24; sys_platform=='linux'", 46 | "toml>=0.10; python_version<'3.11'", 47 | "typing-extensions>=4.0.0", 48 | ] 49 | classifiers = [ 50 | "Programming Language :: Python :: 3", 51 | "Programming Language :: Python :: 3 :: Only", 52 | "Programming Language :: Python :: 3.10", 53 | "Programming Language :: Python :: 3.11", 54 | "Programming Language :: Python :: 3.12", 55 | "Programming Language :: Python :: 3.13", 56 | "Topic :: Security", 57 | "Topic :: Scientific/Engineering", 58 | "Intended Audience :: Developers", 59 | "Intended Audience :: Science/Research", 60 | "License :: OSI Approved :: CEA CNRS Inria Logiciel Libre License, version 2.1 (CeCILL-2.1)" 61 | ] 62 | 63 | [project.urls] 64 | "Homepage" = "https://doc.secbench.fr" 65 | "Bug Reports" = "https://github.com/CEA-Leti/secbench/issues" 66 | "Source" = "https://github.com/CEA-Leti/secbench" 67 | 68 | [build-system] 69 | requires = ["setuptools >= 61.0"] 70 | build-backend = "setuptools.build_meta" 71 | 72 | [tool.pyright] 73 | include = ["secbench"] 74 | # typeCheckingMode = "strict" 75 | stubPath = "../../../typings" 76 | 77 | [tool.ruff.lint] 78 | select = [ 79 | # pycodestyle 80 | "E", 81 | # Pyflakes 82 | "F", 83 | # pyupgrade 84 | # "UP", 85 | # flake8-bugbear 86 | "B", 87 | # flake8-simplify 88 | "SIM", 89 | # isort 90 | "I", 91 | ] 92 | ignore = [ 93 | "E501", # Line too long. 94 | "SIM108", # Use of ternary operator. 95 | "SIM102", # Nested if: we do not think this makes better code. 96 | "SIM103", # Return condition vs. if: we do not think this makes better code in all situations. 97 | "SIM105", # Use contextlib.supress instead of try/except: we do not think this makes better code. 98 | ] -------------------------------------------------------------------------------- /src/secbench-native/crates/secbench_processing/src/errors.rs: -------------------------------------------------------------------------------- 1 | // Copyright CEA (Commissariat à l'énergie atomique et aux 2 | // énergies alternatives) (2017-2025) 3 | // 4 | // This software is governed by the CeCILL license under French law and 5 | // abiding by the rules of distribution of free software. You can use, 6 | // modify and/ or redistribute the software under the terms of the CeCILL 7 | // license as circulated by CEA, CNRS and INRIA at the following URL 8 | // "http://www.cecill.info". 9 | // 10 | // As a counterpart to the access to the source code and rights to copy, 11 | // modify and redistribute granted by the license, users are provided only 12 | // with a limited warranty and the software's author, the holder of the 13 | // economic rights, and the successive licensors have only limited 14 | // liability. 15 | // 16 | // In this respect, the user's attention is drawn to the risks associated 17 | // with loading, using, modifying and/or developing or reproducing the 18 | // software by the user in light of its specific status of free software, 19 | // that may mean that it is complicated to manipulate, and that also 20 | // therefore means that it is reserved for developers and experienced 21 | // professionals having in-depth computer knowledge. Users are therefore 22 | // encouraged to load and test the software's suitability as regards their 23 | // requirements in conditions enabling the security of their systems and/or 24 | // data to be ensured and, more generally, to use and operate it in the 25 | // same conditions as regards security. 26 | // 27 | // The fact that you are presently reading this means that you have had 28 | // knowledge of the CeCILL license and that you accept its terms. 29 | 30 | use pyo3::{exceptions::PyException, prelude::*}; 31 | 32 | pyo3::create_exception!(secbench_ffi, ShapeException, PyException, "Incorrect shape"); 33 | 34 | impl ShapeException { 35 | pub fn from_expected_shapes(expected: &[usize], got: &[usize]) -> PyErr { 36 | Self::new_err(format!("Expected shape {:?}, but got {:?}", expected, got)) 37 | } 38 | } 39 | 40 | /// Macro to assert that the given array matches a specific shape 41 | /// 42 | /// ## Usage 43 | /// 44 | /// To check if an array2 has the correct amount of columns (axis 1) but we don't care amount the 45 | /// amount of rows (axis 0): 46 | /// ```rust 47 | /// let data = Array2::zeros([10, 200]); 48 | /// assert_shape_match!([_, 200] => data); 49 | /// ``` 50 | #[macro_export] 51 | macro_rules! assert_shape_match { 52 | ([$($vals:tt)*] => $target:expr) => { 53 | let target = $target.shape(); 54 | if assert_shape_match!(@expand_check [target, 0] $($vals)*,) { 55 | return Err($crate::errors::ShapeException::from_expected_shapes(&assert_shape_match!(@expand_expected [target, 0, []] $($vals)*,), target)); 56 | } 57 | }; 58 | 59 | // Parse expected 60 | // if _ 61 | (@expand_expected [$target:expr, $i:expr, [$($expected:expr),*]] _, $($rest:tt)*) => { 62 | assert_shape_match!(@expand_expected [$target, $i+1, [$($expected,)* $target[$i]]] $($rest)*) 63 | }; 64 | // if value 65 | (@expand_expected [$target:expr, $i:expr, [$($expected:expr),*]] $val:expr, $($rest:tt)*) => { 66 | assert_shape_match!(@expand_expected [$target, $i+1, [$($expected,)* $val]] $($rest)*) 67 | }; 68 | // terminate recursion 69 | (@expand_expected [$t:expr, $i:expr, [$($expected:expr),*]]) => { 70 | [$($expected),*] 71 | }; 72 | 73 | // Emit if condition 74 | // Case for _ 75 | (@expand_check [$target:expr, $i:expr] _, $($rest:tt)*) => { 76 | assert_shape_match!(@expand_check [$target, $i+1] $($rest)*) 77 | }; 78 | // Case for expr 79 | (@expand_check [$target:expr, $i:expr] $val:expr, $($rest:tt)*) => { 80 | ($target[$i] != $val) || assert_shape_match!(@expand_check [$target, $i+1] $($rest)*) 81 | }; 82 | // terminal case 83 | (@expand_check [$t:expr, $i:expr]) => { false }; 84 | } -------------------------------------------------------------------------------- /src/secbench-processing/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | ### 30 | 31 | [project] 32 | name = "secbench-processing" 33 | version = "2.11.0" # <> 34 | description = "Secbench algorithms for side-channel analysis" 35 | authors = [ { name = "Secbench team" , email = "support@secbench.fr" } ] 36 | readme = "README.md" 37 | # Unsupported by nix :( 38 | # license-files = ["LICENSE"] 39 | license = { file = "LICENSE" } 40 | requires-python = ">= 3.10" 41 | dependencies = [ 42 | "numpy>=1.21", 43 | "scipy>=1.4.1", 44 | "scikit-learn>=1.0.2", 45 | # We make matplotlib and tensorflow optional dependencies because there are 46 | # very large and not always needed. 47 | # tensorflow = { version = "^2.3", optional = true } 48 | "lttbc>=0.2", 49 | "typing-extensions>=4.0.0", 50 | "pandas>=2.0", 51 | ] 52 | classifiers = [ 53 | "Programming Language :: Python :: 3", 54 | "Programming Language :: Python :: 3 :: Only", 55 | "Programming Language :: Python :: 3.10", 56 | "Programming Language :: Python :: 3.11", 57 | "Programming Language :: Python :: 3.12", 58 | "Programming Language :: Python :: 3.13", 59 | "Topic :: Security", 60 | "Topic :: Scientific/Engineering", 61 | "Intended Audience :: Developers", 62 | "Intended Audience :: Science/Research", 63 | "License :: OSI Approved :: CEA CNRS Inria Logiciel Libre License, version 2.1 (CeCILL-2.1)" 64 | ] 65 | 66 | [project.optional-dependencies] 67 | mpl = ["matplotlib>=3.5"] 68 | 69 | [project.urls] 70 | "Homepage" = "https://doc.secbench.fr" 71 | "Bug Reports" = "https://github.com/CEA-Leti/secbench/issues" 72 | "Source" = "https://github.com/CEA-Leti/secbench" 73 | 74 | [tool.setuptools.packages.find] 75 | where = ["."] 76 | exclude = ["assets"] 77 | 78 | [tool.ruff.lint] 79 | select = [ 80 | # pycodestyle 81 | "E", 82 | # Pyflakes 83 | "F", 84 | # pyupgrade 85 | # "UP", 86 | # flake8-bugbear 87 | "B", 88 | # flake8-simplify 89 | "SIM", 90 | # isort 91 | "I", 92 | ] 93 | ignore = [ 94 | "E501", # Line too long. 95 | "SIM108", # Use of ternary operator. 96 | "B006", # TODO: Fix those, we have lot of them... 97 | ] 98 | 99 | [build-system] 100 | requires = ["setuptools >= 61.0"] 101 | build-backend = "setuptools.build_meta" 102 | -------------------------------------------------------------------------------- /src/secbench-processing/tests/test_profiled.py: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | 30 | import numpy as np 31 | import pytest 32 | from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis 33 | from sklearn.model_selection import train_test_split 34 | 35 | from secbench.processing.crypto.aes import aes_sbox 36 | from secbench.processing.helpers import has_tensorflow 37 | from secbench.processing.models import ( 38 | hamming_weight, 39 | hamming_weight_leakage, 40 | ) 41 | from secbench.processing.profiled import ( 42 | ClassPCA, 43 | DenseLayerSpec, 44 | GenericNetworkBuilder, 45 | SklearnModel, 46 | ) 47 | 48 | tensorflow_tc = pytest.mark.skipif( 49 | not has_tensorflow(), reason="tensorflow not installed or not working" 50 | ) 51 | 52 | 53 | def run_aes_attack(key: int, model, **kwargs): 54 | n_traces = 100_000 55 | 56 | p = np.random.randint(0, 256, size=n_traces, dtype=np.uint8) 57 | 58 | y = aes_sbox(p ^ key) 59 | X = hamming_weight_leakage(y, n_leaking_samples=3, n_random_samples=3, noise=0.01) 60 | X_train, X_test, p_train, p_test = train_test_split(X, p, test_size=0.01) 61 | 62 | model.fit(X_train, p_train, secret=key, **kwargs) 63 | scores = model.key_scores(X_test, np.arange(256), p_test) 64 | return scores 65 | 66 | 67 | def aes_sbox_model(private, public): 68 | return hamming_weight(aes_sbox(private ^ public)) 69 | 70 | 71 | def test_class_pca(): 72 | n_samples = 5_000 73 | y = np.random.randint(0, 256, size=n_samples, dtype=np.uint8) 74 | X = np.random.random((n_samples, 3000)) 75 | Xt = ClassPCA(n_components=10).fit_transform(X, y) 76 | assert Xt.shape == (n_samples, 10) 77 | 78 | 79 | @pytest.mark.parametrize("key", [32, 66]) 80 | def test_profiled_qda(key): 81 | model = SklearnModel( 82 | QuadraticDiscriminantAnalysis(), target_variable_fn=aes_sbox_model 83 | ) 84 | scores = run_aes_attack(key, model) 85 | assert scores.shape == (256,) 86 | assert np.argmax(scores) == key 87 | 88 | 89 | @tensorflow_tc 90 | def test_profiled_mlp(): 91 | model = GenericNetworkBuilder( 92 | conv_layers=[], 93 | batch_normalization=False, 94 | dense_layers=[DenseLayerSpec(size=4, activation=None)], 95 | ).build(6, num_classes=9, target_variable_fn=aes_sbox_model) 96 | key = 0xAA 97 | scores = run_aes_attack(key, model) 98 | assert scores.shape == (256,) 99 | assert np.argmax(scores) == key -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/exceptions.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | """ 32 | Exceptions raised by the secbench module. 33 | """ 34 | 35 | 36 | class SecbenchError(Exception): 37 | """ 38 | Base exception for *secbench* related operations. 39 | """ 40 | 41 | pass 42 | 43 | 44 | class BackendError(SecbenchError): 45 | """ 46 | An error that occurred in a communication backend. 47 | """ 48 | 49 | def __init__(self, msg): 50 | super().__init__(msg) 51 | 52 | 53 | class NoSuchHardwareError(SecbenchError): 54 | """ 55 | Exception raised when no device of the requested hardware type is 56 | available. 57 | """ 58 | 59 | def __init__(self, hw_class: type, what=""): 60 | super().__init__(f"no hardware found for {hw_class.__name__}{what}") 61 | 62 | 63 | class MissingDependency(SecbenchError): 64 | """ 65 | A dependency (e.g., a Python package) is missing for using a feature. 66 | """ 67 | 68 | pass 69 | 70 | 71 | class InstrumentError(SecbenchError): 72 | """ 73 | Base exception for instrument-related operations. 74 | """ 75 | 76 | def __init__(self, msg): 77 | super().__init__(msg) 78 | 79 | 80 | class InstrumentPendingErrors(InstrumentError): 81 | def __init__(self, errors): 82 | self.errors = errors 83 | super().__init__( 84 | f"there are {len(errors)} pending errors on the instruments: {errors}" 85 | ) 86 | 87 | 88 | class InstrumentUnsupportedFeature(InstrumentError): 89 | def __init__(self, msg): 90 | super().__init__(f"operation not supported: {msg}") 91 | 92 | 93 | class UnsupportedFeature(SecbenchError): 94 | """ 95 | Exception raised when attempting to use a feature that is not supported. 96 | """ 97 | 98 | def __init__(self, pkg_name: type, usage=""): 99 | self.pkg_name = pkg_name 100 | self.usage = "" 101 | super().__init__(f"missing package {pkg_name}.") 102 | 103 | 104 | class InvalidParameter(InstrumentError): 105 | """ 106 | Invalid parameters requested to an instrument. 107 | """ 108 | 109 | pass 110 | 111 | 112 | class NoSuchChannelError(InstrumentError): 113 | """ 114 | Exception raised when accessing a channel that is not available on the 115 | instrument. 116 | """ 117 | 118 | def __init__(self, channel): 119 | super().__init__(f"no such channel: {channel}") -------------------------------------------------------------------------------- /src/secbench-api/tests/test_config.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | from secbench.api import UserConfig 32 | 33 | 34 | def test_config_query(tmp_path): 35 | """ 36 | Test of basic configuration queries. 37 | """ 38 | demo_cfg = """ 39 | [instrument.reset_chip] 40 | dev_0 = "0403:6015:XXXX,FTDI" 41 | 42 | [instrument.pulser] 43 | dev_0 = "0403:6001:YYYY,FTDI" 44 | 45 | [instrument.ftdi_cable] 46 | dev_0 = "0403:6001:ZZZZ,FTDI" 47 | dev_1 = "0403:6001:WWWW,FTDI" 48 | dev_2 = "0403:6001:AAAA,FTDI" 49 | dev_3 = "0403:6001:BBBB,FTDI" 50 | 51 | [instrument.thermal_sensor] 52 | sensor_1 = "0403:6015:UUUU,FTDI" 53 | 54 | [host.bench1] 55 | shortname = "bench1" 56 | scopenet = "192.168.0.0/27" 57 | axes = { x = "xxxx", y = "yyyy", z = "zzzz" } 58 | 59 | [host.bench2] 60 | shortname = "bench2" 61 | scopenet = "192.168.1.0/26" 62 | axes = { x = "xxxx.2", y = "yyyy.2", z = "zzzz.2" } 63 | """ 64 | cfg_path = tmp_path / "a.toml" 65 | cfg_path.write_text(demo_cfg) 66 | cfg = UserConfig() 67 | cfg.load(cfg_path) 68 | 69 | assert cfg.query("host", "bench1", "scopenet") == "192.168.0.0/27" 70 | assert cfg.query("host", "bench1", "axes", "y") == "yyyy" 71 | assert len(cfg.query("host")) == 2 72 | assert cfg.query("host", "bench2", "shortname") == "bench2" 73 | 74 | 75 | def test_user_config_override(tmp_path): 76 | """ 77 | Test of the option override logic. 78 | """ 79 | cfg_a = """ 80 | [host.demo_host.instrument] 81 | scopenet = "192.168.0.0/29" 82 | dut_tty = "/dev/usb1" 83 | 84 | [instrument] 85 | scopenet = "12.34.56.78.0/27" 86 | dut_tty = "/dev/usb0" 87 | """ 88 | cfg_a_path = tmp_path / "a.toml" 89 | cfg_a_path.write_text(cfg_a) 90 | 91 | cfg_b = """ 92 | [instrument] 93 | scopenet = "192.168.0.0/29" 94 | """ 95 | cfg_b_path = tmp_path / "b.toml" 96 | cfg_b_path.write_text(cfg_b) 97 | 98 | cfg = UserConfig() 99 | cfg.load([str(cfg_a_path), str(cfg_b_path)], hostname="demo_host") 100 | 101 | assert cfg.query("invalid") is None 102 | 103 | # cfg_b should have priority over cfg_a 104 | assert cfg.query("instrument", "scopenet") == "192.168.0.0/29" 105 | 106 | # Check that host override works 107 | assert cfg.query("instrument", "dut_tty") == "/dev/usb1" 108 | assert cfg.query("instrument", "dut_tty", host_override=False) == "/dev/usb0" -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/instrument/psu.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | import abc 33 | from typing import List 34 | 35 | 36 | class PowerSupplyChannel(abc.ABC): 37 | """ 38 | Base abstract class for a power supply channel. 39 | """ 40 | 41 | @abc.abstractmethod 42 | def set_output_enabled(self, enabled: bool): 43 | """ 44 | Enable the output of this channel. 45 | """ 46 | pass 47 | 48 | @abc.abstractmethod 49 | def output_enabled(self) -> bool: 50 | pass 51 | 52 | @abc.abstractmethod 53 | def set_voltage(self, voltage: float): 54 | """ 55 | Set the channel output voltage (in volts). 56 | """ 57 | pass 58 | 59 | @abc.abstractmethod 60 | def voltage(self) -> float: 61 | """ 62 | Return the current voltage value (in volts). 63 | """ 64 | pass 65 | 66 | @abc.abstractmethod 67 | def set_current_limit(self, current: float): 68 | """ 69 | Maximum current limit for the channel in Ampere. 70 | """ 71 | pass 72 | 73 | @abc.abstractmethod 74 | def current_limit(self) -> float: 75 | """ 76 | Return the current value in Ampere. 77 | """ 78 | pass 79 | 80 | 81 | class PowerSupply(abc.ABC): 82 | """ 83 | Base abstract class for a Power Supply hardware. 84 | """ 85 | 86 | # Methods to implement 87 | 88 | @abc.abstractmethod 89 | def description(self) -> str: 90 | """ 91 | The self-description of this instrument. 92 | 93 | This is typically a string representation of the device serial number. 94 | 95 | :Example: 96 | 97 | >>> alim.description 98 | 'SPD3XIDD4R5542,1.01.01.02.05,V3.0' 99 | """ 100 | pass 101 | 102 | @abc.abstractmethod 103 | def _clear(self, pop_errors: bool): 104 | pass 105 | 106 | @abc.abstractmethod 107 | def get_channel(self, channel: str) -> PowerSupplyChannel: 108 | """ 109 | Return a specific power channel output. 110 | """ 111 | pass 112 | 113 | @abc.abstractmethod 114 | def channels(self) -> List[str]: 115 | pass 116 | 117 | def default_channel(self): 118 | """ 119 | Return a conventional default channel for the AFG. 120 | 121 | The default implementation returns the first channel. 122 | """ 123 | return self.get_channel(self.channels()[0]) 124 | 125 | def __getitem__(self, key): 126 | return self.get_channel(key) 127 | 128 | # Methods provided 129 | 130 | def clear(self, pop_errors=True): 131 | """ 132 | Clear pending measurements, status flags and optionally pop errors. 133 | 134 | Can be used to bring back the scope in a usable mode if something goes 135 | wrong. 136 | """ 137 | return self._clear(pop_errors) -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | Secbench Framework 2 | ================== 3 | 4 | .. figure:: _static/secbench-logo-2023.png 5 | :align: center 6 | :width: 500px 7 | 8 | Welcome to *Secbench* documentation! The *Secbench* project is a framework for 9 | hardware security testing of systems. The framework has been developed since 10 | 2017 at `CEA-LETI `__. 11 | 12 | *Secbench* provides Python packages for side-channel analysis and fault 13 | injection, that security researchers, teachers or students can use to create 14 | complex and **reproducible experiments**. Here is an example side-channel 15 | acquisition: 16 | 17 | .. code-block:: python 18 | 19 | 20 | from secbench.api import get_bench 21 | 22 | bench = get_bench() 23 | scope = bench.get_scope() 24 | table = bench.get_table() 25 | 26 | table.move_to(x=0.5, y=1.2) 27 | scope.arm() 28 | # Let the target device compute. 29 | scope.wait() 30 | d, = scope.get_data("1") 31 | 32 | A fault injection experiment can be written as: 33 | 34 | .. code-block:: python 35 | 36 | 37 | from secbench.api import get_bench 38 | from secbench.api.instruments import EMPulser 39 | 40 | bench = get_bench() 41 | table = bench.get_table() 42 | pulser = bench.get(EMPulser) 43 | 44 | table.move_to(x=0.1, y=0.3) 45 | # Configure first channel of EM injector 46 | pulser["1"].setup(amplitude=500, width_ns=20, rise_time_ns=6) 47 | pulser.set_output_enabled(True) 48 | 49 | # Iterate delays 50 | for delay_ns in range(0, 200, 10): 51 | pulser.set_params(delay_ns=10) 52 | # 1. Let the target device compute and generate a trigger. 53 | # 2. Analyze response 54 | 55 | As you probably noticed, *Secbench* allows describing experiments without 56 | reference to the actual lab instruments, and the scripts can operate with 57 | different vendors as long as drivers are implemented for 58 | :py:mod:`secbench.api`. 59 | 60 | The main components of the open-source version of Secbench are: 61 | 62 | - :py:mod:`secbench.api`: a Python package that defines abstractions for common 63 | hardware used in security characterization (oscilloscopes, XYZ-Tables, 64 | injectors). Experiments are written using interfaces defined in 65 | :py:mod:`secbench.api` and concrete driver implementations are provided in 66 | separated packages (e.g., :py:mod:`secbench.picoscope`). 67 | - :py:mod:`secbench.storage`: a thin wrapper on top of the HDF5 file format 68 | that allows creating and accessing side-channel datasets. 69 | - :py:mod:`secbench.processing`: a collection of common side-channel processing 70 | tools. 71 | 72 | Getting Started 73 | --------------- 74 | 75 | Ready to start using secbench? 76 | 77 | First :ref:`install secbench `, then follow one of the :ref:`tutorials `. 78 | At any moment, you may also find the :ref:`API reference ` useful. 79 | 80 | If you have any question or encounter some bugs, feel free to open a issue on the `main repository `__. 81 | You can also `contact us `__ for specific requests. 82 | 83 | Table of Contents 84 | ----------------- 85 | 86 | .. toctree:: 87 | :maxdepth: 2 88 | 89 | installation.md 90 | tutorials/index.rst 91 | api-reference/index.rst 92 | glossary 93 | 94 | About Secbench 95 | -------------- 96 | 97 | Secbench is used internally at CEA to conduct security caracterisations. 98 | Only the core parts of the framework are currently open-source. 99 | The whole architecture is depicted on the following image. 100 | 101 | .. figure:: _static/secbench_arch_overview.jpg 102 | :align: center 103 | :width: 70% 104 | 105 | Overall architecture of the Secbench framework. 106 | 107 | If you are interested in some other modules of the framework, please `contact us `__. 108 | 109 | Contributors 110 | ------------ 111 | 112 | The following people contributed to Secbench: 113 | 114 | - Thomas Hiscock (Maintainer) 115 | - Julien Maillard 116 | - Maxime Lecomte 117 | - Lucas Malandrino-Guyot 118 | - Antoine Moran 119 | - Ulysse Vincenti 120 | - Marine Sauze-Kadar 121 | - Raphael Collado 122 | - Thomas Loubier 123 | - Alexandre Macabies 124 | 125 | License 126 | ------- 127 | 128 | This project is licensed under `CECILL-2.1 `__ (see `LICENSE `__). 129 | 130 | Indices and tables 131 | ------------------ 132 | 133 | * :ref:`genindex` 134 | * :ref:`modindex` 135 | * :ref:`search` 136 | -------------------------------------------------------------------------------- /src/secbench-processing/secbench/processing/crypto/crc8.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | import numba 33 | import numpy as np 34 | 35 | # fmt: off 36 | CRC8_TABLE = np.array([ 37 | 0xea, 0xd4, 0x96, 0xa8, 0x12, 0x2c, 0x6e, 0x50, 0x7f, 0x41, 0x03, 0x3d, 38 | 0x87, 0xb9, 0xfb, 0xc5, 0xa5, 0x9b, 0xd9, 0xe7, 0x5d, 0x63, 0x21, 0x1f, 39 | 0x30, 0x0e, 0x4c, 0x72, 0xc8, 0xf6, 0xb4, 0x8a, 0x74, 0x4a, 0x08, 0x36, 40 | 0x8c, 0xb2, 0xf0, 0xce, 0xe1, 0xdf, 0x9d, 0xa3, 0x19, 0x27, 0x65, 0x5b, 41 | 0x3b, 0x05, 0x47, 0x79, 0xc3, 0xfd, 0xbf, 0x81, 0xae, 0x90, 0xd2, 0xec, 42 | 0x56, 0x68, 0x2a, 0x14, 0xb3, 0x8d, 0xcf, 0xf1, 0x4b, 0x75, 0x37, 0x09, 43 | 0x26, 0x18, 0x5a, 0x64, 0xde, 0xe0, 0xa2, 0x9c, 0xfc, 0xc2, 0x80, 0xbe, 44 | 0x04, 0x3a, 0x78, 0x46, 0x69, 0x57, 0x15, 0x2b, 0x91, 0xaf, 0xed, 0xd3, 45 | 0x2d, 0x13, 0x51, 0x6f, 0xd5, 0xeb, 0xa9, 0x97, 0xb8, 0x86, 0xc4, 0xfa, 46 | 0x40, 0x7e, 0x3c, 0x02, 0x62, 0x5c, 0x1e, 0x20, 0x9a, 0xa4, 0xe6, 0xd8, 47 | 0xf7, 0xc9, 0x8b, 0xb5, 0x0f, 0x31, 0x73, 0x4d, 0x58, 0x66, 0x24, 0x1a, 48 | 0xa0, 0x9e, 0xdc, 0xe2, 0xcd, 0xf3, 0xb1, 0x8f, 0x35, 0x0b, 0x49, 0x77, 49 | 0x17, 0x29, 0x6b, 0x55, 0xef, 0xd1, 0x93, 0xad, 0x82, 0xbc, 0xfe, 0xc0, 50 | 0x7a, 0x44, 0x06, 0x38, 0xc6, 0xf8, 0xba, 0x84, 0x3e, 0x00, 0x42, 0x7c, 51 | 0x53, 0x6d, 0x2f, 0x11, 0xab, 0x95, 0xd7, 0xe9, 0x89, 0xb7, 0xf5, 0xcb, 52 | 0x71, 0x4f, 0x0d, 0x33, 0x1c, 0x22, 0x60, 0x5e, 0xe4, 0xda, 0x98, 0xa6, 53 | 0x01, 0x3f, 0x7d, 0x43, 0xf9, 0xc7, 0x85, 0xbb, 0x94, 0xaa, 0xe8, 0xd6, 54 | 0x6c, 0x52, 0x10, 0x2e, 0x4e, 0x70, 0x32, 0x0c, 0xb6, 0x88, 0xca, 0xf4, 55 | 0xdb, 0xe5, 0xa7, 0x99, 0x23, 0x1d, 0x5f, 0x61, 0x9f, 0xa1, 0xe3, 0xdd, 56 | 0x67, 0x59, 0x1b, 0x25, 0x0a, 0x34, 0x76, 0x48, 0xf2, 0xcc, 0x8e, 0xb0, 57 | 0xd0, 0xee, 0xac, 0x92, 0x28, 0x16, 0x54, 0x6a, 0x45, 0x7b, 0x39, 0x07, 58 | 0xbd, 0x83, 0xc1, 0xff], dtype=np.uint8) 59 | # fmt: on 60 | 61 | 62 | @numba.njit 63 | def crc8(array, crc=0): 64 | """ 65 | Lookup-table based CRC8 implementation 66 | 67 | Implement a standard CRC with parameters: width=8 poly=0x4d init=0xff 68 | refin=true refout=true xorout=0xff check=0xd8 name="CRC-8/KOOP" 69 | 70 | Here is an equivalent C code that generates the CRC table: 71 | 72 | .. code-block:: c 73 | 74 | uint8_t crc8(uint8_t crc, uint8_t* data, size_t size) 75 | { 76 | if (data == NULL) 77 | return 0; 78 | crc = ~crc & 0xff; 79 | for (size_t i = 0; i < size; i++) { 80 | crc ^= data[i]; 81 | for (unsigned k = 0; k < 8; k++) { 82 | crc = crc & 1 ? (crc >> 1) ^ 0xb2 : crc >> 1; 83 | } 84 | } 85 | return crc ^ 0xff; 86 | } 87 | 88 | :Example: 89 | 90 | >>> crc8(b"DEADBEEF") 91 | 61 92 | >>> crc8(b"Hello world") 93 | 19 94 | 95 | """ 96 | if len(array) == 0: 97 | return 0 98 | crc &= 0xFF 99 | for b in array: 100 | crc = CRC8_TABLE[crc ^ b] 101 | return crc -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/instrument/types.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | from __future__ import annotations 32 | 33 | import logging 34 | from typing import TYPE_CHECKING, Iterable, Protocol 35 | 36 | from ..backend.types import Backend 37 | from ..exceptions import InstrumentPendingErrors 38 | 39 | if TYPE_CHECKING: 40 | from ..bench import UserConfig 41 | 42 | logger = logging.getLogger(__name__) 43 | 44 | 45 | class RawInstrument(Protocol): 46 | """ 47 | Interface that **must** be implemented by SCPI-like instruments. 48 | 49 | For remainder, SCPI (Standard Commands for Programmable Instruments) is a 50 | command format specification. Instruments that complies to SCPI describe 51 | their commands in their programmer manual in terms of ``query`` and 52 | ``write`` commands. 53 | 54 | :ivar backend: Current :py:class:`Backend` used by the instrument. 55 | 56 | """ 57 | 58 | backend: Backend 59 | 60 | @classmethod 61 | def from_backend(cls, backend: Backend, cfg: UserConfig) -> RawInstrument: 62 | """ 63 | Create an instance from a Backend. 64 | """ 65 | ... 66 | 67 | def has_error(self) -> bool: 68 | """ 69 | Return ``True`` if the instrument has an error pending. 70 | """ 71 | ... 72 | 73 | def pop_next_error(self) -> str | None: 74 | """ 75 | Pop the next pending error from the instrument. 76 | """ 77 | ... 78 | 79 | 80 | class InstrumentMixin(RawInstrument): 81 | """ 82 | Defines convenience methods in instruments. 83 | """ 84 | 85 | def pop_errors(self) -> list[str]: 86 | errors = [] 87 | while True: 88 | if not self.has_error(): 89 | break 90 | last_error = self.pop_next_error() 91 | errors.append(last_error) 92 | return errors 93 | 94 | def query(self, msgs: str) -> str: 95 | return self.backend.query(msgs) 96 | 97 | def query_raw(self, msgs: str, size: int) -> bytes: 98 | return self.backend.query_raw(msgs, size) 99 | 100 | def write(self, msgs: str): 101 | self.write_unchecked(msgs) 102 | pending_errors = self.pop_errors() 103 | if pending_errors: 104 | logger.debug(f"command '{msgs}' generated errors: {pending_errors}") 105 | raise InstrumentPendingErrors(pending_errors) 106 | 107 | def write_unchecked(self, msgs: str): 108 | self.backend.write(msgs) 109 | 110 | 111 | class QueryWriteInstrument(Protocol): 112 | def query(self, msgs: str) -> str: ... 113 | 114 | def write(self, msgs: str) -> str: ... 115 | 116 | def join_commands(self, msgs: Iterable[str]) -> str: ... 117 | 118 | 119 | class WriteManyMixin: 120 | """ 121 | Provide a `write_many` method for Instruments that support chained commands. 122 | """ 123 | 124 | def write_many(self: QueryWriteInstrument, *msgs: str): 125 | self.write(self.join_commands(msgs)) 126 | 127 | def query_many(self: QueryWriteInstrument, *msgs: str) -> str: 128 | return self.query(self.join_commands(msgs)) -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/instrument/features.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | import abc 32 | from typing import Sequence 33 | 34 | 35 | class HasScreenShot(abc.ABC): 36 | @abc.abstractmethod 37 | def get_screenshot(self): 38 | """ 39 | Get a screenshot of the instrument screen. 40 | Obviously this is not supported by screen-less devices. 41 | See PIL.Image_ for available methods. 42 | 43 | >>> scope.get_screenshot().save('screenshot.jpg') 44 | 45 | :rtype: PIL.Image_ 46 | 47 | .. _PIL.Image: http://pillow.readthedocs.io/en/3.1.x/reference/Image.html 48 | """ 49 | pass 50 | 51 | 52 | class HasSetupStorage(abc.ABC): 53 | @abc.abstractmethod 54 | def setup_slots(self) -> Sequence[str]: 55 | pass 56 | 57 | @abc.abstractmethod 58 | def setup_load(self, name: str) -> None: 59 | """ 60 | Load instrument settings from the specified file preset on the device. 61 | Can be used instead of setting up the various channels and parameters 62 | manually from Python. 63 | 64 | To create such a preset, use the instrument interface or call 65 | :meth:`setup_save`. 66 | 67 | >>> instr.setup_load('my_preset') 68 | 69 | :param name: file name to load (absolute or relative to default preset 70 | location) 71 | """ 72 | pass 73 | 74 | @abc.abstractmethod 75 | def setup_save(self, name: str) -> None: 76 | """ 77 | Save the current instrument settings to the specified file on the 78 | device. 79 | 80 | To later load this preset, use the instrument interface or call 81 | :meth:`setup_load`. 82 | 83 | >>> instr.setup_save('my_preset') 84 | 85 | :param name: file name to save (absolute or relative to default preset 86 | location) 87 | """ 88 | pass 89 | 90 | 91 | class HasWaveformStorage(abc.ABC): 92 | @abc.abstractmethod 93 | def write_waveform(self, channel: str, path: str, temporary: bool = False) -> None: 94 | """ 95 | Write waveform of a channel on the scope local storage. 96 | 97 | :param channel: Channel to be saved 98 | :param path: Path to the waveform on the device. 99 | :param temporary: 100 | if True, will store the waveform in a temporary directory, thus you 101 | can only pass the file name. 102 | """ 103 | pass 104 | 105 | @abc.abstractmethod 106 | def read_waveform(self, path: str, temporary=False, reshape=False): 107 | """ 108 | Read a binary file at a given location on the scope. 109 | 110 | :param path: Path to the waveform on the device. 111 | :param temporary: 112 | If True, will look into the scope internal waveform directory, 113 | thus you can only pass the file name. 114 | :param reshape: 115 | If true, will reshape the data according to the current 116 | segmentation policy and scope acquisition. 117 | :returns: the data read. 118 | """ 119 | pass -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/backend/vxi11.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | from __future__ import annotations 32 | 33 | import abc 34 | import logging 35 | from typing import Iterator 36 | 37 | from typing_extensions import TypeAlias 38 | 39 | from ..backend.types import Backend 40 | from ..bench import HardwareInfo, VxiScanner 41 | from ..exceptions import BackendError 42 | from ..instrument import RawInstrument 43 | 44 | logger = logging.getLogger(__name__) 45 | 46 | VXIBuildArgs: TypeAlias = str 47 | 48 | 49 | class VXIBackend(Backend): 50 | def __init__(self, host: str): 51 | import vxi11 # type: ignore 52 | 53 | self.inst = vxi11.Instrument(host) 54 | try: 55 | self.inst.open() 56 | except OSError as e: 57 | raise BackendError(f"could not open {host}; check connectivity") from e 58 | super().__init__() 59 | 60 | def set_timeout(self, secs: float): 61 | self.inst.timeout = secs 62 | 63 | def close(self): 64 | self.inst.close() 65 | 66 | def write(self, cmds: str): 67 | self.inst.write(cmds) 68 | 69 | def query(self, cmds: str) -> str: 70 | return self.inst.ask(cmds) 71 | 72 | def query_raw(self, cmds: str, size: int) -> bytes: 73 | self.inst.write(cmds) 74 | return self.inst.read_raw(size) 75 | 76 | 77 | class VXIDiscoverableMixin(abc.ABC): 78 | """ 79 | Make your hardware an instance of ``Discoverable[VXIBuildArgs]`` 80 | 81 | You must implement :py:meth:`VXIDiscoverableMixin._vxi_match_idn`. 82 | """ 83 | 84 | @classmethod 85 | @abc.abstractmethod 86 | def _vxi_match_idn(cls, idn: str) -> bool: 87 | """ 88 | A predicate to detect if an entry matches the current hardware. 89 | 90 | :param idn: the device description returned by the ``*IDN?`` SCPI command. 91 | """ 92 | pass 93 | 94 | @classmethod 95 | def _vxi_configure(cls, backend: Backend) -> None: 96 | """ 97 | A hook called after a :py:class:`VxiBackend` is constructed. 98 | 99 | This allows applying hardware-specific configuration. 100 | """ 101 | return 102 | 103 | @classmethod 104 | def is_supported(cls, hardware_info: HardwareInfo) -> bool: 105 | return hardware_info.has_scanner(VxiScanner) 106 | 107 | @classmethod 108 | def discover(cls, hw_info: HardwareInfo) -> Iterator[VXIBuildArgs]: 109 | scanner = hw_info.get_scanner(VxiScanner) 110 | if scanner is None: 111 | logger.info("VxiScanner not loaded, cannot discover pyvisa devices.") 112 | return 113 | for dev in scanner.devices(): 114 | if cls._vxi_match_idn(dev.idn): 115 | logger.info(f"found matching device {dev}.") 116 | yield dev.host 117 | 118 | @classmethod 119 | def build( 120 | cls: RawInstrument | VXIDiscoverableMixin, 121 | hardware_info: HardwareInfo, 122 | host: VXIBuildArgs, 123 | ): 124 | backend = VXIBackend(host) 125 | cls._vxi_configure(backend) 126 | return cls.from_backend(backend, hardware_info.user_config()) -------------------------------------------------------------------------------- /doc/tutorials/pattern_matching_alignment.md: -------------------------------------------------------------------------------- 1 | --- 2 | jupytext: 3 | formats: ipynb,md:myst 4 | text_representation: 5 | extension: .md 6 | format_name: myst 7 | format_version: 0.13 8 | jupytext_version: 1.16.6 9 | kernelspec: 10 | display_name: Python 3 (ipykernel) 11 | language: python 12 | name: python3 13 | --- 14 | 15 | (sec-pattern_matching_tutorial)= 16 | 17 | # Pattern Matching and Alignment 18 | 19 | In this notebook, we show how to do pattern matching and alignment using secbench primitives. 20 | 21 | ```{code-cell} ipython3 22 | import importlib 23 | 24 | import numpy as np 25 | import matplotlib.pyplot as plt 26 | 27 | # NOTE: tune the figure size as needed for better visualization in the notebook 28 | plt.rcParams["figure.figsize"] = (14, 6) 29 | ``` 30 | 31 | ```{code-cell} ipython3 32 | from secbench.processing.helpers import qplot 33 | from secbench.processing.signal import match_correlation, match_euclidean, phase_correlation 34 | ``` 35 | 36 | ## Input Generation 37 | 38 | We start by generating a simple pattern: 39 | 40 | ```{code-cell} ipython3 41 | pattern_width = 300 42 | 43 | xs = np.linspace(-1, 3, pattern_width) 44 | pattern = 2. * (np.sinc(xs**2) - np.sinc(xs - 4) + np.sinc(5 * xs) - 1) 45 | pattern = pattern.astype(np.float32) 46 | plt.plot(pattern) 47 | plt.title("Reference pattern") 48 | plt.show() 49 | ``` 50 | 51 | Then, we generate a trace and insert the pattern into it. 52 | 53 | ```{code-cell} ipython3 54 | samples = 5000 55 | 56 | offset = 300 # np.random.randint(pattern_width, samples - pattern_width) 57 | p_start, p_end = offset, offset + pattern_width 58 | 59 | data = np.random.normal(size=samples).astype(np.float32) 60 | data[p_start:p_end] += pattern 61 | print(f"offest is {offset}") 62 | 63 | plt.plot(data) 64 | plt.axvline(p_start, color="r") 65 | plt.axvline(p_end, color="r") 66 | plt.title("noisy trace with a pattern") 67 | plt.show() 68 | ``` 69 | 70 | ## Pattern Matching 71 | 72 | +++ 73 | 74 | Now, we run the different matchers available: 75 | - {py:func}`secbench.processing.signal.match_correlation`, we are interested by the maximum value, 76 | - {py:func}`secbench.processing.signal.match_euclidean`, we are interested by the minimum, 77 | - {py:func}`secbench.processing.signal.phase_correlation`, we are interested by the maximum value. 78 | 79 | ```{code-cell} ipython3 80 | matchers = [ 81 | ("correlation", match_correlation, "max"), 82 | ("Eucliean distance", match_euclidean, "min"), 83 | ("Phase correlation", phase_correlation, "max")] 84 | 85 | solutions = [] 86 | for label, matcher, order in matchers: 87 | fig, ax1 = plt.subplots() 88 | ax1.set_ylabel("metric") 89 | score = matcher(data, pattern, dtype=np.float32) 90 | sol = np.argmin(score) if order == "min" else np.argmax(score) 91 | solutions.append(sol) 92 | ax1.plot(score, color="red") 93 | ax1.axvline(sol, color="black", linestyle="--") 94 | 95 | ax2 = ax1.twinx() 96 | ax2.plot(data, alpha=0.3, color="green") 97 | ax2.set_ylabel("sample value") 98 | plt.title(f"Pattern matching with {label}") 99 | plt.show() 100 | 101 | for (label, _, _), sol in zip(matchers, solutions): 102 | print(f"offset found by {label}: {sol}") 103 | ``` 104 | 105 | ## Alignment 106 | 107 | Traces alignement simply consists of finding the pattern location in each trace and shifting them accordingly. 108 | 109 | This section shows a basic example. 110 | 111 | We first generate more traces using the same technique as in the previous section. 112 | 113 | ```{code-cell} ipython3 114 | samples = 5000 115 | 116 | data = np.zeros((50, samples), dtype=np.float32) 117 | 118 | for i in range(data.shape[0]): 119 | offset = np.random.randint(1000, 1500) 120 | p_start, p_end = offset, offset + pattern_width 121 | data[i] = np.random.normal(size=samples).astype(np.float32) 122 | data[i, p_start:p_end] += pattern 123 | ``` 124 | 125 | ```{code-cell} ipython3 126 | qplot(data, plot_mean=True) 127 | plt.title("Unaligned traces overlaid") 128 | plt.show() 129 | ``` 130 | 131 | We now run the alignment. 132 | 133 | ```{code-cell} ipython3 134 | matchers = [ 135 | ("correlation", match_correlation, "max"), 136 | ("eucliean distance", match_euclidean, "min"), 137 | ("phase correlation", phase_correlation, "max")] 138 | 139 | for label, matcher, order in matchers: 140 | 141 | fig, ax1 = plt.subplots() 142 | ax1.set_ylabel("metric") 143 | score = matcher(data, pattern) 144 | sol = np.argmin(score, axis=1) if order == "min" else np.argmax(score, axis=1) 145 | 146 | d_aligned = np.copy(data) 147 | for i, sh in enumerate(sol): 148 | d_aligned[i] = np.roll(d_aligned[i], -sh) 149 | 150 | ax1.plot(np.mean(d_aligned, axis=0)) 151 | plt.title(f"Alignment with {label}") 152 | plt.show() 153 | ``` 154 | 155 | ```{code-cell} ipython3 156 | 157 | ``` -------------------------------------------------------------------------------- /src/secbench-api/tests/conftest.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | import contextlib 33 | import time 34 | 35 | import pint 36 | import pytest 37 | 38 | u = pint.UnitRegistry() 39 | 40 | 41 | @pytest.fixture 42 | def bench(): 43 | from secbench.api import get_bench 44 | 45 | with get_bench() as bench: 46 | yield bench 47 | 48 | 49 | @pytest.fixture 50 | def table(bench): 51 | with bench.get_table() as table: 52 | yield table 53 | 54 | 55 | @pytest.fixture() 56 | def scope_dut(): 57 | from secbench.scope.util import ScopeHifiveDut 58 | 59 | all_duts = [ScopeHifiveDut] 60 | for dut_cls in all_duts: 61 | try: 62 | dut = dut_cls() 63 | yield dut 64 | dut.close() 65 | except Exception: 66 | pass 67 | return None 68 | 69 | 70 | @pytest.fixture 71 | def benchmark(): 72 | @contextlib.contextmanager 73 | def bencher(msg="", n=None, unit="unit"): 74 | t = time.monotonic() 75 | yield 76 | duration = time.monotonic() - t 77 | duration = (u.second * duration).to_compact() 78 | if n: 79 | print(msg, "duration: ", duration, "that is", duration / n, "per", unit) 80 | else: 81 | print(msg, "duration: ", duration) 82 | 83 | return bencher 84 | 85 | 86 | def pytest_generate_tests(metafunc): 87 | if "horizontal_args" in metafunc.fixturenames: 88 | module = metafunc.module.__name__ 89 | if "ps2000a" in module: 90 | params = [ 91 | # interval, samples 92 | (1 * u.us, 1e4), 93 | (10 * u.us, 1e3), 94 | (10 * u.us, 5e3), 95 | (10 * u.us, 10e3), 96 | (100 * u.us, 1e2), 97 | ] 98 | elif "rohdeschwartz" in module: 99 | params = [ 100 | # interval, samples 101 | (100 * u.us, 10e6), 102 | (1 * u.us, 10e6), 103 | (100 * u.ns, 10e6), 104 | (10 * u.ns, 10e6), 105 | (10 * u.ns, 10e6), 106 | (1 * u.ns, 4e6), 107 | (1 * u.ns, 1e6), 108 | (1 * u.ns, 1e3), 109 | (100 * u.ps, 1e3), 110 | ] 111 | elif "lecroy" in module: 112 | params = [ 113 | # interval, samples 114 | (100 * u.us, 10e6), 115 | (1 * u.us, 10e6), 116 | (100 * u.ns, 10e6), 117 | (10 * u.ns, 10e6), 118 | (10 * u.ns, 10e6), 119 | (1 * u.ns, 5e6), 120 | (1 * u.ns, 1e6), 121 | (1 * u.ns, 1e3), 122 | (100 * u.ps, 1e3), 123 | ] 124 | else: 125 | raise NotImplementedError( 126 | "no sensible horizontal params for {}".format(module) 127 | ) 128 | 129 | def gen_params(): 130 | for interval, samples in params: 131 | duration = (interval * samples).to(u.s).magnitude 132 | interval = interval.to(u.s).magnitude 133 | yield (interval, samples, None) 134 | yield (interval, None, duration) 135 | yield (None, samples, duration) 136 | 137 | metafunc.parametrize("horizontal_args", gen_params()) -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/backend/pyvisa.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | from __future__ import annotations 32 | 33 | import abc 34 | import logging 35 | from typing import Any, Iterator, Protocol 36 | 37 | from typing_extensions import TypeAlias 38 | 39 | from ..backend.types import Backend 40 | from ..bench import HardwareInfo, PyVisaScanner 41 | 42 | logger = logging.Logger(__name__) 43 | 44 | PyVisaResourceManager: TypeAlias = Any 45 | PyVisaBuildArgs: TypeAlias = tuple[PyVisaResourceManager, str] 46 | 47 | 48 | class PyVisaBackend(Backend): 49 | """ 50 | Implementation of the :py:class:`Backend` interface through `PyVisa `__. 51 | 52 | This backend allows interacting with any instrument supported by the pyvisa framework. 53 | """ 54 | 55 | def __init__(self, instr): 56 | self._instr = instr 57 | self._eom = False 58 | 59 | def set_timeout(self, secs: float): 60 | self._instr.timeout = 1000 * secs 61 | 62 | def set_eom(self, b: bool): 63 | self._eom = b 64 | 65 | def close(self): 66 | self._instr.close() 67 | 68 | def write(self, cmds: str): 69 | self._instr.write(cmds) 70 | 71 | def query(self, cmds: str) -> str: 72 | return self._instr.query(cmds).rstrip() 73 | 74 | def query_raw(self, cmds: str, size: int) -> bytes: 75 | self.write(cmds) 76 | return self._instr.read_bytes(size, break_on_termchar=self._eom) 77 | 78 | 79 | class PyVisaDiscoverableMixin(Protocol): 80 | """ 81 | Make your hardware discoverable through PyVisa. 82 | 83 | You must define :py:meth:`PyVisaDiscoverableMixin._pyvisa_match_id`. 84 | """ 85 | 86 | @classmethod 87 | @abc.abstractmethod 88 | def _pyvisa_match_id(cls, rm, path: str) -> bool: 89 | """ 90 | A predicate that matches the device. 91 | 92 | :param rm: a pyvisa ressource manager instance 93 | :param path: pyvisa device descriptor 94 | :returns: ``True`` is the given instance is 95 | """ 96 | pass 97 | 98 | @classmethod 99 | def _pyvisa_configure(cls, backend: PyVisaBackend): 100 | """ 101 | An optional hook called after the pyvisa backend is created. 102 | 103 | Overriding this method allows customizing the 104 | backend properties. 105 | """ 106 | pass 107 | 108 | @classmethod 109 | def is_supported(cls, hardware_info: HardwareInfo) -> bool: 110 | return hardware_info.has_scanner(PyVisaScanner) 111 | 112 | @classmethod 113 | def build(cls, hardware_info: HardwareInfo, args: PyVisaBuildArgs): 114 | rm, path = args 115 | backend = PyVisaBackend(rm.open_resource(path)) 116 | cls._pyvisa_configure(backend) 117 | return cls.from_backend(backend, hardware_info.user_config()) 118 | 119 | @classmethod 120 | def discover(cls, hw_info: HardwareInfo) -> Iterator[PyVisaBuildArgs]: 121 | scanner = hw_info.get_scanner(PyVisaScanner) 122 | if scanner is None: 123 | logger.info("PyVisaScanner not loaded, cannot discover pyvisa devices.") 124 | return 125 | 126 | for dev in scanner.devices(): 127 | if cls._pyvisa_match_id(scanner.resource_manager(), dev): 128 | logger.info(f"found matching PyVisa device {dev}.") 129 | yield scanner.resource_manager(), dev -------------------------------------------------------------------------------- /src/secbench-processing/tests/test_keccak.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | import numpy as np 33 | import pytest 34 | 35 | from secbench.processing.crypto.keccak import Keccak_f 36 | 37 | 38 | def test_init(): 39 | with pytest.raises(ValueError): 40 | Keccak_f(12345) 41 | 42 | ke = Keccak_f(1600) 43 | assert ke._w == 64 44 | assert ke._nrounds == 24 45 | 46 | 47 | # fmt: off 48 | EXAMPLE_STATE = np.array([ 49 | [0xdc, 0x7f, 0x32, 0x86, 0xbb, 0x9c, 0xa6, 0xa0, 0x71, 0x25, 0x11, 0xa1, 0xb8, 0x8a, 0x9f, 0x39, 0x21, 0x25, 0xe6, 0xad, 0xe2, 0x3f, 0xa4, 0xaf, 0x91], 50 | [0x5a, 0x60, 0x11, 0x63, 0xbe, 0xad, 0xd8, 0xcf, 0xba, 0xb0, 0x88, 0x73, 0x80, 0xe7, 0x95, 0xf6, 0x4c, 0x41, 0x07, 0x38, 0x8d, 0x05, 0x79, 0xf4, 0x4c]], 51 | dtype=np.uint8) 52 | # fmt: on 53 | 54 | 55 | def test_theta(): 56 | result = Keccak_f(200).theta(EXAMPLE_STATE) 57 | # fmt: off 58 | expected = np.array([ 59 | [0x2d, 0xa2, 0x3c, 0x57, 0x9a, 0x6d, 0x7b, 0xae, 0xa0, 0x04, 0xe0, 0x7c, 0xb6, 0x5b, 0xbe, 0xc8, 0xfc, 0x2b, 0x37, 0x8c, 0x13, 0xe2, 0xaa, 0x7e, 0xb0], 60 | [0xb0, 0xa8, 0x08, 0xda, 0x7b, 0x47, 0x10, 0xd6, 0x03, 0x75, 0x62, 0xbb, 0x99, 0x5e, 0x50, 0x1c, 0x84, 0x58, 0xbe, 0xfd, 0x67, 0xcd, 0x60, 0x4d, 0x89]], 61 | dtype=np.uint8) 62 | # fmt: on 63 | assert np.all(result == expected) 64 | 65 | 66 | def test_rho(): 67 | ke = Keccak_f(200) 68 | result = ke.rho(EXAMPLE_STATE) 69 | # fmt: off 70 | expected = np.array([ 71 | [0xdc, 0xfe, 0x8c, 0x68, 0xdd, 0xc9, 0x6a, 0x28, 0xb8, 0x52, 0x88, 0x86, 0xc5, 0x15, 0xcf, 0x72, 0x24, 0x92, 0xdc, 0xad, 0x8b, 0xfc, 0x94, 0xaf, 0x64], 72 | [0x5a, 0xc0, 0x44, 0x36, 0xf5, 0xda, 0x8d, 0xf3, 0x5d, 0x0b, 0x44, 0xcd, 0x04, 0xcf, 0xca, 0xed, 0x89, 0xa0, 0xe0, 0x38, 0x36, 0x14, 0x2f, 0xf4, 0x13]], 73 | dtype=np.uint8) 74 | # fmt: on 75 | assert np.all(result == expected) 76 | 77 | 78 | def test_pi(): 79 | ke = Keccak_f(200) 80 | result = ke.pi(EXAMPLE_STATE) 81 | # fmt: off 82 | expected = np.array([ 83 | [0xdc, 0xa6, 0xb8, 0xe6, 0x91, 0x86, 0x25, 0x11, 0x21, 0xa4, 0x7f, 0xa0, 0x8a, 0xad, 0xe2, 0xbb, 0x9c, 0xa1, 0x25, 0xaf, 0x32, 0x71, 0x9f, 0x39, 0x3f], 84 | [0x5a, 0xd8, 0x80, 0x07, 0x4c, 0x63, 0xb0, 0x88, 0x4c, 0x79, 0x60, 0xcf, 0xe7, 0x38, 0x8d, 0xbe, 0xad, 0x73, 0x41, 0xf4, 0x11, 0xba, 0x95, 0xf6, 0x05]], 85 | dtype=np.uint8) 86 | # fmt: on 87 | assert np.all(result == expected) 88 | 89 | 90 | def test_chi(): 91 | ke = Keccak_f(200) 92 | result = ke.chi(EXAMPLE_STATE) 93 | # fmt: off 94 | expected = np.array([ 95 | [0xdc, 0xfb, 0x0b, 0xc2, 0x98, 0x9c, 0xf7, 0xa4, 0xe9, 0x07, 0x09, 0xa3, 0xad, 0x8a, 0x3f, 0x3d, 0xe3, 0x2c, 0xf6, 0xad, 0x62, 0x34, 0xb4, 0xcd, 0x8c], 96 | [0x4b, 0x02, 0x8d, 0x23, 0x9e, 0xaa, 0xe8, 0xcf, 0xb7, 0xe0, 0x08, 0x14, 0x90, 0xef, 0xe6, 0xf7, 0x4a, 0x79, 0xc1, 0x30, 0xf5, 0x81, 0x71, 0x75, 0x4c]], 97 | dtype=np.uint8) 98 | # fmt: on 99 | assert np.all(result == expected) 100 | 101 | 102 | def test_permutation(): 103 | ke = Keccak_f(200) 104 | result = ke.permutation(EXAMPLE_STATE) 105 | # fmt: off 106 | expected = np.array([ 107 | [0x53, 0xf0, 0x2a, 0x15, 0xec, 0xd8, 0xa8, 0x6e, 0xc5, 0x66, 0x47, 0x39, 0xa9, 0x1e, 0x4f, 0xa1, 0x73, 0xe5, 0xd9, 0x52, 0xc3, 0x21, 0x4c, 0x6c, 0x78], 108 | [0xf2, 0x9d, 0xe2, 0xed, 0xdc, 0x20, 0x55, 0x5c, 0x25, 0xa3, 0xcc, 0x82, 0x3a, 0xec, 0xce, 0xa0, 0x9c, 0x5d, 0xb0, 0xc2, 0xbe, 0xf5, 0xd6, 0x2f, 0x3f]], 109 | dtype=np.uint8) 110 | # fmt: on 111 | assert np.all(result == expected) -------------------------------------------------------------------------------- /src/secbench-api/secbench/api/hooks.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | """ 32 | A collection of post-experiments hooks. 33 | """ 34 | 35 | import subprocess 36 | 37 | from .bench import Bench 38 | 39 | 40 | def _invoke_hook(hook, *args): 41 | if not hook: 42 | return 43 | if isinstance(hook, list): 44 | for h in hook: 45 | h(*args) 46 | return 47 | hook(*args) 48 | 49 | 50 | def secbench_main(on_success=None, on_failure=None, exit_on_failure=True): 51 | """ 52 | A Decorator for secbench experiments. 53 | 54 | Decorating running your experiment with ``secbench_main``, has a few advantages: 55 | 56 | - It will automatically create a :py:class:`secbench.core.bench.Bench` and 57 | pass it as first argument to your function. 58 | - ``secbench_main`` performs some clean-up and allows to supply 59 | post-experiment actions, like sending you an e-mail or copying results 60 | (see the example below). 61 | 62 | :param on_success: An optional hook called if the experiment runs 63 | successfully 64 | :param on_failure: An optional hook called if the experiment failed 65 | :param exit_on_failure: If true, will invoke sys.exit(1) on error 66 | 67 | :Examples: 68 | 69 | Here is a simple example of using the ``secbench_main`` decorator. 70 | 71 | .. code-block:: python 72 | 73 | from secbench.api.hooks import secbench_main, NotifySendHook 74 | 75 | # A custom hook to copy data into a shared directory. You can do 76 | # anything there. 77 | def backup_results(results): 78 | subprocess.check_call(['cp', 'my-store', '/home/...']) 79 | 80 | # Apply the secbench_main decorator to your function -> the argument 81 | # 'bench' will be passed automatically. 82 | @secbench_main(on_success=backup_results, 83 | on_failure=NotifySendHook("Something went wrong...")) 84 | def my_experiment(bench): 85 | # ... 86 | return results 87 | 88 | 89 | if __name__ == '__main__': 90 | my_experiment() 91 | 92 | """ 93 | import sys 94 | import traceback 95 | 96 | def inner(f): 97 | def _wrapped(): 98 | try: 99 | bench = Bench() 100 | result = f(bench) 101 | _invoke_hook(on_success, result) 102 | return result 103 | except Exception as e: 104 | _invoke_hook(on_failure) 105 | if exit_on_failure: 106 | msg = "\n".join( 107 | [ 108 | "the script failed because of an uncatched exception.", 109 | f"Exception:\n {repr(e)} {e}\n", 110 | "Backtrace:", 111 | ] 112 | ) 113 | print(msg, file=sys.stderr) 114 | traceback.print_tb(e.__traceback__, file=sys.stderr) 115 | sys.exit(1) 116 | raise 117 | 118 | return _wrapped 119 | 120 | return inner 121 | 122 | 123 | class NotifySendHook: 124 | """ 125 | Open a notification pop-up with a message on your windows manager. 126 | 127 | See ``man notify-send``. 128 | """ 129 | 130 | def __init__(self, message: str, urgency="critical"): 131 | self.message = message 132 | self.urgency = urgency 133 | 134 | def __call__(self, *args, **kwargs): 135 | subprocess.check_call(["notify-send", "-u", self.urgency, self.message]) -------------------------------------------------------------------------------- /src/secbench-native/crates/secbench_processing/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright CEA (Commissariat à l'énergie atomique et aux 2 | // énergies alternatives) (2017-2025) 3 | // 4 | // This software is governed by the CeCILL license under French law and 5 | // abiding by the rules of distribution of free software. You can use, 6 | // modify and/ or redistribute the software under the terms of the CeCILL 7 | // license as circulated by CEA, CNRS and INRIA at the following URL 8 | // "http://www.cecill.info". 9 | // 10 | // As a counterpart to the access to the source code and rights to copy, 11 | // modify and redistribute granted by the license, users are provided only 12 | // with a limited warranty and the software's author, the holder of the 13 | // economic rights, and the successive licensors have only limited 14 | // liability. 15 | // 16 | // In this respect, the user's attention is drawn to the risks associated 17 | // with loading, using, modifying and/or developing or reproducing the 18 | // software by the user in light of its specific status of free software, 19 | // that may mean that it is complicated to manipulate, and that also 20 | // therefore means that it is reserved for developers and experienced 21 | // professionals having in-depth computer knowledge. Users are therefore 22 | // encouraged to load and test the software's suitability as regards their 23 | // requirements in conditions enabling the security of their systems and/or 24 | // data to be ensured and, more generally, to use and operate it in the 25 | // same conditions as regards security. 26 | // 27 | // The fact that you are presently reading this means that you have had 28 | // knowledge of the CeCILL license and that you accept its terms. 29 | 30 | use pyo3::prelude::*; 31 | use tracing::level_filters::LevelFilter; 32 | 33 | use crate::errors::ShapeException; 34 | 35 | mod crypto; 36 | mod dsp; 37 | mod errors; 38 | 39 | pub fn make_secbench_processing(py: Python) -> PyResult> { 40 | let m = PyModule::new_bound(py, "processing")?; 41 | 42 | // Forward logging to caller's stderr. 43 | tracing_subscriber::fmt() 44 | .with_max_level(LevelFilter::INFO) 45 | .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) 46 | .init(); 47 | 48 | // Errors 49 | m.add("ShapeException", py.get_type_bound::())?; 50 | 51 | 52 | // Dsp 53 | m.add_class::()?; 54 | m.add_class::()?; 55 | m.add_function(wrap_pyfunction!(dsp::moving_sum_i8, &m)?)?; 56 | m.add_function(wrap_pyfunction!(dsp::moving_sum_i16, &m)?)?; 57 | m.add_function(wrap_pyfunction!(dsp::moving_sum_f32, &m)?)?; 58 | 59 | m.add_function(wrap_pyfunction!(dsp::fft_filter_i8, &m)?)?; 60 | m.add_function(wrap_pyfunction!(dsp::fft_filter_i16, &m)?)?; 61 | m.add_function(wrap_pyfunction!(dsp::fft_filter_f32, &m)?)?; 62 | 63 | m.add_function(wrap_pyfunction!(dsp::phase_correlation_i8, &m)?)?; 64 | m.add_function(wrap_pyfunction!(dsp::phase_correlation_i16, &m)?)?; 65 | m.add_function(wrap_pyfunction!(dsp::phase_correlation_f32, &m)?)?; 66 | 67 | m.add_function(wrap_pyfunction!(dsp::rfft_mag_i8, &m)?)?; 68 | m.add_function(wrap_pyfunction!(dsp::rfft_mag_i16, &m)?)?; 69 | m.add_function(wrap_pyfunction!(dsp::rfft_mag_f32, &m)?)?; 70 | 71 | m.add_function(wrap_pyfunction!(dsp::match_euclidean_i8, &m)?)?; 72 | m.add_function(wrap_pyfunction!(dsp::match_euclidean_i16, &m)?)?; 73 | m.add_function(wrap_pyfunction!(dsp::match_euclidean_f32, &m)?)?; 74 | 75 | m.add_function(wrap_pyfunction!(dsp::match_correlation_i8, &m)?)?; 76 | m.add_function(wrap_pyfunction!(dsp::match_correlation_i16, &m)?)?; 77 | m.add_function(wrap_pyfunction!(dsp::match_correlation_f32, &m)?)?; 78 | 79 | 80 | // Add Pcg32 81 | m.add_class::()?; 82 | 83 | m.add_function(wrap_pyfunction!(dsp::sliding_mean_f32_i8, &m)?)?; 84 | m.add_function(wrap_pyfunction!(dsp::sliding_mean_f32_i16, &m)?)?; 85 | m.add_function(wrap_pyfunction!(dsp::sliding_mean_f32_f32, &m)?)?; 86 | m.add_function(wrap_pyfunction!(dsp::sliding_mean_f64_f64, &m)?)?; 87 | 88 | m.add_function(wrap_pyfunction!(dsp::sliding_var_f32_i8, &m)?)?; 89 | m.add_function(wrap_pyfunction!(dsp::sliding_var_f32_i16, &m)?)?; 90 | m.add_function(wrap_pyfunction!(dsp::sliding_var_f32_f32, &m)?)?; 91 | m.add_function(wrap_pyfunction!(dsp::sliding_var_f64_f64, &m)?)?; 92 | 93 | m.add_function(wrap_pyfunction!(dsp::sliding_std_f32_i8, &m)?)?; 94 | m.add_function(wrap_pyfunction!(dsp::sliding_std_f32_i16, &m)?)?; 95 | m.add_function(wrap_pyfunction!(dsp::sliding_std_f32_f32, &m)?)?; 96 | m.add_function(wrap_pyfunction!(dsp::sliding_std_f64_f64, &m)?)?; 97 | 98 | m.add_function(wrap_pyfunction!(dsp::sliding_skew_f32_i8, &m)?)?; 99 | m.add_function(wrap_pyfunction!(dsp::sliding_skew_f32_i16, &m)?)?; 100 | m.add_function(wrap_pyfunction!(dsp::sliding_skew_f32_f32, &m)?)?; 101 | m.add_function(wrap_pyfunction!(dsp::sliding_skew_f64_f64, &m)?)?; 102 | 103 | m.add_function(wrap_pyfunction!(dsp::sliding_kurt_f32_i8, &m)?)?; 104 | m.add_function(wrap_pyfunction!(dsp::sliding_kurt_f32_i16, &m)?)?; 105 | m.add_function(wrap_pyfunction!(dsp::sliding_kurt_f32_f32, &m)?)?; 106 | m.add_function(wrap_pyfunction!(dsp::sliding_kurt_f64_f64, &m)?)?; 107 | 108 | Ok(m) 109 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Documentation](https://img.shields.io/badge/documentation-blue)](https://doc.secbench.fr) 2 | [![License](https://img.shields.io/badge/License-CECILL%202.1-blue)](https://opensource.org/license/cecill-2-1) 3 | [![secbench-api version](https://img.shields.io/pypi/v/secbench-api?label=pypi%3A%20secbench-api)](https://pypi.org/project/secbench-api/#history) 4 | [![secbench-storage version](https://img.shields.io/pypi/v/secbench-storage?label=pypi%3A%20secbench-storage)](https://pypi.org/project/secbench-storage/#history) 5 | [![secbench-picoscope version](https://img.shields.io/pypi/v/secbench-picoscope?label=pypi%3A%20secbench-picoscope)](https://pypi.org/project/secbench-picoscope/#history) 6 | [![secbench-processing version](https://img.shields.io/pypi/v/secbench-processing?label=pypi%3A%20secbench-processing)](https://pypi.org/project/secbench-processing/#history) 7 | ![Python Version](https://img.shields.io/pypi/pyversions/secbench-api) 8 | 9 | # The Secbench Framework 10 | 11 | ![Secbench logo](./secbench_logo.png) 12 | 13 | Secbench is a cross-platform Python toolkit for hardware security characterization developed by [CEA-Leti](https://www.leti-cea.com/cea-tech/leti/english) cybersecurity teams. 14 | It provides a unified solution for side-channel analysis and fault injection, enabling researchers, educators, and students to conduct advanced and **reproducible experiments**. 15 | 16 | ## Main Features 17 | 18 | The main features of the Secbench framework are: 19 | 20 | - Abstract interfaces for common lab instruments in the [secbench-api](http://doc.secbench.fr/api-reference/api.html#module-secbench-api) package, including: 21 | - [oscilloscopes](http://doc.secbench.fr/api-reference/api.html#secbench.api.instrument.Scope), 22 | - [fault injectors](http://doc.secbench.fr/api-reference/api.html#pulser), 23 | - [arbitrary function generators](http://doc.secbench.fr/api-reference/api.html#arbitrary-function-generators), 24 | - [tables](http://doc.secbench.fr/api-reference/api.html#table) and other equipments. 25 | - A [Bench](http://doc.secbench.fr/api-reference/api.html#secbench.api.Bench) abstraction, that supports automatic device discovery and easy configuration. 26 | - Drivers for specific lab hardware, implementing the abstract interfaces from [secbench-api](http://doc.secbench.fr/api-reference/api.html#module-secbench-api). 27 | - An [efficient HDF5-based trace format](http://doc.secbench.fr/api-reference/storage.html) for managing side-channel data. 28 | - Optimized side-channel processing algorithms in the `secbench-processing` package (**to be released soon**). 29 | 30 | ## Example Usage 31 | 32 | Thanks to Secbench, hardware-agnostic experiments can be written and shared by researchers, such as a side-channel acquisition: 33 | 34 | ```python 35 | from secbench.api import get_bench 36 | 37 | bench = get_bench() 38 | scope = bench.get_scope() 39 | table = bench.get_table() 40 | 41 | table.move_to(x=0.5, y=1.2) 42 | scope.arm() 43 | # Let the target device compute: 44 | # dut.run_crypto_computation() 45 | scope.wait() 46 | d, = scope.get_data("1") 47 | ``` 48 | 49 | ## Getting started 50 | 51 | Please refer to the [framework documentation](https://doc.secbench.fr) for getting started. 52 | 53 | If you want to build the documentation locally, you need to [create a development environment](https://doc.secbench.fr/installation.html#developers) and run `make build-html` in the [./doc](./doc) directory. 54 | 55 | ## News 56 | 57 | **IMPORTANT**: The open-souce deployment of secbench is on-going. Not all 58 | components are released yet, stay tuned! 59 | 60 | * Upcoming release: 61 | * Better platform support (MacOS, Windows) 62 | * `secbench.chipwhisperer` module: drivers for [ChipWhisperer](https://www.newae.com/chipwhisperer) devices. 63 | * 05/2025: 64 | * add `secbench.processing` module (contains side-channel processing tools). 65 | * add `secbench.native` module, contains Rust-accelerated side-channel processing functions. 66 | * `secbench.picoscope` module: support of rapidmode and PS3000 models. 67 | * 02/2025: initial release of secbench core components: 68 | * `secbench.api` module. 69 | * `secbench.storage` module. 70 | * `secbench.picoscope` module. 71 | * Documentation and tutorials 72 | 73 | ## License 74 | 75 | This project is licensed under [CECILL-2.1](http://www.cecill.info/index.en.html) (see [LICENSE](./LICENSE)). 76 | 77 | If this license is too restricting for your use case, please [contact us](mailto:support@secbench.fr). 78 | 79 | ## Contributors 80 | 81 | The following people have contributed to Secbench: 82 | 83 | - Thomas Hiscock (Maintainer) 84 | - Julien Maillard 85 | - Maxime Lecomte 86 | - Lucas Malandrino-Guyot 87 | - Antoine Moran 88 | - Ulysse Vincenti 89 | - Marine Sauze-Kadar 90 | - Raphael Collado 91 | - Thomas Loubier 92 | - Alexandre Macabies 93 | 94 | ## Research Works Using Secbench 95 | 96 | We would be happy to hear about your use of Secbench. 97 | In [PUBLICATIONS.md](./PUBLICATIONS.md) we list some research works made at CEA which used the Secbench framework. 98 | 99 | ## Acknowledgements 100 | 101 | The open-source release of the Secbench framework is done as part of [PEPR Cybersécurité](https://www.pepr-cybersecurite.fr), [REV project](https://www.pepr-cybersecurite.fr/projet/rev/). 102 | 103 | This work has benefited from a government grant managed by the National Research Agency under France 2030 with reference ANR-22-PECY-0009. 104 | -------------------------------------------------------------------------------- /src/secbench-processing/tests/test_models.py: -------------------------------------------------------------------------------- 1 | # Copyright CEA (Commissariat à l'énergie atomique et aux 2 | # énergies alternatives) (2017-2025) 3 | # 4 | # This software is governed by the CeCILL license under French law and 5 | # abiding by the rules of distribution of free software. You can use, 6 | # modify and/ or redistribute the software under the terms of the CeCILL 7 | # license as circulated by CEA, CNRS and INRIA at the following URL 8 | # "http://www.cecill.info". 9 | # 10 | # As a counterpart to the access to the source code and rights to copy, 11 | # modify and redistribute granted by the license, users are provided only 12 | # with a limited warranty and the software's author, the holder of the 13 | # economic rights, and the successive licensors have only limited 14 | # liability. 15 | # 16 | # In this respect, the user's attention is drawn to the risks associated 17 | # with loading, using, modifying and/or developing or reproducing the 18 | # software by the user in light of its specific status of free software, 19 | # that may mean that it is complicated to manipulate, and that also 20 | # therefore means that it is reserved for developers and experienced 21 | # professionals having in-depth computer knowledge. Users are therefore 22 | # encouraged to load and test the software's suitability as regards their 23 | # requirements in conditions enabling the security of their systems and/or 24 | # data to be ensured and, more generally, to use and operate it in the 25 | # same conditions as regards security. 26 | # 27 | # The fact that you are presently reading this means that you have had 28 | # knowledge of the CeCILL license and that you accept its terms. 29 | ### 30 | 31 | import random 32 | 33 | import numpy as np 34 | import pytest 35 | 36 | from secbench.processing import InvalidInputError 37 | from secbench.processing.models import ( 38 | hamming_weight, 39 | lra_unpackbits, 40 | lra_unpackbits_2nd_order, 41 | unpackbits, 42 | ) 43 | 44 | 45 | def test_hamming_weight(): 46 | x = np.array([0xAAAAAAAA, 0x0], dtype=np.uint32) 47 | y = np.array([0x0, 0x1111_1111_2222_2222], dtype=np.uint64) 48 | 49 | assert list(hamming_weight(x)) == [16, 0] 50 | assert list(hamming_weight(y)) == [0, 16] 51 | 52 | assert hamming_weight(np.array([1 << 62], dtype=np.uint64)) == 1 53 | assert hamming_weight(np.array([1 << 12], dtype=np.uint64)) == 1 54 | 55 | assert hamming_weight(np.array([1 << 30], dtype=np.uint32)) == 1 56 | assert hamming_weight(np.array([1 << 12], dtype=np.uint32)) == 1 57 | 58 | assert hamming_weight(np.array([1 << 15], dtype=np.uint32)) == 1 59 | assert hamming_weight(np.array([1 << 5], dtype=np.uint32)) == 1 60 | 61 | 62 | def test_hamming_weight_int(): 63 | # Unsupported input type 64 | with pytest.raises(InvalidInputError): 65 | _ = hamming_weight(0.0) 66 | 67 | # Supported, but out of range 68 | with pytest.raises(InvalidInputError): 69 | _ = hamming_weight(-1) 70 | 71 | with pytest.raises(InvalidInputError): 72 | _ = hamming_weight(2**64) 73 | 74 | # Randomized test against oracle. 75 | for _ in range(200): 76 | x = random.randint(0, 2**64) 77 | assert hamming_weight(x) == bin(x).count("1") 78 | 79 | 80 | @pytest.mark.parametrize("dtype", [np.uint8, np.uint16, np.uint32]) 81 | @pytest.mark.parametrize("shape", [10, (10, 3), (5, 2, 3)]) 82 | @pytest.mark.parametrize("count", [0, 5, 13]) 83 | def test_unpackbits(dtype, shape, count): 84 | y = np.random.randint(0, 2**32, size=shape, dtype=np.uint64) 85 | if count: 86 | y = y & ((1 << count) - 1) 87 | if dtype == np.uint8 and count > 8: 88 | return 89 | 90 | y = y.astype(dtype) 91 | 92 | decomp = unpackbits(y, count=count) 93 | n_bits = decomp.shape[-1] if count == 0 else count 94 | y_rebuilt = np.zeros_like(y, dtype=np.uint64) 95 | print(decomp.shape) 96 | for i in range(n_bits): 97 | y_rebuilt += decomp[..., i].astype(np.uint64) << i 98 | y_rebuilt = y_rebuilt.astype(y.dtype) 99 | np.testing.assert_equal(y, y_rebuilt) 100 | 101 | 102 | def test_lra_unpackbits(): 103 | xs = np.arange(256, dtype=np.uint8) 104 | ys = lra_unpackbits(xs, center=True) 105 | assert ys.shape == (256, 9) 106 | np.testing.assert_equal(ys[:, -1], np.ones(256)) 107 | assert len(np.unique(ys)) == 2, "the output is made of two values" 108 | print(ys[0]) 109 | np.testing.assert_equal(ys[0, :8], -1 * np.ones(8)) 110 | np.testing.assert_equal(ys[-1], 1 * np.ones(9)) 111 | 112 | ys = lra_unpackbits(xs, with_intercept=False) 113 | assert ys.shape == (256, 8) 114 | 115 | ys = lra_unpackbits(xs, with_intercept=False, count=3) 116 | assert ys.shape == (256, 3) 117 | 118 | ys = lra_unpackbits(xs, with_intercept=True, count=5) 119 | assert ys.shape == (256, 6) 120 | 121 | 122 | def test_lra_unpackbits_example(): 123 | ys = np.array([0, 0b0001_1101, 0x80], dtype=np.uint8) 124 | expected = np.array( 125 | [[0] * 8, [1, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1]], dtype=np.uint8 126 | ) 127 | expected_i8 = (2 * (expected - 0.5)).astype(np.int8) 128 | expected_lra = np.c_[expected_i8, np.ones(expected_i8.shape[0], dtype=np.int8)] 129 | bs = lra_unpackbits(ys, center=True) 130 | assert bs.dtype == np.int8 131 | np.testing.assert_equal(bs, expected_lra) 132 | 133 | bs = lra_unpackbits(ys, center=False) 134 | np.testing.assert_equal( 135 | bs, np.c_[expected, np.ones(expected.shape[0], dtype=np.int8)] 136 | ) 137 | 138 | bs = lra_unpackbits_2nd_order(ys) 139 | assert bs.shape == (3, 37) -------------------------------------------------------------------------------- /src/secbench-processing/secbench/processing/_native.py: -------------------------------------------------------------------------------- 1 | ### 2 | # Copyright CEA (Commissariat à l'énergie atomique et aux 3 | # énergies alternatives) (2017-2025) 4 | # 5 | # This software is governed by the CeCILL license under French law and 6 | # abiding by the rules of distribution of free software. You can use, 7 | # modify and/ or redistribute the software under the terms of the CeCILL 8 | # license as circulated by CEA, CNRS and INRIA at the following URL 9 | # "http://www.cecill.info". 10 | # 11 | # As a counterpart to the access to the source code and rights to copy, 12 | # modify and redistribute granted by the license, users are provided only 13 | # with a limited warranty and the software's author, the holder of the 14 | # economic rights, and the successive licensors have only limited 15 | # liability. 16 | # 17 | # In this respect, the user's attention is drawn to the risks associated 18 | # with loading, using, modifying and/or developing or reproducing the 19 | # software by the user in light of its specific status of free software, 20 | # that may mean that it is complicated to manipulate, and that also 21 | # therefore means that it is reserved for developers and experienced 22 | # professionals having in-depth computer knowledge. Users are therefore 23 | # encouraged to load and test the software's suitability as regards their 24 | # requirements in conditions enabling the security of their systems and/or 25 | # data to be ensured and, more generally, to use and operate it in the 26 | # same conditions as regards security. 27 | # 28 | # The fact that you are presently reading this means that you have had 29 | # knowledge of the CeCILL license and that you accept its terms. 30 | ### 31 | 32 | """ 33 | Re-exports from :py:mod:`secbench_native.processing` module 34 | """ 35 | 36 | from __future__ import annotations 37 | 38 | import functools 39 | import os 40 | 41 | import numpy as np 42 | 43 | from .helpers import InvalidInputError, MissingPackageError, check_array 44 | 45 | try: 46 | import secbench_native.processing as secbench_native_processing 47 | except ImportError: 48 | secbench_native_processing = None 49 | 50 | 51 | def _native_not_available(symbol: str): 52 | def wrapped(*args, **kwargs): 53 | """ 54 | Stub for :py:mod:`secbench_native.processing` module. 55 | 56 | .. warning:: 57 | 58 | If you see this message, it means that the ``secbench_native.processing`` module is 59 | not available. You need to install it to access this functionality. 60 | """ 61 | raise MissingPackageError( 62 | f"Unable to use '{symbol}', the 'secbench_native.processing' package must be installed." 63 | ) 64 | 65 | return wrapped 66 | 67 | 68 | def secbench_native_import(symbol: str): 69 | """ 70 | Safely re-export a function defined in the :py:mod:`secbench_native.processing` module. 71 | 72 | This will generate a user-friendly message if someone 73 | tries to use (import is allowed) a feature from secbench_native without 74 | having it installed. 75 | """ 76 | if secbench_native_processing is None: 77 | return _native_not_available(symbol) 78 | return getattr(secbench_native_processing, symbol) 79 | 80 | 81 | _N_THREADS = os.environ.get("RAYON_NUM_THREADS") or os.cpu_count() 82 | 83 | 84 | def _chunk_size(n_rows, chunks_per_thread=2.0) -> int | None: 85 | """ 86 | Compute the default chunk size for 87 | """ 88 | total = int(n_rows / (chunks_per_thread * _N_THREADS)) 89 | if total == 0: 90 | return None 91 | return total 92 | 93 | 94 | def transform_2d(input_types, output_types, allow_1d_inputs=True, c_continuous=True): 95 | def wrap(f): 96 | @functools.wraps(f) 97 | def inner( 98 | X, 99 | *args, 100 | output=None, 101 | parallel=False, 102 | chunk_size=None, 103 | dtype=None, 104 | **kwargs, 105 | ): 106 | if dtype is None: 107 | if output is None: 108 | if X.dtype == np.float64: 109 | dtype = np.float64 110 | else: 111 | dtype = np.float32 112 | else: 113 | dtype = output.dtype 114 | 115 | if dtype is not None and dtype not in output_types: 116 | raise InvalidInputError( 117 | f"unsupported output type {dtype}, supported values are: {output_types}" 118 | ) 119 | input_is_1d = X.ndim == 1 120 | if allow_1d_inputs and input_is_1d: 121 | X = X[np.newaxis, :] 122 | if output is not None: 123 | check_array( 124 | output, 125 | ndim=2, 126 | dtype=dtype, 127 | array_name="output", 128 | check_c_continuous=c_continuous, 129 | ) 130 | check_array( 131 | X, 132 | ndim=2, 133 | dtype=input_types, 134 | array_name="X", 135 | check_c_continuous=c_continuous, 136 | ) 137 | # Compute default chunk size if needed. 138 | if chunk_size is None and parallel: 139 | chunk_size = _chunk_size(X.shape[0]) 140 | 141 | out = f( 142 | X, 143 | *args, 144 | output=output, 145 | parallel=parallel, 146 | chunk_size=chunk_size, 147 | dtype=dtype, 148 | **kwargs, 149 | ) 150 | 151 | if allow_1d_inputs and input_is_1d: 152 | return out[0] 153 | return out 154 | 155 | return inner 156 | 157 | return wrap --------------------------------------------------------------------------------