tiny.machine.checkpoint.roots.branch
Defined in checkpoint.roots.
API (19)
Actions
Public operations.
Branch.aliases: Answers whether a byte range touches the branch value itself or any of the four caller-owned regions: the index slots, the page pool, the authentication bitmap, and the digest cache.Branch.fill: Sets every byte of a range inside memory to one value, working through private pages.Branch.preparePages: Makes every distinct page index in the list private.Branch.prepareWrite: Gives the branch a private copy of every page a byte range touches.Branch.privatePageCount: Reports how many pool slots the branch has spent on private pages.Branch.read: Fills a caller's output buffer from a byte range that lies inside memory.Branch.readPage: Delivers a whole page, named by its zero-based index, into an aligned buffer the caller owns.Branch.residentBytes: Returns the branch metadata together with the authenticated-digest and private-page bytes.Branch.writablePage: Hands back a page the caller can write into directly, named by its zero-based index.Branch.write: Sends a caller's bytes into private pages over a range that lies inside memory.Capacity.derive: Derives the storage counts forpagesslots.Storage.init: Pairs each aligned private page with the index slot that names it.restore: Opens one stored manifest root for shared-page access.
Types and contracts
Public types and contracts.
Branch: Provides a mutable memory view over one stored manifest root.Capacity: Sizes the storage a branch needs for its private pages exactly.Error: Combines stored-capture failures together with branch range, capacity, and storage failures.Storage: Holds the caller-owned memory a branch uses.
Values and defaults
Public values and defaults.
Source
Source: lib/machine/src/checkpoint/roots/branch.zig
zig
const os = @import("os");const std = @import("std");const owner = @import("owner.zig");const tree = @import("tree.zig");const types = @import("types.zig");const authentication_word_bits: usize = @bitSizeOf(u64);pub const authentication_word_count: usize = (types.page_count + authentication_word_bits - 1) / authentication_word_bits;const BranchError = error{ BranchAddressOverflow, BranchOutOfBounds, BranchPageCapacityExceeded, BranchStorageMismatch,};/// Combines stored-capture failures together with branch range, capacity, and/// storage failures.pub const Error = types.Error || BranchError;/// Sizes the storage a branch needs for its private pages exactly. The byte/// counts cover one two-byte page index and one aligned 4096-byte page for/// every slot.pub const Capacity = struct { pages: u16, index_storage_bytes: u32, page_storage_bytes: u32, /// Derives the storage counts for `pages` slots. A count above 16,384 /// returns `BranchPageCapacityExceeded`. pub fn derive(pages: usize) error{BranchPageCapacityExceeded}!Capacity { if (pages > types.page_count) return error.BranchPageCapacityExceeded; const index_bytes = std.math.mul( usize, pages, @sizeOf(u16), ) catch return error.BranchPageCapacityExceeded; const page_storage_bytes = std.math.mul( usize, pages, types.page_bytes, ) catch return error.BranchPageCapacityExceeded; return .{ .pages = @intCast(pages), .index_storage_bytes = @intCast(index_bytes), .page_storage_bytes = @intCast(page_storage_bytes), }; }};pub const maximum_capacity = Capacity.derive(types.page_count) catch unreachable;/// Holds the caller-owned memory a branch uses. The page pool holds private/// writes. A bitmap of fixed size and a digest array remember which shared/// pages have been authenticated.pub const Storage = struct { capacity: Capacity, indices: []u16, pages: []align(types.page_bytes) u8, authenticated: *[authentication_word_count]u64, digests: *[types.page_count]os.abi.Digest, /// Pairs each aligned private page with the index slot that names it. The /// authentication bitmap holds 256 words of 64 bits and the digest array /// holds one digest per page, both covering all 16,384 pages. More than /// 16,384 indices returns `BranchPageCapacityExceeded`. Any other /// page-storage length returns `BranchStorageMismatch`. pub fn init( indices: []u16, pages: []align(types.page_bytes) u8, authenticated: *[authentication_word_count]u64, digests: *[types.page_count]os.abi.Digest, ) Error!Storage { const capacity = try Capacity.derive(indices.len); if (pages.len != capacity.page_storage_bytes) { return error.BranchStorageMismatch; } return .{ .capacity = capacity, .indices = indices, .pages = pages, .authenticated = authenticated, .digests = digests, }; }};/// Provides a mutable memory view over one stored manifest root. A read/// authenticates a shared page the first time that page is touched. A page is/// copied into private storage the caller supplied when a write first touches/// it. Ownership of the provider and of every storage region stays with the/// caller.pub const Branch = struct { root_storage: types.Storage, root: types.ManifestRoot, manifest: types.Manifest, storage: Storage, private_count: u16 = 0, authenticated_count: u16 = 0, /// Fills a caller's output buffer from a byte range that lies inside /// memory. A shared page is checked against its digest and the tree path /// above it the first time the branch touches it. A read consumes no pool /// slot. A range reaching past 67,108,864 bytes returns /// `BranchOutOfBounds`, and an address whose sum overflows returns /// `BranchAddressOverflow`. pub fn read( self: *@This(), address: usize, output: []u8, ) Error!void { const range = try checkedRange(address, output.len); var cursor = range.start; var output_offset: usize = 0; while (cursor < range.end) { const page_index: u16 = @intCast(cursor / types.page_bytes); const page_offset = cursor % types.page_bytes; const count = @min(types.page_bytes - page_offset, range.end - cursor); var page: [types.page_bytes]u8 align(types.page_bytes) = undefined; try self.readPage(page_index, &page); @memcpy(output[output_offset..][0..count], page[page_offset..][0..count]); cursor += count; output_offset += count; } std.debug.assert(output_offset == output.len); } /// Sends a caller's bytes into private pages over a range that lies inside /// memory. Too little pool capacity is refused before any input byte is /// written. pub fn write( self: *@This(), address: usize, input: []const u8, ) Error!void { const range = try checkedRange(address, input.len); try self.preflightPrivate(range); try self.materializeRange(range); var cursor = range.start; var input_offset: usize = 0; while (cursor < range.end) { const page_index: u16 = @intCast(cursor / types.page_bytes); const page_offset = cursor % types.page_bytes; const count = @min(types.page_bytes - page_offset, range.end - cursor); const page = self.privatePage(page_index) orelse unreachable; @memcpy(page[page_offset..][0..count], input[input_offset..][0..count]); cursor += count; input_offset += count; } std.debug.assert(input_offset == input.len); } /// Sets every byte of a range inside memory to one value, working through /// private pages. Too little pool capacity is refused before any /// destination byte is changed. pub fn fill( self: *@This(), address: usize, byte_count: usize, value: u8, ) Error!void { const range = try checkedRange(address, byte_count); try self.preflightPrivate(range); try self.materializeRange(range); var cursor = range.start; while (cursor < range.end) { const page_index: u16 = @intCast(cursor / types.page_bytes); const page_offset = cursor % types.page_bytes; const count = @min(types.page_bytes - page_offset, range.end - cursor); const page = self.privatePage(page_index) orelse unreachable; @memset(page[page_offset..][0..count], value); cursor += count; } } /// Delivers a whole page, named by its zero-based index, into an aligned /// buffer the caller owns. A private page is copied from the pool, and any /// other page is read and authenticated through the provider. An index of /// 16,384 or more returns `BranchOutOfBounds`. pub fn readPage( self: *@This(), page_index: u16, output: *align(types.page_bytes) [types.page_bytes]u8, ) Error!void { if (page_index >= types.page_count) return error.BranchOutOfBounds; if (self.privatePage(page_index)) |page| { @memcpy(output, page); return; } return self.readSharedPage(page_index, output); } /// Hands back a page the caller can write into directly, named by its /// zero-based index. The first access authenticates the shared page, copies /// it into the pool, and consumes one pool slot. A full pool returns /// `BranchPageCapacityExceeded`. pub fn writablePage( self: *@This(), page_index: u16, ) Error!*align(types.page_bytes) [types.page_bytes]u8 { if (page_index >= types.page_count) return error.BranchOutOfBounds; if (self.privatePage(page_index)) |page| return page; if (self.private_count == self.storage.capacity.pages) { return error.BranchPageCapacityExceeded; } var page: [types.page_bytes]u8 align(types.page_bytes) = undefined; try self.readSharedPage(page_index, &page); const slot = self.private_count; const destination = pageAt(self.storage.pages, slot); @memcpy(destination, &page); self.storage.indices[slot] = page_index; self.private_count += 1; return destination; } /// Makes every distinct page index in the list private. The whole list is /// sized against the pool before a single slot is taken, and an index that /// appears twice costs one slot. A caller reserves pages up front so a /// later write cannot run out of pool. pub fn preparePages(self: *@This(), pages: []const u16) Error!void { var missing: usize = 0; for (pages, 0..) |page_index, index| { if (page_index >= types.page_count) return error.BranchOutOfBounds; if (self.privatePage(page_index) != null) continue; var duplicate = false; for (pages[0..index]) |previous| { duplicate = duplicate or previous == page_index; } if (!duplicate) missing += 1; } const available = self.storage.capacity.pages - self.private_count; if (missing > available) return error.BranchPageCapacityExceeded; for (pages) |page_index| _ = try self.writablePage(page_index); } /// Gives the branch a private copy of every page a byte range touches. The /// range is sized against the pool before a single slot is taken. pub fn prepareWrite( self: *@This(), address: usize, byte_count: usize, ) Error!void { const range = try checkedRange(address, byte_count); try self.preflightPrivate(range); try self.materializeRange(range); } /// Reports how many pool slots the branch has spent on private pages. pub fn privatePageCount(self: *const @This()) u16 { return self.private_count; } /// Returns the branch metadata together with the authenticated-digest and /// private-page bytes. The total counts the branch value, the whole /// authentication bitmap, one digest for each authenticated page, and 4098 /// bytes for each private page. pub fn residentBytes(self: *const @This()) u64 { const authenticated_bytes = @as(u64, self.authenticated_count) * @sizeOf(os.abi.Digest); const private_bytes = @as(u64, self.private_count) * (types.page_bytes + @sizeOf(u16)); return @sizeOf(Branch) + @sizeOf(@TypeOf(self.storage.authenticated.*)) + authenticated_bytes + private_bytes; } /// Answers whether a byte range touches the branch value itself or any of /// the four caller-owned regions: the index slots, the page pool, the /// authentication bitmap, and the digest cache. A caller checks this to /// keep a buffer clear of everything the branch borrows. pub fn aliases(self: *const @This(), bytes: []const u8) bool { return buffersOverlap(bytes, std.mem.asBytes(self)) or buffersOverlap(bytes, std.mem.sliceAsBytes(self.storage.indices)) or buffersOverlap(bytes, self.storage.pages) or buffersOverlap(bytes, std.mem.asBytes(self.storage.authenticated)) or buffersOverlap(bytes, std.mem.asBytes(self.storage.digests)); } fn readSharedPage( self: *@This(), page_index: u16, output: *align(types.page_bytes) [types.page_bytes]u8, ) Error!void { if (self.authenticated(page_index)) { return tree.readAuthenticatedPage( self.root_storage, self.storage.digests[page_index], output, ); } const digest = try tree.readPageAt( self.root_storage, self.manifest.pages, page_index, output, ); self.storage.digests[page_index] = digest; self.markAuthenticated(page_index); } fn privatePage( self: *const @This(), page_index: u16, ) ?*align(types.page_bytes) [types.page_bytes]u8 { for (self.storage.indices[0..self.private_count], 0..) |index, slot| { if (index == page_index) return pageAt(self.storage.pages, slot); } return null; } fn preflightPrivate(self: *const @This(), range: Range) Error!void { if (range.start == range.end) return; const first = range.start / types.page_bytes; const last = (range.end - 1) / types.page_bytes; var missing: usize = 0; for (first..last + 1) |page_index| { if (self.privatePage(@intCast(page_index)) == null) missing += 1; } const available = self.storage.capacity.pages - self.private_count; if (missing > available) return error.BranchPageCapacityExceeded; } fn materializeRange(self: *@This(), range: Range) Error!void { if (range.start == range.end) return; const first = range.start / types.page_bytes; const last = (range.end - 1) / types.page_bytes; for (first..last + 1) |page_index| { _ = try self.writablePage(@intCast(page_index)); } } fn authenticated(self: *const @This(), page_index: u16) bool { const word = page_index / authentication_word_bits; const bit: u6 = @intCast(page_index % authentication_word_bits); return self.storage.authenticated[word] & (@as(u64, 1) << bit) != 0; } fn markAuthenticated(self: *@This(), page_index: u16) void { const word = page_index / authentication_word_bits; const bit: u6 = @intCast(page_index % authentication_word_bits); std.debug.assert(!self.authenticated(page_index)); self.storage.authenticated[word] |= @as(u64, 1) << bit; self.authenticated_count += 1; }};const Range = struct { start: usize, end: usize,};/// Opens one stored manifest root for shared-page access. The function/// authenticates the manifest chain and its delta relationships, leaving each/// page for the read that first touches it. The call validates the private pool/// and clears the authentication bitmap, so no page starts out trusted. The/// returned branch borrows every supplied resource.pub fn restore( root_storage: types.Storage, root: types.ManifestRoot, storage: Storage,) Error!Branch { try validateStorage(storage); const value = try owner.openShared(root_storage, root); @memset(storage.authenticated, 0); return .{ .root_storage = root_storage, .root = root, .manifest = value, .storage = storage, };}fn validateStorage(storage: Storage) Error!void { const actual = try Capacity.derive(storage.indices.len); if (!std.meta.eql(actual, storage.capacity) or storage.pages.len != storage.capacity.page_storage_bytes) { return error.BranchStorageMismatch; }}fn checkedRange(address: usize, byte_count: usize) Error!Range { const end = std.math.add(usize, address, byte_count) catch return error.BranchAddressOverflow; const ram_bytes = types.page_count * types.page_bytes; if (address > ram_bytes or end > ram_bytes) return error.BranchOutOfBounds; return .{ .start = address, .end = end };}fn pageAt( pages: []align(types.page_bytes) u8, slot: usize,) *align(types.page_bytes) [types.page_bytes]u8 { const start = slot * types.page_bytes; std.debug.assert(start + types.page_bytes <= pages.len); return @ptrCast(@alignCast(pages[start..][0..types.page_bytes]));}fn buffersOverlap(left: []const u8, right: []const u8) bool { if (left.len == 0 or right.len == 0) return false; const left_start = @intFromPtr(left.ptr); const right_start = @intFromPtr(right.ptr); const left_end = std.math.add(usize, left_start, left.len) catch return true; const right_end = std.math.add(usize, right_start, right.len) catch return true; return left_start < right_end and right_start < left_end;}test "branch capacity rejects max plus one" { try std.testing.expectEqual( @as(u16, types.page_count), maximum_capacity.pages, ); try std.testing.expectError( error.BranchPageCapacityExceeded, Capacity.derive(types.page_count + 1), );}comptime { std.debug.assert(types.page_count % authentication_word_bits == 0); std.debug.assert(types.page_count <= std.math.maxInt(u16)); std.debug.assert(authentication_word_count == 256);}Source: lib/machine/src/checkpoint/roots/root.zig:82
zig
pub const branch = @import("branch.zig");Audit
| Definitions | 20 |
|---|---|
| Public names | 20 |
| Members | 14 |
| Version | 26.7.0 |
| Revision | daab053ee433 |