Skip to content

Commit be25453

Browse files
committed
Examples: Add basic_lowram example (sets MLD_CONFIG_REDUCE_RAM)
Signed-off-by: Matthias J. Kannwischer <[email protected]>
1 parent f3c56d4 commit be25453

File tree

14 files changed

+1043
-0
lines changed

14 files changed

+1043
-0
lines changed

BIBLIOGRAPHY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ source code and documentation.
2424
* URL: https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements
2525
* Referenced from:
2626
- [examples/basic_deterministic/mldsa_native/mldsa_native_config.h](examples/basic_deterministic/mldsa_native/mldsa_native_config.h)
27+
- [examples/basic_lowram/mldsa_native/mldsa_native_config.h](examples/basic_lowram/mldsa_native/mldsa_native_config.h)
2728
- [examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h)
2829
- [examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h)
2930
- [examples/custom_backend/mldsa_native/mldsa_native_config.h](examples/custom_backend/mldsa_native/mldsa_native_config.h)
@@ -72,6 +73,7 @@ source code and documentation.
7273
* Referenced from:
7374
- [README.md](README.md)
7475
- [examples/basic_deterministic/mldsa_native/mldsa_native_config.h](examples/basic_deterministic/mldsa_native/mldsa_native_config.h)
76+
- [examples/basic_lowram/mldsa_native/mldsa_native_config.h](examples/basic_lowram/mldsa_native/mldsa_native_config.h)
7577
- [examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h)
7678
- [examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h)
7779
- [examples/custom_backend/mldsa_native/mldsa_native_config.h](examples/custom_backend/mldsa_native/mldsa_native_config.h)

examples/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ See [basic](basic) for a basic example of how to build a single instance of mlds
1111
## Basic_deterministic
1212

1313
See [basic_deterministic](basic_deterministic) for a basic example of how to build a single instance of mldsa-native without `randombytes()` implementation. This allows users to build mldsa-native using only the deterministic API when randomized functions are not required.
14+
15+
## Basic_lowram
16+
17+
See [basic_lowram](basic_lowram) for a basic example of how to build a single instance of mldsa-native with reduced RAM usage (`MLD_CONFIG_REDUCE_RAM`). This is useful for embedded systems with tight RAM constraints.
18+
1419
## Multi-level build (C only)
1520

1621
See [multilevel_build](multilevel_build) for an example of how to build one instance of mldsa-native per security level,

examples/basic_lowram/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
2+
3+
build/

