macroonz-harness 0.2.0

Safe-Rust property, fuzz, fault, schedule, mutation, network, and benchmark testing with typed evidence, reduction, and replay.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
//! The canonical bytes this home's preimage-bearing values commit to: one root schema declaration, one authored row, and one trial's coordinates.
//!
//! These bytes are preimages, never identities, and no reader is meant to parse meaning out of them.
//! They exist so that one value has exactly one byte string, and so that a change to any member of that value moves the identity derived from it.
//! The encoding is a function of the value and of nothing else — no clock, no environment, no source text, no iteration order that is not the declared one.
//! It is stated completely here, because an independent party re-deriving one of these identities writes its own encoder from this page and imports nothing.
//!
//! # Two primitives
//!
//! - `u32be(n)` and `u64be(n)` — the integer in four or eight big-endian bytes.
//! - `bytes(x)` — `u64be(len(x))` followed by the bytes of `x`.
//!
//! Every variable-length member is framed, so no two member sequences can be cut at a different boundary and produce one byte string.
//! A name is `bytes(namespace)` then `bytes(stem)`, two framed members rather than a joined spelling.
//! Nothing is folded on the way in, so the derived identity is the only compression anywhere in the derivation.
//!
//! # The schema declaration
//!
//! | # | member | encoding |
//! | - | ------ | -------- |
//! | 1 | encoding version | `u32be` |
//! | 2 | descriptor member | member tag `1`, then its roster |
//! | 3 | mutation-discovery member | member tag `2`, then its roster |
//! | 4 | bench member | member tag `3`, then its roster |
//!
//! A roster is `u64be(field count)` followed by each field in declared order.
//! A field is `bytes(name)`, then its shape, then one byte for its cardinality slot.
//! A shape is one byte for its slot; the closed-choice shape additionally writes `u64be(arm count)` followed by `bytes(arm)` for each arm in declared order.
//!
//! # The row
//!
//! | # | member | encoding |
//! | - | ------ | -------- |
//! | 1 | encoding version | `u32be`, the row encoding's own |
//! | 2 | claim | the reference's name |
//! | 3 | execution suite | the reference's name |
//! | 4 | roles | `u64be(count)`, then each role's name |
//! | 5 | tags | `u64be(count)`, then each tag's name |
//! | 6 | subject route | the reference's name |
//! | 7 | check reference | the reference's name |
//! | 8 | population | the reference's name |
//! | 9 | origin | one byte, [`Origin::slot`], then the arm's own members |
//!
//! | slot | arm | members |
//! | ---- | --- | ------- |
//! | 1 | hand-written | nothing |
//! | 2 | generated | the door's name, then the projection's name |
//! | 3 | candidate | one byte, [`SynthesisFacts::slot`]; the survivor arm then writes the mutation point's name |
//! | 4 | admitted-replay | `bytes(proposal address)`, one byte for the ground, the destination suite's name, `bytes(replay address)` |
//! | 5 | admitted-discharge | `bytes(proposal address)`, the destination suite's name |
//!
//! The member order is the descriptor schema's declared reading order, so the roster a producer emits against and the bytes a row commits to are read the same way round.
//! The discharge arm writes no ground byte, and that is the elision law: its ground is forced by the arm, so a second byte would state a value that could not have been anything else.
//!
//! Roles and tags are written in storage order rather than authoring order, so two rows carrying the same labels encode identically however they were written.
//! The schema identity, the producer's provenance, and the two revision bindings are absent, because none of them is a row field.
//!
//! The two encodings carry separate version constants, because how a schema is cut and how a row is cut are two decisions and one bump must rename nothing under the other.
//! Their preimages are never compared with each other: they are derived under different domain tags, so their identities are unrelated values rather than neighbouring ones.

use super::types::{
    AdmissionGround, CheckRef, ClaimRef, Classification, DESCRIPTOR_PROJECTIONS,
    DescriptorProjection, DischargeAdmission, EncodeRefusal, ExecutionSuite, FieldCardinality,
    FieldShape, GeneratedSupportSchema, NamespacedName, Origin, PopulationRef, ReplayAdmission,
    SchemaField, SubjectRoute, SynthesisFacts, TrialCoordinates, generated_support_members,
    origin_declarations,
};
use crate::identity::{encode_bytes, encode_length};

