fw: Import tkey-libs fw-2

This is an import of the fw-2 tag of tkey-libs.

We import the entire tkey-libs repo minus dot files into the
tillitis-key1 repo to make it very simple not to make mistakes
regarding which firmware tag depends on which tkey-libs tag,
especially considering locking down with NVCM.

Please see README for information about developing with another
tkey-libs or how to import future tkey-libs.

Since tkey-libs is now a part of the repo we also add tkey-libs to the
clean_fw target.
This commit is contained in:
Michael Cardell Widerkrantz 2025-03-11 13:16:56 +01:00
parent 59b5360bcb
commit 3875508d1f
No known key found for this signature in database
GPG Key ID: D3DB3DDF57E704E5
38 changed files with 5973 additions and 0 deletions

3
.gitignore vendored
View File

@ -28,6 +28,9 @@
/testbench_verilator*
/check.smt2
/check.vcd
/hw/application_fpga/tkey-libs/libcommon.a
/hw/application_fpga/tkey-libs/libcrt0.a
/hw/application_fpga/tkey-libs/libmonocypher.a
synth.json
synth.txt
synth.v

View File

@ -70,6 +70,39 @@ Note that the TP1 is only used for provisioning the FPGA bitstream
into flash or the FPGA configuration memory. It's not necessary if you
just want to develop apps for the TKey.
We use the tkey-libs libraries used for device app development in the
firmware, too:
https://github.com/tillitis/tkey-libs
but keep our own copy of it in the repo. See below.
## Updating and working with tkey-libs
A copy of [tkey-libs](https://github.com/tillitis/tkey-libs) is kept
in `hw/application_fpga/tkey-libs`. This is mostly to avoid the
subtleties of Git submodules.
If you want to change something in tkey-libs, always change in the
upstream library at:
https://github.com/tillitis/tkey-libs
You can build with an out-of-tree copy if you set `LIBDIR`, for
example:
```
make LIBDIR=~/git/tkey-libs firmware.elf
```
When it's time to update the in-tree tkey-lib first tag the upstream
repo with an `fw` prefix, like `fw-1` even if it already has an
official version tag.
Easiest is probably to just remove the tkey-libs directory and then
git clone the desired tag. Use the entire repo, but remove the .-files
like `.git`, `.github`, et cetera.
## Measured boot
The key behind guaranteeing security even as a general computer is the

View File

@ -492,6 +492,7 @@ clean_fw:
rm -f testfw.{elf,map,bin,hex}
rm -f $(TESTFW_OBJS)
rm -f qemu_firmware.elf
make -C tkey-libs clean
.PHONY: clean_fw
clean_sim:

View File

@ -0,0 +1,26 @@
BSD 2-Clause License
Copyright 2022 Tillitis AB <tillitis.se>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,24 @@
Copyright 2022 Tillitis AB <tillitis.se>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@ -0,0 +1,94 @@
OBJCOPY ?= llvm-objcopy
CC = clang
INCLUDE=include
# Set QEMU_DEBUG and TKEY_DEBUG below when compiling tkey-libs if you
# want debug prints from tkey-libs functions.
#
# - QEMU_DEBUG: the debug port on our qemu emulator
#
# - TKEY_DEBUG: The extra HID endpoint on a real TKey which you can
# listen on for debug prints.
#
# NOTE WELL: If you just want debug prints on either of them in *your
# own device app* you just need to include tkey/debug.h and define
# either of them. You don't need to recompile tkey-libs.
CFLAGS = -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 \
-mcmodel=medany -static -std=gnu99 -O2 -ffast-math -fno-common \
-fno-builtin-printf -fno-builtin-putchar -nostdlib -mno-relax -flto \
-Wall -Werror=implicit-function-declaration \
-I $(INCLUDE) -I .
AS = clang
AR = llvm-ar
ASFLAGS = -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 \
-mcmodel=medany -mno-relax
LDFLAGS=-T app.lds -L libcommon/ -lcommon -L libcrt0/ -lcrt0
.PHONY: all
all: libcrt0.a libcommon.a libmonocypher.a
IMAGE=ghcr.io/tillitis/tkey-builder:4
podman:
podman run --rm --mount type=bind,source=$(CURDIR),target=/src \
-w /src -it $(IMAGE) make -j
.PHONY: check
check:
clang-tidy -header-filter=.* -checks=cert-* libcommon/*.c -- $(CFLAGS)
# C runtime library
libcrt0.a: libcrt0/crt0.o
$(AR) -qc $@ libcrt0/crt0.o
# Common C functions
LIBOBJS=libcommon/assert.o libcommon/blake2s.o libcommon/led.o libcommon/lib.o \
libcommon/proto.o libcommon/touch.o libcommon/io.o
libcommon.a: $(LIBOBJS)
$(AR) -qc $@ $(LIBOBJS)
$(LIBOBJS): include/tkey/assert.h include/tkey/blake2s.h include/tkey/led.h \
include/tkey/lib.h include/tkey/proto.h include/tkey/tk1_mem.h \
include/tkey/touch.h include/tkey/debug.h
# Monocypher
MONOOBJS=monocypher/monocypher.o monocypher/monocypher-ed25519.o
libmonocypher.a: $(MONOOBJS)
$(AR) -qc $@ $(MONOOBJS)
$MONOOBJS: monocypher/monocypher-ed25519.h monocypher/monocypher.h
LIBS=libcrt0.a libcommon.a
.PHONY: clean
clean:
rm -f $(LIBS) $(LIBOBJS) libcrt0/crt0.o
rm -f libmonocypher.a $(MONOOBJS)
# Create compile_commands.json for clangd and LSP
.PHONY: clangd
clangd: compile_commands.json
compile_commands.json:
$(MAKE) clean
bear -- make all
# Uses ../.clang-format
FMTFILES=include/tkey/*.h libcommon/*.c
.PHONY: fmt
fmt:
clang-format --dry-run --ferror-limit=0 $(FMTFILES)
clang-format --verbose -i $(FMTFILES)
.PHONY: checkfmt
checkfmt:
clang-format --dry-run --ferror-limit=0 --Werror $(FMTFILES)
.PHONY: update-mem-include
update-mem-include:
cp -af ../tillitis-key1/hw/application_fpga/fw/tk1_mem.h \
include/tkey/tk1_mem.h
echo "Remember to update header include guard!"

View File

@ -0,0 +1,29 @@
tkey-libs binary distribution
This is the binary distribution of:
https://github.com/tillitis/tkey-libs
Which is an SDK for developing device apps for the Tillitis TKey in C.
Please see the TKey Developer Handbook for more:
https://dev.tillitis.se/
and the company web site:
https://tillitis.se/
You should be able to use this distribution directly in device apps
simply by pointing LIBDIR to where you unpacked this archive:
make LIBDIR=~/Download/tkey-libs
Copyright Tillitis AB.
These programs are free software: you can redistribute it and/or
modify it under the terms of the BSD-2-Clause license.
See LICENSE for the full BSD-2-Clause license text.
Note that Monocypher is Copyright Loup Vaillant and released under CC0
1.0 Universal, see monocypher/LICENSE.

View File

@ -0,0 +1,125 @@
[![ci](https://github.com/tillitis/tkey-libs/actions/workflows/ci.yaml/badge.svg?branch=main&event=push)](https://github.com/tillitis/tkey-libs/actions/workflows/ci.yaml)
# Device libraries for the Tillitis TKey
- C runtime: libcrt0.
- Common C functions including protocol calls: libcommon.
- Cryptographic functions: libmonocypher.
Based on monocypher version 4.0.2
https://github.com/LoupVaillant/Monocypher
Release notes in [RELEASE.md](RELEASE.md).
## Licenses and SPDX tags
Unless otherwise noted, the project sources are copyright Tillitis AB,
licensed under the terms and conditions of the "BSD-2-Clause" license.
See [LICENSE](LICENSE) for the full license text.
Until Oct 8, 2024, the license was GPL-2.0 Only.
External source code we have imported are isolated in their own
directories. They may be released under other licenses. This is noted
with a similar `LICENSE` file in every directory containing imported
sources.
The project uses single-line references to Unique License Identifiers
as defined by the Linux Foundation's [SPDX project](https://spdx.org/)
on its own source files, but not necessarily imported files. The line
in each individual source file identifies the license applicable to
that file.
The current set of valid, predefined SPDX identifiers can be found on
the SPDX License List at:
https://spdx.org/licenses/
We attempt to follow the [REUSE
specification](https://reuse.software/).
## Hardware support
### Bellatrix and earlier
Please note that you need to use `uart_write()` and `uart_read()` for
I/O.
If you want debug prints in QEMU you can still use `write(IO_QEMU,
...)`. Avoid using `write()` in other cases.
## Building
In order to build, you must have the `make`, `clang`, `llvm`, and
`lld` packages installed.
Version 15 or higher of LLVM/Clang is necessary for the RV32IC\_Zmmul
architecture we are using. For more detailed information on the
supported build and development environment, please refer to the
[Developer Handbook](https://dev.tillitis.se/).
## Building using Podman
You can also build the libraries with our OCI image
`ghcr.io/tillitis/tkey-builder`.
The easiest way to build this is if you have `make` installed:
```
make podman
```
You can also specify a different image by using
`IMAGE=localhost/tkey-builder-local`.
Or use Podman directly:
```
podman run --rm --mount type=bind,source=.,target=/src -w /src -it ghcr.io/tillitis/tkey-builder:4 make -j
```
## Minimal application build
You will typically need to link at least the `libcrt0` C runtime
otherwise your program won't even reach `main()`.
We provide a linker script in `apps.lds` which shows the linker the
memory layout.
Minimal compilation would look something like:
```
clang -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 \
-mcmodel=medany -static -std=gnu99 -O2 -ffast-math -fno-common \
-fno-builtin-printf -fno-builtin-putchar -nostdlib -mno-relax -flto \
-Wall -Werror=implicit-function-declaration \
-I ../tkey-libs/include \
-I ../tkey-libs -c -o foo.o foo.c
clang -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 \
-mcmodel=medany -static -ffast-math -fno-common -nostdlib \
-T ../tkey-libs/app.lds \
-L ../tkey-libs -lcrt0 \
-I ../tkey-libs -o foo.elf foo.o
```
## Makefile example
See `example-app/Makefile` for an example Makefile for a simple device
application.
## Debug output
If you want to have debug prints in your program you can use the
`debug_putchar()`, `debug_puts()`, `debug_putinthex()`,
`debug_hexdump()` and friends. See `include/tkey/debug.h` for list of
functions.
These functions will be turned on if you define either of these when
compiling your program and linking with `libcommon`:
- `QEMU_DEBUG`: Uses the special debug port only available in qemu to
print to the qemu console.
- `TKEY_DEBUG`: Uses the extra HID device.
Note that if you use `TKEY_DEBUG` you *must* have something listening
on the corresponding HID device. It's usually the last HID device
created. On Linux, for instance, this means the last reported hidraw
in `dmesg` is the one you should do `cat /dev/hidrawX` on.

View File

@ -0,0 +1,168 @@
# Release notes
## Upcoming release
NOTE WELL! Rewritten I/O functions with new semantics!
### I/O
The Castor TKey hardware supports more USB endpoints:
- CDC - the same thing as older versions.
- HID security token, for FIDO-like apps.
- CTRL, a HID debug port.
The communication is still over a single UART. To differ between the
endpoints we use an internal USB Mode Protocol between programs
running on the PicoRV32 and the CH552 USB Controller.
The I/O functions has changed accordingly. Please use:
- `readselect()` with appropriate bitmask (e.g. `IO_CDC|IO_HID`) to
see if there's anything to read in the endpoints you are interested
in. Data from endpoints not mentioned in the bitmask will be
discarded.
- `read()` is now non-blocking and returns the number of bytes read
from the endpoint you specify, because more might not be available
yet.
- `write()` now takes an endpoint destination.
- We also introduce generic `putchar()`, `puts()`, `puthex()`,
`putinthex()`, and `hexdump()` functions that take a destination
argument.
We recommend you use only these functions for I/O on Castor and going
forward.
For compatibility to develop device apps for the Bellatrix platform
and earlier, use the low-level, blocking function `uart_read()` for
reads and *only* the `IO_UART` and `IO_QEMU` destinations for output
functions like `write()`, `puts()`.
### Debug prints
The optionally built debug prints have changed. You now use
`debug_puts()` et cetera instead of `qemu_*()`.
You define the debug output endpoint when you compile your program by
including `debug.h` and defining `QEMU_DEBUG` for the qemu debug port
or `TKEY_DEBUG` for output on the CTRL HID endpoint. If you don't
define either, they won't appear in your code.
Similiarly, `assert()` now also follows `QEMU_DEBUG` or `TKEY_DEBUG`,
and prints something on either before halting the CPU.
Note that on the Bellatrix platform only `QEMU_DEBUG` works.
## v0.1.2
From now on tkey-libs is licensed under the BSD-2-Clause license,
moving from the previous GPLv2-only.
Note: There is a possibility that this update may impact the generated
CDI for an app that relies on this library. It is recommended to
always check for potential CDI changes for each specific app with
every update. If the generated CDI does change, and if applicable, it
should be clearly communicated to end users to prevent unintentional
changes to their identity.
Changes:
- New license, BSD-2-Clause
- Reuse compliant, see https://reuse.software/
- Fix row alignment in qemu_hexdump
- Update memory map, tk1_mem.h, from canonical tillitis-key1 repo
- Added make target for creating compile_commands.json for clangd
- Added missing include in touch.h
Full changelog:
[v0.1.1...v0.1.2](https://github.com/tillitis/tkey-libs/compare/v0.1.1...v0.1.2)
## v0.1.1
This is a minor release correcting a mistake and syncing with the
latest HW release, TK1-24.03.
Note: There is a possibility that this update may impact the generated
CDI for an app that relies on this library. It is recommended to
always check for potential CDI changes for each specific app with
every update. If the generated CDI does change, and if applicable, it
should be clearly communicated to end users to prevent unintentional
changes to their identity.
Changes:
- Update memory map, tk1_mem.h, to match the latest TK1-24.03 release.
- Default to tkey-builder:4 for the podman target
- Default to have QEMU debug enabled in tkey-libs. Mistakenly removed
in previous release.
- Revise readme accordingly
Full changelog:
[v0.1.0...v0.1.1](https://github.com/tillitis/tkey-libs/compare/v0.1.0...v0.1.1)
## v0.1.0
This release contains some changes that forces applications that use
tkey-libs to be updated to work with this release.
Note: It is highly likely that this update will affect the CDI of the
TKey. It is advised to always verify this for each specific app, for
every update. If the CDI changes, and it is applicable, it should be
stated clearly to end users to avoid unknowingly changing the TKey
identity.
Breaking changes:
- Check destination buffer's size for read(). To prevent writing
outside of destination buffer.
- Renaming LED-functions to follow led_*().
Changes:
- New function, secure_wipe(), to clean memory of secret data.
- New function, touch_wait(). Waits for a touch by the user, with
selectable timeout.
- New function, led_get(). Get the value of the applied LED color.
- Upgraded Monocypher to 4.0.2.
- Add variable AR in Makefile to enabling passing llvm-ar from command
line.
- Update example app to use led.h.
- Don't have QEMU debug enabled by default.
- Minor tweaks and formatting.
Full changelog:
[v0.0.2...v0.1.0](https://github.com/tillitis/tkey-libs/compare/v0.0.2...v0.1.0)
## v0.0.2
This release contains some changes that forces applications that use
tkey-libs to be updated to work with this release.
Breaking changes:
- Introducing include hierarchy to make it less generic, e.g.,
`#include <tkey/led.h>`.
- Use stdint.h/stddef.h infavor of types.h.
- Library .a files built on top level to simplify inclusion.
- Upgraded Monocypher to 4.0.1.
- QEMU debug behaviour changed, instead of defining `NODEBUG` to
disable debug, one has to enable it by defining `QEMU_DEBUG`.
Changes:
- Introduce functions to control the LED, led.h and led.c.
- New function, assert() to make an illegal instruction and forcing
the CPU to halt.
- Add functions memcpy_s(), wordcpy_s(), memeq() from firmware
- Adding `const` to MMIO variables and qemu_* functions.
- Minor tweaks, clean up and bugfixes.
Full changelog:
[v0.0.1...v0.0.2](https://github.com/tillitis/tkey-libs/compare/v0.0.1...v0.0.2)
## v0.0.1
Just ripped from
https://github.com/tillitis/tillitis-key1-apps
No semantic changes.

View File

@ -0,0 +1,23 @@
# SPDX-FileCopyrightText: 2024 Tillitis AB <tillitis.se>
# SPDX-License-Identifier: BSD-2-Clause
version = 1
[[annotations]]
path = ".github/workflows/*"
SPDX-FileCopyrightText = "2022 Tillitis AB <tillitis.se>"
SPDX-License-Identifier = "BSD-2-Clause"
[[annotations]]
path = [
".clang-format",
".editorconfig",
".gitignore",
"example-app/Makefile",
"monocypher/README.md",
"Makefile",
"README-DIST.txt",
"README.md",
"RELEASE.md"
]
SPDX-FileCopyrightText = "2022 Tillitis AB <tillitis.se>"
SPDX-License-Identifier = "BSD-2-Clause"

View File

@ -0,0 +1,64 @@
/*
* SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
* SPDX-License-Identifier: BSD-2-Clause
*/
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
MEMORY
{
RAM (rwx) : ORIGIN = 0x40000000, LENGTH = 0x20000 /* 128 KB */
}
SECTIONS
{
.text.init :
{
*(.text.init)
} >RAM
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.srodata) /* .rodata sections (constants, strings, etc.) */
*(.srodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
_etext = .;
_sidata = _etext;
} >RAM
.data : AT (_etext)
{
. = ALIGN(4);
_sdata = .;
. = ALIGN(4);
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.sdata) /* .sdata sections */
*(.sdata*) /* .sdata* sections */
. = ALIGN(4);
_edata = .;
} >RAM
/* Uninitialized data section */
.bss :
{
. = ALIGN(4);
_sbss = .;
*(.bss)
*(.bss*)
*(.sbss)
*(.sbss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >RAM
/* libcrt0/crt0.S inits stack to start just below end of RAM */
}

View File

@ -0,0 +1,33 @@
P := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
LIBDIR ?= $(P)/../
OBJCOPY ?= llvm-objcopy
CC = clang
# If you want debug_puts() etcetera to output something on our QEMU
# debug port, use -DQEMU_DEBUG below, or -DTKEY_DEBUG to use Tkeys USB debug pipe
CFLAGS = -g -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 -mcmodel=medany \
-static -std=gnu99 -O2 -ffast-math -fno-common -fno-builtin-printf \
-fno-builtin-putchar -nostdlib -mno-relax -flto \
-Wall -Werror=implicit-function-declaration \
-I $(LIBDIR)/include -I $(LIBDIR)
# -DQEMU_DEBUG -DTKEY_DEBUG
INCLUDE=$(LIBDIR)/include
LDFLAGS=-T $(LIBDIR)/app.lds -L $(LIBDIR) -lcommon -lcrt0
.PHONY: all
all: blue.bin
# Turn elf into bin for device
%.bin: %.elf
$(OBJCOPY) --input-target=elf32-littleriscv --output-target=binary $^ $@
chmod a-x $@
BLUEOBJS=blue.o
blue.elf: blue.o
$(CC) $(CFLAGS) $(BLUEOBJS) $(LDFLAGS) -I $(LIBDIR) -o $@
.PHONY: clean
clean:
rm -f blue.bin blue.elf $(BLUEOBJS)

View File

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stdint.h>
#include <tkey/led.h>
#include <tkey/tk1_mem.h>
#include <tkey/debug.h>
#define SLEEPTIME 100000
void sleep(uint32_t n)
{
for (volatile int i = 0; i < n; i++);
}
int main(void)
{
debug_puts("Hello, world!\n");
debug_puts("Going to sleep between blinks: ");
debug_putinthex(SLEEPTIME);
debug_lf();
for (;;) {
led_set(LED_RED);
sleep(SLEEPTIME);
led_set(LED_GREEN);
sleep(SLEEPTIME);
led_set(LED_BLUE);
sleep(SLEEPTIME);
}
}

View File

@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#ifndef TKEY_ASSERT_H
#define TKEY_ASSERT_H
#include <tkey/io.h>
#if defined(QEMU_DEBUG)
#define assert(expr) \
((expr) ? (void)(0) \
: assert_fail(IO_QEMU, #expr, __FILE__, __LINE__, __func__))
#elif defined(TKEY_DEBUG)
#define assert(expr) \
((expr) \
? (void)(0) \
: assert_fail(IO_TKEYCTRL, #expr, __FILE__, __LINE__, __func__))
#else
#define assert(expr) ((expr) ? (void)(0) : assert_halt())
#endif
void assert_fail(enum ioend dest, const char *assertion, const char *file,
unsigned int line, const char *function);
void assert_halt(void);
#endif

View File

@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#ifndef TKEY_BLAKE2S_H
#define TKEY_BLAKE2S_H
#include <stddef.h>
#include <stdint.h>
// blake2s state context
typedef struct {
uint8_t b[64]; // input buffer
uint32_t h[8]; // chained state
uint32_t t[2]; // total number of bytes
size_t c; // pointer for b[]
size_t outlen; // digest size
} blake2s_ctx;
int blake2s(void *out, unsigned long outlen, const void *key,
unsigned long keylen, const void *in, unsigned long inlen,
blake2s_ctx *ctx);
#endif

View File

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#ifndef TKEY_DEBUG_H
#define TKEY_DEBUG_H
#include <stdint.h>
#include "io.h"
#if defined(QEMU_DEBUG)
#define debug_putchar(ch) putchar(IO_QEMU, ch)
#define debug_lf() putchar(IO_QEMU, '\n')
#define debug_putinthex(ch) putinthex(IO_QEMU, ch)
#define debug_puts(s) puts(IO_QEMU, s)
#define debug_puthex(ch) puthex(IO_QEMU, ch)
#define debug_hexdump(buf, len) hexdump(IO_QEMU, buf, len)
#elif defined(TKEY_DEBUG)
#define debug_putchar(ch) putchar(IO_TKEYCTRL, ch)
#define debug_lf() putchar(IO_TKEYCTRL, '\n')
#define debug_putinthex(ch) putinthex(IO_TKEYCTRL, ch)
#define debug_puts(s) puts(IO_TKEYCTRL, s)
#define debug_puthex(ch) puthex(IO_TKEYCTRL, ch)
#define debug_hexdump(buf, len) hexdump(IO_TKEYCTRL, buf, len)
#else
#define debug_putchar(ch)
#define debug_lf()
#define debug_putinthex(n)
#define debug_puts(s)
#define debug_puthex(ch)
#define debug_hexdump(buf, len)
#endif
#endif

View File

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stddef.h>
#include <stdint.h>
#ifndef TKEY_IO_H
#define TKEY_IO_H
// I/O endpoints. Keep it as bits possible to use in a bitmask in
// readselect().
//
// Note that the the TKEYCTRL, CDC, and HID should be kept the same on
// the CH552 side.
enum ioend {
IO_NONE = 0x00, // No endpoint
IO_UART = 0x01, // Only destination, raw UART access
IO_QEMU = 0x10, // Only destination, QEMU debug port
IO_TKEYCTRL = 0x20, // HID debug port
IO_CDC = 0x40, // CDC "serial port"
IO_HID = 0x80, // HID security token
};
void write(enum ioend dest, const uint8_t *buf, size_t nbytes);
int read(enum ioend src, uint8_t *buf, size_t bufsize, size_t nbytes);
int uart_read(uint8_t *buf, size_t bufsize, size_t nbytes);
int readselect(int bitmask, enum ioend *endpoint, uint8_t *len);
void putchar(enum ioend dest, const uint8_t ch);
void puthex(enum ioend dest, const uint8_t ch);
void putinthex(enum ioend dest, const uint32_t n);
void puts(enum ioend dest, const char *s);
void hexdump(enum ioend dest, void *buf, int len);
#endif

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#ifndef TKEY_LED_H
#define TKEY_LED_H
#include <stdint.h>
#include <tkey/tk1_mem.h>
// clang-format off
#define LED_BLACK 0
#define LED_RED (1 << TK1_MMIO_TK1_LED_R_BIT)
#define LED_GREEN (1 << TK1_MMIO_TK1_LED_G_BIT)
#define LED_BLUE (1 << TK1_MMIO_TK1_LED_B_BIT)
#define LED_WHITE (LED_RED | LED_GREEN | LED_BLUE)
// clang-format on
uint32_t led_get(void);
void led_set(uint32_t ledvalue);
void led_flash_forever(uint32_t ledvalue);
#endif

View File

@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#ifndef TKEY_LIB_H
#define TKEY_LIB_H
#include <stddef.h>
#include <stdint.h>
void *memset(void *dest, int c, unsigned n);
void *memcpy(void *dest, const void *src, unsigned n);
void memcpy_s(void *dest, size_t destsize, const void *src, size_t n);
void *wordcpy(void *dest, const void *src, unsigned n);
void wordcpy_s(void *dest, size_t destsize, const void *src, size_t n);
int memeq(void *dest, const void *src, size_t n);
void secure_wipe(void *v, size_t n);
size_t strlen(const char *str);
#endif

View File

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stddef.h>
#include <stdint.h>
#ifndef TKEY_PROTO_H
#define TKEY_PROTO_H
enum endpoints {
DST_HW_IFPGA = 0x00,
DST_HW_AFPGA = 0x01,
DST_FW = 0x02,
DST_SW = 0x03
};
enum cmdlen {
LEN_1,
LEN_4,
LEN_32,
LEN_128
};
#define CMDLEN_MAXBYTES 128
enum status {
STATUS_OK,
STATUS_BAD
};
struct frame_header {
uint8_t id;
enum endpoints endpoint;
size_t len;
};
uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, enum cmdlen len);
int parseframe(uint8_t b, struct frame_header *hdr);
#endif

View File

@ -0,0 +1,148 @@
/*
* Tillitis TKey Memory Map
*
* SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
* SPDX-License-Identifier: BSD-2-Clause
*
* Note that this file is also in tillitis-key1 and qemu
* (GPL-2.0-or-later). Needs to stay in sync and have a compatible
* license.
*/
// clang-format off
#ifndef TKEY_TK1_MEM_H
#define TKEY_TK1_MEM_H
/*
The canonical location of this file is in:
https://github.com/tillitis/tkey-libs
Under:
include/tkey/tk1_mem.h
The contents are mostly derived from the Verilog code in
https://github.com/tillitis/tillitis-key1
Memory map
Top level prefix, the first 2 bits in a 32-bit address:
name prefix address length
--------------------------------------------------------
ROM 0b00 30 bit address
RAM 0b01 30 bit address
Reserved 0b10
Cores 0b11 6 bits for core select, 24 bits rest
Address Prefix, the first 8 bits in a 32-bit address:
name prefix
--------------------
ROM 0x00
RAM 0x40
TRNG 0xc0
TIMER 0xc1
UDS 0xc2
UART 0xc3
TOUCH 0xc4
FW_RAM 0xd0
QEMU 0xfe Not used in real hardware
TK1 0xff
*/
#define TK1_ROM_BASE 0x00000000
#define TK1_ROM_SIZE 0x2000
#define TK1_RAM_BASE 0x40000000
#define TK1_RAM_SIZE 0x20000
#define TK1_MMIO_BASE 0xc0000000
#define TK1_MMIO_SIZE 0x3fffffff
#define TK1_APP_MAX_SIZE 0x20000
#define TK1_MMIO_FW_RAM_BASE 0xd0000000
// FW_RAM is 4096 bytes
#define TK1_MMIO_FW_RAM_SIZE 0x1000
#define TK1_MMIO_TRNG_BASE 0xc0000000
#define TK1_MMIO_TRNG_STATUS 0xc0000024
#define TK1_MMIO_TRNG_STATUS_READY_BIT 0
#define TK1_MMIO_TRNG_ENTROPY 0xc0000080
#define TK1_MMIO_TIMER_BASE 0xc1000000
#define TK1_MMIO_TIMER_CTRL 0xc1000020
#define TK1_MMIO_TIMER_CTRL_START_BIT 0
#define TK1_MMIO_TIMER_CTRL_STOP_BIT 1
#define TK1_MMIO_TIMER_STATUS 0xc1000024
#define TK1_MMIO_TIMER_STATUS_RUNNING_BIT 0
#define TK1_MMIO_TIMER_PRESCALER 0xc1000028
#define TK1_MMIO_TIMER_TIMER 0xc100002c
#define TK1_MMIO_UDS_BASE 0xc2000000
#define TK1_MMIO_UDS_FIRST 0xc2000000
#define TK1_MMIO_UDS_LAST 0xc200001c
#define TK1_MMIO_UART_BASE 0xc3000000
#define TK1_MMIO_UART_RX_STATUS 0xc3000080
#define TK1_MMIO_UART_RX_DATA 0xc3000084
#define TK1_MMIO_UART_RX_BYTES 0xc3000088
#define TK1_MMIO_UART_TX_STATUS 0xc3000100
#define TK1_MMIO_UART_TX_DATA 0xc3000104
#define TK1_MMIO_TOUCH_BASE 0xc4000000
#define TK1_MMIO_TOUCH_STATUS 0xc4000024
#define TK1_MMIO_TOUCH_STATUS_EVENT_BIT 0
// This only exists in QEMU, not real hardware
#define TK1_MMIO_QEMU_BASE 0xfe000000
#define TK1_MMIO_QEMU_DEBUG 0xfe001000
#define TK1_MMIO_TK1_BASE 0xff000000
#define TK1_MMIO_TK1_NAME0 0xff000000
#define TK1_MMIO_TK1_NAME1 0xff000004
#define TK1_MMIO_TK1_VERSION 0xff000008
#define TK1_MMIO_TK1_LED 0xff000024
#define TK1_MMIO_TK1_LED_R_BIT 2
#define TK1_MMIO_TK1_LED_G_BIT 1
#define TK1_MMIO_TK1_LED_B_BIT 0
#define TK1_MMIO_TK1_GPIO 0xff000028
#define TK1_MMIO_TK1_GPIO1_BIT 0
#define TK1_MMIO_TK1_GPIO2_BIT 1
#define TK1_MMIO_TK1_GPIO3_BIT 2
#define TK1_MMIO_TK1_GPIO4_BIT 3
#define TK1_MMIO_TK1_APP_ADDR 0xff000030
#define TK1_MMIO_TK1_APP_SIZE 0xff000034
#define TK1_MMIO_TK1_CDI_FIRST 0xff000080
#define TK1_MMIO_TK1_CDI_LAST 0xff00009c
#define TK1_MMIO_TK1_UDI_FIRST 0xff0000c0
#define TK1_MMIO_TK1_UDI_LAST 0xff0000c4
// Deprecated - use _ADDR_RAND instead
#define TK1_MMIO_TK1_RAM_ASLR 0xff000100
#define TK1_MMIO_TK1_RAM_ADDR_RAND 0xff000100
// Deprecated - use _DATA_RAND instead
#define TK1_MMIO_TK1_RAM_SCRAMBLE 0xff000104
#define TK1_MMIO_TK1_RAM_DATA_RAND 0xff000104
#define TK1_MMIO_TK1_CPU_MON_CTRL 0xff000180
#define TK1_MMIO_TK1_CPU_MON_FIRST 0xff000184
#define TK1_MMIO_TK1_CPU_MON_LAST 0xff000188
#define TK1_MMIO_TK1_SYSTEM_RESET 0xff0001C0
#define TK1_MMIO_TK1_SPI_EN 0xff000200
#define TK1_MMIO_TK1_SPI_XFER 0xff000204
#define TK1_MMIO_TK1_SPI_DATA 0xff000208
#endif

View File

@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#ifndef TKEY_TOUCH_H
#define TKEY_TOUCH_H
#include <stdbool.h>
#include <stdint.h>
#include <tkey/tk1_mem.h>
// touchwait() waits for a touch event while blinking color on the
// status LED. timeout_s is the timeout in seconds.
//
// If a touch event occurs it returns true. If the timeout expires it
// returns false.
bool touch_wait(int color, int timeout_s);
#endif

View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <tkey/assert.h>
#include <tkey/io.h>
#include <tkey/lib.h>
void assert_fail(enum ioend dest, const char *assertion, const char *file,
unsigned int line, const char *function)
{
puts(dest, "assert: ");
puts(dest, assertion);
puts(dest, " ");
puts(dest, file);
puts(dest, ":");
putinthex(dest, line);
puts(dest, " ");
puts(dest, function);
puts(dest, "\n");
// Force illegal instruction to halt CPU
asm volatile("unimp");
// Not reached
__builtin_unreachable();
}
void assert_halt(void)
{
// Force illegal instruction to halt CPU
asm volatile("unimp");
// Not reached
__builtin_unreachable();
}

View File

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stdint.h>
#include <tkey/blake2s.h>
#include <tkey/tk1_mem.h>
int blake2s(void *out, unsigned long outlen, const void *key,
unsigned long keylen, const void *in, unsigned long inlen,
blake2s_ctx *ctx)
{
// Not implemented.
return -1;
}

View File

@ -0,0 +1,350 @@
// SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stdint.h>
#include <tkey/assert.h>
#include <tkey/debug.h>
#include <tkey/lib.h>
#include <tkey/proto.h>
#include <tkey/tk1_mem.h>
// Maximum payload size sent over the USB Mode Protocol.
//
// USB Mode Protocol:
// 1 byte mode
// 1 byte length
//
// Our USB Mode Protocol packets has room for 255 bytes according to
// the header but we send at most 64 bytes of payload + the 2 byte
// header. The header is removed in the USB controller and the maximum
// payload fits in a single USB frame on the other side.
#define USBMODE_PACKET_SIZE 64
static void hex(uint8_t buf[2], const uint8_t c);
static int discard(size_t nbytes);
static uint8_t readbyte(void);
static void writebyte(uint8_t b);
struct usb_mode {
enum ioend endpoint; // Current USB endpoint with data
uint8_t len; // Data available in from current USB mode.
};
static struct usb_mode cur_endpoint = {
IO_NONE,
0,
};
// clang-format off
static volatile uint32_t* const can_rx = (volatile uint32_t *)TK1_MMIO_UART_RX_STATUS;
static volatile uint32_t* const rx = (volatile uint32_t *)TK1_MMIO_UART_RX_DATA;
static volatile uint32_t* const can_tx = (volatile uint32_t *)TK1_MMIO_UART_TX_STATUS;
static volatile uint32_t* const tx = (volatile uint32_t *)TK1_MMIO_UART_TX_DATA;
static volatile uint8_t* const debugtx = (volatile uint8_t *)TK1_MMIO_QEMU_DEBUG;
// clang-format on
// writebyte blockingly writes byte b to UART
static void writebyte(uint8_t b)
{
for (;;) {
if (*can_tx) {
*tx = b;
return;
}
}
}
// write_with_header writes nbytes of buf to UART with a USB Mode
// Protocol header telling the receiver about the mode and length.
static void write_with_header(enum ioend dest, const uint8_t *buf,
size_t nbytes)
{
// USB Mode Protocol header:
// 1 byte mode
// 1 byte length
writebyte(dest);
writebyte(nbytes);
for (int i = 0; i < nbytes; i++) {
writebyte(buf[i]);
}
}
// write blockingly writes nbytes bytes of data from buf to dest which
// is either:
//
// - IO_QEMU: QEMU debug port
//
// - IO_UART: Low-level UART access, no USB Mode Header added.
//
// - IO_CDC: Through the UART for the CDC endpoint, with header.
//
// - IO_HID: Through the UART for the HID endpoint, with header.
//
// - IO_TKEYCTRL: Through the UART for the debug HID endpoint, with
// header.
void write(enum ioend dest, const uint8_t *buf, size_t nbytes)
{
if (dest == IO_QEMU) {
for (int i = 0; i < nbytes; i++) {
*debugtx = buf[i];
}
return;
} else if (dest == IO_UART) {
for (int i = 0; i < nbytes; i++) {
writebyte(buf[i]);
}
return;
}
while (nbytes > 0) {
// We split the data into chunks that will fit in the
// USB Mode Protocol and fits neatly in the USB frames
// on the other side of the USB controller.
uint8_t len =
nbytes < USBMODE_PACKET_SIZE ? nbytes : USBMODE_PACKET_SIZE;
write_with_header(dest, (const uint8_t *)buf, len);
buf += len;
nbytes -= len;
}
}
// readbyte reads a byte from UART and returns it. Blocking.
static uint8_t readbyte(void)
{
for (;;) {
if (*can_rx) {
return *rx;
}
}
return 0;
}
// read reads into buf of size bufsize from UART, nbytes or less, from
// the current USB endpoint. It doesn't block.
//
// Returns the number of bytes read. Empty data returns 0.
int read(enum ioend src, uint8_t *buf, size_t bufsize, size_t nbytes)
{
if (buf == NULL || nbytes > bufsize) {
return -1;
}
if (src == IO_NONE || src == IO_UART || src == IO_QEMU) {
// Destination only endpoints
return -1;
}
if (src != cur_endpoint.endpoint) {
// No data for this source available right now.
return 0;
}
int n = 0;
for (n = 0; n < nbytes; n++) {
buf[n] = readbyte();
cur_endpoint.len--;
}
return n;
}
// uart_read reads blockingly into buf o size bufsize from UART nbytes
// bytes.
//
// Returns negative on error.
int uart_read(uint8_t *buf, size_t bufsize, size_t nbytes)
{
if (nbytes > bufsize) {
return -1;
}
for (int n = 0; n < nbytes; n++) {
buf[n] = readbyte();
}
return 0;
}
// discard nbytes of what's available.
//
// Returns how many bytes were discarded.
static int discard(size_t nbytes)
{
int n = 0;
uint8_t len = nbytes < cur_endpoint.len ? nbytes : cur_endpoint.len;
for (n = 0; n < len; n++) {
(void)readbyte();
cur_endpoint.len--;
}
return n;
}
// readselect blocks and returns when there is something readable from
// some mode.
//
// Use like this:
//
// readselect(IO_CDC|IO_HID, &endpoint, &len)
//
// to wait for some data from either the CDC or the HID endpoint.
//
// NOTE WELL: You need to call readselect() first, before doing any
// calls to read().
//
// Only endpoints available for read are:
//
// - IO_TKEYCTRL
// - IO_CDC
// - IO_HID
//
// If you need blocking low-level UART reads, use uart_read() instead.
//
// Sets endpoint of the first endpoint in the bitmask with data
// available. Indicates how many bytes available in len.
//
// Returns non-zero on error.
int readselect(int bitmask, enum ioend *endpoint, uint8_t *len)
{
if (bitmask & IO_UART || bitmask & IO_QEMU) {
// Not possible to use readselect() on these
// endpoints.
return -1;
}
for (;;) {
// Check what is in the current UART buffer.
//
// - If nothing known, block until something comes along.
//
// - If not in bitmask, discard the data available
// from that endpoint.
//
// - If in the bitmask, return the first endpoint with
// data available and indicate how much data in len.
if (cur_endpoint.len == 0) {
// Read USB Mode Protocol header:
// 1 byte mode
// 1 byte length
cur_endpoint.endpoint = readbyte();
cur_endpoint.len = readbyte();
}
*len = cur_endpoint.len;
if (cur_endpoint.endpoint & bitmask) {
*endpoint = cur_endpoint.endpoint;
return 0;
}
// Not the USB endpoint caller asked for. Discard the
// rest from this endpoint.
if (discard(*len) != *len) {
// We couldn't discard what the USB Mode
// Protocol itself reported was available!
// Something's fishy. Halt.
assert(1 == 2);
}
}
return 0;
}
void putchar(enum ioend dest, const uint8_t ch)
{
write(dest, &ch, 1);
}
static void hex(uint8_t buf[2], const uint8_t c)
{
unsigned int upper = (c >> 4) & 0xf;
unsigned int lower = c & 0xf;
buf[0] = upper < 10 ? '0' + upper : 'a' - 10 + upper;
buf[1] = lower < 10 ? '0' + lower : 'a' - 10 + lower;
}
void puthex(enum ioend dest, const uint8_t c)
{
uint8_t hexbuf[2] = {0};
hex(hexbuf, c);
write(dest, hexbuf, 2);
}
// Size of of a maximum integer in hex text format
#define INTBUFSIZE 10
void putinthex(enum ioend dest, const uint32_t n)
{
uint8_t buf[INTBUFSIZE] = {0};
uint8_t hexbuf[2] = {0};
uint8_t *intbuf = (uint8_t *)&n;
int j = 0;
buf[j++] = '0';
buf[j++] = 'x';
for (int i = 3; i > -1; i--) {
hex(hexbuf, intbuf[i]);
buf[j++] = hexbuf[0];
buf[j++] = hexbuf[1];
}
write(dest, buf, INTBUFSIZE);
}
void puts(enum ioend dest, const char *s)
{
write(dest, (const uint8_t *)s, strlen(s));
}
// Size of a hex row: Contains 16 bytes where each byte is printed as
// 3 characters (hex + hex + space). Every row ends with newline or at
// most CR+LF.
#define FULLROW (16 * 3)
#define ROWBUFSIZE (FULLROW + 2)
void hexdump(enum ioend dest, void *buf, int len)
{
uint8_t rowbuf[ROWBUFSIZE] = {0};
uint8_t hexbuf[2] = {0};
uint8_t *byte_buf = (uint8_t *)buf;
int rowpos = 0;
for (int i = 0; i < len; i++) {
hex(hexbuf, byte_buf[i]);
rowbuf[rowpos++] = hexbuf[0];
rowbuf[rowpos++] = hexbuf[1];
rowbuf[rowpos++] = ' ';
// If the row is full, print it now.
if (rowpos == FULLROW) {
if (dest == IO_CDC) {
rowbuf[rowpos++] = '\r';
}
rowbuf[rowpos++] = '\n';
write(dest, rowbuf, rowpos);
rowpos = 0;
}
}
// If final row wasn't full, print it now.
if (rowpos != 0) {
if (dest == IO_CDC) {
rowbuf[rowpos++] = '\r';
}
rowbuf[rowpos++] = '\n';
write(dest, rowbuf, rowpos);
}
}

View File

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stdint.h>
#include <tkey/led.h>
// clang-format off
static volatile uint32_t* const led = (volatile uint32_t *)TK1_MMIO_TK1_LED;
// clang-format on
void led_set(uint32_t ledvalue)
{
*led = ledvalue;
}
uint32_t led_get()
{
return *led;
}
void led_flash_forever(uint32_t ledvalue)
{
int led_on = 0;
for (;;) {
*led = led_on ? ledvalue : LED_BLACK;
for (volatile int i = 0; i < 800000; i++) {
}
led_on = !led_on;
}
}

View File

@ -0,0 +1,101 @@
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stdint.h>
#include <tkey/assert.h>
#include <tkey/lib.h>
#include <tkey/tk1_mem.h>
void *memset(void *dest, int c, unsigned n)
{
uint8_t *s = dest;
for (; n; n--, s++)
*s = c;
return dest;
}
__attribute__((used)) void *memcpy(void *dest, const void *src, unsigned n)
{
uint8_t *src_byte = (uint8_t *)src;
uint8_t *dest_byte = (uint8_t *)dest;
for (int i = 0; i < n; i++) {
dest_byte[i] = src_byte[i];
}
return dest;
}
void memcpy_s(void *dest, size_t destsize, const void *src, size_t n)
{
assert(dest != NULL);
assert(src != NULL);
assert(destsize >= n);
uint8_t *src_byte = (uint8_t *)src;
uint8_t *dest_byte = (uint8_t *)dest;
for (size_t i = 0; i < n; i++) {
dest_byte[i] = src_byte[i];
}
}
__attribute__((used)) void *wordcpy(void *dest, const void *src, unsigned n)
{
uint32_t *src_word = (uint32_t *)src;
uint32_t *dest_word = (uint32_t *)dest;
for (int i = 0; i < n; i++) {
dest_word[i] = src_word[i];
}
return dest;
}
void wordcpy_s(void *dest, size_t destsize, const void *src, size_t n)
{
assert(dest != NULL);
assert(src != NULL);
assert(destsize >= n);
uint32_t *src_word = (uint32_t *)src;
uint32_t *dest_word = (uint32_t *)dest;
for (size_t i = 0; i < n; i++) {
dest_word[i] = src_word[i];
}
}
int memeq(void *dest, const void *src, size_t n)
{
uint8_t *src_byte = (uint8_t *)src;
uint8_t *dest_byte = (uint8_t *)dest;
int res = -1;
for (size_t i = 0; i < n; i++) {
if (dest_byte[i] != src_byte[i]) {
res = 0;
}
}
return res;
}
void secure_wipe(void *v, size_t n)
{
volatile uint8_t *p = (volatile uint8_t *)v;
while (n--)
*p++ = 0;
}
size_t strlen(const char *str)
{
const char *s;
for (s = str; *s; ++s)
;
return (s - str);
}

View File

@ -0,0 +1,51 @@
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stddef.h>
#include <stdint.h>
#include <tkey/assert.h>
#include <tkey/debug.h>
#include <tkey/proto.h>
#include <tkey/tk1_mem.h>
uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, enum cmdlen len)
{
return (id << 5) | (endpoint << 3) | (status << 2) | len;
}
int parseframe(uint8_t b, struct frame_header *hdr)
{
if ((b & 0x80) != 0) {
// Bad version
return -1;
}
if ((b & 0x4) != 0) {
// Must be 0
return -1;
}
hdr->id = (b & 0x60) >> 5;
hdr->endpoint = (b & 0x18) >> 3;
// Length
switch (b & 0x3) {
case LEN_1:
hdr->len = 1;
break;
case LEN_4:
hdr->len = 4;
break;
case LEN_32:
hdr->len = 32;
break;
case LEN_128:
hdr->len = 128;
break;
default:
// Unknown length
return -1;
}
return 0;
}

View File

@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stdbool.h>
#include <tkey/debug.h>
#include <tkey/led.h>
#include <tkey/touch.h>
// CPU clock frequenzy in Hz
#define CPUFREQ 18000000
// clang-format off
static volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER;
static volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER;
static volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS;
static volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
static volatile uint32_t *touch = (volatile uint32_t *)TK1_MMIO_TOUCH_STATUS;
// clang-format on
// Returns !0 if touch sensor has been touched
#define touched() (*touch & (1 << TK1_MMIO_TOUCH_STATUS_EVENT_BIT))
bool touch_wait(int color, int timeout_s)
{
int ledon = 0;
int orig_color = led_get();
uint32_t time = 0;
uint32_t lasttime = 0;
// Tick once every decisecond
*timer_prescaler = CPUFREQ / 10;
*timer = timeout_s * 10; // Seconds
// Start timer
*timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
// Acknowledge any stray touch events before waiting for real
// touch
*touch = 0;
// Blink until either the touch sensor has been touched or the
// timer hits 0.
while (!touched() && *timer_status != 0) {
time = *timer;
if (time % 2 == 0 && time != lasttime) {
lasttime = time;
ledon = !ledon;
led_set(ledon ? color : LED_BLACK);
}
}
// Restore LED
led_set(orig_color);
// Do we have a timeout?
if (*timer_status == 0) {
return false;
}
// Stop timer
*timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT);
// Confirm touch event
*touch = 0;
return true;
}

View File

@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
.section ".text.init"
.global _start
_start:
li x1, 0
li x2, 0
li x3, 0
li x4, 0
li x5, 0
li x6, 0
li x7, 0
li x8, 0
li x9, 0
li x10,0
li x11,0
li x12,0
li x13,0
li x14,0
li x15,0
li x16,0
li x17,0
li x18,0
li x19,0
li x20,0
li x21,0
li x22,0
li x23,0
li x24,0
li x25,0
li x26,0
li x27,0
li x28,0
li x29,0
li x30,0
li x31,0
/* init stack below 0x40020000 (TK1_RAM_BASE+TK1_RAM_SIZE) */
li sp, 0x4001fff0
/* zero-init bss section */
la a0, _sbss
la a1, _ebss
bge a0, a1, end_init_bss
loop_init_bss:
sw zero, 0(a0)
addi a0, a0, 4
blt a0, a1, loop_init_bss
end_init_bss:
call main

View File

@ -0,0 +1,116 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@ -0,0 +1,5 @@
# Monocypher
A ed25519 implementation from https://github.com/LoupVaillant/Monocypher
Small changes made for building.

View File

@ -0,0 +1,500 @@
// Monocypher version 4.0.2
//
// This file is dual-licensed. Choose whichever licence you want from
// the two licences listed below.
//
// The first licence is a regular 2-clause BSD licence. The second licence
// is the CC-0 from Creative Commons. It is intended to release Monocypher
// to the public domain. The BSD licence serves as a fallback option.
//
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
//
// ------------------------------------------------------------------------
//
// Copyright (c) 2017-2019, Loup Vaillant
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ------------------------------------------------------------------------
//
// Written in 2017-2019 by Loup Vaillant
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along
// with this software. If not, see
// <https://creativecommons.org/publicdomain/zero/1.0/>
#include "monocypher-ed25519.h"
#ifdef MONOCYPHER_CPP_NAMESPACE
namespace MONOCYPHER_CPP_NAMESPACE {
#endif
/////////////////
/// Utilities ///
/////////////////
#define FOR(i, min, max) for (size_t i = min; i < max; i++)
#define COPY(dst, src, size) FOR(_i_, 0, size) (dst)[_i_] = (src)[_i_]
#define ZERO(buf, size) FOR(_i_, 0, size) (buf)[_i_] = 0
#define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx)))
#define WIPE_BUFFER(buffer) crypto_wipe(buffer, sizeof(buffer))
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
typedef uint8_t u8;
typedef uint64_t u64;
// Returns the smallest positive integer y such that
// (x + y) % pow_2 == 0
// Basically, it's how many bytes we need to add to "align" x.
// Only works when pow_2 is a power of 2.
// Note: we use ~x+1 instead of -x to avoid compiler warnings
static size_t align(size_t x, size_t pow_2)
{
return (~x + 1) & (pow_2 - 1);
}
static u64 load64_be(const u8 s[8])
{
return((u64)s[0] << 56)
| ((u64)s[1] << 48)
| ((u64)s[2] << 40)
| ((u64)s[3] << 32)
| ((u64)s[4] << 24)
| ((u64)s[5] << 16)
| ((u64)s[6] << 8)
| (u64)s[7];
}
static void store64_be(u8 out[8], u64 in)
{
out[0] = (in >> 56) & 0xff;
out[1] = (in >> 48) & 0xff;
out[2] = (in >> 40) & 0xff;
out[3] = (in >> 32) & 0xff;
out[4] = (in >> 24) & 0xff;
out[5] = (in >> 16) & 0xff;
out[6] = (in >> 8) & 0xff;
out[7] = in & 0xff;
}
static void load64_be_buf (u64 *dst, const u8 *src, size_t size) {
FOR(i, 0, size) { dst[i] = load64_be(src + i*8); }
}
///////////////
/// SHA 512 ///
///////////////
static u64 rot(u64 x, int c ) { return (x >> c) | (x << (64 - c)); }
static u64 ch (u64 x, u64 y, u64 z) { return (x & y) ^ (~x & z); }
static u64 maj(u64 x, u64 y, u64 z) { return (x & y) ^ ( x & z) ^ (y & z); }
static u64 big_sigma0(u64 x) { return rot(x, 28) ^ rot(x, 34) ^ rot(x, 39); }
static u64 big_sigma1(u64 x) { return rot(x, 14) ^ rot(x, 18) ^ rot(x, 41); }
static u64 lit_sigma0(u64 x) { return rot(x, 1) ^ rot(x, 8) ^ (x >> 7); }
static u64 lit_sigma1(u64 x) { return rot(x, 19) ^ rot(x, 61) ^ (x >> 6); }
static const u64 K[80] = {
0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc,
0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118,
0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694,
0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65,
0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5,
0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70,
0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df,
0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b,
0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30,
0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec,
0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b,
0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178,
0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b,
0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c,
0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817
};
static void sha512_compress(crypto_sha512_ctx *ctx)
{
u64 a = ctx->hash[0]; u64 b = ctx->hash[1];
u64 c = ctx->hash[2]; u64 d = ctx->hash[3];
u64 e = ctx->hash[4]; u64 f = ctx->hash[5];
u64 g = ctx->hash[6]; u64 h = ctx->hash[7];
FOR (j, 0, 16) {
u64 in = K[j] + ctx->input[j];
u64 t1 = big_sigma1(e) + ch (e, f, g) + h + in;
u64 t2 = big_sigma0(a) + maj(a, b, c);
h = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
size_t i16 = 0;
FOR(i, 1, 5) {
i16 += 16;
FOR (j, 0, 16) {
ctx->input[j] += lit_sigma1(ctx->input[(j- 2) & 15]);
ctx->input[j] += lit_sigma0(ctx->input[(j-15) & 15]);
ctx->input[j] += ctx->input[(j- 7) & 15];
u64 in = K[i16 + j] + ctx->input[j];
u64 t1 = big_sigma1(e) + ch (e, f, g) + h + in;
u64 t2 = big_sigma0(a) + maj(a, b, c);
h = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
}
ctx->hash[0] += a; ctx->hash[1] += b;
ctx->hash[2] += c; ctx->hash[3] += d;
ctx->hash[4] += e; ctx->hash[5] += f;
ctx->hash[6] += g; ctx->hash[7] += h;
}
// Write 1 input byte
static void sha512_set_input(crypto_sha512_ctx *ctx, u8 input)
{
size_t word = ctx->input_idx >> 3;
size_t byte = ctx->input_idx & 7;
ctx->input[word] |= (u64)input << (8 * (7 - byte));
}
// Increment a 128-bit "word".
static void sha512_incr(u64 x[2], u64 y)
{
x[1] += y;
if (x[1] < y) {
x[0]++;
}
}
void crypto_sha512_init(crypto_sha512_ctx *ctx)
{
ctx->hash[0] = 0x6a09e667f3bcc908;
ctx->hash[1] = 0xbb67ae8584caa73b;
ctx->hash[2] = 0x3c6ef372fe94f82b;
ctx->hash[3] = 0xa54ff53a5f1d36f1;
ctx->hash[4] = 0x510e527fade682d1;
ctx->hash[5] = 0x9b05688c2b3e6c1f;
ctx->hash[6] = 0x1f83d9abfb41bd6b;
ctx->hash[7] = 0x5be0cd19137e2179;
ctx->input_size[0] = 0;
ctx->input_size[1] = 0;
ctx->input_idx = 0;
ZERO(ctx->input, 16);
}
void crypto_sha512_update(crypto_sha512_ctx *ctx,
const u8 *message, size_t message_size)
{
// Avoid undefined NULL pointer increments with empty messages
if (message_size == 0) {
return;
}
// Align ourselves with word boundaries
if ((ctx->input_idx & 7) != 0) {
size_t nb_bytes = MIN(align(ctx->input_idx, 8), message_size);
FOR (i, 0, nb_bytes) {
sha512_set_input(ctx, message[i]);
ctx->input_idx++;
}
message += nb_bytes;
message_size -= nb_bytes;
}
// Align ourselves with block boundaries
if ((ctx->input_idx & 127) != 0) {
size_t nb_words = MIN(align(ctx->input_idx, 128), message_size) >> 3;
load64_be_buf(ctx->input + (ctx->input_idx >> 3), message, nb_words);
ctx->input_idx += nb_words << 3;
message += nb_words << 3;
message_size -= nb_words << 3;
}
// Compress block if needed
if (ctx->input_idx == 128) {
sha512_incr(ctx->input_size, 1024); // size is in bits
sha512_compress(ctx);
ctx->input_idx = 0;
ZERO(ctx->input, 16);
}
// Process the message block by block
FOR (i, 0, message_size >> 7) { // number of blocks
load64_be_buf(ctx->input, message, 16);
sha512_incr(ctx->input_size, 1024); // size is in bits
sha512_compress(ctx);
ctx->input_idx = 0;
ZERO(ctx->input, 16);
message += 128;
}
message_size &= 127;
if (message_size != 0) {
// Remaining words
size_t nb_words = message_size >> 3;
load64_be_buf(ctx->input, message, nb_words);
ctx->input_idx += nb_words << 3;
message += nb_words << 3;
message_size -= nb_words << 3;
// Remaining bytes
FOR (i, 0, message_size) {
sha512_set_input(ctx, message[i]);
ctx->input_idx++;
}
}
}
void crypto_sha512_final(crypto_sha512_ctx *ctx, u8 hash[64])
{
// Add padding bit
if (ctx->input_idx == 0) {
ZERO(ctx->input, 16);
}
sha512_set_input(ctx, 128);
// Update size
sha512_incr(ctx->input_size, ctx->input_idx * 8);
// Compress penultimate block (if any)
if (ctx->input_idx > 111) {
sha512_compress(ctx);
ZERO(ctx->input, 14);
}
// Compress last block
ctx->input[14] = ctx->input_size[0];
ctx->input[15] = ctx->input_size[1];
sha512_compress(ctx);
// Copy hash to output (big endian)
FOR (i, 0, 8) {
store64_be(hash + i*8, ctx->hash[i]);
}
WIPE_CTX(ctx);
}
void crypto_sha512(u8 hash[64], const u8 *message, size_t message_size)
{
crypto_sha512_ctx ctx;
crypto_sha512_init (&ctx);
crypto_sha512_update(&ctx, message, message_size);
crypto_sha512_final (&ctx, hash);
}
////////////////////
/// HMAC SHA 512 ///
////////////////////
void crypto_sha512_hmac_init(crypto_sha512_hmac_ctx *ctx,
const u8 *key, size_t key_size)
{
// hash key if it is too long
if (key_size > 128) {
crypto_sha512(ctx->key, key, key_size);
key = ctx->key;
key_size = 64;
}
// Compute inner key: padded key XOR 0x36
FOR (i, 0, key_size) { ctx->key[i] = key[i] ^ 0x36; }
FOR (i, key_size, 128) { ctx->key[i] = 0x36; }
// Start computing inner hash
crypto_sha512_init (&ctx->ctx);
crypto_sha512_update(&ctx->ctx, ctx->key, 128);
}
void crypto_sha512_hmac_update(crypto_sha512_hmac_ctx *ctx,
const u8 *message, size_t message_size)
{
crypto_sha512_update(&ctx->ctx, message, message_size);
}
void crypto_sha512_hmac_final(crypto_sha512_hmac_ctx *ctx, u8 hmac[64])
{
// Finish computing inner hash
crypto_sha512_final(&ctx->ctx, hmac);
// Compute outer key: padded key XOR 0x5c
FOR (i, 0, 128) {
ctx->key[i] ^= 0x36 ^ 0x5c;
}
// Compute outer hash
crypto_sha512_init (&ctx->ctx);
crypto_sha512_update(&ctx->ctx, ctx->key , 128);
crypto_sha512_update(&ctx->ctx, hmac, 64);
crypto_sha512_final (&ctx->ctx, hmac); // outer hash
WIPE_CTX(ctx);
}
void crypto_sha512_hmac(u8 hmac[64], const u8 *key, size_t key_size,
const u8 *message, size_t message_size)
{
crypto_sha512_hmac_ctx ctx;
crypto_sha512_hmac_init (&ctx, key, key_size);
crypto_sha512_hmac_update(&ctx, message, message_size);
crypto_sha512_hmac_final (&ctx, hmac);
}
////////////////////
/// HKDF SHA 512 ///
////////////////////
void crypto_sha512_hkdf_expand(u8 *okm, size_t okm_size,
const u8 *prk, size_t prk_size,
const u8 *info, size_t info_size)
{
int not_first = 0;
u8 ctr = 1;
u8 blk[64];
while (okm_size > 0) {
size_t out_size = MIN(okm_size, sizeof(blk));
crypto_sha512_hmac_ctx ctx;
crypto_sha512_hmac_init(&ctx, prk , prk_size);
if (not_first) {
// For some reason HKDF uses some kind of CBC mode.
// For some reason CTR mode alone wasn't enough.
// Like what, they didn't trust HMAC in 2010? Really??
crypto_sha512_hmac_update(&ctx, blk , sizeof(blk));
}
crypto_sha512_hmac_update(&ctx, info, info_size);
crypto_sha512_hmac_update(&ctx, &ctr, 1);
crypto_sha512_hmac_final(&ctx, blk);
COPY(okm, blk, out_size);
not_first = 1;
okm += out_size;
okm_size -= out_size;
ctr++;
}
}
void crypto_sha512_hkdf(u8 *okm , size_t okm_size,
const u8 *ikm , size_t ikm_size,
const u8 *salt, size_t salt_size,
const u8 *info, size_t info_size)
{
// Extract
u8 prk[64];
crypto_sha512_hmac(prk, salt, salt_size, ikm, ikm_size);
// Expand
crypto_sha512_hkdf_expand(okm, okm_size, prk, sizeof(prk), info, info_size);
}
///////////////
/// Ed25519 ///
///////////////
void crypto_ed25519_key_pair(u8 secret_key[64], u8 public_key[32], u8 seed[32])
{
u8 a[64];
COPY(a, seed, 32); // a[ 0..31] = seed
crypto_wipe(seed, 32);
COPY(secret_key, a, 32); // secret key = seed
crypto_sha512(a, a, 32); // a[ 0..31] = scalar
crypto_eddsa_trim_scalar(a, a); // a[ 0..31] = trimmed scalar
crypto_eddsa_scalarbase(public_key, a); // public key = [trimmed scalar]B
COPY(secret_key + 32, public_key, 32); // secret key includes public half
WIPE_BUFFER(a);
}
static void hash_reduce(u8 h[32],
const u8 *a, size_t a_size,
const u8 *b, size_t b_size,
const u8 *c, size_t c_size,
const u8 *d, size_t d_size)
{
u8 hash[64];
crypto_sha512_ctx ctx;
crypto_sha512_init (&ctx);
crypto_sha512_update(&ctx, a, a_size);
crypto_sha512_update(&ctx, b, b_size);
crypto_sha512_update(&ctx, c, c_size);
crypto_sha512_update(&ctx, d, d_size);
crypto_sha512_final (&ctx, hash);
crypto_eddsa_reduce(h, hash);
}
static void ed25519_dom_sign(u8 signature [64], const u8 secret_key[32],
const u8 *dom, size_t dom_size,
const u8 *message, size_t message_size)
{
u8 a[64]; // secret scalar and prefix
u8 r[32]; // secret deterministic "random" nonce
u8 h[32]; // publically verifiable hash of the message (not wiped)
u8 R[32]; // first half of the signature (allows overlapping inputs)
const u8 *pk = secret_key + 32;
crypto_sha512(a, secret_key, 32);
crypto_eddsa_trim_scalar(a, a);
hash_reduce(r, dom, dom_size, a + 32, 32, message, message_size, 0, 0);
crypto_eddsa_scalarbase(R, r);
hash_reduce(h, dom, dom_size, R, 32, pk, 32, message, message_size);
COPY(signature, R, 32);
crypto_eddsa_mul_add(signature + 32, h, a, r);
WIPE_BUFFER(a);
WIPE_BUFFER(r);
}
void crypto_ed25519_sign(u8 signature [64], const u8 secret_key[64],
const u8 *message, size_t message_size)
{
ed25519_dom_sign(signature, secret_key, 0, 0, message, message_size);
}
int crypto_ed25519_check(const u8 signature[64], const u8 public_key[32],
const u8 *msg, size_t msg_size)
{
u8 h_ram[32];
hash_reduce(h_ram, signature, 32, public_key, 32, msg, msg_size, 0, 0);
return crypto_eddsa_check_equation(signature, public_key, h_ram);
}
static const u8 domain[34] = "SigEd25519 no Ed25519 collisions\1";
void crypto_ed25519_ph_sign(uint8_t signature[64], const uint8_t secret_key[64],
const uint8_t message_hash[64])
{
ed25519_dom_sign(signature, secret_key, domain, sizeof(domain),
message_hash, 64);
}
int crypto_ed25519_ph_check(const uint8_t sig[64], const uint8_t pk[32],
const uint8_t msg_hash[64])
{
u8 h_ram[32];
hash_reduce(h_ram, domain, sizeof(domain), sig, 32, pk, 32, msg_hash, 64);
return crypto_eddsa_check_equation(sig, pk, h_ram);
}
#ifdef MONOCYPHER_CPP_NAMESPACE
}
#endif

View File

@ -0,0 +1,140 @@
// Monocypher version 4.0.2
//
// This file is dual-licensed. Choose whichever licence you want from
// the two licences listed below.
//
// The first licence is a regular 2-clause BSD licence. The second licence
// is the CC-0 from Creative Commons. It is intended to release Monocypher
// to the public domain. The BSD licence serves as a fallback option.
//
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
//
// ------------------------------------------------------------------------
//
// Copyright (c) 2017-2019, Loup Vaillant
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ------------------------------------------------------------------------
//
// Written in 2017-2019 by Loup Vaillant
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along
// with this software. If not, see
// <https://creativecommons.org/publicdomain/zero/1.0/>
#ifndef ED25519_H
#define ED25519_H
#include "monocypher.h"
#ifdef MONOCYPHER_CPP_NAMESPACE
namespace MONOCYPHER_CPP_NAMESPACE {
#elif defined(__cplusplus)
extern "C" {
#endif
////////////////////////
/// Type definitions ///
////////////////////////
// Do not rely on the size or content on any of those types,
// they may change without notice.
typedef struct {
uint64_t hash[8];
uint64_t input[16];
uint64_t input_size[2];
size_t input_idx;
} crypto_sha512_ctx;
typedef struct {
uint8_t key[128];
crypto_sha512_ctx ctx;
} crypto_sha512_hmac_ctx;
// SHA 512
// -------
void crypto_sha512_init (crypto_sha512_ctx *ctx);
void crypto_sha512_update(crypto_sha512_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_sha512_final (crypto_sha512_ctx *ctx, uint8_t hash[64]);
void crypto_sha512(uint8_t hash[64],
const uint8_t *message, size_t message_size);
// SHA 512 HMAC
// ------------
void crypto_sha512_hmac_init(crypto_sha512_hmac_ctx *ctx,
const uint8_t *key, size_t key_size);
void crypto_sha512_hmac_update(crypto_sha512_hmac_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_sha512_hmac_final(crypto_sha512_hmac_ctx *ctx, uint8_t hmac[64]);
void crypto_sha512_hmac(uint8_t hmac[64],
const uint8_t *key , size_t key_size,
const uint8_t *message, size_t message_size);
// SHA 512 HKDF
// ------------
void crypto_sha512_hkdf_expand(uint8_t *okm, size_t okm_size,
const uint8_t *prk, size_t prk_size,
const uint8_t *info, size_t info_size);
void crypto_sha512_hkdf(uint8_t *okm , size_t okm_size,
const uint8_t *ikm , size_t ikm_size,
const uint8_t *salt, size_t salt_size,
const uint8_t *info, size_t info_size);
// Ed25519
// -------
// Signatures (EdDSA with curve25519 + SHA-512)
// --------------------------------------------
void crypto_ed25519_key_pair(uint8_t secret_key[64],
uint8_t public_key[32],
uint8_t seed[32]);
void crypto_ed25519_sign(uint8_t signature [64],
const uint8_t secret_key[64],
const uint8_t *message, size_t message_size);
int crypto_ed25519_check(const uint8_t signature [64],
const uint8_t public_key[32],
const uint8_t *message, size_t message_size);
// Pre-hash variants
void crypto_ed25519_ph_sign(uint8_t signature [64],
const uint8_t secret_key [64],
const uint8_t message_hash[64]);
int crypto_ed25519_ph_check(const uint8_t signature [64],
const uint8_t public_key [32],
const uint8_t message_hash[64]);
#ifdef __cplusplus
}
#endif
#endif // ED25519_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,321 @@
// Monocypher version 4.0.2
//
// This file is dual-licensed. Choose whichever licence you want from
// the two licences listed below.
//
// The first licence is a regular 2-clause BSD licence. The second licence
// is the CC-0 from Creative Commons. It is intended to release Monocypher
// to the public domain. The BSD licence serves as a fallback option.
//
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
//
// ------------------------------------------------------------------------
//
// Copyright (c) 2017-2019, Loup Vaillant
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ------------------------------------------------------------------------
//
// Written in 2017-2019 by Loup Vaillant
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along
// with this software. If not, see
// <https://creativecommons.org/publicdomain/zero/1.0/>
#ifndef MONOCYPHER_H
#define MONOCYPHER_H
#include <stddef.h>
#include <stdint.h>
#ifdef MONOCYPHER_CPP_NAMESPACE
namespace MONOCYPHER_CPP_NAMESPACE {
#elif defined(__cplusplus)
extern "C" {
#endif
// Constant time comparisons
// -------------------------
// Return 0 if a and b are equal, -1 otherwise
int crypto_verify16(const uint8_t a[16], const uint8_t b[16]);
int crypto_verify32(const uint8_t a[32], const uint8_t b[32]);
int crypto_verify64(const uint8_t a[64], const uint8_t b[64]);
// Erase sensitive data
// --------------------
void crypto_wipe(void *secret, size_t size);
// Authenticated encryption
// ------------------------
void crypto_aead_lock(uint8_t *cipher_text,
uint8_t mac [16],
const uint8_t key [32],
const uint8_t nonce[24],
const uint8_t *ad, size_t ad_size,
const uint8_t *plain_text, size_t text_size);
int crypto_aead_unlock(uint8_t *plain_text,
const uint8_t mac [16],
const uint8_t key [32],
const uint8_t nonce[24],
const uint8_t *ad, size_t ad_size,
const uint8_t *cipher_text, size_t text_size);
// Authenticated stream
// --------------------
typedef struct {
uint64_t counter;
uint8_t key[32];
uint8_t nonce[8];
} crypto_aead_ctx;
void crypto_aead_init_x(crypto_aead_ctx *ctx,
const uint8_t key[32], const uint8_t nonce[24]);
void crypto_aead_init_djb(crypto_aead_ctx *ctx,
const uint8_t key[32], const uint8_t nonce[8]);
void crypto_aead_init_ietf(crypto_aead_ctx *ctx,
const uint8_t key[32], const uint8_t nonce[12]);
void crypto_aead_write(crypto_aead_ctx *ctx,
uint8_t *cipher_text,
uint8_t mac[16],
const uint8_t *ad , size_t ad_size,
const uint8_t *plain_text, size_t text_size);
int crypto_aead_read(crypto_aead_ctx *ctx,
uint8_t *plain_text,
const uint8_t mac[16],
const uint8_t *ad , size_t ad_size,
const uint8_t *cipher_text, size_t text_size);
// General purpose hash (BLAKE2b)
// ------------------------------
// Direct interface
void crypto_blake2b(uint8_t *hash, size_t hash_size,
const uint8_t *message, size_t message_size);
void crypto_blake2b_keyed(uint8_t *hash, size_t hash_size,
const uint8_t *key, size_t key_size,
const uint8_t *message, size_t message_size);
// Incremental interface
typedef struct {
// Do not rely on the size or contents of this type,
// for they may change without notice.
uint64_t hash[8];
uint64_t input_offset[2];
uint64_t input[16];
size_t input_idx;
size_t hash_size;
} crypto_blake2b_ctx;
void crypto_blake2b_init(crypto_blake2b_ctx *ctx, size_t hash_size);
void crypto_blake2b_keyed_init(crypto_blake2b_ctx *ctx, size_t hash_size,
const uint8_t *key, size_t key_size);
void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_blake2b_final(crypto_blake2b_ctx *ctx, uint8_t *hash);
// Password key derivation (Argon2)
// --------------------------------
#define CRYPTO_ARGON2_D 0
#define CRYPTO_ARGON2_I 1
#define CRYPTO_ARGON2_ID 2
typedef struct {
uint32_t algorithm; // Argon2d, Argon2i, Argon2id
uint32_t nb_blocks; // memory hardness, >= 8 * nb_lanes
uint32_t nb_passes; // CPU hardness, >= 1 (>= 3 recommended for Argon2i)
uint32_t nb_lanes; // parallelism level (single threaded anyway)
} crypto_argon2_config;
typedef struct {
const uint8_t *pass;
const uint8_t *salt;
uint32_t pass_size;
uint32_t salt_size; // 16 bytes recommended
} crypto_argon2_inputs;
typedef struct {
const uint8_t *key; // may be NULL if no key
const uint8_t *ad; // may be NULL if no additional data
uint32_t key_size; // 0 if no key (32 bytes recommended otherwise)
uint32_t ad_size; // 0 if no additional data
} crypto_argon2_extras;
extern const crypto_argon2_extras crypto_argon2_no_extras;
void crypto_argon2(uint8_t *hash, uint32_t hash_size, void *work_area,
crypto_argon2_config config,
crypto_argon2_inputs inputs,
crypto_argon2_extras extras);
// Key exchange (X-25519)
// ----------------------
// Shared secrets are not quite random.
// Hash them to derive an actual shared key.
void crypto_x25519_public_key(uint8_t public_key[32],
const uint8_t secret_key[32]);
void crypto_x25519(uint8_t raw_shared_secret[32],
const uint8_t your_secret_key [32],
const uint8_t their_public_key [32]);
// Conversion to EdDSA
void crypto_x25519_to_eddsa(uint8_t eddsa[32], const uint8_t x25519[32]);
// scalar "division"
// Used for OPRF. Be aware that exponential blinding is less secure
// than Diffie-Hellman key exchange.
void crypto_x25519_inverse(uint8_t blind_salt [32],
const uint8_t private_key[32],
const uint8_t curve_point[32]);
// "Dirty" versions of x25519_public_key().
// Use with crypto_elligator_rev().
// Leaks 3 bits of the private key.
void crypto_x25519_dirty_small(uint8_t pk[32], const uint8_t sk[32]);
void crypto_x25519_dirty_fast (uint8_t pk[32], const uint8_t sk[32]);
// Signatures
// ----------
// EdDSA with curve25519 + BLAKE2b
void crypto_eddsa_key_pair(uint8_t secret_key[64],
uint8_t public_key[32],
uint8_t seed[32]);
void crypto_eddsa_sign(uint8_t signature [64],
const uint8_t secret_key[64],
const uint8_t *message, size_t message_size);
int crypto_eddsa_check(const uint8_t signature [64],
const uint8_t public_key[32],
const uint8_t *message, size_t message_size);
// Conversion to X25519
void crypto_eddsa_to_x25519(uint8_t x25519[32], const uint8_t eddsa[32]);
// EdDSA building blocks
void crypto_eddsa_trim_scalar(uint8_t out[32], const uint8_t in[32]);
void crypto_eddsa_reduce(uint8_t reduced[32], const uint8_t expanded[64]);
void crypto_eddsa_mul_add(uint8_t r[32],
const uint8_t a[32],
const uint8_t b[32],
const uint8_t c[32]);
void crypto_eddsa_scalarbase(uint8_t point[32], const uint8_t scalar[32]);
int crypto_eddsa_check_equation(const uint8_t signature[64],
const uint8_t public_key[32],
const uint8_t h_ram[32]);
// Chacha20
// --------
// Specialised hash.
// Used to hash X25519 shared secrets.
void crypto_chacha20_h(uint8_t out[32],
const uint8_t key[32],
const uint8_t in [16]);
// Unauthenticated stream cipher.
// Don't forget to add authentication.
uint64_t crypto_chacha20_djb(uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size,
const uint8_t key[32],
const uint8_t nonce[8],
uint64_t ctr);
uint32_t crypto_chacha20_ietf(uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size,
const uint8_t key[32],
const uint8_t nonce[12],
uint32_t ctr);
uint64_t crypto_chacha20_x(uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size,
const uint8_t key[32],
const uint8_t nonce[24],
uint64_t ctr);
// Poly 1305
// ---------
// This is a *one time* authenticator.
// Disclosing the mac reveals the key.
// See crypto_lock() on how to use it properly.
// Direct interface
void crypto_poly1305(uint8_t mac[16],
const uint8_t *message, size_t message_size,
const uint8_t key[32]);
// Incremental interface
typedef struct {
// Do not rely on the size or contents of this type,
// for they may change without notice.
uint8_t c[16]; // chunk of the message
size_t c_idx; // How many bytes are there in the chunk.
uint32_t r [4]; // constant multiplier (from the secret key)
uint32_t pad[4]; // random number added at the end (from the secret key)
uint32_t h [5]; // accumulated hash
} crypto_poly1305_ctx;
void crypto_poly1305_init (crypto_poly1305_ctx *ctx, const uint8_t key[32]);
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_poly1305_final (crypto_poly1305_ctx *ctx, uint8_t mac[16]);
// Elligator 2
// -----------
// Elligator mappings proper
void crypto_elligator_map(uint8_t curve [32], const uint8_t hidden[32]);
int crypto_elligator_rev(uint8_t hidden[32], const uint8_t curve [32],
uint8_t tweak);
// Easy to use key pair generation
void crypto_elligator_key_pair(uint8_t hidden[32], uint8_t secret_key[32],
uint8_t seed[32]);
#ifdef __cplusplus
}
#endif
#endif // MONOCYPHER_H

View File

@ -0,0 +1,92 @@
#!/bin/bash
# SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
# SPDX-License-Identifier: BSD-2-Clause
set -eu
# Check for the SPDX tag in all files in the repo. Exit with a non-zero code if
# some is missing. The missingok arrays below contain files and directories
# with files where the the tag is not required.
cd "${0%/*}"
cd ..
tag="SPDX-License-Identifier:"
missingok_dirs=(
.github/workflows/
LICENSES/
)
missingok_files=(
.clang-format
.editorconfig
.gitignore
LICENSE
Makefile
README.md
README-DIST.txt
RELEASE.md
example-app/Makefile
monocypher/LICENSE
monocypher/README.md
)
is_missingok() {
item="$1"
# ok for empty files
[[ -f "$item" ]] && [[ ! -s "$item" ]] && return 0
for fileok in "${missingok_files[@]}"; do
[[ "$item" = "$fileok" ]] && return 0
done
for dirok in "${missingok_dirs[@]}"; do
[[ "$item" =~ ^$dirok ]] && return 0
done
return 1
}
printf "* Checking for SPDX tags in %s\n" "$PWD"
mapfile -t repofiles < <(git ls-files || true)
if [[ -z "${repofiles[*]}" ]]; then
printf "* No files in the repo?!\n"
exit 1
fi
failed=0
printed=0
for fileok in "${missingok_files[@]}"; do
[[ -f "$fileok" ]] && continue
if (( !printed )); then
printf "* Some files in missingok_files are themselves missing:\n"
printed=1
failed=1
fi
printf "%s\n" "$fileok"
done
printed=0
for dirok in "${missingok_dirs[@]}"; do
[[ -d "$dirok" ]] && continue
if (( !printed )); then
printf "* Some dirs in missingok_dirs are themselves missing:\n"
printed=1
failed=1
fi
printf "%s\n" "$dirok"
done
printed=0
for file in "${repofiles[@]}"; do
is_missingok "$file" && continue
if ! grep -q "$tag" "$file"; then
if (( !printed )); then
printf "* Files missing the SPDX tag:\n"
printed=1
failed=1
fi
printf "%s\n" "$file"
fi
done
exit "$failed"