authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2021-04-20 19:57:27+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-04-20 19:57:27+02:00
log10f2d6278946485f057f65bbb3c094a6fcde1adf
treed7e4f5182e5fd226a705fb3bfbab9d35faa1e1ef
parent1e06a74348d11e4eef456a067dc5065c1e8b1ee9
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std/crypto: use finer-grained error sets in function signatures (#8558)

std/crypto: use finer-grained error sets in function signatures Returning the `crypto.Error` error set for all crypto operations was very convenient to ensure that errors were used consistently, and to avoid having multiple error names for the same thing. The flipside is that callers were forced to always handle all possible errors, even those that could never be returned by a function. This PR makes all functions return union sets of the actual errors they can return. The error sets themselves are all limited to a single error. Larger sets are useful for platform-specific APIs, but we don't have any of these in `std/crypto`, and I couldn't find any meaningful way to build larger sets.

19 files changed, 148 insertions(+), 114 deletions(-)

lib/std/crypto.zig+1-1
......@@ -154,7 +154,7 @@ pub const random = &@import("crypto/tlcsprng.zig").interface;
154154
155155const std = @import("std.zig");
156156
157pub const Error = @import("crypto/error.zig").Error;
157pub const errors = @import("crypto/errors.zig");
158158
159159test "crypto" {
160160 const please_windows_dont_oom = std.Target.current.os.tag == .windows;
lib/std/crypto/25519/curve25519.zig+12-8
......@@ -4,7 +4,11 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66const std = @import("std");
7const Error = std.crypto.Error;
7const crypto = std.crypto;
8
9const IdentityElementError = crypto.errors.IdentityElementError;
10const NonCanonicalError = crypto.errors.NonCanonicalError;
11const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
812
913/// Group operations over Curve25519.
1014pub const Curve25519 = struct {
......@@ -29,12 +33,12 @@ pub const Curve25519 = struct {
2933 pub const basePoint = Curve25519{ .x = Fe.curve25519BasePoint };
3034
3135 /// Check that the encoding of a Curve25519 point is canonical.
32 pub fn rejectNonCanonical(s: [32]u8) Error!void {
36 pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!void {
3337 return Fe.rejectNonCanonical(s, false);
3438 }
3539
3640 /// Reject the neutral element.
37 pub fn rejectIdentity(p: Curve25519) Error!void {
41 pub fn rejectIdentity(p: Curve25519) IdentityElementError!void {
3842 if (p.x.isZero()) {
3943 return error.IdentityElement;
4044 }
......@@ -45,7 +49,7 @@ pub const Curve25519 = struct {
4549 return p.dbl().dbl().dbl();
4650 }
4751
48 fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) Error!Curve25519 {
52 fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) IdentityElementError!Curve25519 {
4953 var x1 = p.x;
5054 var x2 = Fe.one;
5155 var z2 = Fe.zero;
......@@ -86,7 +90,7 @@ pub const Curve25519 = struct {
8690 /// way to use Curve25519 for a DH operation.
8791 /// Return error.IdentityElement if the resulting point is
8892 /// the identity element.
89 pub fn clampedMul(p: Curve25519, s: [32]u8) Error!Curve25519 {
93 pub fn clampedMul(p: Curve25519, s: [32]u8) IdentityElementError!Curve25519 {
9094 var t: [32]u8 = s;
9195 scalar.clamp(&t);
9296 return try ladder(p, t, 255);
......@@ -96,16 +100,16 @@ pub const Curve25519 = struct {
96100 /// Return error.IdentityElement if the resulting point is
97101 /// the identity element or error.WeakPublicKey if the public
98102 /// key is a low-order point.
99 pub fn mul(p: Curve25519, s: [32]u8) Error!Curve25519 {
103 pub fn mul(p: Curve25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Curve25519 {
100104 const cofactor = [_]u8{8} ++ [_]u8{0} ** 31;
101105 _ = ladder(p, cofactor, 4) catch |_| return error.WeakPublicKey;
102106 return try ladder(p, s, 256);
103107 }
104108
105109 /// Compute the Curve25519 equivalent to an Edwards25519 point.
106 pub fn fromEdwards25519(p: std.crypto.ecc.Edwards25519) Error!Curve25519 {
110 pub fn fromEdwards25519(p: crypto.ecc.Edwards25519) IdentityElementError!Curve25519 {
107111 try p.clearCofactor().rejectIdentity();
108 const one = std.crypto.ecc.Edwards25519.Fe.one;
112 const one = crypto.ecc.Edwards25519.Fe.one;
109113 const x = one.add(p.y).mul(one.sub(p.y).invert()); // xMont=(1+yEd)/(1-yEd)
110114 return Curve25519{ .x = x };
111115 }
lib/std/crypto/25519/ed25519.zig+16-9
......@@ -8,8 +8,15 @@ const crypto = std.crypto;
88const debug = std.debug;
99const fmt = std.fmt;
1010const mem = std.mem;
11
1112const Sha512 = crypto.hash.sha2.Sha512;
12const Error = crypto.Error;
13
14const EncodingError = crypto.errors.EncodingError;
15const IdentityElementError = crypto.errors.IdentityElementError;
16const NonCanonicalError = crypto.errors.NonCanonicalError;
17const SignatureVerificationError = crypto.errors.SignatureVerificationError;
18const KeyMismatchError = crypto.errors.KeyMismatchError;
19const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
1320
1421/// Ed25519 (EdDSA) signatures.
1522pub const Ed25519 = struct {
......@@ -41,7 +48,7 @@ pub const Ed25519 = struct {
4148 ///
4249 /// For this reason, an EdDSA secret key is commonly called a seed,
4350 /// from which the actual secret is derived.
44 pub fn create(seed: ?[seed_length]u8) Error!KeyPair {
51 pub fn create(seed: ?[seed_length]u8) IdentityElementError!KeyPair {
4552 const ss = seed orelse ss: {
4653 var random_seed: [seed_length]u8 = undefined;
4754 crypto.random.bytes(&random_seed);
......@@ -51,7 +58,7 @@ pub const Ed25519 = struct {
5158 var h = Sha512.init(.{});
5259 h.update(&ss);
5360 h.final(&az);
54 const p = try Curve.basePoint.clampedMul(az[0..32].*);
61 const p = Curve.basePoint.clampedMul(az[0..32].*) catch return error.IdentityElement;
5562 var sk: [secret_length]u8 = undefined;
5663 mem.copy(u8, &sk, &ss);
5764 const pk = p.toBytes();
......@@ -72,7 +79,7 @@ pub const Ed25519 = struct {
7279 /// Sign a message using a key pair, and optional random noise.
7380 /// Having noise creates non-standard, non-deterministic signatures,
7481 /// but has been proven to increase resilience against fault attacks.
75 pub fn sign(msg: []const u8, key_pair: KeyPair, noise: ?[noise_length]u8) Error![signature_length]u8 {
82 pub fn sign(msg: []const u8, key_pair: KeyPair, noise: ?[noise_length]u8) (IdentityElementError || WeakPublicKeyError || KeyMismatchError)![signature_length]u8 {
7683 const seed = key_pair.secret_key[0..seed_length];
7784 const public_key = key_pair.secret_key[seed_length..];
7885 if (!mem.eql(u8, public_key, &key_pair.public_key)) {
......@@ -113,7 +120,7 @@ pub const Ed25519 = struct {
113120
114121 /// Verify an Ed25519 signature given a message and a public key.
115122 /// Returns error.SignatureVerificationFailed is the signature verification failed.
116 pub fn verify(sig: [signature_length]u8, msg: []const u8, public_key: [public_length]u8) Error!void {
123 pub fn verify(sig: [signature_length]u8, msg: []const u8, public_key: [public_length]u8) (SignatureVerificationError || WeakPublicKeyError || EncodingError || NonCanonicalError || IdentityElementError)!void {
117124 const r = sig[0..32];
118125 const s = sig[32..64];
119126 try Curve.scalar.rejectNonCanonical(s.*);
......@@ -146,7 +153,7 @@ pub const Ed25519 = struct {
146153 };
147154
148155 /// Verify several signatures in a single operation, much faster than verifying signatures one-by-one
149 pub fn verifyBatch(comptime count: usize, signature_batch: [count]BatchElement) Error!void {
156 pub fn verifyBatch(comptime count: usize, signature_batch: [count]BatchElement) (SignatureVerificationError || IdentityElementError || WeakPublicKeyError || EncodingError || NonCanonicalError)!void {
150157 var r_batch: [count][32]u8 = undefined;
151158 var s_batch: [count][32]u8 = undefined;
152159 var a_batch: [count]Curve = undefined;
......@@ -180,7 +187,7 @@ pub const Ed25519 = struct {
180187
181188 var z_batch: [count]Curve.scalar.CompressedScalar = undefined;
182189 for (z_batch) |*z| {
183 std.crypto.random.bytes(z[0..16]);
190 crypto.random.bytes(z[0..16]);
184191 mem.set(u8, z[16..], 0);
185192 }
186193
......@@ -233,8 +240,8 @@ test "ed25519 batch verification" {
233240 const key_pair = try Ed25519.KeyPair.create(null);
234241 var msg1: [32]u8 = undefined;
235242 var msg2: [32]u8 = undefined;
236 std.crypto.random.bytes(&msg1);
237 std.crypto.random.bytes(&msg2);
243 crypto.random.bytes(&msg1);
244 crypto.random.bytes(&msg2);
238245 const sig1 = try Ed25519.sign(&msg1, key_pair, null);
239246 const sig2 = try Ed25519.sign(&msg2, key_pair, null);
240247 var signature_batch = [_]Ed25519.BatchElement{
lib/std/crypto/25519/edwards25519.zig+23-17
......@@ -4,10 +4,16 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66const std = @import("std");
7const crypto = std.crypto;
78const debug = std.debug;
89const fmt = std.fmt;
910const mem = std.mem;
10const Error = std.crypto.Error;
11
12const EncodingError = crypto.errors.EncodingError;
13const IdentityElementError = crypto.errors.IdentityElementError;
14const NonCanonicalError = crypto.errors.NonCanonicalError;
15const NotSquareError = crypto.errors.NotSquareError;
16const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
1117
1218/// Group operations over Edwards25519.
1319pub const Edwards25519 = struct {
......@@ -26,7 +32,7 @@ pub const Edwards25519 = struct {
2632 is_base: bool = false,
2733
2834 /// Decode an Edwards25519 point from its compressed (Y+sign) coordinates.
29 pub fn fromBytes(s: [encoded_length]u8) Error!Edwards25519 {
35 pub fn fromBytes(s: [encoded_length]u8) EncodingError!Edwards25519 {
3036 const z = Fe.one;
3137 const y = Fe.fromBytes(s);
3238 var u = y.sq();
......@@ -56,7 +62,7 @@ pub const Edwards25519 = struct {
5662 }
5763
5864 /// Check that the encoding of a point is canonical.
59 pub fn rejectNonCanonical(s: [32]u8) Error!void {
65 pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!void {
6066 return Fe.rejectNonCanonical(s, true);
6167 }
6268
......@@ -81,7 +87,7 @@ pub const Edwards25519 = struct {
8187 const identityElement = Edwards25519{ .x = Fe.zero, .y = Fe.one, .z = Fe.one, .t = Fe.zero };
8288
8389 /// Reject the neutral element.
84 pub fn rejectIdentity(p: Edwards25519) Error!void {
90 pub fn rejectIdentity(p: Edwards25519) IdentityElementError!void {
8591 if (p.x.isZero()) {
8692 return error.IdentityElement;
8793 }
......@@ -177,7 +183,7 @@ pub const Edwards25519 = struct {
177183 // Based on real-world benchmarks, we only use this for multi-scalar multiplication.
178184 // NAF could be useful to half the size of precomputation tables, but we intentionally
179185 // avoid these to keep the standard library lightweight.
180 fn pcMul(pc: [9]Edwards25519, s: [32]u8, comptime vartime: bool) Error!Edwards25519 {
186 fn pcMul(pc: [9]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 {
181187 std.debug.assert(vartime);
182188 const e = nonAdjacentForm(s);
183189 var q = Edwards25519.identityElement;
......@@ -197,7 +203,7 @@ pub const Edwards25519 = struct {
197203 }
198204
199205 // Scalar multiplication with a 4-bit window and the first 15 multiples.
200 fn pcMul16(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) Error!Edwards25519 {
206 fn pcMul16(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 {
201207 var q = Edwards25519.identityElement;
202208 var pos: usize = 252;
203209 while (true) : (pos -= 4) {
......@@ -233,12 +239,12 @@ pub const Edwards25519 = struct {
233239 };
234240
235241 /// Multiply an Edwards25519 point by a scalar without clamping it.
236 /// Return error.WeakPublicKey if the resulting point is
237 /// the identity element.
238 pub fn mul(p: Edwards25519, s: [32]u8) Error!Edwards25519 {
242 /// Return error.WeakPublicKey if the base generates a small-order group,
243 /// and error.IdentityElement if the result is the identity element.
244 pub fn mul(p: Edwards25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
239245 const pc = if (p.is_base) basePointPc else pc: {
240246 const xpc = precompute(p, 15);
241 xpc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
247 xpc[4].rejectIdentity() catch return error.WeakPublicKey;
242248 break :pc xpc;
243249 };
244250 return pcMul16(pc, s, false);
......@@ -246,7 +252,7 @@ pub const Edwards25519 = struct {
246252
247253 /// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME*
248254 /// This can be used for signature verification.
249 pub fn mulPublic(p: Edwards25519, s: [32]u8) Error!Edwards25519 {
255 pub fn mulPublic(p: Edwards25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
250256 if (p.is_base) {
251257 return pcMul16(basePointPc, s, true);
252258 } else {
......@@ -258,7 +264,7 @@ pub const Edwards25519 = struct {
258264
259265 /// Multiscalar multiplication *IN VARIABLE TIME* for public data
260266 /// Computes ps0*ss0 + ps1*ss1 + ps2*ss2... faster than doing many of these operations individually
261 pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) Error!Edwards25519 {
267 pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
262268 var pcs: [count][9]Edwards25519 = undefined;
263269 for (ps) |p, i| {
264270 if (p.is_base) {
......@@ -297,14 +303,14 @@ pub const Edwards25519 = struct {
297303 /// This is strongly recommended for DH operations.
298304 /// Return error.WeakPublicKey if the resulting point is
299305 /// the identity element.
300 pub fn clampedMul(p: Edwards25519, s: [32]u8) Error!Edwards25519 {
306 pub fn clampedMul(p: Edwards25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
301307 var t: [32]u8 = s;
302308 scalar.clamp(&t);
303309 return mul(p, t);
304310 }
305311
306312 // montgomery -- recover y = sqrt(x^3 + A*x^2 + x)
307 fn xmontToYmont(x: Fe) Error!Fe {
313 fn xmontToYmont(x: Fe) NotSquareError!Fe {
308314 var x2 = x.sq();
309315 const x3 = x.mul(x2);
310316 x2 = x2.mul32(Fe.edwards25519a_32);
......@@ -367,7 +373,7 @@ pub const Edwards25519 = struct {
367373
368374 fn stringToPoints(comptime n: usize, ctx: []const u8, s: []const u8) [n]Edwards25519 {
369375 debug.assert(n <= 2);
370 const H = std.crypto.hash.sha2.Sha512;
376 const H = crypto.hash.sha2.Sha512;
371377 const h_l: usize = 48;
372378 var xctx = ctx;
373379 var hctx: [H.digest_length]u8 = undefined;
......@@ -485,8 +491,8 @@ test "edwards25519 packing/unpacking" {
485491test "edwards25519 point addition/substraction" {
486492 var s1: [32]u8 = undefined;
487493 var s2: [32]u8 = undefined;
488 std.crypto.random.bytes(&s1);
489 std.crypto.random.bytes(&s2);
494 crypto.random.bytes(&s1);
495 crypto.random.bytes(&s2);
490496 const p = try Edwards25519.basePoint.clampedMul(s1);
491497 const q = try Edwards25519.basePoint.clampedMul(s2);
492498 const r = p.add(q).add(q).sub(q).sub(q);
lib/std/crypto/25519/field.zig+6-3
......@@ -4,9 +4,12 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66const std = @import("std");
7const crypto = std.crypto;
78const readIntLittle = std.mem.readIntLittle;
89const writeIntLittle = std.mem.writeIntLittle;
9const Error = std.crypto.Error;
10
11const NonCanonicalError = crypto.errors.NonCanonicalError;
12const NotSquareError = crypto.errors.NotSquareError;
1013
1114pub const Fe = struct {
1215 limbs: [5]u64,
......@@ -113,7 +116,7 @@ pub const Fe = struct {
113116 }
114117
115118 /// Reject non-canonical encodings of an element, possibly ignoring the top bit
116 pub fn rejectNonCanonical(s: [32]u8, comptime ignore_extra_bit: bool) Error!void {
119 pub fn rejectNonCanonical(s: [32]u8, comptime ignore_extra_bit: bool) NonCanonicalError!void {
117120 var c: u16 = (s[31] & 0x7f) ^ 0x7f;
118121 comptime var i = 30;
119122 inline while (i > 0) : (i -= 1) {
......@@ -413,7 +416,7 @@ pub const Fe = struct {
413416 }
414417
415418 /// Compute the square root of `x2`, returning `error.NotSquare` if `x2` was not a square
416 pub fn sqrt(x2: Fe) Error!Fe {
419 pub fn sqrt(x2: Fe) NotSquareError!Fe {
417420 var x2_copy = x2;
418421 const x = x2.uncheckedSqrt();
419422 const check = x.sq().sub(x2_copy);
lib/std/crypto/25519/ristretto255.zig+9-5
......@@ -5,7 +5,11 @@
55// and substantial portions of the software.
66const std = @import("std");
77const fmt = std.fmt;
8const Error = std.crypto.Error;
8
9const EncodingError = std.crypto.errors.EncodingError;
10const IdentityElementError = std.crypto.errors.IdentityElementError;
11const NonCanonicalError = std.crypto.errors.NonCanonicalError;
12const WeakPublicKeyError = std.crypto.errors.WeakPublicKeyError;
913
1014/// Group operations over Edwards25519.
1115pub const Ristretto255 = struct {
......@@ -35,7 +39,7 @@ pub const Ristretto255 = struct {
3539 return .{ .ratio_is_square = @boolToInt(has_m_root) | @boolToInt(has_p_root), .root = x.abs() };
3640 }
3741
38 fn rejectNonCanonical(s: [encoded_length]u8) Error!void {
42 fn rejectNonCanonical(s: [encoded_length]u8) NonCanonicalError!void {
3943 if ((s[0] & 1) != 0) {
4044 return error.NonCanonical;
4145 }
......@@ -43,7 +47,7 @@ pub const Ristretto255 = struct {
4347 }
4448
4549 /// Reject the neutral element.
46 pub fn rejectIdentity(p: Ristretto255) callconv(.Inline) Error!void {
50 pub fn rejectIdentity(p: Ristretto255) callconv(.Inline) IdentityElementError!void {
4751 return p.p.rejectIdentity();
4852 }
4953
......@@ -51,7 +55,7 @@ pub const Ristretto255 = struct {
5155 pub const basePoint = Ristretto255{ .p = Curve.basePoint };
5256
5357 /// Decode a Ristretto255 representative.
54 pub fn fromBytes(s: [encoded_length]u8) Error!Ristretto255 {
58 pub fn fromBytes(s: [encoded_length]u8) (NonCanonicalError || EncodingError)!Ristretto255 {
5559 try rejectNonCanonical(s);
5660 const s_ = Fe.fromBytes(s);
5761 const ss = s_.sq(); // s^2
......@@ -154,7 +158,7 @@ pub const Ristretto255 = struct {
154158 /// Multiply a Ristretto255 element with a scalar.
155159 /// Return error.WeakPublicKey if the resulting element is
156160 /// the identity element.
157 pub fn mul(p: Ristretto255, s: [encoded_length]u8) callconv(.Inline) Error!Ristretto255 {
161 pub fn mul(p: Ristretto255, s: [encoded_length]u8) callconv(.Inline) (IdentityElementError || WeakPublicKeyError)!Ristretto255 {
158162 return Ristretto255{ .p = try p.p.mul(s) };
159163 }
160164
lib/std/crypto/25519/scalar.zig+3-2
......@@ -5,7 +5,8 @@
55// and substantial portions of the software.
66const std = @import("std");
77const mem = std.mem;
8const Error = std.crypto.Error;
8
9const NonCanonicalError = std.crypto.errors.NonCanonicalError;
910
1011/// 2^252 + 27742317777372353535851937790883648493
1112pub const field_size = [32]u8{
......@@ -19,7 +20,7 @@ pub const CompressedScalar = [32]u8;
1920pub const zero = [_]u8{0} ** 32;
2021
2122/// Reject a scalar whose encoding is not canonical.
22pub fn rejectNonCanonical(s: [32]u8) Error!void {
23pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!void {
2324 var c: u8 = 0;
2425 var n: u8 = 1;
2526 var i: usize = 31;
lib/std/crypto/25519/x25519.zig+9-6
......@@ -9,7 +9,10 @@ const mem = std.mem;
99const fmt = std.fmt;
1010
1111const Sha512 = crypto.hash.sha2.Sha512;
12const Error = crypto.Error;
12
13const EncodingError = crypto.errors.EncodingError;
14const IdentityElementError = crypto.errors.IdentityElementError;
15const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
1316
1417/// X25519 DH function.
1518pub const X25519 = struct {
......@@ -32,7 +35,7 @@ pub const X25519 = struct {
3235 secret_key: [secret_length]u8,
3336
3437 /// Create a new key pair using an optional seed.
35 pub fn create(seed: ?[seed_length]u8) Error!KeyPair {
38 pub fn create(seed: ?[seed_length]u8) IdentityElementError!KeyPair {
3639 const sk = seed orelse sk: {
3740 var random_seed: [seed_length]u8 = undefined;
3841 crypto.random.bytes(&random_seed);
......@@ -45,7 +48,7 @@ pub const X25519 = struct {
4548 }
4649
4750 /// Create a key pair from an Ed25519 key pair
48 pub fn fromEd25519(ed25519_key_pair: crypto.sign.Ed25519.KeyPair) Error!KeyPair {
51 pub fn fromEd25519(ed25519_key_pair: crypto.sign.Ed25519.KeyPair) (IdentityElementError || EncodingError)!KeyPair {
4952 const seed = ed25519_key_pair.secret_key[0..32];
5053 var az: [Sha512.digest_length]u8 = undefined;
5154 Sha512.hash(seed, &az, .{});
......@@ -60,13 +63,13 @@ pub const X25519 = struct {
6063 };
6164
6265 /// Compute the public key for a given private key.
63 pub fn recoverPublicKey(secret_key: [secret_length]u8) Error![public_length]u8 {
66 pub fn recoverPublicKey(secret_key: [secret_length]u8) IdentityElementError![public_length]u8 {
6467 const q = try Curve.basePoint.clampedMul(secret_key);
6568 return q.toBytes();
6669 }
6770
6871 /// Compute the X25519 equivalent to an Ed25519 public eky.
69 pub fn publicKeyFromEd25519(ed25519_public_key: [crypto.sign.Ed25519.public_length]u8) Error![public_length]u8 {
72 pub fn publicKeyFromEd25519(ed25519_public_key: [crypto.sign.Ed25519.public_length]u8) (IdentityElementError || EncodingError)![public_length]u8 {
7073 const pk_ed = try crypto.ecc.Edwards25519.fromBytes(ed25519_public_key);
7174 const pk = try Curve.fromEdwards25519(pk_ed);
7275 return pk.toBytes();
......@@ -75,7 +78,7 @@ pub const X25519 = struct {
7578 /// Compute the scalar product of a public key and a secret scalar.
7679 /// Note that the output should not be used as a shared secret without
7780 /// hashing it first.
78 pub fn scalarmult(secret_key: [secret_length]u8, public_key: [public_length]u8) Error![shared_length]u8 {
81 pub fn scalarmult(secret_key: [secret_length]u8, public_key: [public_length]u8) IdentityElementError![shared_length]u8 {
7982 const q = try Curve.fromBytes(public_key).clampedMul(secret_key);
8083 return q.toBytes();
8184 }
lib/std/crypto/aegis.zig+3-3
......@@ -8,7 +8,7 @@ const std = @import("std");
88const mem = std.mem;
99const assert = std.debug.assert;
1010const AesBlock = std.crypto.core.aes.Block;
11const Error = std.crypto.Error;
11const AuthenticationError = std.crypto.errors.AuthenticationError;
1212
1313const State128L = struct {
1414 blocks: [8]AesBlock,
......@@ -137,7 +137,7 @@ pub const Aegis128L = struct {
137137 /// ad: Associated Data
138138 /// npub: public nonce
139139 /// k: private key
140 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
140 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
141141 assert(c.len == m.len);
142142 var state = State128L.init(key, npub);
143143 var src: [32]u8 align(16) = undefined;
......@@ -299,7 +299,7 @@ pub const Aegis256 = struct {
299299 /// ad: Associated Data
300300 /// npub: public nonce
301301 /// k: private key
302 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
302 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
303303 assert(c.len == m.len);
304304 var state = State256.init(key, npub);
305305 var src: [16]u8 align(16) = undefined;
lib/std/crypto/aes_gcm.zig+2-2
......@@ -12,7 +12,7 @@ const debug = std.debug;
1212const Ghash = std.crypto.onetimeauth.Ghash;
1313const mem = std.mem;
1414const modes = crypto.core.modes;
15const Error = crypto.Error;
15const AuthenticationError = crypto.errors.AuthenticationError;
1616
1717pub const Aes128Gcm = AesGcm(crypto.core.aes.Aes128);
1818pub const Aes256Gcm = AesGcm(crypto.core.aes.Aes256);
......@@ -60,7 +60,7 @@ fn AesGcm(comptime Aes: anytype) type {
6060 }
6161 }
6262
63 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
63 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
6464 assert(c.len == m.len);
6565
6666 const aes = Aes.initEnc(key);
lib/std/crypto/aes_ocb.zig+2-2
......@@ -10,7 +10,7 @@ const aes = crypto.core.aes;
1010const assert = std.debug.assert;
1111const math = std.math;
1212const mem = std.mem;
13const Error = crypto.Error;
13const AuthenticationError = crypto.errors.AuthenticationError;
1414
1515pub const Aes128Ocb = AesOcb(aes.Aes128);
1616pub const Aes256Ocb = AesOcb(aes.Aes256);
......@@ -179,7 +179,7 @@ fn AesOcb(comptime Aes: anytype) type {
179179 /// ad: Associated Data
180180 /// npub: public nonce
181181 /// k: secret key
182 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
182 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
183183 assert(c.len == m.len);
184184
185185 const aes_enc_ctx = Aes.initEnc(key);
lib/std/crypto/bcrypt.zig+6-5
......@@ -12,7 +12,8 @@ const mem = std.mem;
1212const debug = std.debug;
1313const testing = std.testing;
1414const utils = crypto.utils;
15const Error = crypto.Error;
15const EncodingError = crypto.errors.EncodingError;
16const PasswordVerificationError = crypto.errors.PasswordVerificationError;
1617
1718const salt_length: usize = 16;
1819const salt_str_length: usize = 22;
......@@ -179,7 +180,7 @@ const Codec = struct {
179180 debug.assert(j == b64.len);
180181 }
181182
182 fn decode(bin: []u8, b64: []const u8) Error!void {
183 fn decode(bin: []u8, b64: []const u8) EncodingError!void {
183184 var i: usize = 0;
184185 var j: usize = 0;
185186 while (j < bin.len) {
......@@ -204,7 +205,7 @@ const Codec = struct {
204205 }
205206};
206207
207fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8) Error![hash_length]u8 {
208fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8) ![hash_length]u8 {
208209 var state = State{};
209210 var password_buf: [73]u8 = undefined;
210211 const trimmed_len = math.min(password.len, password_buf.len - 1);
......@@ -252,14 +253,14 @@ fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8)
252253/// IMPORTANT: by design, bcrypt silently truncates passwords to 72 bytes.
253254/// If this is an issue for your application, hash the password first using a function such as SHA-512,
254255/// and then use the resulting hash as the password parameter for bcrypt.
255pub fn strHash(password: []const u8, rounds_log: u6) Error![hash_length]u8 {
256pub fn strHash(password: []const u8, rounds_log: u6) ![hash_length]u8 {
256257 var salt: [salt_length]u8 = undefined;
257258 crypto.random.bytes(&salt);
258259 return strHashInternal(password, rounds_log, salt);
259260}
260261
261262/// Verify that a previously computed hash is valid for a given password.
262pub fn strVerify(h: [hash_length]u8, password: []const u8) Error!void {
263pub fn strVerify(h: [hash_length]u8, password: []const u8) (EncodingError || PasswordVerificationError)!void {
263264 if (!mem.eql(u8, "$2", h[0..2])) return error.InvalidEncoding;
264265 if (h[3] != '$' or h[6] != '$') return error.InvalidEncoding;
265266 const rounds_log_str = h[4..][0..2];
lib/std/crypto/chacha20.zig+3-3
......@@ -13,7 +13,7 @@ const testing = std.testing;
1313const maxInt = math.maxInt;
1414const Vector = std.meta.Vector;
1515const Poly1305 = std.crypto.onetimeauth.Poly1305;
16const Error = std.crypto.Error;
16const AuthenticationError = std.crypto.errors.AuthenticationError;
1717
1818/// IETF-variant of the ChaCha20 stream cipher, as designed for TLS.
1919pub const ChaCha20IETF = ChaChaIETF(20);
......@@ -521,7 +521,7 @@ fn ChaChaPoly1305(comptime rounds_nb: usize) type {
521521 /// npub: public nonce
522522 /// k: private key
523523 /// NOTE: the check of the authentication tag is currently not done in constant time
524 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
524 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
525525 assert(c.len == m.len);
526526
527527 var polyKey = [_]u8{0} ** 32;
......@@ -583,7 +583,7 @@ fn XChaChaPoly1305(comptime rounds_nb: usize) type {
583583 /// ad: Associated Data
584584 /// npub: public nonce
585585 /// k: private key
586 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
586 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
587587 const extended = extend(k, npub, rounds_nb);
588588 return ChaChaPoly1305(rounds_nb).decrypt(m, c, tag, ad, extended.nonce, extended.key);
589589 }
lib/std/crypto/error.zig deleted-34
......@@ -1,34 +0,0 @@
1pub const Error = error{
2 /// MAC verification failed - The tag doesn't verify for the given ciphertext and secret key
3 AuthenticationFailed,
4
5 /// The requested output length is too long for the chosen algorithm
6 OutputTooLong,
7
8 /// Finite field operation returned the identity element
9 IdentityElement,
10
11 /// Encoded input cannot be decoded
12 InvalidEncoding,
13
14 /// The signature does't verify for the given message and public key
15 SignatureVerificationFailed,
16
17 /// Both a public and secret key have been provided, but they are incompatible
18 KeyMismatch,
19
20 /// Encoded input is not in canonical form
21 NonCanonical,
22
23 /// Square root has no solutions
24 NotSquare,
25
26 /// Verification string doesn't match the provided password and parameters
27 PasswordVerificationFailed,
28
29 /// Parameters would be insecure to use
30 WeakParameters,
31
32 /// Public key would be insecure to use
33 WeakPublicKey,
34};
lib/std/crypto/errors.zig created+35
......@@ -0,0 +1,35 @@
1/// MAC verification failed - The tag doesn't verify for the given ciphertext and secret key
2pub const AuthenticationError = error{AuthenticationFailed};
3
4/// The requested output length is too long for the chosen algorithm
5pub const OutputTooLongError = error{OutputTooLong};
6
7/// Finite field operation returned the identity element
8pub const IdentityElementError = error{IdentityElement};
9
10/// Encoded input cannot be decoded
11pub const EncodingError = error{InvalidEncoding};
12
13/// The signature does't verify for the given message and public key
14pub const SignatureVerificationError = error{SignatureVerificationFailed};
15
16/// Both a public and secret key have been provided, but they are incompatible
17pub const KeyMismatchError = error{KeyMismatch};
18
19/// Encoded input is not in canonical form
20pub const NonCanonicalError = error{NonCanonical};
21
22/// Square root has no solutions
23pub const NotSquareError = error{NotSquare};
24
25/// Verification string doesn't match the provided password and parameters
26pub const PasswordVerificationError = error{PasswordVerificationFailed};
27
28/// Parameters would be insecure to use
29pub const WeakParametersError = error{WeakParameters};
30
31/// Public key would be insecure to use
32pub const WeakPublicKeyError = error{WeakPublicKey};
33
34/// Any error related to cryptography operations
35pub const Error = AuthenticationError || OutputTooLongError || IdentityElementError || EncodingError || SignatureVerificationError || KeyMismatchError || NonCanonicalError || NotSquareError || PasswordVerificationError || WeakParametersError || WeakPublicKeyError;
lib/std/crypto/gimli.zig+2-2
......@@ -20,7 +20,7 @@ const assert = std.debug.assert;
2020const testing = std.testing;
2121const htest = @import("test.zig");
2222const Vector = std.meta.Vector;
23const Error = std.crypto.Error;
23const AuthenticationError = std.crypto.errors.AuthenticationError;
2424
2525pub const State = struct {
2626 pub const BLOCKBYTES = 48;
......@@ -393,7 +393,7 @@ pub const Aead = struct {
393393 /// npub: public nonce
394394 /// k: private key
395395 /// NOTE: the check of the authentication tag is currently not done in constant time
396 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
396 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
397397 assert(c.len == m.len);
398398
399399 var state = Aead.init(ad, npub, k);
lib/std/crypto/isap.zig+2-2
......@@ -3,7 +3,7 @@ const debug = std.debug;
33const mem = std.mem;
44const math = std.math;
55const testing = std.testing;
6const Error = std.crypto.Error;
6const AuthenticationError = std.crypto.errors.AuthenticationError;
77
88/// ISAPv2 is an authenticated encryption system hardened against side channels and fault attacks.
99/// https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/round-2/spec-doc-rnd2/isap-spec-round2.pdf
......@@ -218,7 +218,7 @@ pub const IsapA128A = struct {
218218 tag.* = mac(c, ad, npub, key);
219219 }
220220
221 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
221 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
222222 var computed_tag = mac(c, ad, npub, key);
223223 var acc: u8 = 0;
224224 for (computed_tag) |_, j| {
lib/std/crypto/pbkdf2.zig+3-2
......@@ -7,7 +7,8 @@
77const std = @import("std");
88const mem = std.mem;
99const maxInt = std.math.maxInt;
10const Error = std.crypto.Error;
10const OutputTooLongError = std.crypto.errors.OutputTooLongError;
11const WeakParametersError = std.crypto.errors.WeakParametersError;
1112
1213// RFC 2898 Section 5.2
1314//
......@@ -55,7 +56,7 @@ const Error = std.crypto.Error;
5556/// the dk. It is common to tune this parameter to achieve approximately 100ms.
5657///
5758/// Prf: Pseudo-random function to use. A common choice is `std.crypto.auth.hmac.HmacSha256`.
58pub fn pbkdf2(dk: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) Error!void {
59pub fn pbkdf2(dk: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) (WeakParametersError || OutputTooLongError)!void {
5960 if (rounds < 1) return error.WeakParameters;
6061
6162 const dk_len = dk.len;
lib/std/crypto/salsa20.zig+11-8
......@@ -15,7 +15,10 @@ const Vector = std.meta.Vector;
1515const Poly1305 = crypto.onetimeauth.Poly1305;
1616const Blake2b = crypto.hash.blake2.Blake2b;
1717const X25519 = crypto.dh.X25519;
18const Error = crypto.Error;
18
19const AuthenticationError = crypto.errors.AuthenticationError;
20const IdentityElementError = crypto.errors.IdentityElementError;
21const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
1922
2023const Salsa20VecImpl = struct {
2124 const Lane = Vector(4, u32);
......@@ -399,7 +402,7 @@ pub const XSalsa20Poly1305 = struct {
399402 /// ad: Associated Data
400403 /// npub: public nonce
401404 /// k: private key
402 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
405 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
403406 debug.assert(c.len == m.len);
404407 const extended = extend(k, npub);
405408 var block0 = [_]u8{0} ** 64;
......@@ -447,7 +450,7 @@ pub const SecretBox = struct {
447450
448451 /// Verify and decrypt `c` using a nonce `npub` and a key `k`.
449452 /// `m` must be exactly `tag_length` smaller than `c`, as `c` includes an authentication tag in addition to the encrypted message.
450 pub fn open(m: []u8, c: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
453 pub fn open(m: []u8, c: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
451454 if (c.len < tag_length) {
452455 return error.AuthenticationFailed;
453456 }
......@@ -482,20 +485,20 @@ pub const Box = struct {
482485 pub const KeyPair = X25519.KeyPair;
483486
484487 /// Compute a secret suitable for `secretbox` given a recipent's public key and a sender's secret key.
485 pub fn createSharedSecret(public_key: [public_length]u8, secret_key: [secret_length]u8) Error![shared_length]u8 {
488 pub fn createSharedSecret(public_key: [public_length]u8, secret_key: [secret_length]u8) (IdentityElementError || WeakPublicKeyError)![shared_length]u8 {
486489 const p = try X25519.scalarmult(secret_key, public_key);
487490 const zero = [_]u8{0} ** 16;
488491 return Salsa20Impl.hsalsa20(zero, p);
489492 }
490493
491494 /// Encrypt and authenticate a message using a recipient's public key `public_key` and a sender's `secret_key`.
492 pub fn seal(c: []u8, m: []const u8, npub: [nonce_length]u8, public_key: [public_length]u8, secret_key: [secret_length]u8) Error!void {
495 pub fn seal(c: []u8, m: []const u8, npub: [nonce_length]u8, public_key: [public_length]u8, secret_key: [secret_length]u8) (IdentityElementError || WeakPublicKeyError)!void {
493496 const shared_key = try createSharedSecret(public_key, secret_key);
494497 return SecretBox.seal(c, m, npub, shared_key);
495498 }
496499
497500 /// Verify and decrypt a message using a recipient's secret key `public_key` and a sender's `public_key`.
498 pub fn open(m: []u8, c: []const u8, npub: [nonce_length]u8, public_key: [public_length]u8, secret_key: [secret_length]u8) Error!void {
501 pub fn open(m: []u8, c: []const u8, npub: [nonce_length]u8, public_key: [public_length]u8, secret_key: [secret_length]u8) (IdentityElementError || WeakPublicKeyError || AuthenticationError)!void {
499502 const shared_key = try createSharedSecret(public_key, secret_key);
500503 return SecretBox.open(m, c, npub, shared_key);
501504 }
......@@ -528,7 +531,7 @@ pub const SealedBox = struct {
528531
529532 /// Encrypt a message `m` for a recipient whose public key is `public_key`.
530533 /// `c` must be `seal_length` bytes larger than `m`, so that the required metadata can be added.
531 pub fn seal(c: []u8, m: []const u8, public_key: [public_length]u8) Error!void {
534 pub fn seal(c: []u8, m: []const u8, public_key: [public_length]u8) (WeakPublicKeyError || IdentityElementError)!void {
532535 debug.assert(c.len == m.len + seal_length);
533536 var ekp = try KeyPair.create(null);
534537 const nonce = createNonce(ekp.public_key, public_key);
......@@ -539,7 +542,7 @@ pub const SealedBox = struct {
539542
540543 /// Decrypt a message using a key pair.
541544 /// `m` must be exactly `seal_length` bytes smaller than `c`, as `c` also includes metadata.
542 pub fn open(m: []u8, c: []const u8, keypair: KeyPair) Error!void {
545 pub fn open(m: []u8, c: []const u8, keypair: KeyPair) (IdentityElementError || WeakPublicKeyError || AuthenticationError)!void {
543546 if (c.len < seal_length) {
544547 return error.AuthenticationFailed;
545548 }