/// The version of the schema encoding itself.
///
/// It rides the preimage, so changing how the bytes are cut moves every derived identity.
const SCHEMA_ENCODING_VERSION: u32 = 1;

/// The version of the row encoding itself.
///
/// Its own constant rather than the schema encoding's: the two move for separate reasons, and a bump to one must rename nothing derived under the other.
const ROW_ENCODING_VERSION: u32 = 2;

impl AdmissionGround {
    /// The byte this ground is written as in a row's canonical preimage.
    #[must_use]
    pub const fn slot(self) -> u8 {
        match self {
            Self::MutantKilled => 1,
            Self::ClaimPinned => 2,
            Self::ObligationDischarged => 3,
        }
    }
}

macro_rules! implement_origin_slots {
    ($( $variant:ident $(($payload:pat))? => $spelling:literal => $slot:literal, )+) => {
        impl Origin {
            /// The byte this arm is written as in a row's canonical preimage.
            ///
            /// The origin roster projects both this match and the schema's closed-choice spellings, so their order cannot drift independently.
            #[must_use]
            pub const fn slot(self) -> u8 {
                match self {
                    $(
                        Self::$variant $(($payload))? => $slot,
                    )+
                }
            }
        }
    };
}

origin_declarations!(implement_origin_slots);

impl SynthesisFacts {
    /// The byte this arm is written as in a row's canonical preimage.
    #[must_use]
    pub const fn slot(self) -> u8 {
        match self {
            Self::Survivor(_) => 1,
            Self::ProofGap => 2,
        }
    }
}

impl FieldShape {
    /// The byte this shape is written as in the schema's canonical preimage.
    #[must_use]
    pub const fn slot(self) -> u8 {
        match self {
            Self::NamespacedName => 1,
            Self::ContentAddress => 2,
            Self::ClosedChoice(_) => 3,
            Self::Bytes => 4,
            Self::Count => 5,
            Self::MutationAlternative => 6,
        }
    }
}

impl FieldCardinality {
    /// The byte this cardinality is written as in the schema's canonical preimage.
    #[must_use]
    pub const fn slot(self) -> u8 {
        match self {
            Self::ExactlyOne => 1,
            Self::ZeroOrOne => 2,
            Self::ZeroOrMore => 3,
            Self::OneOrMore => 4,
        }
    }
}

macro_rules! push_generated_support_members {
    ([$bytes:ident, $schema:ident]; $( $member:ident: $member_type:ty => $fields:ident => $tag:literal, )+) => {
        $(
            push_member(&mut $bytes, $tag, $schema.$member().fields())?;
        )+
    };
}

/// The canonical bytes of one root schema declaration.
///
/// # Errors
///
/// Refuses a length that does not fit the sixty-four-bit width the encoding declares.
/// The descriptor adapter establishes that public refusal before delegating the bytes to the identity substrate; on every target this crate supports the case is unreachable.
pub fn encode_generated_support_schema(
    schema: &GeneratedSupportSchema,
) -> Result<Vec<u8>, EncodeRefusal> {
    let mut bytes = Vec::new();
    bytes.extend_from_slice(&SCHEMA_ENCODING_VERSION.to_be_bytes());
    generated_support_members!(push_generated_support_members, bytes, schema);
    Ok(bytes)
}

/// One member: its tag, then its roster.
fn push_member(out: &mut Vec<u8>, tag: u8, fields: &[SchemaField]) -> Result<(), EncodeRefusal> {
    out.push(tag);
    encode_declared_length(fields.len(), out)?;
    for field in fields {
        encode_declared_bytes(field.name().as_bytes(), out)?;
        push_shape(out, field.shape())?;
        out.push(field.cardinality().slot());
    }
    Ok(())
}

