authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-25 17:58:57-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-26 11:42:04-08:00
logea516f0e81d055e0d7504eff36dfde694831bec1
tree753b46f26c09e1dfc435c9d7e976b41e477bf777
parent0fc7c9f57c0042cfe6dab9deb3b5fe2f9404d744

bump package id component to 32 bits

and to make the base64 round even, bump sha256 to 200 bits (up from 192)

4 files changed, 26 insertions(+), 27 deletions(-)

build.zig.zon+1-1
...@@ -12,5 +12,5 @@...@@ -12,5 +12,5 @@
12 },12 },
13 },13 },
14 .paths = .{""},14 .paths = .{""},
15 .nonce = 0xc1ce10810000f013,15 .nonce = 0xc1ce108124179e16,
16}16}
doc/build.zig.zon.md+7-5
...@@ -22,9 +22,11 @@ Zig package namespace....@@ -22,9 +22,11 @@ Zig package namespace.
2222
23Must be a valid bare Zig identifier (don't `@` me), limited to 32 bytes.23Must be a valid bare Zig identifier (don't `@` me), limited to 32 bytes.
2424
25Together with `nonce`, this represents a globally unique package identifier.
26
25### `nonce`27### `nonce`
2628
27Together with name, this represents a globally unique package identifier. This29Together with `name`, this represents a globally unique package identifier. This
28field is auto-initialized by the toolchain when the package is first created,30field is auto-initialized by the toolchain when the package is first created,
29and then *never changes*. This allows Zig to unambiguously detect when one31and then *never changes*. This allows Zig to unambiguously detect when one
30package is an updated version of another.32package is an updated version of another.
...@@ -34,14 +36,14 @@ project is still maintained. Otherwise, the fork is *hostile*, attempting to...@@ -34,14 +36,14 @@ project is still maintained. Otherwise, the fork is *hostile*, attempting to
34take control over the original project's identity. The nonce can be regenerated36take control over the original project's identity. The nonce can be regenerated
35by deleting the field and running `zig build`.37by deleting the field and running `zig build`.
3638
37This 64-bit integer is the combination of a 16-bit id component, a 32-bit39This 64-bit integer is the combination of a 32-bit id component and a 32-bit
38checksum, and 16 bits of reserved zeroes.40checksum.
3941
40The id component within the nonce has these restrictions:42The id component within the nonce has these restrictions:
4143
42`0x0000` is reserved for legacy packages.44`0x00000000` is reserved for legacy packages.
4345
44`0xffff` is reserved to represent "naked" packages.46`0xffffffff` is reserved to represent "naked" packages.
4547
46The checksum is computed from `name` and serves to protect Zig users from48The checksum is computed from `name` and serves to protect Zig users from
47accidental id collisions.49accidental id collisions.
src/Package.zig+16-19
...@@ -11,20 +11,19 @@ pub const multihash_hex_digest_len = 2 * multihash_len;...@@ -11,20 +11,19 @@ pub const multihash_hex_digest_len = 2 * multihash_len;
11pub const MultiHashHexDigest = [multihash_hex_digest_len]u8;11pub const MultiHashHexDigest = [multihash_hex_digest_len]u8;
1212
13pub const Nonce = packed struct(u64) {13pub const Nonce = packed struct(u64) {
14 id: u16,14 id: u32,
15 reserved: u16 = 0,
16 checksum: u32,15 checksum: u32,
1716
18 pub fn generate(name: []const u8) Nonce {17 pub fn generate(name: []const u8) Nonce {
19 return .{18 return .{
20 .id = std.crypto.random.intRangeLessThan(u16, 0x0001, 0xffff),19 .id = std.crypto.random.intRangeLessThan(u32, 1, 0xffffffff),
21 .checksum = std.hash.Crc32.hash(name),20 .checksum = std.hash.Crc32.hash(name),
22 };21 };
23 }22 }
2423
25 pub fn validate(n: Nonce, name: []const u8) bool {24 pub fn validate(n: Nonce, name: []const u8) bool {
26 switch (n.id) {25 switch (n.id) {
27 0x0000, 0xffff => return false,26 0x00000000, 0xffffffff => return false,
28 else => return std.hash.Crc32.hash(name) == n.checksum,27 else => return std.hash.Crc32.hash(name) == n.checksum,
29 }28 }
30 }29 }
...@@ -54,8 +53,8 @@ pub const Hash = struct {...@@ -54,8 +53,8 @@ pub const Hash = struct {
54 pub const Algo = std.crypto.hash.sha2.Sha256;53 pub const Algo = std.crypto.hash.sha2.Sha256;
55 pub const Digest = [Algo.digest_length]u8;54 pub const Digest = [Algo.digest_length]u8;
5655
57 /// Example: "nnnn-vvvv-hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"56 /// Example: "nnnn-vvvv-hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
58 pub const max_len = 32 + 1 + 32 + 1 + (16 + 32 + 192) / 6;57 pub const max_len = 32 + 1 + 32 + 1 + (32 + 32 + 200) / 6;
5958
60 pub fn fromSlice(s: []const u8) Hash {59 pub fn fromSlice(s: []const u8) Hash {
61 assert(s.len <= max_len);60 assert(s.len <= max_len);
...@@ -96,14 +95,12 @@ pub const Hash = struct {...@@ -96,14 +95,12 @@ pub const Hash = struct {
96 /// bytes and assumed be a valid zig identifier95 /// bytes and assumed be a valid zig identifier
97 /// * semver is the version field from build.zig.zon, asserted to be at96 /// * semver is the version field from build.zig.zon, asserted to be at
98 /// most 32 bytes97 /// most 32 bytes
99 /// * hashplus is the following 39-byte array, base64 encoded using -_ to make98 /// * hashplus is the following 33-byte array, base64 encoded using -_ to make
100 /// it filesystem safe:99 /// it filesystem safe:
101 /// - (2 bytes) LE u16 Package ID100 /// - (4 bytes) LE u32 Package ID
102 /// - (4 bytes) LE u32 total decompressed size in bytes, overflow saturated101 /// - (4 bytes) LE u32 total decompressed size in bytes, overflow saturated
103 /// - (24 bytes) truncated SHA-256 digest of hashed files of the package102 /// - (25 bytes) truncated SHA-256 digest of hashed files of the package
104 ///103 pub fn init(digest: Digest, name: []const u8, ver: []const u8, id: u32, size: u32) Hash {
105 /// example: "nasm-2.16.1-3-AAD_ZlwACpGU-c3QXp_yNyn07Q5U9Rq-Cb1ur2G1"
106 pub fn init(digest: Digest, name: []const u8, ver: []const u8, id: u16, size: u32) Hash {
107 assert(name.len <= 32);104 assert(name.len <= 32);
108 assert(ver.len <= 32);105 assert(ver.len <= 32);
109 var result: Hash = undefined;106 var result: Hash = undefined;
...@@ -112,11 +109,11 @@ pub const Hash = struct {...@@ -112,11 +109,11 @@ pub const Hash = struct {
112 buf.appendAssumeCapacity('-');109 buf.appendAssumeCapacity('-');
113 buf.appendSliceAssumeCapacity(ver);110 buf.appendSliceAssumeCapacity(ver);
114 buf.appendAssumeCapacity('-');111 buf.appendAssumeCapacity('-');
115 var hashplus: [30]u8 = undefined;112 var hashplus: [33]u8 = undefined;
116 std.mem.writeInt(u16, hashplus[0..2], id, .little);113 std.mem.writeInt(u32, hashplus[0..4], id, .little);
117 std.mem.writeInt(u32, hashplus[2..6], size, .little);114 std.mem.writeInt(u32, hashplus[4..8], size, .little);
118 hashplus[6..].* = digest[0..24].*;115 hashplus[8..].* = digest[0..25].*;
119 _ = std.base64.url_safe_no_pad.Encoder.encode(buf.addManyAsArrayAssumeCapacity(40), &hashplus);116 _ = std.base64.url_safe_no_pad.Encoder.encode(buf.addManyAsArrayAssumeCapacity(44), &hashplus);
120 @memset(buf.unusedCapacitySlice(), 0);117 @memset(buf.unusedCapacitySlice(), 0);
121 return result;118 return result;
122 }119 }
...@@ -194,8 +191,8 @@ test Hash {...@@ -194,8 +191,8 @@ test Hash {
194 0xc7, 0xf5, 0x71, 0xb7, 0xb4, 0xe7, 0x6f, 0x3c, 0xdb, 0x87, 0x7a, 0x7f, 0xdd, 0xf9, 0x77, 0x87,191 0xc7, 0xf5, 0x71, 0xb7, 0xb4, 0xe7, 0x6f, 0x3c, 0xdb, 0x87, 0x7a, 0x7f, 0xdd, 0xf9, 0x77, 0x87,
195 0x9d, 0xd3, 0x86, 0xfa, 0x73, 0x57, 0x9a, 0xf7, 0x9d, 0x1e, 0xdb, 0x8f, 0x3a, 0xd9, 0xbd, 0x9f,192 0x9d, 0xd3, 0x86, 0xfa, 0x73, 0x57, 0x9a, 0xf7, 0x9d, 0x1e, 0xdb, 0x8f, 0x3a, 0xd9, 0xbd, 0x9f,
196 };193 };
197 const result: Hash = .init(example_digest, "nasm", "2.16.1-2", 0xcafe, 10 * 1024 * 1024);194 const result: Hash = .init(example_digest, "nasm", "2.16.1-3", 0xcafebabe, 10 * 1024 * 1024);
198 try std.testing.expectEqualStrings("nasm-2.16.1-2-_soAAKAAx_Vxt7Tnbzzbh3p_3fl3h53ThvpzV5r3", result.toSlice());195 try std.testing.expectEqualStrings("nasm-2.16.1-3-vrr-ygAAoADH9XG3tOdvPNuHen_d-XeHndOG-nNXmved", result.toSlice());
199}196}
200197
201test {198test {
src/Package/Manifest.zig+2-2
...@@ -36,7 +36,7 @@ pub const ErrorMessage = struct {...@@ -36,7 +36,7 @@ pub const ErrorMessage = struct {
36};36};
3737
38name: []const u8,38name: []const u8,
39id: u16,39id: u32,
40version: std.SemanticVersion,40version: std.SemanticVersion,
41version_node: Ast.Node.Index,41version_node: Ast.Node.Index,
42dependencies: std.StringArrayHashMapUnmanaged(Dependency),42dependencies: std.StringArrayHashMapUnmanaged(Dependency),
...@@ -149,7 +149,7 @@ const Parse = struct {...@@ -149,7 +149,7 @@ const Parse = struct {
149 errors: std.ArrayListUnmanaged(ErrorMessage),149 errors: std.ArrayListUnmanaged(ErrorMessage),
150150
151 name: []const u8,151 name: []const u8,
152 id: u16,152 id: u32,
153 version: std.SemanticVersion,153 version: std.SemanticVersion,
154 version_node: Ast.Node.Index,154 version_node: Ast.Node.Index,
155 dependencies: std.StringArrayHashMapUnmanaged(Dependency),155 dependencies: std.StringArrayHashMapUnmanaged(Dependency),