From ae7f17c0247d169741dba4ed558f6b368c5a89ef Mon Sep 17 00:00:00 2001 From: Lon Date: Wed, 11 Dec 2024 01:54:42 -0300 Subject: [PATCH 1/4] feat: add nix build --- flake.nix | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 flake.nix diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..74f6c6f --- /dev/null +++ b/flake.nix @@ -0,0 +1,81 @@ +{ + description = "Dilithium post-quantum cryptography implementation"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + packages.default = pkgs.stdenv.mkDerivation { + name = "dilithium"; + src = ./.; + + nativeBuildInputs = with pkgs; [ + clang + openssl + ]; + + buildPhase = '' + # Build reference implementation + make -C ref -j$NIX_BUILD_CORES + + # Build AVX2 implementation if supported + if [ "$(uname -m)" = "x86_64" ]; then + make -C avx2 -j$NIX_BUILD_CORES + fi + ''; + + installPhase = '' + mkdir -p $out/bin + + # Install reference implementation binaries + for alg in 2 3 5; do + cp ref/test/test_dilithium$alg $out/bin/ + cp ref/test/test_vectors$alg $out/bin/ + done + + # Install AVX2 binaries if built + if [ "$(uname -m)" = "x86_64" ]; then + for alg in 2 3 5; do + cp avx2/test/test_dilithium$alg $out/bin/test_dilithium$alg-avx2 + cp avx2/test/test_vectors$alg $out/bin/test_vectors$alg-avx2 + done + fi + ''; + + checkPhase = '' + # Run tests for reference implementation + for alg in 2 3 5; do + ref/test/test_dilithium$alg + ref/test/test_vectors$alg > tvecs$alg + done + + # Run tests for AVX2 implementation if available + if [ "$(uname -m)" = "x86_64" ]; then + for alg in 2 3 5; do + avx2/test/test_dilithium$alg + avx2/test/test_vectors$alg > tvecs$alg-avx2 + done + fi + + sha256sum -c SHA256SUMS + ''; + + doCheck = true; + }; + + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + clang + openssl + ]; + }; + } + ); +} \ No newline at end of file From 159057b0f00ea2538544d9bc7fe35ee56785b6cf Mon Sep 17 00:00:00 2001 From: Lon Date: Wed, 11 Dec 2024 01:54:42 -0300 Subject: [PATCH 2/4] chore: add README, examples --- .gitignore | 1 + README.md | 74 +++++++++++++++ example/Makefile | 32 +++++++ example/create_signature.c | 74 +++++++++++++++ example/generate_secretkey.c | 19 ++++ example/runtest.sh | 15 +++ example/secretkey_to_publickey.c | 24 +++++ example/size.h | 5 + example/validate_signature.c | 77 +++++++++++++++ flake.lock | 61 ++++++++++++ flake.nix | 155 +++++++++++++++++++++---------- 11 files changed, 487 insertions(+), 50 deletions(-) create mode 100644 example/Makefile create mode 100644 example/create_signature.c create mode 100644 example/generate_secretkey.c create mode 100644 example/runtest.sh create mode 100644 example/secretkey_to_publickey.c create mode 100644 example/size.h create mode 100644 example/validate_signature.c create mode 100644 flake.lock diff --git a/.gitignore b/.gitignore index 17ace0a..bb26caa 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ PQCsignKAT_Dilithium5.rsp tvecs2 tvecs3 tvecs5 +result diff --git a/README.md b/README.md index 9204fa6..6aed568 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,26 @@ This repository contains the official reference implementation of the [Dilithium](https://www.pq-crystals.org/dilithium/) signature scheme, and an optimized implementation for x86 CPUs supporting the AVX2 instruction set. Dilithium is standardized as [FIPS 204](https://csrc.nist.gov/pubs/fips/204/final). +## Running Dilithium + +Dilithium can be used via Nix flakes. Make sure you have Nix [installed with flakes enabled](https://nixos.org/manual/nix/stable/installation/installing-binary.html#installation-with-flakes). + +To try Dilithium directly on the command line without cloning this repository, run: +```sh +nix run github:pq-crystals/dilithium -- --help +``` + +The following commands create a signing key and a signature for a file "message.txt": +```sh +nix run github:pq-crystals/dilithium -- --keygen -v 2 -p public.key -s secret.key +nix run github:pq-crystals/dilithium -- --sign -v 2 -p public.key -s secret.key -i message.txt -S signature.bin +``` + +Use the `--verify` flag to verify a signature: +```sh +nix run github:pq-crystals/dilithium -- --verify -v 2 -p public.key -i message.txt -S signature.bin +``` + ## Build instructions The implementations contain several test and benchmarking programs and a Makefile to facilitate compilation. @@ -56,6 +76,60 @@ Please note that the reference implementation in `ref/` is not optimized for any Our Dilithium implementations are contained in the [SUPERCOP](https://bench.cr.yp.to) benchmarking framework. See [here](http://bench.cr.yp.to/results-sign.html#amd64-kizomba) for current cycle counts on an Intel KabyLake CPU. +## Development using Nix + +This repository provides a Nix flake with the following outputs: + +- `packages.dilithium`: The main Dilithium CLI tools +- `packages.dilithium-lib`: The Dilithium shared libraries +- `devShells.default`: A development environment with all dependencies + +### Flake Usage Examples + +To use Dilithium as a dependency in your own flake: +```nix +{ + inputs.dilithium.url = "github:pq-crystals/dilithium"; + + outputs = { self, nixpkgs, dilithium }: { + # Use the library + packages.default = pkgs.stdenv.mkDerivation { + buildInputs = [ dilithium.packages.${system}.dilithium-lib ]; + # ... + }; + }; +} +``` + +The following command will enter the development shell and provide the necessary environment variables (CFLAGS and LDFLAGS required to link against Dilithium and OpenSSL): +```sh +nix develop github:pq-crystals/dilithium +``` + +The development shell provides: +- All build dependencies +- Dilithium libraries and headers +- Proper environment variables (CFLAGS, LDFLAGS, etc.) + +To compile and run tests described above, the same make commands work in either directory: +```sh +make +``` + +This produces the same test executables: +```sh +test/test_dilithium$ALG +test/test_vectors$ALG +``` +where `$ALG` ranges over the parameter sets 2, 3, and 5. + +For performance benchmarking, you can additionally run and execute the speed tests: +```sh +make speed +test/test_speed$ALG +``` +These programs measure performance using the CPU's Time Step Counter (TSC) by default, reporting median and average cycle counts over 10000 executions of key operations. + ## Randomized signing By default our code implements Dilithium's hedged signing mode. To change this to the deterministic signing mode, undefine the `DILITHIUM_RANDOMIZED_SIGNING` preprocessor macro at compilation by either commenting the line diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..0e7167d --- /dev/null +++ b/example/Makefile @@ -0,0 +1,32 @@ +CC=gcc +DILITHIUM_MODE ?= 5 +USE_AVX2 ?= $(shell if [ `uname -m` = "x86_64" ] && grep -q avx2 /proc/cpuinfo; then echo "1"; else echo "0"; fi) + +CFLAGS=-I${DILITHIUM_INCLUDE_DIR} -Wall -Wextra -DDILITHIUM_MODE=$(DILITHIUM_MODE) +CFLAGS += $(shell if [ "$(USE_AVX2)" = "1" ]; then echo "-DHAVE_AVX2"; fi) + +LDFLAGS=-L${DILITHIUM_LIB_DIR} +IMPLEMENTATION=$(shell if [ "$(USE_AVX2)" = "1" ]; then echo "avx2"; else echo "ref"; fi) + +ifeq ($(USE_AVX2),1) + LDFLAGS += -lpqcrystals_dilithium$(DILITHIUM_MODE)_avx2 -lpqcrystals_fips202_avx2 -lpqcrystals_fips202x4_avx2 +endif +LDFLAGS += -lpqcrystals_dilithium$(DILITHIUM_MODE)_ref -lpqcrystals_fips202_ref -lcrypto + +all: generate_secretkey secretkey_to_publickey create_signature validate_signature + + +generate_secretkey: generate_secretkey.c + $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c $(LDFLAGS) + +secretkey_to_publickey: secretkey_to_publickey.c + $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c $(LDFLAGS) + +create_signature: create_signature.c + $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c $(LDFLAGS) + +validate_signature: validate_signature.c + $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c $(LDFLAGS) + +clean: + rm -f generate_secretkey secretkey_to_public create_signature validate_signature diff --git a/example/create_signature.c b/example/create_signature.c new file mode 100644 index 0000000..eb6f6dd --- /dev/null +++ b/example/create_signature.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include +#include "size.h" +#include + +int main(int argc, char *argv[]) { + uint8_t sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; + uint8_t sig[PQCLEAN_DILITHIUM5_CRYPTO_BYTES]; + size_t siglen; + FILE *sk_file, *msg_file; + uint8_t *msg; + size_t msg_len; + int opt; + char *sk_path = NULL, *msg_path = NULL; + + while ((opt = getopt(argc, argv, "k:i:")) != -1) { + switch (opt) { + case 'k': sk_path = optarg; break; + case 'i': msg_path = optarg; break; + default: + fprintf(stderr, "Usage: %s -k private -i plaintext\n", argv[0]); + return 1; + } + } + + if (!sk_path || !msg_path) { + fprintf(stderr, "Missing required arguments\n"); + return 1; + } + + // Read secret key + sk_file = fopen(sk_path, "rb"); + if (!sk_file || fread(sk, 1, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES, sk_file) != PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES) { + fprintf(stderr, "Error reading secret key\n"); + return 1; + } + fclose(sk_file); + + // Read message + msg_file = fopen(msg_path, "rb"); + if (!msg_file) { + fprintf(stderr, "Error opening message file\n"); + return 1; + } + fseek(msg_file, 0, SEEK_END); + msg_len = ftell(msg_file); + fseek(msg_file, 0, SEEK_SET); + msg = malloc(msg_len); + if (!msg || fread(msg, 1, msg_len, msg_file) != msg_len) { + fprintf(stderr, "Error reading message\n"); + return 1; + } + fclose(msg_file); + + // Create signature + if (pqcrystals_dilithium5_ref_signature( + sig, &siglen, + msg, msg_len, + NULL, 0, + sk + ) != 0) { + fprintf(stderr, "Signature creation failed\n"); + return 1; + } + + // Write signature to stdout + fwrite(sig, 1, siglen, stdout); + free(msg); + return 0; +} \ No newline at end of file diff --git a/example/generate_secretkey.c b/example/generate_secretkey.c new file mode 100644 index 0000000..091f797 --- /dev/null +++ b/example/generate_secretkey.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include "size.h" + +int main(void) { + unsigned char sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; + unsigned char pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; + + // Generate keypair + if (pqcrystals_dilithium5_ref_keypair(pk, sk) != 0) { + fprintf(stderr, "Key generation failed\n"); + return 1; + } + + // Write secret key to stdout + fwrite(sk, 1, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES, stdout); + return 0; +} \ No newline at end of file diff --git a/example/runtest.sh b/example/runtest.sh new file mode 100644 index 0000000..83cc0ec --- /dev/null +++ b/example/runtest.sh @@ -0,0 +1,15 @@ +#! /usr/bin/env bash + +# Generate a secret key +./generate_secretkey > secret.key + +# Generate the corresponding public key +cat secret.key | ./secretkey_to_publickey > public.key + +# Create a signature for a message +echo "Hello, World!" > message.txt +./create_signature -k secret.key -i message.txt > signature.bin + +# Verify the signature +./validate_signature -p public.key -i message.txt -s signature.bin +echo $? # Should print 0 if signature is valid \ No newline at end of file diff --git a/example/secretkey_to_publickey.c b/example/secretkey_to_publickey.c new file mode 100644 index 0000000..bec7167 --- /dev/null +++ b/example/secretkey_to_publickey.c @@ -0,0 +1,24 @@ +#include +#include +#include "size.h" + +int main(void) { + unsigned char sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; + unsigned char pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; + + // Read secret key from stdin + if (fread(sk, 1, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES, stdin) != PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES) { + fprintf(stderr, "Error reading secret key\n"); + return 1; + } + + // Extract public key from secret key + if (pqcrystals_dilithium5_ref_keypair(pk, sk) != 0) { + fprintf(stderr, "Error extracting public key\n"); + return 1; + } + + // Write public key to stdout + fwrite(pk, 1, PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES, stdout); + return 0; +} \ No newline at end of file diff --git a/example/size.h b/example/size.h new file mode 100644 index 0000000..1aa81ce --- /dev/null +++ b/example/size.h @@ -0,0 +1,5 @@ +#pragma once +#include +uint32_t PQCLEAN_DILITHIUM5_CRYPTO_BYTES = 4627; +uint32_t PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES = 4896; +uint32_t PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES = 2592; \ No newline at end of file diff --git a/example/validate_signature.c b/example/validate_signature.c new file mode 100644 index 0000000..705b197 --- /dev/null +++ b/example/validate_signature.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include "size.h" + +#define CONTEXT_LEN 13 + +int main(int argc, char *argv[]) { + unsigned char pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; + unsigned char sig[PQCLEAN_DILITHIUM5_CRYPTO_BYTES]; + unsigned char ctx[CONTEXT_LEN] = { 0 }; + FILE *pk_file, *sig_file, *msg_file; + unsigned char *msg; + size_t msg_len; + int opt; + char *pk_path = NULL, *sig_path = NULL, *msg_path = NULL; + + while ((opt = getopt(argc, argv, "p:s:i:")) != -1) { + switch (opt) { + case 'p': pk_path = optarg; break; + case 's': sig_path = optarg; break; + case 'i': msg_path = optarg; break; + default: + fprintf(stderr, "Usage: %s -p publickey -i plaintext -s signature\n", argv[0]); + return 1; + } + } + + if (!pk_path || !sig_path || !msg_path) { + fprintf(stderr, "Missing required arguments\n"); + return 1; + } + + // Read public key + pk_file = fopen(pk_path, "rb"); + if (!pk_file || fread(pk, 1, PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES, pk_file) != PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES) { + fprintf(stderr, "Error reading public key\n"); + return 1; + } + fclose(pk_file); + + // Read signature + sig_file = fopen(sig_path, "rb"); + if (!sig_file || fread(sig, 1, PQCLEAN_DILITHIUM5_CRYPTO_BYTES, sig_file) != PQCLEAN_DILITHIUM5_CRYPTO_BYTES) { + fprintf(stderr, "Error reading signature\n"); + return 1; + } + fclose(sig_file); + + // Read message + msg_file = fopen(msg_path, "rb"); + if (!msg_file) { + fprintf(stderr, "Error opening message file\n"); + return 1; + } + fseek(msg_file, 0, SEEK_END); + msg_len = ftell(msg_file); + fseek(msg_file, 0, SEEK_SET); + msg = malloc(msg_len); + if (!msg || fread(msg, 1, msg_len, msg_file) != msg_len) { + fprintf(stderr, "Error reading message\n"); + return 1; + } + fclose(msg_file); + + // Verify signature + int result = pqcrystals_dilithium5_ref_verify( + sig, PQCLEAN_DILITHIUM5_CRYPTO_BYTES, + msg, msg_len, + ctx, CONTEXT_LEN, + pk + ); + free(msg); + return result; +} \ No newline at end of file diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..046dfd5 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1733759999, + "narHash": "sha256-463SNPWmz46iLzJKRzO3Q2b0Aurff3U1n0nYItxq7jU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a73246e2eef4c6ed172979932bc80e1404ba2d56", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 74f6c6f..2528951 100644 --- a/flake.nix +++ b/flake.nix @@ -10,70 +10,125 @@ flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; - in - { - packages.default = pkgs.stdenv.mkDerivation { - name = "dilithium"; - src = ./.; + dilithium = pkgs.stdenv.mkDerivation { + name = "dilithium"; + src = ./.; - nativeBuildInputs = with pkgs; [ - clang - openssl - ]; + nativeBuildInputs = with pkgs; [ + clang + openssl + ]; - buildPhase = '' - # Build reference implementation - make -C ref -j$NIX_BUILD_CORES - - # Build AVX2 implementation if supported - if [ "$(uname -m)" = "x86_64" ]; then - make -C avx2 -j$NIX_BUILD_CORES - fi - ''; - - installPhase = '' - mkdir -p $out/bin - - # Install reference implementation binaries - for alg in 2 3 5; do - cp ref/test/test_dilithium$alg $out/bin/ - cp ref/test/test_vectors$alg $out/bin/ - done - - # Install AVX2 binaries if built - if [ "$(uname -m)" = "x86_64" ]; then + buildPhase = '' + # Save the current directory to buildDir + buildDir=$PWD + + # Build reference implementation with shared libraries + cd ref + make -j$NIX_BUILD_CORES + make shared + + # Build all tests for reference implementation for alg in 2 3 5; do - cp avx2/test/test_dilithium$alg $out/bin/test_dilithium$alg-avx2 - cp avx2/test/test_vectors$alg $out/bin/test_vectors$alg-avx2 + make test/test_dilithium$alg + make test/test_vectors$alg done - fi - ''; - - checkPhase = '' - # Run tests for reference implementation - for alg in 2 3 5; do - ref/test/test_dilithium$alg - ref/test/test_vectors$alg > tvecs$alg - done - - # Run tests for AVX2 implementation if available - if [ "$(uname -m)" = "x86_64" ]; then + + # Build AVX2 implementation if supported + if [ "$(uname -m)" = "x86_64" ]; then + cd ../avx2 + make -j$NIX_BUILD_CORES + make shared + + # Build all tests for AVX2 implementation + for alg in 2 3 5; do + make test/test_dilithium$alg + make test/test_vectors$alg + done + fi + ''; + + installPhase = '' + mkdir -p $out/lib $out/include/dilithium + + cp -r $src/ref/*.h $out/include/dilithium/ + cp -r $buildDir/ref/libpqcrystals_*_ref.so $out/lib/ + + # Install AVX2 implementation libraries if built + if [ "$(uname -m)" = "x86_64" ]; then + cp -r $buildDir/avx2/libpqcrystals_*_avx2.so $out/lib/ + fi + ''; + + checkPhase = '' + mkdir -p $TMPDIR/test-outputs + + # Run tests for alg in 2 3 5; do - avx2/test/test_dilithium$alg - avx2/test/test_vectors$alg > tvecs$alg-avx2 + ./test/test_dilithium$alg + ./test/test_vectors$alg > $TMPDIR/test-outputs/tvecs$alg done - fi - sha256sum -c SHA256SUMS - ''; + # Verify checksums from temporary directory + cd $TMPDIR/test-outputs + sha256sum -c $src/SHA256SUMS + ''; - doCheck = true; + doCheck = false; + }; + in + { + packages = { + inherit dilithium; + default = dilithium; + + examples = pkgs.stdenv.mkDerivation { + name = "dilithium-examples"; + src = ./.; + propagatedBuildInputs = [ dilithium ]; + + nativeBuildInputs = with pkgs; [ + gcc + openssl + ]; + + buildPhase = '' + export DILITHIUM_INCLUDE_DIR="${dilithium}/include" + export DILITHIUM_LIB_DIR="${dilithium}/lib" + export LD_LIBRARY_PATH="${dilithium}/lib:$LD_LIBRARY_PATH" + + cd example + make -j$NIX_BUILD_CORES + ''; + + installPhase = '' + mkdir -p $out/bin $out/lib + + # Install example binaries + cp generate_secretkey $out/bin/ + cp secretkey_to_publickey $out/bin/ + cp create_signature $out/bin/ + cp validate_signature $out/bin/ + + # Create wrapper scripts that set LD_LIBRARY_PATH + for bin in generate_secretkey secretkey_to_publickey create_signature validate_signature; do + mv $out/bin/$bin $out/bin/$bin.real + cat > $out/bin/$bin < Date: Wed, 11 Dec 2024 01:54:42 -0300 Subject: [PATCH 3/4] fix: cryptography --- .gitignore | 9 +++ example/Makefile | 18 ++--- example/base64.c | 109 +++++++++++++++++++++++++++++++ example/base64.h | 14 ++++ example/create_signature.c | 97 +++++++++++++++++++++------ example/debug.h | 19 ++++++ example/example_base64.c | 65 ++++++++++++++++++ example/generate_secretkey.c | 65 +++++++++++++++++- example/runtest.sh | 27 +++++--- example/secretkey_to_publickey | Bin 0 -> 16904 bytes example/secretkey_to_publickey.c | 24 ------- example/test_dilithium.c | 75 +++++++++++++++++++++ example/validate_signature.c | 45 ++++++++----- flake.nix | 9 ++- 14 files changed, 493 insertions(+), 83 deletions(-) create mode 100644 example/base64.c create mode 100644 example/base64.h create mode 100644 example/debug.h create mode 100644 example/example_base64.c mode change 100644 => 100755 example/runtest.sh create mode 100755 example/secretkey_to_publickey delete mode 100644 example/secretkey_to_publickey.c create mode 100644 example/test_dilithium.c diff --git a/.gitignore b/.gitignore index bb26caa..7351865 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,12 @@ tvecs2 tvecs3 tvecs5 result +example/generate_secretkey +example/create_signature +example/validate_signature +example/test_dilithium +example/message.txt +example/public.key +example/secret.key +example/signature.bin +example/example_base64 diff --git a/example/Makefile b/example/Makefile index 0e7167d..e26588c 100644 --- a/example/Makefile +++ b/example/Makefile @@ -13,20 +13,20 @@ ifeq ($(USE_AVX2),1) endif LDFLAGS += -lpqcrystals_dilithium$(DILITHIUM_MODE)_ref -lpqcrystals_fips202_ref -lcrypto -all: generate_secretkey secretkey_to_publickey create_signature validate_signature +all: generate_secretkey create_signature validate_signature test_dilithium -generate_secretkey: generate_secretkey.c - $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c $(LDFLAGS) +generate_secretkey: generate_secretkey.c base64.c + $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) -secretkey_to_publickey: secretkey_to_publickey.c - $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c $(LDFLAGS) +create_signature: create_signature.c base64.c + $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) -create_signature: create_signature.c - $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c $(LDFLAGS) +validate_signature: validate_signature.c base64.c + $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) -validate_signature: validate_signature.c +test_dilithium: test_dilithium.c $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c $(LDFLAGS) clean: - rm -f generate_secretkey secretkey_to_public create_signature validate_signature + rm -f generate_secretkey create_signature validate_signature test_dilithium message.txt public.key secret.key signature.bin diff --git a/example/base64.c b/example/base64.c new file mode 100644 index 0000000..32ace90 --- /dev/null +++ b/example/base64.c @@ -0,0 +1,109 @@ +#include "base64.h" +#include +#include +#include +#include + +#define MAX_LINE_LENGTH 1024 +#define MAX_BASE64_LENGTH 8192 + +// Add at the top, after includes +static int debug_output = 0; + +int read_from_base64_file(const char* filepath, const char* header, const char* footer, + uint8_t* output, size_t expected_size) { + FILE* file = fopen(filepath, "r"); + if (!file) { + fprintf(stderr, "Failed to open file\n"); + return -1; + } + + // Skip header + char line[MAX_LINE_LENGTH]; + if (!fgets(line, sizeof(line), file)) { + fprintf(stderr, "Failed to read header\n"); + fclose(file); + return -3; + } + + // Read base64 content into a temporary buffer + char base64_data[MAX_BASE64_LENGTH] = {0}; + char temp_line[MAX_LINE_LENGTH]; + size_t total_len = 0; + + // Read all lines until footer + while (fgets(temp_line, sizeof(temp_line), file)) { + if (strstr(temp_line, footer) != NULL) { + break; + } + // Remove trailing newline if present + size_t line_len = strlen(temp_line); + if (line_len > 0 && temp_line[line_len-1] == '\n') { + temp_line[line_len-1] = '\0'; + line_len--; + } + // Append to base64_data + if (total_len + line_len < sizeof(base64_data)) { + strcat(base64_data, temp_line); + total_len += line_len; + } else { + fprintf(stderr, "Base64 buffer overflow! Need more than %zu bytes\n", sizeof(base64_data)); + fclose(file); + return -5; + } + } + + // Modify debug output to use debug flag + if (debug_output) { + fprintf(stderr, "Base64 data length: %zu\n", strlen(base64_data)); + } + + // Setup BIO chain for base64 decoding + BIO* bio_mem = BIO_new_mem_buf(base64_data, -1); + BIO* bio_b64 = BIO_new(BIO_f_base64()); + BIO* bio_chain = BIO_push(bio_b64, bio_mem); + + // Disable newline checking + BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL); + + // Read and decode + size_t total_bytes = BIO_read(bio_chain, output, expected_size); + + // Modify debug output to use debug flag + if (debug_output) { + fprintf(stderr, "Decoded %zu bytes, expected %zu bytes\n", total_bytes, expected_size); + } + + fclose(file); + BIO_free_all(bio_chain); + + return (total_bytes == expected_size) ? 0 : -4; +} + +int write_to_base64_file(const char* filepath, const char* header, const char* footer, + const uint8_t* data, size_t data_len) { + FILE* file = fopen(filepath, "w"); + if (!file) { + return -1; + } + + // Setup BIO chain for base64 encoding + BIO* bio_b64 = BIO_new(BIO_f_base64()); + BIO* bio_mem = BIO_new(BIO_s_mem()); + BIO* bio_chain = BIO_push(bio_b64, bio_mem); + BUF_MEM* buffer_ptr; + + // Write data and flush + BIO_write(bio_chain, data, data_len); + BIO_flush(bio_chain); + BIO_get_mem_ptr(bio_chain, &buffer_ptr); + + // Write to file with headers + fprintf(file, "%s\n", header); + fprintf(file, "%.*s", (int)buffer_ptr->length, buffer_ptr->data); + fprintf(file, "%s\n", footer); + + BIO_free_all(bio_chain); + fclose(file); + return 0; +} \ No newline at end of file diff --git a/example/base64.h b/example/base64.h new file mode 100644 index 0000000..f6ddf62 --- /dev/null +++ b/example/base64.h @@ -0,0 +1,14 @@ +#ifndef BASE64_H +#define BASE64_H + +#include +#include +#include + +int read_from_base64_file(const char* filepath, const char* header, const char* footer, + uint8_t* output, size_t expected_size); + +int write_to_base64_file(const char* filepath, const char* header, const char* footer, + const uint8_t* data, size_t data_len); + +#endif // BASE64_H \ No newline at end of file diff --git a/example/create_signature.c b/example/create_signature.c index eb6f6dd..90a694f 100644 --- a/example/create_signature.c +++ b/example/create_signature.c @@ -6,39 +6,88 @@ #include #include "size.h" #include +#include +#include +#include +#include "debug.h" +#include "base64.h" + +#define MAX_LINE_LENGTH 1024 int main(int argc, char *argv[]) { uint8_t sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; + uint8_t pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; uint8_t sig[PQCLEAN_DILITHIUM5_CRYPTO_BYTES]; size_t siglen; - FILE *sk_file, *msg_file; + FILE *sk_file = NULL, *msg_file = NULL; uint8_t *msg; size_t msg_len; int opt; - char *sk_path = NULL, *msg_path = NULL; + char *sk_path = NULL, *msg_path = NULL, *pk_path = NULL; + char line[MAX_LINE_LENGTH]; + int in_key = 0; + size_t line_length; + uint8_t buffer[1024]; + size_t total_bytes = 0; + int bytes_read; - while ((opt = getopt(argc, argv, "k:i:")) != -1) { + while ((opt = getopt(argc, argv, "s:i:p:")) != -1) { switch (opt) { - case 'k': sk_path = optarg; break; + case 's': sk_path = optarg; break; case 'i': msg_path = optarg; break; + case 'p': pk_path = optarg; break; default: - fprintf(stderr, "Usage: %s -k private -i plaintext\n", argv[0]); + fprintf(stderr, "Usage: %s -s secret_key -i plaintext -p public_key\n", argv[0]); return 1; } } - if (!sk_path || !msg_path) { + if (!sk_path || !msg_path || !pk_path) { fprintf(stderr, "Missing required arguments\n"); return 1; } - // Read secret key - sk_file = fopen(sk_path, "rb"); - if (!sk_file || fread(sk, 1, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES, sk_file) != PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES) { - fprintf(stderr, "Error reading secret key\n"); + // Read and decode base64 secret key + FILE *debug_sk_file = fopen(sk_path, "r"); + if (!debug_sk_file) { + fprintf(stderr, "Error opening secret key file: %s\n", sk_path); + return 1; + } + + // Debug: Print raw file contents + printf("Reading secret key from: %s\n", sk_path); + char debug_buffer[256]; + while (fgets(debug_buffer, sizeof(debug_buffer), debug_sk_file)) { + printf("Line: %s", debug_buffer); + } + fclose(debug_sk_file); + + printf("Attempting to decode base64 with:\n"); + printf("Header: %s\n", "-----BEGIN DILITHIUM SECRET KEY-----"); + printf("Footer: %s\n", "-----END DILITHIUM SECRET KEY-----"); + printf("Expected key size: %u bytes\n", PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES); + + int read_result = read_from_base64_file(sk_path, + "-----BEGIN DILITHIUM SECRET KEY-----", + "-----END DILITHIUM SECRET KEY-----", + sk, + PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES); + if (read_result != 0) { + fprintf(stderr, "Error reading secret key (code: %d)\n", read_result); + return 1; + } + debug_hexa("Secret key", sk, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES); + + // Read and decode base64 public key + if (read_from_base64_file(pk_path, + "-----BEGIN DILITHIUM PUBLIC KEY-----", + "-----END DILITHIUM PUBLIC KEY-----", + pk, + PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES) != 0) { + fprintf(stderr, "Error reading public key\n"); return 1; } - fclose(sk_file); + debug_hexa("Public key", pk, PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES); // Read message msg_file = fopen(msg_path, "rb"); @@ -55,20 +104,30 @@ int main(int argc, char *argv[]) { return 1; } fclose(msg_file); + // Debug output: message length and hex dump + debug_hexa("Message", msg, msg_len); // Create signature - if (pqcrystals_dilithium5_ref_signature( - sig, &siglen, - msg, msg_len, - NULL, 0, - sk - ) != 0) { + if (pqcrystals_dilithium5_ref_signature(sig, &siglen, msg, msg_len, NULL, 0, sk) != 0) { fprintf(stderr, "Signature creation failed\n"); return 1; } - // Write signature to stdout - fwrite(sig, 1, siglen, stdout); + // Immediately verify the signature before outputting + if (pqcrystals_dilithium5_ref_verify(sig, siglen, msg, msg_len, NULL, 0, pk) != 0) { + fprintf(stderr, "Signature verification failed - internal error\n"); + return 1; + } + + // Write signature to stdout using base64 functions + if (write_to_base64_file("/dev/stdout", + "-----BEGIN DILITHIUM SIGNATURE-----", + "-----END DILITHIUM SIGNATURE-----", + sig, siglen) != 0) { + fprintf(stderr, "Error writing signature\n"); + return 1; + } + free(msg); return 0; } \ No newline at end of file diff --git a/example/debug.h b/example/debug.h new file mode 100644 index 0000000..d8b78d6 --- /dev/null +++ b/example/debug.h @@ -0,0 +1,19 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#include +#include + +void debug_hexa(const char* name, const uint8_t* array, size_t length) { + printf("%s length: %zu bytes\n", name, length); + printf("%s hex dump: ", name); + for (size_t i = 0; i < length; i++) { + printf("%02x", array[i]); + if ((i + 1) % 32 == 0 && i + 1 < length) { + printf("\n "); + } + } + printf("\n"); +} + +#endif \ No newline at end of file diff --git a/example/example_base64.c b/example/example_base64.c new file mode 100644 index 0000000..ca5b2ac --- /dev/null +++ b/example/example_base64.c @@ -0,0 +1,65 @@ +#include +#include +#include "base64.h" + +#define TEST_DATA_SIZE 80 + +int main() { + // Test data + uint8_t original_data[TEST_DATA_SIZE]; + uint8_t decoded_data[TEST_DATA_SIZE]; + + // Initialize test data + for (int i = 0; i < TEST_DATA_SIZE; i++) { + original_data[i] = i; + } + + const char* header = "-----BEGIN TEST DATA-----"; + const char* footer = "-----END TEST DATA-----"; + + // Test writing + printf("Writing test data to file...\n"); + int write_result = write_to_base64_file("test.b64", header, footer, + original_data, TEST_DATA_SIZE); + if (write_result != 0) { + printf("Error writing base64 file: %d\n", write_result); + return 1; + } + + // Test reading + printf("Reading test data from file...\n"); + int read_result = read_from_base64_file("test.b64", header, footer, + decoded_data, TEST_DATA_SIZE); + if (read_result != 0) { + printf("Error reading base64 file: %d\n", read_result); + // Enhanced debug information + FILE *fp = fopen("test.b64", "r"); + if (fp) { + char buffer[256]; + printf("File contents (with hex for newlines):\n"); + while (fgets(buffer, sizeof(buffer), fp)) { + printf("Line: "); + for (size_t i = 0; buffer[i]; i++) { + if (buffer[i] == '\n') { + printf("\\n[0x%02X]", buffer[i]); + } else { + printf("%c", buffer[i]); + } + } + printf("\n"); + } + fclose(fp); + } + return 1; + } + + // Compare results + if (memcmp(original_data, decoded_data, TEST_DATA_SIZE) == 0) { + printf("Test passed! Data matches after encode/decode cycle\n"); + } else { + printf("Test failed! Data mismatch after encode/decode cycle\n"); + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/example/generate_secretkey.c b/example/generate_secretkey.c index 091f797..dc68117 100644 --- a/example/generate_secretkey.c +++ b/example/generate_secretkey.c @@ -2,18 +2,77 @@ #include #include #include "size.h" +#include +#include +#include +#include +#include "debug.h" +#include "base64.h" -int main(void) { +#define DEBUG_BASE64 0 + +int main(int argc, char *argv[]) { unsigned char sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; unsigned char pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; + int opt; + char *pk_path = NULL; + char *sk_path = NULL; + + // Parse command line arguments + while ((opt = getopt(argc, argv, "p:s:")) != -1) { + switch (opt) { + case 'p': pk_path = optarg; break; + case 's': sk_path = optarg; break; + default: + fprintf(stderr, "Usage: %s -p public_key_file -s secret_key_file\n", argv[0]); + return 1; + } + } + // Add check for secret key path + if (!sk_path) { + fprintf(stderr, "Error: Secret key output path (-s) is required\n"); + return 1; + } + + // Base64 encode and save public key + // Now required - error if no path provided + if (!pk_path) { + fprintf(stderr, "Error: Public key output path (-p) is required\n"); + return 1; + } + // Generate keypair if (pqcrystals_dilithium5_ref_keypair(pk, sk) != 0) { fprintf(stderr, "Key generation failed\n"); return 1; } - // Write secret key to stdout - fwrite(sk, 1, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES, stdout); + // Debug output for generated keys + if (DEBUG_BASE64) { + debug_hexa("Public Key", pk, PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES); + debug_hexa("Secret Key", sk, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES); + } + + // Replace public key writing code with + if (write_to_base64_file(pk_path, + "-----BEGIN DILITHIUM PUBLIC KEY-----", + "-----END DILITHIUM PUBLIC KEY-----", + pk, + PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES) != 0) { + fprintf(stderr, "Error writing public key\n"); + return 1; + } + + // Replace secret key writing code with + if (write_to_base64_file(sk_path, + "-----BEGIN DILITHIUM SECRET KEY-----", + "-----END DILITHIUM SECRET KEY-----", + sk, + PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES) != 0) { + fprintf(stderr, "Error writing secret key\n"); + return 1; + } + return 0; } \ No newline at end of file diff --git a/example/runtest.sh b/example/runtest.sh old mode 100644 new mode 100755 index 83cc0ec..15e401b --- a/example/runtest.sh +++ b/example/runtest.sh @@ -1,15 +1,22 @@ #! /usr/bin/env bash -# Generate a secret key -./generate_secretkey > secret.key +echo "๐Ÿ”‘ Generating keys..." +# Generate both secret and public keys at once +./generate_secretkey -p public.key -s secret.key +echo "โœ… Keys generated" -# Generate the corresponding public key -cat secret.key | ./secretkey_to_publickey > public.key - -# Create a signature for a message +echo -e "\n๐Ÿ“ Creating test message..." echo "Hello, World!" > message.txt -./create_signature -k secret.key -i message.txt > signature.bin +echo "โœ… Message created" + +echo -e "\n๐Ÿ–‹๏ธ Signing message..." +./create_signature -s secret.key -p public.key -i message.txt > signature.bin +echo "โœ… Signature created" -# Verify the signature -./validate_signature -p public.key -i message.txt -s signature.bin -echo $? # Should print 0 if signature is valid \ No newline at end of file +echo -e "\n๐Ÿ” Verifying signature..." +./validate_signature -p public.key -i message.txt -s signature.bin 2> /dev/null +if [ $? -eq 0 ]; then + echo "โœ… Signature is valid!" +else + echo "โŒ Signature verification failed!" +fi diff --git a/example/secretkey_to_publickey b/example/secretkey_to_publickey new file mode 100755 index 0000000000000000000000000000000000000000..6b849c3f1031166c23676eae38ec92d90043f83c GIT binary patch literal 16904 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 B3+?~_ literal 0 HcmV?d00001 diff --git a/example/secretkey_to_publickey.c b/example/secretkey_to_publickey.c deleted file mode 100644 index bec7167..0000000 --- a/example/secretkey_to_publickey.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include "size.h" - -int main(void) { - unsigned char sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; - unsigned char pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; - - // Read secret key from stdin - if (fread(sk, 1, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES, stdin) != PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES) { - fprintf(stderr, "Error reading secret key\n"); - return 1; - } - - // Extract public key from secret key - if (pqcrystals_dilithium5_ref_keypair(pk, sk) != 0) { - fprintf(stderr, "Error extracting public key\n"); - return 1; - } - - // Write public key to stdout - fwrite(pk, 1, PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES, stdout); - return 0; -} \ No newline at end of file diff --git a/example/test_dilithium.c b/example/test_dilithium.c new file mode 100644 index 0000000..e78f1d5 --- /dev/null +++ b/example/test_dilithium.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include "size.h" + +#define NUM_ITERATIONS 10 +#define MAX_MSG_LEN 100 + +int test_iteration(size_t msg_len) { + // Generate random message + uint8_t msg[MAX_MSG_LEN]; + randombytes(msg, msg_len); + + printf("\nTesting with %zu byte message: ", msg_len); + for(size_t i = 0; i < msg_len && i < 16; i++) { + printf("%02x", msg[i]); + } + if (msg_len > 16) printf("..."); + printf("\n"); + + // Generate keypair + uint8_t pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; + + if (pqcrystals_dilithium5_ref_keypair(pk, sk) != 0) { + fprintf(stderr, "โŒ Key generation failed!\n"); + return 1; + } + + // Create signature + uint8_t sig[PQCLEAN_DILITHIUM5_CRYPTO_BYTES]; + size_t siglen; + + if (pqcrystals_dilithium5_ref_signature(sig, &siglen, msg, msg_len, NULL, 0, sk) != 0) { + fprintf(stderr, "โŒ Signature creation failed!\n"); + return 1; + } + + // Verify signature + int verify_result = pqcrystals_dilithium5_ref_verify(sig, siglen, msg, msg_len, NULL, 0, pk); + + if (verify_result != 0) { + fprintf(stderr, "โŒ Signature verification failed! (error code: %d)\n", verify_result); + return 1; + } + + printf("โœ… Success (message: %zu bytes, signature: %zu bytes)\n", msg_len, siglen); + return 0; +} + +int main(void) { + printf("Running %d iterations with varying message sizes...\n", NUM_ITERATIONS); + + size_t message_sizes[] = {0, 1, 13, 32, 64, 100}; + int num_sizes = sizeof(message_sizes) / sizeof(message_sizes[0]); + + int failed = 0; + for (int i = 0; i < NUM_ITERATIONS; i++) { + printf("\nIteration %d/%d:\n", i + 1, NUM_ITERATIONS); + + for (int s = 0; s < num_sizes; s++) { + if (test_iteration(message_sizes[s]) != 0) { + failed++; + } + } + } + + printf("\nTest summary:\n"); + printf("Total iterations: %d\n", NUM_ITERATIONS * num_sizes); + printf("Failed: %d\n", failed); + printf("Succeeded: %d\n", NUM_ITERATIONS * num_sizes - failed); + + return failed ? 1 : 0; +} \ No newline at end of file diff --git a/example/validate_signature.c b/example/validate_signature.c index 705b197..89dfd90 100644 --- a/example/validate_signature.c +++ b/example/validate_signature.c @@ -4,18 +4,24 @@ #include #include #include "size.h" +#include +#include +#include +#include "base64.h" -#define CONTEXT_LEN 13 +#define MAX_LINE_LENGTH 1024 int main(int argc, char *argv[]) { unsigned char pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; unsigned char sig[PQCLEAN_DILITHIUM5_CRYPTO_BYTES]; - unsigned char ctx[CONTEXT_LEN] = { 0 }; FILE *pk_file, *sig_file, *msg_file; unsigned char *msg; size_t msg_len; int opt; char *pk_path = NULL, *sig_path = NULL, *msg_path = NULL; + char line[MAX_LINE_LENGTH]; + int in_key = 0; + BIO *bio, *b64; while ((opt = getopt(argc, argv, "p:s:i:")) != -1) { switch (opt) { @@ -33,21 +39,25 @@ int main(int argc, char *argv[]) { return 1; } - // Read public key - pk_file = fopen(pk_path, "rb"); - if (!pk_file || fread(pk, 1, PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES, pk_file) != PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES) { + // Read and decode base64 public key + if (read_from_base64_file(pk_path, + "-----BEGIN DILITHIUM PUBLIC KEY-----", + "-----END DILITHIUM PUBLIC KEY-----", + pk, + PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES) != 0) { fprintf(stderr, "Error reading public key\n"); return 1; } - fclose(pk_file); - // Read signature - sig_file = fopen(sig_path, "rb"); - if (!sig_file || fread(sig, 1, PQCLEAN_DILITHIUM5_CRYPTO_BYTES, sig_file) != PQCLEAN_DILITHIUM5_CRYPTO_BYTES) { + // Read and decode base64 signature + if (read_from_base64_file(sig_path, + "-----BEGIN DILITHIUM SIGNATURE-----", + "-----END DILITHIUM SIGNATURE-----", + sig, + PQCLEAN_DILITHIUM5_CRYPTO_BYTES) != 0) { fprintf(stderr, "Error reading signature\n"); return 1; } - fclose(sig_file); // Read message msg_file = fopen(msg_path, "rb"); @@ -66,12 +76,15 @@ int main(int argc, char *argv[]) { fclose(msg_file); // Verify signature - int result = pqcrystals_dilithium5_ref_verify( - sig, PQCLEAN_DILITHIUM5_CRYPTO_BYTES, - msg, msg_len, - ctx, CONTEXT_LEN, - pk - ); + int result = pqcrystals_dilithium5_ref_verify(sig, PQCLEAN_DILITHIUM5_CRYPTO_BYTES, + msg, msg_len, NULL, 0, pk); + + if (result != 0) { + fprintf(stderr, "Signature verification failed\n"); + } else { + fprintf(stderr, "Signature verified successfully!\n"); + } + free(msg); return result; } \ No newline at end of file diff --git a/flake.nix b/flake.nix index 2528951..52c26b4 100644 --- a/flake.nix +++ b/flake.nix @@ -106,12 +106,11 @@ # Install example binaries cp generate_secretkey $out/bin/ - cp secretkey_to_publickey $out/bin/ cp create_signature $out/bin/ cp validate_signature $out/bin/ # Create wrapper scripts that set LD_LIBRARY_PATH - for bin in generate_secretkey secretkey_to_publickey create_signature validate_signature; do + for bin in generate_secretkey create_signature validate_signature; do mv $out/bin/$bin $out/bin/$bin.real cat > $out/bin/$bin < Date: Wed, 11 Dec 2024 01:54:42 -0300 Subject: [PATCH 4/4] chore: rename to different binaries --- .gitignore | 12 +-- example/Makefile | 60 +++++++++++---- example/base64.c | 7 +- example/create_signature.c | 133 -------------------------------- example/debug.h | 19 ----- example/dilithium | 82 ++++++++++++++++++++ example/example_base64.c | 65 ---------------- example/generate_secretkey.c | 78 ------------------- example/keygen.c | 114 ++++++++++++++++++++++++++++ example/runtest.sh | 73 ++++++++++++------ example/secretkey_to_publickey | Bin 16904 -> 0 bytes example/sign.c | 130 ++++++++++++++++++++++++++++++++ example/size.h | 5 -- example/test_dilithium.c | 75 ------------------ example/validate_signature.c | 90 ---------------------- example/verify.c | 134 +++++++++++++++++++++++++++++++++ flake.nix | 84 +++++++++++++-------- 17 files changed, 615 insertions(+), 546 deletions(-) delete mode 100644 example/create_signature.c delete mode 100644 example/debug.h create mode 100755 example/dilithium delete mode 100644 example/example_base64.c delete mode 100644 example/generate_secretkey.c create mode 100644 example/keygen.c delete mode 100755 example/secretkey_to_publickey create mode 100644 example/sign.c delete mode 100644 example/size.h delete mode 100644 example/test_dilithium.c delete mode 100644 example/validate_signature.c create mode 100644 example/verify.c diff --git a/.gitignore b/.gitignore index 7351865..6e06bb8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,12 +8,6 @@ tvecs2 tvecs3 tvecs5 result -example/generate_secretkey -example/create_signature -example/validate_signature -example/test_dilithium -example/message.txt -example/public.key -example/secret.key -example/signature.bin -example/example_base64 +example/dilithium2* +example/dilithium3* +example/dilithium5* diff --git a/example/Makefile b/example/Makefile index e26588c..ef08ffa 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,32 +1,60 @@ CC=gcc -DILITHIUM_MODE ?= 5 USE_AVX2 ?= $(shell if [ `uname -m` = "x86_64" ] && grep -q avx2 /proc/cpuinfo; then echo "1"; else echo "0"; fi) -CFLAGS=-I${DILITHIUM_INCLUDE_DIR} -Wall -Wextra -DDILITHIUM_MODE=$(DILITHIUM_MODE) -CFLAGS += $(shell if [ "$(USE_AVX2)" = "1" ]; then echo "-DHAVE_AVX2"; fi) +CFLAGS=-I${DILITHIUM_INCLUDE_DIR} -Wall -Wextra +CFLAGS += $(shell if grep -q avx2 /proc/cpuinfo; then echo "-DDILITHIUM_USE_AVX2 -mavx2"; fi) -LDFLAGS=-L${DILITHIUM_LIB_DIR} +LDFLAGS ?= -L${DILITHIUM_LIB_DIR} IMPLEMENTATION=$(shell if [ "$(USE_AVX2)" = "1" ]; then echo "avx2"; else echo "ref"; fi) +# Add all Dilithium versions to linker flags ifeq ($(USE_AVX2),1) - LDFLAGS += -lpqcrystals_dilithium$(DILITHIUM_MODE)_avx2 -lpqcrystals_fips202_avx2 -lpqcrystals_fips202x4_avx2 + LDFLAGS += -lpqcrystals_dilithium2_avx2 -lpqcrystals_dilithium3_avx2 -lpqcrystals_dilithium5_avx2 \ + -lpqcrystals_fips202_avx2 -lpqcrystals_fips202x4_avx2 +else + LDFLAGS += -lpqcrystals_dilithium2_ref -lpqcrystals_dilithium3_ref -lpqcrystals_dilithium5_ref -lpqcrystals_fips202_ref endif -LDFLAGS += -lpqcrystals_dilithium$(DILITHIUM_MODE)_ref -lpqcrystals_fips202_ref -lcrypto +LDFLAGS += -lcrypto -all: generate_secretkey create_signature validate_signature test_dilithium +all: dilithium2-keygen dilithium2-sign dilithium2-verify \ + dilithium3-keygen dilithium3-sign dilithium3-verify \ + dilithium5-keygen dilithium5-sign dilithium5-verify -generate_secretkey: generate_secretkey.c base64.c - $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) +dilithium2-keygen: keygen.c base64.c + $(CC) $(CFLAGS) -DDILITHIUM_MODE=2 -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) -create_signature: create_signature.c base64.c - $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) +dilithium2-sign: sign.c base64.c + $(CC) $(CFLAGS) -DDILITHIUM_MODE=2 -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) -validate_signature: validate_signature.c base64.c - $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) +dilithium2-verify: verify.c base64.c + $(CC) $(CFLAGS) -DDILITHIUM_MODE=2 -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) -test_dilithium: test_dilithium.c - $(CC) $(CFLAGS) -o $@ $< ../$(IMPLEMENTATION)/randombytes.c $(LDFLAGS) +dilithium3-keygen: keygen.c base64.c + $(CC) $(CFLAGS) -DDILITHIUM_MODE=3 -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) + +dilithium3-sign: sign.c base64.c + $(CC) $(CFLAGS) -DDILITHIUM_MODE=3 -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) + +dilithium3-verify: verify.c base64.c + $(CC) $(CFLAGS) -DDILITHIUM_MODE=3 -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) + +dilithium5-keygen: keygen.c base64.c + $(CC) $(CFLAGS) -DDILITHIUM_MODE=5 -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) + +dilithium5-sign: sign.c base64.c + $(CC) $(CFLAGS) -DDILITHIUM_MODE=5 -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) + +dilithium5-verify: verify.c base64.c + $(CC) $(CFLAGS) -DDILITHIUM_MODE=5 -o $@ $< ../$(IMPLEMENTATION)/randombytes.c base64.c $(LDFLAGS) + +test: all + ./runtest.sh clean: - rm -f generate_secretkey create_signature validate_signature test_dilithium message.txt public.key secret.key signature.bin + rm -f dilithium2-keygen dilithium2-sign dilithium2-verify \ + dilithium3-keygen dilithium3-sign dilithium3-verify \ + dilithium5-keygen dilithium5-sign dilithium5-verify \ + message*.txt public*.key secret*.key signature*.bin + +.PHONY: all test clean diff --git a/example/base64.c b/example/base64.c index 32ace90..c8562b4 100644 --- a/example/base64.c +++ b/example/base64.c @@ -18,13 +18,18 @@ int read_from_base64_file(const char* filepath, const char* header, const char* return -1; } - // Skip header char line[MAX_LINE_LENGTH]; if (!fgets(line, sizeof(line), file)) { fprintf(stderr, "Failed to read header\n"); fclose(file); return -3; } + // Verify header matches expected + if (strncmp(line, header, strlen(header)) != 0) { + fprintf(stderr, "Invalid header\n"); + fclose(file); + return -2; + } // Read base64 content into a temporary buffer char base64_data[MAX_BASE64_LENGTH] = {0}; diff --git a/example/create_signature.c b/example/create_signature.c deleted file mode 100644 index 90a694f..0000000 --- a/example/create_signature.c +++ /dev/null @@ -1,133 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "size.h" -#include -#include -#include -#include -#include "debug.h" -#include "base64.h" - -#define MAX_LINE_LENGTH 1024 - -int main(int argc, char *argv[]) { - uint8_t sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; - uint8_t pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; - uint8_t sig[PQCLEAN_DILITHIUM5_CRYPTO_BYTES]; - size_t siglen; - FILE *sk_file = NULL, *msg_file = NULL; - uint8_t *msg; - size_t msg_len; - int opt; - char *sk_path = NULL, *msg_path = NULL, *pk_path = NULL; - char line[MAX_LINE_LENGTH]; - int in_key = 0; - size_t line_length; - uint8_t buffer[1024]; - size_t total_bytes = 0; - int bytes_read; - - while ((opt = getopt(argc, argv, "s:i:p:")) != -1) { - switch (opt) { - case 's': sk_path = optarg; break; - case 'i': msg_path = optarg; break; - case 'p': pk_path = optarg; break; - default: - fprintf(stderr, "Usage: %s -s secret_key -i plaintext -p public_key\n", argv[0]); - return 1; - } - } - - if (!sk_path || !msg_path || !pk_path) { - fprintf(stderr, "Missing required arguments\n"); - return 1; - } - - // Read and decode base64 secret key - FILE *debug_sk_file = fopen(sk_path, "r"); - if (!debug_sk_file) { - fprintf(stderr, "Error opening secret key file: %s\n", sk_path); - return 1; - } - - // Debug: Print raw file contents - printf("Reading secret key from: %s\n", sk_path); - char debug_buffer[256]; - while (fgets(debug_buffer, sizeof(debug_buffer), debug_sk_file)) { - printf("Line: %s", debug_buffer); - } - fclose(debug_sk_file); - - printf("Attempting to decode base64 with:\n"); - printf("Header: %s\n", "-----BEGIN DILITHIUM SECRET KEY-----"); - printf("Footer: %s\n", "-----END DILITHIUM SECRET KEY-----"); - printf("Expected key size: %u bytes\n", PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES); - - int read_result = read_from_base64_file(sk_path, - "-----BEGIN DILITHIUM SECRET KEY-----", - "-----END DILITHIUM SECRET KEY-----", - sk, - PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES); - if (read_result != 0) { - fprintf(stderr, "Error reading secret key (code: %d)\n", read_result); - return 1; - } - debug_hexa("Secret key", sk, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES); - - // Read and decode base64 public key - if (read_from_base64_file(pk_path, - "-----BEGIN DILITHIUM PUBLIC KEY-----", - "-----END DILITHIUM PUBLIC KEY-----", - pk, - PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES) != 0) { - fprintf(stderr, "Error reading public key\n"); - return 1; - } - debug_hexa("Public key", pk, PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES); - - // Read message - msg_file = fopen(msg_path, "rb"); - if (!msg_file) { - fprintf(stderr, "Error opening message file\n"); - return 1; - } - fseek(msg_file, 0, SEEK_END); - msg_len = ftell(msg_file); - fseek(msg_file, 0, SEEK_SET); - msg = malloc(msg_len); - if (!msg || fread(msg, 1, msg_len, msg_file) != msg_len) { - fprintf(stderr, "Error reading message\n"); - return 1; - } - fclose(msg_file); - // Debug output: message length and hex dump - debug_hexa("Message", msg, msg_len); - - // Create signature - if (pqcrystals_dilithium5_ref_signature(sig, &siglen, msg, msg_len, NULL, 0, sk) != 0) { - fprintf(stderr, "Signature creation failed\n"); - return 1; - } - - // Immediately verify the signature before outputting - if (pqcrystals_dilithium5_ref_verify(sig, siglen, msg, msg_len, NULL, 0, pk) != 0) { - fprintf(stderr, "Signature verification failed - internal error\n"); - return 1; - } - - // Write signature to stdout using base64 functions - if (write_to_base64_file("/dev/stdout", - "-----BEGIN DILITHIUM SIGNATURE-----", - "-----END DILITHIUM SIGNATURE-----", - sig, siglen) != 0) { - fprintf(stderr, "Error writing signature\n"); - return 1; - } - - free(msg); - return 0; -} \ No newline at end of file diff --git a/example/debug.h b/example/debug.h deleted file mode 100644 index d8b78d6..0000000 --- a/example/debug.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef DEBUG_H -#define DEBUG_H - -#include -#include - -void debug_hexa(const char* name, const uint8_t* array, size_t length) { - printf("%s length: %zu bytes\n", name, length); - printf("%s hex dump: ", name); - for (size_t i = 0; i < length; i++) { - printf("%02x", array[i]); - if ((i + 1) % 32 == 0 && i + 1 < length) { - printf("\n "); - } - } - printf("\n"); -} - -#endif \ No newline at end of file diff --git a/example/dilithium b/example/dilithium new file mode 100755 index 0000000..deac478 --- /dev/null +++ b/example/dilithium @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +# Function to print usage +print_usage() { + echo "Usage:" + echo " Generate keypair: $0 --keygen -v VERSION -p pubkey -s seckey" + echo " Sign message: $0 --sign -v VERSION -s seckey -i message -o signature" + echo " Verify signature: $0 --verify -v VERSION -p pubkey -i message -S signature" + echo "" + echo "Options:" + echo " -v VERSION Dilithium version (2, 3, or 5)" + echo " -p pubkey Public key file" + echo " -s seckey Secret key file" + echo " -i message Input message file" + echo " -o signature Output signature file" + echo " -S signature Signature file (for verify)" +} + +# Get the action first +ACTION="" +case "$1" in + --keygen) ACTION="keygen" ;; + --sign) ACTION="sign" ;; + --verify) ACTION="verify" ;; + *) + echo "Error: Must specify --keygen, --sign, or --verify" >&2 + print_usage + exit 1 + ;; +esac +shift # Remove the action argument + +# Parse remaining arguments +VERSION="" +while getopts ":v:p:s:i:o:S:" opt; do + case $opt in + v) VERSION="$OPTARG" ;; + p|s|i|o|S) ;; # Valid options, handled later + \?) + echo "Invalid option: -$OPTARG" >&2 + print_usage + exit 1 + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + print_usage + exit 1 + ;; + esac +done + +# Validate version +if [[ ! "$VERSION" =~ ^[235]$ ]]; then + echo "Error: Version must be 2, 3, or 5" >&2 + print_usage + exit 1 +fi + +export LD_LIBRARY_PATH=LD_LIBRARY_PATH + +# Get the binary path +BINARY_DIR="$(dirname "$0")" +BINARY="$BINARY_DIR/dilithium${VERSION}-${ACTION}" + +if [ ! -x "$BINARY" ]; then + echo "Error: Binary not found at $BINARY" >&2 + exit 1 +fi + +# Reset argument parsing to pass all arguments except -v and the action +OPTIND=1 +args=() +while [ "$#" -gt 0 ]; do + if [ "$1" = "-v" ]; then + shift 2 + else + args+=("$1") + shift + fi +done + +exec "$BINARY" "${args[@]}" diff --git a/example/example_base64.c b/example/example_base64.c deleted file mode 100644 index ca5b2ac..0000000 --- a/example/example_base64.c +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include -#include "base64.h" - -#define TEST_DATA_SIZE 80 - -int main() { - // Test data - uint8_t original_data[TEST_DATA_SIZE]; - uint8_t decoded_data[TEST_DATA_SIZE]; - - // Initialize test data - for (int i = 0; i < TEST_DATA_SIZE; i++) { - original_data[i] = i; - } - - const char* header = "-----BEGIN TEST DATA-----"; - const char* footer = "-----END TEST DATA-----"; - - // Test writing - printf("Writing test data to file...\n"); - int write_result = write_to_base64_file("test.b64", header, footer, - original_data, TEST_DATA_SIZE); - if (write_result != 0) { - printf("Error writing base64 file: %d\n", write_result); - return 1; - } - - // Test reading - printf("Reading test data from file...\n"); - int read_result = read_from_base64_file("test.b64", header, footer, - decoded_data, TEST_DATA_SIZE); - if (read_result != 0) { - printf("Error reading base64 file: %d\n", read_result); - // Enhanced debug information - FILE *fp = fopen("test.b64", "r"); - if (fp) { - char buffer[256]; - printf("File contents (with hex for newlines):\n"); - while (fgets(buffer, sizeof(buffer), fp)) { - printf("Line: "); - for (size_t i = 0; buffer[i]; i++) { - if (buffer[i] == '\n') { - printf("\\n[0x%02X]", buffer[i]); - } else { - printf("%c", buffer[i]); - } - } - printf("\n"); - } - fclose(fp); - } - return 1; - } - - // Compare results - if (memcmp(original_data, decoded_data, TEST_DATA_SIZE) == 0) { - printf("Test passed! Data matches after encode/decode cycle\n"); - } else { - printf("Test failed! Data mismatch after encode/decode cycle\n"); - return 1; - } - - return 0; -} \ No newline at end of file diff --git a/example/generate_secretkey.c b/example/generate_secretkey.c deleted file mode 100644 index dc68117..0000000 --- a/example/generate_secretkey.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include "size.h" -#include -#include -#include -#include -#include "debug.h" -#include "base64.h" - -#define DEBUG_BASE64 0 - -int main(int argc, char *argv[]) { - unsigned char sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; - unsigned char pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; - int opt; - char *pk_path = NULL; - char *sk_path = NULL; - - // Parse command line arguments - while ((opt = getopt(argc, argv, "p:s:")) != -1) { - switch (opt) { - case 'p': pk_path = optarg; break; - case 's': sk_path = optarg; break; - default: - fprintf(stderr, "Usage: %s -p public_key_file -s secret_key_file\n", argv[0]); - return 1; - } - } - - // Add check for secret key path - if (!sk_path) { - fprintf(stderr, "Error: Secret key output path (-s) is required\n"); - return 1; - } - - // Base64 encode and save public key - // Now required - error if no path provided - if (!pk_path) { - fprintf(stderr, "Error: Public key output path (-p) is required\n"); - return 1; - } - - // Generate keypair - if (pqcrystals_dilithium5_ref_keypair(pk, sk) != 0) { - fprintf(stderr, "Key generation failed\n"); - return 1; - } - - // Debug output for generated keys - if (DEBUG_BASE64) { - debug_hexa("Public Key", pk, PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES); - debug_hexa("Secret Key", sk, PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES); - } - - // Replace public key writing code with - if (write_to_base64_file(pk_path, - "-----BEGIN DILITHIUM PUBLIC KEY-----", - "-----END DILITHIUM PUBLIC KEY-----", - pk, - PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES) != 0) { - fprintf(stderr, "Error writing public key\n"); - return 1; - } - - // Replace secret key writing code with - if (write_to_base64_file(sk_path, - "-----BEGIN DILITHIUM SECRET KEY-----", - "-----END DILITHIUM SECRET KEY-----", - sk, - PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES) != 0) { - fprintf(stderr, "Error writing secret key\n"); - return 1; - } - - return 0; -} \ No newline at end of file diff --git a/example/keygen.c b/example/keygen.c new file mode 100644 index 0000000..965e323 --- /dev/null +++ b/example/keygen.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include +#include "base64.h" + +#ifndef DILITHIUM_MODE +#error "DILITHIUM_MODE must be 2, 3, or 5" +#endif +#ifdef DILITHIUM_USE_AVX2 + #include +#else + #include +#endif + +#if DILITHIUM_MODE == 2 + #ifdef DILITHIUM_USE_AVX2 + #define CRYPTO_KEYPAIR pqcrystals_dilithium2_avx2_keypair + #else + #define CRYPTO_KEYPAIR pqcrystals_dilithium2_ref_keypair + #endif + #define CRYPTO_SECRETKEYBYTES pqcrystals_dilithium2_SECRETKEYBYTES + #define CRYPTO_PUBLICKEYBYTES pqcrystals_dilithium2_PUBLICKEYBYTES + #define SK_HEADER "-----BEGIN DILITHIUM2 SECRET KEY-----" + #define SK_FOOTER "-----END DILITHIUM2 SECRET KEY-----" + #define PK_HEADER "-----BEGIN DILITHIUM2 PUBLIC KEY-----" + #define PK_FOOTER "-----END DILITHIUM2 PUBLIC KEY-----" +#elif DILITHIUM_MODE == 3 + #ifdef DILITHIUM_USE_AVX2 + #define CRYPTO_KEYPAIR pqcrystals_dilithium3_avx2_keypair + #else + #define CRYPTO_KEYPAIR pqcrystals_dilithium3_ref_keypair + #endif + #define CRYPTO_SECRETKEYBYTES pqcrystals_dilithium3_SECRETKEYBYTES + #define CRYPTO_PUBLICKEYBYTES pqcrystals_dilithium3_PUBLICKEYBYTES + #define SK_HEADER "-----BEGIN DILITHIUM3 SECRET KEY-----" + #define SK_FOOTER "-----END DILITHIUM3 SECRET KEY-----" + #define PK_HEADER "-----BEGIN DILITHIUM3 PUBLIC KEY-----" + #define PK_FOOTER "-----END DILITHIUM3 PUBLIC KEY-----" +#elif DILITHIUM_MODE == 5 + #ifdef DILITHIUM_USE_AVX2 + #define CRYPTO_KEYPAIR pqcrystals_dilithium5_avx2_keypair + #else + #define CRYPTO_KEYPAIR pqcrystals_dilithium5_ref_keypair + #endif + #define CRYPTO_SECRETKEYBYTES pqcrystals_dilithium5_SECRETKEYBYTES + #define CRYPTO_PUBLICKEYBYTES pqcrystals_dilithium5_PUBLICKEYBYTES + #define SK_HEADER "-----BEGIN DILITHIUM5 SECRET KEY-----" + #define SK_FOOTER "-----END DILITHIUM5 SECRET KEY-----" + #define PK_HEADER "-----BEGIN DILITHIUM5 PUBLIC KEY-----" + #define PK_FOOTER "-----END DILITHIUM5 PUBLIC KEY-----" +#endif + +int main(int argc, char *argv[]) { + unsigned char sk[CRYPTO_SECRETKEYBYTES]; + unsigned char pk[CRYPTO_PUBLICKEYBYTES]; + int opt; + char *pk_path = NULL; + char *sk_path = NULL; + + // Parse command line arguments + while ((opt = getopt(argc, argv, "p:s:")) != -1) { + switch (opt) { + case 'p': pk_path = optarg; break; + case 's': sk_path = optarg; break; + default: + fprintf(stderr, "Usage: %s -p public_key_file -s secret_key_file\n", argv[0]); + return 1; + } + } + + // Add check for secret key path + if (!sk_path) { + fprintf(stderr, "Error: Secret key output path (-s) is required\n"); + return 1; + } + + // Base64 encode and save public key + // Now required - error if no path provided + if (!pk_path) { + fprintf(stderr, "Error: Public key output path (-p) is required\n"); + return 1; + } + + // Generate keypair + if (CRYPTO_KEYPAIR(pk, sk) != 0) { + fprintf(stderr, "Key generation failed\n"); + return 1; + } + + // Write public key + if (write_to_base64_file(pk_path, + PK_HEADER, + PK_FOOTER, + pk, + CRYPTO_PUBLICKEYBYTES) != 0) { + fprintf(stderr, "Error writing public key\n"); + return 1; + } + + // Write secret key + if (write_to_base64_file(sk_path, + SK_HEADER, + SK_FOOTER, + sk, + CRYPTO_SECRETKEYBYTES) != 0) { + fprintf(stderr, "Error writing secret key\n"); + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/example/runtest.sh b/example/runtest.sh index 15e401b..9a89c4b 100755 --- a/example/runtest.sh +++ b/example/runtest.sh @@ -1,22 +1,51 @@ -#! /usr/bin/env bash - -echo "๐Ÿ”‘ Generating keys..." -# Generate both secret and public keys at once -./generate_secretkey -p public.key -s secret.key -echo "โœ… Keys generated" - -echo -e "\n๐Ÿ“ Creating test message..." -echo "Hello, World!" > message.txt -echo "โœ… Message created" - -echo -e "\n๐Ÿ–‹๏ธ Signing message..." -./create_signature -s secret.key -p public.key -i message.txt > signature.bin -echo "โœ… Signature created" - -echo -e "\n๐Ÿ” Verifying signature..." -./validate_signature -p public.key -i message.txt -s signature.bin 2> /dev/null -if [ $? -eq 0 ]; then - echo "โœ… Signature is valid!" -else - echo "โŒ Signature verification failed!" -fi +#!/usr/bin/env bash + +# Test each Dilithium version +for VERSION in 2 3 5; do + echo -e "\n๐Ÿ”ฐ Testing Dilithium${VERSION}" + echo "================================" + + echo "๐Ÿ”‘ Generating keys..." + ./dilithium --keygen -v ${VERSION} -p public${VERSION}.key -s secret${VERSION}.key + if [ $? -ne 0 ]; then + echo "โŒ Key generation failed for version ${VERSION}" + exit 1 + fi + echo "โœ… Keys generated" + + echo -e "\n๐Ÿ“ Creating test message..." + echo "Hello, World! Testing Dilithium${VERSION}" > message${VERSION}.txt + echo "โœ… Message created" + + echo -e "\n๐Ÿ–‹๏ธ Signing message..." + ./dilithium --sign -v ${VERSION} -s secret${VERSION}.key -i message${VERSION}.txt -o signature${VERSION}.bin + if [ $? -ne 0 ]; then + echo "โŒ Signing failed for version ${VERSION}" + exit 1 + fi + echo "โœ… Signature created" + + echo -e "\n๐Ÿ” Verifying signature..." + ./dilithium --verify -v ${VERSION} -p public${VERSION}.key -i message${VERSION}.txt -S signature${VERSION}.bin + if [ $? -eq 0 ]; then + echo "โœ… Signature is valid!" + else + echo "โŒ Signature verification failed!" + exit 1 + fi + + echo -e "\n๐Ÿงช Testing negative case (modified message)..." + echo "Modified message" > message${VERSION}_modified.txt + ./dilithium --verify -v ${VERSION} -p public${VERSION}.key -i message${VERSION}_modified.txt -S signature${VERSION}.bin + if [ $? -ne 0 ]; then + echo "โœ… Verification correctly failed for modified message" + else + echo "โŒ Verification unexpectedly succeeded for modified message" + exit 1 + fi + + echo -e "\n๐Ÿงน Cleaning up version ${VERSION} test files..." + rm -f public${VERSION}.key secret${VERSION}.key message${VERSION}.txt message${VERSION}_modified.txt signature${VERSION}.bin +done + +echo -e "\n๐ŸŽ‰ All tests completed successfully!" diff --git a/example/secretkey_to_publickey b/example/secretkey_to_publickey deleted file mode 100755 index 6b849c3f1031166c23676eae38ec92d90043f83c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16904 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 B3+?~_ diff --git a/example/sign.c b/example/sign.c new file mode 100644 index 0000000..e4b2dda --- /dev/null +++ b/example/sign.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include +#include +#include "base64.h" +#include +#include + +#define MAX_LINE_LENGTH 1024 + +#ifndef DILITHIUM_MODE +#error "DILITHIUM_MODE must be 2, 3, or 5" +#endif +#ifdef DILITHIUM_USE_AVX2 + #include +#else + #include +#endif + +#if DILITHIUM_MODE == 2 + #ifdef DILITHIUM_USE_AVX2 + #define CRYPTO_SIGN pqcrystals_dilithium2_avx2_signature + #else + #define CRYPTO_SIGN pqcrystals_dilithium2_ref_signature + #endif + #define SK_HEADER "-----BEGIN DILITHIUM2 SECRET KEY-----" + #define SK_FOOTER "-----END DILITHIUM2 SECRET KEY-----" + #define SIG_HEADER "-----BEGIN DILITHIUM2 SIGNATURE-----" + #define SIG_FOOTER "-----END DILITHIUM2 SIGNATURE-----" + #define PK_HEADER "-----BEGIN DILITHIUM2 PUBLIC KEY-----" + #define PK_FOOTER "-----END DILITHIUM2 PUBLIC KEY-----" +#elif DILITHIUM_MODE == 3 + #ifdef DILITHIUM_USE_AVX2 + #define CRYPTO_SIGN pqcrystals_dilithium3_avx2_signature + #else + #define CRYPTO_SIGN pqcrystals_dilithium3_ref_signature + #endif + #define SK_HEADER "-----BEGIN DILITHIUM3 SECRET KEY-----" + #define SK_FOOTER "-----END DILITHIUM3 SECRET KEY-----" + #define SIG_HEADER "-----BEGIN DILITHIUM3 SIGNATURE-----" + #define SIG_FOOTER "-----END DILITHIUM3 SIGNATURE-----" + #define PK_HEADER "-----BEGIN DILITHIUM3 PUBLIC KEY-----" + #define PK_FOOTER "-----END DILITHIUM3 PUBLIC KEY-----" +#elif DILITHIUM_MODE == 5 + #ifdef DILITHIUM_USE_AVX2 + #define CRYPTO_SIGN pqcrystals_dilithium5_avx2_signature + #else + #define CRYPTO_SIGN pqcrystals_dilithium5_ref_signature + #endif + #define SK_HEADER "-----BEGIN DILITHIUM5 SECRET KEY-----" + #define SK_FOOTER "-----END DILITHIUM5 SECRET KEY-----" + #define SIG_HEADER "-----BEGIN DILITHIUM5 SIGNATURE-----" + #define SIG_FOOTER "-----END DILITHIUM5 SIGNATURE-----" + #define PK_HEADER "-----BEGIN DILITHIUM5 PUBLIC KEY-----" + #define PK_FOOTER "-----END DILITHIUM5 PUBLIC KEY-----" +#endif + +int main(int argc, char *argv[]) { + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + size_t siglen; + FILE *msg_file = NULL; + uint8_t *msg; + size_t msg_len; + int opt; + char *sk_path = NULL, *msg_path = NULL, *sig_path = NULL; + + while ((opt = getopt(argc, argv, "s:i:o:")) != -1) { + switch (opt) { + case 's': sk_path = optarg; break; + case 'i': msg_path = optarg; break; + case 'o': sig_path = optarg; break; + default: + fprintf(stderr, "Usage: %s -s secret_key -i message -o signature\n", argv[0]); + return 1; + } + } + + if (!sk_path || !msg_path || !sig_path) { + fprintf(stderr, "Missing required arguments\n"); + return 1; + } + + // Read and decode base64 secret key + int read_result = read_from_base64_file(sk_path, + SK_HEADER, + SK_FOOTER, + sk, + CRYPTO_SECRETKEYBYTES); + if (read_result != 0) { + fprintf(stderr, "Error reading secret key (code: %d)\n", read_result); + return 1; + } + + // Read message + msg_file = fopen(msg_path, "rb"); + if (!msg_file) { + fprintf(stderr, "Error opening message file\n"); + return 1; + } + fseek(msg_file, 0, SEEK_END); + msg_len = ftell(msg_file); + fseek(msg_file, 0, SEEK_SET); + msg = malloc(msg_len); + if (!msg || fread(msg, 1, msg_len, msg_file) != msg_len) { + fprintf(stderr, "Error reading message\n"); + return 1; + } + fclose(msg_file); + + // Create signature + if (CRYPTO_SIGN(sig, &siglen, msg, msg_len, NULL, 0, sk) != 0) { + fprintf(stderr, "Signature creation failed\n"); + return 1; + } + + // Write signature to stdout using base64 functions + if (write_to_base64_file(sig_path, + SIG_HEADER, + SIG_FOOTER, + sig, siglen) != 0) { + fprintf(stderr, "Error writing signature\n"); + return 1; + } + + free(msg); + return 0; +} \ No newline at end of file diff --git a/example/size.h b/example/size.h deleted file mode 100644 index 1aa81ce..0000000 --- a/example/size.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -#include -uint32_t PQCLEAN_DILITHIUM5_CRYPTO_BYTES = 4627; -uint32_t PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES = 4896; -uint32_t PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES = 2592; \ No newline at end of file diff --git a/example/test_dilithium.c b/example/test_dilithium.c deleted file mode 100644 index e78f1d5..0000000 --- a/example/test_dilithium.c +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include -#include -#include "size.h" - -#define NUM_ITERATIONS 10 -#define MAX_MSG_LEN 100 - -int test_iteration(size_t msg_len) { - // Generate random message - uint8_t msg[MAX_MSG_LEN]; - randombytes(msg, msg_len); - - printf("\nTesting with %zu byte message: ", msg_len); - for(size_t i = 0; i < msg_len && i < 16; i++) { - printf("%02x", msg[i]); - } - if (msg_len > 16) printf("..."); - printf("\n"); - - // Generate keypair - uint8_t pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; - uint8_t sk[PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES]; - - if (pqcrystals_dilithium5_ref_keypair(pk, sk) != 0) { - fprintf(stderr, "โŒ Key generation failed!\n"); - return 1; - } - - // Create signature - uint8_t sig[PQCLEAN_DILITHIUM5_CRYPTO_BYTES]; - size_t siglen; - - if (pqcrystals_dilithium5_ref_signature(sig, &siglen, msg, msg_len, NULL, 0, sk) != 0) { - fprintf(stderr, "โŒ Signature creation failed!\n"); - return 1; - } - - // Verify signature - int verify_result = pqcrystals_dilithium5_ref_verify(sig, siglen, msg, msg_len, NULL, 0, pk); - - if (verify_result != 0) { - fprintf(stderr, "โŒ Signature verification failed! (error code: %d)\n", verify_result); - return 1; - } - - printf("โœ… Success (message: %zu bytes, signature: %zu bytes)\n", msg_len, siglen); - return 0; -} - -int main(void) { - printf("Running %d iterations with varying message sizes...\n", NUM_ITERATIONS); - - size_t message_sizes[] = {0, 1, 13, 32, 64, 100}; - int num_sizes = sizeof(message_sizes) / sizeof(message_sizes[0]); - - int failed = 0; - for (int i = 0; i < NUM_ITERATIONS; i++) { - printf("\nIteration %d/%d:\n", i + 1, NUM_ITERATIONS); - - for (int s = 0; s < num_sizes; s++) { - if (test_iteration(message_sizes[s]) != 0) { - failed++; - } - } - } - - printf("\nTest summary:\n"); - printf("Total iterations: %d\n", NUM_ITERATIONS * num_sizes); - printf("Failed: %d\n", failed); - printf("Succeeded: %d\n", NUM_ITERATIONS * num_sizes - failed); - - return failed ? 1 : 0; -} \ No newline at end of file diff --git a/example/validate_signature.c b/example/validate_signature.c deleted file mode 100644 index 89dfd90..0000000 --- a/example/validate_signature.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include -#include -#include "size.h" -#include -#include -#include -#include "base64.h" - -#define MAX_LINE_LENGTH 1024 - -int main(int argc, char *argv[]) { - unsigned char pk[PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES]; - unsigned char sig[PQCLEAN_DILITHIUM5_CRYPTO_BYTES]; - FILE *pk_file, *sig_file, *msg_file; - unsigned char *msg; - size_t msg_len; - int opt; - char *pk_path = NULL, *sig_path = NULL, *msg_path = NULL; - char line[MAX_LINE_LENGTH]; - int in_key = 0; - BIO *bio, *b64; - - while ((opt = getopt(argc, argv, "p:s:i:")) != -1) { - switch (opt) { - case 'p': pk_path = optarg; break; - case 's': sig_path = optarg; break; - case 'i': msg_path = optarg; break; - default: - fprintf(stderr, "Usage: %s -p publickey -i plaintext -s signature\n", argv[0]); - return 1; - } - } - - if (!pk_path || !sig_path || !msg_path) { - fprintf(stderr, "Missing required arguments\n"); - return 1; - } - - // Read and decode base64 public key - if (read_from_base64_file(pk_path, - "-----BEGIN DILITHIUM PUBLIC KEY-----", - "-----END DILITHIUM PUBLIC KEY-----", - pk, - PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES) != 0) { - fprintf(stderr, "Error reading public key\n"); - return 1; - } - - // Read and decode base64 signature - if (read_from_base64_file(sig_path, - "-----BEGIN DILITHIUM SIGNATURE-----", - "-----END DILITHIUM SIGNATURE-----", - sig, - PQCLEAN_DILITHIUM5_CRYPTO_BYTES) != 0) { - fprintf(stderr, "Error reading signature\n"); - return 1; - } - - // Read message - msg_file = fopen(msg_path, "rb"); - if (!msg_file) { - fprintf(stderr, "Error opening message file\n"); - return 1; - } - fseek(msg_file, 0, SEEK_END); - msg_len = ftell(msg_file); - fseek(msg_file, 0, SEEK_SET); - msg = malloc(msg_len); - if (!msg || fread(msg, 1, msg_len, msg_file) != msg_len) { - fprintf(stderr, "Error reading message\n"); - return 1; - } - fclose(msg_file); - - // Verify signature - int result = pqcrystals_dilithium5_ref_verify(sig, PQCLEAN_DILITHIUM5_CRYPTO_BYTES, - msg, msg_len, NULL, 0, pk); - - if (result != 0) { - fprintf(stderr, "Signature verification failed\n"); - } else { - fprintf(stderr, "Signature verified successfully!\n"); - } - - free(msg); - return result; -} \ No newline at end of file diff --git a/example/verify.c b/example/verify.c new file mode 100644 index 0000000..a050d12 --- /dev/null +++ b/example/verify.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include "base64.h" +#include + +#define MAX_LINE_LENGTH 1024 + +#ifndef DILITHIUM_MODE +#error "DILITHIUM_MODE must be 2, 3, or 5" +#endif +#ifdef DILITHIUM_USE_AVX2 + #include +#else + #include +#endif + + +#if DILITHIUM_MODE == 2 + #ifdef DILITHIUM_USE_AVX2 + #define CRYPTO_VERIFY pqcrystals_dilithium2_avx2_verify + #else + #define CRYPTO_VERIFY pqcrystals_dilithium2_ref_verify + #endif + #define CRYPTO_SECRETKEYBYTES pqcrystals_dilithium2_SECRETKEYBYTES + #define CRYPTO_PUBLICKEYBYTES pqcrystals_dilithium2_PUBLICKEYBYTES + #define CRYPTO_BYTES pqcrystals_dilithium2_BYTES + #define PK_HEADER "-----BEGIN DILITHIUM2 PUBLIC KEY-----" + #define PK_FOOTER "-----END DILITHIUM2 PUBLIC KEY-----" + #define SIG_HEADER "-----BEGIN DILITHIUM2 SIGNATURE-----" + #define SIG_FOOTER "-----END DILITHIUM2 SIGNATURE-----" +#elif DILITHIUM_MODE == 3 + #ifdef DILITHIUM_USE_AVX2 + #define CRYPTO_VERIFY pqcrystals_dilithium3_avx2_verify + #else + #define CRYPTO_VERIFY pqcrystals_dilithium3_ref_verify + #endif + #define CRYPTO_SECRETKEYBYTES pqcrystals_dilithium3_SECRETKEYBYTES + #define CRYPTO_PUBLICKEYBYTES pqcrystals_dilithium3_PUBLICKEYBYTES + #define CRYPTO_BYTES pqcrystals_dilithium3_BYTES + #define PK_HEADER "-----BEGIN DILITHIUM3 PUBLIC KEY-----" + #define PK_FOOTER "-----END DILITHIUM3 PUBLIC KEY-----" + #define SIG_HEADER "-----BEGIN DILITHIUM3 SIGNATURE-----" + #define SIG_FOOTER "-----END DILITHIUM3 SIGNATURE-----" +#elif DILITHIUM_MODE == 5 + #ifdef DILITHIUM_USE_AVX2 + #define CRYPTO_VERIFY pqcrystals_dilithium5_avx2_verify + #else + #define CRYPTO_VERIFY pqcrystals_dilithium5_ref_verify + #endif + #define CRYPTO_SECRETKEYBYTES pqcrystals_dilithium5_SECRETKEYBYTES + #define CRYPTO_PUBLICKEYBYTES pqcrystals_dilithium5_PUBLICKEYBYTES + #define CRYPTO_BYTES pqcrystals_dilithium5_BYTES + #define PK_HEADER "-----BEGIN DILITHIUM5 PUBLIC KEY-----" + #define PK_FOOTER "-----END DILITHIUM5 PUBLIC KEY-----" + #define SIG_HEADER "-----BEGIN DILITHIUM5 SIGNATURE-----" + #define SIG_FOOTER "-----END DILITHIUM5 SIGNATURE-----" +#endif + +int main(int argc, char *argv[]) { + unsigned char pk[CRYPTO_PUBLICKEYBYTES]; + unsigned char sig[CRYPTO_BYTES]; + FILE *msg_file; + unsigned char *msg; + size_t msg_len; + int opt; + char *pk_path = NULL, *sig_path = NULL, *msg_path = NULL; + + while ((opt = getopt(argc, argv, "p:i:S:")) != -1) { + switch (opt) { + case 'p': pk_path = optarg; break; + case 'i': msg_path = optarg; break; + case 'S': sig_path = optarg; break; + default: + fprintf(stderr, "Usage: %s -p publickey -i message -S signature\n", argv[0]); + return 1; + } + } + + if (!pk_path || !sig_path || !msg_path) { + fprintf(stderr, "Missing required arguments\n"); + return 1; + } + + // Read and decode base64 public key + if (read_from_base64_file(pk_path, + PK_HEADER, + PK_FOOTER, + pk, + CRYPTO_PUBLICKEYBYTES) != 0) { + fprintf(stderr, "Error reading public key\n"); + return 1; + } + + // Read and decode base64 signature + if (read_from_base64_file(sig_path, + SIG_HEADER, + SIG_FOOTER, + sig, + CRYPTO_BYTES) != 0) { + fprintf(stderr, "Error reading signature\n"); + return 1; + } + + // Read message + msg_file = fopen(msg_path, "rb"); + if (!msg_file) { + fprintf(stderr, "Error opening message file\n"); + return 1; + } + fseek(msg_file, 0, SEEK_END); + msg_len = ftell(msg_file); + fseek(msg_file, 0, SEEK_SET); + msg = malloc(msg_len); + if (!msg || fread(msg, 1, msg_len, msg_file) != msg_len) { + fprintf(stderr, "Error reading message\n"); + return 1; + } + fclose(msg_file); + + // Verify signature + int result = CRYPTO_VERIFY(sig, CRYPTO_BYTES, + msg, msg_len, NULL, 0, pk); + + if (result != 0) { + fprintf(stderr, "Signature verification failed\n"); + } else { + fprintf(stderr, "Signature verified successfully!\n"); + } + + free(msg); + return result; +} \ No newline at end of file diff --git a/flake.nix b/flake.nix index 52c26b4..24cf43c 100644 --- a/flake.nix +++ b/flake.nix @@ -10,9 +10,16 @@ flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; - dilithium = pkgs.stdenv.mkDerivation { - name = "dilithium"; - src = ./.; + dilithium-lib = pkgs.stdenv.mkDerivation { + name = "dilithium-lib"; + src = pkgs.lib.cleanSourceWith { + src = ./.; + filter = path: type: + let baseName = baseNameOf path; + in !(baseName == "example" || + baseName == "flake.nix" || + baseName == "flake.lock"); + }; nativeBuildInputs = with pkgs; [ clang @@ -56,6 +63,8 @@ # Install AVX2 implementation libraries if built if [ "$(uname -m)" = "x86_64" ]; then + mkdir $out/include/dilithium/avx2 + cp -r $src/avx2/*.h $out/include/dilithium/avx2/ cp -r $buildDir/avx2/libpqcrystals_*_avx2.so $out/lib/ fi ''; @@ -74,66 +83,75 @@ sha256sum -c $src/SHA256SUMS ''; - doCheck = false; + doCheck = true; }; - in - { - packages = { - inherit dilithium; - default = dilithium; - - examples = pkgs.stdenv.mkDerivation { - name = "dilithium-examples"; + dilithium = pkgs.stdenv.mkDerivation { + name = "dilithium"; src = ./.; - propagatedBuildInputs = [ dilithium ]; + propagatedBuildInputs = [ dilithium-lib ]; nativeBuildInputs = with pkgs; [ gcc openssl ]; + checkInputs = with pkgs; [ + bash + ]; buildPhase = '' - export DILITHIUM_INCLUDE_DIR="${dilithium}/include" - export DILITHIUM_LIB_DIR="${dilithium}/lib" - export LD_LIBRARY_PATH="${dilithium}/lib:$LD_LIBRARY_PATH" + export DILITHIUM_INCLUDE_DIR="${dilithium-lib}/include" + export DILITHIUM_LIB_DIR="${dilithium-lib}/lib" + export LD_LIBRARY_PATH="${dilithium-lib}/lib:$LD_LIBRARY_PATH" cd example - make -j$NIX_BUILD_CORES + if [ "$(uname -m)" = "x86_64" ]; then + make -j$NIX_BUILD_CORES USE_AVX2=1 + else + make -j$NIX_BUILD_CORES + fi ''; installPhase = '' mkdir -p $out/bin $out/lib - # Install example binaries - cp generate_secretkey $out/bin/ - cp create_signature $out/bin/ - cp validate_signature $out/bin/ - - # Create wrapper scripts that set LD_LIBRARY_PATH - for bin in generate_secretkey create_signature validate_signature; do - mv $out/bin/$bin $out/bin/$bin.real - cat > $out/bin/$bin <