If you're curious about contributing to ChipWhisperer, be it software or hardware, this is the document for you!
Contribution to the project is always welcome. We are a small team and fixing everything right away or making those enhancements you dream of are often a game of managing priorities. If there is a feature you would like to help with, let us know. If you would like to start out small and get familiar with the project whilst contributing, there are always ways the software documentation could be improved. The software docs are all on github. You can fork the chipwhisperer repository make changes and then take out a pull request. We will discuss the changes then.
Hardware source is spread across several repositories:
- ChipWhisperer-Lite, -Pro, and -Nano: chipwhisperer-capture repository
- ChipWhisperer Husky firmware: chipwhisperer-husky repository
- ChipWhisperer Husky FPGA: chipwhisperer-husky-fpga repository
- CW308/312 Targets: chipwhisperer-target-cw308t repository
If you are having trouble finding what you're looking for, ask us!.
Our source code can be found the ChipWhisperer GitHub Repository. Issues and enhancements being worked on can be found in our GitHub issue tracker. If you need ideas about what to work on, this is the place to go. Development of ChipWhisperer
takes place on the develop
branch. Every release, develop
is merged into master
.
In general, we prefer methods, functions, variables, and modules to be in snake_case
instead of camelCase
. You'll see a lot
of camelCase
scattered throughout the code as this was preferred before ChipWhisperer 5, but all public facing code - what's documented
in the API - is now snake_case
. Class names should be in PascalCase
. Docstrings should be in the Google style. Besides that, there aren't too many requirements for small fixes and additions.
For larger additions (such as adding a whole new scope or target), we have
a few requirements. Arguments that must be present, but can be ignored,
are indicated as well. For example, scope._con()
must have an sn
parameter,
but the method doesn't need to do anything with the value and as such may be ignored.
Scopes can have a wide variety of features. As such, there are only a few additional requirements:
Must inherit the ScopeTemplate
object located in chipwhisperer.capture.scopes.base
and
must implement the following methods:
def _con(self, sn):
"""Connects to the scope. May also be called con().
Args:
sn (str): Unique identifier for the device. May be ignored, must be optional
"""
...
def _dis(self):
"""Disconnects from the scope. May also be called dis().
"""
...
The following methods are required for a scope to be used with cw.capture_trace()
and
otherwise recommended:
def arm(self):
"""Prepares the scope to capture a power trace"""
...
def capture(self):
"""Reads power trace data from the scope.
Returns:
False upon success and True upon failure
"""
...
def get_last_trace(self):
"""Returns the scope data read by capture()
Returns:
A numpy array containing the scope data.
"""
...
Targets must inherit the TargetTemplate
object located in chipwhisperer.capture.targets._base
and must implement the following methods:
def _con(self, scope):
""" Connects to the target. May also be called `con`. Will be passed **kwargs from `cw.target()`.
Args:
scope (CW scope object): May be ignored
"""
...
def _dis(self):
""" Disconnects from the target. May also be called `dis`
"""
...
The following methods are optional as not all targets will be able to implement them (for example,
public crypto may not be able to transmit a message/key in a single command as required by simpleserial_write()
).
These methods, however, are required for a target to be used with cw.capture_target()
and should be implemented
as specified.
def set_key(self, key, ack):
""" Sets the encryption key on the target. Should not resend the key
to the target if key is the same as the one previously sent by this method.
Args:
key (bytearray): The key to be sent to the target. Must not be ignored.
ack (bool): Whether or not to wait for an ack by the target. May be ignored. Must be optional.
"""
...
def simpleserial_write(self, cmd, data, end):
""" Sends a command to the target, along with data.
Args:
cmd (str): The command to send to the target. Must accept
`'k'` for sending a key and `'p'` for sending input.
Must not be ignored.
data (bytearray): The data to send to the target as part of cmd.
Must not be ignored
end (str): A terminator for the end of the command.
May be ignored. Must be optional.
"""
...
def simpleserial_read(self, cmd, pay_len, end, timeout, ack):
""" Reads a response from the target.
Args:
cmd (str): The command to expect from the target. Must accept
'r' for a response after sending 'p'. May be ignored.
pay_len (int): The length of the expected response from the target.
May be ignored.
end (str): The expected termination to the response. May be ignored.
Must be optional.
timeout (int): A timeout value for the read. May be ignored.
Must be optional.
ack (bool): Whether or not to expect an ack at the end of the message.
May be ignored. Must be optional.
Returns:
Must return the response as a bytearray not including cmd, end, or the ack.
"""
...
def is_done(self):
"""Indicates whether or not the target is finished its operation.
Returns:
True if the target is finished, False if it isn't. May immediately return True if
a successful scope.capture() indicates that the device is finished its operation.
"""
...
Documentation is built with Jupyter Book (v1). We use a mix of Markdown, reStructuredText, and Jupyter Notebook source files1:
- Markdown is used for everything in the "Hardware" section.
- The "Tips and Tricks" section uses a mix of Markdown and Notebooks.
- reStructuredText is used elsewhere.
Build requirements can be installed using:
python -m pip install -r chipwhisperer/docs/requirements.txt
You will also need the following submodules:
chipwhisperer/docs/chipwhisperer-target-cw308t
chipwhisperer/docs/cw_tips_tricks
You can then build the documentation site locally by going to the
chipwhisperer/docs
folder and running:
jb build source
This will build the documentation in html form. You can then navigate to the
source/_build/html
directory and open index.html
. This should open the
website in your browser.
After making changes, run make
in chipwhisperer/docs
to run
spellchecking and a few other checks.
For more details on how the documentation is built and why, go to the Site Details page.
Contribution to the documentation is always welcome. To see the effect of changes to the documentation it needs to be rebuilt after each change. When contributing to the documentation here are some rough guidelines to follow:
-
All directive blocks are indented by four spaces. This makes life easier when the text editor you are using is already set for four spaces because of python. For example:
|.. note:: | A note to the user.
-
Indent unnumbered lists with two spaces and a space after the symbol. So that the text block starts at column five. Example:
| * list item 1 | * list item 2
-
Indent numbered lists with one space, then a period and a space. Example:
| #. numbered list item 1 | #. numbered list item 2 | Continuation of code block.
-
We use autodoc for our API documentation, however to get the documentation of the api to look clean a lot of the module and class paths have to be manually specified.
-
When using autodoc do not use the autoproperty directive for properties. Just use autoattribute. autoproperty causes errors on ReadTheDocs.
-
Follow the google style guide for docstrings this makes the documentation easier to read while looking at the source code.
-
Keep in mind that people will be reading both the generated documentation and the source code. Don't make either one too painful to read. This happens a lot with links to other functions. Links help readers of the generated documentation but look quite verbose in the source code. Find a balance.
-
When adding section links, try to make them intuitive with the header and toctree hierarchy. For example: if a file named info.rst has a header Additional Information a good section link would be:
.. info-additional_information: ********************** Additional Information **********************
There are lots of examples throughout the documentation.
-
Use this header structure for documentation:
- # with overline, for parts
- * with overline, for chapters
- =, for sections
- -, for subsections
- ^, for subsubsections
- “, for paragraphs
- keep in mind that markdown files in the
chipwhisperer-target-cw308t
submodule need to also render on GitHub
More formatting guidelines and tips are on the Site Details page.
A few useful resources:
- Restructured Text and Sphinx CheatSheet
- Example Doc Strings (Google Style Guide)
- Napoleon (Google Style to ReST preprocessor)
- reStructuredText - Docutils
- Jupyter Book
ChipWhisperer software is currently tested in two ways:
- Using Jupyter Notebooks
- Unit Tests
The tutorials are not only a great resource for people learning to use the platform, they also are the functional tests for this project. We use the auto-generated output for the tutorials page. Each tutorial has a test section at the end of the notebook which asserts certain test criteria. The criteria is often hard to chose due to the nature of the attacks, especially glitching.
When editing or creating tutorials here are a few things to consider:
-
If the tutorial is meant to be run using some of the chipwhisperer hardware the first source code block must contain
SCOPETYPE = 'OPENADC' PLATFORM = 'CWLITEARM' CRYPTO_TARGET = 'TINYAES128C'
or equivalent for the different types of hardware. Don't worry about getting it right, when you are creating a tutorial, we can help you is you take out a pull request. The reason this block is there is for use with nbparameterize for running our automated tests so we can figure it out for you.
-
When writing in markdown cells please use the pandoc style markdown
-
This list contains guidelines and will update over time. We will run the tutorials through the tutorial build system and fix errors that come up.
The tutorials are run as tests on our own testing machine where we keep
the board used for each hardware type consistent. We are looking to improve
this, and have the beginning of a full test system created. It can be found
in the jupyter/utils/tutorials.py
script. It uses a configuration file
to specify the tutorials and which type of hardware it currently should support.
The configuration file is read in and the tutorials are run for all different configurations. The configuration file is written using YAML and the syntax is as follows
# Expected Syntax:
#
# connected:
# scope: <VALID SCOPE NAME (OPENADC, CWNANO)>
# target: <VALID PLATFORM NAME (CWLITEARM, CWLITEXMEGA, CWNANO)>
# serial number: <device serial number (optional)>
#
# tutorials:
# <tutorial file name including extension>:
# configurations:
# - scope: <VALID SCOPE NAME>
# target: <VALID PLATFORM NAME>
# firmware: <VALID CRYPTO_TARGET NAME (TINYAES128C, AVRCYPTOLIB, MBEDTLS)>
# - ... any more configurations
# kwargs: # extra keyword arguments to nbparameterise (optional)
# num_traces: <number of traces to capture>
# sample_size: <sample size>
You can find the current version in our GitHub Repository as the file jupyter/tests/tutorials.yaml. To run the tests use
cd chipwhisperer/jupyter/tests/
python tutorials.py
This should run the tests in all known configurations and give the output of passed and output written to output/file/path/ or the first error that occurred in each notebook. There is also a notebook for running tests individually if that is needed.
Inside the chipwhisperer/jupyter
folder there is the notebook called
Test_Notebook.ipynb
. This notebook can be used to run the tests individually.
This is great for working on getting a tutorial running or testing a single
notebook you have made changes for.
- Open the notebook as you would any other
notebook and run all the blocks leading up to the blocks containing
different blocks similar to
testscope = 'OPENADC' testplat = 'CWLITEARM' crypt = 'TINYAES128C'
- Then choose the block that is correct for your attached hardware and run that.
- Finally select the block containing the notebook you want to test from the code cells following.
There are also a few unit tests that have been created to test small parts of the API. The unit tests are mostly used in places where we can test without using the hardware. Here are some changes that have been though of that would make the unit tests better.
-
Collect some traces that we know are good and use those for unit testing the analyzer. This should not be too hard, however, it just has to be done.
-
Find a way to test the capture side of things without using hardware. Might require substantial decoupling. Maybe exchange the serial backend of ChipWhisperer with a class that acts like a serial device. Then we could check is the serial messages are the ones we expect when using the API.
-
Increase coverage. This is related to the other improvements as they have to be partially completed before unit test coverage can expand drastically.
Unit tests can be found in the chipwhisperer/tests
directory. There is no
auto discover script yet so just run:
cd chipwhisperer/tests
python test_api.py
Footnotes
-
This mix exists for historical reasons: API documentation originated in .rst, hardware documentation originated in .md. Jupyter Book was chosen in part for its good support for both of these, as well as the notebooks that are used in our Tips & Tricks. ↩