commit 6e1abcffdecc6029cd9b55c4868ca6bead7017fd
parent 32031d22bc7f035cded00343c7ff5d4b4fd7b242
Author: Robin Bron <finwo@pm.me>
Date: Wed, 15 Sep 2021 18:19:36 +0200
Basic key generation
Diffstat:
5 files changed, 356 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,3 @@
+*.o
+lib/
+/supercop
diff --git a/Makefile b/Makefile
@@ -0,0 +1,48 @@
+# Ourselves
+CFLAGS?=
+CFLAGS+=-O2 -mtune=native -march=native -pipe -Wall
+INCLUDES?=
+INCLUDES+=-Isrc
+SRC:=$(wildcard src/*.c)
+
+# lib/argparse
+INCLUDES+=-Ilib/argparse
+SRC+=lib/argparse/argparse.c
+
+# lib/ed25519
+INCLUDES+=-Ilib/ed25519/src
+# SRC+=lib/ed25519/src/add_scalar.c
+SRC+=lib/ed25519/src/fe.c
+SRC+=lib/ed25519/src/ge.c
+SRC+=lib/ed25519/src/key_exchange.c
+SRC+=lib/ed25519/src/keypair.c
+SRC+=lib/ed25519/src/sc.c
+SRC+=lib/ed25519/src/seed.c
+SRC+=lib/ed25519/src/sha512.c
+SRC+=lib/ed25519/src/sign.c
+SRC+=lib/ed25519/src/verify.c
+
+# Map SRC into OBJ
+OBJ:=$(patsubst %.c,%.o,$(SRC))
+
+.PHONY: default
+default: supercop
+
+supercop: lib/argparse lib/ed25519 $(OBJ)
+ $(CC) $(CFLAGS) $(INCLUDES) -o $@ $(OBJ)
+
+%.o: %.c
+ $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+lib/argparse:
+ mkdir -p lib/argparse
+ curl -sL https://github.com/cofyc/argparse/archive/refs/heads/master.tar.gz | tar xzv -C lib/argparse --strip-components=1
+
+lib/ed25519:
+ mkdir -p lib/ed25519
+ curl -sL https://github.com/orlp/ed25519/archive/refs/heads/master.tar.gz | tar xzv -C lib/ed25519 --strip-components=1
+ bash -c 'cd lib/ed25519 && patch -p1 < ../../patch/ed25519/00-single-file-compile.patch'
+
+.PHONY: clean
+clean:
+ rm -rf $(OBJ)
diff --git a/encoding.md b/encoding.md
@@ -0,0 +1,18 @@
+# Key encodings
+
+Keys can (or will) be encoded in multiple formats. This file shows a list of
+encodings supported by this program.
+
+The first byte of a key-file must ALWAYS start with the version identifier
+(byte sequence prefix), allowing a different prefix to identify a different type
+of key encoding.
+
+## 0x00
+
+Plain, binary, ed25519.
+
+Not text-safe. Starts with a 0x00 byte, followed by 32 bytes of the raw public
+key, then followed by 64 bytes of the raw private key.
+
+Intended as the first format supported and to be deprecated later. Meant to be
+simple to code, not to be safe or flexible.
diff --git a/patch/ed25519/00-single-file-compile.patch b/patch/ed25519/00-single-file-compile.patch
@@ -0,0 +1,156 @@
+diff --git a/src/sc.c b/src/sc.c
+index ca5bad2..3d2ab56 100644
+--- a/src/sc.c
++++ b/src/sc.c
+@@ -1,7 +1,7 @@
+ #include "fixedint.h"
+ #include "sc.h"
+
+-static uint64_t load_3(const unsigned char *in) {
++static uint64_t sc_load_3(const unsigned char *in) {
+ uint64_t result;
+
+ result = (uint64_t) in[0];
+@@ -11,7 +11,7 @@ static uint64_t load_3(const unsigned char *in) {
+ return result;
+ }
+
+-static uint64_t load_4(const unsigned char *in) {
++static uint64_t sc_load_4(const unsigned char *in) {
+ uint64_t result;
+
+ result = (uint64_t) in[0];
+@@ -33,30 +33,30 @@ Output:
+ */
+
+ void sc_reduce(unsigned char *s) {
+- int64_t s0 = 2097151 & load_3(s);
+- int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
+- int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
+- int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
+- int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
+- int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
+- int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
+- int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
+- int64_t s8 = 2097151 & load_3(s + 21);
+- int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
+- int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
+- int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
+- int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
+- int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
+- int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
+- int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
+- int64_t s16 = 2097151 & load_3(s + 42);
+- int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
+- int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
+- int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
+- int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
+- int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
+- int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
+- int64_t s23 = (load_4(s + 60) >> 3);
++ int64_t s0 = 2097151 & sc_load_3(s);
++ int64_t s1 = 2097151 & (sc_load_4(s + 2) >> 5);
++ int64_t s2 = 2097151 & (sc_load_3(s + 5) >> 2);
++ int64_t s3 = 2097151 & (sc_load_4(s + 7) >> 7);
++ int64_t s4 = 2097151 & (sc_load_4(s + 10) >> 4);
++ int64_t s5 = 2097151 & (sc_load_3(s + 13) >> 1);
++ int64_t s6 = 2097151 & (sc_load_4(s + 15) >> 6);
++ int64_t s7 = 2097151 & (sc_load_3(s + 18) >> 3);
++ int64_t s8 = 2097151 & sc_load_3(s + 21);
++ int64_t s9 = 2097151 & (sc_load_4(s + 23) >> 5);
++ int64_t s10 = 2097151 & (sc_load_3(s + 26) >> 2);
++ int64_t s11 = 2097151 & (sc_load_4(s + 28) >> 7);
++ int64_t s12 = 2097151 & (sc_load_4(s + 31) >> 4);
++ int64_t s13 = 2097151 & (sc_load_3(s + 34) >> 1);
++ int64_t s14 = 2097151 & (sc_load_4(s + 36) >> 6);
++ int64_t s15 = 2097151 & (sc_load_3(s + 39) >> 3);
++ int64_t s16 = 2097151 & sc_load_3(s + 42);
++ int64_t s17 = 2097151 & (sc_load_4(s + 44) >> 5);
++ int64_t s18 = 2097151 & (sc_load_3(s + 47) >> 2);
++ int64_t s19 = 2097151 & (sc_load_4(s + 49) >> 7);
++ int64_t s20 = 2097151 & (sc_load_4(s + 52) >> 4);
++ int64_t s21 = 2097151 & (sc_load_3(s + 55) >> 1);
++ int64_t s22 = 2097151 & (sc_load_4(s + 57) >> 6);
++ int64_t s23 = (sc_load_4(s + 60) >> 3);
+ int64_t carry0;
+ int64_t carry1;
+ int64_t carry2;
+@@ -360,42 +360,42 @@ Output:
+ */
+
+ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
+- int64_t a0 = 2097151 & load_3(a);
+- int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+- int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+- int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+- int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+- int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+- int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+- int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+- int64_t a8 = 2097151 & load_3(a + 21);
+- int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+- int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+- int64_t a11 = (load_4(a + 28) >> 7);
+- int64_t b0 = 2097151 & load_3(b);
+- int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+- int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+- int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+- int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+- int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+- int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+- int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+- int64_t b8 = 2097151 & load_3(b + 21);
+- int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+- int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+- int64_t b11 = (load_4(b + 28) >> 7);
+- int64_t c0 = 2097151 & load_3(c);
+- int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
+- int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
+- int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
+- int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
+- int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
+- int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
+- int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
+- int64_t c8 = 2097151 & load_3(c + 21);
+- int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
+- int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
+- int64_t c11 = (load_4(c + 28) >> 7);
++ int64_t a0 = 2097151 & sc_load_3(a);
++ int64_t a1 = 2097151 & (sc_load_4(a + 2) >> 5);
++ int64_t a2 = 2097151 & (sc_load_3(a + 5) >> 2);
++ int64_t a3 = 2097151 & (sc_load_4(a + 7) >> 7);
++ int64_t a4 = 2097151 & (sc_load_4(a + 10) >> 4);
++ int64_t a5 = 2097151 & (sc_load_3(a + 13) >> 1);
++ int64_t a6 = 2097151 & (sc_load_4(a + 15) >> 6);
++ int64_t a7 = 2097151 & (sc_load_3(a + 18) >> 3);
++ int64_t a8 = 2097151 & sc_load_3(a + 21);
++ int64_t a9 = 2097151 & (sc_load_4(a + 23) >> 5);
++ int64_t a10 = 2097151 & (sc_load_3(a + 26) >> 2);
++ int64_t a11 = (sc_load_4(a + 28) >> 7);
++ int64_t b0 = 2097151 & sc_load_3(b);
++ int64_t b1 = 2097151 & (sc_load_4(b + 2) >> 5);
++ int64_t b2 = 2097151 & (sc_load_3(b + 5) >> 2);
++ int64_t b3 = 2097151 & (sc_load_4(b + 7) >> 7);
++ int64_t b4 = 2097151 & (sc_load_4(b + 10) >> 4);
++ int64_t b5 = 2097151 & (sc_load_3(b + 13) >> 1);
++ int64_t b6 = 2097151 & (sc_load_4(b + 15) >> 6);
++ int64_t b7 = 2097151 & (sc_load_3(b + 18) >> 3);
++ int64_t b8 = 2097151 & sc_load_3(b + 21);
++ int64_t b9 = 2097151 & (sc_load_4(b + 23) >> 5);
++ int64_t b10 = 2097151 & (sc_load_3(b + 26) >> 2);
++ int64_t b11 = (sc_load_4(b + 28) >> 7);
++ int64_t c0 = 2097151 & sc_load_3(c);
++ int64_t c1 = 2097151 & (sc_load_4(c + 2) >> 5);
++ int64_t c2 = 2097151 & (sc_load_3(c + 5) >> 2);
++ int64_t c3 = 2097151 & (sc_load_4(c + 7) >> 7);
++ int64_t c4 = 2097151 & (sc_load_4(c + 10) >> 4);
++ int64_t c5 = 2097151 & (sc_load_3(c + 13) >> 1);
++ int64_t c6 = 2097151 & (sc_load_4(c + 15) >> 6);
++ int64_t c7 = 2097151 & (sc_load_3(c + 18) >> 3);
++ int64_t c8 = 2097151 & sc_load_3(c + 21);
++ int64_t c9 = 2097151 & (sc_load_4(c + 23) >> 5);
++ int64_t c10 = 2097151 & (sc_load_3(c + 26) >> 2);
++ int64_t c11 = (sc_load_4(c + 28) >> 7);
+ int64_t s0;
+ int64_t s1;
+ int64_t s2;
diff --git a/src/main.c b/src/main.c
@@ -0,0 +1,131 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define COMMAND_GENERATE 1
+#define COMMAND_PUBKEY 2
+#define COMMAND_SIGN 4
+#define COMMAND_VERIFY 8
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "argparse.h"
+#include "ed25519.h"
+
+static const char *const usage[] = {
+ "supercop <command> [options]",
+ NULL,
+};
+
+int cmd_generate(FILE *fd) {
+ unsigned char version = 0;
+ unsigned char seed[32];
+ unsigned char public_key[32];
+ unsigned char private_key[64];
+
+ if (ed25519_create_seed(seed)) {
+ fprintf(stderr, "Error while generating seed\n");
+ return 1;
+ }
+
+ ed25519_create_keypair(public_key, private_key, seed);
+
+ // Hardcoded to format 0x00
+ fwrite(&version, 1, 1, fd);
+ fwrite(public_key, 1, 32, fd);
+ fwrite(private_key, 1, 64, fd);
+
+ return 0;
+}
+
+int cmd_pubkey() {
+ return 0;
+}
+
+int cmd_sign() {
+ return 0;
+}
+int cmd_verify() {
+ return 0;
+}
+
+int main(int argc, const char **argv) {
+ const char *identityFile = NULL;
+ const char *verifySignature = NULL;
+ const char *message = NULL;
+ const char *messageFile = NULL;
+ int command = 0;
+ int result = 0;
+
+ FILE *fidentity = NULL;
+ FILE *fmessage = NULL;
+ FILE *fout = NULL;
+
+ // Setup help & argument parsing
+ struct argparse_option options[] = {
+ OPT_GROUP("Operations"),
+ OPT_BIT(0, "pubkey" , &command, "Generate new key" , NULL, COMMAND_GENERATE),
+ OPT_BIT(0, "generate", &command, "Generate new key" , NULL, COMMAND_GENERATE),
+ OPT_BIT(0, "sign" , &command, "Sign a message" , NULL, COMMAND_SIGN ),
+ OPT_BIT(0, "verify" , &command, "Verify a message signature", NULL, COMMAND_VERIFY ),
+ OPT_GROUP("Basic options"),
+ OPT_HELP(),
+ OPT_STRING('i', "identity-file", &identityFile , "Select identity file to use for the operation"),
+ OPT_STRING('m', "message" , &message , "Message to sign or verify (defaults to stdin)"),
+ OPT_STRING('M', "message-file" , &messageFile , "Message file to sign or verify (defaults to stdin)"),
+ OPT_STRING('s', "signature" , &verifySignature, "Signature to verify"),
+ OPT_END(),
+ };
+
+ // Setup basic information
+ struct argparse argparse;
+ argparse_init(&argparse, options, usage, 0);
+ argparse_describe(&argparse, "\nMinimalistic program to generate ed25519 keys and verify/sign messages", "\n (c) 2021 finwo");
+
+ // Actually parse the arguments
+ argc = argparse_parse(&argparse, argc, argv);
+
+ // Our paths separate here
+ switch(command) {
+ case COMMAND_GENERATE:
+
+ // Build output fd
+ fout = stdout;
+ if (identityFile) {
+ fout = fopen(identityFile, "w+");
+ if (fout < 1) {
+ fprintf(stderr, "Could not open output file");
+ return 1;
+ }
+ }
+
+ // Actually generate the key file
+ result = cmd_generate(fout);
+
+ // Close output fd if file
+ if (identityFile) {
+ fclose(fout);
+ }
+
+ // Done
+ return result;
+
+ case COMMAND_PUBKEY:
+ return cmd_pubkey();
+ case COMMAND_VERIFY:
+ return cmd_verify();
+ case COMMAND_SIGN:
+ return cmd_sign();
+ default:
+ argparse_usage(&argparse);
+ return 1;
+ }
+
+ return 42;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif