1use crate::{scoped, with_output_vec, with_output_vec_fallible, FfiSlice};
76use alloc::vec::Vec;
77
78use internal::HpkeKey;
79
80#[derive(Clone, Copy)]
82#[repr(u16)]
83pub enum Kem {
84 P256HkdfSha256 = 16, X25519HkdfSha256 = 32, XWing = 25722, MlKem768 = 65, MlKem1024 = 66, }
95
96impl Kem {
97 fn as_ffi_ptr(&self) -> *const bssl_sys::EVP_HPKE_KEM {
98 unsafe {
100 match self {
101 Kem::P256HkdfSha256 => bssl_sys::EVP_hpke_p256_hkdf_sha256(),
102 Kem::X25519HkdfSha256 => bssl_sys::EVP_hpke_x25519_hkdf_sha256(),
103 Kem::XWing => bssl_sys::EVP_hpke_xwing(),
104 Kem::MlKem768 => bssl_sys::EVP_hpke_mlkem768(),
105 Kem::MlKem1024 => bssl_sys::EVP_hpke_mlkem1024(),
106 }
107 }
108 }
109
110 fn from_rfc_id(n: u16) -> Option<Kem> {
111 match n {
112 n if n == Kem::P256HkdfSha256 as u16 => Some(Self::P256HkdfSha256),
113 n if n == Kem::X25519HkdfSha256 as u16 => Some(Self::X25519HkdfSha256),
114 n if n == Kem::XWing as u16 => Some(Self::XWing),
115 n if n == Kem::MlKem768 as u16 => Some(Self::MlKem768),
116 n if n == Kem::MlKem1024 as u16 => Some(Self::MlKem1024),
117 _ => None,
118 }
119 }
120
121 pub fn generate_keypair(&self) -> (Vec<u8>, Vec<u8>) {
123 let mut key = scoped::EvpHpkeKey::new();
124 let ret =
127 unsafe { bssl_sys::EVP_HPKE_KEY_generate(key.as_mut_ffi_ptr(), self.as_ffi_ptr()) };
128 assert_eq!(ret, 1);
131
132 let pub_key = Self::get_value_from_key(
133 &key,
134 bssl_sys::EVP_HPKE_KEY_public_key,
135 bssl_sys::EVP_HPKE_MAX_PUBLIC_KEY_LENGTH as usize,
136 );
137 let priv_key = Self::get_value_from_key(
138 &key,
139 bssl_sys::EVP_HPKE_KEY_private_key,
140 bssl_sys::EVP_HPKE_MAX_PRIVATE_KEY_LENGTH as usize,
141 );
142 (pub_key, priv_key)
143 }
144
145 pub fn public_from_private(&self, priv_key: &[u8]) -> Option<Vec<u8>> {
148 let HpkeKey { key } = self.parse_from_private_key(priv_key)?;
149
150 let pub_key = Self::get_value_from_key(
151 &key,
152 bssl_sys::EVP_HPKE_KEY_public_key,
153 bssl_sys::EVP_HPKE_MAX_PUBLIC_KEY_LENGTH as usize,
154 );
155 Some(pub_key)
156 }
157
158 pub fn parse_from_private_key(&self, priv_key: &[u8]) -> Option<HpkeKey> {
162 let mut key = scoped::EvpHpkeKey::new();
163 let ret = unsafe {
166 bssl_sys::EVP_HPKE_KEY_init(
167 key.as_mut_ffi_ptr(),
168 self.as_ffi_ptr(),
169 priv_key.as_ffi_ptr(),
170 priv_key.len(),
171 )
172 };
173 (ret == 1).then_some(HpkeKey { key })
174 }
175
176 fn get_value_from_key(
177 key: &scoped::EvpHpkeKey,
178 accessor: unsafe extern "C" fn(
179 *const bssl_sys::EVP_HPKE_KEY,
180 *mut u8,
182 *mut usize,
184 usize,
186 ) -> core::ffi::c_int,
187 max_len: usize,
188 ) -> Vec<u8> {
189 unsafe {
190 with_output_vec(max_len, |out| {
191 let mut out_len = 0usize;
192 let ret = accessor(key.as_ffi_ptr(), out, &mut out_len, max_len);
193 assert_eq!(ret, 1);
195 assert!(out_len <= max_len);
196 out_len
198 })
199 }
200 }
201}
202
203#[doc(hidden)]
204pub mod internal {
205 use crate::scoped;
206
207 pub struct HpkeKey {
209 pub(crate) key: scoped::EvpHpkeKey,
210 }
211
212 impl HpkeKey {
213 pub unsafe fn as_ffi_ptr(&self) -> *const bssl_sys::EVP_HPKE_KEY {
215 self.key.as_ffi_ptr()
216 }
217 }
218}
219
220#[derive(Clone, Copy)]
224#[repr(u16)]
225pub enum Kdf {
226 HkdfSha256 = 1,
229}
230
231#[derive(Clone, Copy)]
235pub enum Aead {
236 Aes128Gcm = 1,
238 Aes256Gcm = 2,
240 Chacha20Poly1305 = 3,
242}
243
244impl Aead {
245 fn from_rfc_id(n: u16) -> Option<Aead> {
246 let ret = match n {
247 1 => Aead::Aes128Gcm,
248 2 => Aead::Aes256Gcm,
249 3 => Aead::Chacha20Poly1305,
250 _ => return None,
251 };
252 assert_eq!(n, ret as u16);
254 Some(ret)
255 }
256
257 fn as_ffi_ptr(&self) -> *const bssl_sys::EVP_HPKE_AEAD {
258 unsafe {
260 match self {
261 Aead::Aes128Gcm => bssl_sys::EVP_hpke_aes_128_gcm(),
262 Aead::Aes256Gcm => bssl_sys::EVP_hpke_aes_256_gcm(),
263 Aead::Chacha20Poly1305 => bssl_sys::EVP_hpke_chacha20_poly1305(),
264 }
265 }
266 }
267}
268
269const MAX_ENCAPSULATED_KEY_LEN: usize = bssl_sys::EVP_HPKE_MAX_ENC_LENGTH as usize;
271
272pub struct Params {
274 kem: *const bssl_sys::EVP_HPKE_KEM,
275 kdf: *const bssl_sys::EVP_HPKE_KDF,
276 aead: *const bssl_sys::EVP_HPKE_AEAD,
277}
278
279impl Params {
280 pub fn new(kem: Kem, _kdf: Kdf, aead: Aead) -> Self {
282 Self {
283 kem: kem.as_ffi_ptr(),
284 kdf: unsafe {
286 bssl_sys::EVP_hpke_hkdf_sha256()
288 },
289 aead: aead.as_ffi_ptr(),
290 }
291 }
292
293 pub fn new_from_rfc_ids(kem_id: u16, kdf_id: u16, aead_id: u16) -> Option<Self> {
295 let kem = Kem::from_rfc_id(kem_id)?;
296 let kdf = Kdf::HkdfSha256;
297 let aead = Aead::from_rfc_id(aead_id)?;
298
299 if kdf_id != kdf as u16 {
300 return None;
301 }
302 Some(Self::new(kem, kdf, aead))
303 }
304}
305
306pub struct SenderContext(scoped::EvpHpkeCtx);
308
309impl SenderContext {
310 pub fn new(params: &Params, recipient_pub_key: &[u8], info: &[u8]) -> Option<(Self, Vec<u8>)> {
317 let mut ctx = scoped::EvpHpkeCtx::new();
318 unsafe {
319 with_output_vec_fallible(MAX_ENCAPSULATED_KEY_LEN, |enc_key_buf| {
320 let mut enc_key_len = 0usize;
321 let ret = bssl_sys::EVP_HPKE_CTX_setup_sender(
326 ctx.as_mut_ffi_ptr(),
327 enc_key_buf,
328 &mut enc_key_len,
329 MAX_ENCAPSULATED_KEY_LEN,
330 params.kem,
331 params.kdf,
332 params.aead,
333 recipient_pub_key.as_ffi_ptr(),
334 recipient_pub_key.len(),
335 info.as_ffi_ptr(),
336 info.len(),
337 );
338 if ret == 1 {
339 Some(enc_key_len)
340 } else {
341 None
342 }
343 })
344 }
345 .map(|enc_key| (Self(ctx), enc_key))
346 }
347
348 pub fn seal(&mut self, plaintext: &[u8], aad: &[u8]) -> Vec<u8> {
356 #[allow(clippy::expect_used)]
358 let max_out_len = plaintext
359 .len()
360 .checked_add(unsafe { bssl_sys::EVP_HPKE_CTX_max_overhead(self.0.as_ffi_ptr()) })
361 .expect("Maximum output length calculation overflow");
362 unsafe {
363 with_output_vec(max_out_len, |out_buf| {
364 let mut out_len = 0usize;
365 let result = bssl_sys::EVP_HPKE_CTX_seal(
369 self.0.as_mut_ffi_ptr(),
370 out_buf,
371 &mut out_len,
372 max_out_len,
373 plaintext.as_ffi_ptr(),
374 plaintext.len(),
375 aad.as_ffi_ptr(),
376 aad.len(),
377 );
378 assert_eq!(result, 1);
379 out_len
380 })
381 }
382 }
383
384 pub fn export(&mut self, context: &[u8], out_len: usize) -> Vec<u8> {
387 unsafe {
388 with_output_vec(out_len, |out_buf| {
389 let ret = bssl_sys::EVP_HPKE_CTX_export(
394 self.0.as_mut_ffi_ptr(),
395 out_buf,
396 out_len,
397 context.as_ffi_ptr(),
398 context.len(),
399 );
400 assert_eq!(ret, 1);
401 out_len
402 })
403 }
404 }
405}
406
407pub struct RecipientContext(scoped::EvpHpkeCtx);
409
410impl RecipientContext {
411 pub fn new(
420 params: &Params,
421 recipient_priv_key: &[u8],
422 encapsulated_key: &[u8],
423 info: &[u8],
424 ) -> Option<Self> {
425 let mut hpke_key = scoped::EvpHpkeKey::new();
426
427 let result = unsafe {
429 bssl_sys::EVP_HPKE_KEY_init(
430 hpke_key.as_mut_ffi_ptr(),
431 params.kem,
432 recipient_priv_key.as_ffi_ptr(),
433 recipient_priv_key.len(),
434 )
435 };
436 if result != 1 {
437 return None;
438 }
439
440 let mut ctx = scoped::EvpHpkeCtx::new();
441
442 let result = unsafe {
448 bssl_sys::EVP_HPKE_CTX_setup_recipient(
449 ctx.as_mut_ffi_ptr(),
450 hpke_key.as_ffi_ptr(),
451 params.kdf,
452 params.aead,
453 encapsulated_key.as_ffi_ptr(),
454 encapsulated_key.len(),
455 info.as_ffi_ptr(),
456 info.len(),
457 )
458 };
459 if result == 1 {
460 Some(Self(ctx))
461 } else {
462 None
463 }
464 }
465
466 pub fn open(&mut self, ciphertext: &[u8], aad: &[u8]) -> Option<Vec<u8>> {
471 let max_out_len = ciphertext.len();
472 unsafe {
473 with_output_vec_fallible(max_out_len, |out_buf| {
474 let mut out_len = 0usize;
475 let result = bssl_sys::EVP_HPKE_CTX_open(
479 self.0.as_mut_ffi_ptr(),
480 out_buf,
481 &mut out_len,
482 max_out_len,
483 ciphertext.as_ffi_ptr(),
484 ciphertext.len(),
485 aad.as_ffi_ptr(),
486 aad.len(),
487 );
488 if result == 1 {
489 Some(out_len)
490 } else {
491 None
492 }
493 })
494 }
495 }
496
497 pub fn export(&mut self, context: &[u8], out_len: usize) -> Vec<u8> {
500 unsafe {
501 with_output_vec(out_len, |out_buf| {
502 let ret = bssl_sys::EVP_HPKE_CTX_export(
507 self.0.as_mut_ffi_ptr(),
508 out_buf,
509 out_len,
510 context.as_ffi_ptr(),
511 context.len(),
512 );
513 assert_eq!(ret, 1);
514 out_len
515 })
516 }
517 }
518}
519
520#[cfg(test)]
521mod test {
522 use super::*;
523 use crate::test_helpers::{decode_hex, decode_hex_into_vec};
524
525 struct TestVector {
526 kem_id: u16,
527 kdf_id: u16,
528 aead_id: u16,
529 info: [u8; 20],
530 seed_for_testing: [u8; 32], recipient_pub_key: Vec<u8>, recipient_priv_key: [u8; 32], encapsulated_key: Vec<u8>, plaintext: [u8; 29], associated_data: [u8; 7], ciphertext: [u8; 45], exporter_context: [u8; 11],
538 exported_value: [u8; 32],
539 }
540
541 fn x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm() -> TestVector {
543 TestVector {
544 kem_id: 32,
545 kdf_id: 1,
546 aead_id: 1,
547 info: decode_hex("4f6465206f6e2061204772656369616e2055726e"),
548 seed_for_testing: decode_hex("52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736"),
549 recipient_pub_key: decode_hex_into_vec("3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d"),
550 recipient_priv_key: decode_hex("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8"),
551 encapsulated_key: decode_hex_into_vec("37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431"),
552 plaintext: decode_hex("4265617574792069732074727574682c20747275746820626561757479"),
553 associated_data: decode_hex("436f756e742d30"),
554 ciphertext: decode_hex("f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a"),
555 exporter_context: decode_hex("54657374436f6e74657874"),
556 exported_value: decode_hex("e9e43065102c3836401bed8c3c3c75ae46be1639869391d62c61f1ec7af54931"),
557 }
558 }
559
560 fn x25519_hkdf_sha256_hkdf_sha256_chacha20_poly1305() -> TestVector {
562 TestVector {
563 kem_id: 32,
564 kdf_id: 1,
565 aead_id: 3,
566 info: decode_hex("4f6465206f6e2061204772656369616e2055726e"),
567 seed_for_testing: decode_hex("f4ec9b33b792c372c1d2c2063507b684ef925b8c75a42dbcbf57d63ccd381600"),
568 recipient_pub_key: decode_hex_into_vec("4310ee97d88cc1f088a5576c77ab0cf5c3ac797f3d95139c6c84b5429c59662a"),
569 recipient_priv_key: decode_hex("8057991eef8f1f1af18f4a9491d16a1ce333f695d4db8e38da75975c4478e0fb"),
570 encapsulated_key: decode_hex_into_vec("1afa08d3dec047a643885163f1180476fa7ddb54c6a8029ea33f95796bf2ac4a"),
571 plaintext: decode_hex("4265617574792069732074727574682c20747275746820626561757479"),
572 associated_data: decode_hex("436f756e742d30"),
573 ciphertext: decode_hex("1c5250d8034ec2b784ba2cfd69dbdb8af406cfe3ff938e131f0def8c8b60b4db21993c62ce81883d2dd1b51a28"),
574 exporter_context: decode_hex("54657374436f6e74657874"),
575 exported_value: decode_hex("5acb09211139c43b3090489a9da433e8a30ee7188ba8b0a9a1ccf0c229283e53"),
576 }
577 }
578
579 fn p256_hkdf_sha256_hkdf_sha256_aes_128_gcm() -> TestVector {
581 TestVector {
582 kem_id: 16,
583 kdf_id: 1,
584 aead_id: 1,
585 info: decode_hex("4f6465206f6e2061204772656369616e2055726e"),
586 seed_for_testing: decode_hex("4270e54ffd08d79d5928020af4686d8f6b7d35dbe470265f1f5aa22816ce860e"),
587 recipient_pub_key: decode_hex_into_vec("04fe8c19ce0905191ebc298a9245792531f26f0cece2460639e8bc39cb7f706a826a779b4cf969b8a0e539c7f62fb3d30ad6aa8f80e30f1d128aafd68a2ce72ea0"),
588 recipient_priv_key: decode_hex("f3ce7fdae57e1a310d87f1ebbde6f328be0a99cdbcadf4d6589cf29de4b8ffd2"),
589 encapsulated_key: decode_hex_into_vec("04a92719c6195d5085104f469a8b9814d5838ff72b60501e2c4466e5e67b325ac98536d7b61a1af4b78e5b7f951c0900be863c403ce65c9bfcb9382657222d18c4"),
590 plaintext: decode_hex("4265617574792069732074727574682c20747275746820626561757479"),
591 associated_data: decode_hex("436f756e742d30"),
592 ciphertext: decode_hex("5ad590bb8baa577f8619db35a36311226a896e7342a6d836d8b7bcd2f20b6c7f9076ac232e3ab2523f39513434"),
593 exporter_context: decode_hex("54657374436f6e74657874"),
594 exported_value: decode_hex("d8f1ea7942adbba7412c6d431c62d01371ea476b823eb697e1f6e6cae1dab85a"),
595 }
596 }
597
598 #[test]
599 fn all_algorithms() {
600 let kems = vec![
601 Kem::X25519HkdfSha256,
602 Kem::P256HkdfSha256,
603 Kem::XWing,
604 Kem::MlKem768,
605 Kem::MlKem1024,
606 ];
607 let kdfs = vec![Kdf::HkdfSha256];
608 let aeads = vec![Aead::Aes128Gcm, Aead::Aes256Gcm, Aead::Chacha20Poly1305];
609 let plaintext: &[u8] = b"plaintext";
610 let aad: &[u8] = b"aad";
611 let info: &[u8] = b"info";
612
613 for kem in &kems {
614 let (pub_key, priv_key) = kem.generate_keypair();
615 for kdf in &kdfs {
616 for aead in &aeads {
617 let params =
618 Params::new_from_rfc_ids(*kem as u16, *kdf as u16, *aead as u16).unwrap();
619
620 let (mut send_ctx, encapsulated_key) =
621 SenderContext::new(¶ms, &pub_key, info).unwrap();
622 let mut recv_ctx =
623 RecipientContext::new(¶ms, &priv_key, &encapsulated_key, info).unwrap();
624 assert_eq!(
625 plaintext,
626 recv_ctx
627 .open(send_ctx.seal(plaintext, aad).as_ref(), aad)
628 .unwrap()
629 );
630 assert_eq!(
631 plaintext,
632 recv_ctx
633 .open(send_ctx.seal(plaintext, aad).as_ref(), aad)
634 .unwrap()
635 );
636 assert!(recv_ctx.open(b"nonsense", aad).is_none());
637 }
638 }
639 }
640 }
641
642 #[test]
643 fn kem_public_from_private() {
644 let kems = vec![
645 Kem::X25519HkdfSha256,
646 Kem::P256HkdfSha256,
647 Kem::XWing,
648 Kem::MlKem768,
649 Kem::MlKem1024,
650 ];
651 for kem in &kems {
652 let (pub_key, priv_key) = kem.generate_keypair();
653 assert_eq!(kem.public_from_private(&priv_key), Some(pub_key));
654
655 assert_eq!(kem.public_from_private(b"invalid"), None);
656 }
657 }
658
659 fn new_sender_context_for_testing(
660 params: &Params,
661 recipient_pub_key: &[u8],
662 info: &[u8],
663 seed_for_testing: &[u8],
664 ) -> (SenderContext, Vec<u8>) {
665 let mut ctx = scoped::EvpHpkeCtx::new();
666
667 let encapsulated_key = unsafe {
668 with_output_vec_fallible(MAX_ENCAPSULATED_KEY_LEN, |enc_key_buf| {
669 let mut enc_key_len = 0usize;
670 let result = bssl_sys::EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
675 ctx.as_mut_ffi_ptr(),
676 enc_key_buf,
677 &mut enc_key_len,
678 MAX_ENCAPSULATED_KEY_LEN,
679 params.kem,
680 params.kdf,
681 params.aead,
682 recipient_pub_key.as_ffi_ptr(),
683 recipient_pub_key.len(),
684 info.as_ffi_ptr(),
685 info.len(),
686 seed_for_testing.as_ffi_ptr(),
687 seed_for_testing.len(),
688 );
689 if result == 1 {
690 Some(enc_key_len)
691 } else {
692 None
693 }
694 })
695 }
696 .unwrap();
697 (SenderContext(ctx), encapsulated_key)
698 }
699
700 #[test]
701 fn seal_with_vector() {
702 for test in vec![
703 x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm(),
704 x25519_hkdf_sha256_hkdf_sha256_chacha20_poly1305(),
705 p256_hkdf_sha256_hkdf_sha256_aes_128_gcm(),
706 ] {
707 let params = Params::new_from_rfc_ids(test.kem_id, test.kdf_id, test.aead_id).unwrap();
708
709 let (mut ctx, encapsulated_key) = new_sender_context_for_testing(
710 ¶ms,
711 &test.recipient_pub_key,
712 &test.info,
713 &test.seed_for_testing,
714 );
715
716 assert_eq!(encapsulated_key, test.encapsulated_key.to_vec());
717
718 let ciphertext = ctx.seal(&test.plaintext, &test.associated_data);
719 assert_eq!(&ciphertext, test.ciphertext.as_ref());
720 }
721 }
722
723 #[test]
724 fn open_with_vector() {
725 for test in vec![
726 x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm(),
727 x25519_hkdf_sha256_hkdf_sha256_chacha20_poly1305(),
728 p256_hkdf_sha256_hkdf_sha256_aes_128_gcm(),
729 ] {
730 let params = Params::new_from_rfc_ids(test.kem_id, test.kdf_id, test.aead_id).unwrap();
731
732 let mut ctx = RecipientContext::new(
733 ¶ms,
734 &test.recipient_priv_key,
735 &test.encapsulated_key,
736 &test.info,
737 )
738 .unwrap();
739
740 let plaintext = ctx.open(&test.ciphertext, &test.associated_data).unwrap();
741 assert_eq!(&plaintext, test.plaintext.as_ref());
742 }
743 }
744
745 #[test]
746 fn export_with_vector() {
747 for test in vec![
748 x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm(),
749 x25519_hkdf_sha256_hkdf_sha256_chacha20_poly1305(),
750 p256_hkdf_sha256_hkdf_sha256_aes_128_gcm(),
751 ] {
752 let params = Params::new_from_rfc_ids(test.kem_id, test.kdf_id, test.aead_id).unwrap();
753
754 let (mut sender_ctx, _encapsulated_key) = new_sender_context_for_testing(
755 ¶ms,
756 &test.recipient_pub_key,
757 &test.info,
758 &test.seed_for_testing,
759 );
760 assert_eq!(
761 test.exported_value.as_ref(),
762 sender_ctx.export(&test.exporter_context, test.exported_value.len())
763 );
764
765 let mut recipient_ctx = RecipientContext::new(
766 ¶ms,
767 &test.recipient_priv_key,
768 &test.encapsulated_key,
769 &test.info,
770 )
771 .unwrap();
772 assert_eq!(
773 test.exported_value.as_ref(),
774 recipient_ctx.export(&test.exporter_context, test.exported_value.len())
775 );
776 }
777 }
778
779 #[test]
780 fn disallowed_params_fail() {
781 let vec: TestVector = x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm();
782
783 assert!(Params::new_from_rfc_ids(0, vec.kdf_id, vec.aead_id).is_none());
784 assert!(Params::new_from_rfc_ids(vec.kem_id, 0, vec.aead_id).is_none());
785 assert!(Params::new_from_rfc_ids(vec.kem_id, vec.kdf_id, 0).is_none());
786 }
787
788 #[test]
789 fn bad_recipient_pub_key_fails() {
790 let vec: TestVector = x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm();
791 let params = Params::new_from_rfc_ids(vec.kem_id, vec.kdf_id, vec.aead_id).unwrap();
792
793 assert!(SenderContext::new(¶ms, b"", &vec.info).is_none());
794 }
795
796 #[test]
797 fn bad_recipient_priv_key_fails() {
798 let vec: TestVector = x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm();
799 let params = Params::new_from_rfc_ids(vec.kem_id, vec.kdf_id, vec.aead_id).unwrap();
800
801 assert!(RecipientContext::new(¶ms, b"", &vec.encapsulated_key, &vec.info).is_none());
802 }
803}