aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAlexandros Naskos <alex_naskos@hotmail.com>2020-10-04 10:39:26 +0300
committerAlexandros Naskos <alex_naskos@hotmail.com>2020-10-04 10:39:26 +0300
commit23cd3b33312ea5fcae32dcb6cd53cbd502361ce9 (patch)
treeeae3657140271fb945dae6e4e1ad9c788808ac58 /lib/std
parent82f0ede3ad4150a80ab745419664f1dce4a6be9c (diff)
parent8170a3d574a7118a6ee616d1b1258b2e839de173 (diff)
downloadzig-23cd3b33312ea5fcae32dcb6cd53cbd502361ce9.tar.gz
zig-23cd3b33312ea5fcae32dcb6cd53cbd502361ce9.zip
Merge branch 'master' of https://github.com/ziglang/zig into add_some_frees
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/array_list.zig574
-rw-r--r--lib/std/build.zig8
-rw-r--r--lib/std/builtin.zig3
-rw-r--r--lib/std/c/darwin.zig2
-rw-r--r--lib/std/crypto.zig86
-rw-r--r--lib/std/crypto/benchmark.zig1
-rw-r--r--lib/std/crypto/ghash.zig310
-rw-r--r--lib/std/crypto/hkdf.zig66
-rw-r--r--lib/std/crypto/poly1305.zig11
-rw-r--r--lib/std/fmt.zig10
-rw-r--r--lib/std/fs.zig16
-rw-r--r--lib/std/math/big/int.zig120
-rw-r--r--lib/std/math/big/int_test.zig45
-rw-r--r--lib/std/meta.zig2
-rw-r--r--lib/std/meta/trailer_flags.zig1
-rw-r--r--lib/std/os.zig2
-rw-r--r--lib/std/packed_int_array.zig15
17 files changed, 1049 insertions, 223 deletions
diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig
index f298d14631..9144d2c644 100644
--- a/lib/std/array_list.zig
+++ b/lib/std/array_list.zig
@@ -371,7 +371,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
var self = Self{};
- const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least);
+ const new_memory = try allocator.allocAdvanced(T, alignment, num, .at_least);
self.items.ptr = new_memory.ptr;
self.capacity = new_memory.len;
@@ -419,7 +419,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
/// Replace range of elements `list[start..start+len]` with `new_items`
/// grows list if `len < new_items.len`. may allocate
/// shrinks list if `len > new_items.len`
- pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: SliceConst) !void {
+ pub fn replaceRange(self: *Self, allocator: *Allocator, start: usize, len: usize, new_items: SliceConst) !void {
var managed = self.toManaged(allocator);
try managed.replaceRange(start, len, new_items);
self.* = managed.toUnmanaged();
@@ -617,201 +617,414 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
};
}
-test "std.ArrayList.init" {
- var list = ArrayList(i32).init(testing.allocator);
- defer list.deinit();
+test "std.ArrayList/ArrayListUnmanaged.init" {
+ {
+ var list = ArrayList(i32).init(testing.allocator);
+ defer list.deinit();
- testing.expect(list.items.len == 0);
- testing.expect(list.capacity == 0);
-}
+ testing.expect(list.items.len == 0);
+ testing.expect(list.capacity == 0);
+ }
-test "std.ArrayList.initCapacity" {
- var list = try ArrayList(i8).initCapacity(testing.allocator, 200);
- defer list.deinit();
- testing.expect(list.items.len == 0);
- testing.expect(list.capacity >= 200);
-}
+ {
+ var list = ArrayListUnmanaged(i32){};
-test "std.ArrayList.basic" {
- var list = ArrayList(i32).init(testing.allocator);
- defer list.deinit();
+ testing.expect(list.items.len == 0);
+ testing.expect(list.capacity == 0);
+ }
+}
+test "std.ArrayList/ArrayListUnmanaged.initCapacity" {
+ const a = testing.allocator;
{
- var i: usize = 0;
- while (i < 10) : (i += 1) {
- list.append(@intCast(i32, i + 1)) catch unreachable;
- }
+ var list = try ArrayList(i8).initCapacity(a, 200);
+ defer list.deinit();
+ testing.expect(list.items.len == 0);
+ testing.expect(list.capacity >= 200);
+ }
+ {
+ var list = try ArrayListUnmanaged(i8).initCapacity(a, 200);
+ defer list.deinit(a);
+ testing.expect(list.items.len == 0);
+ testing.expect(list.capacity >= 200);
}
+}
+test "std.ArrayList/ArrayListUnmanaged.basic" {
+ const a = testing.allocator;
{
- var i: usize = 0;
- while (i < 10) : (i += 1) {
- testing.expect(list.items[i] == @intCast(i32, i + 1));
+ var list = ArrayList(i32).init(a);
+ defer list.deinit();
+
+ {
+ var i: usize = 0;
+ while (i < 10) : (i += 1) {
+ list.append(@intCast(i32, i + 1)) catch unreachable;
+ }
+ }
+
+ {
+ var i: usize = 0;
+ while (i < 10) : (i += 1) {
+ testing.expect(list.items[i] == @intCast(i32, i + 1));
+ }
+ }
+
+ for (list.items) |v, i| {
+ testing.expect(v == @intCast(i32, i + 1));
}
- }
- for (list.items) |v, i| {
- testing.expect(v == @intCast(i32, i + 1));
+ testing.expect(list.pop() == 10);
+ testing.expect(list.items.len == 9);
+
+ list.appendSlice(&[_]i32{ 1, 2, 3 }) catch unreachable;
+ testing.expect(list.items.len == 12);
+ testing.expect(list.pop() == 3);
+ testing.expect(list.pop() == 2);
+ testing.expect(list.pop() == 1);
+ testing.expect(list.items.len == 9);
+
+ list.appendSlice(&[_]i32{}) catch unreachable;
+ testing.expect(list.items.len == 9);
+
+ // can only set on indices < self.items.len
+ list.items[7] = 33;
+ list.items[8] = 42;
+
+ testing.expect(list.pop() == 42);
+ testing.expect(list.pop() == 33);
}
+ {
+ var list = ArrayListUnmanaged(i32){};
+ defer list.deinit(a);
+
+ {
+ var i: usize = 0;
+ while (i < 10) : (i += 1) {
+ list.append(a, @intCast(i32, i + 1)) catch unreachable;
+ }
+ }
+
+ {
+ var i: usize = 0;
+ while (i < 10) : (i += 1) {
+ testing.expect(list.items[i] == @intCast(i32, i + 1));
+ }
+ }
+
+ for (list.items) |v, i| {
+ testing.expect(v == @intCast(i32, i + 1));
+ }
- testing.expect(list.pop() == 10);
- testing.expect(list.items.len == 9);
+ testing.expect(list.pop() == 10);
+ testing.expect(list.items.len == 9);
- list.appendSlice(&[_]i32{ 1, 2, 3 }) catch unreachable;
- testing.expect(list.items.len == 12);
- testing.expect(list.pop() == 3);
- testing.expect(list.pop() == 2);
- testing.expect(list.pop() == 1);
- testing.expect(list.items.len == 9);
+ list.appendSlice(a, &[_]i32{ 1, 2, 3 }) catch unreachable;
+ testing.expect(list.items.len == 12);
+ testing.expect(list.pop() == 3);
+ testing.expect(list.pop() == 2);
+ testing.expect(list.pop() == 1);
+ testing.expect(list.items.len == 9);
- list.appendSlice(&[_]i32{}) catch unreachable;
- testing.expect(list.items.len == 9);
+ list.appendSlice(a, &[_]i32{}) catch unreachable;
+ testing.expect(list.items.len == 9);
- // can only set on indices < self.items.len
- list.items[7] = 33;
- list.items[8] = 42;
+ // can only set on indices < self.items.len
+ list.items[7] = 33;
+ list.items[8] = 42;
- testing.expect(list.pop() == 42);
- testing.expect(list.pop() == 33);
+ testing.expect(list.pop() == 42);
+ testing.expect(list.pop() == 33);
+ }
}
-test "std.ArrayList.appendNTimes" {
- var list = ArrayList(i32).init(testing.allocator);
- defer list.deinit();
+test "std.ArrayList/ArrayListUnmanaged.appendNTimes" {
+ const a = testing.allocator;
+ {
+ var list = ArrayList(i32).init(a);
+ defer list.deinit();
+
+ try list.appendNTimes(2, 10);
+ testing.expectEqual(@as(usize, 10), list.items.len);
+ for (list.items) |element| {
+ testing.expectEqual(@as(i32, 2), element);
+ }
+ }
+ {
+ var list = ArrayListUnmanaged(i32){};
+ defer list.deinit(a);
- try list.appendNTimes(2, 10);
- testing.expectEqual(@as(usize, 10), list.items.len);
- for (list.items) |element| {
- testing.expectEqual(@as(i32, 2), element);
+ try list.appendNTimes(a, 2, 10);
+ testing.expectEqual(@as(usize, 10), list.items.len);
+ for (list.items) |element| {
+ testing.expectEqual(@as(i32, 2), element);
+ }
}
}
-test "std.ArrayList.appendNTimes with failing allocator" {
- var list = ArrayList(i32).init(testing.failing_allocator);
- defer list.deinit();
- testing.expectError(error.OutOfMemory, list.appendNTimes(2, 10));
+test "std.ArrayList/ArrayListUnmanaged.appendNTimes with failing allocator" {
+ const a = testing.failing_allocator;
+ {
+ var list = ArrayList(i32).init(a);
+ defer list.deinit();
+ testing.expectError(error.OutOfMemory, list.appendNTimes(2, 10));
+ }
+ {
+ var list = ArrayListUnmanaged(i32){};
+ defer list.deinit(a);
+ testing.expectError(error.OutOfMemory, list.appendNTimes(a, 2, 10));
+ }
}
-test "std.ArrayList.orderedRemove" {
- var list = ArrayList(i32).init(testing.allocator);
- defer list.deinit();
+test "std.ArrayList/ArrayListUnmanaged.orderedRemove" {
+ const a = testing.allocator;
+ {
+ var list = ArrayList(i32).init(a);
+ defer list.deinit();
+
+ try list.append(1);
+ try list.append(2);
+ try list.append(3);
+ try list.append(4);
+ try list.append(5);
+ try list.append(6);
+ try list.append(7);
+
+ //remove from middle
+ testing.expectEqual(@as(i32, 4), list.orderedRemove(3));
+ testing.expectEqual(@as(i32, 5), list.items[3]);
+ testing.expectEqual(@as(usize, 6), list.items.len);
+
+ //remove from end
+ testing.expectEqual(@as(i32, 7), list.orderedRemove(5));
+ testing.expectEqual(@as(usize, 5), list.items.len);
+
+ //remove from front
+ testing.expectEqual(@as(i32, 1), list.orderedRemove(0));
+ testing.expectEqual(@as(i32, 2), list.items[0]);
+ testing.expectEqual(@as(usize, 4), list.items.len);
+ }
+ {
+ var list = ArrayListUnmanaged(i32){};
+ defer list.deinit(a);
- try list.append(1);
- try list.append(2);
- try list.append(3);
- try list.append(4);
- try list.append(5);
- try list.append(6);
- try list.append(7);
-
- //remove from middle
- testing.expectEqual(@as(i32, 4), list.orderedRemove(3));
- testing.expectEqual(@as(i32, 5), list.items[3]);
- testing.expectEqual(@as(usize, 6), list.items.len);
-
- //remove from end
- testing.expectEqual(@as(i32, 7), list.orderedRemove(5));
- testing.expectEqual(@as(usize, 5), list.items.len);
-
- //remove from front
- testing.expectEqual(@as(i32, 1), list.orderedRemove(0));
- testing.expectEqual(@as(i32, 2), list.items[0]);
- testing.expectEqual(@as(usize, 4), list.items.len);
+ try list.append(a, 1);
+ try list.append(a, 2);
+ try list.append(a, 3);
+ try list.append(a, 4);
+ try list.append(a, 5);
+ try list.append(a, 6);
+ try list.append(a, 7);
+
+ //remove from middle
+ testing.expectEqual(@as(i32, 4), list.orderedRemove(3));
+ testing.expectEqual(@as(i32, 5), list.items[3]);
+ testing.expectEqual(@as(usize, 6), list.items.len);
+
+ //remove from end
+ testing.expectEqual(@as(i32, 7), list.orderedRemove(5));
+ testing.expectEqual(@as(usize, 5), list.items.len);
+
+ //remove from front
+ testing.expectEqual(@as(i32, 1), list.orderedRemove(0));
+ testing.expectEqual(@as(i32, 2), list.items[0]);
+ testing.expectEqual(@as(usize, 4), list.items.len);
+ }
}
-test "std.ArrayList.swapRemove" {
- var list = ArrayList(i32).init(testing.allocator);
- defer list.deinit();
+test "std.ArrayList/ArrayListUnmanaged.swapRemove" {
+ const a = testing.allocator;
+ {
+ var list = ArrayList(i32).init(a);
+ defer list.deinit();
- try list.append(1);
- try list.append(2);
- try list.append(3);
- try list.append(4);
- try list.append(5);
- try list.append(6);
- try list.append(7);
-
- //remove from middle
- testing.expect(list.swapRemove(3) == 4);
- testing.expect(list.items[3] == 7);
- testing.expect(list.items.len == 6);
-
- //remove from end
- testing.expect(list.swapRemove(5) == 6);
- testing.expect(list.items.len == 5);
-
- //remove from front
- testing.expect(list.swapRemove(0) == 1);
- testing.expect(list.items[0] == 5);
- testing.expect(list.items.len == 4);
+ try list.append(1);
+ try list.append(2);
+ try list.append(3);
+ try list.append(4);
+ try list.append(5);
+ try list.append(6);
+ try list.append(7);
+
+ //remove from middle
+ testing.expect(list.swapRemove(3) == 4);
+ testing.expect(list.items[3] == 7);
+ testing.expect(list.items.len == 6);
+
+ //remove from end
+ testing.expect(list.swapRemove(5) == 6);
+ testing.expect(list.items.len == 5);
+
+ //remove from front
+ testing.expect(list.swapRemove(0) == 1);
+ testing.expect(list.items[0] == 5);
+ testing.expect(list.items.len == 4);
+ }
+ {
+ var list = ArrayListUnmanaged(i32){};
+ defer list.deinit(a);
+
+ try list.append(a, 1);
+ try list.append(a, 2);
+ try list.append(a, 3);
+ try list.append(a, 4);
+ try list.append(a, 5);
+ try list.append(a, 6);
+ try list.append(a, 7);
+
+ //remove from middle
+ testing.expect(list.swapRemove(3) == 4);
+ testing.expect(list.items[3] == 7);
+ testing.expect(list.items.len == 6);
+
+ //remove from end
+ testing.expect(list.swapRemove(5) == 6);
+ testing.expect(list.items.len == 5);
+
+ //remove from front
+ testing.expect(list.swapRemove(0) == 1);
+ testing.expect(list.items[0] == 5);
+ testing.expect(list.items.len == 4);
+ }
}
-test "std.ArrayList.insert" {
- var list = ArrayList(i32).init(testing.allocator);
- defer list.deinit();
+test "std.ArrayList/ArrayListUnmanaged.insert" {
+ const a = testing.allocator;
+ {
+ var list = ArrayList(i32).init(a);
+ defer list.deinit();
- try list.append(1);
- try list.append(2);
- try list.append(3);
- try list.insert(0, 5);
- testing.expect(list.items[0] == 5);
- testing.expect(list.items[1] == 1);
- testing.expect(list.items[2] == 2);
- testing.expect(list.items[3] == 3);
+ try list.append(1);
+ try list.append(2);
+ try list.append(3);
+ try list.insert(0, 5);
+ testing.expect(list.items[0] == 5);
+ testing.expect(list.items[1] == 1);
+ testing.expect(list.items[2] == 2);
+ testing.expect(list.items[3] == 3);
+ }
+ {
+ var list = ArrayListUnmanaged(i32){};
+ defer list.deinit(a);
+
+ try list.append(a, 1);
+ try list.append(a, 2);
+ try list.append(a, 3);
+ try list.insert(a, 0, 5);
+ testing.expect(list.items[0] == 5);
+ testing.expect(list.items[1] == 1);
+ testing.expect(list.items[2] == 2);
+ testing.expect(list.items[3] == 3);
+ }
}
-test "std.ArrayList.insertSlice" {
- var list = ArrayList(i32).init(testing.allocator);
- defer list.deinit();
+test "std.ArrayList/ArrayListUnmanaged.insertSlice" {
+ const a = testing.allocator;
+ {
+ var list = ArrayList(i32).init(a);
+ defer list.deinit();
- try list.append(1);
- try list.append(2);
- try list.append(3);
- try list.append(4);
- try list.insertSlice(1, &[_]i32{ 9, 8 });
- testing.expect(list.items[0] == 1);
- testing.expect(list.items[1] == 9);
- testing.expect(list.items[2] == 8);
- testing.expect(list.items[3] == 2);
- testing.expect(list.items[4] == 3);
- testing.expect(list.items[5] == 4);
-
- const items = [_]i32{1};
- try list.insertSlice(0, items[0..0]);
- testing.expect(list.items.len == 6);
- testing.expect(list.items[0] == 1);
+ try list.append(1);
+ try list.append(2);
+ try list.append(3);
+ try list.append(4);
+ try list.insertSlice(1, &[_]i32{ 9, 8 });
+ testing.expect(list.items[0] == 1);
+ testing.expect(list.items[1] == 9);
+ testing.expect(list.items[2] == 8);
+ testing.expect(list.items[3] == 2);
+ testing.expect(list.items[4] == 3);
+ testing.expect(list.items[5] == 4);
+
+ const items = [_]i32{1};
+ try list.insertSlice(0, items[0..0]);
+ testing.expect(list.items.len == 6);
+ testing.expect(list.items[0] == 1);
+ }
+ {
+ var list = ArrayListUnmanaged(i32){};
+ defer list.deinit(a);
+
+ try list.append(a, 1);
+ try list.append(a, 2);
+ try list.append(a, 3);
+ try list.append(a, 4);
+ try list.insertSlice(a, 1, &[_]i32{ 9, 8 });
+ testing.expect(list.items[0] == 1);
+ testing.expect(list.items[1] == 9);
+ testing.expect(list.items[2] == 8);
+ testing.expect(list.items[3] == 2);
+ testing.expect(list.items[4] == 3);
+ testing.expect(list.items[5] == 4);
+
+ const items = [_]i32{1};
+ try list.insertSlice(a, 0, items[0..0]);
+ testing.expect(list.items.len == 6);
+ testing.expect(list.items[0] == 1);
+ }
}
-test "std.ArrayList.replaceRange" {
+test "std.ArrayList/ArrayListUnmanaged.replaceRange" {
var arena = std.heap.ArenaAllocator.init(testing.allocator);
defer arena.deinit();
+ const a = &arena.allocator;
- const alloc = &arena.allocator;
const init = [_]i32{ 1, 2, 3, 4, 5 };
const new = [_]i32{ 0, 0, 0 };
- var list_zero = ArrayList(i32).init(alloc);
- var list_eq = ArrayList(i32).init(alloc);
- var list_lt = ArrayList(i32).init(alloc);
- var list_gt = ArrayList(i32).init(alloc);
+ const result_zero = [_]i32{ 1, 0, 0, 0, 2, 3, 4, 5 };
+ const result_eq = [_]i32{ 1, 0, 0, 0, 5 };
+ const result_le = [_]i32{ 1, 0, 0, 0, 4, 5 };
+ const result_gt = [_]i32{ 1, 0, 0, 0 };
- try list_zero.appendSlice(&init);
- try list_eq.appendSlice(&init);
- try list_lt.appendSlice(&init);
- try list_gt.appendSlice(&init);
-
- try list_zero.replaceRange(1, 0, &new);
- try list_eq.replaceRange(1, 3, &new);
- try list_lt.replaceRange(1, 2, &new);
-
- // after_range > new_items.len in function body
- testing.expect(1 + 4 > new.len);
- try list_gt.replaceRange(1, 4, &new);
-
- testing.expectEqualSlices(i32, list_zero.items, &[_]i32{ 1, 0, 0, 0, 2, 3, 4, 5 });
- testing.expectEqualSlices(i32, list_eq.items, &[_]i32{ 1, 0, 0, 0, 5 });
- testing.expectEqualSlices(i32, list_lt.items, &[_]i32{ 1, 0, 0, 0, 4, 5 });
- testing.expectEqualSlices(i32, list_gt.items, &[_]i32{ 1, 0, 0, 0 });
+ {
+ var list_zero = ArrayList(i32).init(a);
+ var list_eq = ArrayList(i32).init(a);
+ var list_lt = ArrayList(i32).init(a);
+ var list_gt = ArrayList(i32).init(a);
+
+ try list_zero.appendSlice(&init);
+ try list_eq.appendSlice(&init);
+ try list_lt.appendSlice(&init);
+ try list_gt.appendSlice(&init);
+
+ try list_zero.replaceRange(1, 0, &new);
+ try list_eq.replaceRange(1, 3, &new);
+ try list_lt.replaceRange(1, 2, &new);
+
+ // after_range > new_items.len in function body
+ testing.expect(1 + 4 > new.len);
+ try list_gt.replaceRange(1, 4, &new);
+
+ testing.expectEqualSlices(i32, list_zero.items, &result_zero);
+ testing.expectEqualSlices(i32, list_eq.items, &result_eq);
+ testing.expectEqualSlices(i32, list_lt.items, &result_le);
+ testing.expectEqualSlices(i32, list_gt.items, &result_gt);
+ }
+ {
+ var list_zero = ArrayListUnmanaged(i32){};
+ var list_eq = ArrayListUnmanaged(i32){};
+ var list_lt = ArrayListUnmanaged(i32){};
+ var list_gt = ArrayListUnmanaged(i32){};
+
+ try list_zero.appendSlice(a, &init);
+ try list_eq.appendSlice(a, &init);
+ try list_lt.appendSlice(a, &init);
+ try list_gt.appendSlice(a, &init);
+
+ try list_zero.replaceRange(a, 1, 0, &new);
+ try list_eq.replaceRange(a, 1, 3, &new);
+ try list_lt.replaceRange(a, 1, 2, &new);
+
+ // after_range > new_items.len in function body
+ testing.expect(1 + 4 > new.len);
+ try list_gt.replaceRange(a, 1, 4, &new);
+
+ testing.expectEqualSlices(i32, list_zero.items, &result_zero);
+ testing.expectEqualSlices(i32, list_eq.items, &result_eq);
+ testing.expectEqualSlices(i32, list_lt.items, &result_le);
+ testing.expectEqualSlices(i32, list_gt.items, &result_gt);
+ }
}
const Item = struct {
@@ -819,11 +1032,25 @@ const Item = struct {
sub_items: ArrayList(Item),
};
-test "std.ArrayList: ArrayList(T) of struct T" {
- var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(testing.allocator) };
- defer root.sub_items.deinit();
- try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(testing.allocator) });
- testing.expect(root.sub_items.items[0].integer == 42);
+const ItemUnmanaged = struct {
+ integer: i32,
+ sub_items: ArrayListUnmanaged(ItemUnmanaged),
+};
+
+test "std.ArrayList/ArrayListUnmanaged: ArrayList(T) of struct T" {
+ const a = std.testing.allocator;
+ {
+ var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(a) };
+ defer root.sub_items.deinit();
+ try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(a) });
+ testing.expect(root.sub_items.items[0].integer == 42);
+ }
+ {
+ var root = ItemUnmanaged{ .integer = 1, .sub_items = ArrayListUnmanaged(ItemUnmanaged){} };
+ defer root.sub_items.deinit(a);
+ try root.sub_items.append(a, ItemUnmanaged{ .integer = 42, .sub_items = ArrayListUnmanaged(ItemUnmanaged){} });
+ testing.expect(root.sub_items.items[0].integer == 42);
+ }
}
test "std.ArrayList(u8) implements outStream" {
@@ -837,19 +1064,32 @@ test "std.ArrayList(u8) implements outStream" {
testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.span());
}
-test "std.ArrayList.shrink still sets length on error.OutOfMemory" {
+test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMemory" {
// use an arena allocator to make sure realloc returns error.OutOfMemory
var arena = std.heap.ArenaAllocator.init(testing.allocator);
defer arena.deinit();
+ const a = &arena.allocator;
- var list = ArrayList(i32).init(&arena.allocator);
+ {
+ var list = ArrayList(i32).init(a);
- try list.append(1);
- try list.append(2);
- try list.append(3);
+ try list.append(1);
+ try list.append(2);
+ try list.append(3);
- list.shrink(1);
- testing.expect(list.items.len == 1);
+ list.shrink(1);
+ testing.expect(list.items.len == 1);
+ }
+ {
+ var list = ArrayListUnmanaged(i32){};
+
+ try list.append(a, 1);
+ try list.append(a, 2);
+ try list.append(a, 3);
+
+ list.shrink(a, 1);
+ testing.expect(list.items.len == 1);
+ }
}
test "std.ArrayList.writer" {
@@ -864,7 +1104,7 @@ test "std.ArrayList.writer" {
testing.expectEqualSlices(u8, list.items, "abcdefg");
}
-test "addManyAsArray" {
+test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" {
const a = std.testing.allocator;
{
var list = ArrayList(u8).init(a);
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 7e3c75bc78..8749c7ce2d 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -1239,6 +1239,7 @@ pub const LibExeObjStep = struct {
/// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF
/// file.
link_eh_frame_hdr: bool = false,
+ link_emit_relocs: bool = false,
/// Place every function in its own section so that unused ones may be
/// safely garbage-collected during the linking phase.
@@ -2075,6 +2076,9 @@ pub const LibExeObjStep = struct {
if (self.link_eh_frame_hdr) {
try zig_args.append("--eh-frame-hdr");
}
+ if (self.link_emit_relocs) {
+ try zig_args.append("--emit-relocs");
+ }
if (self.link_function_sections) {
try zig_args.append("-ffunction-sections");
}
@@ -2168,8 +2172,8 @@ pub const LibExeObjStep = struct {
}
if (self.linker_script) |linker_script| {
- zig_args.append("--linker-script") catch unreachable;
- zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable;
+ try zig_args.append("--script");
+ try zig_args.append(builder.pathFromRoot(linker_script));
}
if (self.version_script) |version_script| {
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 52b8f641cd..92fa78bc39 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -262,6 +262,7 @@ pub const TypeInfo = union(enum) {
field_type: type,
default_value: anytype,
is_comptime: bool,
+ alignment: comptime_int,
};
/// This data structure is used by the Zig language code generation and
@@ -318,6 +319,7 @@ pub const TypeInfo = union(enum) {
pub const UnionField = struct {
name: []const u8,
field_type: type,
+ alignment: comptime_int,
};
/// This data structure is used by the Zig language code generation and
@@ -341,6 +343,7 @@ pub const TypeInfo = union(enum) {
/// therefore must be kept in sync with the compiler implementation.
pub const Fn = struct {
calling_convention: CallingConvention,
+ alignment: comptime_int,
is_generic: bool,
is_var_args: bool,
return_type: ?type,
diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig
index ed1ddb7d91..976690d6b7 100644
--- a/lib/std/c/darwin.zig
+++ b/lib/std/c/darwin.zig
@@ -12,7 +12,7 @@ usingnamespace @import("../os/bits.zig");
extern "c" fn __error() *c_int;
pub extern "c" fn NSVersionOfRunTimeLibrary(library_name: [*:0]const u8) u32;
-pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int;
+pub extern "c" fn _NSGetExecutablePath(buf: [*:0]u8, bufsize: *u32) c_int;
pub extern "c" fn _dyld_image_count() u32;
pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header;
pub extern "c" fn _dyld_get_image_vmaddr_slide(image_index: u32) usize;
diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig
index fa69d51d4d..5699f7db36 100644
--- a/lib/std/crypto.zig
+++ b/lib/std/crypto.zig
@@ -4,6 +4,48 @@
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
+/// Authenticated Encryption with Associated Data
+pub const aead = struct {
+ const chacha20 = @import("crypto/chacha20.zig");
+
+ pub const Gimli = @import("crypto/gimli.zig").Aead;
+ pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
+ pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
+ pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L;
+ pub const AEGIS256 = @import("crypto/aegis.zig").AEGIS256;
+};
+
+/// Authentication (MAC) functions.
+pub const auth = struct {
+ pub const hmac = @import("crypto/hmac.zig");
+ pub const siphash = @import("crypto/siphash.zig");
+};
+
+/// Core functions, that should rarely be used directly by applications.
+pub const core = struct {
+ pub const aes = @import("crypto/aes.zig");
+ pub const Gimli = @import("crypto/gimli.zig").State;
+
+ /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations.
+ ///
+ /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees.
+ ///
+ /// Most applications may want to use AEADs instead.
+ pub const modes = @import("crypto/modes.zig");
+};
+
+/// Diffie-Hellman key exchange functions.
+pub const dh = struct {
+ pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
+};
+
+/// Elliptic-curve arithmetic.
+pub const ecc = struct {
+ pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
+ pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
+ pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
+};
+
/// Hash functions.
pub const hash = struct {
pub const Md5 = @import("crypto/md5.zig").Md5;
@@ -15,26 +57,15 @@ pub const hash = struct {
pub const Gimli = @import("crypto/gimli.zig").Hash;
};
-/// Authentication (MAC) functions.
-pub const auth = struct {
- pub const hmac = @import("crypto/hmac.zig");
- pub const siphash = @import("crypto/siphash.zig");
-};
-
-/// Authenticated Encryption with Associated Data
-pub const aead = struct {
- const chacha20 = @import("crypto/chacha20.zig");
-
- pub const Gimli = @import("crypto/gimli.zig").Aead;
- pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
- pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
- pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L;
- pub const AEGIS256 = @import("crypto/aegis.zig").AEGIS256;
+/// Key derivation functions.
+pub const kdf = struct {
+ pub const hkdf = @import("crypto/hkdf.zig");
};
/// MAC functions requiring single-use secret keys.
pub const onetimeauth = struct {
pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
+ pub const Ghash = @import("crypto/ghash.zig").Ghash;
};
/// A password hashing function derives a uniform key from low-entropy input material such as passwords.
@@ -57,31 +88,6 @@ pub const pwhash = struct {
pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2;
};
-/// Core functions, that should rarely be used directly by applications.
-pub const core = struct {
- pub const aes = @import("crypto/aes.zig");
- pub const Gimli = @import("crypto/gimli.zig").State;
-
- /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations.
- ///
- /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees.
- ///
- /// Most applications may want to use AEADs instead.
- pub const modes = @import("crypto/modes.zig");
-};
-
-/// Elliptic-curve arithmetic.
-pub const ecc = struct {
- pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
- pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
- pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
-};
-
-/// Diffie-Hellman key exchange functions.
-pub const dh = struct {
- pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
-};
-
/// Digital signature functions.
pub const sign = struct {
pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;
diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig
index 3c7e3445a2..d0ff29e896 100644
--- a/lib/std/crypto/benchmark.zig
+++ b/lib/std/crypto/benchmark.zig
@@ -57,6 +57,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64
}
const macs = [_]Crypto{
+ Crypto{ .ty = crypto.onetimeauth.Ghash, .name = "ghash" },
Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" },
Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" },
Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" },
diff --git a/lib/std/crypto/ghash.zig b/lib/std/crypto/ghash.zig
new file mode 100644
index 0000000000..6a1bf7c186
--- /dev/null
+++ b/lib/std/crypto/ghash.zig
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2020 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+//
+// Adapted from BearSSL's ctmul64 implementation originally written by Thomas Pornin <pornin@bolet.org>
+
+const std = @import("../std.zig");
+const assert = std.debug.assert;
+const math = std.math;
+const mem = std.mem;
+
+/// GHASH is a universal hash function that features multiplication
+/// by a fixed parameter within a Galois field.
+///
+/// It is not a general purpose hash function - The key must be secret, unpredictable and never reused.
+///
+/// GHASH is typically used to compute the authentication tag in the AES-GCM construction.
+pub const Ghash = struct {
+ pub const block_size: usize = 16;
+ pub const mac_length = 16;
+ pub const minimum_key_length = 16;
+
+ y0: u64 = 0,
+ y1: u64 = 0,
+ h0: u64,
+ h1: u64,
+ h2: u64,
+ h0r: u64,
+ h1r: u64,
+ h2r: u64,
+
+ hh0: u64 = undefined,
+ hh1: u64 = undefined,
+ hh2: u64 = undefined,
+ hh0r: u64 = undefined,
+ hh1r: u64 = undefined,
+ hh2r: u64 = undefined,
+
+ leftover: usize = 0,
+ buf: [block_size]u8 align(16) = undefined,
+
+ pub fn init(key: *const [minimum_key_length]u8) Ghash {
+ const h1 = mem.readIntBig(u64, key[0..8]);
+ const h0 = mem.readIntBig(u64, key[8..16]);
+ const h1r = @bitReverse(u64, h1);
+ const h0r = @bitReverse(u64, h0);
+ const h2 = h0 ^ h1;
+ const h2r = h0r ^ h1r;
+
+ if (std.builtin.mode == .ReleaseSmall) {
+ return Ghash{
+ .h0 = h0,
+ .h1 = h1,
+ .h2 = h2,
+ .h0r = h0r,
+ .h1r = h1r,
+ .h2r = h2r,
+ };
+ } else {
+ // Precompute H^2
+ var hh = Ghash{
+ .h0 = h0,
+ .h1 = h1,
+ .h2 = h2,
+ .h0r = h0r,
+ .h1r = h1r,
+ .h2r = h2r,
+ };
+ hh.update(key);
+ const hh1 = hh.y1;
+ const hh0 = hh.y0;
+ const hh1r = @bitReverse(u64, hh1);
+ const hh0r = @bitReverse(u64, hh0);
+ const hh2 = hh0 ^ hh1;
+ const hh2r = hh0r ^ hh1r;
+
+ return Ghash{
+ .h0 = h0,
+ .h1 = h1,
+ .h2 = h2,
+ .h0r = h0r,
+ .h1r = h1r,
+ .h2r = h2r,
+
+ .hh0 = hh0,
+ .hh1 = hh1,
+ .hh2 = hh2,
+ .hh0r = hh0r,
+ .hh1r = hh1r,
+ .hh2r = hh2r,
+ };
+ }
+ }
+
+ inline fn clmul_pclmul(x: u64, y: u64) u64 {
+ const Vector = std.meta.Vector;
+ const product = asm (
+ \\ vpclmulqdq $0x00, %[x], %[y], %[out]
+ : [out] "=x" (-> Vector(2, u64))
+ : [x] "x" (@bitCast(Vector(2, u64), @as(u128, x))),
+ [y] "x" (@bitCast(Vector(2, u64), @as(u128, y)))
+ );
+ return product[0];
+ }
+
+ fn clmul_soft(x: u64, y: u64) u64 {
+ const x0 = x & 0x1111111111111111;
+ const x1 = x & 0x2222222222222222;
+ const x2 = x & 0x4444444444444444;
+ const x3 = x & 0x8888888888888888;
+ const y0 = y & 0x1111111111111111;
+ const y1 = y & 0x2222222222222222;
+ const y2 = y & 0x4444444444444444;
+ const y3 = y & 0x8888888888888888;
+ var z0 = (x0 *% y0) ^ (x1 *% y3) ^ (x2 *% y2) ^ (x3 *% y1);
+ var z1 = (x0 *% y1) ^ (x1 *% y0) ^ (x2 *% y3) ^ (x3 *% y2);
+ var z2 = (x0 *% y2) ^ (x1 *% y1) ^ (x2 *% y0) ^ (x3 *% y3);
+ var z3 = (x0 *% y3) ^ (x1 *% y2) ^ (x2 *% y1) ^ (x3 *% y0);
+ z0 &= 0x1111111111111111;
+ z1 &= 0x2222222222222222;
+ z2 &= 0x4444444444444444;
+ z3 &= 0x8888888888888888;
+ return z0 | z1 | z2 | z3;
+ }
+
+ const has_pclmul = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .pclmul);
+ const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx);
+ const clmul = if (std.Target.current.cpu.arch == .x86_64 and has_pclmul and has_avx) clmul_pclmul else clmul_soft;
+
+ fn blocks(st: *Ghash, msg: []const u8) void {
+ assert(msg.len % 16 == 0); // GHASH blocks() expects full blocks
+ var y1 = st.y1;
+ var y0 = st.y0;
+
+ var i: usize = 0;
+
+ // 2-blocks aggregated reduction
+ if (std.builtin.mode != .ReleaseSmall) {
+ while (i + 32 <= msg.len) : (i += 32) {
+ // B0 * H^2 unreduced
+ y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
+ y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
+
+ const y1r = @bitReverse(u64, y1);
+ const y0r = @bitReverse(u64, y0);
+ const y2 = y0 ^ y1;
+ const y2r = y0r ^ y1r;
+
+ var z0 = clmul(y0, st.hh0);
+ var z1 = clmul(y1, st.hh1);
+ var z2 = clmul(y2, st.hh2) ^ z0 ^ z1;
+ var z0h = clmul(y0r, st.hh0r);
+ var z1h = clmul(y1r, st.hh1r);
+ var z2h = clmul(y2r, st.hh2r) ^ z0h ^ z1h;
+
+ // B1 * H unreduced
+ const sy1 = mem.readIntBig(u64, msg[i..][16..24]);
+ const sy0 = mem.readIntBig(u64, msg[i..][24..32]);
+
+ const sy1r = @bitReverse(u64, sy1);
+ const sy0r = @bitReverse(u64, sy0);
+ const sy2 = sy0 ^ sy1;
+ const sy2r = sy0r ^ sy1r;
+
+ const sz0 = clmul(sy0, st.h0);
+ const sz1 = clmul(sy1, st.h1);
+ const sz2 = clmul(sy2, st.h2) ^ sz0 ^ sz1;
+ const sz0h = clmul(sy0r, st.h0r);
+ const sz1h = clmul(sy1r, st.h1r);
+ const sz2h = clmul(sy2r, st.h2r) ^ sz0h ^ sz1h;
+
+ // ((B0 * H^2) + B1 * H) (mod M)
+ z0 ^= sz0;
+ z1 ^= sz1;
+ z2 ^= sz2;
+ z0h ^= sz0h;
+ z1h ^= sz1h;
+ z2h ^= sz2h;
+ z0h = @bitReverse(u64, z0h) >> 1;
+ z1h = @bitReverse(u64, z1h) >> 1;
+ z2h = @bitReverse(u64, z2h) >> 1;
+
+ var v3 = z1h;
+ var v2 = z1 ^ z2h;
+ var v1 = z0h ^ z2;
+ var v0 = z0;
+
+ v3 = (v3 << 1) | (v2 >> 63);
+ v2 = (v2 << 1) | (v1 >> 63);
+ v1 = (v1 << 1) | (v0 >> 63);
+ v0 = (v0 << 1);
+
+ v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
+ v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
+ y1 = v3 ^ v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
+ y0 = v2 ^ (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
+ }
+ }
+
+ // single block
+ while (i + 16 <= msg.len) : (i += 16) {
+ y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
+ y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
+
+ const y1r = @bitReverse(u64, y1);
+ const y0r = @bitReverse(u64, y0);
+ const y2 = y0 ^ y1;
+ const y2r = y0r ^ y1r;
+
+ const z0 = clmul(y0, st.h0);
+ const z1 = clmul(y1, st.h1);
+ var z2 = clmul(y2, st.h2) ^ z0 ^ z1;
+ var z0h = clmul(y0r, st.h0r);
+ var z1h = clmul(y1r, st.h1r);
+ var z2h = clmul(y2r, st.h2r) ^ z0h ^ z1h;
+ z0h = @bitReverse(u64, z0h) >> 1;
+ z1h = @bitReverse(u64, z1h) >> 1;
+ z2h = @bitReverse(u64, z2h) >> 1;
+
+ // shift & reduce
+ var v3 = z1h;
+ var v2 = z1 ^ z2h;
+ var v1 = z0h ^ z2;
+ var v0 = z0;
+
+ v3 = (v3 << 1) | (v2 >> 63);
+ v2 = (v2 << 1) | (v1 >> 63);
+ v1 = (v1 << 1) | (v0 >> 63);
+ v0 = (v0 << 1);
+
+ v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
+ v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
+ y1 = v3 ^ v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
+ y0 = v2 ^ (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
+ }
+ st.y1 = y1;
+ st.y0 = y0;
+ }
+
+ pub fn update(st: *Ghash, m: []const u8) void {
+ var mb = m;
+
+ if (st.leftover > 0) {
+ const want = math.min(block_size - st.leftover, mb.len);
+ const mc = mb[0..want];
+ for (mc) |x, i| {
+ st.buf[st.leftover + i] = x;
+ }
+ mb = mb[want..];
+ st.leftover += want;
+ if (st.leftover > block_size) {
+ return;
+ }
+ st.blocks(&st.buf);
+ st.leftover = 0;
+ }
+ if (mb.len >= block_size) {
+ const want = mb.len & ~(block_size - 1);
+ st.blocks(mb[0..want]);
+ mb = mb[want..];
+ }
+ if (mb.len > 0) {
+ for (mb) |x, i| {
+ st.buf[st.leftover + i] = x;
+ }
+ st.leftover += mb.len;
+ }
+ }
+
+ pub fn final(st: *Ghash, out: *[mac_length]u8) void {
+ if (st.leftover > 0) {
+ var i = st.leftover;
+ while (i < block_size) : (i += 1) {
+ st.buf[i] = 0;
+ }
+ st.blocks(&st.buf);
+ }
+ mem.writeIntBig(u64, out[0..8], st.y1);
+ mem.writeIntBig(u64, out[8..16], st.y0);
+
+ mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Ghash)]);
+ }
+
+ pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [minimum_key_length]u8) void {
+ var st = Ghash.init(key);
+ st.update(msg);
+ st.final(out);
+ }
+};
+
+const htest = @import("test.zig");
+
+test "ghash" {
+ const key = [_]u8{0x42} ** 16;
+ const m = [_]u8{0x69} ** 256;
+
+ var st = Ghash.init(&key);
+ st.update(&m);
+ var out: [16]u8 = undefined;
+ st.final(&out);
+ htest.assertEqual("889295fa746e8b174bf4ec80a65dea41", &out);
+
+ st = Ghash.init(&key);
+ st.update(m[0..100]);
+ st.update(m[100..]);
+ st.final(&out);
+ htest.assertEqual("889295fa746e8b174bf4ec80a65dea41", &out);
+}
diff --git a/lib/std/crypto/hkdf.zig b/lib/std/crypto/hkdf.zig
new file mode 100644
index 0000000000..7ac3603637
--- /dev/null
+++ b/lib/std/crypto/hkdf.zig
@@ -0,0 +1,66 @@
+const std = @import("../std.zig");
+const assert = std.debug.assert;
+const hmac = std.crypto.auth.hmac;
+const mem = std.mem;
+
+/// HKDF-SHA256
+pub const HkdfSha256 = Hkdf(hmac.sha2.HmacSha256);
+
+/// HKDF-SHA512
+pub const HkdfSha512 = Hkdf(hmac.sha2.HmacSha512);
+
+/// The Hkdf construction takes some source of initial keying material and
+/// derives one or more uniform keys from it.
+pub fn Hkdf(comptime Hmac: type) type {
+ return struct {
+ /// Return a master key from a salt and initial keying material.
+ fn extract(salt: []const u8, ikm: []const u8) [Hmac.mac_length]u8 {
+ var prk: [Hmac.mac_length]u8 = undefined;
+ Hmac.create(&prk, ikm, salt);
+ return prk;
+ }
+
+ /// Derive a subkey from a master key `prk` and a subkey description `ctx`.
+ fn expand(out: []u8, ctx: []const u8, prk: [Hmac.mac_length]u8) void {
+ assert(out.len < Hmac.mac_length * 255); // output size is too large for the Hkdf construction
+ var i: usize = 0;
+ var counter = [1]u8{1};
+ while (i + Hmac.mac_length <= out.len) : (i += Hmac.mac_length) {
+ var st = Hmac.init(&prk);
+ if (i != 0) {
+ st.update(out[i - Hmac.mac_length ..][0..Hmac.mac_length]);
+ }
+ st.update(ctx);
+ st.update(&counter);
+ st.final(out[i..][0..Hmac.mac_length]);
+ counter[0] += 1;
+ }
+ const left = out.len % Hmac.mac_length;
+ if (left > 0) {
+ var st = Hmac.init(&prk);
+ if (i != 0) {
+ st.update(out[i - Hmac.mac_length ..][0..Hmac.mac_length]);
+ }
+ st.update(ctx);
+ st.update(&counter);
+ var tmp: [Hmac.mac_length]u8 = undefined;
+ st.final(tmp[0..Hmac.mac_length]);
+ mem.copy(u8, out[i..][0..left], tmp[0..left]);
+ }
+ }
+ };
+}
+
+const htest = @import("test.zig");
+
+test "Hkdf" {
+ const ikm = [_]u8{0x0b} ** 22;
+ const salt = [_]u8{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c };
+ const context = [_]u8{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 };
+ const kdf = HkdfSha256;
+ const prk = kdf.extract(&salt, &ikm);
+ htest.assertEqual("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5", &prk);
+ var out: [42]u8 = undefined;
+ kdf.expand(&out, &context, prk);
+ htest.assertEqual("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865", &out);
+}
diff --git a/lib/std/crypto/poly1305.zig b/lib/std/crypto/poly1305.zig
index a95b9d7cb3..31d1d6ba5a 100644
--- a/lib/std/crypto/poly1305.zig
+++ b/lib/std/crypto/poly1305.zig
@@ -22,8 +22,7 @@ pub const Poly1305 = struct {
// partial block buffer
buf: [block_size]u8 align(16) = undefined,
- pub fn init(key: []const u8) Poly1305 {
- std.debug.assert(key.len >= minimum_key_length);
+ pub fn init(key: *const [minimum_key_length]u8) Poly1305 {
const t0 = mem.readIntLittle(u64, key[0..8]);
const t1 = mem.readIntLittle(u64, key[8..16]);
return Poly1305{
@@ -115,8 +114,7 @@ pub const Poly1305 = struct {
}
}
- pub fn final(st: *Poly1305, out: []u8) void {
- std.debug.assert(out.len >= mac_length);
+ pub fn final(st: *Poly1305, out: *[mac_length]u8) void {
if (st.leftover > 0) {
var i = st.leftover;
st.buf[i] = 1;
@@ -187,10 +185,7 @@ pub const Poly1305 = struct {
std.mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Poly1305)]);
}
- pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
- std.debug.assert(out.len >= mac_length);
- std.debug.assert(key.len >= minimum_key_length);
-
+ pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [minimum_key_length]u8) void {
var st = Poly1305.init(key);
st.update(msg);
st.final(out);
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index 56a1aba217..ab2cc1577d 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -1181,6 +1181,16 @@ fn bufPrintIntToSlice(buf: []u8, value: anytype, base: u8, uppercase: bool, opti
return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
}
+pub fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args)]u8 {
+ comptime var buf: [count(fmt, args)]u8 = undefined;
+ _ = bufPrint(&buf, fmt, args) catch unreachable;
+ return &buf;
+}
+
+test "comptimePrint" {
+ std.testing.expectEqualSlices(u8, "100", comptime comptimePrint("{}", .{100}));
+}
+
test "parse u64 digit too big" {
_ = parseUnsigned(u64, "123a", 10) catch |err| {
if (err == error.InvalidCharacter) return;
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index 1890d7e136..1d98c03c5c 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -2162,7 +2162,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags);
}
-pub const SelfExePathError = os.ReadLinkError || os.SysCtlError;
+pub const SelfExePathError = os.ReadLinkError || os.SysCtlError || os.RealPathError;
/// `selfExePath` except allocates the result on the heap.
/// Caller owns returned memory.
@@ -2190,10 +2190,18 @@ pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 {
/// TODO make the return type of this a null terminated pointer
pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
if (is_darwin) {
- var u32_len: u32 = @intCast(u32, math.min(out_buffer.len, math.maxInt(u32)));
- const rc = std.c._NSGetExecutablePath(out_buffer.ptr, &u32_len);
+ // Note that _NSGetExecutablePath() will return "a path" to
+ // the executable not a "real path" to the executable.
+ var symlink_path_buf: [MAX_PATH_BYTES:0]u8 = undefined;
+ var u32_len: u32 = MAX_PATH_BYTES + 1; // include the sentinel
+ const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &u32_len);
if (rc != 0) return error.NameTooLong;
- return mem.spanZ(@ptrCast([*:0]u8, out_buffer));
+
+ var real_path_buf: [MAX_PATH_BYTES]u8 = undefined;
+ const real_path = try std.os.realpathZ(&symlink_path_buf, &real_path_buf);
+ if (real_path.len > out_buffer.len) return error.NameTooLong;
+ std.mem.copy(u8, out_buffer, real_path);
+ return out_buffer[0..real_path.len];
}
switch (builtin.os.tag) {
.linux => return os.readlinkZ("/proc/self/exe", out_buffer),
diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig
index 19f6d0809e..207d76af67 100644
--- a/lib/std/math/big/int.zig
+++ b/lib/std/math/big/int.zig
@@ -58,6 +58,11 @@ pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize {
return (string_len + (limb_bits / base - 1)) / (limb_bits / base);
}
+pub fn calcPowLimbsBufferLen(a_bit_count: usize, y: usize) usize {
+ // The 1 accounts for the multiplication carry
+ return 1 + (a_bit_count * y + (limb_bits - 1)) / limb_bits;
+}
+
/// a + b * c + *carry, sets carry to the overflow bits
pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
@setRuntimeSafety(debug_safety);
@@ -597,6 +602,52 @@ pub const Mutable = struct {
return gcdLehmer(rma, x_copy, y_copy, limbs_buffer);
}
+ /// q = a ^ b
+ ///
+ /// r may not alias a.
+ ///
+ /// Asserts that `r` has enough limbs to store the result. Upper bound is
+ /// `calcPowLimbsBufferLen(a.bitCountAbs(), b)`.
+ ///
+ /// `limbs_buffer` is used for temporary storage.
+ /// The amount required is given by `calcPowLimbsBufferLen`.
+ pub fn pow(r: *Mutable, a: Const, b: u32, limbs_buffer: []Limb) !void {
+ assert(r.limbs.ptr != a.limbs.ptr); // illegal aliasing
+
+ // Handle all the trivial cases first
+ switch (b) {
+ 0 => {
+ // a^0 = 1
+ return r.set(1);
+ },
+ 1 => {
+ // a^1 = a
+ return r.copy(a);
+ },
+ else => {},
+ }
+
+ if (a.eqZero()) {
+ // 0^b = 0
+ return r.set(0);
+ } else if (a.limbs.len == 1 and a.limbs[0] == 1) {
+ // 1^b = 1 and -1^b = ±1
+ r.set(1);
+ r.positive = a.positive or (b & 1) == 0;
+ return;
+ }
+
+ // Here a>1 and b>1
+ const needed_limbs = calcPowLimbsBufferLen(a.bitCountAbs(), b);
+ assert(r.limbs.len >= needed_limbs);
+ assert(limbs_buffer.len >= needed_limbs);
+
+ llpow(r.limbs, a.limbs, b, limbs_buffer);
+
+ r.normalize(needed_limbs);
+ r.positive = a.positive or (b & 1) == 0;
+ }
+
/// rma may not alias x or y.
/// x and y may alias each other.
/// Asserts that `rma` has enough limbs to store the result. Upper bound is given by `calcGcdNoAliasLimbLen`.
@@ -1775,6 +1826,29 @@ pub const Managed = struct {
try m.gcd(x.toConst(), y.toConst(), &limbs_buffer);
rma.setMetadata(m.positive, m.len);
}
+
+ pub fn pow(rma: *Managed, a: Managed, b: u32) !void {
+ const needed_limbs = calcPowLimbsBufferLen(a.bitCountAbs(), b);
+
+ const limbs_buffer = try rma.allocator.alloc(Limb, needed_limbs);
+ defer rma.allocator.free(limbs_buffer);
+
+ if (rma.limbs.ptr == a.limbs.ptr) {
+ var m = try Managed.initCapacity(rma.allocator, needed_limbs);
+ errdefer m.deinit();
+ var m_mut = m.toMutable();
+ try m_mut.pow(a.toConst(), b, limbs_buffer);
+ m.setMetadata(m_mut.positive, m_mut.len);
+
+ rma.deinit();
+ rma.swap(&m);
+ } else {
+ try rma.ensureCapacity(needed_limbs);
+ var rma_mut = rma.toMutable();
+ try rma_mut.pow(a.toConst(), b, limbs_buffer);
+ rma.setMetadata(rma_mut.positive, rma_mut.len);
+ }
+ }
};
/// Knuth 4.3.1, Algorithm M.
@@ -2129,6 +2203,52 @@ fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void {
}
}
+/// Knuth 4.6.3
+fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void {
+ mem.copy(Limb, r, a);
+ mem.set(Limb, r[a.len..], 0);
+
+ // Multiplication requires no aliasing between the operand and the result
+ // variable, use the output limbs and another temporary set to overcome this
+ // limit.
+ // Note that the order is important in the code below.
+ var list = [_][]Limb{ r, tmp_limbs };
+ var index: usize = 0;
+
+ // Scan the exponent as a binary number, from left to right, dropping the
+ // most significant bit set
+ var exp = @bitReverse(u32, b) >> (1 + @intCast(u5, @clz(u32, b)));
+ while (exp != 0) : (exp >>= 1) {
+ // Square
+ {
+ const cur_buf = list[index];
+ const cur_buf_len = llnormalize(cur_buf);
+ const cur_buf_out = list[index ^ 1];
+
+ mem.set(Limb, cur_buf_out, 0);
+ llmulacc(null, cur_buf_out, cur_buf[0..cur_buf_len], cur_buf[0..cur_buf_len]);
+
+ index ^= 1;
+ }
+
+ if ((exp & 1) != 0) {
+ // Multiply
+ const cur_buf = list[index];
+ const cur_buf_len = llnormalize(cur_buf);
+ const cur_buf_out = list[index ^ 1];
+
+ mem.set(Limb, cur_buf_out, 0);
+ llmulacc(null, cur_buf_out, cur_buf, a);
+
+ index ^= 1;
+ }
+ }
+
+ if (index != 0) {
+ mem.copy(Limb, r, tmp_limbs);
+ }
+}
+
// Storage must live for the lifetime of the returned value
fn fixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Mutable {
assert(storage.len >= 2);
diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig
index 9de93e94ac..85c0ff3875 100644
--- a/lib/std/math/big/int_test.zig
+++ b/lib/std/math/big/int_test.zig
@@ -1480,3 +1480,48 @@ test "big.int const to managed" {
testing.expect(a.toConst().eq(b.toConst()));
}
+
+test "big.int pow" {
+ {
+ var a = try Managed.initSet(testing.allocator, 10);
+ defer a.deinit();
+
+ var y = try Managed.init(testing.allocator);
+ defer y.deinit();
+
+ // y and a are not aliased
+ try y.pow(a, 123);
+ // y and a are aliased
+ try a.pow(a, 123);
+
+ testing.expect(a.eq(y));
+
+ const ys = try y.toString(testing.allocator, 16, false);
+ defer testing.allocator.free(ys);
+ testing.expectEqualSlices(
+ u8,
+ "183425a5f872f126e00a5ad62c839075cd6846c6fb0230887c7ad7a9dc530fcb" ++
+ "4933f60e8000000000000000000000000000000",
+ ys,
+ );
+ }
+ // Special cases
+ {
+ var a = try Managed.initSet(testing.allocator, 0);
+ defer a.deinit();
+
+ try a.pow(a, 100);
+ testing.expectEqual(@as(i32, 0), try a.to(i32));
+
+ try a.set(1);
+ try a.pow(a, 0);
+ testing.expectEqual(@as(i32, 1), try a.to(i32));
+ try a.pow(a, 100);
+ testing.expectEqual(@as(i32, 1), try a.to(i32));
+ try a.set(-1);
+ try a.pow(a, 15);
+ testing.expectEqual(@as(i32, -1), try a.to(i32));
+ try a.pow(a, 16);
+ testing.expectEqual(@as(i32, 1), try a.to(i32));
+ }
+}
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index 492e497ff4..79b0424e96 100644
--- a/lib/std/meta.zig
+++ b/lib/std/meta.zig
@@ -854,6 +854,7 @@ pub fn ArgsTuple(comptime Function: type) type {
.field_type = arg.arg_type.?,
.default_value = @as(?(arg.arg_type.?), null),
.is_comptime = false,
+ .alignment = @alignOf(arg.arg_type.?),
};
}
@@ -884,6 +885,7 @@ pub fn Tuple(comptime types: []const type) type {
.field_type = T,
.default_value = @as(?T, null),
.is_comptime = false,
+ .alignment = @alignOf(T),
};
}
diff --git a/lib/std/meta/trailer_flags.zig b/lib/std/meta/trailer_flags.zig
index c8c1323686..6cd8dc9357 100644
--- a/lib/std/meta/trailer_flags.zig
+++ b/lib/std/meta/trailer_flags.zig
@@ -47,6 +47,7 @@ pub fn TrailerFlags(comptime Fields: type) type {
@as(?struct_field.field_type, null),
),
.is_comptime = false,
+ .alignment = @alignOf(?struct_field.field_type),
};
}
break :blk @Type(.{
diff --git a/lib/std/os.zig b/lib/std/os.zig
index c06ce4ed00..ef342edf56 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -3993,7 +3993,7 @@ pub const RealPathError = error{
/// Expands all symbolic links and resolves references to `.`, `..`, and
/// extra `/` characters in `pathname`.
/// The return value is a slice of `out_buffer`, but not necessarily from the beginning.
-/// See also `realpathC` and `realpathW`.
+/// See also `realpathZ` and `realpathW`.
pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
if (builtin.os.tag == .windows) {
const pathname_w = try windows.sliceToPrefixedFileW(pathname);
diff --git a/lib/std/packed_int_array.zig b/lib/std/packed_int_array.zig
index de99afa303..f25ff0b1b8 100644
--- a/lib/std/packed_int_array.zig
+++ b/lib/std/packed_int_array.zig
@@ -318,9 +318,12 @@ pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: builtin.Endian)
};
}
+const we_are_testing_this_with_stage1_which_leaks_comptime_memory = true;
+
test "PackedIntArray" {
// TODO @setEvalBranchQuota generates panics in wasm32. Investigate.
if (builtin.arch == .wasm32) return error.SkipZigTest;
+ if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
@setEvalBranchQuota(10000);
const max_bits = 256;
@@ -358,6 +361,7 @@ test "PackedIntArray" {
}
test "PackedIntArray init" {
+ if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
const PackedArray = PackedIntArray(u3, 8);
var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 });
var i = @as(usize, 0);
@@ -367,6 +371,7 @@ test "PackedIntArray init" {
test "PackedIntSlice" {
// TODO @setEvalBranchQuota generates panics in wasm32. Investigate.
if (builtin.arch == .wasm32) return error.SkipZigTest;
+ if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
@setEvalBranchQuota(10000);
const max_bits = 256;
@@ -405,6 +410,7 @@ test "PackedIntSlice" {
}
test "PackedIntSlice of PackedInt(Array/Slice)" {
+ if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
const max_bits = 16;
const int_count = 19;
@@ -470,6 +476,7 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
}
test "PackedIntSlice accumulating bit offsets" {
+ if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
//bit_offset is u3, so standard debugging asserts should catch
// anything
{
@@ -497,6 +504,8 @@ test "PackedIntSlice accumulating bit offsets" {
//@NOTE: As I do not have a big endian system to test this on,
// big endian values were not tested
test "PackedInt(Array/Slice) sliceCast" {
+ if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
+
const PackedArray = PackedIntArray(u1, 16);
var packed_array = PackedArray.init([_]u1{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 });
const packed_slice_cast_2 = packed_array.sliceCast(u2);
@@ -537,6 +546,8 @@ test "PackedInt(Array/Slice) sliceCast" {
}
test "PackedInt(Array/Slice)Endian" {
+ if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
+
{
const PackedArrayBe = PackedIntArrayEndian(u4, .Big, 8);
var packed_array_be = PackedArrayBe.init([_]u4{ 0, 1, 2, 3, 4, 5, 6, 7 });
@@ -604,6 +615,8 @@ test "PackedInt(Array/Slice)Endian" {
// after this one is not mapped and will cause a segfault if we
// don't account for the bounds.
test "PackedIntArray at end of available memory" {
+ if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
+
switch (builtin.os.tag) {
.linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
else => return,
@@ -623,6 +636,8 @@ test "PackedIntArray at end of available memory" {
}
test "PackedIntSlice at end of available memory" {
+ if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
+
switch (builtin.os.tag) {
.linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
else => return,