Skip to content

Commit d3bb681

Browse files
authored
Merge pull request #12 from pq-code-package/ci-c90
Achieve C90 compliance and test in CI
2 parents f4f8d99 + 64ee44c commit d3bb681

File tree

8 files changed

+147
-68
lines changed

8 files changed

+147
-68
lines changed

.github/workflows/base.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,30 @@ jobs:
4040
run: |
4141
make
4242
python3 test/acvp_client.py --version ${{ matrix.acvp-version }}
43+
quickcheck-c90:
44+
strategy:
45+
fail-fast: false
46+
matrix:
47+
external:
48+
- ${{ github.repository_owner != 'pq-code-package' }}
49+
target:
50+
- runner: pqcp-arm64
51+
name: 'aarch64'
52+
- runner: ubuntu-latest
53+
name: 'x86_64'
54+
exclude:
55+
- {external: true,
56+
target: {
57+
runner: pqcp-arm64,
58+
name: 'aarch64'
59+
}}
60+
name: Quickcheck C90 (${{ matrix.target.name }})
61+
runs-on: ${{ matrix.target.runner }}
62+
steps:
63+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
64+
with:
65+
submodules: true
66+
- name: make quickcheck
67+
run: |
68+
CFLAGS=-std=c90 make test
69+

Makefile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ OBJS = $(CSRC:.c=.o)
99
XTEST ?= xfips205
1010
XTESTC ?= test/xfips205.c
1111

12-
CC = gcc
13-
CFLAGS := -Wall \
12+
CC ?= gcc
13+
CFLAGS := -Wall \
1414
-Wextra \
1515
-Werror=unused-result \
1616
-Wpedantic \
@@ -24,7 +24,8 @@ CFLAGS := -Wall \
2424
-O3 \
2525
-fomit-frame-pointer \
2626
-std=c99 \
27-
-pedantic
27+
-pedantic \
28+
$(CFLAGS)
2829

2930
LDLIBS +=
3031

