hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 95992f6d6f9d7a548ace16af84d66bc4571bff41
parent 6603f946fc2fd6158778dca4d97e86b0f467a3fc
Author: Armin Preiml <apreiml@strohwolke.at>
Date:   Fri,  6 May 2022 15:13:21 +0200

implement crypto::x25519

Signed-off-by: Armin Preiml <apreiml@strohwolke.at>

Diffstat:
Acrypto/x25519/+test.ha | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acrypto/x25519/README | 13+++++++++++++
Acrypto/x25519/x25519.ha | 27+++++++++++++++++++++++++++
Mscripts/gen-stdlib | 13+++++++++++++
Mstdlib.mk | 33+++++++++++++++++++++++++++++++++
5 files changed, 154 insertions(+), 0 deletions(-)

diff --git a/crypto/x25519/+test.ha b/crypto/x25519/+test.ha @@ -0,0 +1,68 @@ +// License: MPL-2.0 +// (c) 2022 Armin Preiml <apreiml@strohwolke.at> +use bytes; +use encoding::hex; +use crypto::random; + +@test fn sample() void = { + let seed: [32]u8 = [0xff...]; + let priv: key = [0...]; + priv[31] = 0xbf; + + newkey(&priv, &seed); + + let pub: key = [0...]; + pubkey(&pub, &priv); + + const pexpected: key = [ + 0x84, 0x7c, 0x0d, 0x2c, 0x37, 0x52, 0x34, 0xf3, 0x65, 0xe6, + 0x60, 0x95, 0x51, 0x87, 0xa3, 0x73, 0x5a, 0x0f, 0x76, 0x13, + 0xd1, 0x60, 0x9d, 0x3a, 0x6a, 0x4d, 0x8c, 0x53, 0xae, 0xaa, + 0x5a, 0x22, + ]; + + assert(bytes::equal(pexpected, pub)); + + const otherpub: key = [ + 0x28, 0x18, 0x84, 0xe0, 0x0f, 0xae, 0x8a, 0x33, 0x75, 0x05, + 0xbf, 0x38, 0x15, 0x2a, 0x97, 0xc0, 0x20, 0x4a, 0x8c, 0x1d, + 0x4c, 0xfa, 0x2d, 0x2b, 0x12, 0x99, 0x80, 0xed, 0xe7, 0x32, + 0xaf, 0x0d, + ]; + + const expected: key = [ + 0x07, 0x4a, 0xaf, 0x3c, 0xa3, 0x87, 0xd5, 0xa3, 0x71, 0x25, + 0x9f, 0x50, 0xb3, 0xf0, 0xa1, 0xe9, 0x63, 0x6b, 0x18, 0x1d, + 0x5e, 0x4e, 0x6e, 0xb3, 0x1a, 0xe9, 0xda, 0x01, 0x05, 0x4a, + 0x8c, 0x3b, + ]; + + let shared: key = [0...]; + + derive(&shared, &priv, &otherpub); + assert(bytes::equal(expected, shared)); +}; + +@test fn random() void = { + let seed: [32]u8 = [0...]; + let priv1: key = [0...]; + let priv2: key = [0...]; + let pub1: key = [0...]; + let pub2: key = [0...]; + let shared1: key = [0...]; + let shared2: key = [0...]; + + random::buffer(seed); + newkey(&priv1, &seed); + + random::buffer(seed); + newkey(&priv2, &seed); + + pubkey(&pub1, &priv1); + pubkey(&pub2, &priv2); + + derive(&shared1, &priv1, &pub2); + derive(&shared2, &priv2, &pub1); + + assert(bytes::equal(&shared1, &shared2)); +}; diff --git a/crypto/x25519/README b/crypto/x25519/README @@ -0,0 +1,13 @@ +The crypto::x25519 module provides functions to generate key pairs and to +derive shared keys between them, based on curve25519. + +A key pair is created by generating a private key with [[newkey]] and deriving +the public key with [[pubkey]]. A shared key can be found by using [[derive]]. + +This is a low-level module which implements cryptographic primitives. Direct use +of cryptographic primitives is not recommended for non-experts, as incorrect use +of these primitives can easily lead to the introduction of security +vulnerabilities. Non-experts are advised to use the high-level operations +available in the top-level [[crypto]] module. + +Be advised that Hare's cryptography implementations have not been audited. diff --git a/crypto/x25519/x25519.ha b/crypto/x25519/x25519.ha @@ -0,0 +1,27 @@ +// License: MPL-2.0 +// (c) 2022 Armin Preiml <apreiml@strohwolke.at> +use crypto::curve25519; + +// Type for private, public or shared keys. +export type key = [32]u8; + +// Initializes a new x25519 private key from the provided 32-byte seed, +// which should be generated with [[crypto::random]]. +export fn newkey(priv: *key, seed: *[32]u8) void = { + priv[..] = seed[..]; + curve25519::clamp(priv); +}; + +// Derives the public key from a private key prepared with [[newkey]], +// writing it to the 'pub' parameter. +export fn pubkey(pub: *key, priv: const *key) void = + curve25519::scalarmult_base(pub, priv); + +// Derives a 32-byte shared key from the private key of one key-pair and +// the public key of a second key-pair. +export fn derive(shared: *key, priv: *key, pub: *key) void = { + curve25519::x25519(shared, priv, pub); + + // TODO figure out if checking for low order points is required + // https://github.com/jedisct1/libsodium/blob/cec56d867f741e66f78b9fde37d9081643599a2a/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c#L90 +}; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -471,6 +471,18 @@ crypto_ed25519() { fi } +crypto_x25519() { + if [ $testing -eq 0 ] + then + gen_srcs crypto::x25519 x25519.ha + gen_ssa crypto::x25519 crypto::curve25519 + else + gen_srcs crypto::x25519 x25519.ha +test.ha + gen_ssa crypto::x25519 bytes crypto::curve25519 encoding::hex \ + crypto::random + fi +} + dirs() { gen_srcs dirs \ xdg.ha @@ -1343,6 +1355,7 @@ crypto::sha256 crypto::sha512 crypto::curve25519 crypto::ed25519 +crypto::x25519 datetime linux freebsd dirs encoding::base64 diff --git a/stdlib.mk b/stdlib.mk @@ -270,6 +270,12 @@ stdlib_deps_any += $(stdlib_crypto_ed25519_any) stdlib_crypto_ed25519_linux = $(stdlib_crypto_ed25519_any) stdlib_crypto_ed25519_freebsd = $(stdlib_crypto_ed25519_any) +# gen_lib crypto::x25519 (any) +stdlib_crypto_x25519_any = $(HARECACHE)/crypto/x25519/crypto_x25519-any.o +stdlib_deps_any += $(stdlib_crypto_x25519_any) +stdlib_crypto_x25519_linux = $(stdlib_crypto_x25519_any) +stdlib_crypto_x25519_freebsd = $(stdlib_crypto_x25519_any) + # gen_lib datetime (linux) stdlib_datetime_linux = $(HARECACHE)/datetime/datetime-linux.o stdlib_deps_linux += $(stdlib_datetime_linux) @@ -961,6 +967,16 @@ $(HARECACHE)/crypto/ed25519/crypto_ed25519-any.ssa: $(stdlib_crypto_ed25519_any_ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::ed25519 \ -t$(HARECACHE)/crypto/ed25519/crypto_ed25519.td $(stdlib_crypto_ed25519_any_srcs) +# crypto::x25519 (+any) +stdlib_crypto_x25519_any_srcs = \ + $(STDLIB)/crypto/x25519/x25519.ha + +$(HARECACHE)/crypto/x25519/crypto_x25519-any.ssa: $(stdlib_crypto_x25519_any_srcs) $(stdlib_rt) $(stdlib_crypto_curve25519_$(PLATFORM)) + @printf 'HAREC \t$@\n' + @mkdir -p $(HARECACHE)/crypto/x25519 + @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::x25519 \ + -t$(HARECACHE)/crypto/x25519/crypto_x25519.td $(stdlib_crypto_x25519_any_srcs) + # datetime (+linux) stdlib_datetime_linux_srcs = \ $(STDLIB)/datetime/arithmetic.ha \ @@ -2316,6 +2332,12 @@ testlib_deps_any += $(testlib_crypto_ed25519_any) testlib_crypto_ed25519_linux = $(testlib_crypto_ed25519_any) testlib_crypto_ed25519_freebsd = $(testlib_crypto_ed25519_any) +# gen_lib crypto::x25519 (any) +testlib_crypto_x25519_any = $(TESTCACHE)/crypto/x25519/crypto_x25519-any.o +testlib_deps_any += $(testlib_crypto_x25519_any) +testlib_crypto_x25519_linux = $(testlib_crypto_x25519_any) +testlib_crypto_x25519_freebsd = $(testlib_crypto_x25519_any) + # gen_lib datetime (linux) testlib_datetime_linux = $(TESTCACHE)/datetime/datetime-linux.o testlib_deps_linux += $(testlib_datetime_linux) @@ -3026,6 +3048,17 @@ $(TESTCACHE)/crypto/ed25519/crypto_ed25519-any.ssa: $(testlib_crypto_ed25519_any @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::ed25519 \ -t$(TESTCACHE)/crypto/ed25519/crypto_ed25519.td $(testlib_crypto_ed25519_any_srcs) +# crypto::x25519 (+any) +testlib_crypto_x25519_any_srcs = \ + $(STDLIB)/crypto/x25519/x25519.ha \ + $(STDLIB)/crypto/x25519/+test.ha + +$(TESTCACHE)/crypto/x25519/crypto_x25519-any.ssa: $(testlib_crypto_x25519_any_srcs) $(testlib_rt) $(testlib_bytes_$(PLATFORM)) $(testlib_crypto_curve25519_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) $(testlib_crypto_random_$(PLATFORM)) + @printf 'HAREC \t$@\n' + @mkdir -p $(TESTCACHE)/crypto/x25519 + @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::x25519 \ + -t$(TESTCACHE)/crypto/x25519/crypto_x25519.td $(testlib_crypto_x25519_any_srcs) + # datetime (+linux) testlib_datetime_linux_srcs = \ $(STDLIB)/datetime/arithmetic.ha \