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 };