lib/machine/src/checkpoint/canon/digest.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const core = @import("machine_instance_core");
  2 const os = @import("os");
  3 const std = @import("std");
  4 
  5 const Sha256 = std.crypto.hash.sha2.Sha256;
  6 const page_domain = "TINYMACHINECHECKPOINTPAGE1\x00";
  7 const leaf_domain = "TINYMACHINECHECKPOINTLEAF1\x00";
  8 const node_domain = "TINYMACHINECHECKPOINTNODE1\x00";
  9 const memory_domain = "TINYMACHINECHECKPOINTMEMORY1\x00";
 10 const machine_domain = "TINYMACHINEROOT1\x00";
 11 
 12 pub const page_bytes: usize = core.layout.page_bytes;
 13 pub const page_count: usize = core.layout.ram_bytes / page_bytes;
 14 pub const tree_levels: usize = std.math.log2_int(usize, page_count);
 15 
 16 /// Computes the SHA-256 digest of one complete 4096-byte page. The call hashes
 17 /// the page domain tag before the page bytes, which keeps this digest apart
 18 /// from a digest of the same bytes taken for another purpose.
 19 pub fn page(value: *const [page_bytes]u8) os.abi.Digest {
 20     var hasher = Sha256.init(.{});
 21     hasher.update(page_domain);
 22     hasher.update(value);
 23     var output: os.abi.Digest = undefined;
 24     hasher.final(&output);
 25     return output;
 26 }
 27 
 28 /// Ties one page digest to the index of the page it came from. The call
 29 /// requires the index to be below 16,384, checked by an assertion. A caller
 30 /// holds a page digest at one position in the page tree.
 31 pub fn leaf(index: usize, page_digest: os.abi.Digest) os.abi.Digest {
 32     std.debug.assert(index < page_count);
 33     var hasher = Sha256.init(.{});
 34     hasher.update(leaf_domain);
 35     hashInteger(&hasher, @as(u32, @intCast(index)));
 36     hasher.update(&page_digest);
 37     var output: os.abi.Digest = undefined;
 38     hasher.final(&output);
 39     return output;
 40 }
 41 
 42 /// Binds one tree level to its two ordered child digests. Level zero joins two
 43 /// leaves. The call requires the level to be below 14, checked by an assertion.
 44 pub fn node(
 45     level: u8,
 46     left: os.abi.Digest,
 47     right: os.abi.Digest,
 48 ) os.abi.Digest {
 49     std.debug.assert(level < tree_levels);
 50     var hasher = Sha256.init(.{});
 51     hasher.update(node_domain);
 52     hashInteger(&hasher, level);
 53     hasher.update(&left);
 54     hasher.update(&right);
 55     var output: os.abi.Digest = undefined;
 56     hasher.final(&output);
 57     return output;
 58 }
 59 
 60 /// Binds a page tree's root digest to the fixed memory geometry, namely base
 61 /// address zero, 67,108,864 bytes, 4096-byte pages, and 16,384 pages.
 62 pub fn memory(tree_root: os.abi.Digest) os.abi.Digest {
 63     var hasher = Sha256.init(.{});
 64     hasher.update(memory_domain);
 65     hashInteger(&hasher, @as(u64, 0));
 66     hashInteger(&hasher, @as(u64, core.layout.ram_bytes));
 67     hashInteger(&hasher, @as(u32, page_bytes));
 68     hashInteger(&hasher, @as(u32, page_count));
 69     hasher.update(&tree_root);
 70     var output: os.abi.Digest = undefined;
 71     hasher.final(&output);
 72     return output;
 73 }
 74 
 75 /// Computes one machine root from a profile fingerprint digest and a state
 76 /// digest.
 77 pub fn machine(
 78     profile_digest: os.abi.Digest,
 79     state_digest: os.abi.Digest,
 80 ) os.abi.Digest {
 81     var hasher = Sha256.init(.{});
 82     hasher.update(machine_domain);
 83     hasher.update(&profile_digest);
 84     hasher.update(&state_digest);
 85     var output: os.abi.Digest = undefined;
 86     hasher.final(&output);
 87     return output;
 88 }
 89 
 90 fn hashInteger(hasher: *Sha256, value: anytype) void {
 91     var encoded: [@sizeOf(@TypeOf(value))]u8 = undefined;
 92     std.mem.writeInt(@TypeOf(value), &encoded, value, .little);
 93     hasher.update(&encoded);
 94 }
 95 
 96 comptime {
 97     std.debug.assert(std.math.isPowerOfTwo(page_count));
 98     std.debug.assert(page_count == 16_384);
 99     std.debug.assert(tree_levels == 14);
100 }