Skip to content

Commit

Permalink
Initial commit of the public Pinata source code
Browse files Browse the repository at this point in the history
  • Loading branch information
rwols committed Feb 7, 2024
0 parents commit 41b1d3b
Show file tree
Hide file tree
Showing 215 changed files with 78,039 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* text=auto
*.sh text eol=lf
39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
on:
push:
branches:
- main
paths-ignore:
- README.md
pull_request:
branches:
- main
paths-ignore:
- README.md

jobs:
ubuntu:
runs-on: ubuntu-latest

steps:
# Install system packages.
- name: Install system packages
run: sudo apt-get update && sudo apt-get install gcc-arm-none-eabi ninja-build libssl-dev libgtest-dev libboost-dev dfu-util

# Checkout the repository.
- uses: actions/checkout@v4
with:
submodules: recursive

# Compile firmware.
- name: Configure firmware
run: cmake -DCMAKE_TOOLCHAIN_FILE=gcc-arm-none-eabi.toolchain.cmake -DCMAKE_INSTALL_PREFIX=$(pwd)/build/firmware -GNinja -S. -Bbuild
- name: Build firmware
run: cmake --build ./build
- name: Prepare firmware
run: cmake --build ./build --target install

# Compile test driver.
- name: Configure test runner
run: cmake -DCMAKE_BUILD_TYPE=Debug -SPinataTests -BPinataTests/build -GNinja
- name: Build test runner
run: cmake --build ./PinataTests/build
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
build/
*.o
*.bin
*.dfu
*.elf

3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "PinataTests/PQClean"]
path = PinataTests/PQClean
url = https://github.com/PQClean/PQClean.git
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.16)
project(Pinata VERSION 3.2 LANGUAGES C ASM)

if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
message(STATUS "Setting CMAKE_BUILD_TYPE to MinSizeRel")
set(CMAKE_BUILD_TYPE MinSizeRel)
endif()

add_subdirectory(src)
32 changes: 32 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
The Clear BSD License

Copyright (c) 2024 Riscure B.V.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the disclaimer
below) provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
4 changes: 4 additions & 0 deletions PinataTests/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
ColumnLimit: 120
IndentWidth: 4
...
9 changes: 9 additions & 0 deletions PinataTests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
dilithium3_round2/
dilithium3_round3/
kyber512_round3/
fuzz-dilithium
fuzz-kyber
crash-*
*.json
.cache
build/
45 changes: 45 additions & 0 deletions PinataTests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 3.16)
project(PinataTests C CXX)

find_package(OpenSSL REQUIRED)
find_package(GTest REQUIRED)
find_package(Boost REQUIRED)

set(DILITHIUM PQClean/crypto_sign/dilithium3/clean)
set(KYBER PQClean/crypto_kem/kyber512/clean)

add_executable(PinataTests
main.cpp
dilithium/test-dilithium.cpp
kyber/test-kyber.cpp
tests/Environment.cpp
tests/PinataTests.cpp
utilities/common.cpp
#COMMON
PQClean/common/fips202.c
PQClean/common/randombytes.c
PQClean/common/aes.c
#DILITHIUM
${DILITHIUM}/packing.c
${DILITHIUM}/ntt.c
${DILITHIUM}/poly.c
${DILITHIUM}/polyvec.c
${DILITHIUM}/reduce.c
${DILITHIUM}/rounding.c
${DILITHIUM}/sign.c
${DILITHIUM}/symmetric-shake.c
#KYBER
${KYBER}/indcpa.c
${KYBER}/polyvec.c
${KYBER}/reduce.c
${KYBER}/kem.c
${KYBER}/ntt.c
${KYBER}/cbd.c
${KYBER}/poly.c
${KYBER}/verify.c
${KYBER}/symmetric-shake.c
)

target_compile_features(PinataTests PRIVATE cxx_std_20)
target_include_directories(PinataTests PRIVATE PQClean/common)
target_link_libraries(PinataTests PRIVATE Boost::boost OpenSSL::Crypto GTest::GTest)
1 change: 1 addition & 0 deletions PinataTests/PQClean
Submodule PQClean added at 4f86c3
73 changes: 73 additions & 0 deletions PinataTests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Testing the Pinata

