hare

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

ecdh.ha (2876B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use bytes;
      5 use crypto::ec;
      6 use io;
      7 
      8 
      9 // Size of the shared secret in bytes when using p256 curves.
     10 export def P256_SHAREDSZ = ec::P256_POINTSZ / 2;
     11 
     12 // Size of the shared secret in bytes when using p384 curves.
     13 export def P384_SHAREDSZ = ec::P384_POINTSZ / 2;
     14 
     15 // Size of the shared secret in bytes when using p521 curves.
     16 export def P521_SHAREDSZ = ec::P521_POINTSZ / 2;
     17 
     18 // Key is either not of expected size or is not a valid point on given curve.
     19 export type invalidkey = !void;
     20 
     21 export type privkey = struct {
     22 	curve: *ec::curve,
     23 	get_x: *fn (priv: *privkey) []u8,
     24 };
     25 
     26 fn p256_get_x(priv: *privkey) []u8 = (priv: *p256key).x;
     27 fn p384_get_x(priv: *privkey) []u8 = (priv: *p384key).x;
     28 fn p521_get_x(priv: *privkey) []u8 = (priv: *p521key).x;
     29 
     30 export type p256key = struct {
     31 	priv: privkey,
     32 	x: [ec::P256_SCALARSZ]u8,
     33 };
     34 
     35 export type p384key = struct {
     36 	priv: privkey,
     37 	x: [ec::P384_SCALARSZ]u8,
     38 };
     39 
     40 export type p521key = struct {
     41 	priv: privkey,
     42 	x: [ec::P521_SCALARSZ]u8,
     43 };
     44 
     45 // Creates an unitialized p256 key. The curve is also known as secp256r1 or
     46 // prime256. The key must be initialized using [[newkey]].
     47 export fn p256() p256key = p256key {
     48 	priv = privkey {
     49 		curve = ec::p256,
     50 		get_x = &p256_get_x,
     51 	},
     52 	...
     53 };
     54 
     55 // Creates an unitialized p384 key. The curve is also known as secp384r1. The
     56 // key must be initialized using [[newkey]].
     57 export fn p384() p384key = p384key {
     58 	priv = privkey {
     59 		curve = ec::p384,
     60 		get_x = &p384_get_x,
     61 	},
     62 	...
     63 };
     64 
     65 // Creates an unitialized p521 key. The curve is also known as secp521r1. The
     66 // key must be initialized using [[newkey]].
     67 export fn p521() p521key = p521key {
     68 	priv = privkey {
     69 		curve = ec::p521,
     70 		get_x = &p521_get_x,
     71 	},
     72 	...
     73 };
     74 
     75 // Generates a key seeding from the 'rand' stream and stores it in 'priv'.
     76 // 'rand' must be a cryptographic random generator like
     77 // [[crypto::random::stream]].
     78 export fn newkey(priv: *privkey, rand: io::handle) (void | io::error) = {
     79 	ec::keygen(priv.curve, priv.get_x(priv), rand)?;
     80 };
     81 
     82 // Derives the public key from given 'priv' and stores it into 'pub'. Returns
     83 // the number of key bytes written to 'pub'.
     84 export fn pubkey(pub: []u8, priv: *privkey) size =
     85 	priv.curve.mulgen(pub, priv.get_x(priv));
     86 
     87 // Derives a shared secret with the private key 'priv' and the peer's public
     88 // key 'pub' and stores it in 'shared'.
     89 export fn derive(
     90 	shared: []u8,
     91 	priv: *privkey,
     92 	pub: []u8
     93 ) (size | invalidkey)  = {
     94 	match (ec::validate_pointformat(priv.curve, pub)) {
     95 	case ec::invalid =>
     96 		return invalidkey;
     97 	case void => void;
     98 	};
     99 
    100 	let buf: [ec::MAX_POINTSZ]u8 = [0...];
    101 	let buf = buf[..len(pub)];
    102 	buf[..] = pub[..];
    103 
    104 	if (priv.curve.mul(buf, priv.get_x(priv)) == 0) {
    105 		return invalidkey;
    106 	};
    107 
    108 	const csz = priv.curve.pointsz / 2;
    109 	shared[..] = buf[1..csz + 1];
    110 	bytes::zero(buf);
    111 	return csz;
    112 };