README.md

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
[//]: # (SPDX-License-Identifier: CC-BY-4.0)
22
# slhdsa-c
3+
[![License: Apache](https://img.shields.io/badge/license-Apache--2.0-green.svg)](https://www.apache.org/licenses/LICENSE-2.0)
4+
[![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
5+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
36

4-
A portable C implementation of SLH-DSA ("Stateless Hash-Based Digital Signature Standard") as described in [FIPS 205](https://doi.org/10.6028/NIST.FIPS.205).
7+
A portable C90 implementation of SLH-DSA ("Stateless Hash-Based Digital Signature Standard") as described in [FIPS 205](https://doi.org/10.6028/NIST.FIPS.205).
58

69
* Supports all 12 parameter sets in FIPS 205, both "pure" and "internal" functions (without recompiling for various parameter sets), as well as prehash modes.
710
* Self-contained implementation without external dependencies. Can be easily included into applications.
@@ -25,6 +28,13 @@ This code was derived from [SLotH](https://github.com/slh-dsa/sloth) driver code
2528
| SLH-DSA-SHA2-256f | 5 | 64 | 128 | 49856 |
2629
| SLH-DSA-SHAKE-256f | 5 | 64 | 128 | 49856 |
2730

31+
## Status
32+
33+
slhdsa-c is work in progress. **WE DO NOT CURRENTLY RECOMMEND RELYING ON THIS LIBRARY IN A
34+
PRODUCTION ENVIRONMENT OR TO PROTECT ANY SENSITIVE DATA.** Once we have the first stable version,
35+
this notice will be removed.
36+
37+
2838
## Building and Running Known Answer Tests
2939

3040
The implementation in this directory includes the necessary hash functions and, hence, has no external library dependencies. On a Linux system, you can typically use `make` to build the test wrapper executable `xfips205`.
@@ -38,23 +48,23 @@ gcc -Wall -Wextra -Werror=unused-result -Wpedantic -Werror -Wmissing-prototypes
3848

3949
### Running the ACVP tests
4050

41-
The static test cases need to be initially fetched from NIST's [ACVP-Server](https://github.com/usnistgov/ACVP-Server) repository, which is instantiated as submodule `test/ACVP-Server`. The Makefile should be able to do this automatically in case the submodule has not been initialized, but this may take some time.
42-
43-
As a prerequisite you will require python3 and [gnu parallel](https://www.gnu.org/software/parallel) (a standard Linux package in most cases), which makes the full test run in less than 1 minute.
44-
45-
During the process, the script [`test/test_slhdsa.py`](test/test_slhdsa.py) will translate the test cases into a shell file `test/acvp_cases.sh`, which then contains test case feed for `xfips205`.
51+
[`test/acvp_client.py`](test/acvp_client.py) implement ACVP tests and can also be executed through `make test`.
52+
The ACVP version can be specified by passing the `--version` argument to the [`test/acvp_client.py`](test/acvp_client.py).
53+
The static test vectors are automatically fetched from NIST's [ACVP-Server](https://github.com/usnistgov/ACVP-Server) repository on first execution.s
4654

4755
```console
4856
$ make test
57+
python3 test/acvp_client.py
58+
Using ACVP test vectors version v1.1.0.40
59+
Running 1248 tests with 16 parallel jobs
60+
[PASS] keyGen SLH-DSA-SHA2-128s [1] slh_keygen_internal()
4961
...
50-
cat test/acvp_cases.sh | parallel --pipe bash | tee test.log
51-
[PASS] sigGen SLH-DSA-SHA2-192f [22] slh_sign()
52-
...
53-
[PASS] sigGen SLH-DSA-SHAKE-192s [553] hash_slh_sign(SHAKE-128)
62+
[PASS] sigVer SLH-DSA-SHAKE-256s [497] slh_verify_internal()
63+
5464
=== test summary ===
5565
PASS: 1248
56-
SKIP: 0
5766
FAIL: 0
67+
ALL GOOD!
5868
```
5969

6070
## Structure of the implementation
@@ -83,10 +93,8 @@ slhdsa-c
8393
├── slh_shake.c # SLH-DSA instantiation for SHA3/SHAKE hash family
8494
├── slh_var.h # internal SLH-DSA context structure
8595
└── test # testing stuff (not for application)
86-
├── acvp_cases.sh # precompiled ACVP test cases
87-
├── ACVP-Server # optional submodule (contains original test cases)
8896
├── Makefile # makefile for local test tasks
89-
├── test_slhdsa.py # parses JSON files into acvp_cases.sh
97+
├── acvp_client.py # ACVP client
9098
└── xfips205.c # command-line test harness
9199
```
92100

plat_local.h

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ extern "C"
1515

1616
#include <stddef.h>
1717
#include <stdint.h>
18+
#include "slh_sys.h"
1819

1920
#ifndef PLAT_VERS_STR
2021
#define PLAT_VERS_STR "dev version"
@@ -112,7 +113,7 @@ extern "C"
112113
#else
113114
/* RISC-V: grev(x, 0x18) or rev8 */
114115

115-
static inline uint32_t rev8_be32(uint32_t x)
116+
static SLH_INLINE uint32_t rev8_be32(uint32_t x)
116117
{
117118
return ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) |
118119
((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24);
@@ -123,7 +124,7 @@ static inline uint32_t rev8_be32(uint32_t x)
123124
#define rev8_be64(x) (x)
124125
#else
125126
/* RISC-V: grev(x, 0x38) or rev8(x) */
126-
static inline uint64_t rev8_be64(uint64_t x)
127+
static SLH_INLINE uint64_t rev8_be64(uint64_t x)
127128
{
128129
return (x << 56) | ((x & 0x000000000000FF00LL) << 40) |
129130
((x & 0x0000000000FF0000LL) << 24) |
@@ -135,70 +136,70 @@ static inline uint64_t rev8_be64(uint64_t x)
135136

136137
/* rotate left */
137138

138-
static inline uint32_t rol32(uint32_t x, uint32_t n)
139+
static SLH_INLINE uint32_t rol32(uint32_t x, uint32_t n)
139140
{
140141
return (x << n) | (x >> (32 - n));
141142
}
142143

143-
static inline uint64_t rol64(uint64_t x, uint64_t n)
144+
static SLH_INLINE uint64_t rol64(uint64_t x, uint64_t n)
144145
{
145146
return (x << n) | (x >> (64 - n));
146147
}
147148

148149
/* rotate right (RISC-V ROR or RORI) */
149150

150-
static inline uint32_t ror32(uint32_t x, uint32_t n)
151+
static SLH_INLINE uint32_t ror32(uint32_t x, uint32_t n)
151152
{
152153
return (x >> n) | (x << (32 - n));
153154
}
154155

155-
static inline uint64_t ror64(uint64_t x, uint64_t n)
156+
static SLH_INLINE uint64_t ror64(uint64_t x, uint64_t n)
156157
{
157158
return (x >> n) | (x << (64 - n));
158159
}
159160

160161
/* and with negate (RISC-V ANDN) */
161162

162-
static inline uint32_t andn32(uint32_t x, uint32_t y) { return x & ~y; }
163+
static SLH_INLINE uint32_t andn32(uint32_t x, uint32_t y) { return x & ~y; }
163164

164-
static inline uint64_t andn64(uint64_t x, uint64_t y) { return x & ~y; }
165+
static SLH_INLINE uint64_t andn64(uint64_t x, uint64_t y) { return x & ~y; }
165166

166167
/* little-endian loads and stores (unaligned) */
167168

168-
static inline uint16_t get16u_le(const uint8_t *v)
169+
static SLH_INLINE uint16_t get16u_le(const uint8_t *v)
169170
{
170171
return (((uint16_t)v[1]) << 8) | ((uint16_t)v[0]);
171172
}
172173

173-
static inline void put16u_le(uint8_t *v, uint16_t x)
174+
static SLH_INLINE void put16u_le(uint8_t *v, uint16_t x)
174175
{
175176
v[0] = x;
176177
v[1] = x >> 8;
177178
}
178179

179-
static inline uint32_t get32u_le(const uint8_t *v)
180+
static SLH_INLINE uint32_t get32u_le(const uint8_t *v)
180181
{
181182
return ((uint32_t)v[0]) | (((uint32_t)v[1]) << 8) |
182183
(((uint32_t)v[2]) << 16) | (((uint32_t)v[3]) << 24);
183184
}
184185

185-
static inline void put32u_le(uint8_t *v, uint32_t x)
186+
static SLH_INLINE void put32u_le(uint8_t *v, uint32_t x)
186187
{
187188
v[0] = x;
188189
v[1] = x >> 8;
189190
v[2] = x >> 16;
190191
v[3] = x >> 24;
191192
}
192193

193-
static inline uint64_t get64u_le(const uint8_t *v)
194+
static SLH_INLINE uint64_t get64u_le(const uint8_t *v)
194195
{
195196
return ((uint64_t)v[0]) | (((uint64_t)v[1]) << 8) |
196197
(((uint64_t)v[2]) << 16) | (((uint64_t)v[3]) << 24) |
197198
(((uint64_t)v[4]) << 32) | (((uint64_t)v[5]) << 40) |
198199
(((uint64_t)v[6]) << 48) | (((uint64_t)v[7]) << 56);
199200
}
200201

201-
static inline void put64u_le(uint8_t *v, uint64_t x)
202+
static SLH_INLINE void put64u_le(uint8_t *v, uint64_t x)
202203
{
203204
v[0] = x;
204205
v[1] = x >> 8;
@@ -212,40 +213,40 @@ static inline uint64_t rev8_be64(uint64_t x)
212213

213214
/* big-endian loads and stores (unaligned) */
214215

215-
static inline uint16_t get16u_be(const uint8_t *v)
216+
static SLH_INLINE uint16_t get16u_be(const uint8_t *v)
216217
{
217218
return (((uint16_t)v[0]) << 8) | ((uint16_t)v[1]);
218219
}
219220

220-
static inline void put16u_be(uint8_t *v, uint16_t x)
221+
static SLH_INLINE void put16u_be(uint8_t *v, uint16_t x)
221222
{
222223
v[0] = x >> 8;
223224
v[1] = x;
224225
}
225226

226-
static inline uint32_t get32u_be(const uint8_t *v)
227+
static SLH_INLINE uint32_t get32u_be(const uint8_t *v)
227228
{
228229
return (((uint32_t)v[0]) << 24) | (((uint32_t)v[1]) << 16) |
229230
(((uint32_t)v[2]) << 8) | ((uint32_t)v[3]);
230231
}
231232

232-
static inline void put32u_be(uint8_t *v, uint32_t x)
233+
static SLH_INLINE void put32u_be(uint8_t *v, uint32_t x)
233234
{
234235
v[0] = x >> 24;
235236
v[1] = x >> 16;
236237
v[2] = x >> 8;
237238
v[3] = x;
238239
}
239240

240-
static inline uint64_t get64u_be(const uint8_t *v)
241+
static SLH_INLINE uint64_t get64u_be(const uint8_t *v)
241242
{
242243
return (((uint64_t)v[0]) << 56) | (((uint64_t)v[1]) << 48) |
243244
(((uint64_t)v[2]) << 40) | (((uint64_t)v[3]) << 32) |
244245
(((uint64_t)v[4]) << 24) | (((uint64_t)v[5]) << 16) |
245246
(((uint64_t)v[6]) << 8) | ((uint64_t)v[7]);
246247
}
247248

248-
static inline void put64u_be(uint8_t *v, uint64_t x)
249+
static SLH_INLINE void put64u_be(uint8_t *v, uint64_t x)
249250
{
250251
v[0] = x >> 56;
251252
v[1] = x >> 48;

0 commit comments

Comments
 (0)