hare

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

key.ha (5301B)


      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 export type pubkey = struct {
      9 	curve: *ec::curve,
     10 	get_q: *fn (pub: *pubkey) []u8,
     11 };
     12 
     13 export type privkey = struct {
     14 	curve: *ec::curve,
     15 	get_x: *fn (priv: *privkey) []u8,
     16 };
     17 
     18 export type p256privkey = struct {
     19 	priv: privkey,
     20 	x: [ec::P256_SCALARSZ]u8,
     21 };
     22 
     23 export type p384privkey = struct {
     24 	priv: privkey,
     25 	x: [ec::P384_SCALARSZ]u8,
     26 };
     27 
     28 export type p521privkey = struct {
     29 	priv: privkey,
     30 	x: [ec::P521_SCALARSZ]u8,
     31 };
     32 
     33 fn p256_get_x(priv: *privkey) []u8 = (priv: *p256privkey).x;
     34 fn p384_get_x(priv: *privkey) []u8 = (priv: *p384privkey).x;
     35 fn p521_get_x(priv: *privkey) []u8 = (priv: *p521privkey).x;
     36 
     37 // Creates an unitialized p256 [[privkey]]. The curve is also known as secp256r1
     38 // or prime256. The key must be initialized using [[newkey]]. The key must be
     39 // finished with [[privkey_finish]] to wipe it from memory.
     40 export fn p256priv() p256privkey = p256privkey {
     41 	priv = privkey {
     42 		curve = ec::p256,
     43 		get_x = &p256_get_x,
     44 	},
     45 	...
     46 };
     47 
     48 // Creates an unitialized p384 [[privkey]]. The curve is also known as
     49 // secp384r1. The key must be initialized using [[newkey]]. The key must be
     50 // finished with [[privkey_finish]] to wipe it from memory.
     51 export fn p384priv() p384privkey = p384privkey {
     52 	priv = privkey {
     53 		curve = ec::p384,
     54 		get_x = &p384_get_x,
     55 	},
     56 	...
     57 };
     58 
     59 // Creates an unitialized p521 [[privkey]]. The curve is also known as
     60 // secp521r1. The key must be initialized using [[newkey]]. The key must be
     61 // finished with [[privkey_finish]] to wipe it from memory.
     62 export fn p521priv() p521privkey = p521privkey {
     63 	priv = privkey {
     64 		curve = ec::p521,
     65 		get_x = &p521_get_x,
     66 	},
     67 	...
     68 };
     69 
     70 
     71 fn p256_get_q(pub: *pubkey) []u8 = (pub: *p256pubkey).q;
     72 fn p384_get_q(pub: *pubkey) []u8 = (pub: *p384pubkey).q;
     73 fn p521_get_q(pub: *pubkey) []u8 = (pub: *p521pubkey).q;
     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 // Returns the buffer to the encoded key. See [[crypto::ec::curve]] on how the
     83 // scalar must be encoded. The key must be valid, otherwise undefined behaviour
     84 // may result. The function [[privkey_validate]] checks if the scalar is valid
     85 // for given curve.
     86 export fn privkey_buf(priv: *privkey) []u8 = priv.get_x(priv);
     87 
     88 // Checks whether 'priv' is a valid private key.
     89 export fn privkey_validate(priv: *privkey) (void | invalidkey) = {
     90 	match (ec::validate_scalar(priv.curve, priv.get_x(priv))) {
     91 	case void => void;
     92 	case ec::invalid =>
     93 		return invalidkey;
     94 	};
     95 };
     96 
     97 // Wipes private key data from memory.
     98 export fn privkey_finish(priv: *privkey) void = {
     99 	bytes::zero(priv.get_x(priv));
    100 };
    101 
    102 export type p256pubkey = struct {
    103 	pub: pubkey,
    104 	q: [ec::P256_POINTSZ]u8,
    105 };
    106 
    107 export type p384pubkey = struct {
    108 	pub: pubkey,
    109 	q: [ec::P384_POINTSZ]u8,
    110 };
    111 
    112 export type p521pubkey = struct {
    113 	pub: pubkey,
    114 	q: [ec::P521_POINTSZ]u8,
    115 };
    116 
    117 // Creates an unitialized p256 [[pubkey]]. The curve is also known as secp256r1
    118 // or prime256.
    119 export fn p256pub() p256pubkey = p256pubkey {
    120 	pub = pubkey {
    121 		curve = ec::p256,
    122 		get_q = &p256_get_q,
    123 	},
    124 	...
    125 };
    126 
    127 export fn p384pub() p384pubkey = p384pubkey {
    128 	pub = pubkey {
    129 		curve = ec::p384,
    130 		get_q = &p384_get_q,
    131 	},
    132 	...
    133 };
    134 
    135 export fn p521pub() p521pubkey = p521pubkey {
    136 	pub = pubkey {
    137 		curve = ec::p521,
    138 		get_q = &p521_get_q,
    139 	},
    140 	...
    141 };
    142 
    143 // Initializes the pubkey 'pub' from the coordinates 'x' and 'y' of a public
    144 // point.
    145 //
    146 // Does not validate if the point is on curve. [[verify]] will fail, if such is
    147 // the case.
    148 export fn pubkey_init(pub: *pubkey, x: []u8, y: []u8) (void | invalidkey) = {
    149 	const csz = pub.curve.pointsz / 2;
    150 	if (len(x) > csz || len(y) > csz) {
    151 		return invalidkey;
    152 	};
    153 
    154 	let q = pub.get_q(pub);
    155 	q[..] = [0x04, 0x00...];
    156 
    157 	const xoff = 1 + (csz - len(x));
    158 	const yoff = 1 + xoff + (csz - len(y));
    159 
    160 	q[xoff..xoff + len(x)] = x[..];
    161 	q[yoff..] = y[..];
    162 };
    163 
    164 // Derives the public key from given 'priv' and stores it into 'pub'.
    165 export fn pubkey_derive(pub: *pubkey, priv: *privkey) void = {
    166 	assert(pub.curve == priv.curve);
    167 	priv.curve.mulgen(pub.get_q(pub), priv.get_x(priv));
    168 };
    169 
    170 // Returns the buffer to the point stored in 'pub' to be able to store or read
    171 // the point in encoded form. See [[crypto::ec::curve]] for how the point is
    172 // and must be encoded.
    173 export fn pubkey_buf(pub: *pubkey) []u8 = pub.get_q(pub);
    174 
    175 // Validates if the pubkey is encoded properly. Does not check if the point is
    176 // on curve. [[verify]] will fail, if the point is not on the curve.
    177 export fn pubkey_validate_format(pub: *pubkey) (void | invalidkey) = {
    178 	match (ec::validate_pointformat(pub.curve, pub.get_q(pub))) {
    179 	case void => void;
    180 	case ec::invalid =>
    181 		return invalidkey;
    182 	};
    183 };
    184 
    185 // Validates the key of 'pub' and checks whether the point is on the curve.
    186 // This operation is expensive and is not strictly necessary, since this is
    187 // done during [[verify]] also.
    188 export fn pubkey_validate(pub: *pubkey) (void | invalidkey) = {
    189 	match (ec::validate_point(pub.curve, pub.get_q(pub))) {
    190 	case void => void;
    191 	case ec::invalid =>
    192 		return invalidkey;
    193 	};
    194 };