/// One shape: its slot, and the arm spellings the closed-choice shape carries.
fn push_shape(out: &mut Vec<u8>, shape: FieldShape) -> Result<(), EncodeRefusal> {
    out.push(shape.slot());
    match shape {
        FieldShape::ClosedChoice(arms) => {
            encode_declared_length(arms.len(), out)?;
            for arm in arms {
                encode_declared_bytes(arm.as_bytes(), out)?;
            }
        }
        FieldShape::NamespacedName
        | FieldShape::ContentAddress
        | FieldShape::Bytes
        | FieldShape::Count
        | FieldShape::MutationAlternative => {}
    }
    Ok(())
}

/// The complete canonical bytes of one row's declared content — every field the row declares, and everything the arm its origin carries earns.
///
/// The road takes the declared values rather than a row, because it runs while the row is being born: [`Row::declared`](super::Row::declared) is its one caller, and its answer is what that row then owns for life.
/// The record home derives the row revision identity from these bytes and encodes nothing itself.
///
/// # Errors
///
/// Refuses a length that does not fit the sixty-four-bit width the encoding declares, which is unreachable on every supported target.
pub(super) fn encode_row_content(
    claim: ClaimRef,
    execution_suite: ExecutionSuite,
    classification: &Classification,
    subject: SubjectRoute,
    check: CheckRef,
    population: PopulationRef,
    origin: Origin,
) -> Result<Vec<u8>, EncodeRefusal> {
    RowEncoding::over(
        claim,
        execution_suite,
        classification,
        subject,
        check,
        population,
        origin,
    )
    .encoded()
}

/// The informed inputs and accumulating bytes of one row encoding.
struct RowEncoding<'classification> {
    bytes: Vec<u8>,
    claim: ClaimRef,
    execution_suite: ExecutionSuite,
    classification: &'classification Classification,
    subject: SubjectRoute,
    check: CheckRef,
    population: PopulationRef,
    origin: Origin,
}

impl<'classification> RowEncoding<'classification> {
    /// Begin one row encoding over the complete declared input roster.
    fn over(
        claim: ClaimRef,
        execution_suite: ExecutionSuite,
        classification: &'classification Classification,
        subject: SubjectRoute,
        check: CheckRef,
        population: PopulationRef,
        origin: Origin,
    ) -> Self {
        Self {
            bytes: ROW_ENCODING_VERSION.to_be_bytes().to_vec(),
            claim,
            execution_suite,
            classification,
            subject,
            check,
            population,
            origin,
        }
    }

    /// Write every declared projection in the roster's canonical order.
    fn encoded(mut self) -> Result<Vec<u8>, EncodeRefusal> {
        for projection in DESCRIPTOR_PROJECTIONS {
            self.push_projection(*projection)?;
        }
        Ok(self.bytes)
    }

    /// Write one informed projection without reopening the row's argument list.
    fn push_projection(&mut self, projection: DescriptorProjection) -> Result<(), EncodeRefusal> {
        match projection {
            DescriptorProjection::Claim => self.claim.name().encode_into(&mut self.bytes),
            DescriptorProjection::ExecutionSuite => {
                self.execution_suite.name().encode_into(&mut self.bytes);
            }
            DescriptorProjection::Roles => self.push_roles()?,
            DescriptorProjection::Tags => self.push_tags()?,
            DescriptorProjection::Subject => self.subject.name().encode_into(&mut self.bytes),
            DescriptorProjection::Check => self.check.name().encode_into(&mut self.bytes),
            DescriptorProjection::Population => {
                self.population.name().encode_into(&mut self.bytes);
            }
            DescriptorProjection::Origin => push_origin(&mut self.bytes, self.origin)?,
        }
        Ok(())
    }

    /// Write the role roster in its informed storage order.
    fn push_roles(&mut self) -> Result<(), EncodeRefusal> {
        encode_declared_length(self.classification.roles().len(), &mut self.bytes)?;
        for role in self.classification.roles() {
            role.name().encode_into(&mut self.bytes);
        }
        Ok(())
    }

    /// Write the tag roster in its informed storage order.
    fn push_tags(&mut self) -> Result<(), EncodeRefusal> {
        encode_declared_length(self.classification.tags().len(), &mut self.bytes)?;
        for tag in self.classification.tags() {
            tag.name().encode_into(&mut self.bytes);
        }
        Ok(())
    }
}

