@@ -136,16 +136,16 @@ impl EnvelopePayload {
136136 ///
137137 /// Returns an error if encoding fails (should not happen with `Vec<u8>` writers).
138138 pub fn to_bytes ( & self ) -> Result < Vec < u8 > , minicbor:: encode:: Error < Infallible > > {
139- minicbor:: to_vec_with ( self , & mut CborContext :: Tagged )
139+ minicbor:: to_vec ( self )
140140 }
141141
142142 /// Decodes `[peer, seq, ver, payload]` from the signed payload array.
143- fn decode_from_signed (
143+ fn decode_from_signed < C > (
144144 decoder : & mut minicbor:: Decoder < ' _ > ,
145- ctx : & mut CborContext ,
145+ ctx : & mut C ,
146146 ) -> Result < Self , minicbor:: decode:: Error > {
147147 let peer: PublicKey = decoder. decode_with ( ctx) ?;
148- let seq: UuidV7 = decoder. decode_with ( ctx ) ?;
148+ let seq: UuidV7 = decoder. decode_with ( & mut CborContext :: Tagged ) ?;
149149 let ver = decoder. u64 ( ) ?;
150150
151151 if ver != PROTOCOL_VERSION {
@@ -178,26 +178,26 @@ impl EnvelopePayload {
178178 }
179179}
180180
181- impl Encode < CborContext > for EnvelopePayload {
181+ impl < C > Encode < C > for EnvelopePayload {
182182 fn encode < W : Write > (
183183 & self ,
184184 e : & mut Encoder < W > ,
185- ctx : & mut CborContext ,
185+ ctx : & mut C ,
186186 ) -> Result < ( ) , minicbor:: encode:: Error < W :: Error > > {
187187 e. array ( 4 ) ?;
188- e. encode ( & self . peer ) ?
189- . encode_with ( self . seq , ctx ) ?
188+ e. encode_with ( & self . peer , ctx ) ?
189+ . encode_with ( self . seq , & mut CborContext :: Tagged ) ?
190190 . u64 ( self . ver ) ?;
191191 <W as Write >:: write_all ( e. writer_mut ( ) , & self . payload )
192192 . map_err ( minicbor:: encode:: Error :: write) ?;
193193 Ok ( ( ) )
194194 }
195195}
196196
197- impl < ' b > Decode < ' b , CborContext > for EnvelopePayload {
197+ impl < ' b , C > Decode < ' b , C > for EnvelopePayload {
198198 fn decode (
199199 d : & mut minicbor:: Decoder < ' b > ,
200- ctx : & mut CborContext ,
200+ ctx : & mut C ,
201201 ) -> Result < Self , minicbor:: decode:: Error > {
202202 let len = d. array ( ) ?;
203203 match len {
@@ -215,7 +215,7 @@ impl<'b> Decode<'b, CborContext> for EnvelopePayload {
215215 }
216216
217217 let peer: PublicKey = d. decode_with ( ctx) ?;
218- let seq: UuidV7 = d. decode_with ( ctx ) ?;
218+ let seq: UuidV7 = d. decode_with ( & mut CborContext :: Tagged ) ?;
219219 let ver = d. u64 ( ) ?;
220220
221221 if ver != PROTOCOL_VERSION {
@@ -248,6 +248,32 @@ impl<'b> Decode<'b, CborContext> for EnvelopePayload {
248248 }
249249}
250250
251+ /// Helper struct for encoding the inner [peer, seq, ver, payload, sig] array.
252+ struct SignedPayloadView < ' a > {
253+ /// Reference to the envelope payload (providing peer, seq, ver, and body).
254+ payload : & ' a EnvelopePayload ,
255+ /// Reference to the signature verifying the payload.
256+ signature : & ' a Signature ,
257+ }
258+
259+ impl < C > Encode < C > for SignedPayloadView < ' _ > {
260+ fn encode < W : Write > (
261+ & self ,
262+ e : & mut Encoder < W > ,
263+ _ctx : & mut C ,
264+ ) -> Result < ( ) , minicbor:: encode:: Error < W :: Error > > {
265+ e. array ( 5 ) ?;
266+ e. encode ( & self . payload . peer ) ?;
267+ e. encode_with ( self . payload . seq , & mut CborContext :: Tagged ) ?;
268+ e. u64 ( self . payload . ver ) ?;
269+ e. writer_mut ( )
270+ . write_all ( & self . payload . payload )
271+ . map_err ( minicbor:: encode:: Error :: write) ?;
272+ e. encode ( self . signature ) ?;
273+ Ok ( ( ) )
274+ }
275+ }
276+
251277/// The final outer message structure.
252278///
253279/// `Envelope` owns both the `[peer, seq, ver, payload, signature]` array (which
@@ -312,46 +338,33 @@ impl Envelope {
312338 ///
313339 /// Returns an error if encoding fails (should not happen with `Vec<u8>` writers).
314340 pub fn to_bytes ( & self ) -> Result < Vec < u8 > , minicbor:: encode:: Error < Infallible > > {
315- let mut encoder = Encoder :: new ( Vec :: new ( ) ) ;
316- encoder. bytes ( & self . signed_payload_bytes ( ) ?) ?;
317- Ok ( encoder. into_writer ( ) )
318- }
319-
320- /// Encodes the `[peer, seq, ver, payload, signature]` array.
321- fn signed_payload_bytes ( & self ) -> Result < Vec < u8 > , minicbor:: encode:: Error < Infallible > > {
322- let mut encoder = Encoder :: new ( Vec :: new ( ) ) ;
323- encoder. array ( 5 ) ?;
324- encoder. encode ( & self . payload . peer ) ?;
325- encoder. encode_with ( self . payload . seq , & mut CborContext :: Tagged ) ?;
326- encoder. u64 ( self . payload . ver ) ?;
327- encoder
328- . writer_mut ( )
329- . write_all ( & self . payload . payload )
330- . map_err ( minicbor:: encode:: Error :: write) ?;
331- encoder. encode ( & self . signature ) ?;
332- Ok ( encoder. into_writer ( ) )
341+ minicbor:: to_vec ( self )
333342 }
334343}
335344
336345impl < C > Encode < C > for Envelope {
337346 fn encode < W : Write > (
338347 & self ,
339348 e : & mut Encoder < W > ,
340- _ctx : & mut C ,
349+ ctx : & mut C ,
341350 ) -> Result < ( ) , minicbor:: encode:: Error < W :: Error > > {
342- // Spec framing: signed payload array wrapped inside an outer `bstr`.
343- let signed_bytes = self
344- . signed_payload_bytes ( )
345- . map_err ( |err| minicbor:: encode:: Error :: message ( err. to_string ( ) ) ) ?;
346- e. bytes ( & signed_bytes) ?;
351+ let view = SignedPayloadView {
352+ payload : & self . payload ,
353+ signature : & self . signature ,
354+ } ;
355+
356+ let inner_bytes = minicbor:: to_vec_with ( & view, ctx)
357+ . map_err ( |e| minicbor:: encode:: Error :: message ( e. to_string ( ) ) ) ?;
358+
359+ e. bytes ( & inner_bytes) ?;
347360 Ok ( ( ) )
348361 }
349362}
350363
351- impl < ' b > Decode < ' b , CborContext > for Envelope {
364+ impl < ' b , C > Decode < ' b , C > for Envelope {
352365 fn decode (
353366 d : & mut minicbor:: Decoder < ' b > ,
354- ctx : & mut CborContext ,
367+ ctx : & mut C ,
355368 ) -> Result < Self , minicbor:: decode:: Error > {
356369 let signed_payload_bytes = d. bytes ( ) ?;
357370 let mut signed_decoder = minicbor:: Decoder :: new ( signed_payload_bytes) ;
@@ -506,4 +519,80 @@ mod tests {
506519 let result = EnvelopePayload :: new ( signing_key. verifying_key ( ) , payload_bytes) ;
507520 assert ! ( result. is_err( ) , "non-map payload must be rejected" ) ;
508521 }
522+
523+ #[ test]
524+ fn decode_rejects_missing_outer_bstr ( ) {
525+ // Attempt to decode the array directly without the outer bstr wrapping
526+ let signing_key = signing_key ( ) ;
527+ let payload_body = sample_payload_body ( ) ;
528+ let payload =
529+ EnvelopePayload :: new ( signing_key. verifying_key ( ) , payload_body) . expect ( "payload" ) ;
530+ let signature = signing_key
531+ . try_sign ( & payload. to_bytes ( ) . expect ( "bytes" ) )
532+ . expect ( "signature" ) ;
533+ let signature = Signature ( signature) ;
534+
535+ let view = SignedPayloadView {
536+ payload : & payload,
537+ signature : & signature,
538+ } ;
539+ let encoded_array = minicbor:: to_vec ( & view) . unwrap ( ) ;
540+
541+ let mut decoder = Decoder :: new ( & encoded_array) ;
542+ // We use () context here for simplicity
543+ let result: Result < Envelope , _ > = decoder. decode_with ( & mut ( ) ) ;
544+
545+ // This should fail because `decode` expects `d.bytes()` (bstr) first,
546+ // but it will encounter an array tag (0x85).
547+ assert ! ( result. is_err( ) , "must reject content without outer bstr" ) ;
548+ }
549+
550+ #[ test]
551+ fn decode_rejects_malformed_inner_array_len ( ) {
552+ let signing_key = signing_key ( ) ;
553+ let payload_body = sample_payload_body ( ) ;
554+ let payload =
555+ EnvelopePayload :: new ( signing_key. verifying_key ( ) , payload_body) . expect ( "payload" ) ;
556+
557+ // Construct a fake array of length 4 instead of 5
558+ let mut bad_array = Encoder :: new ( Vec :: new ( ) ) ;
559+ bad_array. array ( 4 ) . unwrap ( ) ; // Wrong length
560+ bad_array. encode ( & payload. peer ) . unwrap ( ) ;
561+ bad_array
562+ . encode_with ( payload. seq , & mut CborContext :: Tagged )
563+ . unwrap ( ) ;
564+ bad_array. u64 ( PROTOCOL_VERSION ) . unwrap ( ) ;
565+ // Skip payload & signature to force length error or skip signature
566+
567+ let mut envelope = Encoder :: new ( Vec :: new ( ) ) ;
568+ envelope. bytes ( & bad_array. into_writer ( ) ) . unwrap ( ) ;
569+ let bytes = envelope. into_writer ( ) ;
570+
571+ let mut decoder = Decoder :: new ( & bytes) ;
572+ let result: Result < Envelope , _ > = decoder. decode_with ( & mut ( ) ) ;
573+ assert ! ( result. is_err( ) , "must reject wrong array length" ) ;
574+ }
575+
576+ #[ test]
577+ fn compiles_with_custom_context ( ) {
578+ // Verify that we can pass a custom struct as context C
579+ struct MyMetrics {
580+ _bytes_read : usize ,
581+ }
582+
583+ let signing_key = signing_key ( ) ;
584+ let payload_body = sample_payload_body ( ) ;
585+ let payload = EnvelopePayload :: new ( signing_key. verifying_key ( ) , payload_body. clone ( ) )
586+ . expect ( "payload" ) ;
587+ let signature = signing_key. sign ( & payload. to_bytes ( ) . unwrap ( ) ) ;
588+ let envelope = Envelope :: new ( payload, signature) . expect ( "envelope" ) ;
589+
590+ let bytes = envelope. to_bytes ( ) . expect ( "bytes" ) ;
591+
592+ let mut ctx = MyMetrics { _bytes_read : 0 } ;
593+ let mut decoder = Decoder :: new ( & bytes) ;
594+
595+ // This validates that the generic <C> is properly propagated
596+ let _decoded: Envelope = decoder. decode_with ( & mut ctx) . expect ( "decode with context" ) ;
597+ }
509598}
0 commit comments