Skip to documentation
SLOP

tiny.sql.lattice

Reference tiny.sql lattice

Defined in tiny.sql.

API (17)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callstiny.sqllattice
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallslatticeentryStatetest sourcelib.sql.src.latticetest: lattice streaming value chunks ...private sourcelib.sql.src.properties.lattice.OrderPropertypropertyprivate sourcelib.sql.src.tree.TreeentryStateFromRecordprivate sourcelib.sql.src.tree.TreeputInWriteprivate sourcelib.sql.src.treelatticeEntryFromRecordprivate sourcelib.sql.src.lattice.StatelanesFromLittleprivate sourcelib.sql.src.latticeexpandlattice.EntryHasherfinish
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callslatticeentryStatetest sourcelib.sql.src.latticetest: lattice streaming value chunks ...private sourcelib.sql.src.properties.lattice.OrderPropertypropertyprivate sourcelib.sql.src.tree.TreeentryStateFromRecordprivate sourcelib.sql.src.tree.TreeputInWriteprivate sourcelib.sql.src.treelatticeEntryFromRecordlattice.EntryHasherinit
Static calls · unresolved targets: 2 · external targets: 0.
Called byCallsNo direct callslatticeentryStatetest sourcelib.sql.src.latticetest: lattice streaming value chunks ...private sourcelib.sql.src.properties.lattice.OrderPropertypropertyprivate sourcelib.sql.src.tree.TreeentryStateFromRecordprivate sourcelib.sql.src.tree.TreeputInWriteprivate sourcelib.sql.src.treelatticeEntryFromRecordlattice.EntryHasherupdate
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.sql.src.tree.RootBuildfinishLeaflattice.Stateadd
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallstest sourcelib.sql.src.latticetest: lattice encode decode round tri...page.Identitystateprivate sourcelib.sql.src.properties.lattice.CodecPropertypropertyprivate sourcelib.sql.src.lattice.StatelanesFromLittlelattice.Statedecode
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate sourcelib.sql.src.tree.RootBuildfinishlattice.Stateencodelattice.Statedigest
Static calls · unresolved targets: 3 · external targets: 0.
Called byCallsNo direct callslattice.Statedigestlattice.Stateencode
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.sql.src.latticetest: lattice add and subtract inverttest sourcelib.sql.src.latticetest: lattice digest binds entry counttest sourcelib.sql.src.latticetest: lattice empty digest differs fr...test sourcelib.sql.src.latticetest: lattice encode decode round tri...test sourcelib.sql.src.latticetest: lattice entry digests keep thei...+8 morelattice.EntryHasherfinishlattice.EntryHasherinitlattice.EntryHasherupdatelatticeentryState
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/sql/src/lattice.zig