examples/basic_lowram/Makefile

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Copyright (c) The mlkem-native project authors
2+
# Copyright (c) The mldsa-native project authors
3+
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
4+
5+
.PHONY: build run clean
6+
.DEFAULT_GOAL := all
7+
8+
CC ?= gcc
9+
10+
# Adjust CFLAGS if needed
11+
CFLAGS := \
12+
-Wall \
13+
-Wextra \
14+
-Werror=unused-result \
15+
-Wpedantic \
16+
-Werror \
17+
-Wmissing-prototypes \
18+
-Wshadow \
19+
-Wpointer-arith \
20+
-Wredundant-decls \
21+
-Wconversion \
22+
-Wsign-conversion \
23+
-Wno-long-long \
24+
-Wno-unknown-pragmas \
25+
-Wno-unused-command-line-argument \
26+
-O3 \
27+
-fomit-frame-pointer \
28+
-std=c99 \
29+
-pedantic \
30+
-MMD \
31+
$(CFLAGS)
32+
33+
# If you want to use the native backends, the compiler needs to know about
34+
# the target architecture. Here, we import the default host detection from
35+
# mldsa-native's tests, but you can write your own or specialize accordingly.
36+
AUTO ?= 1
37+
include auto.mk
38+
39+
# The following only concerns the cross-compilation tests.
40+
# You can likely ignore the following for your application.
41+
#
42+
# Append cross-prefix for cross compilation
43+
# When called from the root Makefile, CROSS_PREFIX has already been added here
44+
ifeq (,$(findstring $(CROSS_PREFIX),$(CC)))
45+
CC := $(CROSS_PREFIX)$(CC)
46+
endif
47+
48+
# Part A:
49+
#
50+
# mldsa-native source and header files
51+
#
52+
# If you are not concerned about minimizing for a specific backend,
53+
# you can just include _all_ source files into your build.
54+
#
55+
# In this example, we compile the individual mldsa-native source files directly.
56+
# Alternatively, you can compile the 'monobuild' source file mldsa_native.c.
57+
# See examples/monolithic_build for that.
58+
MLD_SOURCE=$(wildcard \
59+
mldsa_native/src/*.c \
60+
mldsa_native/src/**/*.c \
61+
mldsa_native/src/**/**/*.c \
62+
mldsa_native/src/**/**/**/*.c)
63+
64+
INC=-Imldsa_native
65+
66+
# Part B:
67+
#
68+
# Random number generator
69+
#
70+
# !!! WARNING !!!
71+
#
72+
# The randombytes() implementation used here is for TESTING ONLY.
73+
# You MUST NOT use this implementation outside of testing.
74+
#
75+
# !!! WARNING !!!
76+
RNG_SOURCE=$(wildcard test_only_rng/*.c)
77+
78+
# Part C:
79+
#
80+
# Your application source code
81+
APP_SOURCE=$(wildcard *.c)
82+
83+
ALL_SOURCE=$(MLD_SOURCE) $(RNG_SOURCE) $(APP_SOURCE)
84+
85+
BUILD_DIR=build
86+
BIN=test_binary
87+
88+
#
89+
# Configuration adjustments
90+
#
91+
92+
# Pick prefix
93+
CFLAGS += -DMLD_CONFIG_NAMESPACE_PREFIX=mldsa
94+
95+
BINARY_NAME_FULL_44=$(BUILD_DIR)/$(BIN)44
96+
BINARY_NAME_FULL_65=$(BUILD_DIR)/$(BIN)65
97+
BINARY_NAME_FULL_87=$(BUILD_DIR)/$(BIN)87
98+
BINARIES_FULL=$(BINARY_NAME_FULL_44) $(BINARY_NAME_FULL_65) $(BINARY_NAME_FULL_87)
99+
100+
$(BINARY_NAME_FULL_44): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44
101+
$(BINARY_NAME_FULL_65): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65
102+
$(BINARY_NAME_FULL_87): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87
103+
104+
$(BINARIES_FULL): $(ALL_SOURCE)
105+
echo "$@"
106+
mkdir -p $(BUILD_DIR)
107+
$(CC) $(CFLAGS) $(INC) $^ -o $@
108+
109+
all: build
110+
111+
build: $(BINARIES_FULL)
112+
113+
run: $(BINARIES_FULL)
114+
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_44)
115+
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_65)
116+
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_87)
117+
118+
clean:
119+
rm -rf $(BUILD_DIR)

examples/basic_lowram/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
[//]: # (SPDX-License-Identifier: CC-BY-4.0)
2+
3+
# Low RAM build
4+
5+
This directory contains a minimal example for how to build mldsa-native with reduced RAM usage.
6+
7+
## Use Case
8+
9+
Use this approach when:
10+
- You are building for an embedded system with tight RAM constraints
11+
- You need to minimize stack usage
12+
- Performance is less critical than memory footprint
13+
14+
## Configuration
15+
16+
The `MLD_CONFIG_REDUCE_RAM` option enables optimizations that reduce RAM usage:
17+
- Uses unions for major allocations to reduce stack usage
18+
- Trades some performance for lower memory footprint
19+
20+
## Components
21+
22+
1. mldsa-native source tree: [`mldsa/src/`](../../mldsa/src) and [`mldsa/src/fips202/`](../../mldsa/src/fips202)
23+
2. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h)
24+
3. Your application source code
25+
26+
## Configuration
27+
28+
The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets:
29+
- `MLD_CONFIG_PARAMETER_SET`: Security level (44, 65, or 87). Default is 65.
30+
- `MLD_CONFIG_NAMESPACE_PREFIX`: Symbol prefix for the API. Set to `mldsa` in this example.
31+
- `MLD_CONFIG_REDUCE_RAM`: Enables reduced RAM usage optimizations.
32+
33+
To change the security level, modify `MLD_CONFIG_PARAMETER_SET` in the config file or pass it via CFLAGS.
34+
35+
## Usage
36+
37+
```bash
38+
make build # Build the example
39+
make run # Run the example
40+
```
41+
42+
## Warning
43+
44+
The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY.
45+
You MUST provide a cryptographically secure RNG for production use.

examples/basic_lowram/auto.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../test/mk/auto.mk
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../basic/expected_signatures.h

examples/basic_lowram/main.c

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Copyright (c) The mldsa-native project authors
3+
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
4+
*/
5+
6+
#include <stdint.h>
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
#include <string.h>
10+
11+
/* Import public mldsa-native API
12+
*
13+
* This requires specifying the parameter set and namespace prefix
14+
* used for the build.
15+
*/
16+
#include <mldsa_native.h>
17+
#include "expected_signatures.h"
18+
#include "test_only_rng/notrandombytes.h"
19+
20+
#define CHECK(x) \
21+
do \
22+
{ \
23+
int rc; \
24+
rc = (x); \
25+
if (!rc) \
26+
{ \
27+
fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \
28+
return 1; \
29+
} \
30+
} while (0)
31+
32+
#define TEST_MSG \
33+
"This is a test message for ML-DSA digital signature algorithm!"
34+
#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1)
35+
36+
#define TEST_CTX "test_context_123"
37+
#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1)
38+
39+
int main(void)
40+
{
41+
const char test_msg[] = TEST_MSG;
42+
const char test_ctx[] = TEST_CTX;
43+
44+
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
45+
uint8_t sk[CRYPTO_SECRETKEYBYTES];
46+
uint8_t sig[CRYPTO_BYTES];
47+
uint8_t sm[TEST_MSG_LEN + CRYPTO_BYTES]; /* signed message buffer */
48+
uint8_t m2[TEST_MSG_LEN + CRYPTO_BYTES]; /* recovered message buffer */
49+
size_t siglen;
50+
size_t smlen;
51+
size_t mlen;
52+
53+
/* WARNING: Test-only
54+
* Normally, you would want to seed a PRNG with trustworthy entropy here. */
55+
randombytes_reset();
56+
57+
printf("ML-DSA-%d Low RAM Example\n", MLD_CONFIG_PARAMETER_SET);
58+
printf("========================\n\n");
59+
60+
printf("Message: %s\n", test_msg);
61+
printf("Context: %s\n\n", test_ctx);
62+
63+
printf("Generating keypair ... ");
64+
65+
/* Alice generates a public/private key pair */
66+
CHECK(crypto_sign_keypair(pk, sk) == 0);
67+
68+
printf("DONE\n");
69+
printf("Signing message... ");
70+
71+
/* Alice signs the message */
72+
CHECK(crypto_sign_signature(sig, &siglen, (const uint8_t *)test_msg,
73+
TEST_MSG_LEN, (const uint8_t *)test_ctx,
74+
TEST_CTX_LEN, sk) == 0);
75+
76+
printf("DONE\n");
77+
printf("Verifying signature... ");
78+
79+
/* Bob verifies Alice's signature */
80+
CHECK(crypto_sign_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN,
81+
(const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0);
82+
83+
printf("DONE\n");
84+
printf("Creating signed message... ");
85+
86+
/* Alternative API: Create a signed message (signature + message combined) */
87+
CHECK(crypto_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN,
88+
(const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0);
89+
90+
printf("DONE\n");
91+
printf("Opening signed message... ");
92+
93+
/* Bob opens the signed message to recover the original message */
94+
CHECK(crypto_sign_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx,
95+
TEST_CTX_LEN, pk) == 0);
96+
97+
printf("DONE\n");
98+
printf("Compare messages... ");
99+
100+
/* Verify the recovered message matches the original */
101+
CHECK(mlen == TEST_MSG_LEN);
102+
CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0);
103+
104+
printf("DONE\n\n");
105+
106+
printf("Results:\n");
107+
printf("--------\n");
108+
printf("Public key size: %d bytes\n", CRYPTO_PUBLICKEYBYTES);
109+
printf("Secret key size: %d bytes\n", CRYPTO_SECRETKEYBYTES);
110+
printf("Signature size: %d bytes\n", CRYPTO_BYTES);
111+
printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN);
112+
printf("Signature length: %lu bytes\n", (unsigned long)siglen);
113+
printf("Signed msg length: %lu bytes\n", (unsigned long)smlen);
114+
115+
#if !defined(MLD_CONFIG_KEYGEN_PCT)
116+
/* Check against expected signature to make sure that
117+
* we integrated the library correctly */
118+
printf("Checking deterministic signature... ");
119+
{
120+
/* Compare the generated signature directly against the expected signature
121+
*/
122+
CHECK(siglen == sizeof(expected_signature));
123+
CHECK(memcmp(sig, expected_signature, siglen) == 0);
124+
}
125+
printf("DONE\n");
126+
#else /* !MLD_CONFIG_KEYGEN_PCT */
127+
printf(
128+
"[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n");
129+
#endif /* MLD_CONFIG_KEYGEN_PCT */
130+
131+
printf("Signature verification completed successfully!\n");
132+
133+
printf("\nAll tests passed! ML-DSA signature verification successful.\n");
134+
return 0;
135+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../mldsa/mldsa_native.h

0 commit comments

Comments
 (0)