Commit ea516f0e81

Andrew Kelley <andrew@ziglang.org>
2025-02-26 02:58:57
bump package id component to 32 bits
and to make the base64 round even, bump sha256 to 200 bits (up from 192)
1 parent 0fc7c9f
doc/build.zig.zon.md
@@ -22,9 +22,11 @@ Zig package namespace.
 
 Must be a valid bare Zig identifier (don't `@` me), limited to 32 bytes.
 
+Together with `nonce`, this represents a globally unique package identifier.
+
 ### `nonce`
 
-Together with name, this represents a globally unique package identifier. This
+Together with `name`, this represents a globally unique package identifier. This
 field is auto-initialized by the toolchain when the package is first created,
 and then *never changes*. This allows Zig to unambiguously detect when one
 package is an updated version of another.
@@ -34,14 +36,14 @@ project is still maintained. Otherwise, the fork is *hostile*, attempting to
 take control over the original project's identity. The nonce can be regenerated
 by deleting the field and running `zig build`.
 
-This 64-bit integer is the combination of a 16-bit id component, a 32-bit
-checksum, and 16 bits of reserved zeroes.
+This 64-bit integer is the combination of a 32-bit id component and a 32-bit
+checksum.
 
 The id component within the nonce has these restrictions:
 
-`0x0000` is reserved for legacy packages.
+`0x00000000` is reserved for legacy packages.
 
-`0xffff` is reserved to represent "naked" packages.
+`0xffffffff` is reserved to represent "naked" packages.
 
 The checksum is computed from `name` and serves to protect Zig users from
 accidental id collisions.
src/Package/Manifest.zig
@@ -36,7 +36,7 @@ pub const ErrorMessage = struct {
 };
 
 name: []const u8,
-id: u16,
+id: u32,
 version: std.SemanticVersion,
 version_node: Ast.Node.Index,
 dependencies: std.StringArrayHashMapUnmanaged(Dependency),
@@ -149,7 +149,7 @@ const Parse = struct {
     errors: std.ArrayListUnmanaged(ErrorMessage),
 
     name: []const u8,
-    id: u16,
+    id: u32,
     version: std.SemanticVersion,
     version_node: Ast.Node.Index,
     dependencies: std.StringArrayHashMapUnmanaged(Dependency),
src/Package.zig
@@ -11,20 +11,19 @@ pub const multihash_hex_digest_len = 2 * multihash_len;
 pub const MultiHashHexDigest = [multihash_hex_digest_len]u8;
 
 pub const Nonce = packed struct(u64) {
-    id: u16,
-    reserved: u16 = 0,
+    id: u32,
     checksum: u32,
 
     pub fn generate(name: []const u8) Nonce {
         return .{
-            .id = std.crypto.random.intRangeLessThan(u16, 0x0001, 0xffff),
+            .id = std.crypto.random.intRangeLessThan(u32, 1, 0xffffffff),
             .checksum = std.hash.Crc32.hash(name),
         };
     }
 
     pub fn validate(n: Nonce, name: []const u8) bool {
         switch (n.id) {
-            0x0000, 0xffff => return false,
+            0x00000000, 0xffffffff => return false,
             else => return std.hash.Crc32.hash(name) == n.checksum,
         }
     }
@@ -54,8 +53,8 @@ pub const Hash = struct {
     pub const Algo = std.crypto.hash.sha2.Sha256;
     pub const Digest = [Algo.digest_length]u8;
 
-    /// Example: "nnnn-vvvv-hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
-    pub const max_len = 32 + 1 + 32 + 1 + (16 + 32 + 192) / 6;
+    /// Example: "nnnn-vvvv-hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
+    pub const max_len = 32 + 1 + 32 + 1 + (32 + 32 + 200) / 6;
 
     pub fn fromSlice(s: []const u8) Hash {
         assert(s.len <= max_len);
@@ -96,14 +95,12 @@ pub const Hash = struct {
     ///   bytes and assumed be a valid zig identifier
     /// * semver is the version field from build.zig.zon, asserted to be at
     ///   most 32 bytes
-    /// * hashplus is the following 39-byte array, base64 encoded using -_ to make
+    /// * hashplus is the following 33-byte array, base64 encoded using -_ to make
     ///   it filesystem safe:
-    ///   - (2 bytes) LE u16 Package ID
+    ///   - (4 bytes) LE u32 Package ID
     ///   - (4 bytes) LE u32 total decompressed size in bytes, overflow saturated
-    ///   - (24 bytes) truncated SHA-256 digest of hashed files of the package
-    ///
-    /// example: "nasm-2.16.1-3-AAD_ZlwACpGU-c3QXp_yNyn07Q5U9Rq-Cb1ur2G1"
-    pub fn init(digest: Digest, name: []const u8, ver: []const u8, id: u16, size: u32) Hash {
+    ///   - (25 bytes) truncated SHA-256 digest of hashed files of the package
+    pub fn init(digest: Digest, name: []const u8, ver: []const u8, id: u32, size: u32) Hash {
         assert(name.len <= 32);
         assert(ver.len <= 32);
         var result: Hash = undefined;
@@ -112,11 +109,11 @@ pub const Hash = struct {
         buf.appendAssumeCapacity('-');
         buf.appendSliceAssumeCapacity(ver);
         buf.appendAssumeCapacity('-');
-        var hashplus: [30]u8 = undefined;
-        std.mem.writeInt(u16, hashplus[0..2], id, .little);
-        std.mem.writeInt(u32, hashplus[2..6], size, .little);
-        hashplus[6..].* = digest[0..24].*;
-        _ = std.base64.url_safe_no_pad.Encoder.encode(buf.addManyAsArrayAssumeCapacity(40), &hashplus);
+        var hashplus: [33]u8 = undefined;
+        std.mem.writeInt(u32, hashplus[0..4], id, .little);
+        std.mem.writeInt(u32, hashplus[4..8], size, .little);
+        hashplus[8..].* = digest[0..25].*;
+        _ = std.base64.url_safe_no_pad.Encoder.encode(buf.addManyAsArrayAssumeCapacity(44), &hashplus);
         @memset(buf.unusedCapacitySlice(), 0);
         return result;
     }
@@ -194,8 +191,8 @@ test Hash {
         0xc7, 0xf5, 0x71, 0xb7, 0xb4, 0xe7, 0x6f, 0x3c, 0xdb, 0x87, 0x7a, 0x7f, 0xdd, 0xf9, 0x77, 0x87,
         0x9d, 0xd3, 0x86, 0xfa, 0x73, 0x57, 0x9a, 0xf7, 0x9d, 0x1e, 0xdb, 0x8f, 0x3a, 0xd9, 0xbd, 0x9f,
     };
-    const result: Hash = .init(example_digest, "nasm", "2.16.1-2", 0xcafe, 10 * 1024 * 1024);
-    try std.testing.expectEqualStrings("nasm-2.16.1-2-_soAAKAAx_Vxt7Tnbzzbh3p_3fl3h53ThvpzV5r3", result.toSlice());
+    const result: Hash = .init(example_digest, "nasm", "2.16.1-3", 0xcafebabe, 10 * 1024 * 1024);
+    try std.testing.expectEqualStrings("nasm-2.16.1-3-vrr-ygAAoADH9XG3tOdvPNuHen_d-XeHndOG-nNXmved", result.toSlice());
 }
 
 test {
build.zig.zon
@@ -12,5 +12,5 @@
         },
     },
     .paths = .{""},
-    .nonce = 0xc1ce10810000f013,
+    .nonce = 0xc1ce108124179e16,
 }