1use 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
18pub trait PartHasher {
20 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#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
34pub enum CellKind {
35 Insert,
37 Update,
39}
40
41#[derive(Clone, Debug, PartialEq, Eq)]
43pub enum Leaf {
44 Creation {
47 row: RowId,
49 generation: u64,
51 creator: Option<ChangeId>,
53 },
54 Cell {
56 row: RowId,
58 generation: u64,
60 kind: CellKind,
62 column: String,
64 value: ColumnValue<Value>,
66 },
67 Deletion {
69 row: RowId,
71 generation: u64,
73 },
74 Step {
76 row: RowId,
78 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 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 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 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
181pub 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#[derive(Clone, Debug, PartialEq, Eq)]
217pub enum KeptLeaf {
218 Known(Leaf),
221 Digest {
223 row: RowId,
225 generation: u64,
227 kind: CellKind,
229 column: String,
231 digest: [u8; 32],
233 },
234 Step,
236}
237
238impl KeptLeaf {
239 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
259pub 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
314pub 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
323pub 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#[cfg(any(test, feature = "test-utils"))]
333pub fn part_leaves(part: &WritePart) -> Vec<Leaf> {
334 part.records().flat_map(record_leaves).collect()
335}
336
337fn split(count: u64) -> u64 {
339 debug_assert!(count > 1);
340 1 << (63 - (count - 1).leading_zeros())
341}
342
343pub struct RootBuilder<'h, H: PartHasher> {
346 hasher: &'h H,
347 stack: Vec<([u8; 32], u64)>,
349}
350impl<'h, H: PartHasher> RootBuilder<'h, H> {
351 pub fn new(hasher: &'h H) -> Self {
353 Self { hasher, stack: Vec::new() }
354 }
355
356 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 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
391pub 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#[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#[derive(Clone, Debug, PartialEq, Eq)]
409pub struct Multiproof {
410 pub leaves: u64,
412 pub revealed: Vec<(u64, Vec<u8>)>,
414 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 #[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 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 pub fn opened(&self) -> Result<Vec<Leaf>, Error> {
471 self.revealed.iter().map(|(_, leaf)| Leaf::decode(leaf)).collect()
472 }
473
474 pub fn root(&self, hasher: &impl PartHasher) -> Result<[u8; 32], Error> {
477 self.rebuild(|leaf| hasher.leaf(leaf))
478 }
479
480 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 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#[derive(Clone, Debug, PartialEq, Eq)]
644pub struct WriteEvidence {
645 pub write: coven_merge::WriteId,
647 pub prefix: Vec<u8>,
649 pub header: Vec<u8>,
651 pub roots: Vec<[u8; 32]>,
653 pub signature: [u8; coven_crypto::SIGNATURE_LEN],
655 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#[derive(Clone, Debug, PartialEq, Eq)]
699pub struct Creation {
700 pub row: RowId,
702 pub write: coven_merge::WriteId,
704 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 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;