uts_core/codec/v1/timestamp/
builder.rs1use crate::{
4 alloc::{Allocator, Global, vec, vec::Vec},
5 codec::v1::{
6 Attestation, Timestamp,
7 opcode::{DigestOpExt, OpCode},
8 timestamp::Step,
9 },
10 error::EncodeError,
11};
12use allocator_api2::SliceExt;
13use std::sync::OnceLock;
14use uts_bmt::{NodePosition, SiblingIter};
15
16#[derive(Debug, Clone)]
17pub struct TimestampBuilder<A: Allocator = Global> {
18 steps: Vec<LinearStep<A>, A>,
19}
20
21#[derive(Debug, Clone)]
22struct LinearStep<A: Allocator> {
23 op: OpCode,
24 data: Vec<u8, A>,
25}
26
27impl<A: Allocator + Clone> TimestampBuilder<A> {
28 pub fn new_in(alloc: A) -> TimestampBuilder<A> {
30 TimestampBuilder {
31 steps: Vec::new_in(alloc),
32 }
33 }
34
35 pub(crate) fn push_immediate_step(&mut self, op: OpCode, data: Vec<u8, A>) -> &mut Self {
41 assert!(op.has_immediate());
42 self.steps.push(LinearStep { op, data });
43 self
44 }
45
46 pub fn push_step(&mut self, op: OpCode) -> &mut Self {
54 self.steps.push(LinearStep {
55 op,
56 data: Vec::new_in(self.allocator().clone()),
57 });
58 self
59 }
60
61 pub fn digest<D: DigestOpExt>(&mut self) -> &mut Self {
63 self.push_step(D::OPCODE.to_opcode());
64 self
65 }
66
67 pub fn merkle_proof<D: DigestOpExt>(&mut self, proof: SiblingIter<'_, D>) -> &mut Self {
69 let alloc = self.allocator().clone();
70 for (side, sibling_hash) in proof {
71 let sibling_hash = SliceExt::to_vec_in(sibling_hash.as_slice(), alloc.clone());
72 match side {
73 NodePosition::Left => self
74 .prepend(vec![in alloc.clone(); uts_bmt::INNER_NODE_PREFIX])
75 .append(sibling_hash),
76 NodePosition::Right => self
77 .prepend(sibling_hash)
78 .prepend(vec![in alloc.clone(); uts_bmt::INNER_NODE_PREFIX]),
79 }
80 .digest::<D>();
81 }
82 self
83 }
84
85 pub fn commitment(&self, input: impl AsRef<[u8]>) -> Vec<u8, A> {
100 let alloc = self.allocator().clone();
101 let mut commitment = SliceExt::to_vec_in(input.as_ref(), alloc.clone());
102 for step in &self.steps {
103 commitment = step.op.execute_in(&commitment, &step.data, alloc.clone());
104 }
105 commitment
106 }
107
108 pub fn attest<'a, T: Attestation<'a>>(
115 self,
116 attestation: T,
117 ) -> Result<Timestamp<A>, EncodeError> {
118 let current = Timestamp::Attestation(attestation.to_raw_in(self.allocator().clone())?);
119 Ok(self.concat(current))
120 }
121
122 pub fn concat(self, timestamp: Timestamp<A>) -> Timestamp<A> {
124 let alloc = self.allocator().clone();
125
126 let mut current = timestamp;
127
128 for step in self.steps.into_iter().rev() {
129 let step_node = Step {
130 op: step.op,
131 data: step.data,
132 input: OnceLock::new(),
133 next: {
134 let mut v = Vec::with_capacity_in(1, alloc.clone());
135 v.push(current);
136 v
137 },
138 };
139 current = Timestamp::Step(step_node);
140 }
141
142 current
143 }
144
145 #[inline]
146 fn allocator(&self) -> &A {
147 self.steps.allocator()
148 }
149}