This project is for testing ciphers on Pinata.

## Step 1

Run

```sh
git submodule update --init --recursive
```

To initialize and fetch PQClean repo

## Step 2

For Debian/Ubuntu, install the following system packages:

```sh
apt install libboost-dev libssl-dev libgtest-dev
```

It's possible you may be able to use a different clang version. In that case, you will have to modify the `Makefile` to modify the clang version to your specific version.

To be able to run and debug tests in VSCode (or any other text editor with LSP capabilities), install the following packages:


```sh
apt install clangd
```

## Step 3

Compile the tests

```sh
cmake -S. -Bbuild -DCMAKE_EXPORT_COMPILE_COMMANDS=ON && cd build && make
```

Enabling the option `CMAKE_EXPORT_COMPILE_COMMANDS` is optional. It creates the JSON compilation database (a file named `compile_commands.json`), which clangd will use for code autocompletion, navigation and suggestions.

## Step 4

Let the Test Application know what serial port to use. Set and export an environment variable called `SERIAL_PORT` in your shell. For example, at the time of writing this was my serial port used for my physical Pinata:

```sh
export SERIAL_PORT=/dev/serial/by-id/usb-FTDI_TTL232R-3V3_FT9S6WRO-if00-port0
```

## Step 5

Run the tests

```sh
./build/PinataTests
```

To see the list of all test cases:

```sh
./build/PinataTests --gtest_list_tests
```

To run a specific test case of the test suite:

```sh
./build/PinataTests --gtest_filter=test128AESSWEncrypt
```

Note that wildcards work for filtering test cases. For example, `/build/PinataTests --gtest_filter=test128AES* ` will run all 128AES tests.

Run `./build/PinataTests --help` for help.

109 changes: 109 additions & 0 deletions PinataTests/dilithium/test-dilithium.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include "test-dilithium.hpp"
#include <optional>


extern "C" {
#include "../PQClean/crypto_sign/dilithium3/clean/api.h"
}

#if DILITHIUM_PUBLIC_KEY_SIZE != PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_PUBLICKEYBYTES
#error invalid public key size, update me!
#endif
#if DILITHIUM_PRIVATE_KEY_SIZE != PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_SECRETKEYBYTES
#error invalid private key size, update me!
#endif
#if DILITHIUM_SIGNATURE_SIZE != PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES
#error invalid signature size, update me!
#endif

#if defined(MODE) && !defined(DILITHIUM_MODE)
#define DILITHIUM_MODE MODE
#endif


DilithiumGlobalState::DilithiumGlobalState() {
// Ensure we're talking to a modern Pinata
std::cout << "reading pinata device version...\n";
const auto [deviceMajorVersion, deviceMinorVersion] = pinata.getVersion();
if (deviceMajorVersion != PinataVersionMajor) {
throw std::runtime_error("expected pinata major version 3");
}
if (deviceMinorVersion != PinataVersionMinor) {
throw std::runtime_error("expected pinata minor version 2");
}

// Ensure the mode is the same
std::cout << "ensuring dilithium modes agree\n";
if (pinata.dilithiumGetSecurityLevel() != 3) {
throw std::runtime_error("pinata dilithium mode is not equal to " + std::to_string(3));
}

// Ensure public and private key sizes match
std::cout << "ensuring dilithium public and private key sizes agree\n";
const auto [pinataPublicKeySize, pinataPrivateKeySize] = pinata.dilithiumGetKeySizes();
if (pinataPublicKeySize != PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_PUBLICKEYBYTES) {
throw std::runtime_error("mismatching public key sizes (pinata: " + std::to_string(pinataPublicKeySize) +
", reference impl: " + std::to_string(PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_PUBLICKEYBYTES) + ")");
}
if (pinataPrivateKeySize != PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_SECRETKEYBYTES) {
throw std::runtime_error("mismatching private key sizes (pinata: " + std::to_string(pinataPrivateKeySize) +
", reference impl: " + std::to_string(PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_SECRETKEYBYTES) + ")");
}

// Generate a public/private key pair with the reference X86 implementation
PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_keypair(m_publicKey.data(), m_privateKey.data());

// Tell the pinata to use this public/private key pair for signing with Dilithium3
std::cout << "setting public and private key on Pinata (public key size: " << std::dec << PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_PUBLICKEYBYTES
<< ", private key size: " << PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_SECRETKEYBYTES << ")\n";
pinata.dilithiumSetPublicPrivateKeyPair(m_publicKey.data(), m_publicKey.size(), m_privateKey.data(), m_privateKey.size());
}