/// The complete preimage one [`TrialKey`](super::TrialKey) is derived from: the claim, the subject route, the check, and the population, each as its reference's name, in that order.
///
/// The execution suite is absent because two rows differing only by suite are one trial run under two seats, and nothing about where the row is written appears either, so the key survives a file move and a rename.
pub(super) fn encode_trial_coordinates(coordinates: TrialCoordinates) -> Vec<u8> {
    let mut out = Vec::new();
    coordinates.claim().name().encode_into(&mut out);
    coordinates.subject().name().encode_into(&mut out);
    coordinates.check().name().encode_into(&mut out);
    coordinates.population().name().encode_into(&mut out);
    out
}

/// One origin: its slot, then exactly what its arm earns.
fn push_origin(out: &mut Vec<u8>, origin: Origin) -> Result<(), EncodeRefusal> {
    out.push(origin.slot());
    match origin {
        Origin::HandWritten => Ok(()),
        Origin::Generated(facts) => {
            facts.door().name().encode_into(out);
            facts.projection().name().encode_into(out);
            Ok(())
        }
        Origin::Candidate(facts) => {
            push_synthesis(out, facts);
            Ok(())
        }
        Origin::AdmittedReplay(admitted) => push_replay_admission(out, admitted),
        Origin::AdmittedDischarge(admitted) => push_discharge_admission(out, admitted),
    }
}

/// One synthesis fact: its slot, and the opening the survivor arm names.
fn push_synthesis(out: &mut Vec<u8>, facts: SynthesisFacts) {
    out.push(facts.slot());
    match facts {
        SynthesisFacts::Survivor(point) => point.name().encode_into(out),
        SynthesisFacts::ProofGap => {}
    }
}

/// One replay-bearing admission: the proposal, the ground, the destination suite, and the capsule entry the act authored.
///
/// The ground is written at summary width, so one ground has one identity-bearing byte wherever it is encoded.
fn push_replay_admission(
    out: &mut Vec<u8>,
    admitted: ReplayAdmission,
) -> Result<(), EncodeRefusal> {
    encode_declared_bytes(admitted.proposal().address().as_bytes(), out)?;
    out.push(admitted.admission().ground().slot());
    admitted.destination().name().encode_into(out);
    encode_declared_bytes(admitted.replay().address().as_bytes(), out)
}

/// One discharge admission: the proposal, then the destination suite.
///
/// No ground byte: the arm's own slot already states the one ground a discharge can stand on.
fn push_discharge_admission(
    out: &mut Vec<u8>,
    admitted: DischargeAdmission,
) -> Result<(), EncodeRefusal> {
    encode_declared_bytes(admitted.proposal().address().as_bytes(), out)?;
    admitted.destination().name().encode_into(out);
    Ok(())
}

impl NamespacedName {
    /// Appends this name's canonical bytes: the namespace then the stem, each length-framed through the substrate's one framing.
    ///
    /// Seated with the type on purpose: five homes once restated these two lines, and one lawful edit to the spelling would have split the identity families of the homes that drifted from the homes that did not.
    pub fn encode_into(self, into: &mut Vec<u8>) {
        encode_bytes(self.namespace().written().as_bytes(), into);
        encode_bytes(self.stem().written().as_bytes(), into);
    }
}

/// Append one descriptor length after proving that its public encoding width can hold it.
pub(crate) fn encode_declared_length(
    length: usize,
    into: &mut Vec<u8>,
) -> Result<(), EncodeRefusal> {
    declared_length(length)?;
    encode_length(length, into);
    Ok(())
}

/// Append one descriptor byte string after proving that its public encoding width can hold it.
pub(crate) fn encode_declared_bytes(
    material: &[u8],
    into: &mut Vec<u8>,
) -> Result<(), EncodeRefusal> {
    declared_length(material.len())?;
    encode_bytes(material, into);
    Ok(())
}

/// Prove that one descriptor length fits its public encoding width.
fn declared_length(length: usize) -> Result<(), EncodeRefusal> {
    u64::try_from(length).map_err(|_| EncodeRefusal::LengthPastEncodingWidth)?;
    Ok(())
}