zig
const std = @import("std");const simd = @import("simd");const Aes128 = std.crypto.core.aes.Aes128;const Blake3 = std.crypto.hash.Blake3;const Sha256 = std.crypto.hash.sha2.Sha256;const native_endian = @import("builtin").cpu.arch.endian();pub const lane_count = 1024;pub const encoded_size = lane_count * @sizeOf(u16);pub const digest_size = Sha256.digest_length;const entry_tag = "sql.lattice.entry";const digest_tag = "sql.lattice";const Lanes = simd.ScalableTag(u16);/// Counter blocks the entry expansion builds and encrypts together.const group_blocks = 8;const block_size = 16;const group_size = group_blocks * block_size;const Words = @Vector(group_blocks, u64);comptime {    std.debug.assert(lane_count % Lanes.lane_count == 0);    std.debug.assert(encoded_size % group_size == 0);}pub const State = struct {    lanes: [lane_count]u16,    pub const empty = State{ .lanes = @splat(0) };    pub fn add(self: *State, entry: *const State) void {        simd.transform1(Lanes, &self.lanes, &entry.lanes, WrappingAdd{});    }    pub fn subtract(self: *State, entry: *const State) void {        simd.transform1(Lanes, &self.lanes, &entry.lanes, WrappingSubtract{});    }    pub fn isEmpty(self: *const State) bool {        return simd.allEqual(Lanes, &self.lanes, 0);    }    pub fn eql(self: *const State, other: *const State) bool {        return simd.equal(Lanes, &self.lanes, &other.lanes);    }    pub fn encode(self: *const State, out: *[encoded_size]u8) void {        if (native_endian == .little) {            @memcpy(out, std.mem.asBytes(&self.lanes));        } else {            for (&self.lanes, 0..) |*lane, index| {                std.mem.writeInt(u16, out[index * 2 ..][0..2], lane.*, .little);            }        }    }    pub fn decode(bytes: *const [encoded_size]u8) State {        var state: State = undefined;        @memcpy(std.mem.asBytes(&state.lanes), bytes);        state.lanesFromLittle();        return state;    }    pub fn digest(self: *const State, entries: u64) [digest_size]u8 {        var hasher = Sha256.init(.{});        hasher.update(digest_tag);        var count: [8]u8 = undefined;        std.mem.writeInt(u64, &count, entries, .big);        hasher.update(&count);        var encoded: [encoded_size]u8 = undefined;        self.encode(&encoded);        hasher.update(&encoded);        var out: [digest_size]u8 = undefined;        hasher.final(&out);        return out;    }    /// Puts lanes read from little-endian bytes in native byte order.    fn lanesFromLittle(self: *State) void {        if (native_endian == .big) std.mem.byteSwapAllElements(u16, &self.lanes);    }};const WrappingAdd = struct {    pub fn call(_: WrappingAdd, comptime D: type, lanes: D.Vector, entry: D.Vector) D.Vector {        return lanes +% entry;    }};const WrappingSubtract = struct {    pub fn call(_: WrappingSubtract, comptime D: type, lanes: D.Vector, entry: D.Vector) D.Vector {        return lanes -% entry;    }};pub const EntryHasher = struct {    hasher: Blake3,    pub fn init(entry_key: []const u8) EntryHasher {        var hasher = Blake3.init(.{});        hasher.update(entry_tag);        var length: [8]u8 = undefined;        std.mem.writeInt(u64, &length, entry_key.len, .big);        hasher.update(&length);        hasher.update(entry_key);        return .{ .hasher = hasher };    }    pub fn update(self: *EntryHasher, value_chunk: []const u8) void {        self.hasher.update(value_chunk);    }    pub fn finish(self: *const EntryHasher) State {        var digest: [32]u8 = undefined;        self.hasher.final(&digest);        var state: State = undefined;        expand(&digest, std.mem.asBytes(&state.lanes));        state.lanesFromLittle();        return state;    }};pub fn entryState(entry_key: []const u8, value: []const u8) State {    var hasher = EntryHasher.init(entry_key);    hasher.update(value);    return hasher.finish();}/// Writes the keystream that expands an entry digest into lattice lanes:/// AES-128 in counter mode over zeros, keyed by the digest's first half,/// counting from its second half read as a big-endian integer. Each group/// of counter blocks is written in place and encrypted there.fn expand(digest: *const [32]u8, out: *[encoded_size]u8) void {    const aes = Aes128.initEnc(digest[0..16].*);    var counter = std.mem.readInt(u128, digest[16..32], .big);    var offset: usize = 0;    while (offset < encoded_size) : (offset += group_size) {        const group = out[offset..][0..group_size];        writeCounters(counter, group);        aes.encryptWide(group_blocks, group, group);        counter +%= group_blocks;    }}/// Writes the big-endian counter blocks `first` through/// `first + group_blocks - 1`. Each vector lane adds its block's offset to/// the low word, and a lane whose low word wraps carries one into its high/// word, so no block formats a 128-bit integer a byte at a time.fn writeCounters(first: u128, out: *[group_size]u8) void {    const low_first: u64 = @truncate(first);    const high_first: u64 = @truncate(first >> 64);    const low = @as(Words, @splat(low_first)) +% std.simd.iota(u64, group_blocks);    const wrapped = low < @as(Words, @splat(low_first));    const carry = @select(u64, wrapped, @as(Words, @splat(1)), @as(Words, @splat(0)));    const high = @as(Words, @splat(high_first)) +% carry;    const words: [2 * group_blocks]u64 =        @shuffle(u64, bigEndian(high), bigEndian(low), high_then_low);    @memcpy(out, std.mem.asBytes(&words));}/// Shuffle mask that takes each block's high word and then its low word.const high_then_low = mask: {    var lanes: [2 * group_blocks]i32 = undefined;    for (0..group_blocks) |block| {        lanes[2 * block] = @intCast(block);        lanes[2 * block + 1] = ~@as(i32, @intCast(block));    }    break :mask lanes;};fn bigEndian(words: Words) Words {    return if (native_endian == .little) @byteSwap(words) else words;}/// Expands a digest with the standard library's counter mode, the/// construction `expand` reproduces.fn expandReference(digest: *const [32]u8, out: *[encoded_size]u8) void {    const aes = Aes128.initEnc(digest[0..16].*);    const zeros: [encoded_size]u8 = @splat(0);    std.crypto.core.modes.ctr(@TypeOf(aes), aes, out, &zeros, digest[16..32].*, .big);}test "lattice expansion matches counter mode across counter carries" {    var prng = std.Random.DefaultPrng.init(0x1a77_1ce5);    const random = prng.random();    const low_ends = [_]u64{ 0, 1, std.math.maxInt(u64) - group_blocks, std.math.maxInt(u64) };    for (0..640) |round| {        var digest: [32]u8 = undefined;        random.bytes(&digest);        if (round % 5 != 0) {            const low_end = low_ends[round % low_ends.len];            const offset = random.uintAtMost(u64, 2 * group_blocks);            std.mem.writeInt(u64, digest[24..32], low_end -% offset, .big);        }        if (round % 8 == 0) @memset(digest[16..24], 0xff);        var fresh: [encoded_size]u8 = undefined;        var expected: [encoded_size]u8 = undefined;        expand(&digest, &fresh);        expandReference(&digest, &expected);        try std.testing.expectEqualSlices(u8, &expected, &fresh);    }}test "lattice entry digests keep their persisted values" {    const alpha = entryState("alpha", "one");    const empty = entryState("", "");    const beta = entryState("beta", "two");    var pair = State.empty;    pair.add(&alpha);    pair.add(&beta);    const alpha_hex = "0fa6d7690ea57bfcb0e5c0fff010ad1d11a101560d69c9471d71dc2f87dbf558";    const empty_hex = "088cb4b17ab38962b95e7df2e7fe65dbaadab2ee20a7e48b21ce2c6210faaaad";    const pair_hex = "53e5f002f002639e7c61c98d23876fbd8ddd8afcd3132bb61b527b973370a9e1";    try expectDigest(alpha_hex, alpha.digest(1));    try expectDigest(empty_hex, empty.digest(1));    try expectDigest(pair_hex, pair.digest(2));}fn expectDigest(comptime hex: []const u8, actual: [digest_size]u8) !void {    var expected: [digest_size]u8 = undefined;    _ = try std.fmt.hexToBytes(&expected, hex);    try std.testing.expectEqualSlices(u8, &expected, &actual);}test "lattice add and subtract invert" {    const first = entryState("alpha", "one");    const second = entryState("beta", "two");    var state = State.empty;    state.add(&first);    state.add(&second);    var expected = State.empty;    expected.add(&first);    state.subtract(&second);    try std.testing.expect(state.eql(&expected));    state.subtract(&first);    try std.testing.expect(state.isEmpty());}test "lattice entry framing separates key and value boundaries" {    const joined_left = entryState("ab", "c");    const joined_right = entryState("a", "bc");    try std.testing.expect(!joined_left.eql(&joined_right));    const key_only = entryState("a", "");    const value_only = entryState("", "a");    try std.testing.expect(!key_only.eql(&value_only));}test "lattice streaming value chunks match one shot" {    var hasher = EntryHasher.init("stream");    hasher.update("he");    hasher.update("l");    hasher.update("lo");    const streamed = hasher.finish();    const oneshot = entryState("stream", "hello");    try std.testing.expect(streamed.eql(&oneshot));}test "lattice encode decode round trips" {    var state = State.empty;    const entry = entryState("round", "trip");    state.add(&entry);    var encoded: [encoded_size]u8 = undefined;    state.encode(&encoded);    const decoded = State.decode(&encoded);    try std.testing.expect(state.eql(&decoded));}test "lattice digest binds entry count" {    var state = State.empty;    const entry = entryState("count", "bound");    state.add(&entry);    const one = state.digest(1);    const two = state.digest(2);    try std.testing.expect(!std.mem.eql(u8, &one, &two));}test "lattice empty digest differs from populated digest" {    var state = State.empty;    const empty_digest = State.empty.digest(0);    const entry = entryState("k", "v");    state.add(&entry);    const populated = state.digest(1);    try std.testing.expect(!std.mem.eql(u8, &empty_digest, &populated));}

Source: lib/sql/src/root.zig:31

zig
pub const lattice = @import("lattice.zig");

Complete caller list for lattice.entryState

13 direct callers.

Audit

Definitions18
Public names18
Members2
Version26.7.0
Revisiondaab053ee433