umsh_core/
builder.rs

1use core::{marker::PhantomData, ops::Range};
2
3use crate::{
4    BuildError, ChannelId, Fcf, FloodHops, MicSize, NodeHint, OptionNumber, PacketType, PublicKey,
5    Scf, SecInfo, UnsealedPacket, options::OptionEncoder,
6};
7
8/// Typestate markers used by [`PacketBuilder`] and its specialized builders.
9pub mod state {
10    /// Builder state that still requires a source address.
11    pub struct NeedsSource;
12    /// Builder state that still requires a frame counter.
13    pub struct NeedsCounter;
14    /// Builder state where options and payload can be configured.
15    pub struct Configuring;
16    /// Builder state after payload bytes have been staged.
17    pub struct Complete;
18}
19
20/// Entry point for typestate packet construction.
21///
22/// The builder consumes itself as it transitions through required stages so
23/// invalid packet layouts are rejected at compile time where possible.
24pub struct PacketBuilder<'a> {
25    buf: &'a mut [u8],
26}
27
28impl<'a> PacketBuilder<'a> {
29    /// Start building a packet into `buf`.
30    pub fn new(buf: &'a mut [u8]) -> Self {
31        Self { buf }
32    }
33
34    /// Begin a broadcast packet.
35    pub fn broadcast(self) -> BroadcastBuilder<'a, state::NeedsSource> {
36        Builder::new(self.buf, PacketType::Broadcast)
37    }
38
39    /// Build a MAC ACK packet with all required addressing fixed up front.
40    pub fn mac_ack(self, dst: NodeHint, ack_tag: [u8; 8]) -> MacAckBuilder<'a, state::Configuring> {
41        let mut builder = Builder::new(self.buf, PacketType::MacAck);
42        builder.ack_dst = Some(dst);
43        builder.ack_tag = Some(ack_tag);
44        builder
45    }
46
47    /// Begin a unicast packet to `dst`.
48    pub fn unicast(self, dst: NodeHint) -> UnicastBuilder<'a, state::NeedsSource> {
49        let mut builder = Builder::new(self.buf, PacketType::Unicast);
50        builder.dst = Some(dst);
51        builder
52    }
53
54    /// Begin a multicast packet on `channel`.
55    pub fn multicast(self, channel: ChannelId) -> MulticastBuilder<'a, state::NeedsSource> {
56        let mut builder = Builder::new(self.buf, PacketType::Multicast);
57        builder.channel = Some(channel);
58        builder
59    }
60
61    /// Begin a blind-unicast packet addressed through `channel` to `dst`.
62    pub fn blind_unicast(
63        self,
64        channel: ChannelId,
65        dst: NodeHint,
66    ) -> BlindUnicastBuilder<'a, state::NeedsSource> {
67        let mut builder = Builder::new(self.buf, PacketType::BlindUnicast);
68        builder.channel = Some(channel);
69        builder.dst = Some(dst);
70        builder
71    }
72}
73
74/// Broadcast packet builder alias.
75pub type BroadcastBuilder<'a, S> = Builder<'a, BroadcastKind, S>;
76/// MAC ACK packet builder alias.
77pub type MacAckBuilder<'a, S> = Builder<'a, MacAckKind, S>;
78/// Unicast packet builder alias.
79pub type UnicastBuilder<'a, S> = Builder<'a, UnicastKind, S>;
80/// Multicast packet builder alias.
81pub type MulticastBuilder<'a, S> = Builder<'a, MulticastKind, S>;
82/// Blind-unicast packet builder alias.
83pub type BlindUnicastBuilder<'a, S> = Builder<'a, BlindUnicastKind, S>;
84
85/// Marker type for broadcast builders.
86pub struct BroadcastKind;
87/// Marker type for MAC ACK builders.
88pub struct MacAckKind;
89/// Marker type for unicast builders.
90pub struct UnicastKind;
91/// Marker type for multicast builders.
92pub struct MulticastKind;
93/// Marker type for blind-unicast builders.
94pub struct BlindUnicastKind;
95
96enum SourceValue {
97    Hint(NodeHint),
98    Full(PublicKey),
99}
100
101/// Internal generic builder implementation shared by all packet kinds.
102pub struct Builder<'a, K, S> {
103    buf: &'a mut [u8],
104    packet_type: PacketType,
105    options_used: bool,
106    options_finalized: bool,
107    options_len: usize,
108    last_option_number: Option<u16>,
109    option_error: Option<BuildError>,
110    source: Option<SourceValue>,
111    dst: Option<NodeHint>,
112    channel: Option<ChannelId>,
113    ack_dst: Option<NodeHint>,
114    ack_tag: Option<[u8; 8]>,
115    frame_counter: Option<u32>,
116    encrypted: bool,
117    mic_size: MicSize,
118    salt: Option<u16>,
119    flood_hops: Option<FloodHops>,
120    payload: Option<Range<usize>>,
121    blind_addr: Option<Range<usize>>,
122    _marker: PhantomData<(K, S)>,
123}
124
125impl<'a, K, S> Builder<'a, K, S> {
126    fn new(buf: &'a mut [u8], packet_type: PacketType) -> Self {
127        Self {
128            buf,
129            packet_type,
130            options_used: false,
131            options_finalized: false,
132            options_len: 0,
133            last_option_number: None,
134            option_error: None,
135            source: None,
136            dst: None,
137            channel: None,
138            ack_dst: None,
139            ack_tag: None,
140            frame_counter: None,
141            encrypted: matches!(
142                packet_type,
143                PacketType::BlindUnicast | PacketType::BlindUnicastAckReq
144            ),
145            mic_size: MicSize::Mic16,
146            salt: None,
147            flood_hops: None,
148            payload: None,
149            blind_addr: None,
150            _marker: PhantomData,
151        }
152    }
153
154    fn with_state<NS>(self) -> Builder<'a, K, NS> {
155        Builder {
156            buf: self.buf,
157            packet_type: self.packet_type,
158            options_used: self.options_used,
159            options_finalized: self.options_finalized,
160            options_len: self.options_len,
161            last_option_number: self.last_option_number,
162            option_error: self.option_error,
163            source: self.source,
164            dst: self.dst,
165            channel: self.channel,
166            ack_dst: self.ack_dst,
167            ack_tag: self.ack_tag,
168            frame_counter: self.frame_counter,
169            encrypted: self.encrypted,
170            mic_size: self.mic_size,
171            salt: self.salt,
172            flood_hops: self.flood_hops,
173            payload: self.payload,
174            blind_addr: self.blind_addr,
175            _marker: PhantomData,
176        }
177    }
178
179    fn push_option(&mut self, number: u16, value: &[u8]) {
180        if self.option_error.is_some() {
181            return;
182        }
183        if let Some(last) = self.last_option_number {
184            if number < last {
185                self.option_error = Some(BuildError::OptionOutOfOrder);
186                return;
187            }
188        }
189        let mut live = match self.last_option_number {
190            Some(last_number) => {
191                OptionEncoder::with_last_number(&mut self.buf[1 + self.options_len..], last_number)
192            }
193            None => OptionEncoder::new(&mut self.buf[1 + self.options_len..]),
194        };
195        match live.put(number, value) {
196            Ok(()) => {
197                self.options_len += live.finish();
198                self.options_used = true;
199                self.last_option_number = Some(number);
200            }
201            Err(err) => self.option_error = Some(err.into()),
202        }
203    }
204
205    fn finalize_options(&mut self) -> Result<(), BuildError> {
206        if !self.options_used || self.options_finalized {
207            return Ok(());
208        }
209        let mut encoder = OptionEncoder::new(&mut self.buf[1 + self.options_len..]);
210        encoder.end_marker()?;
211        self.options_len += encoder.finish();
212        self.options_finalized = true;
213        Ok(())
214    }
215
216    fn write_common_prefix(&mut self) -> Result<usize, BuildError> {
217        if let Some(err) = self.option_error {
218            return Err(err);
219        }
220        self.finalize_options()?;
221        let full_source = matches!(self.source, Some(SourceValue::Full(_)));
222        let fcf = Fcf::new(
223            self.packet_type,
224            full_source,
225            self.options_used,
226            self.flood_hops.is_some(),
227        );
228        if self.buf.is_empty() {
229            return Err(BuildError::BufferTooSmall);
230        }
231        self.buf[0] = fcf.0;
232        let mut cursor = 1;
233        cursor += self.options_len;
234        if let Some(fhops) = self.flood_hops {
235            self.buf
236                .get_mut(cursor)
237                .ok_or(BuildError::BufferTooSmall)
238                .map(|slot| *slot = fhops.0)?;
239            cursor += 1;
240        }
241        Ok(cursor)
242    }
243
244    fn write_source(&mut self, cursor: &mut usize) -> Result<(), BuildError> {
245        match self.source {
246            Some(SourceValue::Hint(hint)) => {
247                let end = *cursor + 3;
248                self.buf
249                    .get_mut(*cursor..end)
250                    .ok_or(BuildError::BufferTooSmall)?
251                    .copy_from_slice(&hint.0);
252                *cursor = end;
253            }
254            Some(SourceValue::Full(key)) => {
255                let end = *cursor + 32;
256                self.buf
257                    .get_mut(*cursor..end)
258                    .ok_or(BuildError::BufferTooSmall)?
259                    .copy_from_slice(&key.0);
260                *cursor = end;
261            }
262            None => return Err(BuildError::MissingSource),
263        }
264        Ok(())
265    }
266
267    fn stage_payload(&mut self, data: &[u8]) {
268        let scratch_start = match self.buf.len().checked_sub(data.len()) {
269            Some(value) => value,
270            None => {
271                self.option_error = Some(BuildError::BufferTooSmall);
272                return;
273            }
274        };
275        if let Some(slot) = self.buf.get_mut(scratch_start..scratch_start + data.len()) {
276            slot.copy_from_slice(data);
277            self.payload = Some(scratch_start..scratch_start + data.len());
278        } else {
279            self.option_error = Some(BuildError::BufferTooSmall);
280        }
281    }
282
283    fn copy_staged_payload(&mut self, cursor: &mut usize) -> Result<Range<usize>, BuildError> {
284        let payload = self.payload.clone().ok_or(BuildError::MissingPayload)?;
285        let len = payload.end - payload.start;
286        let start = *cursor;
287        let end = start + len;
288        if end > self.buf.len() {
289            return Err(BuildError::BufferTooSmall);
290        }
291        self.buf.copy_within(payload, start);
292        *cursor = end;
293        Ok(start..end)
294    }
295
296    fn stage_blind_addr(&mut self, cursor: &mut usize) -> Result<Range<usize>, BuildError> {
297        let dst = self.dst.ok_or(BuildError::MissingDestination)?;
298        let start = *cursor;
299        let dst_end = start + 3;
300        self.buf
301            .get_mut(start..dst_end)
302            .ok_or(BuildError::BufferTooSmall)?
303            .copy_from_slice(&dst.0);
304        *cursor = dst_end;
305        self.write_source(cursor)?;
306        let end = *cursor;
307        Ok(start..end)
308    }
309}
310
311impl<'a> BroadcastBuilder<'a, state::NeedsSource> {
312    /// Encode the source address as a three-byte hint.
313    pub fn source_hint(mut self, hint: NodeHint) -> BroadcastBuilder<'a, state::Configuring> {
314        self.source = Some(SourceValue::Hint(hint));
315        self.with_state()
316    }
317
318    /// Encode the source address as a full public key.
319    pub fn source_full(mut self, key: &PublicKey) -> BroadcastBuilder<'a, state::Configuring> {
320        self.source = Some(SourceValue::Full(*key));
321        self.with_state()
322    }
323}
324
325impl<'a> UnicastBuilder<'a, state::NeedsSource> {
326    /// Encode the source address as a three-byte hint.
327    pub fn source_hint(mut self, hint: NodeHint) -> UnicastBuilder<'a, state::NeedsCounter> {
328        self.source = Some(SourceValue::Hint(hint));
329        self.with_state()
330    }
331
332    /// Encode the source address as a full public key.
333    pub fn source_full(mut self, key: &PublicKey) -> UnicastBuilder<'a, state::NeedsCounter> {
334        self.source = Some(SourceValue::Full(*key));
335        self.with_state()
336    }
337}
338
339impl<'a> MulticastBuilder<'a, state::NeedsSource> {
340    /// Encode the source address as a three-byte hint.
341    pub fn source_hint(mut self, hint: NodeHint) -> MulticastBuilder<'a, state::NeedsCounter> {
342        self.source = Some(SourceValue::Hint(hint));
343        self.with_state()
344    }
345
346    /// Encode the source address as a full public key.
347    pub fn source_full(mut self, key: &PublicKey) -> MulticastBuilder<'a, state::NeedsCounter> {
348        self.source = Some(SourceValue::Full(*key));
349        self.with_state()
350    }
351}
352
353impl<'a> BlindUnicastBuilder<'a, state::NeedsSource> {
354    /// Encode the source address as a three-byte hint.
355    pub fn source_hint(mut self, hint: NodeHint) -> BlindUnicastBuilder<'a, state::NeedsCounter> {
356        self.source = Some(SourceValue::Hint(hint));
357        self.with_state()
358    }
359
360    /// Encode the source address as a full public key.
361    pub fn source_full(mut self, key: &PublicKey) -> BlindUnicastBuilder<'a, state::NeedsCounter> {
362        self.source = Some(SourceValue::Full(*key));
363        self.with_state()
364    }
365}
366
367impl<'a> UnicastBuilder<'a, state::NeedsCounter> {
368    /// Set the frame counter for the secure packet.
369    pub fn frame_counter(mut self, counter: u32) -> UnicastBuilder<'a, state::Configuring> {
370        self.frame_counter = Some(counter);
371        self.with_state()
372    }
373}
374
375impl<'a> MulticastBuilder<'a, state::NeedsCounter> {
376    /// Set the frame counter for the secure packet.
377    pub fn frame_counter(mut self, counter: u32) -> MulticastBuilder<'a, state::Configuring> {
378        self.frame_counter = Some(counter);
379        self.with_state()
380    }
381}
382
383impl<'a> BlindUnicastBuilder<'a, state::NeedsCounter> {
384    /// Set the frame counter for the secure packet.
385    pub fn frame_counter(mut self, counter: u32) -> BlindUnicastBuilder<'a, state::Configuring> {
386        self.frame_counter = Some(counter);
387        self.with_state()
388    }
389}
390
391macro_rules! impl_configuring_common {
392    ($name:ident<$state:ty>) => {
393        impl<'a> $name<'a, $state> {
394            /// Set the initial flood-hop budget.
395            pub fn flood_hops(mut self, remaining: u8) -> Self {
396                if let Some(value) = FloodHops::new(remaining, 0) {
397                    self.flood_hops = Some(value);
398                }
399                self
400            }
401
402            /// Add the region-code option.
403            pub fn region_code(mut self, code: [u8; 2]) -> Self {
404                self.push_option(OptionNumber::RegionCode.as_u16(), &code);
405                self
406            }
407
408            /// Add an empty trace-route option.
409            pub fn trace_route(mut self) -> Self {
410                self.push_option(OptionNumber::TraceRoute.as_u16(), &[]);
411                self
412            }
413
414            /// Add a source-route option from a router-hint slice.
415            pub fn source_route(mut self, hops: &[crate::RouterHint]) -> Self {
416                let mut encoded = [0u8; 30];
417                let needed = hops.len() * 2;
418                if needed > encoded.len() {
419                    self.option_error = Some(BuildError::BufferTooSmall);
420                    return self;
421                }
422                for (index, hop) in hops.iter().enumerate() {
423                    encoded[index * 2..index * 2 + 2].copy_from_slice(&hop.0);
424                }
425                self.push_option(OptionNumber::SourceRoute.as_u16(), &encoded[..needed]);
426                self
427            }
428
429            /// Add an arbitrary option number/value pair.
430            pub fn option(mut self, number: OptionNumber, value: &[u8]) -> Self {
431                self.push_option(number.as_u16(), value);
432                self
433            }
434        }
435    };
436}
437
438impl_configuring_common!(BroadcastBuilder<state::Configuring>);
439impl_configuring_common!(MacAckBuilder<state::Configuring>);
440impl_configuring_common!(UnicastBuilder<state::Configuring>);
441impl_configuring_common!(MulticastBuilder<state::Configuring>);
442impl_configuring_common!(BlindUnicastBuilder<state::Configuring>);
443
444impl<'a> UnicastBuilder<'a, state::Configuring> {
445    /// Upgrade the packet type to ACK-requested unicast.
446    pub fn ack_requested(mut self) -> Self {
447        self.packet_type = PacketType::UnicastAckReq;
448        self
449    }
450
451    /// Mark the packet body for encryption.
452    pub fn encrypted(mut self) -> Self {
453        self.encrypted = true;
454        self
455    }
456
457    /// Select the MIC size reserved in the packet footer.
458    pub fn mic_size(mut self, size: MicSize) -> Self {
459        self.mic_size = size;
460        self
461    }
462
463    /// Attach an explicit salt value to SECINFO.
464    pub fn salt(mut self, salt: u16) -> Self {
465        self.salt = Some(salt);
466        self
467    }
468
469    /// Stage the application payload and advance to the terminal builder state.
470    pub fn payload(mut self, data: &[u8]) -> UnicastBuilder<'a, state::Complete> {
471        self.stage_payload(data);
472        self.with_state()
473    }
474}
475
476impl<'a> MulticastBuilder<'a, state::Configuring> {
477    /// Mark the packet body for encryption.
478    pub fn encrypted(mut self) -> Self {
479        self.encrypted = true;
480        self
481    }
482
483    /// Select the MIC size reserved in the packet footer.
484    pub fn mic_size(mut self, size: MicSize) -> Self {
485        self.mic_size = size;
486        self
487    }
488
489    /// Attach an explicit salt value to SECINFO.
490    pub fn salt(mut self, salt: u16) -> Self {
491        self.salt = Some(salt);
492        self
493    }
494
495    /// Stage the application payload and advance to the terminal builder state.
496    pub fn payload(mut self, data: &[u8]) -> MulticastBuilder<'a, state::Complete> {
497        self.stage_payload(data);
498        self.with_state()
499    }
500}
501
502impl<'a> BlindUnicastBuilder<'a, state::Configuring> {
503    /// Upgrade the packet type to ACK-requested blind unicast.
504    pub fn ack_requested(mut self) -> Self {
505        self.packet_type = PacketType::BlindUnicastAckReq;
506        self
507    }
508
509    /// Mark the body and blinded address block for encryption.
510    pub fn encrypted(mut self) -> Self {
511        self.encrypted = true;
512        self
513    }
514
515    /// Emit a blind-unicast packet without encrypting the payload.
516    ///
517    /// This exists primarily for tests and for explicit policy-rejection
518    /// scenarios where higher layers need to construct a frame they expect to
519    /// reject. Normal blind-unicast traffic should remain encrypted.
520    pub fn unencrypted(mut self) -> Self {
521        self.encrypted = false;
522        self
523    }
524
525    /// Select the MIC size reserved in the packet footer.
526    pub fn mic_size(mut self, size: MicSize) -> Self {
527        self.mic_size = size;
528        self
529    }
530
531    /// Attach an explicit salt value to SECINFO.
532    pub fn salt(mut self, salt: u16) -> Self {
533        self.salt = Some(salt);
534        self
535    }
536
537    /// Stage the application payload and advance to the terminal builder state.
538    pub fn payload(mut self, data: &[u8]) -> BlindUnicastBuilder<'a, state::Complete> {
539        self.stage_payload(data);
540        self.with_state()
541    }
542}
543
544impl<'a> BroadcastBuilder<'a, state::Configuring> {
545    /// Stage a broadcast payload.
546    pub fn payload(mut self, data: &[u8]) -> BroadcastBuilder<'a, state::Complete> {
547        self.stage_payload(data);
548        self.with_state()
549    }
550
551    /// Finalize the broadcast packet and return the written frame bytes.
552    pub fn build(mut self) -> Result<&'a [u8], BuildError> {
553        let mut cursor = self.write_common_prefix()?;
554        self.write_source(&mut cursor)?;
555        if self.payload.is_some() {
556            let _ = self.copy_staged_payload(&mut cursor)?;
557        }
558        Ok(&self.buf[..cursor])
559    }
560}
561
562impl<'a> BroadcastBuilder<'a, state::Complete> {
563    /// Finalize the broadcast packet and return the written frame bytes.
564    pub fn build(self) -> Result<&'a [u8], BuildError> {
565        self.with_state::<state::Configuring>().build()
566    }
567}
568
569impl<'a> MacAckBuilder<'a, state::Configuring> {
570    /// Finalize the MAC ACK packet and return the written frame bytes.
571    pub fn build(mut self) -> Result<&'a [u8], BuildError> {
572        let mut cursor = self.write_common_prefix()?;
573        let dst = self.ack_dst.ok_or(BuildError::MissingDestination)?;
574        self.buf
575            .get_mut(cursor..cursor + 3)
576            .ok_or(BuildError::BufferTooSmall)?
577            .copy_from_slice(&dst.0);
578        cursor += 3;
579        let ack_tag = self.ack_tag.ok_or(BuildError::MissingAckTag)?;
580        self.buf
581            .get_mut(cursor..cursor + 8)
582            .ok_or(BuildError::BufferTooSmall)?
583            .copy_from_slice(&ack_tag);
584        cursor += 8;
585        Ok(&self.buf[..cursor])
586    }
587}
588
589impl<'a> UnicastBuilder<'a, state::Complete> {
590    pub fn build(self) -> Result<UnsealedPacket<'a>, BuildError> {
591        self.with_state::<state::Configuring>().build()
592    }
593}
594
595impl<'a> UnicastBuilder<'a, state::Configuring> {
596    pub fn build(mut self) -> Result<UnsealedPacket<'a>, BuildError> {
597        let mut cursor = self.write_common_prefix()?;
598        let dst = self.dst.ok_or(BuildError::MissingDestination)?;
599        self.buf
600            .get_mut(cursor..cursor + 3)
601            .ok_or(BuildError::BufferTooSmall)?
602            .copy_from_slice(&dst.0);
603        cursor += 3;
604        self.write_source(&mut cursor)?;
605        let scf = Scf::new(self.encrypted, self.mic_size, self.salt.is_some());
606        let sec_info = SecInfo {
607            scf,
608            frame_counter: self.frame_counter.ok_or(BuildError::MissingFrameCounter)?,
609            salt: self.salt,
610        };
611        let sec_start = cursor;
612        cursor += sec_info.encode(
613            self.buf
614                .get_mut(cursor..)
615                .ok_or(BuildError::BufferTooSmall)?,
616        )?;
617        let body_range = self.copy_staged_payload(&mut cursor)?;
618        let mic_start = cursor;
619        let mic_end = mic_start + self.mic_size.byte_len();
620        self.buf
621            .get_mut(mic_start..mic_end)
622            .ok_or(BuildError::BufferTooSmall)?
623            .fill(0);
624        cursor = mic_end;
625        Ok(UnsealedPacket::new(
626            self.buf,
627            cursor,
628            body_range,
629            None,
630            mic_start..mic_end,
631            sec_start..sec_start + sec_info.wire_len(),
632            1..1 + self.options_len,
633        ))
634    }
635}
636
637impl<'a> MulticastBuilder<'a, state::Complete> {
638    pub fn build(self) -> Result<UnsealedPacket<'a>, BuildError> {
639        self.with_state::<state::Configuring>().build()
640    }
641}
642
643impl<'a> MulticastBuilder<'a, state::Configuring> {
644    pub fn build(mut self) -> Result<UnsealedPacket<'a>, BuildError> {
645        let mut cursor = self.write_common_prefix()?;
646        let channel = self.channel.ok_or(BuildError::MissingChannel)?;
647        self.buf
648            .get_mut(cursor..cursor + 2)
649            .ok_or(BuildError::BufferTooSmall)?
650            .copy_from_slice(&channel.0);
651        cursor += 2;
652        let scf = Scf::new(self.encrypted, self.mic_size, self.salt.is_some());
653        let sec_info = SecInfo {
654            scf,
655            frame_counter: self.frame_counter.ok_or(BuildError::MissingFrameCounter)?,
656            salt: self.salt,
657        };
658        let sec_start = cursor;
659        cursor += sec_info.encode(
660            self.buf
661                .get_mut(cursor..)
662                .ok_or(BuildError::BufferTooSmall)?,
663        )?;
664        let body_start = cursor;
665        self.write_source(&mut cursor)?;
666        let payload_range = self.copy_staged_payload(&mut cursor)?;
667        let body_range = if self.encrypted {
668            body_start..payload_range.end
669        } else {
670            payload_range
671        };
672        let mic_start = cursor;
673        let mic_end = mic_start + self.mic_size.byte_len();
674        self.buf
675            .get_mut(mic_start..mic_end)
676            .ok_or(BuildError::BufferTooSmall)?
677            .fill(0);
678        cursor = mic_end;
679        Ok(UnsealedPacket::new(
680            self.buf,
681            cursor,
682            body_range,
683            None,
684            mic_start..mic_end,
685            sec_start..sec_start + sec_info.wire_len(),
686            1..1 + self.options_len,
687        ))
688    }
689}
690
691impl<'a> BlindUnicastBuilder<'a, state::Complete> {
692    pub fn build(self) -> Result<UnsealedPacket<'a>, BuildError> {
693        self.with_state::<state::Configuring>().build()
694    }
695}
696
697impl<'a> BlindUnicastBuilder<'a, state::Configuring> {
698    pub fn build(mut self) -> Result<UnsealedPacket<'a>, BuildError> {
699        let mut cursor = self.write_common_prefix()?;
700        let channel = self.channel.ok_or(BuildError::MissingChannel)?;
701        self.buf
702            .get_mut(cursor..cursor + 2)
703            .ok_or(BuildError::BufferTooSmall)?
704            .copy_from_slice(&channel.0);
705        cursor += 2;
706        let scf = Scf::new(self.encrypted, self.mic_size, self.salt.is_some());
707        let sec_info = SecInfo {
708            scf,
709            frame_counter: self.frame_counter.ok_or(BuildError::MissingFrameCounter)?,
710            salt: self.salt,
711        };
712        let sec_start = cursor;
713        cursor += sec_info.encode(
714            self.buf
715                .get_mut(cursor..)
716                .ok_or(BuildError::BufferTooSmall)?,
717        )?;
718        let blind_addr_range = self.stage_blind_addr(&mut cursor)?;
719        let body_range = self.copy_staged_payload(&mut cursor)?;
720        let mic_start = cursor;
721        let mic_end = mic_start + self.mic_size.byte_len();
722        self.buf
723            .get_mut(mic_start..mic_end)
724            .ok_or(BuildError::BufferTooSmall)?
725            .fill(0);
726        cursor = mic_end;
727        Ok(UnsealedPacket::new(
728            self.buf,
729            cursor,
730            body_range,
731            Some(blind_addr_range),
732            mic_start..mic_end,
733            sec_start..sec_start + sec_info.wire_len(),
734            1..1 + self.options_len,
735        ))
736    }
737}