hare

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

ecdh.ha (2891B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use bytes;
      5 use crypto::ec;
      6 use crypto::random;
      7 use io;
      8 
      9 
     10 // Size of the shared secret in bytes when using p256 curves.
     11 export def P256_SHAREDSZ = ec::P256_POINTSZ / 2;
     12 
     13 // Size of the shared secret in bytes when using p384 curves.
     14 export def P384_SHAREDSZ = ec::P384_POINTSZ / 2;
     15 
     16 // Size of the shared secret in bytes when using p521 curves.
     17 export def P521_SHAREDSZ = ec::P521_POINTSZ / 2;
     18 
     19 // Key is either not of expected size or is not a valid point on given curve.
     20 export type invalidkey = !void;
     21 
     22 export type privkey = struct {
     23 	curve: *ec::curve,
     24 	get_x: *fn (priv: *privkey) []u8,
     25 };
     26 
     27 fn p256_get_x(priv: *privkey) []u8 = (priv: *p256key).x;
     28 fn p384_get_x(priv: *privkey) []u8 = (priv: *p384key).x;
     29 fn p521_get_x(priv: *privkey) []u8 = (priv: *p521key).x;
     30 
     31 export type p256key = struct {
     32 	priv: privkey,
     33 	x: [ec::P256_SCALARSZ]u8,
     34 };
     35 
     36 export type p384key = struct {
     37 	priv: privkey,
     38 	x: [ec::P384_SCALARSZ]u8,
     39 };
     40 
     41 export type p521key = struct {
     42 	priv: privkey,
     43 	x: [ec::P521_SCALARSZ]u8,
     44 };
     45 
     46 // Creates an unitialized p256 key. The curve is also known as secp256r1 or
     47 // prime256. The key must be initialized using [[newkey]].
     48 export fn p256() p256key = p256key {
     49 	priv = privkey {
     50 		curve = ec::p256,
     51 		get_x = &p256_get_x,
     52 	},
     53 	...
     54 };
     55 
     56 // Creates an unitialized p384 key. The curve is also known as secp384r1. The
     57 // key must be initialized using [[newkey]].
     58 export fn p384() p384key = p384key {
     59 	priv = privkey {
     60 		curve = ec::p384,
     61 		get_x = &p384_get_x,
     62 	},
     63 	...
     64 };
     65 
     66 // Creates an unitialized p521 key. The curve is also known as secp521r1. The
     67 // key must be initialized using [[newkey]].
     68 export fn p521() p521key = p521key {
     69 	priv = privkey {
     70 		curve = ec::p521,
     71 		get_x = &p521_get_x,
     72 	},
     73 	...
     74 };
     75 
     76 // Generates a key seeding from the 'rand' stream and stores it in 'priv'.
     77 // 'rand' must be a cryptographic random generator like
     78 // [[crypto::random::stream]].
     79 export fn newkey(priv: *privkey, rand: io::handle) (void | io::error) =
     80 	ec::keygen(priv.curve, priv.get_x(priv), rand)?;
     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 };