Skip to main content

coven_format/
authorship.rs

1//! Authorship leaves of a write part, its keyed tree and multiproofs (D11).
2//!
3//! Each part commits to its original creations, cells, deletions and SQL
4//! operations as separate leaves, so a snapshot can prove one surviving cell
5//! or a row's creation without revealing values that were later overwritten.
6//! Hashing is keyed with the part's audience key; the tree splits like
7//! RFC 6962, the left side holding the largest power of two below the count.
8
9use crate::error::{bound, require, Error, Rule};
10use crate::value::{name, row, Value};
11use crate::wire::{get_blob, put_blob, wire_struct, Decoder, Encoder, Wire, MAX_ITEMS};
12#[cfg(any(test, feature = "test-utils"))]
13use crate::write::WritePart;
14use crate::write::{PartRecord, RowChange, RowExecution, Step};
15use crate::write_sources::ChangeId;
16use coven_merge::{ColumnValue, Operation, RowId};
17
18/// Keyed hashing of one part's leaves. Branches are unkeyed (D11).
19pub trait PartHasher {
20    /// One leaf's encoded bytes.
21    fn leaf(&self, leaf: &[u8]) -> [u8; 32];
22}
23
24impl PartHasher for coven_crypto::AuthorshipHasher {
25    fn leaf(&self, leaf: &[u8]) -> [u8; 32] {
26        coven_crypto::AuthorshipHasher::leaf(self, leaf)
27    }
28}
29
30use coven_crypto::{authorship_empty, authorship_node};
31
32/// Whether a cell was set by an insert or an update.
33#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
34pub enum CellKind {
35    /// The incarnation's first values.
36    Insert,
37    /// A later change in the same incarnation.
38    Update,
39}
40
41/// One authenticated original fact of a part (D11).
42#[derive(Clone, Debug, PartialEq, Eq)]
43pub enum Leaf {
44    /// An insert's creation marker, with the original creation it copies.
45    /// It carries no values, so it stays openable after every one changes.
46    Creation {
47        /// The inserted row.
48        row: RowId,
49        /// The generation before the insert.
50        generation: u64,
51        /// The copied row's original creation, for an audience copy.
52        creator: Option<ChangeId>,
53    },
54    /// One column an insert or update set.
55    Cell {
56        /// The changed row.
57        row: RowId,
58        /// The generation before the change.
59        generation: u64,
60        /// Insert or update.
61        kind: CellKind,
62        /// The column.
63        column: String,
64        /// Its value and recorded parents.
65        value: ColumnValue<Value>,
66    },
67    /// A delete's marker.
68    Deletion {
69        /// The deleted row.
70        row: RowId,
71        /// The generation before the delete.
72        generation: u64,
73    },
74    /// One SQL operation on the row, in execution order.
75    Step {
76        /// The row the operation changed.
77        row: RowId,
78        /// The operation.
79        step: Step,
80    },
81}
82impl Wire for Leaf {
83    fn put(&self, out: &mut Encoder) -> Result<(), Error> {
84        match self {
85            Self::Creation { row, generation, creator } => {
86                0u8.put(out)?;
87                row.put(out)?;
88                generation.put(out)?;
89                creator.put(out)
90            }
91            Self::Cell { row, generation, kind, column, value } => {
92                1u8.put(out)?;
93                row.put(out)?;
94                generation.put(out)?;
95                (*kind as u8).put(out)?;
96                column.put(out)?;
97                value.put(out)
98            }
99            Self::Deletion { row, generation } => {
100                2u8.put(out)?;
101                row.put(out)?;
102                generation.put(out)
103            }
104            Self::Step { row, step } => {
105                3u8.put(out)?;
106                row.put(out)?;
107                step.put(out)
108            }
109        }
110    }
111    fn get(input: &mut Decoder<'_>) -> Result<Self, Error> {
112        match u8::get(input)? {
113            0 => Ok(Self::Creation {
114                row: Wire::get(input)?,
115                generation: Wire::get(input)?,
116                creator: Wire::get(input)?,
117            }),
118            1 => Ok(Self::Cell {
119                row: Wire::get(input)?,
120                generation: Wire::get(input)?,
121                kind: match u8::get(input)? {
122                    0 => CellKind::Insert,
123                    1 => CellKind::Update,
124                    tag => return Err(Error::UnknownTag { field: "cell kind", tag }),
125                },
126                column: crate::wire::get_name(input)?,
127                value: Wire::get(input)?,
128            }),
129            2 => Ok(Self::Deletion { row: Wire::get(input)?, generation: Wire::get(input)? }),
130            3 => Ok(Self::Step { row: Wire::get(input)?, step: Wire::get(input)? }),
131            tag => Err(Error::UnknownTag { field: "authorship leaf", tag }),
132        }
133    }
134}
135impl Leaf {
136    /// The leaf's canonical bytes, the input of its keyed hash.
137    pub fn encode(&self) -> Result<Vec<u8>, Error> {
138        self.validate()?;
139        let mut out = Encoder::new();
140        self.put(&mut out)?;
141        Ok(out.bytes)
142    }
143
144    /// Decode exactly one leaf.
145    pub fn decode(bytes: &[u8]) -> Result<Self, Error> {
146        #[cfg(any(test, feature = "test-utils"))]
147        coven_foundation::test_work::snapshot_record_decode();
148        let mut input = Decoder::new(bytes)?;
149        let leaf = Self::get(&mut input)?;
150        input.finish()?;
151        leaf.validate()?;
152        Ok(leaf)
153    }
154
155    /// The row the leaf describes.
156    pub fn row(&self) -> &RowId {
157        match self {
158            Self::Creation { row, .. }
159            | Self::Cell { row, .. }
160            | Self::Deletion { row, .. }
161            | Self::Step { row, .. } => row,
162        }
163    }
164
165    fn validate(&self) -> Result<(), Error> {
166        row(self.row())?;
167        match self {
168            Self::Cell { column, value, .. } => {
169                name(column)?;
170                crate::merge_wire::column(value)
171            }
172            Self::Step { row, step } => {
173                crate::write::Execution { steps: vec![step.clone()], sources: Default::default() }
174                    .validate(row)
175            }
176            Self::Creation { .. } | Self::Deletion { .. } => Ok(()),
177        }
178    }
179}
180
181/// A net change's leaves, then one per operation (D11).
182pub fn change_leaves(change: &RowChange) -> Vec<Leaf> {
183    let row = &change.row;
184    let generation = change.change.generation;
185    let mut leaves = Vec::new();
186    let cells = |kind, columns: &std::collections::BTreeMap<String, ColumnValue<Value>>| {
187        columns
188            .iter()
189            .map(move |(column, value)| Leaf::Cell {
190                row: row.clone(),
191                generation,
192                kind,
193                column: column.clone(),
194                value: value.clone(),
195            })
196            .collect::<Vec<_>>()
197    };
198    match &change.change.operation {
199        Operation::Insert(columns) => {
200            leaves.push(Leaf::Creation {
201                row: row.clone(),
202                generation,
203                creator: change.creator.clone(),
204            });
205            leaves.extend(cells(CellKind::Insert, columns));
206        }
207        Operation::Update(columns) => leaves.extend(cells(CellKind::Update, columns)),
208        Operation::Delete => leaves.push(Leaf::Deletion { row: row.clone(), generation }),
209    }
210    leaves.extend(step_leaves(row, &change.execution.steps));
211    leaves
212}
213
214/// One leaf of a kept record (D7.3, D11): known whole, a cell whose value
215/// the record holds only as a digest, or an operation, never opened.
216#[derive(Clone, Debug, PartialEq, Eq)]
217pub enum KeptLeaf {
218    /// A leaf the record holds whole: a creation, a deletion, or a cell kept
219    /// in full.
220    Known(Leaf),
221    /// A cell kept as a digest. It opens as the cell its value matches.
222    Digest {
223        /// The changed row.
224        row: RowId,
225        /// The generation before the change.
226        generation: u64,
227        /// Insert or update.
228        kind: CellKind,
229        /// The column.
230        column: String,
231        /// The value's digest.
232        digest: [u8; 32],
233    },
234    /// One of the record's operations.
235    Step,
236}
237
238impl KeptLeaf {
239    /// The leaf this one is when its cell holds `value`: a known leaf
240    /// stays as it is; a digest becomes the cell when `value` names no
241    /// parents and is the value it digests.
242    pub fn with_value(&self, value: &ColumnValue<Value>) -> Result<Option<Leaf>, Error> {
243        Ok(match self {
244            Self::Known(leaf) => Some(leaf.clone()),
245            Self::Digest { row, generation, kind, column, digest } => (value.parents.is_empty()
246                && crate::snapshot_rows::KeptValue::Digest(*digest).matches(&value.value)?)
247            .then(|| Leaf::Cell {
248                row: row.clone(),
249                generation: *generation,
250                kind: *kind,
251                column: column.clone(),
252                value: value.clone(),
253            }),
254            Self::Step => None,
255        })
256    }
257}
258
259/// A kept record's leaves, in the order its original record had them.
260pub fn kept_leaves(record: &crate::snapshot_rows::KeptRecord) -> Vec<KeptLeaf> {
261    use crate::snapshot_rows::{KeptRecord, KeptValue};
262    let (mut leaves, steps) = match record {
263        KeptRecord::Execution { steps, .. } => (Vec::new(), *steps),
264        KeptRecord::Change(change) => {
265            let row = &change.row;
266            let generation = change.change.generation;
267            let cells =
268                |kind, columns: &std::collections::BTreeMap<String, ColumnValue<KeptValue>>| {
269                    columns
270                        .iter()
271                        .map(|(column, cell)| match &cell.value {
272                            KeptValue::Value(value) => KeptLeaf::Known(Leaf::Cell {
273                                row: row.clone(),
274                                generation,
275                                kind,
276                                column: column.clone(),
277                                value: ColumnValue {
278                                    value: value.clone(),
279                                    parents: cell.parents.clone(),
280                                },
281                            }),
282                            KeptValue::Digest(digest) => KeptLeaf::Digest {
283                                row: row.clone(),
284                                generation,
285                                kind,
286                                column: column.clone(),
287                                digest: *digest,
288                            },
289                        })
290                        .collect::<Vec<_>>()
291                };
292            let mut leaves = Vec::new();
293            match &change.change.operation {
294                Operation::Insert(columns) => {
295                    leaves.push(KeptLeaf::Known(Leaf::Creation {
296                        row: row.clone(),
297                        generation,
298                        creator: change.creator.clone(),
299                    }));
300                    leaves.extend(cells(CellKind::Insert, columns));
301                }
302                Operation::Update(columns) => leaves.extend(cells(CellKind::Update, columns)),
303                Operation::Delete => {
304                    leaves.push(KeptLeaf::Known(Leaf::Deletion { row: row.clone(), generation }))
305                }
306            }
307            (leaves, change.steps)
308        }
309    };
310    leaves.extend((0..steps).map(|_| KeptLeaf::Step));
311    leaves
312}
313
314/// An execution-only row's leaves: one per operation.
315pub fn execution_leaves(execution: &RowExecution) -> Vec<Leaf> {
316    step_leaves(&execution.row, &execution.execution.steps).collect()
317}
318
319fn step_leaves<'a>(row: &'a RowId, steps: &'a [Step]) -> impl Iterator<Item = Leaf> + 'a {
320    steps.iter().map(|step| Leaf::Step { row: row.clone(), step: step.clone() })
321}
322
323/// One record's leaves.
324pub fn record_leaves(record: PartRecord<'_>) -> Vec<Leaf> {
325    match record {
326        PartRecord::Change(change) => change_leaves(change),
327        PartRecord::Execution(execution) => execution_leaves(execution),
328    }
329}
330
331/// Every leaf of a part, in its stream's record order. Dismissals have none.
332#[cfg(any(test, feature = "test-utils"))]
333pub fn part_leaves(part: &WritePart) -> Vec<Leaf> {
334    part.records().flat_map(record_leaves).collect()
335}
336
337/// The size of a tree's left subtree: the largest power of two below `count`.
338fn split(count: u64) -> u64 {
339    debug_assert!(count > 1);
340    1 << (63 - (count - 1).leading_zeros())
341}
342
343/// Computes a part's root from its leaves in order, keeping one hash per
344/// complete subtree, so a streamed part never holds its leaves.
345pub struct RootBuilder<'h, H: PartHasher> {
346    hasher: &'h H,
347    /// Perfect subtrees, largest first, with their sizes.
348    stack: Vec<([u8; 32], u64)>,
349}
350impl<'h, H: PartHasher> RootBuilder<'h, H> {
351    /// Start an empty part.
352    pub fn new(hasher: &'h H) -> Self {
353        Self { hasher, stack: Vec::new() }
354    }
355
356    /// Add the next leaf, returning its keyed hash.
357    pub fn push(&mut self, leaf: &Leaf) -> Result<[u8; 32], Error> {
358        let hash = self.hasher.leaf(&leaf.encode()?);
359        self.stack = push_hash(std::mem::take(&mut self.stack), hash);
360        Ok(hash)
361    }
362
363    /// The root over every leaf pushed.
364    pub fn finish(self) -> [u8; 32] {
365        finish_hashes(self.stack)
366    }
367}
368
369fn push_hash(mut stack: Vec<([u8; 32], u64)>, mut hash: [u8; 32]) -> Vec<([u8; 32], u64)> {
370    let mut size = 1;
371    while stack.last().is_some_and(|(_, top)| *top == size) {
372        let (left, _) = stack.pop().expect("checked");
373        hash = authorship_node(&left, &hash);
374        size *= 2;
375    }
376    stack.push((hash, size));
377    stack
378}
379
380fn finish_hashes(stack: Vec<([u8; 32], u64)>) -> [u8; 32] {
381    let mut stack = stack.into_iter().rev();
382    let Some((mut root, _)) = stack.next() else {
383        return authorship_empty();
384    };
385    for (left, _) in stack {
386        root = authorship_node(&left, &root);
387    }
388    root
389}
390
391/// The root over a part's leaf hashes, without its key.
392pub fn root_of_hashes(hashes: &[[u8; 32]]) -> [u8; 32] {
393    finish_hashes(hashes.iter().fold(Vec::new(), |stack, hash| push_hash(stack, *hash)))
394}
395
396/// The root of a part over its leaves.
397#[cfg(any(test, feature = "test-utils"))]
398pub fn root(hasher: &impl PartHasher, leaves: &[Leaf]) -> Result<[u8; 32], Error> {
399    let mut builder = RootBuilder::new(hasher);
400    for leaf in leaves {
401        builder.push(leaf)?;
402    }
403    Ok(builder.finish())
404}
405
406/// Opened leaves of one part and one hash per maximal unopened subtree, in
407/// left-to-right order (D7). The tree's shape follows from `leaves`.
408#[derive(Clone, Debug, PartialEq, Eq)]
409pub struct Multiproof {
410    /// How many leaves the part has.
411    pub leaves: u64,
412    /// The opened leaves with their positions, in increasing position order.
413    pub revealed: Vec<(u64, Vec<u8>)>,
414    /// The roots of the subtrees with no opened leaf.
415    pub hidden: Vec<[u8; 32]>,
416}
417impl Wire for Multiproof {
418    fn put(&self, out: &mut Encoder) -> Result<(), Error> {
419        self.leaves.put(out)?;
420        bound(self.revealed.len(), MAX_ITEMS, "collection")?;
421        out.charge_items(self.revealed.len())?;
422        (self.revealed.len() as u32).put(out)?;
423        for (index, leaf) in &self.revealed {
424            index.put(out)?;
425            put_blob(leaf, out)?;
426        }
427        self.hidden.put(out)
428    }
429    fn get(input: &mut Decoder<'_>) -> Result<Self, Error> {
430        Ok(Self {
431            leaves: Wire::get(input)?,
432            revealed: crate::wire::get_sequence(input, |input| {
433                Ok((u64::get(input)?, get_blob(input)?))
434            })?,
435            hidden: Wire::get(input)?,
436        })
437    }
438}
439impl Multiproof {
440    /// Open the leaves `keep` selects, hiding each subtree that has none.
441    #[cfg(any(test, feature = "test-utils"))]
442    pub fn prove(
443        hasher: &impl PartHasher,
444        leaves: &[Leaf],
445        keep: impl Fn(&Leaf) -> bool,
446    ) -> Result<Self, Error> {
447        let encoded = leaves.iter().map(Leaf::encode).collect::<Result<Vec<_>, _>>()?;
448        let hashes: Vec<_> = encoded.iter().map(|leaf| hasher.leaf(leaf)).collect();
449        let opened = leaves
450            .iter()
451            .zip(encoded)
452            .map(|(leaf, bytes)| keep(leaf).then_some(bytes))
453            .collect::<Vec<_>>();
454        Ok(Self::from_hashes(&hashes, opened))
455    }
456
457    /// Open the leaves given with their bytes, hiding each subtree that has
458    /// none by its root over the part's retained leaf hashes, without a key.
459    pub fn from_hashes(hashes: &[[u8; 32]], opened: Vec<Option<Vec<u8>>>) -> Self {
460        debug_assert_eq!(hashes.len(), opened.len());
461        let mut proof =
462            Self { leaves: hashes.len() as u64, revealed: Vec::new(), hidden: Vec::new() };
463        if !hashes.is_empty() {
464            prune(hashes, &opened, 0, &mut proof);
465        }
466        proof
467    }
468
469    /// Every opened leaf, decoded.
470    pub fn opened(&self) -> Result<Vec<Leaf>, Error> {
471        self.revealed.iter().map(|(_, leaf)| Leaf::decode(leaf)).collect()
472    }
473
474    /// The root these openings and hashes reconstruct. Positions must be in
475    /// range and increasing, and every hash must be used exactly once.
476    pub fn root(&self, hasher: &impl PartHasher) -> Result<[u8; 32], Error> {
477        self.rebuild(|leaf| hasher.leaf(leaf))
478    }
479
480    /// Reconstruct the root and retain the hash of each revealed leaf, in
481    /// revealed order, so later proofs can hide it without the audience key.
482    pub fn root_with_leaf_hashes(
483        &self,
484        hasher: &impl PartHasher,
485    ) -> Result<([u8; 32], Vec<[u8; 32]>), Error> {
486        let mut hashes = Vec::with_capacity(self.revealed.len());
487        let root = self.rebuild(|leaf| {
488            let hash = hasher.leaf(leaf);
489            hashes.push(hash);
490            hash
491        })?;
492        Ok((root, hashes))
493    }
494
495    fn rebuild(&self, mut hash_leaf: impl FnMut(&[u8]) -> [u8; 32]) -> Result<[u8; 32], Error> {
496        require(
497            self.revealed.windows(2).all(|pair| pair[0].0 < pair[1].0)
498                && self.revealed.last().is_none_or(|(i, _)| *i < self.leaves),
499            "multiproof positions",
500            Rule::Order,
501        )?;
502        for (_, leaf) in &self.revealed {
503            Leaf::decode(leaf)?;
504        }
505        if self.leaves == 0 {
506            require(
507                self.revealed.is_empty() && self.hidden.is_empty(),
508                "multiproof hashes",
509                Rule::StreamLength,
510            )?;
511            return Ok(authorship_empty());
512        }
513        let mut revealed = self.revealed.iter().peekable();
514        let mut hidden = self.hidden.iter();
515        let root = rebuild(&mut hash_leaf, 0, self.leaves, &mut revealed, &mut hidden)?;
516        require(
517            revealed.next().is_none() && hidden.next().is_none(),
518            "multiproof hashes",
519            Rule::StreamLength,
520        )?;
521        Ok(root)
522    }
523
524    /// Retain a subset of an authenticated proof's openings, merging hidden
525    /// siblings into maximal subtrees. `hashes` and `keep` correspond exactly
526    /// to `revealed`; hashes come from `root_with_leaf_hashes` at authentication.
527    pub fn retain_opened(&self, hashes: &[[u8; 32]], keep: &[bool]) -> Self {
528        let mut proof = Self { leaves: self.leaves, revealed: Vec::new(), hidden: Vec::new() };
529        if self.leaves > 0 {
530            retain_opened(
531                0,
532                self.leaves,
533                &self.revealed,
534                hashes,
535                keep,
536                &mut self.hidden.iter(),
537                &mut proof,
538            );
539        }
540        proof
541    }
542}
543
544fn retain_opened(
545    start: u64,
546    count: u64,
547    revealed: &[(u64, Vec<u8>)],
548    hashes: &[[u8; 32]],
549    keep: &[bool],
550    hidden: &mut std::slice::Iter<'_, [u8; 32]>,
551    proof: &mut Multiproof,
552) -> [u8; 32] {
553    if revealed.is_empty() {
554        let hash = *hidden.next().expect("authenticated subtree");
555        proof.hidden.push(hash);
556        return hash;
557    }
558    if count == 1 {
559        if keep[0] {
560            proof.revealed.push(revealed[0].clone());
561        } else {
562            proof.hidden.push(hashes[0]);
563        }
564        return hashes[0];
565    }
566    let left = split(count);
567    let middle = revealed.partition_point(|(index, _)| *index < start + left);
568    let opened = proof.revealed.len();
569    let hidden_start = proof.hidden.len();
570    let left_hash = retain_opened(
571        start,
572        left,
573        &revealed[..middle],
574        &hashes[..middle],
575        &keep[..middle],
576        hidden,
577        proof,
578    );
579    let right_hash = retain_opened(
580        start + left,
581        count - left,
582        &revealed[middle..],
583        &hashes[middle..],
584        &keep[middle..],
585        hidden,
586        proof,
587    );
588    let hash = authorship_node(&left_hash, &right_hash);
589    if proof.revealed.len() == opened {
590        proof.hidden.truncate(hidden_start);
591        proof.hidden.push(hash);
592    }
593    hash
594}
595
596fn subtree(hashes: &[[u8; 32]]) -> [u8; 32] {
597    if hashes.len() == 1 {
598        return hashes[0];
599    }
600    let (left, right) = hashes.split_at(split(hashes.len() as u64) as usize);
601    authorship_node(&subtree(left), &subtree(right))
602}
603
604fn prune(hashes: &[[u8; 32]], opened: &[Option<Vec<u8>>], start: u64, proof: &mut Multiproof) {
605    if opened.iter().all(Option::is_none) {
606        proof.hidden.push(subtree(hashes));
607    } else if hashes.len() == 1 {
608        proof.revealed.push((start, opened[0].clone().expect("an opened leaf")));
609    } else {
610        let left = split(hashes.len() as u64) as usize;
611        prune(&hashes[..left], &opened[..left], start, proof);
612        prune(&hashes[left..], &opened[left..], start + left as u64, proof);
613    }
614}
615
616fn rebuild<'a>(
617    hash_leaf: &mut impl FnMut(&[u8]) -> [u8; 32],
618    start: u64,
619    count: u64,
620    revealed: &mut std::iter::Peekable<impl Iterator<Item = &'a (u64, Vec<u8>)>>,
621    hidden: &mut impl Iterator<Item = &'a [u8; 32]>,
622) -> Result<[u8; 32], Error> {
623    let opens = revealed.peek().is_some_and(|(index, _)| *index < start + count);
624    if !opens {
625        return hidden
626            .next()
627            .copied()
628            .ok_or(Error::Invalid { field: "multiproof hashes", rule: Rule::StreamLength });
629    }
630    if count == 1 {
631        let (_, leaf) = revealed.next().expect("checked");
632        return Ok(hash_leaf(leaf));
633    }
634    let left = split(count);
635    let left_hash = rebuild(hash_leaf, start, left, revealed, hidden)?;
636    let right_hash = rebuild(hash_leaf, start + left, count - left, revealed, hidden)?;
637    Ok(authorship_node(&left_hash, &right_hash))
638}
639
640/// A write's evidence for its part in one audience (D7 section 7): the
641/// cleartext prefix, the sealed header chunk, every part root, the header
642/// signature and a multiproof of that part's needed leaves.
643#[derive(Clone, Debug, PartialEq, Eq)]
644pub struct WriteEvidence {
645    /// The write.
646    pub write: coven_merge::WriteId,
647    /// The exact cleartext `kind | version | prefix` bytes.
648    pub prefix: Vec<u8>,
649    /// The sealed header chunk exactly as stored, with its length field.
650    pub header: Vec<u8>,
651    /// Every part's root, in header order.
652    pub roots: Vec<[u8; 32]>,
653    /// The header signature over these bytes (D9).
654    pub signature: [u8; coven_crypto::SIGNATURE_LEN],
655    /// The openings in the snapshot audience's part.
656    pub proof: Multiproof,
657}
658impl Wire for WriteEvidence {
659    fn put(&self, out: &mut Encoder) -> Result<(), Error> {
660        self.write.put(out)?;
661        put_blob(&self.prefix, out)?;
662        put_blob(&self.header, out)?;
663        self.roots.put(out)?;
664        self.signature.put(out)?;
665        self.proof.put(out)
666    }
667    fn get(input: &mut Decoder<'_>) -> Result<Self, Error> {
668        Ok(Self {
669            write: Wire::get(input)?,
670            prefix: get_blob(input)?,
671            header: get_blob(input)?,
672            roots: Wire::get(input)?,
673            signature: Wire::get(input)?,
674            proof: Wire::get(input)?,
675        })
676    }
677}
678impl WriteEvidence {
679    pub(crate) fn validate(&self) -> Result<(), Error> {
680        crate::value::positive(self.write.number)?;
681        let prefix = crate::sealed_write::WriteObjectPrefix::decode(&self.prefix)?;
682        require(
683            prefix.part_keys.len() == self.roots.len(),
684            "write evidence roots",
685            Rule::StreamLength,
686        )?;
687        crate::sealed_write::WriteObjectPrefix::header_chunk(&self.header)?;
688        for (_, leaf) in &self.proof.revealed {
689            Leaf::decode(leaf)?;
690        }
691        Ok(())
692    }
693}
694
695/// A row's selected original creation (D7 section 6): the generation-zero
696/// insert with the lowest claimed slot, then lowest write number, and the
697/// creation it names as its owner, which differs only for an audience copy (ยง9.6).
698#[derive(Clone, Debug, PartialEq, Eq)]
699pub struct Creation {
700    /// The row.
701    pub row: RowId,
702    /// The selected generation-zero insert's write.
703    pub write: coven_merge::WriteId,
704    /// The original creation: this insert itself, or the creation it copied.
705    pub creator: ChangeId,
706}
707wire_struct!(Creation, row, write, creator);
708impl Creation {
709    pub(crate) fn validate(&self) -> Result<(), Error> {
710        row(&self.row)?;
711        crate::value::positive(self.write.number)?;
712        crate::value::positive(self.creator.write.number)?;
713        // The creator keeps its original write's table name across renames.
714        require(self.creator.row.key == self.row.key, "creation row", Rule::Required)?;
715        require(
716            (self.creator.write == self.write) == (self.creator.row.audience == self.row.audience),
717            "creation copy",
718            Rule::Required,
719        )
720    }
721}
722
723#[cfg(test)]
724#[path = "authorship_tests.rs"]
725mod tests;