std::optional<DilithiumGlobalState> dg_state;

std::array<unsigned char, DILITHIUM_MESSAGE_SIZE> message;
std::array<unsigned char, PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES + DILITHIUM_MESSAGE_SIZE> pinataSignedMessage;
std::array<unsigned char, PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES + DILITHIUM_MESSAGE_SIZE> referenceSignedMessage;


extern "C" int TestDilithiumOneInput(const uint8_t *data, size_t size) {

// ensure global state object is initialized
if (!dg_state.has_value()) {
std::cout << "setting up global state\n";
dg_state.emplace();
std::cout << "created state\n";
}

// Prepare the fuzzed message
std::fill(pinataSignedMessage.begin(), pinataSignedMessage.end(), (unsigned char)0);
std::fill(message.begin(), message.end(), (unsigned char)0);
std::copy(data, data + std::min(message.size(), size), message.begin());
std::cout << "message: " << message << '\n';

// Sign the fuzzed message on pinata
dg_state->pinata.dilithiumSign(message.data(), message.size(), pinataSignedMessage.data(), PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES);
// Concatenate the signature and the fuzzed message together to obtain a "signed message"
assert(pinataSignedMessage.size() == PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES + message.size());

std::copy(message.begin(), message.end(), pinataSignedMessage.data() + PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES);
// The message should be at the end of the signed message buffer
assert(std::memcmp(pinataSignedMessage.data() + PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES, message.begin(), 16) == 0);

// Sign the fuzzed message with the X86 reference implementation.
// The reference implementation doesn't use randomized signatures.
unsigned long messageLength = static_cast<unsigned long>(pinataSignedMessage.size());
PQCLEAN_DILITHIUM3_CLEAN_crypto_sign(referenceSignedMessage.data(), &messageLength, message.data(), message.size(),
dg_state->getPrivateKey().data());

assert(messageLength == referenceSignedMessage.size());

// Pinata sign --> Reference verify
assert(PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_open(pinataSignedMessage.data(), &messageLength, pinataSignedMessage.data(),
pinataSignedMessage.size(), dg_state->getPublicKey().data()) == 0);

// Reference sign --> Pinata verify
assert(dg_state->pinata.dilithiumVerify(referenceSignedMessage.data(), referenceSignedMessage.size()));

return 0;
}
27 changes: 27 additions & 0 deletions PinataTests/dilithium/test-dilithium.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once


#include <boost/algorithm/string/join.hpp>
#include "../utilities/common.hpp"


#define DILITHIUM_PUBLIC_KEY_SIZE 1952
#define DILITHIUM_PRIVATE_KEY_SIZE 4016
#define DILITHIUM_SIGNATURE_SIZE 3293
#define DILITHIUM_MESSAGE_SIZE 16
#define DILITHIUM_SIGNED_MESSAGE_SIZE (DILITHIUM_SIGNATURE_SIZE + DILITHIUM_MESSAGE_SIZE)


class DilithiumGlobalState {
public:
DilithiumGlobalState();
const std::array<unsigned char, DILITHIUM_PUBLIC_KEY_SIZE>& getPublicKey() const noexcept { return m_publicKey; }
const std::array<unsigned char, DILITHIUM_PRIVATE_KEY_SIZE>& getPrivateKey() const noexcept { return m_privateKey; }
PinataClient pinata;

private:
std::array<unsigned char, DILITHIUM_PUBLIC_KEY_SIZE> m_publicKey;
std::array<unsigned char, DILITHIUM_PRIVATE_KEY_SIZE> m_privateKey;
};

extern "C" int TestDilithiumOneInput(const uint8_t* data, size_t size);
Loading

0 comments on commit 41b1d3b

Please sign in to comment.