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 @@
1212 },
1313 },
1414 .paths = .{""},
15 .nonce = 0xc1ce10810000f013,
15 .nonce = 0xc1ce108124179e16,
1616}
doc/build.zig.zon.md+7-5
......@@ -22,9 +22,11 @@ Zig package namespace.
2222
2323Must 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
2527### `nonce`
2628
27Together with name, this represents a globally unique package identifier. This
29Together with `name`, this represents a globally unique package identifier. This
2830field is auto-initialized by the toolchain when the package is first created,
2931and then *never changes*. This allows Zig to unambiguously detect when one
3032package is an updated version of another.
......@@ -34,14 +36,14 @@ project is still maintained. Otherwise, the fork is *hostile*, attempting to
3436take control over the original project's identity. The nonce can be regenerated
3537by deleting the field and running `zig build`.
3638
37This 64-bit integer is the combination of a 16-bit id component, a 32-bit
38checksum, and 16 bits of reserved zeroes.
39This 64-bit integer is the combination of a 32-bit id component and a 32-bit
40checksum.
3941
4042The 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
4648The checksum is computed from `name` and serves to protect Zig users from
4749accidental id collisions.
src/Package.zig+16-19
......@@ -11,20 +11,19 @@ pub const multihash_hex_digest_len = 2 * multihash_len;
1111pub const MultiHashHexDigest = [multihash_hex_digest_len]u8;
1212
1313pub const Nonce = packed struct(u64) {
14 id: u16,
15 reserved: u16 = 0,
14 id: u32,
1615 checksum: u32,
1716
1817 pub fn generate(name: []const u8) Nonce {
1918 return .{
20 .id = std.crypto.random.intRangeLessThan(u16, 0x0001, 0xffff),
19 .id = std.crypto.random.intRangeLessThan(u32, 1, 0xffffffff),
2120 .checksum = std.hash.Crc32.hash(name),
2221 };
2322 }
2423
2524 pub fn validate(n: Nonce, name: []const u8) bool {
2625 switch (n.id) {
27 0x0000, 0xffff => return false,
26 0x00000000, 0xffffffff => return false,
2827 else => return std.hash.Crc32.hash(name) == n.checksum,
2928 }
3029 }
......@@ -54,8 +53,8 @@ pub const Hash = struct {
5453 pub const Algo = std.crypto.hash.sha2.Sha256;
5554 pub const Digest = [Algo.digest_length]u8;
5655
57 /// Example: "nnnn-vvvv-hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
58 pub const max_len = 32 + 1 + 32 + 1 + (16 + 32 + 192) / 6;
56 /// Example: "nnnn-vvvv-hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
57 pub const max_len = 32 + 1 + 32 + 1 + (32 + 32 + 200) / 6;
5958
6059 pub fn fromSlice(s: []const u8) Hash {
6160 assert(s.len <= max_len);
......@@ -96,14 +95,12 @@ pub const Hash = struct {
9695 /// bytes and assumed be a valid zig identifier
9796 /// * semver is the version field from build.zig.zon, asserted to be at
9897 /// most 32 bytes
99 /// * hashplus is the following 39-byte array, base64 encoded using -_ to make
98 /// * hashplus is the following 33-byte array, base64 encoded using -_ to make
10099 /// it filesystem safe:
101 /// - (2 bytes) LE u16 Package ID
100 /// - (4 bytes) LE u32 Package ID
102101 /// - (4 bytes) LE u32 total decompressed size in bytes, overflow saturated
103 /// - (24 bytes) truncated SHA-256 digest of hashed files of the package
104 ///
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 {
102 /// - (25 bytes) truncated SHA-256 digest of hashed files of the package
103 pub fn init(digest: Digest, name: []const u8, ver: []const u8, id: u32, size: u32) Hash {
107104 assert(name.len <= 32);
108105 assert(ver.len <= 32);
109106 var result: Hash = undefined;
......@@ -112,11 +109,11 @@ pub const Hash = struct {
112109 buf.appendAssumeCapacity('-');
113110 buf.appendSliceAssumeCapacity(ver);
114111 buf.appendAssumeCapacity('-');
115 var hashplus: [30]u8 = undefined;
116 std.mem.writeInt(u16, hashplus[0..2], id, .little);
117 std.mem.writeInt(u32, hashplus[2..6], size, .little);
118 hashplus[6..].* = digest[0..24].*;
119 _ = std.base64.url_safe_no_pad.Encoder.encode(buf.addManyAsArrayAssumeCapacity(40), &hashplus);
112 var hashplus: [33]u8 = undefined;
113 std.mem.writeInt(u32, hashplus[0..4], id, .little);
114 std.mem.writeInt(u32, hashplus[4..8], size, .little);
115 hashplus[8..].* = digest[0..25].*;
116 _ = std.base64.url_safe_no_pad.Encoder.encode(buf.addManyAsArrayAssumeCapacity(44), &hashplus);
120117 @memset(buf.unusedCapacitySlice(), 0);
121118 return result;
122119 }
......@@ -194,8 +191,8 @@ test Hash {
194191 0xc7, 0xf5, 0x71, 0xb7, 0xb4, 0xe7, 0x6f, 0x3c, 0xdb, 0x87, 0x7a, 0x7f, 0xdd, 0xf9, 0x77, 0x87,
195192 0x9d, 0xd3, 0x86, 0xfa, 0x73, 0x57, 0x9a, 0xf7, 0x9d, 0x1e, 0xdb, 0x8f, 0x3a, 0xd9, 0xbd, 0x9f,
196193 };
197 const result: Hash = .init(example_digest, "nasm", "2.16.1-2", 0xcafe, 10 * 1024 * 1024);
198 try std.testing.expectEqualStrings("nasm-2.16.1-2-_soAAKAAx_Vxt7Tnbzzbh3p_3fl3h53ThvpzV5r3", result.toSlice());
194 const result: Hash = .init(example_digest, "nasm", "2.16.1-3", 0xcafebabe, 10 * 1024 * 1024);
195 try std.testing.expectEqualStrings("nasm-2.16.1-3-vrr-ygAAoADH9XG3tOdvPNuHen_d-XeHndOG-nNXmved", result.toSlice());
199196}
200197
201198test {
src/Package/Manifest.zig+2-2
......@@ -36,7 +36,7 @@ pub const ErrorMessage = struct {
3636};
3737
3838name: []const u8,
39id: u16,
39id: u32,
4040version: std.SemanticVersion,
4141version_node: Ast.Node.Index,
4242dependencies: std.StringArrayHashMapUnmanaged(Dependency),
......@@ -149,7 +149,7 @@ const Parse = struct {
149149 errors: std.ArrayListUnmanaged(ErrorMessage),
150150
151151 name: []const u8,
152 id: u16,
152 id: u32,
153153 version: std.SemanticVersion,
154154 version_node: Ast.Node.Index,
155155 dependencies: std.StringArrayHashMapUnmanaged(Dependency),