| ... | ... | @@ -299,16 +299,37 @@ fn fetchAndUnpack( |
| 299 | 299 | // Check if the expected_hash is already present in the global package |
| 300 | 300 | // cache, and thereby avoid both fetching and unpacking. |
| 301 | 301 | if (expected_hash) |h| cached: { |
| 302 | | if (h.len != 2 * Hash.digest_length) { |
| 302 | const hex_multihash_len = 2 * multihash_len; |
| 303 | if (h.len >= 2) { |
| 304 | const their_multihash_func = std.fmt.parseInt(u8, h[0..2], 16) catch |err| { |
| 305 | return reportError( |
| 306 | ini, |
| 307 | comp_directory, |
| 308 | h.ptr, |
| 309 | "invalid multihash value: unable to parse hash function: {s}", |
| 310 | .{@errorName(err)}, |
| 311 | ); |
| 312 | }; |
| 313 | if (@intToEnum(MultihashFunction, their_multihash_func) != multihash_function) { |
| 314 | return reportError( |
| 315 | ini, |
| 316 | comp_directory, |
| 317 | h.ptr, |
| 318 | "unsupported hash function: only sha2-256 is supported", |
| 319 | .{}, |
| 320 | ); |
| 321 | } |
| 322 | } |
| 323 | if (h.len != hex_multihash_len) { |
| 303 | 324 | return reportError( |
| 304 | 325 | ini, |
| 305 | 326 | comp_directory, |
| 306 | 327 | h.ptr, |
| 307 | 328 | "wrong hash size. expected: {d}, found: {d}", |
| 308 | | .{ Hash.digest_length, h.len }, |
| 329 | .{ hex_multihash_len, h.len }, |
| 309 | 330 | ); |
| 310 | 331 | } |
| 311 | | const hex_digest = h[0 .. 2 * Hash.digest_length]; |
| 332 | const hex_digest = h[0..hex_multihash_len]; |
| 312 | 333 | const pkg_dir_sub_path = "p" ++ s ++ hex_digest; |
| 313 | 334 | var pkg_dir = global_cache_directory.handle.openDir(pkg_dir_sub_path, .{}) catch |err| switch (err) { |
| 314 | 335 | error.FileNotFound => break :cached, |
| ... | ... | @@ -397,8 +418,8 @@ fn fetchAndUnpack( |
| 397 | 418 | const pkg_dir_sub_path = "p" ++ s ++ hexDigest(actual_hash); |
| 398 | 419 | try renameTmpIntoCache(global_cache_directory.handle, tmp_dir_sub_path, pkg_dir_sub_path); |
| 399 | 420 | |
| 421 | const actual_hex = hexDigest(actual_hash); |
| 400 | 422 | if (expected_hash) |h| { |
| 401 | | const actual_hex = hexDigest(actual_hash); |
| 402 | 423 | if (!mem.eql(u8, h, &actual_hex)) { |
| 403 | 424 | return reportError( |
| 404 | 425 | ini, |
| ... | ... | @@ -414,7 +435,7 @@ fn fetchAndUnpack( |
| 414 | 435 | comp_directory, |
| 415 | 436 | url.ptr, |
| 416 | 437 | "url field is missing corresponding hash field: hash={s}", |
| 417 | | .{std.fmt.fmtSliceHexLower(&actual_hash)}, |
| 438 | .{&actual_hex}, |
| 418 | 439 | ); |
| 419 | 440 | } |
| 420 | 441 | |
| ... | ... | @@ -592,11 +613,30 @@ test hex64 { |
| 592 | 613 | try std.testing.expectEqualStrings("[00efcdab78563412]", s); |
| 593 | 614 | } |
| 594 | 615 | |
| 595 | | fn hexDigest(digest: [Hash.digest_length]u8) [Hash.digest_length * 2]u8 { |
| 596 | | var result: [Hash.digest_length * 2]u8 = undefined; |
| 616 | const multihash_function: MultihashFunction = switch (Hash) { |
| 617 | std.crypto.hash.sha2.Sha256 => .@"sha2-256", |
| 618 | else => @compileError("unreachable"), |
| 619 | }; |
| 620 | comptime { |
| 621 | // We avoid unnecessary uleb128 code in hexDigest by asserting here the |
| 622 | // values are small enough to be contained in the one-byte encoding. |
| 623 | assert(@enumToInt(multihash_function) < 127); |
| 624 | assert(Hash.digest_length < 127); |
| 625 | } |
| 626 | const multihash_len = 1 + 1 + Hash.digest_length; |
| 627 | |
| 628 | fn hexDigest(digest: [Hash.digest_length]u8) [multihash_len * 2]u8 { |
| 629 | var result: [multihash_len * 2]u8 = undefined; |
| 630 | |
| 631 | result[0] = hex_charset[@enumToInt(multihash_function) >> 4]; |
| 632 | result[1] = hex_charset[@enumToInt(multihash_function) & 15]; |
| 633 | |
| 634 | result[2] = hex_charset[Hash.digest_length >> 4]; |
| 635 | result[3] = hex_charset[Hash.digest_length & 15]; |
| 636 | |
| 597 | 637 | for (digest) |byte, i| { |
| 598 | | result[i * 2 + 0] = hex_charset[byte >> 4]; |
| 599 | | result[i * 2 + 1] = hex_charset[byte & 15]; |
| 638 | result[4 + i * 2] = hex_charset[byte >> 4]; |
| 639 | result[5 + i * 2] = hex_charset[byte & 15]; |
| 600 | 640 | } |
| 601 | 641 | return result; |
| 602 | 642 | } |
| ... | ... | @@ -629,3 +669,21 @@ fn renameTmpIntoCache( |
| 629 | 669 | break; |
| 630 | 670 | } |
| 631 | 671 | } |
| 672 | |
| 673 | const MultihashFunction = enum(u16) { |
| 674 | identity = 0x00, |
| 675 | sha1 = 0x11, |
| 676 | @"sha2-256" = 0x12, |
| 677 | @"sha2-512" = 0x13, |
| 678 | @"sha3-512" = 0x14, |
| 679 | @"sha3-384" = 0x15, |
| 680 | @"sha3-256" = 0x16, |
| 681 | @"sha3-224" = 0x17, |
| 682 | @"sha2-384" = 0x20, |
| 683 | @"sha2-256-trunc254-padded" = 0x1012, |
| 684 | @"sha2-224" = 0x1013, |
| 685 | @"sha2-512-224" = 0x1014, |
| 686 | @"sha2-512-256" = 0x1015, |
| 687 | @"blake2b-256" = 0xb220, |
| 688 | _, |
| 689 | }; |