File: key.ha

package info (click to toggle)
hare 0.26.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,352 kB
  • sloc: asm: 1,374; makefile: 123; sh: 117; lisp: 101
file content (194 lines) | stat: -rw-r--r-- 5,301 bytes parent folder | download | duplicates (2)
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;
	};
};