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