From 068a6c0d2db8ea6e3fec2ea0af775c62253d9512 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 5 Feb 2024 16:02:06 +1100 Subject: [PATCH 01/30] Changing and breaking public APIs as discussed w/ @mmalenic: i.e: no more buffer passing as arguments. Also taking the opportunity to transition from CLI-integration tests to functional tests instead (we are primarily testing the functions not the CLI) since they introduce OS-dependent constructs (i.e Paths) and difficult WASM code reuse, for instance. [ci skip] --- Cargo.lock | 384 ++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 5 +- README.md | 8 - src/header.rs | 4 +- src/lib.rs | 26 ++- tests/test_common.rs | 101 +----------- tests/test_keys.rs | 156 +++--------------- 7 files changed, 413 insertions(+), 271 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0cae49..181c163 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.21.2" @@ -212,6 +224,12 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "cpufeatures" version = "0.2.8" @@ -246,10 +264,23 @@ dependencies = [ "rpassword", "scrypt", "serde", + "ssh-key", "testresult", "thiserror", ] +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -290,6 +321,7 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", + "digest", "fiat-crypto", "platforms", "rustc_version", @@ -308,6 +340,16 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -315,10 +357,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2", + "subtle", +] + [[package]] name = "ed25519_to_curve25519" version = "0.2.3" @@ -331,6 +409,25 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -365,6 +462,16 @@ dependencies = [ "libc", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.1.20" @@ -379,6 +486,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -392,6 +500,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "heck" version = "0.4.0" @@ -454,9 +573,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -466,6 +585,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -473,6 +595,12 @@ version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -494,6 +622,54 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -512,6 +688,44 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core", + "sha2", +] + [[package]] name = "password-hash" version = "0.5.0" @@ -533,6 +747,36 @@ dependencies = [ "hmac", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "platforms" version = "3.0.2" @@ -566,6 +810,15 @@ dependencies = [ "log", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -655,6 +908,16 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rpassword" version = "7.2.0" @@ -666,6 +929,27 @@ dependencies = [ "winapi", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rtoolbox" version = "0.0.1" @@ -720,6 +1004,20 @@ dependencies = [ "sha2", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "semver" version = "1.0.18" @@ -748,15 +1046,89 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "ssh-cipher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" +dependencies = [ + "cipher", + "ssh-encoding", +] + +[[package]] +name = "ssh-encoding" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" +dependencies = [ + "base64ct", + "pem-rfc7468", + "sha2", +] + +[[package]] +name = "ssh-key" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01f8f4ea73476c0aa5d5e6a75ce1e8634e2c3f82005ef3bbed21547ac57f2bf7" +dependencies = [ + "ed25519-dalek", + "p256", + "p384", + "p521", + "rand_core", + "rsa", + "sec1", + "sha2", + "signature", + "ssh-cipher", + "ssh-encoding", + "subtle", + "zeroize", +] + [[package]] name = "strsim" version = "0.10.0" @@ -965,6 +1337,6 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index d897b48..eb5d8d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,12 +38,13 @@ serde = { version = "1", features = ["derive"] } log = "0.4" pretty_env_logger = "0.5" thiserror = "1" -itertools = "0.11" +itertools = "0.12" rand = "0.8" rand_chacha = "0.3" ed25519_to_curve25519 = "0.2" -curve25519-dalek = "4.0.0" +curve25519-dalek = "4" +ssh-key = { version = "0.6.4", features = ["ed25519"] } [dev-dependencies] testresult = "0.3" diff --git a/README.md b/README.md index 6955131..40363a8 100644 --- a/README.md +++ b/README.md @@ -89,16 +89,12 @@ Use the exposed functions: ```rust pub fn encrypt( recipient_keys: &HashSet, - read_buffer: &mut R, - write_buffer: &mut W, range_start: usize, range_span: Option ) -> Result<()> pub fn decrypt( keys: Vec, - read_buffer: &mut R, - write_buffer: &mut W, range_start: usize, range_span: Option, sender_pubkey: Option>, @@ -107,15 +103,11 @@ pub fn decrypt( pub fn reencrypt( keys: Vec, recipient_keys: HashSet, - read_buffer: &mut R, - write_buffer: &mut W, trim: bool, ) -> Result<()> pub fn rearrange( keys: Vec, - read_buffer: &mut R, - write_buffer: &mut W, range_start: usize, range_span: Option, ) -> Result<()> diff --git a/src/header.rs b/src/header.rs index 3191ebc..1469930 100644 --- a/src/header.rs +++ b/src/header.rs @@ -332,10 +332,10 @@ pub fn deconstruct_header_body( /// /// Reads the magic number, the version and the number of packets from the bytes. pub fn deconstruct_header_info( - header_info_file: &[u8; std::mem::size_of::()], + header_info_file: Option<&[u8; 16]>, // TODO: HeaderInfo::len() ) -> Result { let header_info = - bincode::deserialize::(header_info_file).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; + bincode::deserialize::(header_info_file.unwrap()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; if &header_info.magic_number != MAGIC_NUMBER { return Err(Crypt4GHError::MagicStringError); diff --git a/src/lib.rs b/src/lib.rs index 5d5adfb..a667b5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,8 +107,6 @@ pub struct Keys { /// In case that `range_span` is none, it will encrypt from `range_start` to the end of the input. pub fn encrypt( recipient_keys: &HashSet, - read_buffer: &mut R, - write_buffer: &mut W, range_start: usize, range_span: Option, ) -> Result<(), Crypt4GHError> { @@ -124,11 +122,11 @@ pub fn encrypt( log::info!("Forwarding to position: {}", range_start); } - read_buffer - .by_ref() - .take(range_start as u64) - .read_to_end(&mut Vec::new()) - .map_err(|e| Crypt4GHError::NotEnoughInput(range_start, e.into()))?; + // read_buffer + // .by_ref() + // .take(range_start as u64) + // .read_to_end(&mut Vec::new()) + // .map_err(|e| Crypt4GHError::NotEnoughInput(range_start, e.into()))?; log::debug!(" Span: {:?}", range_span); @@ -263,14 +261,13 @@ pub fn encrypt_segment(data: &[u8], nonce: Nonce, key: &Key) -> Result, /// In case that `range_span` is none, it will encrypt from `range_start` to the end of the input. /// If `sender_pubkey` is specified the program will check that the `recipient_key` in the message /// is the same as the `sender_pubkey`. -pub fn decrypt( +pub fn decrypt( + payload: &[u8], keys: &[Keys], - read_buffer: &mut R, - write_buffer: &mut W, range_start: usize, range_span: Option, sender_pubkey: &Option>, -) -> Result<(), Crypt4GHError> { +) -> Result, Crypt4GHError> { range_span.map_or_else( || { log::info!("Decrypting file | Range: [{}, EOF)", range_start); @@ -281,11 +278,8 @@ pub fn decrypt( ); // Get header info - let mut temp_buf = [0_u8; 16]; // Size of the header - read_buffer - .read_exact(&mut temp_buf) - .map_err(|e| Crypt4GHError::ReadHeaderError(e.into()))?; - let header_info: header::HeaderInfo = header::deconstruct_header_info(&temp_buf)?; + let header = payload.get(0..16); + let header_info = header::deconstruct_header_info(header)?; // Calculate header packets let encrypted_packets = (0..header_info.packets_count) diff --git a/tests/test_common.rs b/tests/test_common.rs index 3590e8c..5022dbb 100644 --- a/tests/test_common.rs +++ b/tests/test_common.rs @@ -211,90 +211,6 @@ impl Default for Cleanup { } } -pub fn equal(file1: &str, file2: &str) { - let status = Command::new("diff") - .arg(file1) - .arg(file2) - .stderr(Stdio::null()) - .stdout(Stdio::null()) - .spawn() - .unwrap() - .wait() - .unwrap() - .code() - .unwrap(); - assert_eq!(status, 0); -} - -pub fn new_random_file(filename: &str, size_in_mb: usize) { - File::create(filename).unwrap(); - let status = Command::new("dd") - .arg("if=/dev/urandom") - .arg("bs=1048576") - .arg(format!("count={}", size_in_mb)) - .arg(format!("of={}", filename)) - .stderr(Stdio::null()) - .spawn() - .unwrap() - .wait() - .unwrap() - .code() - .unwrap(); - assert_eq!(status, 0); -} - -pub fn remove_file(file_pattern: &str) { - Command::new(r#"rm"#) - .arg("-rf") - .arg(file_pattern) - .spawn() - .unwrap() - .wait() - .ok(); -} - -#[must_use] -pub fn temp_file(filename: &str) -> String { - let mut s = TEMP_LOCATION.to_string(); - s.push('/'); - s.push_str(filename); - s -} - -#[must_use] -pub fn strip_prefix(filename: &str) -> String { - let ref_file = PathBuf::from(temp_file(filename)); - let ref_file = ref_file.strip_prefix("tests/").unwrap(); - ref_file.to_str().unwrap().to_string() -} - -#[must_use] -pub fn add_prefix(filename: &str) -> String { - let mut ref_file = PathBuf::new(); - ref_file.push("tests/"); - ref_file.push(filename); - ref_file.to_str().unwrap().to_string() -} - -pub fn ssh_gen(secret_filepath: &str, passphrase: &str) { - let status = Command::new("ssh-keygen") - .arg("-t") - .arg("ed25519") - .arg("-f") - .arg(secret_filepath) - .arg("-N") - .arg(passphrase) - .stderr(Stdio::null()) - .stdout(Stdio::null()) - .spawn() - .unwrap() - .wait() - .unwrap() - .code() - .unwrap(); - assert_eq!(status, 0); -} - pub fn echo(message: &str, filename: &str) { let file = File::create(filename).unwrap(); let status = Command::new("echo") @@ -337,19 +253,4 @@ pub fn count_characters(filepath: &str, assert_size: usize) { assert!(result.status.success()); let out = String::from_utf8(result.stdout).unwrap(); assert_eq!(out.trim().parse::().unwrap(), assert_size); -} - -pub fn grep(filepath: &str, substring: &str) { - let status = Command::new("grep") - .arg("-v") - .arg(substring) - .arg(filepath) - .stderr(Stdio::null()) - .spawn() - .unwrap() - .wait() - .unwrap() - .code() - .unwrap(); - assert_eq!(status, 1); -} +} \ No newline at end of file diff --git a/tests/test_keys.rs b/tests/test_keys.rs index 755f270..74282f5 100644 --- a/tests/test_keys.rs +++ b/tests/test_keys.rs @@ -1,172 +1,54 @@ mod test_common; -use std::{path::PathBuf, fs::File, io::Read}; - use crypt4gh::{keys::get_private_key, Keys}; +use rand::Rng; +use rand_chacha::rand_core::OsRng; +use ssh_key::PrivateKey; pub use test_common::*; use testresult::TestResult; -// #[test] -// fn encrypt_ssh_decrypt() -> TestResult { -// // Init -// let init = Cleanup::new(); - -// // Create random file -// new_random_file(&temp_file("random.10MB"), 10); - -// remove_file(&temp_file(BOB_PUBKEY_SSH)); -// remove_file(&temp_file(BOB_SECKEY_SSH)); - -// ssh_gen(&temp_file(BOB_SECKEY_SSH), BOB_PASSPHRASE); - -// // Encrypt -// CommandUnderTest::new() -// .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) -// .arg("encrypt") -// .arg("--sk") -// .arg(&strip_prefix(BOB_SECKEY_SSH)) -// .arg("--recipient_pk") -// .arg(ALICE_PUBKEY) -// .pipe_in(&temp_file("random.10MB")) -// .pipe_out(&temp_file("random.10MB.c4gh")) -// .succeeds(); - -// // Decrypt -// CommandUnderTest::new() -// .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) -// .arg("decrypt") -// .arg("--sk") -// .arg(ALICE_SECKEY) -// .pipe_in(&temp_file("random.10MB.c4gh")) -// .pipe_out(&temp_file("random.10MB.received")) -// .succeeds(); - -// // Compare -// equal(&temp_file("random.10MB"), &temp_file("random.10MB.received")); - -// // Cleanup -// drop(init); - -// Ok(()) -// } - #[test] -fn encrypt_decrypt_ssh() -> TestResult{ +fn encrypt_decrypt_ssh() -> TestResult { // Init let init = Cleanup::new(); pretty_env_logger::init(); + let mut rng = rand::thread_rng(); - // Create random file - new_random_file(&temp_file("random.10MB"), 10); - - remove_file(&temp_file(ALICE_PUBKEY_SSH)); - remove_file(&temp_file(ALICE_SECKEY_SSH)); - - ssh_gen(&temp_file(ALICE_SECKEY_SSH), ALICE_PASSPHRASE); + // Generate 10MB of "cleartext" payload + let mut cleartext = vec![0u8; 10 * 1024 * 1024]; + rng.fill(&mut cleartext[..]); + // Generate a random SSH key, no pubkey for sender and no range values + let private_key = PrivateKey::random(&mut OsRng, ssh_key::Algorithm::Ed25519)?; let sender_pubkey = None; let (range_start, range_span) = (0, None); - let seckey = get_private_key(PathBuf::from("tests/tempfiles/alice.sshkey"), Ok(ALICE_PASSPHRASE.to_string()))?; - let keys = vec![Keys { method: 0, - privkey: seckey, + privkey: private_key.to_bytes()?.to_vec(), recipient_pubkey: vec![], }]; - let mut file = File::open(PathBuf::from("tests/tempfiles/random.10MB.c4gh"))?; - - let mut out = vec![]; - file.read_to_end(&mut out)?; - - let mut buf_in = std::io::BufReader::new(&out[..]); - let mut buf = vec![]; - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(&strip_prefix(ALICE_PUBKEY_SSH)) - .pipe_in(&temp_file("random.10MB")) - .pipe_out(&temp_file("random.10MB.c4gh")) - .succeeds(); + let cryptext = crypt4gh::encrypt( + &keys, + range_start, + range_span + ); // Decrypt - crypt4gh::decrypt( + let plaintext = crypt4gh::decrypt( &keys, - &mut buf_in, - &mut buf, range_start, range_span, &sender_pubkey, )?; - // Decrypt - // CommandUnderTest::new() - // .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - // .arg("decrypt") - // .arg("--sk") - // .arg(&strip_prefix(ALICE_SECKEY_SSH)) - // .pipe_in(&temp_file("random.10MB.c4gh")) - // .pipe_out(&temp_file("random.10MB.received")) - // .succeeds(); - // Compare - equal(&temp_file("random.10MB"), &temp_file("random.10MB.received")); + equal(&cleartext, &plaintext); // Cleanup drop(init); Ok(()) -} - -// #[test] -// fn encrypt_ssh_decrypt_ssh() -> TestResult { -// // Init -// let init = Cleanup::new(); - -// // Create random file -// new_random_file(&temp_file("random.10MB"), 10); - -// remove_file(&temp_file(ALICE_PUBKEY_SSH)); -// remove_file(&temp_file(ALICE_SECKEY_SSH)); -// remove_file(&temp_file(BOB_PUBKEY_SSH)); -// remove_file(&temp_file(BOB_SECKEY_SSH)); - -// ssh_gen(&temp_file(ALICE_SECKEY_SSH), ALICE_PASSPHRASE); -// ssh_gen(&temp_file(BOB_SECKEY_SSH), BOB_PASSPHRASE); - -// // Encrypt -// CommandUnderTest::new() -// .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) -// .arg("encrypt") -// .arg("--sk") -// .arg(&strip_prefix(BOB_SECKEY_SSH)) -// .arg("--recipient_pk") -// .arg(&strip_prefix(ALICE_PUBKEY_SSH)) -// .pipe_in(&temp_file("random.10MB")) -// .pipe_out(&temp_file("random.10MB.c4gh")) -// .succeeds(); - -// // Decrypt -// CommandUnderTest::new() -// .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) -// .arg("decrypt") -// .arg("--sk") -// .arg(&strip_prefix(ALICE_SECKEY_SSH)) -// .pipe_in(&temp_file("random.10MB.c4gh")) -// .pipe_out(&temp_file("random.10MB.received")) -// .succeeds(); - -// // Compare -// equal(&temp_file("random.10MB"), &temp_file("random.10MB.received")); - -// // Cleanup -// drop(init); - -// Ok(()) -// } +} \ No newline at end of file From 9a81982a13e052a73d7069547aa188cc3807eccd Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 6 Feb 2024 15:22:54 +1100 Subject: [PATCH 02/30] Define public API for decrypt/encrypt, remove filesystem-based helper functions, start importing equivalent IO and Async functions written in htsget-rs crate async_crypt4gh --- src/header.rs | 4 +- src/keys.rs | 664 ++------------------------------------------------ src/lib.rs | 143 ++++------- 3 files changed, 64 insertions(+), 747 deletions(-) diff --git a/src/header.rs b/src/header.rs index 1469930..e0fed3a 100644 --- a/src/header.rs +++ b/src/header.rs @@ -331,8 +331,8 @@ pub fn deconstruct_header_body( /// Deserializes the data info from the header bytes. /// /// Reads the magic number, the version and the number of packets from the bytes. -pub fn deconstruct_header_info( - header_info_file: Option<&[u8; 16]>, // TODO: HeaderInfo::len() +pub fn deserialize_header_info( + header_info_file: , // TODO: HeaderInfo::len() ) -> Result { let header_info = bincode::deserialize::(header_info_file.unwrap()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; diff --git a/src/keys.rs b/src/keys.rs index 29838cd..bcc36af 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -61,654 +61,18 @@ lazy_static! { .collect(); } -fn read_lines(filename: &PathBuf) -> Result, Crypt4GHError> -where -{ - let file = File::open(filename)?; - Ok(BufReader::new(file) - .lines() - .filter_map(std::result::Result::ok) - .collect()) -} - -fn load_from_pem(filepath: &PathBuf) -> Result, Crypt4GHError> { - // Read lines - let lines = read_lines(&filepath) - .map_err(|e| Crypt4GHError::ReadLinesError(filepath.to_owned(), Box::new(e)))?; - - // Check format - if lines.len() < 3 { - return Err(Crypt4GHError::InvalidPEMFormatLength(filepath.into())); - } - - if !lines.first().unwrap().starts_with("-----BEGIN ") || - !lines.last().unwrap().starts_with("-----END ") { - return Err(Crypt4GHError::InvalidPEMHeaderOrFooter); - } - - // Decode with base64 - general_purpose::STANDARD.decode(&lines[1..lines.len() - 1].join("")).map_err(move |e| Crypt4GHError::BadBase64Error(e.into())) -} - -fn decode_string_ssh(stream: &mut impl BufRead) -> Result, Crypt4GHError> { - // Get data len - let mut slen = [0_u8; 4]; - stream.read_exact(&mut slen)?; - let len = u32::from_be_bytes(slen); - - // Get data - let mut data = vec![0_u8; len as usize]; - stream.read_exact(data.as_mut_slice())?; - - Ok(data) -} - -fn decode_string_c4gh(stream: &mut impl BufRead) -> Result, Crypt4GHError> { - // Get data len - let mut slen = [0_u8; 2]; - stream.read_exact(&mut slen)?; - let len = u16::from_be_bytes(slen); - - // Get data - let mut data = vec![0_u8; len as usize]; - stream.read_exact(data.as_mut_slice())?; - - Ok(data) -} - -fn derive_key( - alg: &str, - passphrase: &str, - salt: Option>, - rounds: Option, - dklen: usize, -) -> Result, Crypt4GHError> { - let mut output = vec![0_u8; dklen]; - - match alg { - "scrypt" => { - // TODO: Is dklen the right key length always? - let params = scrypt::Params::new(14, 8, 1, dklen).map_err(|_| Crypt4GHError::ScryptParamsError)?; - scrypt::scrypt( - passphrase.as_bytes(), - &salt.unwrap_or_else(|| { - log::warn!("Using default salt = [0_u8; 8]"); - vec![0_u8; 0] - }), - ¶ms, - &mut output, - ).map_err(|_| Crypt4GHError::ScryptParamsError)? - }, - "bcrypt" => { - bcrypt_pbkdf::bcrypt_pbkdf( - passphrase.as_bytes(), - &salt.unwrap_or_else(|| { - log::warn!("Using default salt = [0_u8; 8]"); - vec![0_u8; 0] - }), - rounds.unwrap_or_else(|| { - log::warn!("Using default rounds = 0"); - 0 - }), - &mut output, - ).map_err(|_| Crypt4GHError::BcryptPBKDFError)? - }, - "pbkdf2_hmac_sha256" => unimplemented!(), - unsupported_alg => return Err(Crypt4GHError::UnsupportedKdf(unsupported_alg.into())), - }; - - Ok(output) -} - -fn parse_c4gh_private_key( - mut stream: impl BufRead, - callback: Result, -) -> Result, Crypt4GHError> { - let kdfname = String::from_utf8(decode_string_c4gh(&mut stream)?) - .map_err(|e| Crypt4GHError::UnsupportedKdf(e.to_string()))?; - log::debug!("KDF: {}", kdfname); - - if kdfname != "none" && !KDFS.contains_key(kdfname.as_str()) { - return Err(Crypt4GHError::InvalidCrypt4GHKey); - } - - let mut rounds = None; - let mut salt = None; - let kdfoptions: Vec; - - if kdfname == "none" { - log::debug!("Not Encrypted"); - } - else { - kdfoptions = decode_string_c4gh(&mut stream)?; - rounds = Some(u32::from_be_bytes([ - kdfoptions[0], - kdfoptions[1], - kdfoptions[2], - kdfoptions[3], - ])); - salt = Some(kdfoptions[4..].to_vec()); - log::debug!("Salt: {:02x?}", salt); - log::debug!("Rounds: {}", rounds.unwrap()); - } - - let ciphername = - String::from_utf8(decode_string_c4gh(&mut stream)?).map_err(|e| Crypt4GHError::BadCiphername(e.to_string()))?; - log::debug!("Ciphername: {}", ciphername); - - let private_data = decode_string_c4gh(&mut stream)?; - - log::debug!("Private data: {:?}", &private_data); - - if ciphername == "none" { - return Ok(private_data); - } - - // Else, the data was encrypted - if ciphername != "chacha20_poly1305" { - return Err(Crypt4GHError::BadCiphername(ciphername)); - } - - let passphrase = callback?; - - let shared_key = derive_key(&kdfname, &passphrase, salt, rounds, 32)?; - log::debug!("Shared Key: {:02x?}", shared_key); - log::debug!("Nonce: {:02x?}", &private_data[0..12]); - - let nonce = chacha20poly1305::Nonce::from_slice(&private_data[0..12]); - let key = chacha20poly1305::Key::from_slice(&shared_key); - let encrypted_data = &private_data[12..]; - - log::debug!("Encrypted data: {:?}", &encrypted_data); - - // TODO: Clarify why we are **encrypting** the private key in this function? - let privkey_plain = ChaCha20Poly1305::new(key).encrypt(nonce, encrypted_data) - .map_err(|_| Crypt4GHError::InvalidKeyFormat)?; - - log::debug!(" key argument: {:?}", &key); - log::debug!(" nonce argument: {:?}", &nonce); - log::debug!(" encrypted_data argument: {:?}", &encrypted_data); - - log::debug!("Privkey plaintext: {:?}", privkey_plain); - Ok(privkey_plain) -} - -fn parse_ssh_private_key( - mut stream: impl BufRead, - callback: Result, -) -> Result<([u8; 32], [u8; 32]), Crypt4GHError> { - let ciphername = - String::from_utf8(decode_string_ssh(&mut stream)?).map_err(|e| Crypt4GHError::BadCiphername(e.to_string()))?; - let kdfname = - String::from_utf8(decode_string_ssh(&mut stream)?).map_err(|e| Crypt4GHError::BadKdfName(e.into()))?; - let kdfoptions = decode_string_ssh(&mut stream)?; - - log::debug!("KDF: {}", kdfname); - log::debug!("Ciphername: {}", ciphername); - - let mut salt: Option> = None; - let mut rounds: Option = None; - - match kdfname.as_str() { - "none" => { - log::info!("Not Encrypted"); - }, - "bcrypt" => { - if ciphername.as_str() == "none" { - return Err(Crypt4GHError::InvalidSSHKey); - } - else { - // Get salt - let mut kdfoptions_cursor = Cursor::new(kdfoptions); - salt = Some(decode_string_ssh(&mut kdfoptions_cursor)?); - - // Get rounds - let mut buf = [0_u8; 4]; - kdfoptions_cursor - .read_exact(&mut buf) - .map_err(|_| Crypt4GHError::ReadRoundsError)?; - rounds = Some(u32::from_be_bytes(buf)); - - // Make sure kdfoptions are initialized to other values than 0 - if kdfoptions_cursor.read_exact(&mut [0_u8]).is_ok() { - return Err(Crypt4GHError::BadKey); - } - - // Log - log::debug!("Salt: {:02x?}", salt); - log::debug!("Rounds: {:?}", rounds); - } - }, - _ => return Err(Crypt4GHError::InvalidSSHKey), - } - - // N keys - let mut buf = [0_u8; 4]; - stream.read_exact(&mut buf).map_err(|_| Crypt4GHError::ReadSSHKeys)?; - let n: u32 = u32::from_be_bytes(buf); - log::debug!("Number of keys: {}", n); - - // Apparently always 1: https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L3857 - assert!(n == 1); - - // Ignore public keys - decode_string_ssh(&mut stream)?; - - // Padded list of private keys - let private_ciphertext = decode_string_ssh(&mut stream)?; - - // There should be no more data to read - assert!( - stream.read_exact(&mut [0_u8; 1]).is_err(), - "There should be no trailing data" - ); - - if ciphername == "none" { - // No need to unpad - get_skpk_from_decrypted_private_blob(&private_ciphertext) - } - else { - // Encrypted - assert!(salt.is_some() && rounds.is_some()); - - let passphrase = callback.map_err(|e| Crypt4GHError::NoPassphrase(e.into()))?; // TODO: Just check for passphrase being null since callback is gone? - - let dklen = get_derived_key_length(&ciphername)?; - log::debug!("Derived Key len: {}", dklen); - - let derived_key = derive_key(&kdfname, &passphrase, salt, rounds, dklen)?; - log::debug!("Derived Key: {:02x?}", derived_key); - - let private_data = decipher(&ciphername, &derived_key, &private_ciphertext)?; - get_skpk_from_decrypted_private_blob(&private_data) - } -} - -fn decipher(ciphername: &str, data: &[u8], private_ciphertext: &[u8]) -> Result, Crypt4GHError> { - let (ivlen, keylen) = CIPHER_INFO - .get(ciphername) - .ok_or_else(|| Crypt4GHError::BadCiphername(ciphername.into()))?; - - log::debug!("IV length and Key length: {} {}", ivlen, keylen); - log::debug!("Private ciphertext length and target ciphername block size: {} {}", private_ciphertext.len(), block_size(ciphername)?); - - if ((ivlen + keylen) as usize) != data.len() { - return Err(Crypt4GHError::InvalidData(String::from("IV length and Key length should match total data length"))); - } - - if (private_ciphertext.len() % block_size(ciphername)?) != 0 { - return Err(Crypt4GHError::InvalidData(String::from("Ciphertext does not match target cipher block size"))); - } - - // Get params - let key = &data[..*keylen as usize]; - let iv = &data[*keylen as usize..]; - let iv_ga = GenericArray::from_slice(iv); - - log::debug!("Decryption Key ({}): {:02x?}", key.len(), key); - log::debug!("IV ({}): {:02x?}", iv.len(), iv); - - let mut reader: Vec = vec![]; - let output = vec![0_u8; private_ciphertext.len()]; - - BufReader::new(private_ciphertext).read_to_end(&mut reader)?; - let mut writer = BufWriter::new(output); - - // log::debug!("Input ciphername is: {}", ciphername); - // log::debug!("Private ciphertext is: {:#?}", private_ciphertext); - - // Decipher - match ciphername { - "aes128-ctr" => { - type Aes128Ctr = ctr::Ctr128LE; - let mut cipher = Aes128Ctr::new(key.into(), iv_ga); - cipher.apply_keystream_b2b(&reader, writer.get_mut()).map_err(|_| Crypt4GHError::BadCiphername(String::from("aes128-ctr")))? - }, - "aes192-ctr" => { - type Aes192Ctr = ctr::Ctr128LE; - let mut cipher = Aes192Ctr::new(key.into(), iv_ga); - cipher.apply_keystream_b2b(&reader, writer.get_mut()).map_err(|_| Crypt4GHError::BadCiphername(String::from("aes192-ctr")))? - }, - "aes256-ctr" => { - type Aes256Ctr = ctr::Ctr128LE; - let mut cipher = Aes256Ctr::new(key.into(), iv_ga); - log::debug!("Reading reader: {:#?}", &reader); - cipher.apply_keystream_b2b(&reader, &mut writer.get_mut()).map_err(|_| Crypt4GHError::BadCiphername(String::from("aes256-ctr")))? - }, - "aes128-cbc" => { - todo!(); - }, - "aes192-cbc" => { - todo!(); - }, - "aes256-cbc" => { - todo!(); - }, - "3des-cbc" => unimplemented!(), - unknown_cipher => return Err(Crypt4GHError::BadCiphername(unknown_cipher.into())), - } - - writer.into_inner().map_err(|err| Crypt4GHError::IoError(err.into_error())) -} - -fn block_size(ciphername: &str) -> Result { - let (block_sz, _) = CIPHER_INFO - .get(ciphername) - .ok_or_else(|| Crypt4GHError::BadCiphername(ciphername.into()))?; - Ok(*block_sz as usize) -} - -fn get_derived_key_length(ciphername: &str) -> Result { - let (ivlen, keylen) = CIPHER_INFO - .get(ciphername) - .ok_or_else(|| Crypt4GHError::BadCiphername(ciphername.into()))?; - Ok((ivlen + keylen) as usize) -} - -fn get_skpk_from_decrypted_private_blob(blob: &[u8]) -> Result<([u8; 32], [u8; 32]), Crypt4GHError> { - let check_number_1: u32 = bincode::deserialize(&blob[0..4]).map_err(|_| Crypt4GHError::ReadCheckNumber1Error)?; - let check_number_2: u32 = bincode::deserialize(&blob[4..8]).map_err(|_| Crypt4GHError::ReadCheckNumber2Error)?; - assert!( - check_number_1 == check_number_2, - "Check numbers: {} != {}", - check_number_1, - check_number_2 - ); - - let mut stream = Cursor::new(&blob[8..]); - - // We should parse n keys, but n is 1 - decode_string_ssh(&mut stream)?; // ignore key name - decode_string_ssh(&mut stream)?; // ignore pubkey - - let skpk = decode_string_ssh(&mut stream)?; - log::debug!("Private Key blob: {:02x?}", skpk.iter()); - assert!(skpk.len() == 64, "The length of the private key blob must be 64"); - - let (sk, pk) = skpk.split_at(32); - log::debug!("ed25519 sk: {:02x?}", sk.iter()); - log::debug!("ed25519 pk: {:02x?}", pk.iter()); - - let seckey = convert_ed25519_sk_to_curve25519(sk)?; - log::debug!("x25519 sk: {:02x?}", seckey.iter()); - - let pubkey = convert_ed25519_pk_to_curve25519(pk)?; - log::debug!("x25519 pk: {:02x?}", pubkey.iter()); - - Ok((seckey, pubkey)) -} - -/// Reads and decodes the private key stored in `key_path`. -/// -/// It supports `Crypt4GH` and OpenSSH private keys. Fails if it can not read the file -/// or if the key is not one of the two supported formats. Returns the decode key. -/// If the key is encrypted, passphrase should return the passphrase of the key. -pub fn get_private_key( - key_path: PathBuf, - passphrase: Result, -) -> Result, Crypt4GHError> { - let data = load_from_pem(&key_path)?; - - if data.starts_with(C4GH_MAGIC_WORD) { - log::info!("Loading a Crypt4GH private key"); - let mut stream = BufReader::new(data.as_slice()); - stream - .read_exact(&mut [0_u8; C4GH_MAGIC_WORD.len()]) - .map_err(|e| Crypt4GHError::ReadMagicWord(e.into()))?; - parse_c4gh_private_key(stream, passphrase) - } - else if data.starts_with(SSH_MAGIC_WORD) { - log::info!("Loading an OpenSSH private key"); - let mut stream = BufReader::new(data.as_slice()); - stream - .read_exact(&mut [0_u8; SSH_MAGIC_WORD.len()]) - .map_err(|e| Crypt4GHError::ReadMagicWord(e.into()))?; - let (seckey, pubkey) = parse_ssh_private_key(stream, passphrase)?; - Ok(vec![seckey, pubkey].concat()) - } - else { - Err(Crypt4GHError::InvalidKeyFormat) - } -} - -/// Reads and decodes the public key stored in `key_path`. -/// -/// It supports `Crypt4GH` and OpenSSH public keys. Fails if it can not read the file -/// or if the key is not one of the two supported formats. Returns the decoded key. -pub fn get_public_key(key_path: PathBuf) -> Result, Crypt4GHError> { - // Read lines from public key file - match read_lines(&key_path) { - Ok(lines_vec) => { - // Empty key - if lines_vec.is_empty() { - Err(Crypt4GHError::EmptyPublicKey(key_path.into())) - } - // CRYPT4GH key - else if lines_vec[0].contains("CRYPT4GH") { - log::info!("Loading a Crypt4GH public key"); - general_purpose::STANDARD.decode(&lines_vec[1]).map_err(|e| Crypt4GHError::BadBase64Error(e.into())) - } - // SSH key - else if lines_vec[0].len() >= 4 && lines_vec[0].get(0..4).unwrap() == "ssh-" { - log::info!("Loading an OpenSSH public key"); - Ok(ssh_get_public_key(&lines_vec[0])?.to_vec()) - } - // Unsupported key - else { - Err(Crypt4GHError::InvalidKeyFormat) - } - }, - Err(_) => { - // Could not read lines - Err(Crypt4GHError::ReadPublicKeyError) - }, - } -} - -fn ssh_get_public_key(line: &str) -> Result<[u8; 32], Crypt4GHError> { - if &line[4..11] != "ed25519" { - return Err(Crypt4GHError::InvalidSSHKey); - } - - let pkey = general_purpose::STANDARD.decode( - line[12..] - .split(' ') - .take(1) - .next() - .ok_or(Crypt4GHError::InvalidSSHKey)?, - ) - .map_err(|e| Crypt4GHError::BadBase64Error(e.into()))?; - let mut pkey_stream = Cursor::new(pkey); - - let key_type = decode_string_ssh(&mut pkey_stream)?; - assert!(key_type == b"ssh-ed25519", "Unsupported public key type"); - - let pubkey_bytes = decode_string_ssh(&mut pkey_stream)?; - convert_ed25519_pk_to_curve25519(&pubkey_bytes) -} - -// TODO: Move all this SSH-key parsing related logic to a higher abstraction crate that does precisely that. -// Alternatively, use: ed25519_to_curve25519::ed25519_sk_to_curve25519(ed25519_sk) from ed25519_to_curve25519 crate -fn convert_ed25519_pk_to_curve25519(ed25519_pk: &[u8]) -> Result<[u8; 32], Crypt4GHError> { - if ed25519_pk.len() != 32 { - return Err(Crypt4GHError::ConversionFailed); - } - - let mut curve_pk = [0_u8; 32]; - - // let mut montgomery_point = MontgomeryPoint(CompressedEdwardsY::identity()); - let mut montgomery_point = MontgomeryPoint(curve_pk); // TODO: Fix this nonsense :point_up: - montgomery_point.0.copy_from_slice(ed25519_pk); - - // Ensure the given point is not the identity point - if montgomery_point.is_identity() { - return Err(Crypt4GHError::ConversionFailed); - } - - curve_pk.copy_from_slice(&montgomery_point.to_bytes()); - - Ok(curve_pk) -} - -fn convert_ed25519_sk_to_curve25519(ed25519_sk: &[u8]) -> Result<[u8; 32], Crypt4GHError> { - if ed25519_sk.len() != 32 { - return Err(Crypt4GHError::ConversionFailed); - } - - let mut curve_sk = [0_u8; 32]; - - // let mut montgomery_point = MontgomeryPoint(CompressedEdwardsY::identity()); - let mut montgomery_point = MontgomeryPoint(curve_sk); // TODO: Fix this nonsense :point_up: - montgomery_point.0.copy_from_slice(ed25519_sk); - - // Ensure the given point is not the identity point - if montgomery_point.is_identity() { - return Err(Crypt4GHError::ConversionFailed); - } - - curve_sk.copy_from_slice(&montgomery_point.to_bytes()); - - Ok(curve_sk) -} - -/// Generates a random privary key. -/// -/// It generates 32 random bytes and calculates the public key using the curve25519 algorithm. -/// The resulting private key has a length of 64. The first 32 bytes belong to the secret key, -/// the last 32 bytes belong to the public key. -pub fn generate_private_key() -> Result, Crypt4GHError> { - let seckey = ChaCha20Poly1305::generate_key(OsRng).to_vec(); - let pubkey = get_public_key_from_private_key(&seckey)?; - assert_eq!(seckey.len(), pubkey.len()); - log::debug!("Secret key in generate_private_key(): {:#?}", &seckey); - Ok(vec![seckey, pubkey].concat()) -} - -/// Generates a pair of `Crypt4GH` keys. -/// -/// It creates two files, one for the public key and another for the private key. It stores the -/// keys following the [`Crypt4GH` format](https://ega-archive.github.io/crypt4gh-rust/3_key_format.html). -/// The passphrase callback should return a string that will be used to encode the keys. You can add -/// an optional comment at the end of the keys. -pub fn generate_keys( - seckey: PathBuf, - pubkey: PathBuf, - passphrase: Result, - comment: Option, -) -> Result<(), Crypt4GHError> { - let skpk = generate_private_key()?; - log::debug!("Private Key: {:02x?}", skpk); - - // Public key permissions (read & write) - let mut pk_file = File::create(pubkey).expect("Unable to create public key file"); - let mut permissions = pk_file.metadata().unwrap().permissions(); - permissions.set_readonly(false); - pk_file.set_permissions(permissions).unwrap(); - - // Write public key - let (sk, pk) = skpk.split_at(32); - log::debug!("Public Key: {:02x?}", pk); - pk_file.write_all(b"-----BEGIN CRYPT4GH PUBLIC KEY-----\n").unwrap(); - pk_file.write_all(general_purpose::STANDARD.encode(pk).as_bytes()).unwrap(); - pk_file.write_all(b"\n-----END CRYPT4GH PUBLIC KEY-----\n").unwrap(); - - // Secret key file open - let mut sk_file = File::create(seckey).unwrap(); - - // Write secret key - let sk_encrypted = encode_private_key(sk, &passphrase?, comment)?; - log::debug!( - "Encoded Private Key ({}): {:02x?}", - sk_encrypted.len(), - sk - ); - sk_file.write_all(b"-----BEGIN CRYPT4GH PRIVATE KEY-----\n").unwrap(); - sk_file.write_all(general_purpose::STANDARD.encode(sk_encrypted).as_bytes()).unwrap(); - sk_file.write_all(b"\n-----END CRYPT4GH PRIVATE KEY-----\n").unwrap(); - - // Secret key file permissions (read only) - let mut permissions = sk_file.metadata().unwrap().permissions(); - permissions.set_readonly(true); - sk_file.set_permissions(permissions).unwrap(); - - Ok(()) -} - -fn encode_string_c4gh(s: Option<&[u8]>) -> Vec { - let string = s.unwrap_or(b"none"); - vec![(string.len() as u16).to_be_bytes().to_vec(), string.to_vec()].concat() -} - -fn encode_private_key(skpk: &[u8], passphrase: &str, comment: Option) -> Result, Crypt4GHError> { - Ok(if passphrase.is_empty() { - log::warn!("The private key is not encrypted"); - vec![ - C4GH_MAGIC_WORD.to_vec(), - encode_string_c4gh(None), // KDF = None - encode_string_c4gh(None), // Cipher = None - encode_string_c4gh(Some(skpk)), - match comment { - Some(c) => encode_string_c4gh(Some(c.as_bytes())), - None => [].to_vec(), - }, - ] - .concat() - } - else { - let kdfname = "scrypt"; - let (salt_size, rounds) = get_kdf(kdfname)?; - - let mut rnd = rand_chacha::ChaCha20Rng::from_entropy(); - let mut salt = vec![0; salt_size]; - - rnd.try_fill_bytes(&mut salt).map_err(|_| Crypt4GHError::NoRandomNonce)?; - - let mut nonce_bytes = [0u8; 12]; - rnd.fill(&mut nonce_bytes); - let nonce_array = GenericArray::from_slice(&nonce_bytes); - - let derived_key = derive_key(kdfname, passphrase, Some(salt.clone().to_vec()), Some(rounds), 32)?; - // let nonce = ChaCha20Poly1305::generate_nonce(OsRng); - let key = chacha20poly1305::Key::from_slice(&derived_key); - - let encrypted_key = ChaCha20Poly1305::new(&key) - .encrypt(&nonce_array, skpk) - .map_err(|_| Crypt4GHError::BadKey)?; - - let encrypted_key_ga = GenericArray::::from_slice(encrypted_key.as_slice()); - - log::debug!("Derived Key: {:02x?}", derived_key); - log::debug!("Salt: {:02x?}", salt); - // log::debug!("Nonce: {:02x?}", nonce); - - vec![ - C4GH_MAGIC_WORD.to_vec(), - encode_string_c4gh(Some(kdfname.as_bytes())), - encode_string_c4gh(Some(&vec![(rounds as u32).to_be_bytes().to_vec(), salt.to_vec()].concat())), - encode_string_c4gh(Some(b"chacha20_poly1305")), - encode_string_c4gh(Some(&vec![nonce_array.to_vec(), encrypted_key_ga.to_vec()].concat())), - match comment { - Some(c) => encode_string_c4gh(Some(c.as_bytes())), - None => [].to_vec(), - }, - ] - .concat() - }) -} - -fn get_kdf(kdfname: &str) -> Result<(usize, u32), Crypt4GHError> { - KDFS.get(kdfname) - .copied() - .ok_or_else(|| Crypt4GHError::UnsupportedKdf(kdfname.into())) -} - -/// Gets the public key from a private key -/// -/// Computes the curve25519 `scalarmult_base` to the first 32 bytes of `sk`. -/// `sk` must be at least 32 bytes. -pub fn get_public_key_from_private_key(sk: &[u8]) -> Result, Crypt4GHError> { - let secret_key = SecretKey::try_from(sk).map_err(|_| Crypt4GHError::BadServerPrivateKey)?; - let keypair = Keypair::from(secret_key); - let public_key = keypair.public(); - Ok(public_key.as_ref().to_vec()) +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +/// Key information. +pub struct Keys { + /// Method used for the key encryption. + /// > Only method 0 is supported. + pub method: u8, + /// Secret key of the encryptor / decryptor (your key). + pub privkey: Vec, + /// Public key of the recipient (the key you want to encrypt for). + pub recipient_pubkey: Vec, +} + +pub struct SessionKeys { + inner: Vec> } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index a667b5a..861f5f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,9 @@ clippy::redundant_else )] +use bytes::Bytes; +use io::Cursor; +use keys::SessionKeys; use rand::{SeedableRng, RngCore, Rng}; use rand_chacha; @@ -88,28 +91,17 @@ impl<'a, W: Write> WriteInfo<'a, W> { } } -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -/// Key information. -pub struct Keys { - /// Method used for the key encryption. - /// > Only method 0 is supported. - pub method: u8, - /// Secret key of the encryptor / decryptor (your key). - pub privkey: Vec, - /// Public key of the recipient (the key you want to encrypt for). - pub recipient_pubkey: Vec, -} - /// Reads from the `read_buffer` and writes the encrypted data to `write_buffer`. /// /// Reads from the `read_buffer` and writes the encrypted data (for every `recipient_key`) to `write_buffer`. /// If the range is specified, it will only encrypt the bytes from `range_start` to `range_start` + `range_span`. /// In case that `range_span` is none, it will encrypt from `range_start` to the end of the input. pub fn encrypt( - recipient_keys: &HashSet, + data_block: Bytes, + recipient_keys: &HashSet, range_start: usize, range_span: Option, -) -> Result<(), Crypt4GHError> { +) -> Result { if recipient_keys.is_empty() { return Err(Crypt4GHError::NoRecipients); } @@ -225,8 +217,8 @@ pub fn encrypt( /// /// Returns the encrypted header bytes pub fn encrypt_header( - recipient_keys: &HashSet, - session_key: &Option<[u8; 32]>, + recipient_keys: &HashSet, + session_key: SessionKeys, ) -> Result, Crypt4GHError> { let encryption_method = 0; @@ -254,88 +246,49 @@ pub fn encrypt_segment(data: &[u8], nonce: Nonce, key: &Key) -> Result, Ok(vec![nonce.to_vec(), ciphertext].concat()) } -/// Reads from the `read_buffer` and writes the decrypted data to `write_buffer`. -/// -/// Reads from the `read_buffer` and writes the decrypted data to `write_buffer`. -/// If the range is specified, it will only encrypt the bytes from `range_start` to `range_start` + `range_span`. -/// In case that `range_span` is none, it will encrypt from `range_start` to the end of the input. -/// If `sender_pubkey` is specified the program will check that the `recipient_key` in the message -/// is the same as the `sender_pubkey`. pub fn decrypt( - payload: &[u8], - keys: &[Keys], - range_start: usize, - range_span: Option, - sender_pubkey: &Option>, -) -> Result, Crypt4GHError> { - range_span.map_or_else( - || { - log::info!("Decrypting file | Range: [{}, EOF)", range_start); - }, - |span| { - log::info!("Decrypting file | Range: [{}, {})", range_start, range_start + span + 1); - }, - ); - - // Get header info - let header = payload.get(0..16); - let header_info = header::deconstruct_header_info(header)?; - - // Calculate header packets - let encrypted_packets = (0..header_info.packets_count) - .map(|_| { - // Get length - let mut length_buffer = [0_u8; 4]; - read_buffer - .read_exact(&mut length_buffer) - .map_err(|e| Crypt4GHError::ReadHeaderPacketLengthError(e.into()))?; - let length = bincode::deserialize::(&length_buffer) - .map_err(|e| Crypt4GHError::ParseHeaderPacketLengthError(e))?; - let length = length - 4; - - // Get data - let mut encrypted_data = vec![0_u8; length as usize]; - read_buffer - .read_exact(&mut encrypted_data) - .map_err(|e| Crypt4GHError::ReadHeaderPacketDataError(e.into()))?; - Ok(encrypted_data) - }) - .collect::>, Crypt4GHError>>()?; - - let DecryptedHeaderPackets { - data_enc_packets: session_keys, - edit_list_packet: edit_list, - } = header::deconstruct_header_body(encrypted_packets, keys, sender_pubkey)?; - - range_span.map_or_else( - || { - log::info!("Slicing from {} | Keeping all bytes", range_start); - }, - |span| { - log::info!("Slicing from {} | Keeping {} bytes", range_start, span); - }, - ); - - if range_span.is_some() && range_span.unwrap() == 0 { - return Err(Crypt4GHError::InvalidRangeSpan(range_span)); - } - - let mut write_info = WriteInfo::new(range_start, range_span, write_buffer); - - // TODO: Might fail here on Some() due to read_buffer coming from io::stdin is not populated? See run_decrypt() in bin.rs or - // the appropriate test - match edit_list { - None => body_decrypt(read_buffer, &session_keys, &mut write_info, range_start)?, - Some(edit_list_content) => body_decrypt_parts(read_buffer, session_keys, write_info, edit_list_content)?, - } - - log::info!("Decryption Over"); - Ok(()) + data_block: Bytes, + session_keys: SessionKeys, + edit_list_packet: Option>, + ) -> Result { + let size = data_block.len(); + + let read_buf = Cursor::new(data_block.to_vec()); + let mut write_buf = Cursor::new(vec![]); + let mut write_info = WriteInfo::new(0, None, &mut write_buf); + + // Todo crypt4gh-rust body_decrypt_parts does not work properly, so just apply edit list here. + body_decrypt(read_buf, session_keys.as_slice(), &mut write_info, 0) + .map_err(|err| Crypt4GHError(err.to_string()))?; + let mut decrypted_bytes: Bytes = write_buf.into_inner().into(); + let mut edited_bytes = Bytes::new(); + + let edits = DecrypterStream::<()>::create_internal_edit_list(edit_list_packet) + .unwrap_or(vec![(false, decrypted_bytes.len() as u64)]); + if edits.iter().map(|(_, edit)| edit).sum::() > decrypted_bytes.len() as u64 { + return Err(Crypt4GHError( + "invalid edit lists for the decrypted data block".to_string(), + )); + } + + edits.into_iter().for_each(|(discarding, edit)| { + if !discarding { + let edit = decrypted_bytes.slice(0..edit as usize); + edited_bytes = [edited_bytes.clone(), edit].concat().into(); + } + + decrypted_bytes = decrypted_bytes.slice(edit as usize..); + }); + + Ok(DecryptedDataBlock::new( + DecryptedBytes::new(edited_bytes), + size, + )) } struct DecryptedBuffer<'a, W: Write> { read_buffer: &'a mut dyn Read, - session_keys: Vec>, + session_keys: keys::SessionKeys, buf: Vec, is_decrypted: bool, block: u64, @@ -344,7 +297,7 @@ struct DecryptedBuffer<'a, W: Write> { } impl<'a, W: Write> DecryptedBuffer<'a, W> { - fn new(read_buffer: &'a mut impl Read, session_keys: Vec>, output: WriteInfo<'a, W>) -> Result { + fn new(read_buffer: &'a mut impl Read, session_keys: keys::SessionKeys, output: WriteInfo<'a, W>) -> Result { let mut decryptor = Self { read_buffer, session_keys, @@ -655,7 +608,7 @@ pub fn reencrypt( /// If the range is specified, it will only rearrange the bytes from `range_start` to `range_start` + `range_span`. /// In case that `range_span` is none, it will rearrange from `range_start` to the end of the input. pub fn rearrange( - keys: Vec, + keys: Vec, read_buffer: &mut R, write_buffer: &mut W, range_start: usize, From 39132a966d0368f1eb9c8b4395b566e2e7d84508 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 6 Feb 2024 15:23:41 +1100 Subject: [PATCH 03/30] Add ssh-keys to replace low level equivalents --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + 2 files changed, 8 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 181c163..d2bf4bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,6 +131,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + [[package]] name = "cbc" version = "0.1.2" @@ -247,6 +253,7 @@ dependencies = [ "base64", "bcrypt-pbkdf", "bincode", + "bytes", "cbc", "chacha20poly1305", "clap", diff --git a/Cargo.toml b/Cargo.toml index eb5d8d3..1ce1d96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ ed25519_to_curve25519 = "0.2" curve25519-dalek = "4" ssh-key = { version = "0.6.4", features = ["ed25519"] } +bytes = "1.5.0" [dev-dependencies] testresult = "0.3" From 05e0bf87bef01797599c9ade9ae34ab530c2affd Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Wed, 7 Feb 2024 16:19:49 +1100 Subject: [PATCH 04/30] [ci skip] Migrating more logic from async-crypt4gh to crypt4gh-rust --- Cargo.lock | 79 +- Cargo.toml | 1 + src/decoder/mod.rs | 427 ++++++++++ src/decrypter/builder.rs | 95 +++ src/decrypter/data_block.rs | 211 +++++ src/decrypter/header/mod.rs | 41 + src/decrypter/header/packets.rs | 81 ++ src/decrypter/mod.rs | 1329 +++++++++++++++++++++++++++++++ src/edit_lists.rs | 339 ++++++++ src/encrypter/builder.rs | 95 +++ src/encrypter/data_block.rs | 124 +++ src/encrypter/header/mod.rs | 41 + src/encrypter/header/packets.rs | 81 ++ src/encrypter/mod.rs | 1329 +++++++++++++++++++++++++++++++ src/header.rs | 32 + src/keys.rs | 58 ++ src/lib.rs | 13 +- src/reader/builder.rs | 112 +++ src/reader/mod.rs | 774 ++++++++++++++++++ src/util/mod.rs | 197 +++++ 20 files changed, 5443 insertions(+), 16 deletions(-) create mode 100644 src/decoder/mod.rs create mode 100644 src/decrypter/builder.rs create mode 100644 src/decrypter/data_block.rs create mode 100644 src/decrypter/header/mod.rs create mode 100644 src/decrypter/header/packets.rs create mode 100644 src/decrypter/mod.rs create mode 100644 src/edit_lists.rs create mode 100644 src/encrypter/builder.rs create mode 100644 src/encrypter/data_block.rs create mode 100644 src/encrypter/header/mod.rs create mode 100644 src/encrypter/header/packets.rs create mode 100644 src/encrypter/mod.rs create mode 100644 src/reader/builder.rs create mode 100644 src/reader/mod.rs create mode 100644 src/util/mod.rs diff --git a/Cargo.lock b/Cargo.lock index d2bf4bb..229e044 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,9 +148,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.73" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -269,6 +272,7 @@ dependencies = [ "rand_chacha", "regex", "rpassword", + "rustls", "scrypt", "serde", "ssh-key", @@ -498,9 +502,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -593,14 +597,14 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "spin", + "spin 0.5.2", ] [[package]] name = "libc" -version = "0.2.146" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libm" @@ -925,6 +929,20 @@ dependencies = [ "subtle", ] +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted", + "windows-sys", +] + [[package]] name = "rpassword" version = "7.2.0" @@ -990,6 +1008,37 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustls" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" + +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "salsa20" version = "0.10.2" @@ -1084,6 +1133,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spki" version = "0.7.3" @@ -1233,6 +1288,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "version_check" version = "0.9.4" @@ -1241,9 +1302,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index 1ce1d96..b58b7ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ ed25519_to_curve25519 = "0.2" curve25519-dalek = "4" ssh-key = { version = "0.6.4", features = ["ed25519"] } bytes = "1.5.0" +rustls = "0.22" [dev-dependencies] testresult = "0.3" diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs new file mode 100644 index 0000000..2977bc5 --- /dev/null +++ b/src/decoder/mod.rs @@ -0,0 +1,427 @@ +use std::io; + +use bytes::{Bytes, BytesMut}; +use crypt4gh::header::{deconstruct_header_info, HeaderInfo}; +use tokio_util::codec::Decoder; + +use crate::error::Error::{ + Crypt4GHError, DecodingHeaderInfo, MaximumHeaderSize, NumericConversionError, + SliceConversionError, +}; +use crate::error::{Error, Result}; +use crate::{EncryptedHeaderPacketBytes, EncryptedHeaderPackets}; + +pub const ENCRYPTED_BLOCK_SIZE: usize = 65536; +pub const NONCE_SIZE: usize = 12; // ChaCha20 IETF Nonce size +pub const MAC_SIZE: usize = 16; + +const DATA_BLOCK_SIZE: usize = NONCE_SIZE + ENCRYPTED_BLOCK_SIZE + MAC_SIZE; + +const MAGIC_STRING_SIZE: usize = 8; +const VERSION_STRING_SIZE: usize = 4; +const HEADER_PACKET_COUNT_SIZE: usize = 4; + +pub const HEADER_INFO_SIZE: usize = + MAGIC_STRING_SIZE + VERSION_STRING_SIZE + HEADER_PACKET_COUNT_SIZE; + +const HEADER_PACKET_LENGTH_SIZE: usize = 4; + +/// Have some sort of maximum header size to prevent any overflows. +const MAX_HEADER_SIZE: usize = 8 * 1024 * 1024; + +/// The type that a block is decoded into. +#[derive(Debug)] +pub enum DecodedBlock { + /// The magic string, version string and header packet count. + /// Corresponds to `deconstruct_header_info`. + HeaderInfo(HeaderInfo), + /// Header packets, both data encryption key packets and a data edit list packets. + /// Corresponds to `deconstruct_header_body`. + HeaderPackets(EncryptedHeaderPackets), + /// The encrypted data blocks + /// Corresponds to `body_decrypt`. + DataBlock(Bytes), +} + +/// State to keep track of the current block being decoded corresponding to `BlockType`. +#[derive(Debug)] +enum BlockState { + /// Expecting header info. + HeaderInfo, + /// Expecting header packets and the number of header packets left to decode. + HeaderPackets(u32), + /// Expecting a data block. + DataBlock, + /// Expecting the end of the file. This is to account for the last data block potentially being + /// shorter. + Eof, +} + +#[derive(Debug)] +pub struct Block { + next_block: BlockState, +} + +impl Block { + fn get_header_info(src: &mut BytesMut) -> Result { + deconstruct_header_info( + src + .split_to(HEADER_INFO_SIZE) + .as_ref() + .try_into() + .map_err(|_| SliceConversionError)?, + ) + .map_err(DecodingHeaderInfo) + } + + /// Parses the header info, updates the state and returns the block type. Unlike the other + /// `decode` methods, this method parses the header info before returning a decoded block + /// because the header info contains the number of packets which is required for decoding + /// the rest of the source. + pub fn decode_header_info(&mut self, src: &mut BytesMut) -> Result> { + // Header info is a fixed size. + if src.len() < HEADER_INFO_SIZE { + src.reserve(HEADER_INFO_SIZE); + return Ok(None); + } + + // Parse the header info because it contains the number of header packets. + let header_info = Self::get_header_info(src)?; + + self.next_block = BlockState::HeaderPackets(header_info.packets_count); + + Ok(Some(DecodedBlock::HeaderInfo(header_info))) + } + + /// Decodes header packets, updates the state and returns a header packet block type. + pub fn decode_header_packets( + &mut self, + src: &mut BytesMut, + header_packets: u32, + ) -> Result> { + let mut header_packet_bytes = vec![]; + for _ in 0..header_packets { + // Get enough bytes to read the header packet length. + if src.len() < HEADER_PACKET_LENGTH_SIZE { + src.reserve(HEADER_PACKET_LENGTH_SIZE); + return Ok(None); + } + + // Read the header packet length. + let length_bytes = src.split_to(HEADER_PACKET_LENGTH_SIZE).freeze(); + let mut length: usize = u32::from_le_bytes( + length_bytes + .as_ref() + .try_into() + .map_err(|_| SliceConversionError)?, + ) + .try_into() + .map_err(|_| NumericConversionError)?; + + // We have already taken 4 bytes out of the length. + length -= HEADER_PACKET_LENGTH_SIZE; + + // Have a maximum header size to prevent any overflows. + if length > MAX_HEADER_SIZE { + return Err(MaximumHeaderSize); + } + + // Get enough bytes to read the entire header packet. + if src.len() < length { + src.reserve(length - src.len()); + return Ok(None); + } + + header_packet_bytes.push(EncryptedHeaderPacketBytes::new( + length_bytes, + src.split_to(length).freeze(), + )); + } + + self.next_block = BlockState::DataBlock; + + let header_length = u64::try_from( + header_packet_bytes + .iter() + .map(|packet| packet.packet_length().len() + packet.header().len()) + .sum::(), + ) + .map_err(|_| NumericConversionError)?; + + Ok(Some(DecodedBlock::HeaderPackets( + EncryptedHeaderPackets::new(header_packet_bytes, header_length), + ))) + } + + /// Decodes data blocks, updates the state and returns a data block type. + pub fn decode_data_block(&mut self, src: &mut BytesMut) -> Result> { + // Data blocks are a fixed size, so we can return the + // next data block without much processing. + if src.len() < DATA_BLOCK_SIZE { + src.reserve(DATA_BLOCK_SIZE); + return Ok(None); + } + + self.next_block = BlockState::DataBlock; + + Ok(Some(DecodedBlock::DataBlock( + src.split_to(DATA_BLOCK_SIZE).freeze(), + ))) + } + + /// Get the standard size of all non-ending data blocks. + pub const fn standard_data_block_size() -> u64 { + DATA_BLOCK_SIZE as u64 + } + + /// Get the size of the magic string, version and header packet count. + pub const fn header_info_size() -> u64 { + HEADER_INFO_SIZE as u64 + } + + /// Get the encrypted block size, without nonce and mac bytes. + pub const fn encrypted_block_size() -> u64 { + ENCRYPTED_BLOCK_SIZE as u64 + } + + /// Get the size of the nonce. + pub const fn nonce_size() -> u64 { + NONCE_SIZE as u64 + } + + /// Get the size of the mac. + pub const fn mac_size() -> u64 { + MAC_SIZE as u64 + } + + /// Get the maximum possible header size. + pub const fn max_header_size() -> u64 { + MAX_HEADER_SIZE as u64 + } +} + +impl Default for Block { + fn default() -> Self { + Self { + next_block: BlockState::HeaderInfo, + } + } +} + +impl Decoder for Block { + type Item = DecodedBlock; + type Error = Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result> { + match self.next_block { + BlockState::HeaderInfo => self.decode_header_info(src), + BlockState::HeaderPackets(header_packets) => self.decode_header_packets(src, header_packets), + BlockState::DataBlock => self.decode_data_block(src), + BlockState::Eof => Ok(None), + } + } + + fn decode_eof(&mut self, buf: &mut BytesMut) -> Result> { + // Need a custom implementation of decode_eof because the last data block can be shorter. + match self.decode(buf)? { + Some(frame) => Ok(Some(frame)), + None => { + if buf.is_empty() { + Ok(None) + } else if let BlockState::DataBlock = self.next_block { + // The last data block can be smaller than 64KiB. + if buf.len() <= DATA_BLOCK_SIZE { + self.next_block = BlockState::Eof; + + Ok(Some(DecodedBlock::DataBlock(buf.split().freeze()))) + } else { + Err(Crypt4GHError( + "the last data block is too large".to_string(), + )) + } + } else { + Err(io::Error::new(io::ErrorKind::Other, "bytes remaining on stream").into()) + } + } + } + } +} + +#[cfg(test)] +pub(crate) mod tests { + use std::io::Cursor; + + use crypt4gh::header::{deconstruct_header_body, DecryptedHeaderPackets}; + use crypt4gh::{body_decrypt, Keys, WriteInfo}; + use futures_util::stream::Skip; + use futures_util::StreamExt; + use tokio::fs::File; + use tokio::io::AsyncReadExt; + use tokio_util::codec::FramedRead; + + use htsget_test::crypt4gh::get_decryption_keys; + use htsget_test::http_tests::get_test_file; + + use crate::tests::get_original_file; + + use super::*; + + #[tokio::test] + async fn decode_header_info() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let mut reader = FramedRead::new(src, Block::default()); + + let header_info = reader.next().await.unwrap().unwrap(); + + // Assert that the first block output is a header info with one packet. + assert!( + matches!(header_info, DecodedBlock::HeaderInfo(header_info) if header_info.packets_count == 1) + ); + } + + #[tokio::test] + async fn decode_header_packets() { + let (recipient_private_key, sender_public_key, header_packet, _) = + get_first_header_packet().await; + let header = get_header_packets(recipient_private_key, sender_public_key, header_packet); + + assert_first_header_packet(header); + + // Todo handle case where there is more than one header packet. + } + + #[tokio::test] + async fn decode_data_block() { + let (header, data_block) = get_data_block(0).await; + + let read_buf = Cursor::new(data_block.to_vec()); + let mut write_buf = Cursor::new(vec![]); + let mut write_info = WriteInfo::new(0, None, &mut write_buf); + + body_decrypt(read_buf, &header.data_enc_packets, &mut write_info, 0).unwrap(); + + let decrypted_bytes = write_buf.into_inner(); + + assert_first_data_block(decrypted_bytes).await; + } + + #[tokio::test] + async fn decode_eof() { + let (header, data_block) = get_data_block(39).await; + + let read_buf = Cursor::new(data_block.to_vec()); + let mut write_buf = Cursor::new(vec![]); + let mut write_info = WriteInfo::new(0, None, &mut write_buf); + + body_decrypt(read_buf, &header.data_enc_packets, &mut write_info, 0).unwrap(); + + let decrypted_bytes = write_buf.into_inner(); + + assert_last_data_block(decrypted_bytes).await; + } + + /// Assert that the first header packet is a data encryption key packet. + pub(crate) fn assert_first_header_packet(header: DecryptedHeaderPackets) { + assert_eq!(header.data_enc_packets.len(), 1); + assert!(header.edit_list_packet.is_none()); + } + + /// Assert that the last data block is equal to the expected ending bytes of the original file. + pub(crate) async fn assert_last_data_block(decrypted_bytes: Vec) { + let mut original_file = get_test_file("bam/htsnexus_test_NA12878.bam").await; + let mut original_bytes = vec![]; + original_file + .read_to_end(&mut original_bytes) + .await + .unwrap(); + + assert_eq!( + decrypted_bytes, + original_bytes + .into_iter() + .rev() + .take(40895) + .rev() + .collect::>() + ); + } + + /// Assert that the first data block is equal to the first 64KiB of the original file. + pub(crate) async fn assert_first_data_block(decrypted_bytes: Vec) { + let original_bytes = get_original_file().await; + + assert_eq!(decrypted_bytes, original_bytes[..65536]); + } + + /// Get the first header packet from the test file. + pub(crate) async fn get_first_header_packet( + ) -> (Keys, Vec, Vec, Skip>) { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = FramedRead::new(src, Block::default()).skip(1); + + // The second block should contain a header packet. + let header_packets = reader.next().await.unwrap().unwrap(); + + let (header_packet, header_length) = + if let DecodedBlock::HeaderPackets(header_packets) = header_packets { + Some(header_packets) + } else { + None + } + .unwrap() + .into_inner(); + + assert_eq!(header_length, 108); + + ( + recipient_private_key, + sender_public_key, + header_packet + .into_iter() + .map(|packet| packet.into_header_bytes()) + .collect(), + reader, + ) + } + + /// Get the first data block from the test file. + pub(crate) async fn get_data_block(skip: usize) -> (DecryptedHeaderPackets, Bytes) { + let (recipient_private_key, sender_public_key, header_packets, reader) = + get_first_header_packet().await; + let header = get_header_packets(recipient_private_key, sender_public_key, header_packets); + + let data_block = reader.skip(skip).next().await.unwrap().unwrap(); + + let data_block = if let DecodedBlock::DataBlock(data_block) = data_block { + Some(data_block) + } else { + None + } + .unwrap(); + + (header, data_block) + } + + /// Get the header packets from a decoded block. + pub(crate) fn get_header_packets( + recipient_private_key: Keys, + sender_public_key: Vec, + header_packets: Vec, + ) -> DecryptedHeaderPackets { + // Assert the size of the header packet is correct. + assert_eq!(header_packets.len(), 1); + assert_eq!(header_packets.first().unwrap().len(), 104); + + deconstruct_header_body( + header_packets + .into_iter() + .map(|header_packet| header_packet.to_vec()) + .collect(), + &[recipient_private_key], + &Some(sender_public_key), + ) + .unwrap() + } +} diff --git a/src/decrypter/builder.rs b/src/decrypter/builder.rs new file mode 100644 index 0000000..4c41f2c --- /dev/null +++ b/src/decrypter/builder.rs @@ -0,0 +1,95 @@ +use crypt4gh::Keys; +use tokio::io::{AsyncRead, AsyncSeek}; +use tokio_util::codec::FramedRead; + +use crate::decrypter::DecrypterStream; +use crate::error::Result; +use crate::PublicKey; + +/// An decrypter reader builder. +#[derive(Debug, Default)] +pub struct Builder { + sender_pubkey: Option, + stream_length: Option, + edit_list: Option>, +} + +impl Builder { + /// Sets the sender public key + pub fn with_sender_pubkey(self, sender_pubkey: PublicKey) -> Self { + self.set_sender_pubkey(Some(sender_pubkey)) + } + + /// Sets the sender public key + pub fn set_sender_pubkey(mut self, sender_pubkey: Option) -> Self { + self.sender_pubkey = sender_pubkey; + self + } + + /// Sets the stream length. + pub fn with_stream_length(self, stream_length: u64) -> Self { + self.set_stream_length(Some(stream_length)) + } + + /// Sets the stream length. + pub fn set_stream_length(mut self, stream_length: Option) -> Self { + self.stream_length = stream_length; + self + } + + /// Set the edit list manually. + pub fn with_edit_list(self, edit_list: Vec) -> Self { + self.set_edit_list(Some(edit_list)) + } + + /// Set the edit list manually. + pub fn set_edit_list(mut self, edit_list: Option>) -> Self { + self.edit_list = edit_list; + self + } + + /// Build the decrypter. + pub fn build(self, inner: R, keys: Vec) -> DecrypterStream + where + R: AsyncRead, + { + DecrypterStream { + inner: FramedRead::new(inner, Default::default()), + header_packet_future: None, + keys, + sender_pubkey: self.sender_pubkey, + session_keys: vec![], + encrypted_header_packets: None, + edit_list_packet: DecrypterStream::<()>::create_internal_edit_list(self.edit_list), + header_info: None, + header_length: None, + current_block_size: None, + stream_length: self.stream_length, + } + } + + /// Build the decrypter and compute the stream length for seek operations. This function will + /// ensure that recompute_stream_length is called at least once on the decrypter stream. + /// + /// This means that data block positions past the end of the stream will be valid and will equal + /// the the length of the stream. Use the build function if this behaviour is not desired. Seeking + /// past the end of the stream without a stream length is allowed but the behaviour is dependent + /// on the underlying reader and data block positions may not be valid. + pub async fn build_with_stream_length( + self, + inner: R, + keys: Vec, + ) -> Result> + where + R: AsyncRead + AsyncSeek + Unpin, + { + let stream_length = self.stream_length; + let mut stream = self.build(inner, keys); + + if stream_length.is_none() { + stream.recompute_stream_length().await?; + } + + Ok(stream) + } +} diff --git a/src/decrypter/data_block.rs b/src/decrypter/data_block.rs new file mode 100644 index 0000000..6ca726d --- /dev/null +++ b/src/decrypter/data_block.rs @@ -0,0 +1,211 @@ +use std::future::Future; +use std::io::Cursor; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use bytes::Bytes; +use crypt4gh::{body_decrypt, WriteInfo}; +use pin_project_lite::pin_project; +use tokio::task::JoinHandle; + +use crate::decrypter::DecrypterStream; +use crate::error::Error::{Crypt4GHError, JoinHandleError}; +use crate::error::Result; +use crate::{DecryptedBytes, DecryptedDataBlock}; + +pin_project! { + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct DataBlockDecrypter { + #[pin] + handle: JoinHandle> + } +} + +/// Represents the decrypted data block and its original encrypted size. +#[derive(Debug, Default)] +pub struct DecryptedDataBlock { + bytes: DecryptedBytes, + encrypted_size: usize, +} + +impl DecryptedDataBlock { + /// Create a new decrypted data block. + pub fn new(bytes: DecryptedBytes, encrypted_size: usize) -> Self { + Self { + bytes, + encrypted_size, + } + } + + /// Get the plain text bytes. + pub fn bytes(&self) -> &DecryptedBytes { + &self.bytes + } + + /// Get the encrypted size. + pub fn encrypted_size(&self) -> usize { + self.encrypted_size + } + + /// Get the inner bytes and size. + pub fn into_inner(self) -> (DecryptedBytes, usize) { + (self.bytes, self.encrypted_size) + } + + /// Get the length of the decrypted bytes. + pub const fn len(&self) -> usize { + self.bytes.len() + } + + /// Check if the decrypted bytes are empty + pub const fn is_empty(&self) -> bool { + self.bytes.is_empty() + } +} + +impl Deref for DecryptedDataBlock { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.bytes.deref() + } +} + +/// A wrapper around a vec of bytes that represents decrypted data. +#[derive(Debug, Default, Clone)] +pub struct DecryptedBytes(Bytes); + +impl DecryptedBytes { + /// Create new decrypted bytes from bytes. + pub fn new(bytes: Bytes) -> Self { + Self(bytes) + } + + /// Get the inner bytes. + pub fn into_inner(self) -> Bytes { + self.0 + } + + /// Get the length of the inner bytes. + pub const fn len(&self) -> usize { + self.0.len() + } + + /// Check if the inner bytes are empty. + pub const fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl Deref for DecryptedBytes { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.0.deref() + } +} + + +impl DataBlockDecrypter { + pub fn new( + data_block: Bytes, + session_keys: Vec>, + edit_list_packet: Option>, + ) -> Self { + Self { + handle: tokio::task::spawn_blocking(move || { + DataBlockDecrypter::decrypt(data_block, session_keys, edit_list_packet) + }), + } + } + + pub fn decrypt( + data_block: Bytes, + session_keys: Vec>, + edit_list_packet: Option>, + ) -> Result { + let size = data_block.len(); + + let read_buf = Cursor::new(data_block.to_vec()); + let mut write_buf = Cursor::new(vec![]); + let mut write_info = WriteInfo::new(0, None, &mut write_buf); + + // Todo crypt4gh-rust body_decrypt_parts does not work properly, so just apply edit list here. + body_decrypt(read_buf, session_keys.as_slice(), &mut write_info, 0) + .map_err(|err| Crypt4GHError(err.to_string()))?; + let mut decrypted_bytes: Bytes = write_buf.into_inner().into(); + let mut edited_bytes = Bytes::new(); + + let edits = DecrypterStream::<()>::create_internal_edit_list(edit_list_packet) + .unwrap_or(vec![(false, decrypted_bytes.len() as u64)]); + if edits.iter().map(|(_, edit)| edit).sum::() > decrypted_bytes.len() as u64 { + return Err(Crypt4GHError( + "invalid edit lists for the decrypted data block".to_string(), + )); + } + + edits.into_iter().for_each(|(discarding, edit)| { + if !discarding { + let edit = decrypted_bytes.slice(0..edit as usize); + edited_bytes = [edited_bytes.clone(), edit].concat().into(); + } + + decrypted_bytes = decrypted_bytes.slice(edit as usize..); + }); + + Ok(DecryptedDataBlock::new( + DecryptedBytes::new(edited_bytes), + size, + )) + } +} + +impl Future for DataBlockDecrypter { + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().handle.poll(cx).map_err(JoinHandleError)? + } +} + +#[cfg(test)] +mod tests { + use crate::decoder::tests::{assert_first_data_block, get_data_block}; + use crate::tests::get_original_file; + + use super::*; + + #[tokio::test] + async fn data_block_decrypter() { + let (header_packets, data_block) = get_data_block(0).await; + + let data = DataBlockDecrypter::new( + data_block, + header_packets.data_enc_packets, + header_packets.edit_list_packet, + ) + .await + .unwrap(); + + assert_first_data_block(data.bytes.to_vec()).await; + } + + #[tokio::test] + async fn data_block_decrypter_with_edit_list() { + let (header_packets, data_block) = get_data_block(0).await; + + let data = DataBlockDecrypter::new( + data_block, + header_packets.data_enc_packets, + Some(vec![0, 4668, 60868]), + ) + .await + .unwrap(); + + let original_bytes = get_original_file().await; + + assert_eq!(data.bytes.to_vec(), original_bytes[..4668]); + } +} diff --git a/src/decrypter/header/mod.rs b/src/decrypter/header/mod.rs new file mode 100644 index 0000000..278825f --- /dev/null +++ b/src/decrypter/header/mod.rs @@ -0,0 +1,41 @@ +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use tokio::io::AsyncRead; + +use crate::decrypter::DecrypterStream; +use crate::decrypter::Result; + +pub mod packets; + +/// A struct which will poll a decrypter stream until the session keys are found. +/// After polling the future, the underlying decrypter stream should have processed +/// the session keys. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct SessionKeysFuture<'a, R> { + handle: &'a mut DecrypterStream, +} + +impl<'a, R> SessionKeysFuture<'a, R> { + /// Create the future. + pub fn new(handle: &'a mut DecrypterStream) -> Self { + Self { handle } + } + + /// Get the inner handle. + pub fn get_mut(&mut self) -> &mut DecrypterStream { + self.handle + } +} + +impl<'a, R> Future for SessionKeysFuture<'a, R> +where + R: AsyncRead + Unpin, +{ + type Output = Result<()>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.handle.poll_session_keys_unpin(cx) + } +} diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs new file mode 100644 index 0000000..69ba5bc --- /dev/null +++ b/src/decrypter/header/packets.rs @@ -0,0 +1,81 @@ +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use bytes::Bytes; +use crypt4gh::header::{deconstruct_header_body, DecryptedHeaderPackets}; +use crypt4gh::Keys; +use pin_project_lite::pin_project; +use tokio::task::{spawn_blocking, JoinHandle}; + +use crate::error::Error::JoinHandleError; +use crate::error::Result; +use crate::PublicKey; + +pin_project! { + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct HeaderPacketsDecrypter { + #[pin] + handle: JoinHandle> + } +} + +impl HeaderPacketsDecrypter { + pub fn new( + header_packets: Vec, + keys: Vec, + sender_pubkey: Option, + ) -> Self { + Self { + handle: spawn_blocking(|| { + HeaderPacketsDecrypter::decrypt(header_packets, keys, sender_pubkey) + }), + } + } + + pub fn decrypt( + header_packets: Vec, + keys: Vec, + sender_pubkey: Option, + ) -> Result { + Ok(deconstruct_header_body( + header_packets + .into_iter() + .map(|bytes| bytes.to_vec()) + .collect(), + keys.as_slice(), + &sender_pubkey.map(|pubkey| pubkey.into_inner()), + )?) + } +} + +impl Future for HeaderPacketsDecrypter { + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().handle.poll(cx).map_err(JoinHandleError)? + } +} + +#[cfg(test)] +mod tests { + use crate::decoder::tests::{assert_first_header_packet, get_first_header_packet}; + + use super::*; + + #[tokio::test] + async fn header_packet_decrypter() { + let (recipient_private_key, sender_public_key, header_packets, _) = + get_first_header_packet().await; + + let data = HeaderPacketsDecrypter::new( + header_packets, + vec![recipient_private_key], + Some(PublicKey::new(sender_public_key)), + ) + .await + .unwrap(); + + assert_first_header_packet(data); + } +} diff --git a/src/decrypter/mod.rs b/src/decrypter/mod.rs new file mode 100644 index 0000000..be7545b --- /dev/null +++ b/src/decrypter/mod.rs @@ -0,0 +1,1329 @@ +use std::cmp::min; +use std::future::Future; +use std::io; +use std::io::SeekFrom; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use async_trait::async_trait; +use bytes::Bytes; +use crypt4gh::header::HeaderInfo; +use crypt4gh::Keys; +use futures::ready; +use futures::Stream; +use pin_project_lite::pin_project; +use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt}; +use tokio_util::codec::FramedRead; + +use crate::advance::Advance; +use crate::decoder::Block; +use crate::decoder::DecodedBlock; +use crate::decrypter::data_block::DataBlockDecrypter; +use crate::decrypter::header::packets::HeaderPacketsDecrypter; +use crate::decrypter::header::SessionKeysFuture; +use crate::error::Error::Crypt4GHError; +use crate::error::Result; +use crate::EncryptedHeaderPacketBytes; +use crate::{util, PublicKey}; + +pub mod builder; +pub mod data_block; +pub mod header; + +pin_project! { + /// A decrypter for an entire AsyncRead Crypt4GH file. + pub struct DecrypterStream { + #[pin] + inner: FramedRead, + #[pin] + header_packet_future: Option, + keys: Vec, + sender_pubkey: Option, + encrypted_header_packets: Option>, + header_info: Option, + session_keys: Vec>, + edit_list_packet: Option>, + header_length: Option, + current_block_size: Option, + stream_length: Option, + } +} + +impl DecrypterStream +where + R: AsyncRead, +{ + /// Partitions the edit list packet so that it applies to the current data block, returning a new + /// edit list that correctly discards and keeps the specified bytes this particular data block. + /// Todo, this should possibly go into the decoder, where bytes can be skipped directly. + pub fn partition_edit_list(mut self: Pin<&mut Self>, data_block: &Bytes) -> Option> { + let this = self.as_mut().project(); + + if let Some(edit_list) = this.edit_list_packet { + let mut new_edit_list = vec![]; + let mut bytes_consumed = 0; + + edit_list.retain_mut(|(discarding, value)| { + // If this is not a discarding edit, then discard 0 at the start. + if !*discarding && new_edit_list.is_empty() { + new_edit_list.push(0); + } + + // Get the encrypted block size. + let data_block_len = data_block.len() as u64 - Block::nonce_size() - Block::mac_size(); + + // Can only consume as many bytes as there are in the data block. + if min(bytes_consumed + *value, data_block_len) == data_block_len { + if bytes_consumed != data_block_len { + // If the whole data block hasn't been consumed yet, an edit still needs to be added. + let last_edit = data_block_len - bytes_consumed; + new_edit_list.push(last_edit); + + // And remove this edit from the next value. + *value -= last_edit; + // Now the whole data block has been consumed. + bytes_consumed = data_block_len; + } + + // Keep all values from now. + true + } else { + // Otherwise, consume the value and remove it from the edit list packet. + bytes_consumed += *value; + new_edit_list.push(*value); + false + } + }); + + (!new_edit_list.is_empty()).then_some(new_edit_list) + } else { + // If there is no edit list to begin with, we just keep the whole block. + None + } + } + + /// Polls a data block. This function shouldn't execute until all the header packets have been + /// processed. + pub fn poll_data_block( + mut self: Pin<&mut Self>, + data_block: Bytes, + ) -> Poll>> { + let edit_list = self.as_mut().partition_edit_list(&data_block); + + let this = self.project(); + Poll::Ready(Some(Ok(DataBlockDecrypter::new( + data_block, + // Todo make this so it doesn't use owned Keys and SenderPublicKey as it will be called asynchronously. + this.session_keys.clone(), + edit_list, + )))) + } + + /// Poll the stream until the header packets and session keys are processed. + pub fn poll_session_keys(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + // Only execute this function if there are no session keys. + if !self.session_keys.is_empty() { + return Poll::Ready(Ok(())); + } + + // Header packets are waiting to be decrypted. + if let Some(header_packet_decrypter) = self.as_mut().project().header_packet_future.as_pin_mut() + { + return match ready!(header_packet_decrypter.poll(cx)) { + Ok(header_packets) => { + let mut this = self.as_mut().project(); + + // Update the session keys and edit list packets. + this.header_packet_future.set(None); + this.session_keys.extend(header_packets.data_enc_packets); + if this.edit_list_packet.is_none() { + *this.edit_list_packet = + Self::create_internal_edit_list(header_packets.edit_list_packet); + } + + Poll::Ready(Ok(())) + } + Err(err) => Poll::Ready(Err(err)), + }; + } + + // No header packets yet, so more data needs to be decoded. + let mut this = self.as_mut().project(); + match ready!(this.inner.poll_next(cx)) { + Some(Ok(buf)) => match buf { + DecodedBlock::HeaderInfo(header_info) => { + // Store the header info but otherwise ignore it and poll again. + *this.header_info = Some(header_info); + cx.waker().wake_by_ref(); + Poll::Pending + } + // todo no clones here. + DecodedBlock::HeaderPackets(header_packets) => { + // Update the header length because we have access to the header packets. + let (header_packets, header_length) = header_packets.into_inner(); + *this.encrypted_header_packets = Some(header_packets.clone()); + *this.header_length = Some(header_length + Block::header_info_size()); + + // Add task for decrypting the header packets. + this + .header_packet_future + .set(Some(HeaderPacketsDecrypter::new( + header_packets + .into_iter() + .map(|packet| packet.into_header_bytes()) + .collect(), + this.keys.clone(), + this.sender_pubkey.clone(), + ))); + + // Poll again. + cx.waker().wake_by_ref(); + Poll::Pending + } + DecodedBlock::DataBlock(_) => Poll::Ready(Err(Crypt4GHError( + "data block reached without finding session keys".to_string(), + ))), + }, + Some(Err(e)) => Poll::Ready(Err(e)), + None => Poll::Ready(Err(Crypt4GHError( + "end of stream reached without finding session keys".to_string(), + ))), + } + } + + /// Convenience for calling [`poll_session_keys`] on [`Unpin`] types. + pub fn poll_session_keys_unpin(&mut self, cx: &mut Context<'_>) -> Poll> + where + Self: Unpin, + { + Pin::new(self).poll_session_keys(cx) + } + + /// Poll the stream until the header has been read. + pub async fn read_header(&mut self) -> Result<()> + where + R: Unpin, + { + SessionKeysFuture::new(self).await + } +} + +impl DecrypterStream { + /// An override for setting the stream length. + pub async fn set_stream_length(&mut self, length: u64) { + self.stream_length = Some(length); + } + + /// Get a reference to the inner reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref() + } + + /// Get a mutable reference to the inner reader. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut() + } + + /// Get a pinned mutable reference to the inner reader. + pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut R> { + self.project().inner.get_pin_mut() + } + + /// Get the inner reader. + pub fn into_inner(self) -> R { + self.inner.into_inner() + } + + /// Get the length of the header, including the magic string, version number, packet count + /// and the header packets. Returns `None` before the header packet is polled. + pub fn header_size(&self) -> Option { + self.header_length + } + + /// Get the size of the current data block represented by the encrypted block returned by calling + /// poll_next. This will equal `decoder::DATA_BLOCK_SIZE` except for the last block which may be + /// less than that. Returns `None` before the first data block is polled. + pub fn current_block_size(&self) -> Option { + self.current_block_size + } + + /// Clamps the byte position to the nearest data block if the header length is known. This + /// function takes into account the stream length if it is present. + pub fn clamp_position(&self, position: u64) -> Option { + self.header_size().map(|length| { + if position < length { + length + } else { + match self.stream_length { + Some(end_length) if position >= end_length => end_length, + _ => { + let remainder = (position - length) % Block::standard_data_block_size(); + + position - remainder + } + } + } + }) + } + + /// Convert an unencrypted position to an encrypted position if the header length is known. + pub fn to_encrypted(&self, position: u64) -> Option { + self.header_size().map(|length| { + let encrypted_position = util::to_encrypted(position, length); + + match self.stream_length { + Some(end_length) if encrypted_position + Block::mac_size() > end_length => end_length, + _ => encrypted_position, + } + }) + } + + /// Get the session keys. Empty before the header is polled. + pub fn session_keys(&self) -> &[Vec] { + &self.session_keys + } + + /// Get the edit list packet. Empty before the header is polled. + pub fn edit_list_packet(&self) -> Option> { + self + .edit_list_packet + .as_ref() + .map(|packet| packet.iter().map(|(_, edit)| *edit).collect()) + } + + /// Get the header info. + pub fn header_info(&self) -> Option<&HeaderInfo> { + self.header_info.as_ref() + } + + /// Get the original encrypted header packets, not including the header info. + pub fn encrypted_header_packets(&self) -> Option<&Vec> { + self.encrypted_header_packets.as_ref() + } + + /// Get the stream's keys. + pub fn keys(&self) -> &[Keys] { + self.keys.as_slice() + } + + pub(crate) fn create_internal_edit_list(edit_list: Option>) -> Option> { + edit_list.map(|edits| [true, false].iter().cloned().cycle().zip(edits).collect()) + } +} + +impl DecrypterStream +where + R: AsyncRead + AsyncSeek + Unpin, +{ + /// Recompute the stream length. Having a stream length means that data block positions past the + /// end of the stream will be valid and will equal the the length of the stream. By default this + /// struct contains no stream length when it is initialized. + /// + /// This can take up to 3 seek calls. If the size of the underlying buffer changes, this function + /// should be called again, otherwise data block positions may not be valid. + pub async fn recompute_stream_length(&mut self) -> Result { + let inner = self.inner.get_mut(); + + let position = inner.seek(SeekFrom::Current(0)).await?; + let length = inner.seek(SeekFrom::End(0)).await?; + + if position != length { + inner.seek(SeekFrom::Start(position)).await?; + } + + self.stream_length = Some(length); + + Ok(length) + } +} + +impl Stream for DecrypterStream +where + R: AsyncRead, +{ + type Item = Result; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + // When polling, we first need to process enough data to get the session keys. + if let Err(err) = ready!(self.as_mut().poll_session_keys(cx)) { + return Poll::Ready(Some(Err(err))); + } + + let this = self.as_mut().project(); + let item = this.inner.poll_next(cx); + + match ready!(item) { + Some(Ok(buf)) => match buf { + DecodedBlock::HeaderInfo(_) | DecodedBlock::HeaderPackets(_) => { + // Session keys have already been read, so ignore the header info and header packets + // and poll again + cx.waker().wake_by_ref(); + Poll::Pending + } + DecodedBlock::DataBlock(data_block) => { + // The new size of the data block is available, so update it. + *this.current_block_size = Some(data_block.len()); + + // Session keys have been obtained so process the data blocks. + self.poll_data_block(data_block) + } + }, + Some(Err(e)) => Poll::Ready(Some(Err(e))), + None => Poll::Ready(None), + } + } +} + +impl DecrypterStream +where + R: AsyncRead + AsyncSeek + Unpin + Send, +{ + /// Seek to a position in the encrypted stream. + pub async fn seek_encrypted(&mut self, position: SeekFrom) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // First poll to the position specified. + let seek = self.inner.get_mut().seek(position).await?; + + // Then advance to the correct data block position. + let advance = self.advance_encrypted(seek).await?; + + // Then seek to the correct position. + let seek = self.inner.get_mut().seek(SeekFrom::Start(advance)).await?; + self.inner.read_buffer_mut().clear(); + + Ok(seek) + } + + /// Seek to a position in the unencrypted stream. + pub async fn seek_unencrypted(&mut self, position: u64) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // Convert to an encrypted position and seek + let position = self + .to_encrypted(position) + .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; + + // Then do the seek. + self.seek_encrypted(SeekFrom::Start(position)).await + } +} + +#[async_trait] +impl Advance for DecrypterStream +where + R: AsyncRead + Send + Unpin, +{ + async fn advance_encrypted(&mut self, position: u64) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // Get the next position. + let data_block_position = self + .clamp_position(position) + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "could not find data block position"))?; + + Ok(data_block_position) + } + + async fn advance_unencrypted(&mut self, position: u64) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // Convert to an encrypted position and seek + let position = self + .to_encrypted(position) + .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; + + // Then do the advance. + self.advance_encrypted(position).await + } + + fn stream_length(&self) -> Option { + self.stream_length + } +} + +#[cfg(test)] +mod tests { + use bytes::BytesMut; + use futures_util::future::join_all; + use futures_util::StreamExt; + use tokio::fs::File; + + use htsget_test::http_tests::get_test_file; + + use crate::decoder::tests::assert_last_data_block; + use crate::decrypter::builder::Builder; + use crate::tests::get_original_file; + use htsget_test::crypt4gh::get_decryption_keys; + + use super::*; + + #[tokio::test] + async fn partition_edit_lists() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_edit_list(vec![60113, 100000, 65536]) + .build(src, vec![recipient_private_key]); + + assert_edit_list(&mut stream, Some(vec![60113, 5423]), vec![0; 65564]); + assert_edit_list(&mut stream, Some(vec![0, 65536]), vec![0; 65564]); + assert_edit_list(&mut stream, Some(vec![0, 29041, 36495]), vec![0; 65564]); + assert_edit_list(&mut stream, Some(vec![29041]), vec![0; 29041 + 12 + 16]); + } + + fn assert_edit_list( + stream: &mut DecrypterStream, + expected: Option>, + bytes: Vec, + ) { + let stream = Pin::new(stream); + let edit_list = stream.partition_edit_list(&Bytes::from(bytes)); + assert_eq!(edit_list, expected); + } + + #[tokio::test] + async fn decrypter_stream() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn get_header_length() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + assert!(stream.header_size().is_none()); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.header_size(), Some(124)); + } + + #[tokio::test] + async fn first_block_size() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + assert!(stream.current_block_size().is_none()); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.current_block_size(), Some(65564)); + } + + #[tokio::test] + async fn last_block_size() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + assert!(stream.current_block_size().is_none()); + + let mut stream = stream.skip(39); + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.get_ref().current_block_size(), Some(40923)); + } + + #[tokio::test] + async fn clamp_position_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.clamp_position(0), Some(124)); + assert_eq!(stream.clamp_position(124), Some(124)); + assert_eq!(stream.clamp_position(200), Some(124)); + } + + #[tokio::test] + async fn clamp_position_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.clamp_position(80000), Some(124 + 65564)); + } + + #[tokio::test] + async fn clamp_position_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.clamp_position(2598044), Some(2598043)); + } + + #[tokio::test] + async fn convert_position_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + let pos = stream.to_encrypted(0); + assert_eq!(pos, Some(124)); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); + + let pos = stream.to_encrypted(200); + assert_eq!(pos, Some(124 + 12 + 200)); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); + } + + #[tokio::test] + async fn convert_position_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + let pos = stream.to_encrypted(80000); + assert_eq!(pos, Some(124 + 65564 + 12 + (80000 - 65536))); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(124 + 65564)); + } + + #[tokio::test] + async fn convert_position_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + let _ = stream.next().await.unwrap().unwrap().await; + + let pos = stream.to_encrypted(2596800); + assert_eq!(pos, Some(2598043)); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(2598043)); + } + + #[tokio::test] + async fn seek_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::Start(80000)).await.unwrap(); + + assert_eq!(seek, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let seek = stream + .seek_encrypted(SeekFrom::Current(-20000)) + .await + .unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::End(-1000)).await.unwrap(); + + assert_eq!(seek, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let block = stream.next().await.unwrap().unwrap().await.unwrap(); + assert_last_data_block(block.bytes.to_vec()).await; + } + + #[tokio::test] + async fn seek_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn seek_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn advance_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(0).await.unwrap(); + + assert_eq!(advance, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(80000).await.unwrap(); + + assert_eq!(advance, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(2598042).await.unwrap(); + + assert_eq!(advance, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(2598044).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let advance = stream.advance_encrypted(2598044).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(0).await.unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_second_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(65537).await.unwrap(); + + assert_eq!(seek, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let seek = stream.seek_unencrypted(65535).await.unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(2596799).await.unwrap(); + + assert_eq!(seek, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let block = stream.next().await.unwrap().unwrap().await.unwrap(); + assert_last_data_block(block.bytes.to_vec()).await; + } + + #[tokio::test] + async fn seek_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(2596800).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn seek_past_end_stream_unencrypted_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let seek = stream.seek_unencrypted(2596800).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn advance_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(0).await.unwrap(); + + assert_eq!(advance, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_second_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(65537).await.unwrap(); + + assert_eq!(advance, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(2596799).await.unwrap(); + + assert_eq!(advance, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(2596800).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end_unencrypted_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let advance = stream.advance_unencrypted(2596800).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } +} diff --git a/src/edit_lists.rs b/src/edit_lists.rs new file mode 100644 index 0000000..221f10c --- /dev/null +++ b/src/edit_lists.rs @@ -0,0 +1,339 @@ +use std::collections::HashSet; + +use crypt4gh::header::{encrypt, make_packet_data_edit_list, HeaderInfo}; +use crypt4gh::Keys; +use rustls::PrivateKey; +use tokio::io::AsyncRead; + +use crate::error::{Error, Result}; +use crate::reader::Reader; +use crate::PublicKey; + +/// Unencrypted byte range positions. Contains inclusive start values and exclusive end values. +#[derive(Debug, Clone)] +pub struct UnencryptedPosition { + start: u64, + end: u64, +} + +impl UnencryptedPosition { + pub fn new(start: u64, end: u64) -> Self { + Self { start, end } + } + + pub fn start(&self) -> u64 { + self.start + } + + pub fn end(&self) -> u64 { + self.end + } +} + +/// Encrypted byte range positions. Contains inclusive start values and exclusive end values. +#[derive(Debug, Clone)] +pub struct ClampedPosition { + start: u64, + end: u64, +} + +impl ClampedPosition { + pub fn new(start: u64, end: u64) -> Self { + Self { start, end } + } + + pub fn start(&self) -> u64 { + self.start + } + + pub fn end(&self) -> u64 { + self.end + } +} + +/// Bytes representing a header packet with an edit list. +#[derive(Debug, Clone)] +pub struct Header { + header_info: Vec, + original_header: Vec, + edit_list_packet: Vec, +} + +impl Header { + pub fn new(header_info: Vec, original_header: Vec, edit_list_packet: Vec) -> Self { + Self { + header_info, + original_header, + edit_list_packet, + } + } + + pub fn into_inner(self) -> (Vec, Vec, Vec) { + ( + self.header_info, + self.original_header, + self.edit_list_packet, + ) + } + + pub fn as_slice(&self) -> Vec { + [ + self.header_info.as_slice(), + self.original_header.as_slice(), + self.edit_list_packet.as_slice(), + ] + .concat() + } +} + +impl From<(Vec, Vec, Vec)> for Header { + fn from((header_info, original_header, edit_list_packet): (Vec, Vec, Vec)) -> Self { + Self::new(header_info, original_header, edit_list_packet) + } +} + +pub struct EditHeader<'a, R> +where + R: AsyncRead + Unpin, +{ + reader: &'a Reader, + unencrypted_positions: Vec, + clamped_positions: Vec, + private_key: PrivateKey, + recipient_public_key: PublicKey, +} + +impl<'a, R> EditHeader<'a, R> +where + R: AsyncRead + Unpin, +{ + pub fn new( + reader: &'a Reader, + unencrypted_positions: Vec, + clamped_positions: Vec, + private_key: PrivateKey, + recipient_public_key: PublicKey, + ) -> Self { + Self { + reader, + unencrypted_positions, + clamped_positions, + private_key, + recipient_public_key, + } + } + + /// Encrypt the edit list packet. + pub fn encrypt_edit_list(&self, edit_list_packet: Vec) -> Result> { + let keys = Keys { + method: 0, + privkey: self.private_key.clone().0, + recipient_pubkey: self.recipient_public_key.clone().into_inner(), + }; + + encrypt(&edit_list_packet, &HashSet::from_iter(vec![keys]))? + .into_iter() + .last() + .ok_or_else(|| Error::Crypt4GHError("could not encrypt header packet".to_string())) + } + + /// Create the edit lists from the unencrypted byte positions. + pub fn create_edit_list(&self) -> Vec { + let mut unencrypted_positions: Vec = self + .unencrypted_positions + .iter() + .flat_map(|pos| [pos.start, pos.end]) + .collect(); + + // Collect the clamped and unencrypted positions into separate edit list groups. + let (mut edit_list, last_discard) = + self + .clamped_positions + .iter() + .fold((vec![], 0), |(mut edit_list, previous_discard), pos| { + // Get the correct number of unencrypted positions that fit within this clamped position. + let partition = + unencrypted_positions.partition_point(|unencrypted_pos| unencrypted_pos <= &pos.end); + let mut positions: Vec = unencrypted_positions.drain(..partition).collect(); + + // Merge all positions. + positions.insert(0, pos.start); + positions.push(pos.end); + + // Find the difference between consecutive positions to get the edits. + let mut positions: Vec = positions + .iter() + .zip(positions.iter().skip(1)) + .map(|(start, end)| end - start) + .collect(); + + // Add the previous discard to the first edit. + if let Some(first) = positions.first_mut() { + *first += previous_discard; + } + + // If the last edit is a discard, then carry this over into the next iteration. + let next_discard = if positions.len() % 2 == 0 { + 0 + } else { + positions.pop().unwrap_or(0) + }; + + // Add edits to the accumulating edit list. + edit_list.extend(positions); + (edit_list, next_discard) + }); + + // If there is a final discard, then add this to the edit list. + if last_discard != 0 { + edit_list.push(last_discard); + } + + edit_list + } + + /// Add edit lists and return a header packet. + pub fn edit_list(self) -> Result> { + if self.reader.edit_list_packet().is_some() { + return Err(Error::Crypt4GHError("edit lists already exist".to_string())); + } + + // Todo, header info should have copy or clone on it. + let (mut header_info, encrypted_header_packets) = + if let (Some(header_info), Some(encrypted_header_packets)) = ( + self.reader.header_info(), + self.reader.encrypted_header_packets(), + ) { + ( + HeaderInfo { + magic_number: header_info.magic_number, + version: header_info.version, + packets_count: header_info.packets_count, + }, + encrypted_header_packets + .iter() + .flat_map(|packet| [packet.packet_length().to_vec(), packet.header.to_vec()].concat()) + .collect::>(), + ) + } else { + return Ok(None); + }; + + // Todo rewrite this from the context of an encryption stream like the decrypter. + header_info.packets_count += 1; + let header_info_bytes = + bincode::serialize(&header_info).map_err(|err| Error::Crypt4GHError(err.to_string()))?; + + let edit_list = self.create_edit_list(); + let edit_list_packet = + make_packet_data_edit_list(edit_list.into_iter().map(|edit| edit as usize).collect()); + + let edit_list_bytes = self.encrypt_edit_list(edit_list_packet)?; + let edit_list_bytes = [ + ((edit_list_bytes.len() + 4) as u32).to_le_bytes().to_vec(), + edit_list_bytes, + ] + .concat(); + + Ok(Some( + (header_info_bytes, encrypted_header_packets, edit_list_bytes).into(), + )) + } +} + +#[cfg(test)] +mod tests { + use htsget_test::crypt4gh::{get_decryption_keys, get_encryption_keys}; + use htsget_test::http_tests::get_test_file; + + use crate::reader::builder::Builder; + + use super::*; + + #[tokio::test] + async fn test_append_edit_list() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (private_key_decrypt, public_key_decrypt) = get_decryption_keys().await; + let (private_key_encrypt, public_key_encrypt) = get_encryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(public_key_decrypt.clone())) + .with_stream_length(5485112) + .build_with_reader(src, vec![private_key_decrypt.clone()]); + reader.read_header().await.unwrap(); + + let expected_data_packets = reader.session_keys().to_vec(); + + let header = EditHeader::new( + &reader, + test_unencrypted_positions(), + test_clamped_positions(), + PrivateKey(private_key_encrypt.clone().privkey), + PublicKey { + bytes: public_key_encrypt.clone(), + }, + ) + .edit_list() + .unwrap() + .unwrap(); + + let header_slice = header.as_slice(); + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(public_key_decrypt)) + .with_stream_length(5485112) + .build_with_reader(header_slice.as_slice(), vec![private_key_decrypt]); + reader.read_header().await.unwrap(); + + let data_packets = reader.session_keys(); + assert_eq!(data_packets, expected_data_packets); + + let edit_lists = reader.edit_list_packet().unwrap(); + assert_eq!(edit_lists, expected_edit_list()); + } + + #[tokio::test] + async fn test_create_edit_list() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (private_key_decrypt, public_key_decrypt) = get_decryption_keys().await; + let (private_key_encrypt, public_key_encrypt) = get_encryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(public_key_decrypt.clone())) + .with_stream_length(5485112) + .build_with_reader(src, vec![private_key_decrypt.clone()]); + reader.read_header().await.unwrap(); + + let edit_list = EditHeader::new( + &reader, + test_unencrypted_positions(), + test_clamped_positions(), + PrivateKey(private_key_encrypt.clone().privkey), + PublicKey { + bytes: public_key_encrypt.clone(), + }, + ) + .create_edit_list(); + + assert_eq!(edit_list, expected_edit_list()); + } + + fn test_unencrypted_positions() -> Vec { + vec![ + UnencryptedPosition::new(0, 7853), + UnencryptedPosition::new(145110, 453039), + UnencryptedPosition::new(5485074, 5485112), + ] + } + + fn test_clamped_positions() -> Vec { + vec![ + ClampedPosition::new(0, 65536), + ClampedPosition::new(131072, 458752), + ClampedPosition::new(5439488, 5485112), + ] + } + + fn expected_edit_list() -> Vec { + vec![0, 7853, 71721, 307929, 51299, 38] + } +} diff --git a/src/encrypter/builder.rs b/src/encrypter/builder.rs new file mode 100644 index 0000000..4c41f2c --- /dev/null +++ b/src/encrypter/builder.rs @@ -0,0 +1,95 @@ +use crypt4gh::Keys; +use tokio::io::{AsyncRead, AsyncSeek}; +use tokio_util::codec::FramedRead; + +use crate::decrypter::DecrypterStream; +use crate::error::Result; +use crate::PublicKey; + +/// An decrypter reader builder. +#[derive(Debug, Default)] +pub struct Builder { + sender_pubkey: Option, + stream_length: Option, + edit_list: Option>, +} + +impl Builder { + /// Sets the sender public key + pub fn with_sender_pubkey(self, sender_pubkey: PublicKey) -> Self { + self.set_sender_pubkey(Some(sender_pubkey)) + } + + /// Sets the sender public key + pub fn set_sender_pubkey(mut self, sender_pubkey: Option) -> Self { + self.sender_pubkey = sender_pubkey; + self + } + + /// Sets the stream length. + pub fn with_stream_length(self, stream_length: u64) -> Self { + self.set_stream_length(Some(stream_length)) + } + + /// Sets the stream length. + pub fn set_stream_length(mut self, stream_length: Option) -> Self { + self.stream_length = stream_length; + self + } + + /// Set the edit list manually. + pub fn with_edit_list(self, edit_list: Vec) -> Self { + self.set_edit_list(Some(edit_list)) + } + + /// Set the edit list manually. + pub fn set_edit_list(mut self, edit_list: Option>) -> Self { + self.edit_list = edit_list; + self + } + + /// Build the decrypter. + pub fn build(self, inner: R, keys: Vec) -> DecrypterStream + where + R: AsyncRead, + { + DecrypterStream { + inner: FramedRead::new(inner, Default::default()), + header_packet_future: None, + keys, + sender_pubkey: self.sender_pubkey, + session_keys: vec![], + encrypted_header_packets: None, + edit_list_packet: DecrypterStream::<()>::create_internal_edit_list(self.edit_list), + header_info: None, + header_length: None, + current_block_size: None, + stream_length: self.stream_length, + } + } + + /// Build the decrypter and compute the stream length for seek operations. This function will + /// ensure that recompute_stream_length is called at least once on the decrypter stream. + /// + /// This means that data block positions past the end of the stream will be valid and will equal + /// the the length of the stream. Use the build function if this behaviour is not desired. Seeking + /// past the end of the stream without a stream length is allowed but the behaviour is dependent + /// on the underlying reader and data block positions may not be valid. + pub async fn build_with_stream_length( + self, + inner: R, + keys: Vec, + ) -> Result> + where + R: AsyncRead + AsyncSeek + Unpin, + { + let stream_length = self.stream_length; + let mut stream = self.build(inner, keys); + + if stream_length.is_none() { + stream.recompute_stream_length().await?; + } + + Ok(stream) + } +} diff --git a/src/encrypter/data_block.rs b/src/encrypter/data_block.rs new file mode 100644 index 0000000..e4eee3a --- /dev/null +++ b/src/encrypter/data_block.rs @@ -0,0 +1,124 @@ +use std::future::Future; +use std::io::Cursor; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use bytes::Bytes; +use crypt4gh::{body_decrypt, WriteInfo}; +use pin_project_lite::pin_project; +use tokio::task::JoinHandle; + +use crate::decrypter::DecrypterStream; +use crate::error::Error::{Crypt4GHError, JoinHandleError}; +use crate::error::Result; +use crate::{DecryptedBytes, DecryptedDataBlock}; + +pin_project! { + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct DataBlockDecrypter { + #[pin] + handle: JoinHandle> + } +} + +impl DataBlockDecrypter { + pub fn new( + data_block: Bytes, + session_keys: Vec>, + edit_list_packet: Option>, + ) -> Self { + Self { + handle: tokio::task::spawn_blocking(move || { + DataBlockDecrypter::decrypt(data_block, session_keys, edit_list_packet) + }), + } + } + + pub fn decrypt( + data_block: Bytes, + session_keys: Vec>, + edit_list_packet: Option>, + ) -> Result { + let size = data_block.len(); + + let read_buf = Cursor::new(data_block.to_vec()); + let mut write_buf = Cursor::new(vec![]); + let mut write_info = WriteInfo::new(0, None, &mut write_buf); + + // Todo crypt4gh-rust body_decrypt_parts does not work properly, so just apply edit list here. + body_decrypt(read_buf, session_keys.as_slice(), &mut write_info, 0) + .map_err(|err| Crypt4GHError(err.to_string()))?; + let mut decrypted_bytes: Bytes = write_buf.into_inner().into(); + let mut edited_bytes = Bytes::new(); + + let edits = DecrypterStream::<()>::create_internal_edit_list(edit_list_packet) + .unwrap_or(vec![(false, decrypted_bytes.len() as u64)]); + if edits.iter().map(|(_, edit)| edit).sum::() > decrypted_bytes.len() as u64 { + return Err(Crypt4GHError( + "invalid edit lists for the decrypted data block".to_string(), + )); + } + + edits.into_iter().for_each(|(discarding, edit)| { + if !discarding { + let edit = decrypted_bytes.slice(0..edit as usize); + edited_bytes = [edited_bytes.clone(), edit].concat().into(); + } + + decrypted_bytes = decrypted_bytes.slice(edit as usize..); + }); + + Ok(DecryptedDataBlock::new( + DecryptedBytes::new(edited_bytes), + size, + )) + } +} + +impl Future for DataBlockDecrypter { + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().handle.poll(cx).map_err(JoinHandleError)? + } +} + +#[cfg(test)] +mod tests { + use crate::decoder::tests::{assert_first_data_block, get_data_block}; + use crate::tests::get_original_file; + + use super::*; + + #[tokio::test] + async fn data_block_decrypter() { + let (header_packets, data_block) = get_data_block(0).await; + + let data = DataBlockDecrypter::new( + data_block, + header_packets.data_enc_packets, + header_packets.edit_list_packet, + ) + .await + .unwrap(); + + assert_first_data_block(data.bytes.to_vec()).await; + } + + #[tokio::test] + async fn data_block_decrypter_with_edit_list() { + let (header_packets, data_block) = get_data_block(0).await; + + let data = DataBlockDecrypter::new( + data_block, + header_packets.data_enc_packets, + Some(vec![0, 4668, 60868]), + ) + .await + .unwrap(); + + let original_bytes = get_original_file().await; + + assert_eq!(data.bytes.to_vec(), original_bytes[..4668]); + } +} diff --git a/src/encrypter/header/mod.rs b/src/encrypter/header/mod.rs new file mode 100644 index 0000000..f516309 --- /dev/null +++ b/src/encrypter/header/mod.rs @@ -0,0 +1,41 @@ +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use tokio::io::AsyncRead; + +use crate::encrypter::EncrypterStream; +use crate::encrypter::Result; + +pub mod packets; + +/// A struct which will poll an encrypter stream until the session keys are found. +/// After polling the future, the underlying encrypter stream should have processed +/// the session keys. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct SessionKeysFuture<'a, R> { + handle: &'a mut EncrypterStream, +} + +impl<'a, R> SessionKeysFuture<'a, R> { + /// Create the future. + pub fn new(handle: &'a mut EncrypterStream) -> Self { + Self { handle } + } + + /// Get the inner handle. + pub fn get_mut(&mut self) -> &mut EncrypterStream { + self.handle + } +} + +impl<'a, R> Future for SessionKeysFuture<'a, R> +where + R: AsyncRead + Unpin, +{ + type Output = Result<()>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.handle.poll_session_keys_unpin(cx) + } +} diff --git a/src/encrypter/header/packets.rs b/src/encrypter/header/packets.rs new file mode 100644 index 0000000..69ba5bc --- /dev/null +++ b/src/encrypter/header/packets.rs @@ -0,0 +1,81 @@ +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use bytes::Bytes; +use crypt4gh::header::{deconstruct_header_body, DecryptedHeaderPackets}; +use crypt4gh::Keys; +use pin_project_lite::pin_project; +use tokio::task::{spawn_blocking, JoinHandle}; + +use crate::error::Error::JoinHandleError; +use crate::error::Result; +use crate::PublicKey; + +pin_project! { + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct HeaderPacketsDecrypter { + #[pin] + handle: JoinHandle> + } +} + +impl HeaderPacketsDecrypter { + pub fn new( + header_packets: Vec, + keys: Vec, + sender_pubkey: Option, + ) -> Self { + Self { + handle: spawn_blocking(|| { + HeaderPacketsDecrypter::decrypt(header_packets, keys, sender_pubkey) + }), + } + } + + pub fn decrypt( + header_packets: Vec, + keys: Vec, + sender_pubkey: Option, + ) -> Result { + Ok(deconstruct_header_body( + header_packets + .into_iter() + .map(|bytes| bytes.to_vec()) + .collect(), + keys.as_slice(), + &sender_pubkey.map(|pubkey| pubkey.into_inner()), + )?) + } +} + +impl Future for HeaderPacketsDecrypter { + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().handle.poll(cx).map_err(JoinHandleError)? + } +} + +#[cfg(test)] +mod tests { + use crate::decoder::tests::{assert_first_header_packet, get_first_header_packet}; + + use super::*; + + #[tokio::test] + async fn header_packet_decrypter() { + let (recipient_private_key, sender_public_key, header_packets, _) = + get_first_header_packet().await; + + let data = HeaderPacketsDecrypter::new( + header_packets, + vec![recipient_private_key], + Some(PublicKey::new(sender_public_key)), + ) + .await + .unwrap(); + + assert_first_header_packet(data); + } +} diff --git a/src/encrypter/mod.rs b/src/encrypter/mod.rs new file mode 100644 index 0000000..be7545b --- /dev/null +++ b/src/encrypter/mod.rs @@ -0,0 +1,1329 @@ +use std::cmp::min; +use std::future::Future; +use std::io; +use std::io::SeekFrom; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use async_trait::async_trait; +use bytes::Bytes; +use crypt4gh::header::HeaderInfo; +use crypt4gh::Keys; +use futures::ready; +use futures::Stream; +use pin_project_lite::pin_project; +use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt}; +use tokio_util::codec::FramedRead; + +use crate::advance::Advance; +use crate::decoder::Block; +use crate::decoder::DecodedBlock; +use crate::decrypter::data_block::DataBlockDecrypter; +use crate::decrypter::header::packets::HeaderPacketsDecrypter; +use crate::decrypter::header::SessionKeysFuture; +use crate::error::Error::Crypt4GHError; +use crate::error::Result; +use crate::EncryptedHeaderPacketBytes; +use crate::{util, PublicKey}; + +pub mod builder; +pub mod data_block; +pub mod header; + +pin_project! { + /// A decrypter for an entire AsyncRead Crypt4GH file. + pub struct DecrypterStream { + #[pin] + inner: FramedRead, + #[pin] + header_packet_future: Option, + keys: Vec, + sender_pubkey: Option, + encrypted_header_packets: Option>, + header_info: Option, + session_keys: Vec>, + edit_list_packet: Option>, + header_length: Option, + current_block_size: Option, + stream_length: Option, + } +} + +impl DecrypterStream +where + R: AsyncRead, +{ + /// Partitions the edit list packet so that it applies to the current data block, returning a new + /// edit list that correctly discards and keeps the specified bytes this particular data block. + /// Todo, this should possibly go into the decoder, where bytes can be skipped directly. + pub fn partition_edit_list(mut self: Pin<&mut Self>, data_block: &Bytes) -> Option> { + let this = self.as_mut().project(); + + if let Some(edit_list) = this.edit_list_packet { + let mut new_edit_list = vec![]; + let mut bytes_consumed = 0; + + edit_list.retain_mut(|(discarding, value)| { + // If this is not a discarding edit, then discard 0 at the start. + if !*discarding && new_edit_list.is_empty() { + new_edit_list.push(0); + } + + // Get the encrypted block size. + let data_block_len = data_block.len() as u64 - Block::nonce_size() - Block::mac_size(); + + // Can only consume as many bytes as there are in the data block. + if min(bytes_consumed + *value, data_block_len) == data_block_len { + if bytes_consumed != data_block_len { + // If the whole data block hasn't been consumed yet, an edit still needs to be added. + let last_edit = data_block_len - bytes_consumed; + new_edit_list.push(last_edit); + + // And remove this edit from the next value. + *value -= last_edit; + // Now the whole data block has been consumed. + bytes_consumed = data_block_len; + } + + // Keep all values from now. + true + } else { + // Otherwise, consume the value and remove it from the edit list packet. + bytes_consumed += *value; + new_edit_list.push(*value); + false + } + }); + + (!new_edit_list.is_empty()).then_some(new_edit_list) + } else { + // If there is no edit list to begin with, we just keep the whole block. + None + } + } + + /// Polls a data block. This function shouldn't execute until all the header packets have been + /// processed. + pub fn poll_data_block( + mut self: Pin<&mut Self>, + data_block: Bytes, + ) -> Poll>> { + let edit_list = self.as_mut().partition_edit_list(&data_block); + + let this = self.project(); + Poll::Ready(Some(Ok(DataBlockDecrypter::new( + data_block, + // Todo make this so it doesn't use owned Keys and SenderPublicKey as it will be called asynchronously. + this.session_keys.clone(), + edit_list, + )))) + } + + /// Poll the stream until the header packets and session keys are processed. + pub fn poll_session_keys(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + // Only execute this function if there are no session keys. + if !self.session_keys.is_empty() { + return Poll::Ready(Ok(())); + } + + // Header packets are waiting to be decrypted. + if let Some(header_packet_decrypter) = self.as_mut().project().header_packet_future.as_pin_mut() + { + return match ready!(header_packet_decrypter.poll(cx)) { + Ok(header_packets) => { + let mut this = self.as_mut().project(); + + // Update the session keys and edit list packets. + this.header_packet_future.set(None); + this.session_keys.extend(header_packets.data_enc_packets); + if this.edit_list_packet.is_none() { + *this.edit_list_packet = + Self::create_internal_edit_list(header_packets.edit_list_packet); + } + + Poll::Ready(Ok(())) + } + Err(err) => Poll::Ready(Err(err)), + }; + } + + // No header packets yet, so more data needs to be decoded. + let mut this = self.as_mut().project(); + match ready!(this.inner.poll_next(cx)) { + Some(Ok(buf)) => match buf { + DecodedBlock::HeaderInfo(header_info) => { + // Store the header info but otherwise ignore it and poll again. + *this.header_info = Some(header_info); + cx.waker().wake_by_ref(); + Poll::Pending + } + // todo no clones here. + DecodedBlock::HeaderPackets(header_packets) => { + // Update the header length because we have access to the header packets. + let (header_packets, header_length) = header_packets.into_inner(); + *this.encrypted_header_packets = Some(header_packets.clone()); + *this.header_length = Some(header_length + Block::header_info_size()); + + // Add task for decrypting the header packets. + this + .header_packet_future + .set(Some(HeaderPacketsDecrypter::new( + header_packets + .into_iter() + .map(|packet| packet.into_header_bytes()) + .collect(), + this.keys.clone(), + this.sender_pubkey.clone(), + ))); + + // Poll again. + cx.waker().wake_by_ref(); + Poll::Pending + } + DecodedBlock::DataBlock(_) => Poll::Ready(Err(Crypt4GHError( + "data block reached without finding session keys".to_string(), + ))), + }, + Some(Err(e)) => Poll::Ready(Err(e)), + None => Poll::Ready(Err(Crypt4GHError( + "end of stream reached without finding session keys".to_string(), + ))), + } + } + + /// Convenience for calling [`poll_session_keys`] on [`Unpin`] types. + pub fn poll_session_keys_unpin(&mut self, cx: &mut Context<'_>) -> Poll> + where + Self: Unpin, + { + Pin::new(self).poll_session_keys(cx) + } + + /// Poll the stream until the header has been read. + pub async fn read_header(&mut self) -> Result<()> + where + R: Unpin, + { + SessionKeysFuture::new(self).await + } +} + +impl DecrypterStream { + /// An override for setting the stream length. + pub async fn set_stream_length(&mut self, length: u64) { + self.stream_length = Some(length); + } + + /// Get a reference to the inner reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref() + } + + /// Get a mutable reference to the inner reader. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut() + } + + /// Get a pinned mutable reference to the inner reader. + pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut R> { + self.project().inner.get_pin_mut() + } + + /// Get the inner reader. + pub fn into_inner(self) -> R { + self.inner.into_inner() + } + + /// Get the length of the header, including the magic string, version number, packet count + /// and the header packets. Returns `None` before the header packet is polled. + pub fn header_size(&self) -> Option { + self.header_length + } + + /// Get the size of the current data block represented by the encrypted block returned by calling + /// poll_next. This will equal `decoder::DATA_BLOCK_SIZE` except for the last block which may be + /// less than that. Returns `None` before the first data block is polled. + pub fn current_block_size(&self) -> Option { + self.current_block_size + } + + /// Clamps the byte position to the nearest data block if the header length is known. This + /// function takes into account the stream length if it is present. + pub fn clamp_position(&self, position: u64) -> Option { + self.header_size().map(|length| { + if position < length { + length + } else { + match self.stream_length { + Some(end_length) if position >= end_length => end_length, + _ => { + let remainder = (position - length) % Block::standard_data_block_size(); + + position - remainder + } + } + } + }) + } + + /// Convert an unencrypted position to an encrypted position if the header length is known. + pub fn to_encrypted(&self, position: u64) -> Option { + self.header_size().map(|length| { + let encrypted_position = util::to_encrypted(position, length); + + match self.stream_length { + Some(end_length) if encrypted_position + Block::mac_size() > end_length => end_length, + _ => encrypted_position, + } + }) + } + + /// Get the session keys. Empty before the header is polled. + pub fn session_keys(&self) -> &[Vec] { + &self.session_keys + } + + /// Get the edit list packet. Empty before the header is polled. + pub fn edit_list_packet(&self) -> Option> { + self + .edit_list_packet + .as_ref() + .map(|packet| packet.iter().map(|(_, edit)| *edit).collect()) + } + + /// Get the header info. + pub fn header_info(&self) -> Option<&HeaderInfo> { + self.header_info.as_ref() + } + + /// Get the original encrypted header packets, not including the header info. + pub fn encrypted_header_packets(&self) -> Option<&Vec> { + self.encrypted_header_packets.as_ref() + } + + /// Get the stream's keys. + pub fn keys(&self) -> &[Keys] { + self.keys.as_slice() + } + + pub(crate) fn create_internal_edit_list(edit_list: Option>) -> Option> { + edit_list.map(|edits| [true, false].iter().cloned().cycle().zip(edits).collect()) + } +} + +impl DecrypterStream +where + R: AsyncRead + AsyncSeek + Unpin, +{ + /// Recompute the stream length. Having a stream length means that data block positions past the + /// end of the stream will be valid and will equal the the length of the stream. By default this + /// struct contains no stream length when it is initialized. + /// + /// This can take up to 3 seek calls. If the size of the underlying buffer changes, this function + /// should be called again, otherwise data block positions may not be valid. + pub async fn recompute_stream_length(&mut self) -> Result { + let inner = self.inner.get_mut(); + + let position = inner.seek(SeekFrom::Current(0)).await?; + let length = inner.seek(SeekFrom::End(0)).await?; + + if position != length { + inner.seek(SeekFrom::Start(position)).await?; + } + + self.stream_length = Some(length); + + Ok(length) + } +} + +impl Stream for DecrypterStream +where + R: AsyncRead, +{ + type Item = Result; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + // When polling, we first need to process enough data to get the session keys. + if let Err(err) = ready!(self.as_mut().poll_session_keys(cx)) { + return Poll::Ready(Some(Err(err))); + } + + let this = self.as_mut().project(); + let item = this.inner.poll_next(cx); + + match ready!(item) { + Some(Ok(buf)) => match buf { + DecodedBlock::HeaderInfo(_) | DecodedBlock::HeaderPackets(_) => { + // Session keys have already been read, so ignore the header info and header packets + // and poll again + cx.waker().wake_by_ref(); + Poll::Pending + } + DecodedBlock::DataBlock(data_block) => { + // The new size of the data block is available, so update it. + *this.current_block_size = Some(data_block.len()); + + // Session keys have been obtained so process the data blocks. + self.poll_data_block(data_block) + } + }, + Some(Err(e)) => Poll::Ready(Some(Err(e))), + None => Poll::Ready(None), + } + } +} + +impl DecrypterStream +where + R: AsyncRead + AsyncSeek + Unpin + Send, +{ + /// Seek to a position in the encrypted stream. + pub async fn seek_encrypted(&mut self, position: SeekFrom) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // First poll to the position specified. + let seek = self.inner.get_mut().seek(position).await?; + + // Then advance to the correct data block position. + let advance = self.advance_encrypted(seek).await?; + + // Then seek to the correct position. + let seek = self.inner.get_mut().seek(SeekFrom::Start(advance)).await?; + self.inner.read_buffer_mut().clear(); + + Ok(seek) + } + + /// Seek to a position in the unencrypted stream. + pub async fn seek_unencrypted(&mut self, position: u64) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // Convert to an encrypted position and seek + let position = self + .to_encrypted(position) + .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; + + // Then do the seek. + self.seek_encrypted(SeekFrom::Start(position)).await + } +} + +#[async_trait] +impl Advance for DecrypterStream +where + R: AsyncRead + Send + Unpin, +{ + async fn advance_encrypted(&mut self, position: u64) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // Get the next position. + let data_block_position = self + .clamp_position(position) + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "could not find data block position"))?; + + Ok(data_block_position) + } + + async fn advance_unencrypted(&mut self, position: u64) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // Convert to an encrypted position and seek + let position = self + .to_encrypted(position) + .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; + + // Then do the advance. + self.advance_encrypted(position).await + } + + fn stream_length(&self) -> Option { + self.stream_length + } +} + +#[cfg(test)] +mod tests { + use bytes::BytesMut; + use futures_util::future::join_all; + use futures_util::StreamExt; + use tokio::fs::File; + + use htsget_test::http_tests::get_test_file; + + use crate::decoder::tests::assert_last_data_block; + use crate::decrypter::builder::Builder; + use crate::tests::get_original_file; + use htsget_test::crypt4gh::get_decryption_keys; + + use super::*; + + #[tokio::test] + async fn partition_edit_lists() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_edit_list(vec![60113, 100000, 65536]) + .build(src, vec![recipient_private_key]); + + assert_edit_list(&mut stream, Some(vec![60113, 5423]), vec![0; 65564]); + assert_edit_list(&mut stream, Some(vec![0, 65536]), vec![0; 65564]); + assert_edit_list(&mut stream, Some(vec![0, 29041, 36495]), vec![0; 65564]); + assert_edit_list(&mut stream, Some(vec![29041]), vec![0; 29041 + 12 + 16]); + } + + fn assert_edit_list( + stream: &mut DecrypterStream, + expected: Option>, + bytes: Vec, + ) { + let stream = Pin::new(stream); + let edit_list = stream.partition_edit_list(&Bytes::from(bytes)); + assert_eq!(edit_list, expected); + } + + #[tokio::test] + async fn decrypter_stream() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn get_header_length() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + assert!(stream.header_size().is_none()); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.header_size(), Some(124)); + } + + #[tokio::test] + async fn first_block_size() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + assert!(stream.current_block_size().is_none()); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.current_block_size(), Some(65564)); + } + + #[tokio::test] + async fn last_block_size() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + assert!(stream.current_block_size().is_none()); + + let mut stream = stream.skip(39); + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.get_ref().current_block_size(), Some(40923)); + } + + #[tokio::test] + async fn clamp_position_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.clamp_position(0), Some(124)); + assert_eq!(stream.clamp_position(124), Some(124)); + assert_eq!(stream.clamp_position(200), Some(124)); + } + + #[tokio::test] + async fn clamp_position_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.clamp_position(80000), Some(124 + 65564)); + } + + #[tokio::test] + async fn clamp_position_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.clamp_position(2598044), Some(2598043)); + } + + #[tokio::test] + async fn convert_position_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + let pos = stream.to_encrypted(0); + assert_eq!(pos, Some(124)); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); + + let pos = stream.to_encrypted(200); + assert_eq!(pos, Some(124 + 12 + 200)); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); + } + + #[tokio::test] + async fn convert_position_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + let pos = stream.to_encrypted(80000); + assert_eq!(pos, Some(124 + 65564 + 12 + (80000 - 65536))); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(124 + 65564)); + } + + #[tokio::test] + async fn convert_position_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + let _ = stream.next().await.unwrap().unwrap().await; + + let pos = stream.to_encrypted(2596800); + assert_eq!(pos, Some(2598043)); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(2598043)); + } + + #[tokio::test] + async fn seek_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::Start(80000)).await.unwrap(); + + assert_eq!(seek, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let seek = stream + .seek_encrypted(SeekFrom::Current(-20000)) + .await + .unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::End(-1000)).await.unwrap(); + + assert_eq!(seek, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let block = stream.next().await.unwrap().unwrap().await.unwrap(); + assert_last_data_block(block.bytes.to_vec()).await; + } + + #[tokio::test] + async fn seek_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn seek_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn advance_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(0).await.unwrap(); + + assert_eq!(advance, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(80000).await.unwrap(); + + assert_eq!(advance, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(2598042).await.unwrap(); + + assert_eq!(advance, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(2598044).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let advance = stream.advance_encrypted(2598044).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(0).await.unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_second_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(65537).await.unwrap(); + + assert_eq!(seek, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let seek = stream.seek_unencrypted(65535).await.unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(2596799).await.unwrap(); + + assert_eq!(seek, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let block = stream.next().await.unwrap().unwrap().await.unwrap(); + assert_last_data_block(block.bytes.to_vec()).await; + } + + #[tokio::test] + async fn seek_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(2596800).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn seek_past_end_stream_unencrypted_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let seek = stream.seek_unencrypted(2596800).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn advance_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(0).await.unwrap(); + + assert_eq!(advance, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_second_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(65537).await.unwrap(); + + assert_eq!(advance, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(2596799).await.unwrap(); + + assert_eq!(advance, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(2596800).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end_unencrypted_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let advance = stream.advance_unencrypted(2596800).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } +} diff --git a/src/header.rs b/src/header.rs index e0fed3a..dfb3503 100644 --- a/src/header.rs +++ b/src/header.rs @@ -29,6 +29,38 @@ struct HeaderPackets { edit_list_packet: Option>, } +/// Represents the encrypted header packet data, and the total size of all the header packets. +#[derive(Debug, Default)] +pub struct EncryptedHeaderPackets { + header_packets: Vec, + header_length: u64, +} + +impl EncryptedHeaderPackets { + /// Create a new decrypted data block. + pub fn new(header_packets: Vec, size: u64) -> Self { + Self { + header_packets, + header_length: size, + } + } + + /// Get the header packet bytes + pub fn header_packets(&self) -> &Vec { + &self.header_packets + } + + /// Get the size of all the packets. + pub fn header_length(&self) -> u64 { + self.header_length + } + + /// Get the inner bytes and size. + pub fn into_inner(self) -> (Vec, u64) { + (self.header_packets, self.header_length) + } +} + /// Contains the parsed data of the packets pub struct DecryptedHeaderPackets { /// The packets that are coded as data diff --git a/src/keys.rs b/src/keys.rs index bcc36af..79bd44f 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -1,6 +1,9 @@ #![warn(missing_docs)] #![warn(rustdoc::missing_doc_code_examples)] +use bytes::Bytes; +use rustls::PrivateKey; + use aes::cipher::{StreamCipher, generic_array::GenericArray}; use std::collections::HashMap; @@ -75,4 +78,59 @@ pub struct Keys { pub struct SessionKeys { inner: Vec> +} + +/// A wrapper around a vec of bytes that represent a public key. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PublicKey { + bytes: Vec, +} + +/// A key pair containing a public and private key. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct KeyPair { + private_key: PrivateKey, + public_key: PublicKey, +} + +impl KeyPair { + /// Create a new key pair. + pub fn new(private_key: PrivateKey, public_key: PublicKey) -> Self { + Self { + private_key, + public_key, + } + } + + /// Get the inner keys. + pub fn into_inner(self) -> (PrivateKey, PublicKey) { + (self.private_key, self.public_key) + } + + /// Get private key. + pub fn private_key(&self) -> &PrivateKey { + &self.private_key + } + + /// Get private key + pub fn public_key(&self) -> &PublicKey { + &self.public_key + } +} + +impl PublicKey { + /// Create a new sender public key from bytes. + pub fn new(bytes: Vec) -> Self { + Self { bytes } + } + + /// Get the inner bytes. + pub fn into_inner(self) -> Vec { + self.bytes + } + + /// Get the inner bytes as a reference. + pub fn get_ref(&self) -> &[u8] { + self.bytes.as_slice() + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 861f5f0..17823cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,20 +30,19 @@ use rand_chacha; use std::collections::HashSet; use std::io::{self, Read, Write}; -use header::DecryptedHeaderPackets; - use chacha20poly1305::aead::Aead; use chacha20poly1305::{ self, ChaCha20Poly1305, Key, KeyInit, Nonce }; use crate::error::Crypt4GHError; -/// Generate and parse a `Crypt4GH` header. +pub mod decoder; +pub mod decrypter; +//pub mod encrypter; +pub mod edit_lists; +pub mod reader; +pub mod util; pub mod header; - -/// Utility to read Crypt4GH-formatted keys. pub mod keys; - -/// `Crypt4GH` Errors. pub mod error; const CHUNK_SIZE: usize = 4096; diff --git a/src/reader/builder.rs b/src/reader/builder.rs new file mode 100644 index 0000000..acc426f --- /dev/null +++ b/src/reader/builder.rs @@ -0,0 +1,112 @@ +use std::thread; + +use crypt4gh::Keys; +use futures_util::TryStreamExt; +use tokio::io::{AsyncRead, AsyncSeek}; + +use crate::decrypter::builder::Builder as DecrypterBuilder; +use crate::decrypter::DecrypterStream; +use crate::error::Result; +use crate::PublicKey; + +use super::Reader; + +/// An async Crypt4GH reader builder. +#[derive(Debug, Default)] +pub struct Builder { + worker_count: Option, + sender_pubkey: Option, + stream_length: Option, +} + +impl Builder { + /// Sets a worker count. + pub fn with_worker_count(self, worker_count: usize) -> Self { + self.set_worker_count(Some(worker_count)) + } + + /// Sets the sender public key + pub fn with_sender_pubkey(self, sender_pubkey: PublicKey) -> Self { + self.set_sender_pubkey(Some(sender_pubkey)) + } + + /// Sets a worker count. + pub fn set_worker_count(mut self, worker_count: Option) -> Self { + self.worker_count = worker_count; + self + } + + /// Sets the sender public key + pub fn set_sender_pubkey(mut self, sender_pubkey: Option) -> Self { + self.sender_pubkey = sender_pubkey; + self + } + + /// Sets the stream length. + pub fn with_stream_length(self, stream_length: u64) -> Self { + self.set_stream_length(Some(stream_length)) + } + + /// Sets the stream length. + pub fn set_stream_length(mut self, stream_length: Option) -> Self { + self.stream_length = stream_length; + self + } + + /// Build the Crypt4GH reader. + pub fn build_with_reader(self, inner: R, keys: Vec) -> Reader + where + R: AsyncRead, + { + let worker_counter = self.worker_count(); + + Reader { + stream: DecrypterBuilder::default() + .set_sender_pubkey(self.sender_pubkey) + .set_stream_length(self.stream_length) + .build(inner, keys) + .try_buffered(worker_counter), + // Dummy value for bytes to begin with. + current_block: Default::default(), + buf_position: 0, + block_position: None, + } + } + + /// Build the reader and compute the stream length for seek operations. + pub async fn build_with_stream_length(self, inner: R, keys: Vec) -> Result> + where + R: AsyncRead + AsyncSeek + Unpin, + { + let stream_length = self.stream_length; + let mut reader = self.build_with_reader(inner, keys); + + if stream_length.is_none() { + reader.stream.get_mut().recompute_stream_length().await?; + } + + Ok(reader) + } + + /// Build the Crypt4GH reader with a decryper stream. + pub fn build_with_stream(self, stream: DecrypterStream) -> Reader + where + R: AsyncRead, + { + Reader { + stream: stream.try_buffered(self.worker_count()), + // Dummy value for bytes to begin with. + current_block: Default::default(), + buf_position: 0, + block_position: None, + } + } + + fn worker_count(&self) -> usize { + self.worker_count.unwrap_or_else(|| { + thread::available_parallelism() + .map(|worker_count| worker_count.get()) + .unwrap_or_else(|_| 1) + }) + } +} diff --git a/src/reader/mod.rs b/src/reader/mod.rs new file mode 100644 index 0000000..8bf8b9a --- /dev/null +++ b/src/reader/mod.rs @@ -0,0 +1,774 @@ +use std::io::SeekFrom; +use std::pin::Pin; +use std::task::{Context, Poll}; +use std::{cmp, io}; + +use async_trait::async_trait; +use crypt4gh::header::HeaderInfo; +use crypt4gh::Keys; +use futures::ready; +use futures::stream::TryBuffered; +use futures::Stream; +use pin_project_lite::pin_project; +use tokio::io::{AsyncBufRead, AsyncRead, AsyncSeek, ReadBuf}; + +use crate::advance::Advance; +use crate::decoder::Block; +use crate::error::Error::NumericConversionError; +use crate::error::Result; +use crate::reader::builder::Builder; +use crate::{DecryptedDataBlock, EncryptedHeaderPacketBytes}; + +use super::decrypter::DecrypterStream; + +pub mod builder; + +pin_project! { + pub struct Reader + where R: AsyncRead + { + #[pin] + stream: TryBuffered>, + current_block: DecryptedDataBlock, + // The current position in the decrypted buffer. + buf_position: usize, + // The encrypted position of the current data block minus the size of the header. + block_position: Option + } +} + +impl Reader +where + R: AsyncRead, +{ + /// Gets the position of the data block which includes the current position of the underlying + /// reader. This function will return a value that always corresponds the beginning of a data + /// block or `None` if the reader has not read any bytes. + pub fn current_block_position(&self) -> Option { + self.block_position + } + + /// Gets the position of the next data block from the current position of the underlying reader. + /// This function will return a value that always corresponds the beginning of a data block, the + /// size of the file, or `None` if the reader has not read any bytes. + pub fn next_block_position(&self) -> Option { + self.block_position.and_then(|block_position| { + self + .stream + .get_ref() + .clamp_position(block_position + Block::standard_data_block_size()) + }) + } + + /// Get a reference to the inner reader. + pub fn get_ref(&self) -> &R { + self.stream.get_ref().get_ref() + } + + /// Get a mutable reference to the inner reader. + pub fn get_mut(&mut self) -> &mut R { + self.stream.get_mut().get_mut() + } + + /// Get a pinned mutable reference to the inner reader. + pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut R> { + self.project().stream.get_pin_mut().get_pin_mut() + } + + /// Get the inner reader. + pub fn into_inner(self) -> R { + self.stream.into_inner().into_inner() + } + + /// Get the session keys. Empty before the header is polled. + pub fn session_keys(&self) -> &[Vec] { + self.stream.get_ref().session_keys() + } + + /// Get the edit list packet. Empty before the header is polled. + pub fn edit_list_packet(&self) -> Option> { + self.stream.get_ref().edit_list_packet() + } + + /// Get the header info. + pub fn header_info(&self) -> Option<&HeaderInfo> { + self.stream.get_ref().header_info() + } + + /// Get the header size + pub fn header_size(&self) -> Option { + self.stream.get_ref().header_size() + } + + /// Get the original encrypted header packets, not including the header info. + pub fn encrypted_header_packets(&self) -> Option<&Vec> { + self.stream.get_ref().encrypted_header_packets() + } + + /// Poll the reader until the header has been read. + pub async fn read_header(&mut self) -> Result<()> + where + R: Unpin, + { + self.stream.get_mut().read_header().await + } + + /// Get the reader's keys. + pub fn keys(&self) -> &[Keys] { + self.stream.get_ref().keys() + } +} + +impl From> for Reader +where + R: AsyncRead, +{ + fn from(stream: DecrypterStream) -> Self { + Builder::default().build_with_stream(stream) + } +} + +impl AsyncRead for Reader +where + R: AsyncRead, +{ + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + // Defer to poll_fill_buf to do the read. + let src = ready!(self.as_mut().poll_fill_buf(cx))?; + + // Calculate the correct amount to read and copy over to the read buf. + let amt = cmp::min(src.len(), buf.remaining()); + buf.put_slice(&src[..amt]); + + // Inform the internal buffer that amt has been consumed. + self.consume(amt); + + Poll::Ready(Ok(())) + } +} + +impl AsyncBufRead for Reader +where + R: AsyncRead, +{ + fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.project(); + + // If this is the beginning of the stream, set the block position to the header length, if any. + if let (None, length @ Some(_)) = ( + this.block_position.as_ref(), + this.stream.get_ref().header_size(), + ) { + *this.block_position = length; + } + + // If the position is past the end of the buffer, then all the data has been read and a new + // buffer should be initialised. + if *this.buf_position >= this.current_block.len() { + match ready!(this.stream.poll_next(cx)) { + Some(Ok(block)) => { + // Update the block position with the previous block size. + *this.block_position = Some( + this.block_position.unwrap_or_default() + + u64::try_from(this.current_block.encrypted_size()) + .map_err(|_| NumericConversionError)?, + ); + + // We have a new buffer, reinitialise the position and buffer. + *this.current_block = block; + *this.buf_position = 0; + } + Some(Err(e)) => return Poll::Ready(Err(e.into())), + None => return Poll::Ready(Ok(&[])), + } + } + + // Return the unconsumed data from the buffer. + Poll::Ready(Ok(&this.current_block[*this.buf_position..])) + } + + fn consume(self: Pin<&mut Self>, amt: usize) { + let this = self.project(); + // Update the buffer position until the consumed amount reaches the end of the buffer. + *this.buf_position = cmp::min(*this.buf_position + amt, this.current_block.len()); + } +} + +impl Reader +where + R: AsyncRead + AsyncSeek + Unpin + Send, +{ + /// Seek to a position in the encrypted stream. + pub async fn seek_encrypted(&mut self, position: SeekFrom) -> io::Result { + let position = self.stream.get_mut().seek_encrypted(position).await?; + + self.block_position = Some(position); + + Ok(position) + } + + /// Seek to a position in the unencrypted stream. + pub async fn seek_unencrypted(&mut self, position: u64) -> io::Result { + let position = self.stream.get_mut().seek_unencrypted(position).await?; + + self.block_position = Some(position); + + Ok(position) + } +} + +#[async_trait] +impl Advance for Reader +where + R: AsyncRead + Send + Unpin, +{ + async fn advance_encrypted(&mut self, position: u64) -> io::Result { + let position = self.stream.get_mut().advance_encrypted(position).await?; + + self.block_position = Some(position); + + Ok(position) + } + + async fn advance_unencrypted(&mut self, position: u64) -> io::Result { + let position = self.stream.get_mut().advance_unencrypted(position).await?; + + self.block_position = Some(position); + + Ok(position) + } + + fn stream_length(&self) -> Option { + self.stream.get_ref().stream_length() + } +} + +#[cfg(test)] +mod tests { + use std::io::SeekFrom; + + use futures_util::TryStreamExt; + use noodles::bam::AsyncReader; + use noodles::sam::Header; + use tokio::io::AsyncReadExt; + + use htsget_test::http_tests::get_test_file; + + use crate::advance::Advance; + use crate::reader::builder::Builder; + use crate::tests::get_original_file; + use crate::PublicKey; + use htsget_test::crypt4gh::get_decryption_keys; + + #[tokio::test] + async fn reader() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let mut decrypted_bytes = vec![]; + reader.read_to_end(&mut decrypted_bytes).await.unwrap(); + + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn reader_with_noodles() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let mut reader = AsyncReader::new(reader); + + let original_file = get_test_file("bam/htsnexus_test_NA12878.bam").await; + let mut original_reader = AsyncReader::new(original_file); + + let header: Header = reader.read_header().await.unwrap().parse().unwrap(); + let reference_sequences = reader.read_reference_sequences().await.unwrap(); + + let original_header: Header = original_reader + .read_header() + .await + .unwrap() + .parse() + .unwrap(); + let original_reference_sequences = original_reader.read_reference_sequences().await.unwrap(); + + assert_eq!(header, original_header); + assert_eq!(reference_sequences, original_reference_sequences); + + let mut stream = original_reader.records(&original_header); + let mut original_records = vec![]; + while let Some(record) = stream.try_next().await.unwrap() { + original_records.push(record); + } + + let mut stream = reader.records(&header); + let mut records = vec![]; + while let Some(record) = stream.try_next().await.unwrap() { + records.push(record); + } + + assert_eq!(records, original_records); + } + + #[tokio::test] + async fn first_current_block_position() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the current block should not be known. + assert_eq!(reader.current_block_position(), None); + + // Read the first byte of the decrypted data. + let mut buf = [0u8; 1]; + reader.read_exact(&mut buf).await.unwrap(); + + // Now the current position should be at the end of the header. + assert_eq!(reader.current_block_position(), Some(124)); + } + + #[tokio::test] + async fn first_next_block_position() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the next block should not be known. + assert_eq!(reader.next_block_position(), None); + + // Read the first byte of the decrypted data. + let mut buf = [0u8; 1]; + reader.read_exact(&mut buf).await.unwrap(); + + // Now the next position should be at the second data block. + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn last_current_block_position() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the current block should not be known. + assert_eq!(reader.current_block_position(), None); + + // Read the whole file. + let mut decrypted_bytes = vec![]; + reader.read_to_end(&mut decrypted_bytes).await.unwrap(); + + // Now the current position should be at the last data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + } + + #[tokio::test] + async fn last_next_block_position() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the next block should not be known. + assert_eq!(reader.next_block_position(), None); + + // Read the whole file. + let mut decrypted_bytes = vec![]; + reader.read_to_end(&mut decrypted_bytes).await.unwrap(); + + // Now the next position should be the size of the file. + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(124)); + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn seek_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader + .seek_encrypted(SeekFrom::Start(2598042)) + .await + .unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader + .seek_encrypted(SeekFrom::Start(2598044)) + .await + .unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build_with_reader(src, vec![recipient_private_key]); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader + .seek_encrypted(SeekFrom::Start(2598044)) + .await + .unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_encrypted(0).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(124)); + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn advance_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_encrypted(2598042).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_encrypted(2598044).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build_with_reader(src, vec![recipient_private_key]); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_encrypted(2598044).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_unencrypted(0).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(124)); + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn seek_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_unencrypted(2596799).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_unencrypted(2596800).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_past_end_unencrypted_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build_with_reader(src, vec![recipient_private_key]); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_unencrypted(2596800).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_unencrypted(0).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(124)); + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn advance_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_unencrypted(2596799).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_unencrypted(2596800).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_past_end_unencrypted_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build_with_reader(src, vec![recipient_private_key]); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_unencrypted(2596800).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 0000000..a4f4689 --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1,197 @@ +use crypt4gh::keys::{generate_keys, get_private_key, get_public_key}; +use rustls::PrivateKey; +use std::cmp::min; +use tempfile::TempDir; + +use crate::decoder::Block; +use crate::error::{Error, Result}; +use crate::{KeyPair, PublicKey}; + +fn to_current_data_block(pos: u64, header_len: u64) -> u64 { + header_len + (pos / Block::encrypted_block_size()) * Block::standard_data_block_size() +} + +/// Convert an unencrypted file position to an encrypted position if the header length is known. +pub fn to_encrypted(position: u64, header_length: u64) -> u64 { + let number_data_blocks = position / Block::encrypted_block_size(); + // Additional bytes include the full data block size. + let mut additional_bytes = number_data_blocks * (Block::nonce_size() + Block::mac_size()); + + // If there is left over data, then there are more nonce bytes. + let remainder = position % Block::encrypted_block_size(); + if remainder != 0 { + additional_bytes += Block::nonce_size(); + } + + // Then add the extra bytes to the current position. + header_length + position + additional_bytes +} + +/// Convert an encrypted file position to an unencrypted position if the header length is known. +pub fn to_unencrypted(encrypted_position: u64, header_length: u64) -> u64 { + let number_data_blocks = encrypted_position / Block::standard_data_block_size(); + let mut additional_bytes = number_data_blocks * (Block::nonce_size() + Block::mac_size()); + + let remainder = encrypted_position % Block::standard_data_block_size(); + if remainder != 0 { + additional_bytes += Block::nonce_size(); + } + + encrypted_position - header_length - additional_bytes +} + +/// Convert an unencrypted file size to an encrypted file size if the header length is known. +pub fn to_encrypted_file_size(file_size: u64, header_length: u64) -> u64 { + to_encrypted(file_size, header_length) + Block::mac_size() +} + +/// Convert an encrypted file size to an unencrypted file size if the header length is known. +pub fn to_unencrypted_file_size(encrypted_file_size: u64, header_length: u64) -> u64 { + to_unencrypted(encrypted_file_size, header_length) - Block::mac_size() +} + +/// Convert an unencrypted position to an encrypted position as shown in +/// https://samtools.github.io/hts-specs/crypt4gh.pdf chapter 4.1. +pub fn unencrypted_to_data_block(pos: u64, header_len: u64, encrypted_file_size: u64) -> u64 { + min(encrypted_file_size, to_current_data_block(pos, header_len)) +} + +/// Get the next data block position from the unencrypted position. +pub fn unencrypted_to_next_data_block(pos: u64, header_len: u64, encrypted_file_size: u64) -> u64 { + min( + encrypted_file_size, + to_current_data_block(pos, header_len) + Block::standard_data_block_size(), + ) +} + +fn unencrypted_clamped_position(pos: u64, encrypted_file_size: u64) -> u64 { + let data_block_positions = unencrypted_to_data_block(pos, 0, encrypted_file_size); + let data_block_count = data_block_positions / Block::standard_data_block_size(); + + data_block_positions - ((Block::nonce_size() + Block::mac_size()) * data_block_count) +} + +/// Convert an unencrypted position to the additional bytes prior to the position that must be +/// included when encrypting data blocks. +pub fn unencrypted_clamp(pos: u64, encrypted_file_size: u64) -> u64 { + min( + to_unencrypted_file_size(encrypted_file_size, 0), + unencrypted_clamped_position(pos, encrypted_file_size), + ) +} + +/// Convert an unencrypted position to the additional bytes after to the position that must be +/// included when encrypting data blocks. +pub fn unencrypted_clamp_next(pos: u64, encrypted_file_size: u64) -> u64 { + min( + to_unencrypted_file_size(encrypted_file_size, 0), + unencrypted_clamped_position(pos, encrypted_file_size) + Block::encrypted_block_size(), + ) +} + +/// Generate a private and public key pair. +pub fn generate_key_pair() -> Result { + // Todo, very janky, avoid writing this to a file first. + let temp_dir = TempDir::new().map_err(|err| Error::Crypt4GHError(err.to_string()))?; + + let private_key = temp_dir.path().join("private_key"); + let public_key = temp_dir.path().join("public_key"); + generate_keys( + private_key.clone(), + public_key.clone(), + Ok("".to_string()), + None, + ) + .map_err(|err| Error::Crypt4GHError(err.to_string()))?; + + let private_key = get_private_key(private_key, Ok("".to_string()))?; + let public_key = get_public_key(public_key)?; + + Ok(KeyPair::new( + PrivateKey(private_key), + PublicKey::new(public_key), + )) +} + +#[cfg(test)] +mod tests { + use crate::util::{unencrypted_clamp, unencrypted_to_data_block, unencrypted_to_next_data_block}; + + use super::*; + + #[test] + fn test_to_encrypted() { + let pos = 80000; + let expected = 120 + 65536 + 12 + 16; + let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(100000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_to_encrypted_file_size() { + let pos = 110000; + let expected = 60148; + let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(60000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_to_encrypted_pos_greater_than_file_size() { + let pos = 110000; + let expected = 120 + 65536 + 12 + 16; + let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(100000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_next_data_block() { + let pos = 100000; + let expected = 120 + (65536 + 12 + 16) * 2; + let result = unencrypted_to_next_data_block(pos, 120, to_encrypted_file_size(150000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_next_data_block_file_size() { + let pos = 110000; + let expected = 100176; + let result = unencrypted_to_next_data_block(pos, 120, to_encrypted_file_size(100000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_unencrypted_clamp() { + let pos = 0; + let expected = 0; + let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + + let pos = 145110; + let expected = 131072; + let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + + let pos = 5485074; + let expected = 5439488; + let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + } + + #[test] + fn test_unencrypted_clamp_next() { + let pos = 7853; + let expected = 65536; + let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + + let pos = 453039; + let expected = 458752; + let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + + let pos = 5485112; + let expected = 5485112; + let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + } +} From e9f1b63c5fd2b6dfae9970704fd7fe0359080c56 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 9 Feb 2024 16:13:57 +1100 Subject: [PATCH 05/30] Add more async-related deps and helpers (tokio, futures, tokio-io, etc...) --- Cargo.lock | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 5 ++ 2 files changed, 247 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 229e044..bd12543 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.5.2" @@ -38,6 +53,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base16ct" version = "0.2.0" @@ -264,9 +294,12 @@ dependencies = [ "ctr", "curve25519-dalek", "ed25519_to_curve25519", + "futures", + "futures-util", "itertools", "lazy_static", "log", + "pin-project-lite", "pretty_env_logger", "rand", "rand_chacha", @@ -278,6 +311,8 @@ dependencies = [ "ssh-key", "testresult", "thiserror", + "tokio", + "tokio-util", ] [[package]] @@ -489,6 +524,95 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -511,6 +635,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "group" version = "0.13.0" @@ -633,6 +763,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -681,6 +820,25 @@ dependencies = [ "libm", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -767,6 +925,18 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkcs1" version = "0.7.5" @@ -985,6 +1155,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1121,6 +1297,15 @@ dependencies = [ "rand_core", ] +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.13.1" @@ -1260,6 +1445,63 @@ dependencies = [ "syn 1.0.92", ] +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "num_cpus", + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + [[package]] name = "typenum" version = "1.16.0" diff --git a/Cargo.toml b/Cargo.toml index b58b7ea..20de0c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,11 @@ curve25519-dalek = "4" ssh-key = { version = "0.6.4", features = ["ed25519"] } bytes = "1.5.0" rustls = "0.22" +tokio = { version = "1", features = [ "io-util", "test-util", "macros", "rt-multi-thread" ] } +futures = "0.3" +pin-project-lite = "0.2.13" +tokio-util = { version = "0.7", features = ["codec"] } +futures-util = "0.3.30" [dev-dependencies] testresult = "0.3" From e03d95b6142bdb46d106ec9ad6fb7ce4712fe74a Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 9 Feb 2024 16:14:55 +1100 Subject: [PATCH 06/30] [ci skip] More use/project hierarchy refactoring --- src/decrypter/builder.rs | 4 +- src/decrypter/data_block.rs | 11 +- src/decrypter/header/packets.rs | 8 +- src/decrypter/mod.rs | 50 +------ src/edit_lists.rs | 10 +- src/lib.rs | 250 ++++++++++++++++---------------- src/reader/builder.rs | 4 +- src/reader/mod.rs | 2 - src/util/mod.rs | 5 +- 9 files changed, 150 insertions(+), 194 deletions(-) diff --git a/src/decrypter/builder.rs b/src/decrypter/builder.rs index 4c41f2c..e7be65a 100644 --- a/src/decrypter/builder.rs +++ b/src/decrypter/builder.rs @@ -1,10 +1,10 @@ -use crypt4gh::Keys; +use crate::keys::Keys; use tokio::io::{AsyncRead, AsyncSeek}; use tokio_util::codec::FramedRead; use crate::decrypter::DecrypterStream; use crate::error::Result; -use crate::PublicKey; +use crate::keys::PublicKey; /// An decrypter reader builder. #[derive(Debug, Default)] diff --git a/src/decrypter/data_block.rs b/src/decrypter/data_block.rs index 6ca726d..e4dca7f 100644 --- a/src/decrypter/data_block.rs +++ b/src/decrypter/data_block.rs @@ -1,17 +1,17 @@ use std::future::Future; use std::io::Cursor; +use std::ops::Deref; use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; -use crypt4gh::{body_decrypt, WriteInfo}; +use crate::{body_decrypt, WriteInfo}; use pin_project_lite::pin_project; use tokio::task::JoinHandle; use crate::decrypter::DecrypterStream; use crate::error::Error::{Crypt4GHError, JoinHandleError}; use crate::error::Result; -use crate::{DecryptedBytes, DecryptedDataBlock}; pin_project! { #[must_use = "futures do nothing unless you `.await` or poll them"] @@ -173,7 +173,7 @@ impl Future for DataBlockDecrypter { #[cfg(test)] mod tests { use crate::decoder::tests::{assert_first_data_block, get_data_block}; - use crate::tests::get_original_file; + //use crate::tests::get_original_file; use super::*; @@ -204,8 +204,9 @@ mod tests { .await .unwrap(); - let original_bytes = get_original_file().await; + // FIXME: No "file" constructs in this crate! + //let original_bytes = get_original_file().await; - assert_eq!(data.bytes.to_vec(), original_bytes[..4668]); + //assert_eq!(data.bytes.to_vec(), original_bytes[..4668]); } } diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs index 69ba5bc..50dcfec 100644 --- a/src/decrypter/header/packets.rs +++ b/src/decrypter/header/packets.rs @@ -3,14 +3,14 @@ use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; -use crypt4gh::header::{deconstruct_header_body, DecryptedHeaderPackets}; -use crypt4gh::Keys; +use crate::header::{deserialize_header_info, DecryptedHeaderPackets}; +use crate::Keys; use pin_project_lite::pin_project; use tokio::task::{spawn_blocking, JoinHandle}; use crate::error::Error::JoinHandleError; use crate::error::Result; -use crate::PublicKey; +use crate::keys::PublicKey; pin_project! { #[must_use = "futures do nothing unless you `.await` or poll them"] @@ -38,7 +38,7 @@ impl HeaderPacketsDecrypter { keys: Vec, sender_pubkey: Option, ) -> Result { - Ok(deconstruct_header_body( + Ok(deserialize_header_info( header_packets .into_iter() .map(|bytes| bytes.to_vec()) diff --git a/src/decrypter/mod.rs b/src/decrypter/mod.rs index be7545b..f281ec3 100644 --- a/src/decrypter/mod.rs +++ b/src/decrypter/mod.rs @@ -1,21 +1,18 @@ use std::cmp::min; -use std::future::Future; use std::io; use std::io::SeekFrom; use std::pin::Pin; use std::task::{Context, Poll}; -use async_trait::async_trait; use bytes::Bytes; -use crypt4gh::header::HeaderInfo; -use crypt4gh::Keys; +use crate::header::HeaderInfo; +use crate::Keys; use futures::ready; use futures::Stream; use pin_project_lite::pin_project; use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt}; use tokio_util::codec::FramedRead; -use crate::advance::Advance; use crate::decoder::Block; use crate::decoder::DecodedBlock; use crate::decrypter::data_block::DataBlockDecrypter; @@ -411,54 +408,17 @@ where } } -#[async_trait] -impl Advance for DecrypterStream -where - R: AsyncRead + Send + Unpin, -{ - async fn advance_encrypted(&mut self, position: u64) -> io::Result { - // Make sure that session keys are polled. - self.read_header().await?; - - // Get the next position. - let data_block_position = self - .clamp_position(position) - .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "could not find data block position"))?; - - Ok(data_block_position) - } - - async fn advance_unencrypted(&mut self, position: u64) -> io::Result { - // Make sure that session keys are polled. - self.read_header().await?; - - // Convert to an encrypted position and seek - let position = self - .to_encrypted(position) - .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; - - // Then do the advance. - self.advance_encrypted(position).await - } - - fn stream_length(&self) -> Option { - self.stream_length - } -} - +// FIXME: Test suite highly dependent on fs and File(s), migrate to Bytes and/or Streams instead #[cfg(test)] mod tests { use bytes::BytesMut; use futures_util::future::join_all; use futures_util::StreamExt; - use tokio::fs::File; - - use htsget_test::http_tests::get_test_file; + // use tokio::fs::File; use crate::decoder::tests::assert_last_data_block; use crate::decrypter::builder::Builder; - use crate::tests::get_original_file; - use htsget_test::crypt4gh::get_decryption_keys; + // use crate::tests::get_original_file; use super::*; diff --git a/src/edit_lists.rs b/src/edit_lists.rs index 221f10c..62732d5 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -1,13 +1,13 @@ use std::collections::HashSet; -use crypt4gh::header::{encrypt, make_packet_data_edit_list, HeaderInfo}; -use crypt4gh::Keys; +use crate::header::{encrypt, make_packet_data_edit_list, HeaderInfo}; +use crate::keys::Keys; use rustls::PrivateKey; use tokio::io::AsyncRead; use crate::error::{Error, Result}; use crate::reader::Reader; -use crate::PublicKey; +use crate::keys::PublicKey; /// Unencrypted byte range positions. Contains inclusive start values and exclusive end values. #[derive(Debug, Clone)] @@ -243,8 +243,8 @@ where #[cfg(test)] mod tests { - use htsget_test::crypt4gh::{get_decryption_keys, get_encryption_keys}; - use htsget_test::http_tests::get_test_file; + // use htsget_test::crypt4gh::{get_decryption_keys, get_encryption_keys}; + // use htsget_test::http_tests::get_test_file; use crate::reader::builder::Builder; diff --git a/src/lib.rs b/src/lib.rs index 17823cc..69dd14d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,10 +21,20 @@ clippy::redundant_else )] +pub mod decoder; +pub mod decrypter; +//pub mod encrypter; +pub mod edit_lists; +pub mod reader; +pub mod util; +pub mod header; +pub mod keys; +pub mod error; + use bytes::Bytes; use io::Cursor; use keys::SessionKeys; -use rand::{SeedableRng, RngCore, Rng}; +use rand::{SeedableRng, RngCore}; use rand_chacha; use std::collections::HashSet; @@ -35,15 +45,8 @@ use chacha20poly1305::{ self, ChaCha20Poly1305, Key, KeyInit, Nonce }; use crate::error::Crypt4GHError; -pub mod decoder; -pub mod decrypter; -//pub mod encrypter; -pub mod edit_lists; -pub mod reader; -pub mod util; -pub mod header; -pub mod keys; -pub mod error; +use decrypter::data_block::{ DecryptedDataBlock, DecryptedBytes }; +use keys::Keys; const CHUNK_SIZE: usize = 4096; @@ -90,127 +93,122 @@ impl<'a, W: Write> WriteInfo<'a, W> { } } -/// Reads from the `read_buffer` and writes the encrypted data to `write_buffer`. -/// -/// Reads from the `read_buffer` and writes the encrypted data (for every `recipient_key`) to `write_buffer`. -/// If the range is specified, it will only encrypt the bytes from `range_start` to `range_start` + `range_span`. -/// In case that `range_span` is none, it will encrypt from `range_start` to the end of the input. -pub fn encrypt( - data_block: Bytes, - recipient_keys: &HashSet, - range_start: usize, - range_span: Option, -) -> Result { - if recipient_keys.is_empty() { - return Err(Crypt4GHError::NoRecipients); - } +// pub fn encrypt( +// data_block: Bytes, +// recipient_keys: &HashSet, +// range_start: usize, +// range_span: Option, +// ) -> Result { +// if recipient_keys.is_empty() { +// return Err(Crypt4GHError::NoRecipients); +// } - log::info!("Encrypting the file"); - log::debug!(" Start Coordinate: {}", range_start); +// log::info!("Encrypting the file"); +// log::debug!(" Start Coordinate: {}", range_start); - // Seek - if range_start > 0 { - log::info!("Forwarding to position: {}", range_start); - } +// // Seek +// if range_start > 0 { +// log::info!("Forwarding to position: {}", range_start); +// } - // read_buffer - // .by_ref() - // .take(range_start as u64) - // .read_to_end(&mut Vec::new()) - // .map_err(|e| Crypt4GHError::NotEnoughInput(range_start, e.into()))?; +// // read_buffer +// // .by_ref() +// // .take(range_start as u64) +// // .read_to_end(&mut Vec::new()) +// // .map_err(|e| Crypt4GHError::NotEnoughInput(range_start, e.into()))?; - log::debug!(" Span: {:?}", range_span); +// log::debug!(" Span: {:?}", range_span); - log::info!("Creating Crypt4GH header"); +// log::info!("Creating Crypt4GH header"); - let mut session_key = [0_u8; 32]; - let mut rnd = rand_chacha::ChaCha20Rng::from_entropy(); +// let mut session_key = [0_u8; 32]; +// let mut rnd = rand_chacha::ChaCha20Rng::from_entropy(); - // random bytes into session_key - rnd.try_fill_bytes(&mut session_key).map_err(|_| Crypt4GHError::NoRandomNonce)?; +// // random bytes into session_key +// rnd.try_fill_bytes(&mut session_key).map_err(|_| Crypt4GHError::NoRandomNonce)?; - let header_bytes = encrypt_header(recipient_keys, &Some(session_key))?; - - log::debug!("header length: {}", header_bytes.len()); - - write_buffer.write_all(&header_bytes)?; - - log::info!("Streaming content"); - - let mut segment = [0_u8; SEGMENT_SIZE]; - - let mut rnd = rand_chacha::ChaCha20Rng::from_entropy(); - let mut nonce_bytes = [0u8; 12]; - rnd.fill(&mut nonce_bytes); - - // The whole file - match range_span { - None | Some(0) => loop { - let segment_len = read_buffer.read(&mut segment)?; - if segment_len == 0 { - break; - } - else if segment_len < SEGMENT_SIZE { - let (data, _) = segment.split_at(segment_len); - let nonce = Nonce::from_slice(&nonce_bytes); - //.map_err(|_| Crypt4GHError::NoRandomNonce)?; - let key = Key::from_slice(&session_key); - //.ok_or(Crypt4GHError::NoKey)?; - let encrypted_data = encrypt_segment(data, *nonce, &key)?; - write_buffer.write_all(&encrypted_data)?; - break; - } - else { - let nonce = Nonce::from_slice(&nonce_bytes); - //.ok_or(Crypt4GHError::NoRandomNonce)?; - let key = Key::from_slice(&session_key);//.ok_or(Crypt4GHError::NoKey)?; - let encrypted_data = encrypt_segment(&segment, *nonce, &key)?; - write_buffer.write_all(&encrypted_data)?; - } - }, - Some(mut remaining_length) => { - while remaining_length > 0 { - let segment_len = read_buffer.read(&mut segment)?; - - // Stop - if segment_len >= remaining_length { - let (data, _) = segment.split_at(remaining_length); - let nonce = Nonce::from_slice(&nonce_bytes); - //.ok_or(Crypt4GHError::NoRandomNonce)?; - let key = Key::from_slice(&session_key); - //.ok_or(Crypt4GHError::NoKey)?; - let encrypted_data = encrypt_segment(data, *nonce, &key)?; - write_buffer.write_all(&encrypted_data)?; - break; - } - - // Not a full segment - if segment_len < SEGMENT_SIZE { - let (data, _) = segment.split_at(segment_len); - let nonce = Nonce::from_slice(&nonce_bytes); - //.ok_or(Crypt4GHError::NoRandomNonce)?; - let key = Key::from_slice(&session_key); - //.ok_or(Crypt4GHError::NoKey)?; - let encrypted_data = encrypt_segment(data, *nonce, &key)?; - write_buffer.write_all(&encrypted_data)?; - break; - } - - let nonce = Nonce::from_slice(&nonce_bytes); - //.ok_or(Crypt4GHError::NoRandomNonce)?; - let key = Key::from_slice(&session_key); - //.ok_or(Crypt4GHError::NoKey)?; - let encrypted_data = encrypt_segment(&segment, *nonce, &key)?; - write_buffer.write_all(&encrypted_data)?; - - remaining_length -= segment_len; - } - }, - } - - log::info!("Encryption Successful"); - Ok(()) -} +// let header_bytes = encrypt_header(recipient_keys, &Some(session_key))?; + +// log::debug!("header length: {}", header_bytes.len()); + +// write_buffer.write_all(&header_bytes)?; + +// log::info!("Streaming content"); + +// let mut segment = [0_u8; SEGMENT_SIZE]; + +// let mut rnd = rand_chacha::ChaCha20Rng::from_entropy(); +// let mut nonce_bytes = [0u8; 12]; +// rnd.fill(&mut nonce_bytes); + +// // The whole file +// match range_span { +// None | Some(0) => loop { +// let segment_len = read_buffer.read(&mut segment)?; +// if segment_len == 0 { +// break; +// } +// else if segment_len < SEGMENT_SIZE { +// let (data, _) = segment.split_at(segment_len); +// let nonce = Nonce::from_slice(&nonce_bytes); +// //.map_err(|_| Crypt4GHError::NoRandomNonce)?; +// let key = Key::from_slice(&session_key); +// //.ok_or(Crypt4GHError::NoKey)?; +// let encrypted_data = encrypt_segment(data, *nonce, &key)?; +// write_buffer.write_all(&encrypted_data)?; +// break; +// } +// else { +// let nonce = Nonce::from_slice(&nonce_bytes); +// //.ok_or(Crypt4GHError::NoRandomNonce)?; +// let key = Key::from_slice(&session_key);//.ok_or(Crypt4GHError::NoKey)?; +// let encrypted_data = encrypt_segment(&segment, *nonce, &key)?; +// write_buffer.write_all(&encrypted_data)?; +// } +// }, +// Some(mut remaining_length) => { +// while remaining_length > 0 { +// let segment_len = read_buffer.read(&mut segment)?; + +// // Stop +// if segment_len >= remaining_length { +// let (data, _) = segment.split_at(remaining_length); +// let nonce = Nonce::from_slice(&nonce_bytes); +// //.ok_or(Crypt4GHError::NoRandomNonce)?; +// let key = Key::from_slice(&session_key); +// //.ok_or(Crypt4GHError::NoKey)?; +// let encrypted_data = encrypt_segment(data, *nonce, &key)?; +// write_buffer.write_all(&encrypted_data)?; +// break; +// } + +// // Not a full segment +// if segment_len < SEGMENT_SIZE { +// let (data, _) = segment.split_at(segment_len); +// let nonce = Nonce::from_slice(&nonce_bytes); +// //.ok_or(Crypt4GHError::NoRandomNonce)?; +// let key = Key::from_slice(&session_key); +// //.ok_or(Crypt4GHError::NoKey)?; +// let encrypted_data = encrypt_segment(data, *nonce, &key)?; +// write_buffer.write_all(&encrypted_data)?; +// break; +// } + +// let nonce = Nonce::from_slice(&nonce_bytes); +// //.ok_or(Crypt4GHError::NoRandomNonce)?; +// let key = Key::from_slice(&session_key); +// //.ok_or(Crypt4GHError::NoKey)?; +// let encrypted_data = encrypt_segment(&segment, *nonce, &key)?; +// write_buffer.write_all(&encrypted_data)?; + +// remaining_length -= segment_len; +// } +// }, +// } + +// log::info!("Encryption Successful"); +// Ok(()) +// } /// Builds a header with a random session key /// @@ -249,7 +247,7 @@ pub fn decrypt( data_block: Bytes, session_keys: SessionKeys, edit_list_packet: Option>, - ) -> Result { + ) -> Result { let size = data_block.len(); let read_buf = Cursor::new(data_block.to_vec()); @@ -556,7 +554,7 @@ pub fn reencrypt( read_buffer .read_exact(&mut temp_buf) .map_err(|e| Crypt4GHError::ReadHeaderError(e.into()))?; - let header_info: header::HeaderInfo = header::deconstruct_header_info(&temp_buf)?; + let header_info: header::HeaderInfo = header::deserialize_header_info(&temp_buf)?; // Calculate header packets let header_packets = (0..header_info.packets_count) @@ -618,7 +616,7 @@ pub fn rearrange( read_buffer .read_exact(&mut temp_buf) .map_err(|e| Crypt4GHError::ReadHeaderError(e.into()))?; - let header_info: header::HeaderInfo = header::deconstruct_header_info(&temp_buf)?; + let header_info: header::HeaderInfo = header::deserialize_header_info(&temp_buf)?; // Calculate header packets let header_packets = (0..header_info.packets_count) diff --git a/src/reader/builder.rs b/src/reader/builder.rs index acc426f..95ddaaf 100644 --- a/src/reader/builder.rs +++ b/src/reader/builder.rs @@ -1,13 +1,13 @@ use std::thread; -use crypt4gh::Keys; +use crate::keys::Keys; use futures_util::TryStreamExt; use tokio::io::{AsyncRead, AsyncSeek}; use crate::decrypter::builder::Builder as DecrypterBuilder; use crate::decrypter::DecrypterStream; use crate::error::Result; -use crate::PublicKey; +use crate::keys::PublicKey; use super::Reader; diff --git a/src/reader/mod.rs b/src/reader/mod.rs index 8bf8b9a..3ce575a 100644 --- a/src/reader/mod.rs +++ b/src/reader/mod.rs @@ -3,7 +3,6 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::{cmp, io}; -use async_trait::async_trait; use crypt4gh::header::HeaderInfo; use crypt4gh::Keys; use futures::ready; @@ -221,7 +220,6 @@ where } } -#[async_trait] impl Advance for Reader where R: AsyncRead + Send + Unpin, diff --git a/src/util/mod.rs b/src/util/mod.rs index a4f4689..da6a3f9 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,11 +1,10 @@ -use crypt4gh::keys::{generate_keys, get_private_key, get_public_key}; +//use crate::keys::{generate_keys, get_private_key, get_public_key}; use rustls::PrivateKey; use std::cmp::min; -use tempfile::TempDir; use crate::decoder::Block; use crate::error::{Error, Result}; -use crate::{KeyPair, PublicKey}; +use crate::keys::{KeyPair, PublicKey}; fn to_current_data_block(pos: u64, header_len: u64) -> u64 { header_len + (pos / Block::encrypted_block_size()) * Block::standard_data_block_size() From 3049ea1a2e64e2bf07b34cdc756269ad645044b0 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 12 Feb 2024 10:51:46 +1100 Subject: [PATCH 07/30] More sweeping changes on error control, need to consolidate PrivateKey type (from ssh_keys, rustls, our custom one...). Also the testsuite is too based on filesystem. [ci skip] --- src/decoder/mod.rs | 27 ++++------ src/decrypter/data_block.rs | 2 +- src/decrypter/header/packets.rs | 2 +- src/decrypter/mod.rs | 5 +- src/edit_lists.rs | 2 +- src/error.rs | 95 ++++++++++++++++----------------- src/keys.rs | 30 +---------- src/lib.rs | 5 +- src/reader/mod.rs | 32 ++--------- src/util/mod.rs | 2 +- 10 files changed, 71 insertions(+), 131 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 2977bc5..16aae84 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1,15 +1,14 @@ use std::io; use bytes::{Bytes, BytesMut}; -use crypt4gh::header::{deconstruct_header_info, HeaderInfo}; +use crate::header::{deserialize_header_info, HeaderInfo}; use tokio_util::codec::Decoder; -use crate::error::Error::{ - Crypt4GHError, DecodingHeaderInfo, MaximumHeaderSize, NumericConversionError, - SliceConversionError, +use crate::error::Crypt4GHError::{ + self, Crypt4GHError, DecodingHeaderInfo, MaximumHeaderSize, NumericConversionError, SliceConversionError }; -use crate::error::{Error, Result}; -use crate::{EncryptedHeaderPacketBytes, EncryptedHeaderPackets}; +use crate::error::Result; +use crate::header::EncryptedHeaderPackets; pub const ENCRYPTED_BLOCK_SIZE: usize = 65536; pub const NONCE_SIZE: usize = 12; // ChaCha20 IETF Nonce size @@ -132,7 +131,7 @@ impl Block { return Ok(None); } - header_packet_bytes.push(EncryptedHeaderPacketBytes::new( + header_packet_bytes.push(EncryptedHeaderPackets::new( length_bytes, src.split_to(length).freeze(), )); @@ -210,7 +209,7 @@ impl Default for Block { impl Decoder for Block { type Item = DecodedBlock; - type Error = Error; + type Error = Crypt4GHError; fn decode(&mut self, src: &mut BytesMut) -> Result> { match self.next_block { @@ -251,19 +250,13 @@ impl Decoder for Block { pub(crate) mod tests { use std::io::Cursor; - use crypt4gh::header::{deconstruct_header_body, DecryptedHeaderPackets}; - use crypt4gh::{body_decrypt, Keys, WriteInfo}; + use crate::header::{deconstruct_header_body, DecryptedHeaderPackets}; + use crate::{body_decrypt, Keys, WriteInfo}; use futures_util::stream::Skip; use futures_util::StreamExt; - use tokio::fs::File; + //use tokio::fs::File; use tokio::io::AsyncReadExt; use tokio_util::codec::FramedRead; - - use htsget_test::crypt4gh::get_decryption_keys; - use htsget_test::http_tests::get_test_file; - - use crate::tests::get_original_file; - use super::*; #[tokio::test] diff --git a/src/decrypter/data_block.rs b/src/decrypter/data_block.rs index e4dca7f..3a13e18 100644 --- a/src/decrypter/data_block.rs +++ b/src/decrypter/data_block.rs @@ -10,7 +10,7 @@ use pin_project_lite::pin_project; use tokio::task::JoinHandle; use crate::decrypter::DecrypterStream; -use crate::error::Error::{Crypt4GHError, JoinHandleError}; +use crate::error::Crypt4GHError::{Crypt4GHError, JoinHandleError}; use crate::error::Result; pin_project! { diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs index 50dcfec..931cf79 100644 --- a/src/decrypter/header/packets.rs +++ b/src/decrypter/header/packets.rs @@ -8,7 +8,7 @@ use crate::Keys; use pin_project_lite::pin_project; use tokio::task::{spawn_blocking, JoinHandle}; -use crate::error::Error::JoinHandleError; +use crate::error::Crypt4GHError::JoinHandleError; use crate::error::Result; use crate::keys::PublicKey; diff --git a/src/decrypter/mod.rs b/src/decrypter/mod.rs index f281ec3..00c4d31 100644 --- a/src/decrypter/mod.rs +++ b/src/decrypter/mod.rs @@ -18,10 +18,9 @@ use crate::decoder::DecodedBlock; use crate::decrypter::data_block::DataBlockDecrypter; use crate::decrypter::header::packets::HeaderPacketsDecrypter; use crate::decrypter::header::SessionKeysFuture; -use crate::error::Error::Crypt4GHError; +use crate::error::Crypt4GHError::Crypt4GHError; use crate::error::Result; -use crate::EncryptedHeaderPacketBytes; -use crate::{util, PublicKey}; +use crate::{util, keys::PublicKey}; pub mod builder; pub mod data_block; diff --git a/src/edit_lists.rs b/src/edit_lists.rs index 62732d5..323e692 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -5,7 +5,7 @@ use crate::keys::Keys; use rustls::PrivateKey; use tokio::io::AsyncRead; -use crate::error::{Error, Result}; +use crate::error::Result; use crate::reader::Reader; use crate::keys::PublicKey; diff --git a/src/error.rs b/src/error.rs index 9493c06..5a6febc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,13 @@ -use std::error::Error; -use std::path::PathBuf; +use std::{io, result}; use thiserror::Error; +use tokio::task; + +/// The result type for Crypt4GH errors. +pub type Result = result::Result; +use std::path::PathBuf; + +// FIXME: Merge both Error and Crypt4GHError into Crypt4GHError #[derive(Debug, Error)] pub enum Crypt4GHError { @@ -154,53 +160,46 @@ pub enum Crypt4GHError { #[error("Unable to parse the start of the range")] ParseRangeError, - // // Config errors - // #[error("Unable to get environment variable '{0}' (ERROR = {1}) ")] - // NoEnvVar(&'static str, String), - // #[error("Wrong Port")] - // WrongPort, - // #[error("Bad config (ERROR = {0})")] - // BadConfig(String), - - // // Binding errors - // #[error("Unable to bind to the address (ERROR = {0})")] - // BindingError(String), - // #[error("Unable to parse address: {0} (ERROR = {1})")] - // WrongAddress(String, String), - - // // Runtime errors - // #[error("Internal Server Failed (ERROR = {0})")] - // InternalServerError(String), - // #[error("Page not found (ERROR = {0})")] - // NotFound(String), - // #[error("Database Failed (ERROR = {0})")] - // DbError(String), - // #[error("Cache Failed (ERROR = {0})")] - // CacheError(String), - // #[error("Invalid Headers")] - // InvalidHeaders, - - // // Passport errors - // #[error("Unable to construct passport (ERROR = {0})")] - // BadPassport(String), - - // // Authentication errors - // #[error("Unauthorized")] - // Unauthorized, - // #[error("Forbidden")] - // Forbidden, - - // // AMQP - // #[error("Connection url bad format")] - // BadConfigConnectionUrl, - // #[error("AMQP TlsConnector builder failed")] - // TlsConnectorError, - // #[error("AMQP Connection failed")] - // ConnectionError(Option), - // #[error("AMQP Error")] - // AMQPError(#[from] amiquip::Error), - // IO #[error("IO failed")] IoError(#[from] std::io::Error), + + // Conversion and decoding + #[error("converting slice to fixed size array")] + SliceConversionError, + #[error("converting between numeric types")] + NumericConversionError, + // #[error("decoding header info: `{0}`")] + // DecodingHeaderInfo(Crypt4GHError), + // #[error("decoding header packet: `{0}`")] + // DecodingHeaderPacket(Crypt4GHError), + #[error("join handle error: `{0}`")] + JoinHandleError(task::JoinError), + #[error("maximum header size exceeded")] + MaximumHeaderSize, + #[error("crypt4gh error: `{0}`")] + Crypt4GHError(String), +} + +impl From for Crypt4GHError { + fn from(error: io::Error) -> Self { + Self::IOError(error) + } +} + +impl From for Crypt4GHError { + fn from(error: dyn std::error::Error) -> Self { + if let std::error::Error::IOError(error) = error { + error + } else { + Self::new(io::ErrorKind::Other, error) + } + } } + +impl From for Crypt4GHError { + fn from(error: Crypt4GHError) -> Self { + Self::Crypt4GHError(error.to_string()) + } +} + diff --git a/src/keys.rs b/src/keys.rs index 79bd44f..fd5d54f 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -1,39 +1,13 @@ #![warn(missing_docs)] #![warn(rustdoc::missing_doc_code_examples)] -use bytes::Bytes; -use rustls::PrivateKey; - -use aes::cipher::{StreamCipher, generic_array::GenericArray}; +//use rustls::PrivateKey; use std::collections::HashMap; -use std::fs::File; -use std::io::{BufRead, BufReader, Cursor, Read, Write, BufWriter}; -use std::path::PathBuf; - -use base64::engine::general_purpose; -use base64::Engine; +use std::io::Read; use lazy_static::lazy_static; -use rand_chacha; -use rand::{SeedableRng, RngCore, Rng}; - -use crypto_kx::{Keypair, SecretKey}; - -use aes::cipher::{KeyInit, KeyIvInit}; -use aes::cipher::consts::U48; -use chacha20poly1305::aead::Aead; -use chacha20poly1305::aead::OsRng; -use chacha20poly1305::{self, ChaCha20Poly1305}; - -use ctr; - -use curve25519_dalek::montgomery::MontgomeryPoint; -use curve25519_dalek::traits::IsIdentity; - -use crate::error::Crypt4GHError; - const C4GH_MAGIC_WORD: &[u8; 7] = b"c4gh-v1"; const SSH_MAGIC_WORD: &[u8; 15] = b"openssh-key-v1\x00"; diff --git a/src/lib.rs b/src/lib.rs index 69dd14d..11bee66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub mod keys; pub mod error; use bytes::Bytes; +use decrypter::DecrypterStream; use io::Cursor; use keys::SessionKeys; use rand::{SeedableRng, RngCore}; @@ -256,14 +257,14 @@ pub fn decrypt( // Todo crypt4gh-rust body_decrypt_parts does not work properly, so just apply edit list here. body_decrypt(read_buf, session_keys.as_slice(), &mut write_info, 0) - .map_err(|err| Crypt4GHError(err.to_string()))?; + .map_err(|err| Crypt4GHError::UnableToDecryptBlock(read_buf, err.to_string()))?; let mut decrypted_bytes: Bytes = write_buf.into_inner().into(); let mut edited_bytes = Bytes::new(); let edits = DecrypterStream::<()>::create_internal_edit_list(edit_list_packet) .unwrap_or(vec![(false, decrypted_bytes.len() as u64)]); if edits.iter().map(|(_, edit)| edit).sum::() > decrypted_bytes.len() as u64 { - return Err(Crypt4GHError( + return Err(Crypt4GHError::UnableToDecryptBlock(edits, "invalid edit lists for the decrypted data block".to_string(), )); } diff --git a/src/reader/mod.rs b/src/reader/mod.rs index 3ce575a..931c9e6 100644 --- a/src/reader/mod.rs +++ b/src/reader/mod.rs @@ -3,17 +3,16 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::{cmp, io}; -use crypt4gh::header::HeaderInfo; -use crypt4gh::Keys; +use crate::header::HeaderInfo; +use crate::Keys; use futures::ready; use futures::stream::TryBuffered; use futures::Stream; use pin_project_lite::pin_project; use tokio::io::{AsyncBufRead, AsyncRead, AsyncSeek, ReadBuf}; -use crate::advance::Advance; use crate::decoder::Block; -use crate::error::Error::NumericConversionError; +use crate::error::Crypt4GHError::NumericConversionError; use crate::error::Result; use crate::reader::builder::Builder; use crate::{DecryptedDataBlock, EncryptedHeaderPacketBytes}; @@ -220,31 +219,6 @@ where } } -impl Advance for Reader -where - R: AsyncRead + Send + Unpin, -{ - async fn advance_encrypted(&mut self, position: u64) -> io::Result { - let position = self.stream.get_mut().advance_encrypted(position).await?; - - self.block_position = Some(position); - - Ok(position) - } - - async fn advance_unencrypted(&mut self, position: u64) -> io::Result { - let position = self.stream.get_mut().advance_unencrypted(position).await?; - - self.block_position = Some(position); - - Ok(position) - } - - fn stream_length(&self) -> Option { - self.stream.get_ref().stream_length() - } -} - #[cfg(test)] mod tests { use std::io::SeekFrom; diff --git a/src/util/mod.rs b/src/util/mod.rs index da6a3f9..6d706ef 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -3,7 +3,7 @@ use rustls::PrivateKey; use std::cmp::min; use crate::decoder::Block; -use crate::error::{Error, Result}; +use crate::error::Result; use crate::keys::{KeyPair, PublicKey}; fn to_current_data_block(pos: u64, header_len: u64) -> u64 { From 85041ea8e6f56ba1a89e8d1804b2123ffd8cb38f Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 12 Feb 2024 11:35:20 +1100 Subject: [PATCH 08/30] Add Noodles as a dependency for some test that require it... --- Cargo.lock | 413 ++++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 3 + 2 files changed, 414 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd12543..4012b31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,6 +47,19 @@ dependencies = [ "memchr", ] +[[package]] +name = "async-compression" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -106,6 +119,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -155,6 +174,16 @@ dependencies = [ "cipher", ] +[[package]] +name = "bstr" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "byteorder" version = "1.4.3" @@ -167,6 +196,27 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cbc" version = "0.1.2" @@ -278,6 +328,30 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crypt4gh" version = "0.4.1" @@ -299,6 +373,9 @@ dependencies = [ "itertools", "lazy_static", "log", + "noodles", + "noodles-bam", + "noodles-sam", "pin-project-lite", "pretty_env_logger", "rand", @@ -487,6 +564,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.1" @@ -524,6 +607,16 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "futures" version = "0.3.30" @@ -652,6 +745,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "heck" version = "0.4.0" @@ -679,6 +778,16 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "inout" version = "0.1.3" @@ -730,6 +839,70 @@ dependencies = [ "spin 0.5.2", ] +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.153" @@ -757,11 +930,32 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miniz_oxide" @@ -772,6 +966,194 @@ dependencies = [ "adler", ] +[[package]] +name = "noodles" +version = "0.63.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2212020b3faa067f38e4b5ecd558ff85a84f05d772882590d79cb772dadbbd1" +dependencies = [ + "noodles-bam", + "noodles-bcf", + "noodles-bgzf", + "noodles-cram", + "noodles-csi", + "noodles-fasta", + "noodles-fastq", + "noodles-sam", + "noodles-tabix", + "noodles-vcf", +] + +[[package]] +name = "noodles-bam" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3980bc5cf6294d2ec132f8572d57b52f190e788ecd74a71b86ab81e6ce73afbb" +dependencies = [ + "bit-vec", + "bstr", + "byteorder", + "bytes", + "futures", + "indexmap", + "noodles-bgzf", + "noodles-core", + "noodles-csi", + "noodles-sam", + "tokio", +] + +[[package]] +name = "noodles-bcf" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1561dbba3a09a61020b805a598b3d7c50841491c915523e0e4987f67286886f1" +dependencies = [ + "byteorder", + "futures", + "indexmap", + "noodles-bgzf", + "noodles-core", + "noodles-csi", + "noodles-vcf", + "tokio", +] + +[[package]] +name = "noodles-bgzf" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8970db2e84adb1007377dd3988258d7a64e3fc4c05602ebf94e1f8cba207c030" +dependencies = [ + "byteorder", + "bytes", + "crossbeam-channel", + "flate2", + "futures", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "noodles-core" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7336c3be652de4e05444c9b12a32331beb5ba3316e8872d92bfdd8ef3b06c282" + +[[package]] +name = "noodles-cram" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ec9e47cd63c93a1aa9354e7372f1e815bb4ff332048784c8a76af9baa08e613" +dependencies = [ + "async-compression", + "bitflags 2.3.2", + "bstr", + "byteorder", + "bytes", + "bzip2", + "flate2", + "futures", + "indexmap", + "md-5", + "noodles-bam", + "noodles-core", + "noodles-fasta", + "noodles-sam", + "pin-project-lite", + "tokio", + "xz2", +] + +[[package]] +name = "noodles-csi" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a60dfe0919f7ecbd081a82eb1d32e8f89f9041932d035fe8309073c8c01277bf" +dependencies = [ + "bit-vec", + "byteorder", + "indexmap", + "noodles-bgzf", + "noodles-core", + "tokio", +] + +[[package]] +name = "noodles-fasta" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebb3e83e0f112d3482f5234a1eb219081f12cc3aab38a9eba00ef1846b43b63b" +dependencies = [ + "bytes", + "memchr", + "noodles-bgzf", + "noodles-core", + "tokio", +] + +[[package]] +name = "noodles-fastq" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03559005dc319f23454e0ae6804f72d27da2d4293c2dcc01ff7b0d8c5d59ab9f" +dependencies = [ + "futures", + "memchr", + "tokio", +] + +[[package]] +name = "noodles-sam" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b778d5136a0d7659e2e1950df586e0fe18ec793bf44e8a4123417af39ba062" +dependencies = [ + "bitflags 2.3.2", + "bstr", + "futures", + "indexmap", + "lexical-core", + "memchr", + "noodles-bgzf", + "noodles-core", + "noodles-csi", + "tokio", +] + +[[package]] +name = "noodles-tabix" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1ab29335a68d0c2bdf41460a67714ca69e23a1cbeb950ac5c38a9afa446a62" +dependencies = [ + "bit-vec", + "byteorder", + "indexmap", + "noodles-bgzf", + "noodles-core", + "noodles-csi", + "tokio", +] + +[[package]] +name = "noodles-vcf" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1f2fa749afaccadc596ec55ccb7bdcd8101fa79f8382384223c0dbae3e245b" +dependencies = [ + "futures", + "indexmap", + "memchr", + "noodles-bgzf", + "noodles-core", + "noodles-csi", + "noodles-tabix", + "percent-encoding", + "tokio", +] + [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -925,6 +1307,12 @@ dependencies = [ "base64ct", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -958,6 +1346,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" + [[package]] name = "platforms" version = "3.0.2" @@ -1376,6 +1770,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" @@ -1645,6 +2045,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 20de0c8..222d221 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,9 @@ futures-util = "0.3.30" [dev-dependencies] testresult = "0.3" +noodles-bam = "0.55" +noodles-sam = "0.52" +noodles = { version = "0.63", features = [ "sam", "bam", "async" ] } [profile.release] lto = true From 5e9b0c5fb9317536406a2926202218cfa326193c Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 12 Feb 2024 11:35:49 +1100 Subject: [PATCH 09/30] More rearranging and cleanup of imports, error definitions --- src/decoder/mod.rs | 6 +++--- src/decrypter/mod.rs | 2 +- src/edit_lists.rs | 8 ++++---- src/error.rs | 8 ++++---- src/header.rs | 10 +++++++--- src/reader/mod.rs | 7 +------ 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 16aae84..6a4d1e1 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -5,7 +5,7 @@ use crate::header::{deserialize_header_info, HeaderInfo}; use tokio_util::codec::Decoder; use crate::error::Crypt4GHError::{ - self, Crypt4GHError, DecodingHeaderInfo, MaximumHeaderSize, NumericConversionError, SliceConversionError + self, DecodingHeaderInfo, MaximumHeaderSize, NumericConversionError, SliceConversionError }; use crate::error::Result; use crate::header::EncryptedHeaderPackets; @@ -63,7 +63,7 @@ pub struct Block { impl Block { fn get_header_info(src: &mut BytesMut) -> Result { - deconstruct_header_info( + deserialize_header_info( src .split_to(HEADER_INFO_SIZE) .as_ref() @@ -234,7 +234,7 @@ impl Decoder for Block { Ok(Some(DecodedBlock::DataBlock(buf.split().freeze()))) } else { - Err(Crypt4GHError( + Err(Crypt4GHError::UnableToDecryptBlock(self.next_block, "the last data block is too large".to_string(), )) } diff --git a/src/decrypter/mod.rs b/src/decrypter/mod.rs index 00c4d31..49567cf 100644 --- a/src/decrypter/mod.rs +++ b/src/decrypter/mod.rs @@ -5,7 +5,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; -use crate::header::HeaderInfo; +use crate::header::{EncryptedHeaderPacketBytes, HeaderInfo}; use crate::Keys; use futures::ready; use futures::Stream; diff --git a/src/edit_lists.rs b/src/edit_lists.rs index 323e692..fa17ea1 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -5,7 +5,7 @@ use crate::keys::Keys; use rustls::PrivateKey; use tokio::io::AsyncRead; -use crate::error::Result; +use crate::error::{Crypt4GHError, Result}; use crate::reader::Reader; use crate::keys::PublicKey; @@ -134,7 +134,7 @@ where encrypt(&edit_list_packet, &HashSet::from_iter(vec![keys]))? .into_iter() .last() - .ok_or_else(|| Error::Crypt4GHError("could not encrypt header packet".to_string())) + .ok_or_else(|| Crypt4GHError::EditHeader("could not encrypt header packet".to_string())) } /// Create the edit lists from the unencrypted byte positions. @@ -195,7 +195,7 @@ where /// Add edit lists and return a header packet. pub fn edit_list(self) -> Result> { if self.reader.edit_list_packet().is_some() { - return Err(Error::Crypt4GHError("edit lists already exist".to_string())); + return Err(Crypt4GHError::InvalidEditList("edit lists already exist".to_string())); } // Todo, header info should have copy or clone on it. @@ -222,7 +222,7 @@ where // Todo rewrite this from the context of an encryption stream like the decrypter. header_info.packets_count += 1; let header_info_bytes = - bincode::serialize(&header_info).map_err(|err| Error::Crypt4GHError(err.to_string()))?; + bincode::serialize(&header_info).map_err(|err| Crypt4GHError::ReadHeaderError(err.to_string()))?; let edit_list = self.create_edit_list(); let edit_list_packet = diff --git a/src/error.rs b/src/error.rs index 5a6febc..46bb314 100644 --- a/src/error.rs +++ b/src/error.rs @@ -169,10 +169,10 @@ pub enum Crypt4GHError { SliceConversionError, #[error("converting between numeric types")] NumericConversionError, - // #[error("decoding header info: `{0}`")] - // DecodingHeaderInfo(Crypt4GHError), - // #[error("decoding header packet: `{0}`")] - // DecodingHeaderPacket(Crypt4GHError), + #[error("decoding header info: `{0}`")] + DecodingHeaderInfo(Crypt4GHError), + #[error("decoding header packet: `{0}`")] + DecodingHeaderPacket(Crypt4GHError), #[error("join handle error: `{0}`")] JoinHandleError(task::JoinError), #[error("maximum header size exceeded")] diff --git a/src/header.rs b/src/header.rs index dfb3503..98d9bff 100644 --- a/src/header.rs +++ b/src/header.rs @@ -24,11 +24,15 @@ enum HeaderPacketType { EditList = 1, } -struct HeaderPackets { +pub struct HeaderPackets { data_enc_packets: Vec>, edit_list_packet: Option>, } +pub struct EncryptedHeaderPacketBytes { + inner: Vec +} + /// Represents the encrypted header packet data, and the total size of all the header packets. #[derive(Debug, Default)] pub struct EncryptedHeaderPackets { @@ -364,10 +368,10 @@ pub fn deconstruct_header_body( /// /// Reads the magic number, the version and the number of packets from the bytes. pub fn deserialize_header_info( - header_info_file: , // TODO: HeaderInfo::len() + header_info: HeaderInfo, // TODO: HeaderInfo::len() ) -> Result { let header_info = - bincode::deserialize::(header_info_file.unwrap()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; + bincode::deserialize::(header_info.unwrap()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; if &header_info.magic_number != MAGIC_NUMBER { return Err(Crypt4GHError::MagicStringError); diff --git a/src/reader/mod.rs b/src/reader/mod.rs index 931c9e6..db60c0a 100644 --- a/src/reader/mod.rs +++ b/src/reader/mod.rs @@ -15,7 +15,7 @@ use crate::decoder::Block; use crate::error::Crypt4GHError::NumericConversionError; use crate::error::Result; use crate::reader::builder::Builder; -use crate::{DecryptedDataBlock, EncryptedHeaderPacketBytes}; +use crate::{DecryptedDataBlock, header::EncryptedHeaderPacketBytes}; use super::decrypter::DecrypterStream; @@ -228,13 +228,8 @@ mod tests { use noodles::sam::Header; use tokio::io::AsyncReadExt; - use htsget_test::http_tests::get_test_file; - - use crate::advance::Advance; use crate::reader::builder::Builder; - use crate::tests::get_original_file; use crate::PublicKey; - use htsget_test::crypt4gh::get_decryption_keys; #[tokio::test] async fn reader() { From 49b2c2cb2032289fc570fb34a86abeae4d1bba6a Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 12 Feb 2024 16:24:22 +1100 Subject: [PATCH 10/30] Remove custom Result type and be explicit about Crypt4GHErrors everywhere [ci skip] --- src/decoder/mod.rs | 13 +++--- src/decrypter/builder.rs | 1 - src/decrypter/data_block.rs | 13 +++--- src/decrypter/header/packets.rs | 9 ++-- src/decrypter/mod.rs | 15 +++---- src/edit_lists.rs | 6 +-- src/error.rs | 79 +++++++++++++++------------------ src/reader/builder.rs | 4 +- src/reader/mod.rs | 7 ++- src/util/mod.rs | 6 +-- 10 files changed, 69 insertions(+), 84 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 6a4d1e1..8bfac3e 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -7,7 +7,6 @@ use tokio_util::codec::Decoder; use crate::error::Crypt4GHError::{ self, DecodingHeaderInfo, MaximumHeaderSize, NumericConversionError, SliceConversionError }; -use crate::error::Result; use crate::header::EncryptedHeaderPackets; pub const ENCRYPTED_BLOCK_SIZE: usize = 65536; @@ -62,7 +61,7 @@ pub struct Block { } impl Block { - fn get_header_info(src: &mut BytesMut) -> Result { + fn get_header_info(src: &mut BytesMut) -> Result { deserialize_header_info( src .split_to(HEADER_INFO_SIZE) @@ -77,7 +76,7 @@ impl Block { /// `decode` methods, this method parses the header info before returning a decoded block /// because the header info contains the number of packets which is required for decoding /// the rest of the source. - pub fn decode_header_info(&mut self, src: &mut BytesMut) -> Result> { + pub fn decode_header_info(&mut self, src: &mut BytesMut) -> Result, Crypt4GHError> { // Header info is a fixed size. if src.len() < HEADER_INFO_SIZE { src.reserve(HEADER_INFO_SIZE); @@ -97,7 +96,7 @@ impl Block { &mut self, src: &mut BytesMut, header_packets: u32, - ) -> Result> { + ) -> Result, Crypt4GHError> { let mut header_packet_bytes = vec![]; for _ in 0..header_packets { // Get enough bytes to read the header packet length. @@ -153,7 +152,7 @@ impl Block { } /// Decodes data blocks, updates the state and returns a data block type. - pub fn decode_data_block(&mut self, src: &mut BytesMut) -> Result> { + pub fn decode_data_block(&mut self, src: &mut BytesMut) -> Result, Crypt4GHError> { // Data blocks are a fixed size, so we can return the // next data block without much processing. if src.len() < DATA_BLOCK_SIZE { @@ -211,7 +210,7 @@ impl Decoder for Block { type Item = DecodedBlock; type Error = Crypt4GHError; - fn decode(&mut self, src: &mut BytesMut) -> Result> { + fn decode(&mut self, src: &mut BytesMut) -> Result, Crypt4GHError> { match self.next_block { BlockState::HeaderInfo => self.decode_header_info(src), BlockState::HeaderPackets(header_packets) => self.decode_header_packets(src, header_packets), @@ -220,7 +219,7 @@ impl Decoder for Block { } } - fn decode_eof(&mut self, buf: &mut BytesMut) -> Result> { + fn decode_eof(&mut self, buf: &mut BytesMut) -> Result, Crypt4GHError> { // Need a custom implementation of decode_eof because the last data block can be shorter. match self.decode(buf)? { Some(frame) => Ok(Some(frame)), diff --git a/src/decrypter/builder.rs b/src/decrypter/builder.rs index e7be65a..b5c57a6 100644 --- a/src/decrypter/builder.rs +++ b/src/decrypter/builder.rs @@ -3,7 +3,6 @@ use tokio::io::{AsyncRead, AsyncSeek}; use tokio_util::codec::FramedRead; use crate::decrypter::DecrypterStream; -use crate::error::Result; use crate::keys::PublicKey; /// An decrypter reader builder. diff --git a/src/decrypter/data_block.rs b/src/decrypter/data_block.rs index 3a13e18..b15e5b8 100644 --- a/src/decrypter/data_block.rs +++ b/src/decrypter/data_block.rs @@ -10,14 +10,13 @@ use pin_project_lite::pin_project; use tokio::task::JoinHandle; use crate::decrypter::DecrypterStream; -use crate::error::Crypt4GHError::{Crypt4GHError, JoinHandleError}; -use crate::error::Result; +use crate::error::Crypt4GHError::{self, JoinHandleError}; pin_project! { #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct DataBlockDecrypter { #[pin] - handle: JoinHandle> + handle: JoinHandle> } } @@ -125,7 +124,7 @@ impl DataBlockDecrypter { data_block: Bytes, session_keys: Vec>, edit_list_packet: Option>, - ) -> Result { + ) -> Result { let size = data_block.len(); let read_buf = Cursor::new(data_block.to_vec()); @@ -134,14 +133,14 @@ impl DataBlockDecrypter { // Todo crypt4gh-rust body_decrypt_parts does not work properly, so just apply edit list here. body_decrypt(read_buf, session_keys.as_slice(), &mut write_info, 0) - .map_err(|err| Crypt4GHError(err.to_string()))?; + .map_err(|err| Crypt4GHError::DecryptedDataBlock(err.to_string()))?; let mut decrypted_bytes: Bytes = write_buf.into_inner().into(); let mut edited_bytes = Bytes::new(); let edits = DecrypterStream::<()>::create_internal_edit_list(edit_list_packet) .unwrap_or(vec![(false, decrypted_bytes.len() as u64)]); if edits.iter().map(|(_, edit)| edit).sum::() > decrypted_bytes.len() as u64 { - return Err(Crypt4GHError( + return Err(Crypt4GHError::InvalidEditList( "invalid edit lists for the decrypted data block".to_string(), )); } @@ -163,7 +162,7 @@ impl DataBlockDecrypter { } impl Future for DataBlockDecrypter { - type Output = Result; + type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.project().handle.poll(cx).map_err(JoinHandleError)? diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs index 931cf79..a89a0e0 100644 --- a/src/decrypter/header/packets.rs +++ b/src/decrypter/header/packets.rs @@ -8,15 +8,14 @@ use crate::Keys; use pin_project_lite::pin_project; use tokio::task::{spawn_blocking, JoinHandle}; -use crate::error::Crypt4GHError::JoinHandleError; -use crate::error::Result; +use crate::error::Crypt4GHError::{self, JoinHandleError}; use crate::keys::PublicKey; pin_project! { #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct HeaderPacketsDecrypter { #[pin] - handle: JoinHandle> + handle: JoinHandle> } } @@ -37,7 +36,7 @@ impl HeaderPacketsDecrypter { header_packets: Vec, keys: Vec, sender_pubkey: Option, - ) -> Result { + ) -> Result { Ok(deserialize_header_info( header_packets .into_iter() @@ -50,7 +49,7 @@ impl HeaderPacketsDecrypter { } impl Future for HeaderPacketsDecrypter { - type Output = Result; + type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.project().handle.poll(cx).map_err(JoinHandleError)? diff --git a/src/decrypter/mod.rs b/src/decrypter/mod.rs index 49567cf..cc69938 100644 --- a/src/decrypter/mod.rs +++ b/src/decrypter/mod.rs @@ -18,8 +18,7 @@ use crate::decoder::DecodedBlock; use crate::decrypter::data_block::DataBlockDecrypter; use crate::decrypter::header::packets::HeaderPacketsDecrypter; use crate::decrypter::header::SessionKeysFuture; -use crate::error::Crypt4GHError::Crypt4GHError; -use crate::error::Result; +use crate::error::Crypt4GHError::{self, Crypt4GHError}; use crate::{util, keys::PublicKey}; pub mod builder; @@ -103,7 +102,7 @@ where pub fn poll_data_block( mut self: Pin<&mut Self>, data_block: Bytes, - ) -> Poll>> { + ) -> Poll>> { let edit_list = self.as_mut().partition_edit_list(&data_block); let this = self.project(); @@ -116,7 +115,7 @@ where } /// Poll the stream until the header packets and session keys are processed. - pub fn poll_session_keys(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + pub fn poll_session_keys(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { // Only execute this function if there are no session keys. if !self.session_keys.is_empty() { return Poll::Ready(Ok(())); @@ -188,7 +187,7 @@ where } /// Convenience for calling [`poll_session_keys`] on [`Unpin`] types. - pub fn poll_session_keys_unpin(&mut self, cx: &mut Context<'_>) -> Poll> + pub fn poll_session_keys_unpin(&mut self, cx: &mut Context<'_>) -> Poll> where Self: Unpin, { @@ -196,7 +195,7 @@ where } /// Poll the stream until the header has been read. - pub async fn read_header(&mut self) -> Result<()> + pub async fn read_header(&mut self) -> Result<(), Crypt4GHError> where R: Unpin, { @@ -317,7 +316,7 @@ where /// /// This can take up to 3 seek calls. If the size of the underlying buffer changes, this function /// should be called again, otherwise data block positions may not be valid. - pub async fn recompute_stream_length(&mut self) -> Result { + pub async fn recompute_stream_length(&mut self) -> Result { let inner = self.inner.get_mut(); let position = inner.seek(SeekFrom::Current(0)).await?; @@ -337,7 +336,7 @@ impl Stream for DecrypterStream where R: AsyncRead, { - type Item = Result; + type Item = Result; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { // When polling, we first need to process enough data to get the session keys. diff --git a/src/edit_lists.rs b/src/edit_lists.rs index fa17ea1..bf4ca1d 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -5,7 +5,7 @@ use crate::keys::Keys; use rustls::PrivateKey; use tokio::io::AsyncRead; -use crate::error::{Crypt4GHError, Result}; +use crate::error::Crypt4GHError; use crate::reader::Reader; use crate::keys::PublicKey; @@ -124,7 +124,7 @@ where } /// Encrypt the edit list packet. - pub fn encrypt_edit_list(&self, edit_list_packet: Vec) -> Result> { + pub fn encrypt_edit_list(&self, edit_list_packet: Vec) -> Result, Crypt4GHError> { let keys = Keys { method: 0, privkey: self.private_key.clone().0, @@ -193,7 +193,7 @@ where } /// Add edit lists and return a header packet. - pub fn edit_list(self) -> Result> { + pub fn edit_list(self) -> Result, Crypt4GHError> { if self.reader.edit_list_packet().is_some() { return Err(Crypt4GHError::InvalidEditList("edit lists already exist".to_string())); } diff --git a/src/error.rs b/src/error.rs index 46bb314..6131d8c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,15 +1,9 @@ -use std::{io, result}; +use std::error::Error; -use thiserror::Error; +use thiserror::Error as ThisError; use tokio::task; -/// The result type for Crypt4GH errors. -pub type Result = result::Result; -use std::path::PathBuf; - -// FIXME: Merge both Error and Crypt4GHError into Crypt4GHError - -#[derive(Debug, Error)] +#[derive(Debug, ThisError)] pub enum Crypt4GHError { // User errors #[error("No Recipients' Public Key found")] @@ -18,7 +12,6 @@ pub enum Crypt4GHError { InvalidRangeSpan(Option), #[error("The edit list is empty")] EmptyEditList, - // Sodiumoxide errors #[error("Unable to create random nonce")] NoRandomNonce, #[error("Unable to extract nonce")] @@ -33,8 +26,8 @@ pub enum Crypt4GHError { // DecryptKeyError(SymmetricCipherError), #[error("Invalid key format")] InvalidKeyFormat, - #[error("Invalid PEM file length. The file ({0:?}) is not 3 lines long")] - InvalidPEMFormatLength(PathBuf), + #[error("Invalid PEM file length.")] + InvalidPEMFormatLength, #[error("Invalid PEM file header or footer: -----BEGIN or -----END")] InvalidPEMHeaderOrFooter, #[error("Invalid SSH key format")] @@ -62,7 +55,7 @@ pub enum Crypt4GHError { #[error("Decryption failed -> Invalid data: {0}")] InvalidData(String), - // Keys errors + // Key errors #[error("Unable to extract public server key")] BadServerPublicKey, #[error("Unable to extract private server key")] @@ -97,8 +90,8 @@ pub enum Crypt4GHError { ReadBlockError(Box), #[error("Error reading the remainder of the file (ERROR = {0:?})")] ReadRemainderError(Box), - #[error("Unable to read lines from {0:?} (ERROR = {1:?})")] - ReadLinesError(PathBuf, Box), + // #[error("Unable to read lines from {0:?} (ERROR = {1:?})")] + // ReadLinesError(PathBuf, Box), #[error("Unable to deserialize rounds from private key")] ReadRoundsError, #[error("Unable to extract public key")] @@ -115,10 +108,8 @@ pub enum Crypt4GHError { MagicStringError, #[error("Unsupported CRYPT4GH version (version = {0:?})")] InvalidCrypt4GHVersion(u32), - #[error("Empty public key at {0:?}")] - EmptyPublicKey(PathBuf), - #[error("Secret key not found: {0}")] - ReadSecretKeyFileError(PathBuf), + #[error("Empty public key")] + EmptyPublicKey, // Packets #[error("Unable to read packet encryption method")] @@ -169,10 +160,10 @@ pub enum Crypt4GHError { SliceConversionError, #[error("converting between numeric types")] NumericConversionError, - #[error("decoding header info: `{0}`")] - DecodingHeaderInfo(Crypt4GHError), - #[error("decoding header packet: `{0}`")] - DecodingHeaderPacket(Crypt4GHError), + #[error("Decoding header info error")] + DecodingHeaderInfo, + #[error("Decoding header packet error")] + DecodingHeaderPacket, #[error("join handle error: `{0}`")] JoinHandleError(task::JoinError), #[error("maximum header size exceeded")] @@ -181,25 +172,25 @@ pub enum Crypt4GHError { Crypt4GHError(String), } -impl From for Crypt4GHError { - fn from(error: io::Error) -> Self { - Self::IOError(error) - } -} - -impl From for Crypt4GHError { - fn from(error: dyn std::error::Error) -> Self { - if let std::error::Error::IOError(error) = error { - error - } else { - Self::new(io::ErrorKind::Other, error) - } - } -} - -impl From for Crypt4GHError { - fn from(error: Crypt4GHError) -> Self { - Self::Crypt4GHError(error.to_string()) - } -} +// impl From for Crypt4GHError { +// fn from(error: io::Error) -> Self { +// Self::IOError(error) +// } +// } + +// impl From for Crypt4GHError { +// fn from(error: dyn std::error::Error) -> Self { +// if let std::error::Error::IOError(error) = error { +// error +// } else { +// Self::new(io::ErrorKind::Other, error) +// } +// } +// } + +// impl From for Crypt4GHError { +// fn from(error: Crypt4GHError) -> Self { +// Self::Crypt4GHError(error.to_string()) +// } +//} diff --git a/src/reader/builder.rs b/src/reader/builder.rs index 95ddaaf..ebc9c35 100644 --- a/src/reader/builder.rs +++ b/src/reader/builder.rs @@ -1,12 +1,12 @@ use std::thread; +use crate::error::Crypt4GHError; use crate::keys::Keys; use futures_util::TryStreamExt; use tokio::io::{AsyncRead, AsyncSeek}; use crate::decrypter::builder::Builder as DecrypterBuilder; use crate::decrypter::DecrypterStream; -use crate::error::Result; use crate::keys::PublicKey; use super::Reader; @@ -74,7 +74,7 @@ impl Builder { } /// Build the reader and compute the stream length for seek operations. - pub async fn build_with_stream_length(self, inner: R, keys: Vec) -> Result> + pub async fn build_with_stream_length(self, inner: R, keys: Vec) -> Result, Crypt4GHError> where R: AsyncRead + AsyncSeek + Unpin, { diff --git a/src/reader/mod.rs b/src/reader/mod.rs index db60c0a..f374f9c 100644 --- a/src/reader/mod.rs +++ b/src/reader/mod.rs @@ -12,8 +12,7 @@ use pin_project_lite::pin_project; use tokio::io::{AsyncBufRead, AsyncRead, AsyncSeek, ReadBuf}; use crate::decoder::Block; -use crate::error::Crypt4GHError::NumericConversionError; -use crate::error::Result; +use crate::error::Crypt4GHError::{self, NumericConversionError}; use crate::reader::builder::Builder; use crate::{DecryptedDataBlock, header::EncryptedHeaderPacketBytes}; @@ -104,7 +103,7 @@ where } /// Poll the reader until the header has been read. - pub async fn read_header(&mut self) -> Result<()> + pub async fn read_header(&mut self) -> Result<(), Crypt4GHError> where R: Unpin, { @@ -229,7 +228,7 @@ mod tests { use tokio::io::AsyncReadExt; use crate::reader::builder::Builder; - use crate::PublicKey; + use crate::keys::PublicKey; #[tokio::test] async fn reader() { diff --git a/src/util/mod.rs b/src/util/mod.rs index 6d706ef..7e9c96a 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -3,7 +3,7 @@ use rustls::PrivateKey; use std::cmp::min; use crate::decoder::Block; -use crate::error::Result; +use crate::error::Crypt4GHError; use crate::keys::{KeyPair, PublicKey}; fn to_current_data_block(pos: u64, header_len: u64) -> u64 { @@ -89,9 +89,9 @@ pub fn unencrypted_clamp_next(pos: u64, encrypted_file_size: u64) -> u64 { } /// Generate a private and public key pair. -pub fn generate_key_pair() -> Result { +pub fn generate_key_pair() -> Result { // Todo, very janky, avoid writing this to a file first. - let temp_dir = TempDir::new().map_err(|err| Error::Crypt4GHError(err.to_string()))?; + //let temp_dir = TempDir::new().map_err(|err| Crypt4GHError::NoTempFiles(err.to_string()))?; let private_key = temp_dir.path().join("private_key"); let public_key = temp_dir.path().join("public_key"); From 0ecba8c83652afbb28f4cd049e767bc64eaf7457 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 12 Feb 2024 17:40:03 +1100 Subject: [PATCH 11/30] [ci skip] More cleanups before tackling other errors --- src/decoder/mod.rs | 1 - src/decrypter/builder.rs | 3 ++- src/decrypter/data_block.rs | 8 +++----- src/decrypter/header/mod.rs | 4 ++-- src/decrypter/mod.rs | 2 +- src/header.rs | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 8bfac3e..8ca17ff 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -253,7 +253,6 @@ pub(crate) mod tests { use crate::{body_decrypt, Keys, WriteInfo}; use futures_util::stream::Skip; use futures_util::StreamExt; - //use tokio::fs::File; use tokio::io::AsyncReadExt; use tokio_util::codec::FramedRead; use super::*; diff --git a/src/decrypter/builder.rs b/src/decrypter/builder.rs index b5c57a6..e68bb91 100644 --- a/src/decrypter/builder.rs +++ b/src/decrypter/builder.rs @@ -1,3 +1,4 @@ +use crate::error::Crypt4GHError; use crate::keys::Keys; use tokio::io::{AsyncRead, AsyncSeek}; use tokio_util::codec::FramedRead; @@ -78,7 +79,7 @@ impl Builder { self, inner: R, keys: Vec, - ) -> Result> + ) -> Result, Crypt4GHError> where R: AsyncRead + AsyncSeek + Unpin, { diff --git a/src/decrypter/data_block.rs b/src/decrypter/data_block.rs index b15e5b8..8cf066b 100644 --- a/src/decrypter/data_block.rs +++ b/src/decrypter/data_block.rs @@ -1,5 +1,5 @@ use std::future::Future; -use std::io::Cursor; +use std::io::{Cursor, Read}; use std::ops::Deref; use std::pin::Pin; use std::task::{Context, Poll}; @@ -133,16 +133,14 @@ impl DataBlockDecrypter { // Todo crypt4gh-rust body_decrypt_parts does not work properly, so just apply edit list here. body_decrypt(read_buf, session_keys.as_slice(), &mut write_info, 0) - .map_err(|err| Crypt4GHError::DecryptedDataBlock(err.to_string()))?; + .map_err(|err| Crypt4GHError::UnableToDecryptBlock(read_buf.into_inner(), err.to_string()))?; let mut decrypted_bytes: Bytes = write_buf.into_inner().into(); let mut edited_bytes = Bytes::new(); let edits = DecrypterStream::<()>::create_internal_edit_list(edit_list_packet) .unwrap_or(vec![(false, decrypted_bytes.len() as u64)]); if edits.iter().map(|(_, edit)| edit).sum::() > decrypted_bytes.len() as u64 { - return Err(Crypt4GHError::InvalidEditList( - "invalid edit lists for the decrypted data block".to_string(), - )); + return Err(Crypt4GHError::InvalidEditList); } edits.into_iter().for_each(|(discarding, edit)| { diff --git a/src/decrypter/header/mod.rs b/src/decrypter/header/mod.rs index 278825f..9f79dda 100644 --- a/src/decrypter/header/mod.rs +++ b/src/decrypter/header/mod.rs @@ -5,7 +5,7 @@ use std::task::{Context, Poll}; use tokio::io::AsyncRead; use crate::decrypter::DecrypterStream; -use crate::decrypter::Result; +use crate::error::Crypt4GHError; pub mod packets; @@ -33,7 +33,7 @@ impl<'a, R> Future for SessionKeysFuture<'a, R> where R: AsyncRead + Unpin, { - type Output = Result<()>; + type Output = Result<(), Crypt4GHError>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.handle.poll_session_keys_unpin(cx) diff --git a/src/decrypter/mod.rs b/src/decrypter/mod.rs index cc69938..79401f6 100644 --- a/src/decrypter/mod.rs +++ b/src/decrypter/mod.rs @@ -437,7 +437,7 @@ mod tests { } fn assert_edit_list( - stream: &mut DecrypterStream, + stream: &mut DecrypterStream, // FIXME: No files! expected: Option>, bytes: Vec, ) { diff --git a/src/header.rs b/src/header.rs index 98d9bff..75eb28f 100644 --- a/src/header.rs +++ b/src/header.rs @@ -371,7 +371,7 @@ pub fn deserialize_header_info( header_info: HeaderInfo, // TODO: HeaderInfo::len() ) -> Result { let header_info = - bincode::deserialize::(header_info.unwrap()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; + bincode::deserialize::(header_info).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; if &header_info.magic_number != MAGIC_NUMBER { return Err(Crypt4GHError::MagicStringError); From 07a90528287354c4e0ec9ac703fd3bf2e2fa8077 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 16 Feb 2024 11:21:07 +1100 Subject: [PATCH 12/30] Move in-file tests to tests/ to aid refactoring better (too high error count, tests re-factoring is a separate task to tackle later) [ci skip] --- src/decoder/mod.rs | 172 ------- src/decrypter/data_block.rs | 40 -- src/decrypter/header/packets.rs | 2 +- src/decrypter/mod.rs | 884 +------------------------------- src/edit_lists.rs | 99 +--- src/header.rs | 31 +- src/lib.rs | 4 +- src/reader/mod.rs | 523 +------------------ src/util/mod.rs | 88 +--- tests/test_data_block.rs | 40 ++ tests/test_decoder.rs | 171 ++++++ tests/test_decrypter.rs | 879 +++++++++++++++++++++++++++++++ tests/test_edit_list.rs | 195 ++++--- tests/test_header.rs | 21 + tests/test_reader.rs | 520 +++++++++++++++++++ tests/test_util.rs | 82 +++ 16 files changed, 1823 insertions(+), 1928 deletions(-) create mode 100644 tests/test_data_block.rs create mode 100644 tests/test_decoder.rs create mode 100644 tests/test_decrypter.rs create mode 100644 tests/test_header.rs create mode 100644 tests/test_reader.rs create mode 100644 tests/test_util.rs diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 8ca17ff..66435aa 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -69,7 +69,6 @@ impl Block { .try_into() .map_err(|_| SliceConversionError)?, ) - .map_err(DecodingHeaderInfo) } /// Parses the header info, updates the state and returns the block type. Unlike the other @@ -245,174 +244,3 @@ impl Decoder for Block { } } -#[cfg(test)] -pub(crate) mod tests { - use std::io::Cursor; - - use crate::header::{deconstruct_header_body, DecryptedHeaderPackets}; - use crate::{body_decrypt, Keys, WriteInfo}; - use futures_util::stream::Skip; - use futures_util::StreamExt; - use tokio::io::AsyncReadExt; - use tokio_util::codec::FramedRead; - use super::*; - - #[tokio::test] - async fn decode_header_info() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let mut reader = FramedRead::new(src, Block::default()); - - let header_info = reader.next().await.unwrap().unwrap(); - - // Assert that the first block output is a header info with one packet. - assert!( - matches!(header_info, DecodedBlock::HeaderInfo(header_info) if header_info.packets_count == 1) - ); - } - - #[tokio::test] - async fn decode_header_packets() { - let (recipient_private_key, sender_public_key, header_packet, _) = - get_first_header_packet().await; - let header = get_header_packets(recipient_private_key, sender_public_key, header_packet); - - assert_first_header_packet(header); - - // Todo handle case where there is more than one header packet. - } - - #[tokio::test] - async fn decode_data_block() { - let (header, data_block) = get_data_block(0).await; - - let read_buf = Cursor::new(data_block.to_vec()); - let mut write_buf = Cursor::new(vec![]); - let mut write_info = WriteInfo::new(0, None, &mut write_buf); - - body_decrypt(read_buf, &header.data_enc_packets, &mut write_info, 0).unwrap(); - - let decrypted_bytes = write_buf.into_inner(); - - assert_first_data_block(decrypted_bytes).await; - } - - #[tokio::test] - async fn decode_eof() { - let (header, data_block) = get_data_block(39).await; - - let read_buf = Cursor::new(data_block.to_vec()); - let mut write_buf = Cursor::new(vec![]); - let mut write_info = WriteInfo::new(0, None, &mut write_buf); - - body_decrypt(read_buf, &header.data_enc_packets, &mut write_info, 0).unwrap(); - - let decrypted_bytes = write_buf.into_inner(); - - assert_last_data_block(decrypted_bytes).await; - } - - /// Assert that the first header packet is a data encryption key packet. - pub(crate) fn assert_first_header_packet(header: DecryptedHeaderPackets) { - assert_eq!(header.data_enc_packets.len(), 1); - assert!(header.edit_list_packet.is_none()); - } - - /// Assert that the last data block is equal to the expected ending bytes of the original file. - pub(crate) async fn assert_last_data_block(decrypted_bytes: Vec) { - let mut original_file = get_test_file("bam/htsnexus_test_NA12878.bam").await; - let mut original_bytes = vec![]; - original_file - .read_to_end(&mut original_bytes) - .await - .unwrap(); - - assert_eq!( - decrypted_bytes, - original_bytes - .into_iter() - .rev() - .take(40895) - .rev() - .collect::>() - ); - } - - /// Assert that the first data block is equal to the first 64KiB of the original file. - pub(crate) async fn assert_first_data_block(decrypted_bytes: Vec) { - let original_bytes = get_original_file().await; - - assert_eq!(decrypted_bytes, original_bytes[..65536]); - } - - /// Get the first header packet from the test file. - pub(crate) async fn get_first_header_packet( - ) -> (Keys, Vec, Vec, Skip>) { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = FramedRead::new(src, Block::default()).skip(1); - - // The second block should contain a header packet. - let header_packets = reader.next().await.unwrap().unwrap(); - - let (header_packet, header_length) = - if let DecodedBlock::HeaderPackets(header_packets) = header_packets { - Some(header_packets) - } else { - None - } - .unwrap() - .into_inner(); - - assert_eq!(header_length, 108); - - ( - recipient_private_key, - sender_public_key, - header_packet - .into_iter() - .map(|packet| packet.into_header_bytes()) - .collect(), - reader, - ) - } - - /// Get the first data block from the test file. - pub(crate) async fn get_data_block(skip: usize) -> (DecryptedHeaderPackets, Bytes) { - let (recipient_private_key, sender_public_key, header_packets, reader) = - get_first_header_packet().await; - let header = get_header_packets(recipient_private_key, sender_public_key, header_packets); - - let data_block = reader.skip(skip).next().await.unwrap().unwrap(); - - let data_block = if let DecodedBlock::DataBlock(data_block) = data_block { - Some(data_block) - } else { - None - } - .unwrap(); - - (header, data_block) - } - - /// Get the header packets from a decoded block. - pub(crate) fn get_header_packets( - recipient_private_key: Keys, - sender_public_key: Vec, - header_packets: Vec, - ) -> DecryptedHeaderPackets { - // Assert the size of the header packet is correct. - assert_eq!(header_packets.len(), 1); - assert_eq!(header_packets.first().unwrap().len(), 104); - - deconstruct_header_body( - header_packets - .into_iter() - .map(|header_packet| header_packet.to_vec()) - .collect(), - &[recipient_private_key], - &Some(sender_public_key), - ) - .unwrap() - } -} diff --git a/src/decrypter/data_block.rs b/src/decrypter/data_block.rs index 8cf066b..204573f 100644 --- a/src/decrypter/data_block.rs +++ b/src/decrypter/data_block.rs @@ -167,43 +167,3 @@ impl Future for DataBlockDecrypter { } } -#[cfg(test)] -mod tests { - use crate::decoder::tests::{assert_first_data_block, get_data_block}; - //use crate::tests::get_original_file; - - use super::*; - - #[tokio::test] - async fn data_block_decrypter() { - let (header_packets, data_block) = get_data_block(0).await; - - let data = DataBlockDecrypter::new( - data_block, - header_packets.data_enc_packets, - header_packets.edit_list_packet, - ) - .await - .unwrap(); - - assert_first_data_block(data.bytes.to_vec()).await; - } - - #[tokio::test] - async fn data_block_decrypter_with_edit_list() { - let (header_packets, data_block) = get_data_block(0).await; - - let data = DataBlockDecrypter::new( - data_block, - header_packets.data_enc_packets, - Some(vec![0, 4668, 60868]), - ) - .await - .unwrap(); - - // FIXME: No "file" constructs in this crate! - //let original_bytes = get_original_file().await; - - //assert_eq!(data.bytes.to_vec(), original_bytes[..4668]); - } -} diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs index a89a0e0..2132b74 100644 --- a/src/decrypter/header/packets.rs +++ b/src/decrypter/header/packets.rs @@ -42,7 +42,7 @@ impl HeaderPacketsDecrypter { .into_iter() .map(|bytes| bytes.to_vec()) .collect(), - keys.as_slice(), +// keys.as_slice(), &sender_pubkey.map(|pubkey| pubkey.into_inner()), )?) } diff --git a/src/decrypter/mod.rs b/src/decrypter/mod.rs index 79401f6..3a51de4 100644 --- a/src/decrypter/mod.rs +++ b/src/decrypter/mod.rs @@ -18,7 +18,7 @@ use crate::decoder::DecodedBlock; use crate::decrypter::data_block::DataBlockDecrypter; use crate::decrypter::header::packets::HeaderPacketsDecrypter; use crate::decrypter::header::SessionKeysFuture; -use crate::error::Crypt4GHError::{self, Crypt4GHError}; +use crate::error::Crypt4GHError; use crate::{util, keys::PublicKey}; pub mod builder; @@ -404,884 +404,4 @@ where // Then do the seek. self.seek_encrypted(SeekFrom::Start(position)).await } -} - -// FIXME: Test suite highly dependent on fs and File(s), migrate to Bytes and/or Streams instead -#[cfg(test)] -mod tests { - use bytes::BytesMut; - use futures_util::future::join_all; - use futures_util::StreamExt; - // use tokio::fs::File; - - use crate::decoder::tests::assert_last_data_block; - use crate::decrypter::builder::Builder; - // use crate::tests::get_original_file; - - use super::*; - - #[tokio::test] - async fn partition_edit_lists() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_edit_list(vec![60113, 100000, 65536]) - .build(src, vec![recipient_private_key]); - - assert_edit_list(&mut stream, Some(vec![60113, 5423]), vec![0; 65564]); - assert_edit_list(&mut stream, Some(vec![0, 65536]), vec![0; 65564]); - assert_edit_list(&mut stream, Some(vec![0, 29041, 36495]), vec![0; 65564]); - assert_edit_list(&mut stream, Some(vec![29041]), vec![0; 29041 + 12 + 16]); - } - - fn assert_edit_list( - stream: &mut DecrypterStream, // FIXME: No files! - expected: Option>, - bytes: Vec, - ) { - let stream = Pin::new(stream); - let edit_list = stream.partition_edit_list(&Bytes::from(bytes)); - assert_eq!(edit_list, expected); - } - - #[tokio::test] - async fn decrypter_stream() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn get_header_length() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - assert!(stream.header_size().is_none()); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.header_size(), Some(124)); - } - - #[tokio::test] - async fn first_block_size() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - assert!(stream.current_block_size().is_none()); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.current_block_size(), Some(65564)); - } - - #[tokio::test] - async fn last_block_size() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - assert!(stream.current_block_size().is_none()); - - let mut stream = stream.skip(39); - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.get_ref().current_block_size(), Some(40923)); - } - - #[tokio::test] - async fn clamp_position_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.clamp_position(0), Some(124)); - assert_eq!(stream.clamp_position(124), Some(124)); - assert_eq!(stream.clamp_position(200), Some(124)); - } - - #[tokio::test] - async fn clamp_position_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.clamp_position(80000), Some(124 + 65564)); - } - - #[tokio::test] - async fn clamp_position_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.clamp_position(2598044), Some(2598043)); - } - - #[tokio::test] - async fn convert_position_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - let pos = stream.to_encrypted(0); - assert_eq!(pos, Some(124)); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); - - let pos = stream.to_encrypted(200); - assert_eq!(pos, Some(124 + 12 + 200)); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); - } - - #[tokio::test] - async fn convert_position_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - let pos = stream.to_encrypted(80000); - assert_eq!(pos, Some(124 + 65564 + 12 + (80000 - 65536))); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(124 + 65564)); - } - - #[tokio::test] - async fn convert_position_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - let _ = stream.next().await.unwrap().unwrap().await; - - let pos = stream.to_encrypted(2596800); - assert_eq!(pos, Some(2598043)); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(2598043)); - } - - #[tokio::test] - async fn seek_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::Start(80000)).await.unwrap(); - - assert_eq!(seek, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let seek = stream - .seek_encrypted(SeekFrom::Current(-20000)) - .await - .unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::End(-1000)).await.unwrap(); - - assert_eq!(seek, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let block = stream.next().await.unwrap().unwrap().await.unwrap(); - assert_last_data_block(block.bytes.to_vec()).await; - } - - #[tokio::test] - async fn seek_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn seek_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn advance_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(0).await.unwrap(); - - assert_eq!(advance, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(80000).await.unwrap(); - - assert_eq!(advance, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(2598042).await.unwrap(); - - assert_eq!(advance, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(2598044).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let advance = stream.advance_encrypted(2598044).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(0).await.unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_second_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(65537).await.unwrap(); - - assert_eq!(seek, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let seek = stream.seek_unencrypted(65535).await.unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(2596799).await.unwrap(); - - assert_eq!(seek, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let block = stream.next().await.unwrap().unwrap().await.unwrap(); - assert_last_data_block(block.bytes.to_vec()).await; - } - - #[tokio::test] - async fn seek_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(2596800).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn seek_past_end_stream_unencrypted_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let seek = stream.seek_unencrypted(2596800).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn advance_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(0).await.unwrap(); - - assert_eq!(advance, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_second_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(65537).await.unwrap(); - - assert_eq!(advance, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(2596799).await.unwrap(); - - assert_eq!(advance, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(2596800).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end_unencrypted_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let advance = stream.advance_unencrypted(2596800).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } -} +} \ No newline at end of file diff --git a/src/edit_lists.rs b/src/edit_lists.rs index bf4ca1d..dac6de5 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -239,101 +239,4 @@ where (header_info_bytes, encrypted_header_packets, edit_list_bytes).into(), )) } -} - -#[cfg(test)] -mod tests { - // use htsget_test::crypt4gh::{get_decryption_keys, get_encryption_keys}; - // use htsget_test::http_tests::get_test_file; - - use crate::reader::builder::Builder; - - use super::*; - - #[tokio::test] - async fn test_append_edit_list() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (private_key_decrypt, public_key_decrypt) = get_decryption_keys().await; - let (private_key_encrypt, public_key_encrypt) = get_encryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(public_key_decrypt.clone())) - .with_stream_length(5485112) - .build_with_reader(src, vec![private_key_decrypt.clone()]); - reader.read_header().await.unwrap(); - - let expected_data_packets = reader.session_keys().to_vec(); - - let header = EditHeader::new( - &reader, - test_unencrypted_positions(), - test_clamped_positions(), - PrivateKey(private_key_encrypt.clone().privkey), - PublicKey { - bytes: public_key_encrypt.clone(), - }, - ) - .edit_list() - .unwrap() - .unwrap(); - - let header_slice = header.as_slice(); - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(public_key_decrypt)) - .with_stream_length(5485112) - .build_with_reader(header_slice.as_slice(), vec![private_key_decrypt]); - reader.read_header().await.unwrap(); - - let data_packets = reader.session_keys(); - assert_eq!(data_packets, expected_data_packets); - - let edit_lists = reader.edit_list_packet().unwrap(); - assert_eq!(edit_lists, expected_edit_list()); - } - - #[tokio::test] - async fn test_create_edit_list() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (private_key_decrypt, public_key_decrypt) = get_decryption_keys().await; - let (private_key_encrypt, public_key_encrypt) = get_encryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(public_key_decrypt.clone())) - .with_stream_length(5485112) - .build_with_reader(src, vec![private_key_decrypt.clone()]); - reader.read_header().await.unwrap(); - - let edit_list = EditHeader::new( - &reader, - test_unencrypted_positions(), - test_clamped_positions(), - PrivateKey(private_key_encrypt.clone().privkey), - PublicKey { - bytes: public_key_encrypt.clone(), - }, - ) - .create_edit_list(); - - assert_eq!(edit_list, expected_edit_list()); - } - - fn test_unencrypted_positions() -> Vec { - vec![ - UnencryptedPosition::new(0, 7853), - UnencryptedPosition::new(145110, 453039), - UnencryptedPosition::new(5485074, 5485112), - ] - } - - fn test_clamped_positions() -> Vec { - vec![ - ClampedPosition::new(0, 65536), - ClampedPosition::new(131072, 458752), - ClampedPosition::new(5439488, 5485112), - ] - } - - fn expected_edit_list() -> Vec { - vec![0, 7853, 71721, 307929, 51299, 38] - } -} +} \ No newline at end of file diff --git a/src/header.rs b/src/header.rs index 75eb28f..01b4cc4 100644 --- a/src/header.rs +++ b/src/header.rs @@ -29,6 +29,7 @@ pub struct HeaderPackets { edit_list_packet: Option>, } +#[derive(Debug)] pub struct EncryptedHeaderPacketBytes { inner: Vec } @@ -366,12 +367,12 @@ pub fn deconstruct_header_body( /// Deserializes the data info from the header bytes. /// -/// Reads the magic number, the version and the number of packets from the bytes. +/// Reads the magic number, the version and the number of packets from the input bytes. pub fn deserialize_header_info( - header_info: HeaderInfo, // TODO: HeaderInfo::len() + header: Vec, ) -> Result { let header_info = - bincode::deserialize::(header_info).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; + bincode::deserialize::(header.as_slice()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; if &header_info.magic_number != MAGIC_NUMBER { return Err(Crypt4GHError::MagicStringError); @@ -510,26 +511,4 @@ pub fn rearrange<'a>( .collect::>, Crypt4GHError>>()?; Ok((final_packets, segment_oracle)) -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn enum_serialization_0() { - assert_eq!( - bincode::serialize(&HeaderPacketType::DataEnc).unwrap(), - 0_u32.to_le_bytes() - ); - } - - #[test] - fn enum_serialization_1() { - assert_eq!( - bincode::serialize(&HeaderPacketType::EditList).unwrap(), - 1_u32.to_le_bytes() - ); - } -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 11bee66..80ea337 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -426,7 +426,7 @@ impl<'a, W: Write> DecryptedBuffer<'a, W> { /// the first `range_start` bytes. It uses the `edit_list` packets. pub fn body_decrypt_parts( mut read_buffer: impl Read, - session_keys: Vec>, + session_keys: SessionKeys, output: WriteInfo, edit_list: Vec, ) -> Result<(), Crypt4GHError> { @@ -617,7 +617,7 @@ pub fn rearrange( read_buffer .read_exact(&mut temp_buf) .map_err(|e| Crypt4GHError::ReadHeaderError(e.into()))?; - let header_info: header::HeaderInfo = header::deserialize_header_info(&temp_buf)?; + let header_info: header::HeaderInfo = header::deserialize_header_info((&temp_buf).to_vec())?; // Calculate header packets let header_packets = (0..header_info.packets_count) diff --git a/src/reader/mod.rs b/src/reader/mod.rs index f374f9c..17d1c72 100644 --- a/src/reader/mod.rs +++ b/src/reader/mod.rs @@ -216,525 +216,4 @@ where Ok(position) } -} - -#[cfg(test)] -mod tests { - use std::io::SeekFrom; - - use futures_util::TryStreamExt; - use noodles::bam::AsyncReader; - use noodles::sam::Header; - use tokio::io::AsyncReadExt; - - use crate::reader::builder::Builder; - use crate::keys::PublicKey; - - #[tokio::test] - async fn reader() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let mut decrypted_bytes = vec![]; - reader.read_to_end(&mut decrypted_bytes).await.unwrap(); - - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn reader_with_noodles() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let mut reader = AsyncReader::new(reader); - - let original_file = get_test_file("bam/htsnexus_test_NA12878.bam").await; - let mut original_reader = AsyncReader::new(original_file); - - let header: Header = reader.read_header().await.unwrap().parse().unwrap(); - let reference_sequences = reader.read_reference_sequences().await.unwrap(); - - let original_header: Header = original_reader - .read_header() - .await - .unwrap() - .parse() - .unwrap(); - let original_reference_sequences = original_reader.read_reference_sequences().await.unwrap(); - - assert_eq!(header, original_header); - assert_eq!(reference_sequences, original_reference_sequences); - - let mut stream = original_reader.records(&original_header); - let mut original_records = vec![]; - while let Some(record) = stream.try_next().await.unwrap() { - original_records.push(record); - } - - let mut stream = reader.records(&header); - let mut records = vec![]; - while let Some(record) = stream.try_next().await.unwrap() { - records.push(record); - } - - assert_eq!(records, original_records); - } - - #[tokio::test] - async fn first_current_block_position() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the current block should not be known. - assert_eq!(reader.current_block_position(), None); - - // Read the first byte of the decrypted data. - let mut buf = [0u8; 1]; - reader.read_exact(&mut buf).await.unwrap(); - - // Now the current position should be at the end of the header. - assert_eq!(reader.current_block_position(), Some(124)); - } - - #[tokio::test] - async fn first_next_block_position() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the next block should not be known. - assert_eq!(reader.next_block_position(), None); - - // Read the first byte of the decrypted data. - let mut buf = [0u8; 1]; - reader.read_exact(&mut buf).await.unwrap(); - - // Now the next position should be at the second data block. - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn last_current_block_position() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the current block should not be known. - assert_eq!(reader.current_block_position(), None); - - // Read the whole file. - let mut decrypted_bytes = vec![]; - reader.read_to_end(&mut decrypted_bytes).await.unwrap(); - - // Now the current position should be at the last data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - } - - #[tokio::test] - async fn last_next_block_position() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the next block should not be known. - assert_eq!(reader.next_block_position(), None); - - // Read the whole file. - let mut decrypted_bytes = vec![]; - reader.read_to_end(&mut decrypted_bytes).await.unwrap(); - - // Now the next position should be the size of the file. - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(124)); - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn seek_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader - .seek_encrypted(SeekFrom::Start(2598042)) - .await - .unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader - .seek_encrypted(SeekFrom::Start(2598044)) - .await - .unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build_with_reader(src, vec![recipient_private_key]); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader - .seek_encrypted(SeekFrom::Start(2598044)) - .await - .unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_encrypted(0).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(124)); - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn advance_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_encrypted(2598042).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_encrypted(2598044).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build_with_reader(src, vec![recipient_private_key]); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_encrypted(2598044).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_unencrypted(0).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(124)); - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn seek_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_unencrypted(2596799).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_unencrypted(2596800).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_past_end_unencrypted_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build_with_reader(src, vec![recipient_private_key]); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_unencrypted(2596800).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_unencrypted(0).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(124)); - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn advance_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_unencrypted(2596799).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_unencrypted(2596800).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_past_end_unencrypted_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build_with_reader(src, vec![recipient_private_key]); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_unencrypted(2596800).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } -} +} \ No newline at end of file diff --git a/src/util/mod.rs b/src/util/mod.rs index 7e9c96a..6db5f6f 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -100,8 +100,7 @@ pub fn generate_key_pair() -> Result { public_key.clone(), Ok("".to_string()), None, - ) - .map_err(|err| Error::Crypt4GHError(err.to_string()))?; + ); let private_key = get_private_key(private_key, Ok("".to_string()))?; let public_key = get_public_key(public_key)?; @@ -110,87 +109,4 @@ pub fn generate_key_pair() -> Result { PrivateKey(private_key), PublicKey::new(public_key), )) -} - -#[cfg(test)] -mod tests { - use crate::util::{unencrypted_clamp, unencrypted_to_data_block, unencrypted_to_next_data_block}; - - use super::*; - - #[test] - fn test_to_encrypted() { - let pos = 80000; - let expected = 120 + 65536 + 12 + 16; - let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(100000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_to_encrypted_file_size() { - let pos = 110000; - let expected = 60148; - let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(60000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_to_encrypted_pos_greater_than_file_size() { - let pos = 110000; - let expected = 120 + 65536 + 12 + 16; - let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(100000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_next_data_block() { - let pos = 100000; - let expected = 120 + (65536 + 12 + 16) * 2; - let result = unencrypted_to_next_data_block(pos, 120, to_encrypted_file_size(150000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_next_data_block_file_size() { - let pos = 110000; - let expected = 100176; - let result = unencrypted_to_next_data_block(pos, 120, to_encrypted_file_size(100000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_unencrypted_clamp() { - let pos = 0; - let expected = 0; - let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - - let pos = 145110; - let expected = 131072; - let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - - let pos = 5485074; - let expected = 5439488; - let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - } - - #[test] - fn test_unencrypted_clamp_next() { - let pos = 7853; - let expected = 65536; - let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - - let pos = 453039; - let expected = 458752; - let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - - let pos = 5485112; - let expected = 5485112; - let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - } -} +} \ No newline at end of file diff --git a/tests/test_data_block.rs b/tests/test_data_block.rs new file mode 100644 index 0000000..1da3dd2 --- /dev/null +++ b/tests/test_data_block.rs @@ -0,0 +1,40 @@ +#[cfg(test)] +mod tests { + use crate::decoder::tests::{assert_first_data_block, get_data_block}; + //use crate::tests::get_original_file; + + use super::*; + + #[tokio::test] + async fn data_block_decrypter() { + let (header_packets, data_block) = get_data_block(0).await; + + let data = DataBlockDecrypter::new( + data_block, + header_packets.data_enc_packets, + header_packets.edit_list_packet, + ) + .await + .unwrap(); + + assert_first_data_block(data.bytes.to_vec()).await; + } + + #[tokio::test] + async fn data_block_decrypter_with_edit_list() { + let (header_packets, data_block) = get_data_block(0).await; + + let data = DataBlockDecrypter::new( + data_block, + header_packets.data_enc_packets, + Some(vec![0, 4668, 60868]), + ) + .await + .unwrap(); + + // FIXME: No "file" constructs in this crate! + //let original_bytes = get_original_file().await; + + //assert_eq!(data.bytes.to_vec(), original_bytes[..4668]); + } +} \ No newline at end of file diff --git a/tests/test_decoder.rs b/tests/test_decoder.rs new file mode 100644 index 0000000..b0c19a1 --- /dev/null +++ b/tests/test_decoder.rs @@ -0,0 +1,171 @@ +#[cfg(test)] +pub(crate) mod tests { + use std::io::Cursor; + + use crate::header::{deconstruct_header_body, DecryptedHeaderPackets}; + use crate::{body_decrypt, Keys, WriteInfo}; + use futures_util::stream::Skip; + use futures_util::StreamExt; + use tokio::io::AsyncReadExt; + use tokio_util::codec::FramedRead; + use super::*; + + #[tokio::test] + async fn decode_header_info() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let mut reader = FramedRead::new(src, Block::default()); + + let header_info = reader.next().await.unwrap().unwrap(); + + // Assert that the first block output is a header info with one packet. + assert!( + matches!(header_info, DecodedBlock::HeaderInfo(header_info) if header_info.packets_count == 1) + ); + } + + #[tokio::test] + async fn decode_header_packets() { + let (recipient_private_key, sender_public_key, header_packet, _) = + get_first_header_packet().await; + let header = get_header_packets(recipient_private_key, sender_public_key, header_packet); + + assert_first_header_packet(header); + + // Todo handle case where there is more than one header packet. + } + + #[tokio::test] + async fn decode_data_block() { + let (header, data_block) = get_data_block(0).await; + + let read_buf = Cursor::new(data_block.to_vec()); + let mut write_buf = Cursor::new(vec![]); + let mut write_info = WriteInfo::new(0, None, &mut write_buf); + + body_decrypt(read_buf, &header.data_enc_packets, &mut write_info, 0).unwrap(); + + let decrypted_bytes = write_buf.into_inner(); + + assert_first_data_block(decrypted_bytes).await; + } + + #[tokio::test] + async fn decode_eof() { + let (header, data_block) = get_data_block(39).await; + + let read_buf = Cursor::new(data_block.to_vec()); + let mut write_buf = Cursor::new(vec![]); + let mut write_info = WriteInfo::new(0, None, &mut write_buf); + + body_decrypt(read_buf, &header.data_enc_packets, &mut write_info, 0).unwrap(); + + let decrypted_bytes = write_buf.into_inner(); + + assert_last_data_block(decrypted_bytes).await; + } + + /// Assert that the first header packet is a data encryption key packet. + pub(crate) fn assert_first_header_packet(header: DecryptedHeaderPackets) { + assert_eq!(header.data_enc_packets.len(), 1); + assert!(header.edit_list_packet.is_none()); + } + + /// Assert that the last data block is equal to the expected ending bytes of the original file. + pub(crate) async fn assert_last_data_block(decrypted_bytes: Vec) { + let mut original_file = get_test_file("bam/htsnexus_test_NA12878.bam").await; + let mut original_bytes = vec![]; + original_file + .read_to_end(&mut original_bytes) + .await + .unwrap(); + + assert_eq!( + decrypted_bytes, + original_bytes + .into_iter() + .rev() + .take(40895) + .rev() + .collect::>() + ); + } + + /// Assert that the first data block is equal to the first 64KiB of the original file. + pub(crate) async fn assert_first_data_block(decrypted_bytes: Vec) { + let original_bytes = get_original_file().await; + + assert_eq!(decrypted_bytes, original_bytes[..65536]); + } + + /// Get the first header packet from the test file. + pub(crate) async fn get_first_header_packet( + ) -> (Keys, Vec, Vec, Skip>) { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = FramedRead::new(src, Block::default()).skip(1); + + // The second block should contain a header packet. + let header_packets = reader.next().await.unwrap().unwrap(); + + let (header_packet, header_length) = + if let DecodedBlock::HeaderPackets(header_packets) = header_packets { + Some(header_packets) + } else { + None + } + .unwrap() + .into_inner(); + + assert_eq!(header_length, 108); + + ( + recipient_private_key, + sender_public_key, + header_packet + .into_iter() + .map(|packet| packet.into_header_bytes()) + .collect(), + reader, + ) + } + + /// Get the first data block from the test file. + pub(crate) async fn get_data_block(skip: usize) -> (DecryptedHeaderPackets, Bytes) { + let (recipient_private_key, sender_public_key, header_packets, reader) = + get_first_header_packet().await; + let header = get_header_packets(recipient_private_key, sender_public_key, header_packets); + + let data_block = reader.skip(skip).next().await.unwrap().unwrap(); + + let data_block = if let DecodedBlock::DataBlock(data_block) = data_block { + Some(data_block) + } else { + None + } + .unwrap(); + + (header, data_block) + } + + /// Get the header packets from a decoded block. + pub(crate) fn get_header_packets( + recipient_private_key: Keys, + sender_public_key: Vec, + header_packets: Vec, + ) -> DecryptedHeaderPackets { + // Assert the size of the header packet is correct. + assert_eq!(header_packets.len(), 1); + assert_eq!(header_packets.first().unwrap().len(), 104); + + deconstruct_header_body( + header_packets + .into_iter() + .map(|header_packet| header_packet.to_vec()) + .collect(), + &[recipient_private_key], + &Some(sender_public_key), + ) + .unwrap() + } +} \ No newline at end of file diff --git a/tests/test_decrypter.rs b/tests/test_decrypter.rs new file mode 100644 index 0000000..f4e2d41 --- /dev/null +++ b/tests/test_decrypter.rs @@ -0,0 +1,879 @@ +// FIXME: Test suite highly dependent on fs and File(s), migrate to Bytes and/or Streams instead +#[cfg(test)] +mod tests { + use bytes::BytesMut; + use futures_util::future::join_all; + use futures_util::StreamExt; + // use tokio::fs::File; + + use crate::decoder::tests::assert_last_data_block; + use crate::decrypter::builder::Builder; + // use crate::tests::get_original_file; + + use super::*; + + #[tokio::test] + async fn partition_edit_lists() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_edit_list(vec![60113, 100000, 65536]) + .build(src, vec![recipient_private_key]); + + assert_edit_list(&mut stream, Some(vec![60113, 5423]), vec![0; 65564]); + assert_edit_list(&mut stream, Some(vec![0, 65536]), vec![0; 65564]); + assert_edit_list(&mut stream, Some(vec![0, 29041, 36495]), vec![0; 65564]); + assert_edit_list(&mut stream, Some(vec![29041]), vec![0; 29041 + 12 + 16]); + } + + fn assert_edit_list( + stream: &mut DecrypterStream, // FIXME: No files! + expected: Option>, + bytes: Vec, + ) { + let stream = Pin::new(stream); + let edit_list = stream.partition_edit_list(&Bytes::from(bytes)); + assert_eq!(edit_list, expected); + } + + #[tokio::test] + async fn decrypter_stream() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn get_header_length() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + assert!(stream.header_size().is_none()); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.header_size(), Some(124)); + } + + #[tokio::test] + async fn first_block_size() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + assert!(stream.current_block_size().is_none()); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.current_block_size(), Some(65564)); + } + + #[tokio::test] + async fn last_block_size() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + assert!(stream.current_block_size().is_none()); + + let mut stream = stream.skip(39); + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.get_ref().current_block_size(), Some(40923)); + } + + #[tokio::test] + async fn clamp_position_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.clamp_position(0), Some(124)); + assert_eq!(stream.clamp_position(124), Some(124)); + assert_eq!(stream.clamp_position(200), Some(124)); + } + + #[tokio::test] + async fn clamp_position_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.clamp_position(80000), Some(124 + 65564)); + } + + #[tokio::test] + async fn clamp_position_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + let _ = stream.next().await.unwrap().unwrap().await; + + assert_eq!(stream.clamp_position(2598044), Some(2598043)); + } + + #[tokio::test] + async fn convert_position_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + let pos = stream.to_encrypted(0); + assert_eq!(pos, Some(124)); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); + + let pos = stream.to_encrypted(200); + assert_eq!(pos, Some(124 + 12 + 200)); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); + } + + #[tokio::test] + async fn convert_position_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let _ = stream.next().await.unwrap().unwrap().await; + + let pos = stream.to_encrypted(80000); + assert_eq!(pos, Some(124 + 65564 + 12 + (80000 - 65536))); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(124 + 65564)); + } + + #[tokio::test] + async fn convert_position_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + let _ = stream.next().await.unwrap().unwrap().await; + + let pos = stream.to_encrypted(2596800); + assert_eq!(pos, Some(2598043)); + assert_eq!(stream.clamp_position(pos.unwrap()), Some(2598043)); + } + + #[tokio::test] + async fn seek_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::Start(80000)).await.unwrap(); + + assert_eq!(seek, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let seek = stream + .seek_encrypted(SeekFrom::Current(-20000)) + .await + .unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::End(-1000)).await.unwrap(); + + assert_eq!(seek, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let block = stream.next().await.unwrap().unwrap().await.unwrap(); + assert_last_data_block(block.bytes.to_vec()).await; + } + + #[tokio::test] + async fn seek_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn seek_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn advance_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(0).await.unwrap(); + + assert_eq!(advance, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_second_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(80000).await.unwrap(); + + assert_eq!(advance, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(2598042).await.unwrap(); + + assert_eq!(advance, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_encrypted(2598044).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let advance = stream.advance_encrypted(2598044).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(0).await.unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_second_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(65537).await.unwrap(); + + assert_eq!(seek, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let seek = stream.seek_unencrypted(65535).await.unwrap(); + + assert_eq!(seek, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn seek_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(2596799).await.unwrap(); + + assert_eq!(seek, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let block = stream.next().await.unwrap().unwrap().await.unwrap(); + assert_last_data_block(block.bytes.to_vec()).await; + } + + #[tokio::test] + async fn seek_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let seek = stream.seek_unencrypted(2596800).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn seek_past_end_stream_unencrypted_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let seek = stream.seek_unencrypted(2596800).await.unwrap(); + + assert_eq!(seek, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + assert!(stream.next().await.is_none()); + } + + #[tokio::test] + async fn advance_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(0).await.unwrap(); + + assert_eq!(advance, 124); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_second_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(65537).await.unwrap(); + + assert_eq!(advance, 124 + 65564); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(2596799).await.unwrap(); + + assert_eq!(advance, 2598043 - 40923); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let advance = stream.advance_unencrypted(2596800).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn advance_past_end_unencrypted_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut stream = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build(src, vec![recipient_private_key]); + + let advance = stream.advance_unencrypted(2596800).await.unwrap(); + + assert_eq!(advance, 2598043); + assert_eq!(stream.header_size(), Some(124)); + assert_eq!(stream.current_block_size(), None); + + let mut futures = vec![]; + while let Some(block) = stream.next().await { + futures.push(block.unwrap()); + } + + let decrypted_bytes = + join_all(futures) + .await + .into_iter() + .fold(BytesMut::new(), |mut acc, bytes| { + let (bytes, _) = bytes.unwrap().into_inner(); + acc.extend(bytes.0); + acc + }); + + // Assert that the decrypted bytes are equal to the original file bytes. + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } +} \ No newline at end of file diff --git a/tests/test_edit_list.rs b/tests/test_edit_list.rs index f0b536c..41f4fa5 100644 --- a/tests/test_edit_list.rs +++ b/tests/test_edit_list.rs @@ -1,99 +1,96 @@ -mod edit_list_gen; -mod test_common; - -use std::{fs::File, path::PathBuf}; - -pub use test_common::*; -use testresult::TestResult; -use crypt4gh::keys::get_private_key; -use crypt4gh::Keys; -use std::io::Read; - - -const INPUT_EDIT_LIST: &str = "Let's have - beers -in the sauna! - or -Dinner -at 7pm? -"; - -#[test] -fn test_send_message_buried() -> TestResult { - pretty_env_logger::init(); - - // Init - let init = Cleanup::new(); - - // Create input file - echo( - "Let's have beers in the sauna! or Dinner at 7pm?", - &temp_file("message.bob"), - ); - - // Bob encrypts a file for Alice, and tucks in an edit list. The skipped pieces are random data. - let mut file = File::create(&temp_file("message.bob.c4gh"))?; - edit_list_gen::generate( - &add_prefix(BOB_SECKEY), - &add_prefix(ALICE_PUBKEY), - INPUT_EDIT_LIST, - &mut file, - BOB_PASSPHRASE, - )?; - - let sender_pubkey = None; - let (range_start, range_span) = (0, None); - - let seckey = get_private_key(PathBuf::from("tests/testfiles/alice.sec"), Ok(ALICE_PASSPHRASE.to_string()))?; - - let keys = vec![Keys { - method: 0, - privkey: seckey, - recipient_pubkey: vec![], - }]; - - // log::debug!("run_decrypt()'s parameters: {:#?}, {}, {:#?}, {:#?}", &keys, range_start, range_span, &sender_pubkey ); - - let mut file = File::open(PathBuf::from("tests/tempfiles/message.bob.c4gh"))?; - - let mut out = vec![]; - file.read_to_end(&mut out)?; - - let mut buf_in = std::io::BufReader::new(&out[..]); - let mut buf = vec![]; - - // Decrypt - crypt4gh::decrypt( - &keys, - &mut buf_in, - &mut buf, - range_start, - range_span, - &sender_pubkey, - )?; - - // This CLI-only testing (integration tests) garble stdin/stdout which makes it very impractical to debug (with log::debug/log::info). - // - // CommandUnderTest::new() - // .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - // .arg("decrypt") - // .arg("--sk") - // .arg(ALICE_SECKEY) - // .pipe_in(&temp_file("message.bob.c4gh")) - // .pipe_out(&temp_file("message.alice")) - // .succeeds(); - - let mut bob = File::open(&temp_file("message.bob")).unwrap(); - let mut out_copy = vec![]; - bob.read_to_end(&mut out_copy)?; - assert_eq!(buf, out_copy); - - // Compare - // equal(&temp_file("message.bob"), &temp_file("message.alice")); - - // Cleanup - drop(init); - - // All went fine! - Ok(()) -} +#[cfg(test)] +mod tests { + // use htsget_test::crypt4gh::{get_decryption_keys, get_encryption_keys}; + // use htsget_test::http_tests::get_test_file; + + use crate::reader::builder::Builder; + + use super::*; + + #[tokio::test] + async fn test_append_edit_list() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (private_key_decrypt, public_key_decrypt) = get_decryption_keys().await; + let (private_key_encrypt, public_key_encrypt) = get_encryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(public_key_decrypt.clone())) + .with_stream_length(5485112) + .build_with_reader(src, vec![private_key_decrypt.clone()]); + reader.read_header().await.unwrap(); + + let expected_data_packets = reader.session_keys().to_vec(); + + let header = EditHeader::new( + &reader, + test_unencrypted_positions(), + test_clamped_positions(), + PrivateKey(private_key_encrypt.clone().privkey), + PublicKey { + bytes: public_key_encrypt.clone(), + }, + ) + .edit_list() + .unwrap() + .unwrap(); + + let header_slice = header.as_slice(); + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(public_key_decrypt)) + .with_stream_length(5485112) + .build_with_reader(header_slice.as_slice(), vec![private_key_decrypt]); + reader.read_header().await.unwrap(); + + let data_packets = reader.session_keys(); + assert_eq!(data_packets, expected_data_packets); + + let edit_lists = reader.edit_list_packet().unwrap(); + assert_eq!(edit_lists, expected_edit_list()); + } + + #[tokio::test] + async fn test_create_edit_list() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (private_key_decrypt, public_key_decrypt) = get_decryption_keys().await; + let (private_key_encrypt, public_key_encrypt) = get_encryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(public_key_decrypt.clone())) + .with_stream_length(5485112) + .build_with_reader(src, vec![private_key_decrypt.clone()]); + reader.read_header().await.unwrap(); + + let edit_list = EditHeader::new( + &reader, + test_unencrypted_positions(), + test_clamped_positions(), + PrivateKey(private_key_encrypt.clone().privkey), + PublicKey { + bytes: public_key_encrypt.clone(), + }, + ) + .create_edit_list(); + + assert_eq!(edit_list, expected_edit_list()); + } + + fn test_unencrypted_positions() -> Vec { + vec![ + UnencryptedPosition::new(0, 7853), + UnencryptedPosition::new(145110, 453039), + UnencryptedPosition::new(5485074, 5485112), + ] + } + + fn test_clamped_positions() -> Vec { + vec![ + ClampedPosition::new(0, 65536), + ClampedPosition::new(131072, 458752), + ClampedPosition::new(5439488, 5485112), + ] + } + + fn expected_edit_list() -> Vec { + vec![0, 7853, 71721, 307929, 51299, 38] + } +} \ No newline at end of file diff --git a/tests/test_header.rs b/tests/test_header.rs new file mode 100644 index 0000000..2e13195 --- /dev/null +++ b/tests/test_header.rs @@ -0,0 +1,21 @@ +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn enum_serialization_0() { + assert_eq!( + bincode::serialize(&HeaderPacketType::DataEnc).unwrap(), + 0_u32.to_le_bytes() + ); + } + + #[test] + fn enum_serialization_1() { + assert_eq!( + bincode::serialize(&HeaderPacketType::EditList).unwrap(), + 1_u32.to_le_bytes() + ); + } +} \ No newline at end of file diff --git a/tests/test_reader.rs b/tests/test_reader.rs new file mode 100644 index 0000000..0138be5 --- /dev/null +++ b/tests/test_reader.rs @@ -0,0 +1,520 @@ +#[cfg(test)] +mod tests { + use std::io::SeekFrom; + + use futures_util::TryStreamExt; + use noodles::bam::AsyncReader; + use noodles::sam::Header; + use tokio::io::AsyncReadExt; + + use crate::reader::builder::Builder; + use crate::keys::PublicKey; + + #[tokio::test] + async fn reader() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let mut decrypted_bytes = vec![]; + reader.read_to_end(&mut decrypted_bytes).await.unwrap(); + + let original_bytes = get_original_file().await; + assert_eq!(decrypted_bytes, original_bytes); + } + + #[tokio::test] + async fn reader_with_noodles() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + let mut reader = AsyncReader::new(reader); + + let original_file = get_test_file("bam/htsnexus_test_NA12878.bam").await; + let mut original_reader = AsyncReader::new(original_file); + + let header: Header = reader.read_header().await.unwrap().parse().unwrap(); + let reference_sequences = reader.read_reference_sequences().await.unwrap(); + + let original_header: Header = original_reader + .read_header() + .await + .unwrap() + .parse() + .unwrap(); + let original_reference_sequences = original_reader.read_reference_sequences().await.unwrap(); + + assert_eq!(header, original_header); + assert_eq!(reference_sequences, original_reference_sequences); + + let mut stream = original_reader.records(&original_header); + let mut original_records = vec![]; + while let Some(record) = stream.try_next().await.unwrap() { + original_records.push(record); + } + + let mut stream = reader.records(&header); + let mut records = vec![]; + while let Some(record) = stream.try_next().await.unwrap() { + records.push(record); + } + + assert_eq!(records, original_records); + } + + #[tokio::test] + async fn first_current_block_position() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the current block should not be known. + assert_eq!(reader.current_block_position(), None); + + // Read the first byte of the decrypted data. + let mut buf = [0u8; 1]; + reader.read_exact(&mut buf).await.unwrap(); + + // Now the current position should be at the end of the header. + assert_eq!(reader.current_block_position(), Some(124)); + } + + #[tokio::test] + async fn first_next_block_position() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the next block should not be known. + assert_eq!(reader.next_block_position(), None); + + // Read the first byte of the decrypted data. + let mut buf = [0u8; 1]; + reader.read_exact(&mut buf).await.unwrap(); + + // Now the next position should be at the second data block. + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn last_current_block_position() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the current block should not be known. + assert_eq!(reader.current_block_position(), None); + + // Read the whole file. + let mut decrypted_bytes = vec![]; + reader.read_to_end(&mut decrypted_bytes).await.unwrap(); + + // Now the current position should be at the last data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + } + + #[tokio::test] + async fn last_next_block_position() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the next block should not be known. + assert_eq!(reader.next_block_position(), None); + + // Read the whole file. + let mut decrypted_bytes = vec![]; + reader.read_to_end(&mut decrypted_bytes).await.unwrap(); + + // Now the next position should be the size of the file. + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(124)); + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn seek_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader + .seek_encrypted(SeekFrom::Start(2598042)) + .await + .unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader + .seek_encrypted(SeekFrom::Start(2598044)) + .await + .unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build_with_reader(src, vec![recipient_private_key]); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader + .seek_encrypted(SeekFrom::Start(2598044)) + .await + .unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_first_data_block() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_encrypted(0).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(124)); + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn advance_to_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_encrypted(2598042).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_past_end() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_encrypted(2598044).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_past_end_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build_with_reader(src, vec![recipient_private_key]); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_encrypted(2598044).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_unencrypted(0).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(124)); + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn seek_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_unencrypted(2596799).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_unencrypted(2596800).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn seek_past_end_unencrypted_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build_with_reader(src, vec![recipient_private_key]); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.seek_unencrypted(2596800).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_first_data_block_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_unencrypted(0).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(124)); + assert_eq!(reader.next_block_position(), Some(124 + 65564)); + } + + #[tokio::test] + async fn advance_to_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_unencrypted(2596799).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_past_end_unencrypted() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .build_with_stream_length(src, vec![recipient_private_key]) + .await + .unwrap(); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_unencrypted(2596800).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } + + #[tokio::test] + async fn advance_past_end_unencrypted_stream_length_override() { + let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; + let (recipient_private_key, sender_public_key) = get_decryption_keys().await; + + let mut reader = Builder::default() + .with_sender_pubkey(PublicKey::new(sender_public_key)) + .with_stream_length(2598043) + .build_with_reader(src, vec![recipient_private_key]); + + // Before anything is read the block positions should not be known. + assert_eq!(reader.current_block_position(), None); + assert_eq!(reader.next_block_position(), None); + + reader.advance_unencrypted(2596800).await.unwrap(); + + // Now the positions should be at the first data block. + assert_eq!(reader.current_block_position(), Some(2598043)); + assert_eq!(reader.next_block_position(), Some(2598043)); + } +} \ No newline at end of file diff --git a/tests/test_util.rs b/tests/test_util.rs new file mode 100644 index 0000000..ae30827 --- /dev/null +++ b/tests/test_util.rs @@ -0,0 +1,82 @@ +#[cfg(test)] +mod tests { + use crate::util::{unencrypted_clamp, unencrypted_to_data_block, unencrypted_to_next_data_block}; + + use super::*; + + #[test] + fn test_to_encrypted() { + let pos = 80000; + let expected = 120 + 65536 + 12 + 16; + let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(100000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_to_encrypted_file_size() { + let pos = 110000; + let expected = 60148; + let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(60000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_to_encrypted_pos_greater_than_file_size() { + let pos = 110000; + let expected = 120 + 65536 + 12 + 16; + let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(100000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_next_data_block() { + let pos = 100000; + let expected = 120 + (65536 + 12 + 16) * 2; + let result = unencrypted_to_next_data_block(pos, 120, to_encrypted_file_size(150000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_next_data_block_file_size() { + let pos = 110000; + let expected = 100176; + let result = unencrypted_to_next_data_block(pos, 120, to_encrypted_file_size(100000, 120)); + assert_eq!(result, expected); + } + + #[test] + fn test_unencrypted_clamp() { + let pos = 0; + let expected = 0; + let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + + let pos = 145110; + let expected = 131072; + let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + + let pos = 5485074; + let expected = 5439488; + let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + } + + #[test] + fn test_unencrypted_clamp_next() { + let pos = 7853; + let expected = 65536; + let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + + let pos = 453039; + let expected = 458752; + let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + + let pos = 5485112; + let expected = 5485112; + let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); + assert_eq!(result, expected); + } +} \ No newline at end of file From df36586da085c6d41a8d30dcac12f0b8af720898 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 16 Feb 2024 13:12:41 +1100 Subject: [PATCH 13/30] Add Marko and myself as co-authors in the crate --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4012b31..1265c45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -968,9 +968,9 @@ dependencies = [ [[package]] name = "noodles" -version = "0.63.0" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2212020b3faa067f38e4b5ecd558ff85a84f05d772882590d79cb772dadbbd1" +checksum = "4fa9a3104049a2a6b31b8b3cf414774832f28cc6fe3fb5fca21ed28e77c7f95f" dependencies = [ "noodles-bam", "noodles-bcf", @@ -986,9 +986,9 @@ dependencies = [ [[package]] name = "noodles-bam" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3980bc5cf6294d2ec132f8572d57b52f190e788ecd74a71b86ab81e6ce73afbb" +checksum = "d3189e8ecee801ab5c3f4ea9908c4196b429137d8d35d733f00f6681f9188be7" dependencies = [ "bit-vec", "bstr", @@ -1043,9 +1043,9 @@ checksum = "7336c3be652de4e05444c9b12a32331beb5ba3316e8872d92bfdd8ef3b06c282" [[package]] name = "noodles-cram" -version = "0.54.0" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ec9e47cd63c93a1aa9354e7372f1e815bb4ff332048784c8a76af9baa08e613" +checksum = "79515cee0bc37187bd3baf02f2dc02db5ad91b006b7856ce1417053d69168924" dependencies = [ "async-compression", "bitflags 2.3.2", @@ -1106,9 +1106,9 @@ dependencies = [ [[package]] name = "noodles-sam" -version = "0.52.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b778d5136a0d7659e2e1950df586e0fe18ec793bf44e8a4123417af39ba062" +checksum = "1f0d8e441368374f6e144989f823fd7c05e58cdaa3f97d22bb4d75b534327b87" dependencies = [ "bitflags 2.3.2", "bstr", diff --git a/Cargo.toml b/Cargo.toml index 222d221..0cff51c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "crypt4gh" version = "0.4.1" -authors = ["Roberto "] +authors = ["Roberto ", "Marko Malenic ", "Roman Valls Guimera "] edition = "2021" license = "Apache-2.0" description = "Encryption and decryption implementation of the Crypt4GH encryption format." @@ -55,9 +55,9 @@ futures-util = "0.3.30" [dev-dependencies] testresult = "0.3" -noodles-bam = "0.55" -noodles-sam = "0.52" -noodles = { version = "0.63", features = [ "sam", "bam", "async" ] } +noodles-bam = "0.56" +noodles-sam = "0.53" +noodles = { version = "0.64", features = [ "sam", "bam", "async" ] } [profile.release] lto = true From 274718523f578af745c04f56f5b427d96e3be1ed Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 16 Feb 2024 13:13:03 +1100 Subject: [PATCH 14/30] Move header packets test away to tests/ --- tests/test_header_packets.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/test_header_packets.rs diff --git a/tests/test_header_packets.rs b/tests/test_header_packets.rs new file mode 100644 index 0000000..e69de29 From 1e0d351ed2ffe0d00141d77121fc470eddccf21a Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 16 Feb 2024 13:15:29 +1100 Subject: [PATCH 15/30] Remove specific rustls::PrivateKey which doesn't seem to be exposed in the root module (as of 0.22?). Several small fixes, renaming of decrypt to decrypt_header, remove advance-related functionality that will go away anyway in DecrypterStream --- src/decoder/mod.rs | 2 +- src/decrypter/data_block.rs | 2 +- src/decrypter/header/packets.rs | 35 +++----------- src/decrypter/mod.rs | 85 +++++++++++++++++---------------- src/edit_lists.rs | 2 +- src/header.rs | 4 +- src/keys.rs | 44 ++++------------- src/lib.rs | 14 +++--- src/util/mod.rs | 2 - 9 files changed, 69 insertions(+), 121 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 66435aa..3ee0fd0 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -5,7 +5,7 @@ use crate::header::{deserialize_header_info, HeaderInfo}; use tokio_util::codec::Decoder; use crate::error::Crypt4GHError::{ - self, DecodingHeaderInfo, MaximumHeaderSize, NumericConversionError, SliceConversionError + self, MaximumHeaderSize, NumericConversionError, SliceConversionError }; use crate::header::EncryptedHeaderPackets; diff --git a/src/decrypter/data_block.rs b/src/decrypter/data_block.rs index 204573f..bf289ef 100644 --- a/src/decrypter/data_block.rs +++ b/src/decrypter/data_block.rs @@ -1,5 +1,5 @@ use std::future::Future; -use std::io::{Cursor, Read}; +use std::io::Cursor; use std::ops::Deref; use std::pin::Pin; use std::task::{Context, Poll}; diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs index 2132b74..870ece6 100644 --- a/src/decrypter/header/packets.rs +++ b/src/decrypter/header/packets.rs @@ -32,7 +32,7 @@ impl HeaderPacketsDecrypter { } } - pub fn decrypt( + pub fn decrypt_header( header_packets: Vec, keys: Vec, sender_pubkey: Option, @@ -41,10 +41,10 @@ impl HeaderPacketsDecrypter { header_packets .into_iter() .map(|bytes| bytes.to_vec()) - .collect(), -// keys.as_slice(), - &sender_pubkey.map(|pubkey| pubkey.into_inner()), - )?) + .collect()?)? + // keys.as_slice(), + // &sender_pubkey.map(|pubkey| pubkey.into_inner()), + ) } } @@ -54,27 +54,4 @@ impl Future for HeaderPacketsDecrypter { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.project().handle.poll(cx).map_err(JoinHandleError)? } -} - -#[cfg(test)] -mod tests { - use crate::decoder::tests::{assert_first_header_packet, get_first_header_packet}; - - use super::*; - - #[tokio::test] - async fn header_packet_decrypter() { - let (recipient_private_key, sender_public_key, header_packets, _) = - get_first_header_packet().await; - - let data = HeaderPacketsDecrypter::new( - header_packets, - vec![recipient_private_key], - Some(PublicKey::new(sender_public_key)), - ) - .await - .unwrap(); - - assert_first_header_packet(data); - } -} +} \ No newline at end of file diff --git a/src/decrypter/mod.rs b/src/decrypter/mod.rs index 3a51de4..284a8a9 100644 --- a/src/decrypter/mod.rs +++ b/src/decrypter/mod.rs @@ -1,5 +1,8 @@ +pub mod builder; +pub mod data_block; +pub mod header; + use std::cmp::min; -use std::io; use std::io::SeekFrom; use std::pin::Pin; use std::task::{Context, Poll}; @@ -21,9 +24,7 @@ use crate::decrypter::header::SessionKeysFuture; use crate::error::Crypt4GHError; use crate::{util, keys::PublicKey}; -pub mod builder; -pub mod data_block; -pub mod header; +use futures::Future; pin_project! { /// A decrypter for an entire AsyncRead Crypt4GH file. @@ -175,9 +176,9 @@ where cx.waker().wake_by_ref(); Poll::Pending } - DecodedBlock::DataBlock(_) => Poll::Ready(Err(Crypt4GHError( + DecodedBlock::DataBlock(_) => Poll::Ready(Crypt4GHError::UnableToDecryptBlock(buf, "data block reached without finding session keys".to_string(), - ))), + )), }, Some(Err(e)) => Poll::Ready(Err(e)), None => Poll::Ready(Err(Crypt4GHError( @@ -369,39 +370,39 @@ where } } -impl DecrypterStream -where - R: AsyncRead + AsyncSeek + Unpin + Send, -{ - /// Seek to a position in the encrypted stream. - pub async fn seek_encrypted(&mut self, position: SeekFrom) -> io::Result { - // Make sure that session keys are polled. - self.read_header().await?; - - // First poll to the position specified. - let seek = self.inner.get_mut().seek(position).await?; - - // Then advance to the correct data block position. - let advance = self.advance_encrypted(seek).await?; - - // Then seek to the correct position. - let seek = self.inner.get_mut().seek(SeekFrom::Start(advance)).await?; - self.inner.read_buffer_mut().clear(); - - Ok(seek) - } - - /// Seek to a position in the unencrypted stream. - pub async fn seek_unencrypted(&mut self, position: u64) -> io::Result { - // Make sure that session keys are polled. - self.read_header().await?; - - // Convert to an encrypted position and seek - let position = self - .to_encrypted(position) - .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; - - // Then do the seek. - self.seek_encrypted(SeekFrom::Start(position)).await - } -} \ No newline at end of file +// impl DecrypterStream +// where +// R: AsyncRead + AsyncSeek + Unpin + Send, +// { +// /// Seek to a position in the encrypted stream. +// pub async fn seek_encrypted(&mut self, position: SeekFrom) -> io::Result { +// // Make sure that session keys are polled. +// self.read_header().await?; + +// // First poll to the position specified. +// let seek = self.inner.get_mut().seek(position).await?; + +// // Then advance to the correct data block position. +// let advance = self.advance_encrypted(seek).await?; + +// // Then seek to the correct position. +// let seek = self.inner.get_mut().seek(SeekFrom::Start(advance)).await?; +// self.inner.read_buffer_mut().clear(); + +// Ok(seek) +// } + +// /// Seek to a position in the unencrypted stream. +// pub async fn seek_unencrypted(&mut self, position: u64) -> io::Result { +// // Make sure that session keys are polled. +// self.read_header().await?; + +// // Convert to an encrypted position and seek +// let position = self +// .to_encrypted(position) +// .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; + +// // Then do the seek. +// self.seek_encrypted(SeekFrom::Start(position)).await +// } +// } \ No newline at end of file diff --git a/src/edit_lists.rs b/src/edit_lists.rs index dac6de5..e20bae8 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use crate::header::{encrypt, make_packet_data_edit_list, HeaderInfo}; use crate::keys::Keys; -use rustls::PrivateKey; +use crate::keys::PrivateKey; use tokio::io::AsyncRead; use crate::error::Crypt4GHError; diff --git a/src/header.rs b/src/header.rs index 01b4cc4..e9c8bc9 100644 --- a/src/header.rs +++ b/src/header.rs @@ -29,7 +29,7 @@ pub struct HeaderPackets { edit_list_packet: Option>, } -#[derive(Debug)] +#[derive(Debug, Default, Clone)] pub struct EncryptedHeaderPacketBytes { inner: Vec } @@ -369,7 +369,7 @@ pub fn deconstruct_header_body( /// /// Reads the magic number, the version and the number of packets from the input bytes. pub fn deserialize_header_info( - header: Vec, + header: Vec ) -> Result { let header_info = bincode::deserialize::(header.as_slice()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; diff --git a/src/keys.rs b/src/keys.rs index fd5d54f..7bbc171 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -1,43 +1,9 @@ #![warn(missing_docs)] #![warn(rustdoc::missing_doc_code_examples)] -//use rustls::PrivateKey; - -use std::collections::HashMap; -use std::io::Read; - -use lazy_static::lazy_static; - const C4GH_MAGIC_WORD: &[u8; 7] = b"c4gh-v1"; const SSH_MAGIC_WORD: &[u8; 15] = b"openssh-key-v1\x00"; -lazy_static! { - static ref KDFS: HashMap<&'static str, (usize, u32)> = [ - ("scrypt", (16, 0)), - ("bcrypt", (16, 100)), - ("pbkdf2_hmac_sha256", (16, 100_000)), - ] - .iter() - .copied() - .collect(); -} - -lazy_static! { - static ref CIPHER_INFO: HashMap<&'static str, (u64, u64)> = [ - ("aes128-ctr", (16, 16)), - ("aes192-ctr", (16, 24)), - ("aes256-ctr", (16, 32)), - ("aes128-cbc", (16, 16)), - ("aes192-cbc", (16, 24)), - ("aes256-cbc", (16, 32)), - ("3des-cbc", ( 8, 24)), - //("blowfish-cbc", (8, 16)), - ] - .iter() - .copied() - .collect(); -} - #[derive(Debug, PartialEq, Eq, Hash, Clone)] /// Key information. pub struct Keys { @@ -51,13 +17,19 @@ pub struct Keys { } pub struct SessionKeys { - inner: Vec> + pub inner: Vec> +} + +/// Private keys are just bytes since it should support disparate formats, i.e: SSH and GA4GH +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PrivateKey { + pub bytes: Vec, } /// A wrapper around a vec of bytes that represent a public key. #[derive(Debug, Clone, PartialEq, Eq)] pub struct PublicKey { - bytes: Vec, + pub bytes: Vec, } /// A key pair containing a public and private key. diff --git a/src/lib.rs b/src/lib.rs index 80ea337..15d2969 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -256,7 +256,7 @@ pub fn decrypt( let mut write_info = WriteInfo::new(0, None, &mut write_buf); // Todo crypt4gh-rust body_decrypt_parts does not work properly, so just apply edit list here. - body_decrypt(read_buf, session_keys.as_slice(), &mut write_info, 0) + body_decrypt(read_buf, session_keys, &mut write_info, 0) .map_err(|err| Crypt4GHError::UnableToDecryptBlock(read_buf, err.to_string()))?; let mut decrypted_bytes: Bytes = write_buf.into_inner().into(); let mut edited_bytes = Bytes::new(); @@ -295,7 +295,7 @@ struct DecryptedBuffer<'a, W: Write> { } impl<'a, W: Write> DecryptedBuffer<'a, W> { - fn new(read_buffer: &'a mut impl Read, session_keys: keys::SessionKeys, output: WriteInfo<'a, W>) -> Result { + fn new(read_buffer: &'a mut impl Read, session_keys: SessionKeys, output: WriteInfo<'a, W>) -> Result { let mut decryptor = Self { read_buffer, session_keys, @@ -337,7 +337,7 @@ impl<'a, W: Write> DecryptedBuffer<'a, W> { // Decrypts its buffer if !self.is_decrypted { log::debug!("Decrypting block({:?}): {:?}", self.buf.len(), &self.buf); - self.buf = decrypt_block(&self.buf, &self.session_keys)?; + self.buf = decrypt_block(&self.buf, self.session_keys)?; self.is_decrypted = true; } Ok(()) @@ -477,7 +477,7 @@ pub fn body_decrypt_parts( /// the first `range_start` bytes. pub fn body_decrypt( mut read_buffer: impl Read, - session_keys: &[Vec], + session_keys: SessionKeys, output: &mut WriteInfo, range_start: usize, ) -> Result<(), Crypt4GHError> { @@ -517,14 +517,14 @@ pub fn body_decrypt( } /// Reads and returns the first successfully decrypted block, iterating through all the session keys against one ciphersegment. -fn decrypt_block(ciphersegment: &[u8], session_keys: &[Vec]) -> Result, Crypt4GHError> { +fn decrypt_block(ciphersegment: &[u8], session_keys: SessionKeys) -> Result, Crypt4GHError> { //log::debug!("Decrypt_block()'s the cyphersegment is: {:#?}", ciphersegment); let (nonce_slice, data) = ciphersegment.split_at(12); let nonce_bytes: [u8; 12] = nonce_slice .try_into() .map_err(|_| Crypt4GHError::UnableToWrapNonce)?; - session_keys.iter() + session_keys.inner.iter() .find_map(|key| { let key = Key::from_slice(&key); let key = chacha20poly1305::ChaCha20Poly1305::new(&key); @@ -555,7 +555,7 @@ pub fn reencrypt( read_buffer .read_exact(&mut temp_buf) .map_err(|e| Crypt4GHError::ReadHeaderError(e.into()))?; - let header_info: header::HeaderInfo = header::deserialize_header_info(&temp_buf)?; + let header_info: header::HeaderInfo = header::deserialize_header_info((&temp_buf).to_vec())?; // Calculate header packets let header_packets = (0..header_info.packets_count) diff --git a/src/util/mod.rs b/src/util/mod.rs index 6db5f6f..b07d191 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,5 +1,3 @@ -//use crate::keys::{generate_keys, get_private_key, get_public_key}; -use rustls::PrivateKey; use std::cmp::min; use crate::decoder::Block; From 6222a75983b097095ac21a42653462190d4b2910 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 16 Feb 2024 14:43:43 +1100 Subject: [PATCH 16/30] Keys is not KeyPairInfo, many minor fixes (and more expected breakage since rearrange and reencrypt no longer take buffers as arguments :P) --- src/decoder/mod.rs | 8 ++-- src/decrypter/builder.rs | 6 +-- src/decrypter/header/packets.rs | 17 ++++----- src/decrypter/mod.rs | 10 ++--- src/edit_lists.rs | 4 +- src/error.rs | 4 +- src/header.rs | 66 +++++++++++++++++++++++++-------- src/keys.rs | 36 +++++++++++++++++- src/lib.rs | 21 +++++------ src/reader/builder.rs | 6 +-- src/reader/mod.rs | 4 +- src/util/mod.rs | 22 ----------- 12 files changed, 123 insertions(+), 81 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 3ee0fd0..1a11803 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1,7 +1,7 @@ use std::io; use bytes::{Bytes, BytesMut}; -use crate::header::{deserialize_header_info, HeaderInfo}; +use crate::header::{deserialize_header_info, EncryptedHeaderPacketBytes, HeaderInfo}; use tokio_util::codec::Decoder; use crate::error::Crypt4GHError::{ @@ -68,6 +68,8 @@ impl Block { .as_ref() .try_into() .map_err(|_| SliceConversionError)?, + None, + None ) } @@ -129,7 +131,7 @@ impl Block { return Ok(None); } - header_packet_bytes.push(EncryptedHeaderPackets::new( + header_packet_bytes.push(EncryptedHeaderPacketBytes::new( length_bytes, src.split_to(length).freeze(), )); @@ -232,7 +234,7 @@ impl Decoder for Block { Ok(Some(DecodedBlock::DataBlock(buf.split().freeze()))) } else { - Err(Crypt4GHError::UnableToDecryptBlock(self.next_block, + Err(Crypt4GHError::UnableToDecryptBlock(buf.to_vec(), "the last data block is too large".to_string(), )) } diff --git a/src/decrypter/builder.rs b/src/decrypter/builder.rs index e68bb91..8d15686 100644 --- a/src/decrypter/builder.rs +++ b/src/decrypter/builder.rs @@ -1,5 +1,5 @@ use crate::error::Crypt4GHError; -use crate::keys::Keys; +use crate::keys::{KeyPair, KeyPairInfo}; use tokio::io::{AsyncRead, AsyncSeek}; use tokio_util::codec::FramedRead; @@ -49,7 +49,7 @@ impl Builder { } /// Build the decrypter. - pub fn build(self, inner: R, keys: Vec) -> DecrypterStream + pub fn build(self, inner: R, keys: Vec) -> DecrypterStream where R: AsyncRead, { @@ -78,7 +78,7 @@ impl Builder { pub async fn build_with_stream_length( self, inner: R, - keys: Vec, + keys: Vec, ) -> Result, Crypt4GHError> where R: AsyncRead + AsyncSeek + Unpin, diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs index 870ece6..5e545dc 100644 --- a/src/decrypter/header/packets.rs +++ b/src/decrypter/header/packets.rs @@ -4,12 +4,11 @@ use std::task::{Context, Poll}; use bytes::Bytes; use crate::header::{deserialize_header_info, DecryptedHeaderPackets}; -use crate::Keys; use pin_project_lite::pin_project; use tokio::task::{spawn_blocking, JoinHandle}; use crate::error::Crypt4GHError::{self, JoinHandleError}; -use crate::keys::PublicKey; +use crate::keys::{KeyPairInfo, PublicKey}; pin_project! { #[must_use = "futures do nothing unless you `.await` or poll them"] @@ -22,7 +21,7 @@ pin_project! { impl HeaderPacketsDecrypter { pub fn new( header_packets: Vec, - keys: Vec, + keys: Vec, sender_pubkey: Option, ) -> Self { Self { @@ -32,19 +31,19 @@ impl HeaderPacketsDecrypter { } } - pub fn decrypt_header( + pub fn decrypt( header_packets: Vec, - keys: Vec, + keys: Vec, sender_pubkey: Option, ) -> Result { Ok(deserialize_header_info( header_packets .into_iter() .map(|bytes| bytes.to_vec()) - .collect()?)? - // keys.as_slice(), - // &sender_pubkey.map(|pubkey| pubkey.into_inner()), - ) + .collect(), + keys.as_slice(), + &sender_pubkey.map(|pubkey| pubkey.into_inner()) + )) } } diff --git a/src/decrypter/mod.rs b/src/decrypter/mod.rs index 284a8a9..4369fec 100644 --- a/src/decrypter/mod.rs +++ b/src/decrypter/mod.rs @@ -9,7 +9,7 @@ use std::task::{Context, Poll}; use bytes::Bytes; use crate::header::{EncryptedHeaderPacketBytes, HeaderInfo}; -use crate::Keys; +use crate::keys::{KeyPair, KeyPairInfo}; use futures::ready; use futures::Stream; use pin_project_lite::pin_project; @@ -33,7 +33,7 @@ pin_project! { inner: FramedRead, #[pin] header_packet_future: Option, - keys: Vec, + keys: Vec, sender_pubkey: Option, encrypted_header_packets: Option>, header_info: Option, @@ -181,9 +181,9 @@ where )), }, Some(Err(e)) => Poll::Ready(Err(e)), - None => Poll::Ready(Err(Crypt4GHError( + None => Poll::Ready(Crypt4GHError::EndOfStreamReached( "end of stream reached without finding session keys".to_string(), - ))), + )), } } @@ -298,7 +298,7 @@ impl DecrypterStream { } /// Get the stream's keys. - pub fn keys(&self) -> &[Keys] { + pub fn keys(&self) -> &[KeyPairInfo] { self.keys.as_slice() } diff --git a/src/edit_lists.rs b/src/edit_lists.rs index e20bae8..6daa8ae 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use crate::header::{encrypt, make_packet_data_edit_list, HeaderInfo}; -use crate::keys::Keys; +use crate::keys::KeyPairInfo; use crate::keys::PrivateKey; use tokio::io::AsyncRead; @@ -125,7 +125,7 @@ where /// Encrypt the edit list packet. pub fn encrypt_edit_list(&self, edit_list_packet: Vec) -> Result, Crypt4GHError> { - let keys = Keys { + let keys = KeyPairInfo { method: 0, privkey: self.private_key.clone().0, recipient_pubkey: self.recipient_public_key.clone().into_inner(), diff --git a/src/error.rs b/src/error.rs index 6131d8c..6715363 100644 --- a/src/error.rs +++ b/src/error.rs @@ -90,8 +90,6 @@ pub enum Crypt4GHError { ReadBlockError(Box), #[error("Error reading the remainder of the file (ERROR = {0:?})")] ReadRemainderError(Box), - // #[error("Unable to read lines from {0:?} (ERROR = {1:?})")] - // ReadLinesError(PathBuf, Box), #[error("Unable to deserialize rounds from private key")] ReadRoundsError, #[error("Unable to extract public key")] @@ -154,6 +152,8 @@ pub enum Crypt4GHError { // IO #[error("IO failed")] IoError(#[from] std::io::Error), + #[error("End of stream: {0:?}")] + EndOfStreamReached(String), // Conversion and decoding #[error("converting slice to fixed size array")] diff --git a/src/header.rs b/src/header.rs index e9c8bc9..e8dd947 100644 --- a/src/header.rs +++ b/src/header.rs @@ -1,20 +1,20 @@ use std::collections::HashSet; +use std::io::Read; +use bytes::Bytes; use aead::consts::U32; use aead::generic_array::GenericArray; - use chacha20poly1305::aead::Aead; use chacha20poly1305::aead::OsRng; use chacha20poly1305::{self, aead, ChaCha20Poly1305, KeyInit, AeadCore}; +use crypto_kx::{SecretKey, PublicKey, Keypair}; -//use itertools::Itertools; use serde::{Deserialize, Serialize}; -use crypto_kx::{SecretKey, PublicKey, Keypair}; -use crate::Keys; - use super::SEGMENT_SIZE; use crate::error::Crypt4GHError; +use crate::keys::KeyPair; +use crate::keys::KeyPairInfo; const MAGIC_NUMBER: &[u8; 8] = b"crypt4gh"; const VERSION: u32 = 1; @@ -31,7 +31,8 @@ pub struct HeaderPackets { #[derive(Debug, Default, Clone)] pub struct EncryptedHeaderPacketBytes { - inner: Vec + pub packet_length: Bytes, + pub header: Bytes } /// Represents the encrypted header packet data, and the total size of all the header packets. @@ -66,6 +67,37 @@ impl EncryptedHeaderPackets { } } +/// Represents the bytes inside the `EncryptedHeaderPackets` +impl EncryptedHeaderPacketBytes { + /// Create header packet bytes. + pub fn new(packet_length: Bytes, header: Bytes) -> Self { + Self { + packet_length, + header, + } + } + + /// Get packet length bytes. + pub fn packet_length(&self) -> &Bytes { + &self.packet_length + } + + /// Get header bytes. + pub fn header(&self) -> &Bytes { + &self.header + } + + /// Get the owned packet length and header bytes. + pub fn into_inner(self) -> (Bytes, Bytes) { + (self.packet_length, self.header) + } + + /// Get the header bytes only. + pub fn into_header_bytes(self) -> Bytes { + self.header + } +} + /// Contains the parsed data of the packets pub struct DecryptedHeaderPackets { /// The packets that are coded as data @@ -161,7 +193,7 @@ fn encrypt_x25519_chacha20_poly1305( /// /// * `packet` is a vector of bytes of information to be encrypted /// * `keys` is a unique collection of keys with `key.method` == 0 -pub fn encrypt(packet: &[u8], keys: &HashSet) -> Result>, Crypt4GHError> { +pub fn encrypt(packet: &[u8], keys: &HashSet) -> Result>, Crypt4GHError> { keys.iter() .filter(|key| key.method == 0) .map( @@ -192,7 +224,7 @@ pub fn serialize(packets: Vec>) -> Vec { fn decrypt( encrypted_packets: Vec>, - keys: &[Keys], + keys: &[KeyPairInfo], sender_pubkey: &Option>, ) -> (Vec>, Vec>) { let mut decrypted_packets = Vec::new(); @@ -211,7 +243,7 @@ fn decrypt( (decrypted_packets, ignored_packets) } -fn decrypt_packet(packet: &[u8], keys: &[Keys], sender_pubkey: &Option>) -> Result, Crypt4GHError> { +fn decrypt_packet(packet: &[u8], keys: &[KeyPairInfo], sender_pubkey: &Option>) -> Result, Crypt4GHError> { let packet_encryption_method = bincode::deserialize::(packet).map_err(|_| Crypt4GHError::ReadPacketEncryptionMethod)?; @@ -335,7 +367,7 @@ fn parse_edit_list_packet(packet: &[u8]) -> Result, Crypt4GHError> { /// the data packets and the edit list packets. Finally, it parses the packets. pub fn deconstruct_header_body( encrypted_packets: Vec>, - keys: &[Keys], + keys: &[KeyPairInfo], sender_pubkey: &Option>, ) -> Result { let (packets, _) = decrypt(encrypted_packets, keys, sender_pubkey); @@ -369,10 +401,12 @@ pub fn deconstruct_header_body( /// /// Reads the magic number, the version and the number of packets from the input bytes. pub fn deserialize_header_info( - header: Vec + header: Bytes, + keys: Vec, + sender_pubkey: &Option> ) -> Result { let header_info = - bincode::deserialize::(header.as_slice()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; + bincode::deserialize::(header.bytes()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; if &header_info.magic_number != MAGIC_NUMBER { return Err(Crypt4GHError::MagicStringError); @@ -391,8 +425,8 @@ pub fn deserialize_header_info( /// key in `recipient_keys`. If trim is specified, the packets that cannot be decrypted are discarded. pub fn reencrypt( header_packets: Vec>, - keys: &[Keys], - recipient_keys: &HashSet, + keys: &[KeyPairInfo], + recipient_keys: &HashSet, trim: bool, ) -> Result>, Crypt4GHError> { log::info!("Reencrypting the header"); @@ -422,7 +456,7 @@ pub fn reencrypt( /// along with an oracle that decides if the next packet should be kept (starting by the first). pub fn rearrange<'a>( header_packets: Vec>, - keys: Vec, + keys: Vec, range_start: usize, range_span: Option, sender_pubkey: &Option>, @@ -503,7 +537,7 @@ pub fn rearrange<'a>( packets.push(edit_packet); - let hash_keys = keys.into_iter().collect::>(); + let hash_keys = keys.into_iter().collect::>(); let final_packets = packets .into_iter() diff --git a/src/keys.rs b/src/keys.rs index 7bbc171..93a3c3c 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -4,9 +4,11 @@ const C4GH_MAGIC_WORD: &[u8; 7] = b"c4gh-v1"; const SSH_MAGIC_WORD: &[u8; 15] = b"openssh-key-v1\x00"; +use crate::error::Crypt4GHError; + #[derive(Debug, PartialEq, Eq, Hash, Clone)] /// Key information. -pub struct Keys { +pub struct KeyPairInfo { /// Method used for the key encryption. /// > Only method 0 is supported. pub method: u8, @@ -65,8 +67,14 @@ impl KeyPair { } impl PublicKey { + /// Generate a new sender public key. + pub fn new() -> Self { + unimplemented!() + //Self { OsRng:: } + } + /// Create a new sender public key from bytes. - pub fn new(bytes: Vec) -> Self { + pub fn new_from_bytes(bytes: Vec) -> Self { Self { bytes } } @@ -79,4 +87,28 @@ impl PublicKey { pub fn get_ref(&self) -> &[u8] { self.bytes.as_slice() } +} + +/// Generate a private and public key pair. +pub fn generate_key_pair() -> Result { + // Todo, very janky, avoid writing this to a file first. + //let temp_dir = TempDir::new().map_err(|err| Crypt4GHError::NoTempFiles(err.to_string()))?; + + let private_key = PrivateKey::new(); + let public_key = PublicKey::new(); + + // generate_keys( + // private_key.clone(), + // public_key.clone(), + // Ok("".to_string()), + // None, + // ); + + // let private_key = get_private_key(private_key, Ok("".to_string()))?; + // let public_key = get_public_key(public_key)?; + + Ok(KeyPair::new( + private_key, + public_key + )) } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 15d2969..8184356 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,8 @@ use chacha20poly1305::{ self, ChaCha20Poly1305, Key, KeyInit, Nonce }; use crate::error::Crypt4GHError; use decrypter::data_block::{ DecryptedDataBlock, DecryptedBytes }; -use keys::Keys; +use keys::KeyPairInfo; +use header::{ HeaderInfo, deserialize_header_info }; const CHUNK_SIZE: usize = 4096; @@ -215,7 +216,7 @@ impl<'a, W: Write> WriteInfo<'a, W> { /// /// Returns the encrypted header bytes pub fn encrypt_header( - recipient_keys: &HashSet, + recipient_keys: &HashSet, session_key: SessionKeys, ) -> Result, Crypt4GHError> { let encryption_method = 0; @@ -544,18 +545,16 @@ fn decrypt_block(ciphersegment: &[u8], session_keys: SessionKeys) -> Result( - keys: &[Keys], - recipient_keys: &HashSet, - read_buffer: &mut R, - write_buffer: &mut W, - trim: bool, + keys: &[KeyPairInfo], + recipient_keys: &HashSet, + trim: bool, // FIXME: Does this need to be an argument or can be decided in code? ) -> Result<(), Crypt4GHError> { // Get header info let mut temp_buf = [0_u8; 16]; // Size of the header read_buffer .read_exact(&mut temp_buf) .map_err(|e| Crypt4GHError::ReadHeaderError(e.into()))?; - let header_info: header::HeaderInfo = header::deserialize_header_info((&temp_buf).to_vec())?; + let header_info: HeaderInfo = deserialize_header_info((&temp_buf).to_vec())?; // Calculate header packets let header_packets = (0..header_info.packets_count) @@ -606,9 +605,7 @@ pub fn reencrypt( /// If the range is specified, it will only rearrange the bytes from `range_start` to `range_start` + `range_span`. /// In case that `range_span` is none, it will rearrange from `range_start` to the end of the input. pub fn rearrange( - keys: Vec, - read_buffer: &mut R, - write_buffer: &mut W, + keys: Vec, range_start: usize, range_span: Option, ) -> Result<(), Crypt4GHError> { @@ -617,7 +614,7 @@ pub fn rearrange( read_buffer .read_exact(&mut temp_buf) .map_err(|e| Crypt4GHError::ReadHeaderError(e.into()))?; - let header_info: header::HeaderInfo = header::deserialize_header_info((&temp_buf).to_vec())?; + let header_info: HeaderInfo = deserialize_header_info((&temp_buf).to_vec())?; // Calculate header packets let header_packets = (0..header_info.packets_count) diff --git a/src/reader/builder.rs b/src/reader/builder.rs index ebc9c35..250c912 100644 --- a/src/reader/builder.rs +++ b/src/reader/builder.rs @@ -1,7 +1,7 @@ use std::thread; use crate::error::Crypt4GHError; -use crate::keys::Keys; +use crate::keys::KeyPairInfo; use futures_util::TryStreamExt; use tokio::io::{AsyncRead, AsyncSeek}; @@ -54,7 +54,7 @@ impl Builder { } /// Build the Crypt4GH reader. - pub fn build_with_reader(self, inner: R, keys: Vec) -> Reader + pub fn build_with_reader(self, inner: R, keys: Vec) -> Reader where R: AsyncRead, { @@ -74,7 +74,7 @@ impl Builder { } /// Build the reader and compute the stream length for seek operations. - pub async fn build_with_stream_length(self, inner: R, keys: Vec) -> Result, Crypt4GHError> + pub async fn build_with_stream_length(self, inner: R, keys: Vec) -> Result, Crypt4GHError> where R: AsyncRead + AsyncSeek + Unpin, { diff --git a/src/reader/mod.rs b/src/reader/mod.rs index 17d1c72..a0a99ce 100644 --- a/src/reader/mod.rs +++ b/src/reader/mod.rs @@ -4,7 +4,7 @@ use std::task::{Context, Poll}; use std::{cmp, io}; use crate::header::HeaderInfo; -use crate::Keys; +use crate::keys::KeyPairInfo; use futures::ready; use futures::stream::TryBuffered; use futures::Stream; @@ -111,7 +111,7 @@ where } /// Get the reader's keys. - pub fn keys(&self) -> &[Keys] { + pub fn keys(&self) -> &[KeyPairInfo] { self.stream.get_ref().keys() } } diff --git a/src/util/mod.rs b/src/util/mod.rs index b07d191..8293d47 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -86,25 +86,3 @@ pub fn unencrypted_clamp_next(pos: u64, encrypted_file_size: u64) -> u64 { ) } -/// Generate a private and public key pair. -pub fn generate_key_pair() -> Result { - // Todo, very janky, avoid writing this to a file first. - //let temp_dir = TempDir::new().map_err(|err| Crypt4GHError::NoTempFiles(err.to_string()))?; - - let private_key = temp_dir.path().join("private_key"); - let public_key = temp_dir.path().join("public_key"); - generate_keys( - private_key.clone(), - public_key.clone(), - Ok("".to_string()), - None, - ); - - let private_key = get_private_key(private_key, Ok("".to_string()))?; - let public_key = get_public_key(public_key)?; - - Ok(KeyPair::new( - PrivateKey(private_key), - PublicKey::new(public_key), - )) -} \ No newline at end of file From 352bdf6bf1c6aa25ccba97197541c119a5e140f5 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 16 Feb 2024 16:24:32 +1100 Subject: [PATCH 17/30] Refactoring header.rs to get rid of free-standing functions, thinking towards Header { HeaderInfo, HeaderData } and methods that read/write/encrypt/decrypt those fields accordingly /cc @mmalenic, might need to discuss this for you to have a clean design that we both feel comfortable with? --- src/decoder/mod.rs | 4 +- src/header.rs | 718 +++++++++++++++++++++++---------------------- 2 files changed, 366 insertions(+), 356 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 1a11803..c98316a 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1,7 +1,7 @@ use std::io; use bytes::{Bytes, BytesMut}; -use crate::header::{deserialize_header_info, EncryptedHeaderPacketBytes, HeaderInfo}; +use crate::header::{Header, EncryptedHeaderPacketBytes}; use tokio_util::codec::Decoder; use crate::error::Crypt4GHError::{ @@ -68,8 +68,6 @@ impl Block { .as_ref() .try_into() .map_err(|_| SliceConversionError)?, - None, - None ) } diff --git a/src/header.rs b/src/header.rs index e8dd947..adfe33b 100644 --- a/src/header.rs +++ b/src/header.rs @@ -20,10 +20,15 @@ const VERSION: u32 = 1; #[derive(Serialize, Deserialize, PartialEq)] enum HeaderPacketType { - DataEnc = 0, + DataEnc = 0, // FIXME: C-style enums not needed here? Remove numbers. EditList = 1, } +pub struct Header { + header_info: HeaderInfo, + header_data: Bytes +} + pub struct HeaderPackets { data_enc_packets: Vec>, edit_list_packet: Option>, @@ -117,432 +122,439 @@ pub struct HeaderInfo { pub packets_count: u32, } -/// Constructs an encrypted data packet -pub fn make_packet_data_enc(encryption_method: usize, session_key: &[u8; 32]) -> Vec { - vec![ - bincode::serialize(&HeaderPacketType::DataEnc).expect("Unable to serialize packet type"), - (encryption_method as u32).to_le_bytes().to_vec(), - session_key.to_vec(), - ] - .concat() -} - -/// Constructs an edit list packet -pub fn make_packet_data_edit_list(edit_list: Vec) -> Vec { - vec![ - bincode::serialize(&HeaderPacketType::EditList).unwrap(), - (edit_list.len() as u32).to_le_bytes().to_vec(), - edit_list - .into_iter() - .flat_map(|n| (n as u64).to_le_bytes().to_vec()) - .collect(), - ] - .concat() -} +impl Header { + pub fn new() { -fn encrypt_x25519_chacha20_poly1305( - data: &[u8], - seckey: &[u8], - recipient_pubkey: &[u8], -) -> Result, Crypt4GHError> { + } - let server_sk = SecretKey::try_from(&seckey[0..SecretKey::BYTES]).map_err(|_| Crypt4GHError::BadClientPrivateKey)?; - let client_pk = PublicKey::try_from(recipient_pubkey).map_err(|_| Crypt4GHError::BadServerPublicKey)?; + /// Constructs an encrypted data packet + pub fn make_packet_data_enc(encryption_method: usize, session_key: &[u8; 32]) -> Vec { + vec![ + bincode::serialize(&HeaderPacketType::DataEnc).expect("Unable to serialize packet type"), + (encryption_method as u32).to_le_bytes().to_vec(), + session_key.to_vec(), + ] + .concat() + } - let pubkey = server_sk.public_key(); + /// Constructs an edit list packet + pub fn make_packet_data_edit_list(edit_list: Vec) -> Vec { + vec![ + bincode::serialize(&HeaderPacketType::EditList).unwrap(), + (edit_list.len() as u32).to_le_bytes().to_vec(), + edit_list + .into_iter() + .flat_map(|n| (n as u64).to_le_bytes().to_vec()) + .collect(), + ] + .concat() + } + fn encrypt_x25519_chacha20_poly1305( + data: &[u8], + seckey: &[u8], + recipient_pubkey: &[u8], + ) -> Result, Crypt4GHError> { - log::debug!(" packed data({}): {:02x?}", data.len(), data); - log::debug!(" public key({}): {:02x?}", pubkey.as_ref().len(), pubkey.as_ref()); - log::debug!( - " private key({}): {:02x?}", - seckey[0..32].len(), - &seckey[0..32] - ); - log::debug!( - " recipient public key({}): {:02x?}", - recipient_pubkey.len(), - recipient_pubkey - ); + let server_sk = SecretKey::try_from(&seckey[0..SecretKey::BYTES]).map_err(|_| Crypt4GHError::BadClientPrivateKey)?; + let client_pk = PublicKey::try_from(recipient_pubkey).map_err(|_| Crypt4GHError::BadServerPublicKey)?; - // TODO: Make sure this doesn't exceed 2^32 executions, otherwise implement a counter and/or other countermeasures against repeats - let nonce = ChaCha20Poly1305::generate_nonce(OsRng); + let pubkey = server_sk.public_key(); - let keypair = Keypair::from(server_sk); - let server_session_keys = keypair.session_keys_from(&client_pk); - let shared_key = GenericArray::::from_slice(&server_session_keys.rx.as_ref().as_slice()); - log::debug!(" shared key: {:02x?}", shared_key.to_vec()); + log::debug!(" packed data({}): {:02x?}", data.len(), data); + log::debug!(" public key({}): {:02x?}", pubkey.as_ref().len(), pubkey.as_ref()); + log::debug!( + " private key({}): {:02x?}", + seckey[0..32].len(), + &seckey[0..32] + ); + log::debug!( + " recipient public key({}): {:02x?}", + recipient_pubkey.len(), + recipient_pubkey + ); - let cipher = ChaCha20Poly1305::new(shared_key); + // TODO: Make sure this doesn't exceed 2^32 executions, otherwise implement a counter and/or other countermeasures against repeats + let nonce = ChaCha20Poly1305::generate_nonce(OsRng); - let ciphertext = cipher.encrypt(&nonce, data) - .map_err(|err| Crypt4GHError::UnableToEncryptPacket(err.to_string()))?; + let keypair = Keypair::from(server_sk); + let server_session_keys = keypair.session_keys_from(&client_pk); + let shared_key = GenericArray::::from_slice(&server_session_keys.rx.as_ref().as_slice()); - Ok(vec![ - pubkey.as_ref(), - nonce.as_slice(), - ciphertext.as_slice() - ].concat()) -} + log::debug!(" shared key: {:02x?}", shared_key.to_vec()); -/// Computes the encrypted part, using all keys -/// -/// Given a set of keys and a vector of bytes, it iterates the keys and for every valid key (key.method == 0), it encrypts the packet. -/// It uses chacha20 and poly1305 to encrypt the packet. It returns a set of encrypted segments that represent the packet for every key. -/// -/// * `packet` is a vector of bytes of information to be encrypted -/// * `keys` is a unique collection of keys with `key.method` == 0 -pub fn encrypt(packet: &[u8], keys: &HashSet) -> Result>, Crypt4GHError> { - keys.iter() - .filter(|key| key.method == 0) - .map( - |key| match encrypt_x25519_chacha20_poly1305(packet, &key.privkey, &key.recipient_pubkey) { - Ok(session_key) => Ok(vec![u32::from(key.method).to_le_bytes().to_vec(), session_key].concat()), - Err(e) => Err(e), - }, - ) - .collect() -} + let cipher = ChaCha20Poly1305::new(shared_key); -/// Serializes the header. -/// -/// Returns [ Magic "crypt4gh" + version + packet count + header packets... ] serialized. -pub fn serialize(packets: Vec>) -> Vec { - log::info!("Serializing the header ({} packets)", packets.len()); - vec![ - MAGIC_NUMBER.to_vec(), - (VERSION as u32).to_le_bytes().to_vec(), - (packets.len() as u32).to_le_bytes().to_vec(), - packets - .into_iter() - .flat_map(|packet| vec![((packet.len() + 4) as u32).to_le_bytes().to_vec(), packet].concat()) - .collect::>(), - ] - .concat() -} + let ciphertext = cipher.encrypt(&nonce, data) + .map_err(|err| Crypt4GHError::UnableToEncryptPacket(err.to_string()))?; -fn decrypt( - encrypted_packets: Vec>, - keys: &[KeyPairInfo], - sender_pubkey: &Option>, -) -> (Vec>, Vec>) { - let mut decrypted_packets = Vec::new(); - let mut ignored_packets = Vec::new(); - - for packet in encrypted_packets { - match decrypt_packet(&packet, keys, sender_pubkey) { - Ok(decrypted_packet) => decrypted_packets.push(decrypted_packet), - Err(e) => { - log::warn!("Ignoring packet because: {}", e); - ignored_packets.push(packet); - }, - } + Ok(vec![ + pubkey.as_ref(), + nonce.as_slice(), + ciphertext.as_slice() + ].concat()) } - (decrypted_packets, ignored_packets) -} - -fn decrypt_packet(packet: &[u8], keys: &[KeyPairInfo], sender_pubkey: &Option>) -> Result, Crypt4GHError> { - let packet_encryption_method = - bincode::deserialize::(packet).map_err(|_| Crypt4GHError::ReadPacketEncryptionMethod)?; + /// Computes the encrypted part, using all keys + /// + /// Given a set of keys and a vector of bytes, it iterates the keys and for every valid key (key.method == 0), it encrypts the packet. + /// It uses chacha20 and poly1305 to encrypt the packet. It returns a set of encrypted segments that represent the packet for every key. + /// + /// * `packet` is a vector of bytes of information to be encrypted + /// * `keys` is a unique collection of keys with `key.method` == 0 + pub fn encrypt(packet: &[u8], keys: &HashSet) -> Result>, Crypt4GHError> { + keys.iter() + .filter(|key| key.method == 0) + .map( + |key| match encrypt_x25519_chacha20_poly1305(packet, &key.privkey, &key.recipient_pubkey) { + Ok(session_key) => Ok(vec![u32::from(key.method).to_le_bytes().to_vec(), session_key].concat()), + Err(e) => Err(e), + }, + ) + .collect() + } - log::debug!("Header Packet Encryption Method: {}", packet_encryption_method); + /// Serializes the header. + /// + /// Returns [ Magic "crypt4gh" + version + packet count + header packets... ] serialized. + pub fn serialize(packets: Vec>) -> Vec { + log::info!("Serializing the header ({} packets)", packets.len()); + vec![ + MAGIC_NUMBER.to_vec(), + (VERSION as u32).to_le_bytes().to_vec(), + (packets.len() as u32).to_le_bytes().to_vec(), + packets + .into_iter() + .flat_map(|packet| vec![((packet.len() + 4) as u32).to_le_bytes().to_vec(), packet].concat()) + .collect::>(), + ] + .concat() + } - for key in keys { - if packet_encryption_method != u32::from(key.method) { - continue; + fn decrypt( + encrypted_packets: Vec>, + keys: &[KeyPairInfo], + sender_pubkey: &Option>, + ) -> (Vec>, Vec>) { + let mut decrypted_packets = Vec::new(); + let mut ignored_packets = Vec::new(); + + for packet in encrypted_packets { + match decrypt_packet(&packet, keys, sender_pubkey) { + Ok(decrypted_packet) => decrypted_packets.push(decrypted_packet), + Err(e) => { + log::warn!("Ignoring packet because: {}", e); + ignored_packets.push(packet); + }, + } } - match packet_encryption_method { - 0 => { - let plaintext_packet = decrypt_x25519_chacha20_poly1305(&packet[4..], &key.privkey, sender_pubkey); - //log::debug!("Decrypting packet: {:?}\n into plaintext packet: {:?}\n", &packet[8..], &plaintext_packet); - return plaintext_packet; - }, - 1 => unimplemented!("AES-256-GCM support is not implemented"), - n => return Err(Crypt4GHError::BadHeaderEncryptionMethod(n)), - } + (decrypted_packets, ignored_packets) } - Err(Crypt4GHError::UnableToEncryptPacket("Error encrypting".to_string())) -} -fn decrypt_x25519_chacha20_poly1305( - encrypted_part: &[u8], - privkey: &[u8], - sender_pubkey: &Option>, -) -> Result, Crypt4GHError> { - log::debug!(" secret key: {:02x?}", &privkey[0..32]); + fn decrypt_packet(packet: &[u8], keys: &[KeyPairInfo], sender_pubkey: &Option>) -> Result, Crypt4GHError> { + let packet_encryption_method = + bincode::deserialize::(packet).map_err(|_| Crypt4GHError::ReadPacketEncryptionMethod)?; + + log::debug!("Header Packet Encryption Method: {}", packet_encryption_method); - let peer_pubkey = &encrypted_part[0..32];//PublicKey::BYTES]; - //log::debug!(" peer_pubkey({}): {:02x?}", peer_pubkey.len(), peer_pubkey); + for key in keys { + if packet_encryption_method != u32::from(key.method) { + continue; + } - if sender_pubkey.is_some() && sender_pubkey.clone().unwrap().as_slice() != peer_pubkey { - return Err(Crypt4GHError::InvalidPeerPubPkey); + match packet_encryption_method { + 0 => { + let plaintext_packet = decrypt_x25519_chacha20_poly1305(&packet[4..], &key.privkey, sender_pubkey); + //log::debug!("Decrypting packet: {:?}\n into plaintext packet: {:?}\n", &packet[8..], &plaintext_packet); + return plaintext_packet; + }, + 1 => unimplemented!("AES-256-GCM support is not implemented"), + n => return Err(Crypt4GHError::BadHeaderEncryptionMethod(n)), + } + } + Err(Crypt4GHError::UnableToEncryptPacket("Error encrypting".to_string())) } - let nonce = GenericArray::from_slice(&encrypted_part[32..44]); - let packet_data = &encrypted_part[44..]; + fn decrypt_x25519_chacha20_poly1305( + encrypted_part: &[u8], + privkey: &[u8], + sender_pubkey: &Option>, + ) -> Result, Crypt4GHError> { + log::debug!(" secret key: {:02x?}", &privkey[0..32]); - let client_sk = SecretKey::try_from(&privkey[0..SecretKey::BYTES]).map_err(|_| Crypt4GHError::BadClientPrivateKey)?; - let server_pk = PublicKey::try_from(peer_pubkey).map_err(|_| Crypt4GHError::BadServerPublicKey)?; + let peer_pubkey = &encrypted_part[0..32];//PublicKey::BYTES]; + //log::debug!(" peer_pubkey({}): {:02x?}", peer_pubkey.len(), peer_pubkey); - let keypair = Keypair::from(client_sk); - let client_session_keys = keypair.session_keys_to(&server_pk); - let shared_key = GenericArray::::from_slice(&client_session_keys.tx.as_ref().as_slice()); + if sender_pubkey.is_some() && sender_pubkey.clone().unwrap().as_slice() != peer_pubkey { + return Err(Crypt4GHError::InvalidPeerPubPkey); + } - let cipher = ChaCha20Poly1305::new(shared_key); + let nonce = GenericArray::from_slice(&encrypted_part[32..44]); + let packet_data = &encrypted_part[44..]; - log::debug!(" peer pubkey: {:02x?}", peer_pubkey); - log::debug!(" nonce: {:02x?}", &nonce); - log::debug!( - " encrypted data ({}): {:02x?}", - packet_data.len(), - packet_data - ); + let client_sk = SecretKey::try_from(&privkey[0..SecretKey::BYTES]).map_err(|_| Crypt4GHError::BadClientPrivateKey)?; + let server_pk = PublicKey::try_from(peer_pubkey).map_err(|_| Crypt4GHError::BadServerPublicKey)?; - log::debug!("shared key: {:02x?}", shared_key); + let keypair = Keypair::from(client_sk); + let client_session_keys = keypair.session_keys_to(&server_pk); + let shared_key = GenericArray::::from_slice(&client_session_keys.tx.as_ref().as_slice()); - let plaintext = cipher.decrypt(&nonce, packet_data) - .map_err(|err| Crypt4GHError::UnableToDecryptBlock(packet_data.to_vec(), err.to_string()))?; + let cipher = ChaCha20Poly1305::new(shared_key); - Ok(plaintext) -} + log::debug!(" peer pubkey: {:02x?}", peer_pubkey); + log::debug!(" nonce: {:02x?}", &nonce); + log::debug!( + " encrypted data ({}): {:02x?}", + packet_data.len(), + packet_data + ); -fn partition_packets(packets: Vec>) -> Result { - let mut enc_packets = Vec::new(); - let mut edits = None; + log::debug!("shared key: {:02x?}", shared_key); - for packet in packets { - let packet_type = - bincode::deserialize::(&packet[0..4]).map_err(|_| Crypt4GHError::InvalidPacketType)?; + let plaintext = cipher.decrypt(&nonce, packet_data) + .map_err(|err| Crypt4GHError::UnableToDecryptBlock(packet_data.to_vec(), err.to_string()))?; - match packet_type { - HeaderPacketType::DataEnc => { - enc_packets.push(packet[4..].to_vec()); - }, - HeaderPacketType::EditList => { - match edits { - None => edits = Some(packet[4..].to_vec()), - Some(_) => return Err(Crypt4GHError::TooManyEditListPackets), - }; - }, - } + Ok(plaintext) } - Ok(HeaderPackets { - data_enc_packets: enc_packets, - edit_list_packet: edits, - }) -} + fn partition_packets(packets: Vec>) -> Result { + let mut enc_packets = Vec::new(); + let mut edits = None; + + for packet in packets { + let packet_type = + bincode::deserialize::(&packet[0..4]).map_err(|_| Crypt4GHError::InvalidPacketType)?; + + match packet_type { + HeaderPacketType::DataEnc => { + enc_packets.push(packet[4..].to_vec()); + }, + HeaderPacketType::EditList => { + match edits { + None => edits = Some(packet[4..].to_vec()), + Some(_) => return Err(Crypt4GHError::TooManyEditListPackets), + }; + }, + } + } -fn parse_enc_packet(packet: &[u8]) -> Result, Crypt4GHError> { - match packet[0..4] { - [0, 0, 0, 0] => Ok(packet[4..].to_vec()), - _ => Err(Crypt4GHError::UnsupportedEncryptionMethod( - bincode::deserialize::(&packet[0..4]).expect("Unable to deserialize bulk encryption method"), - )), + Ok(HeaderPackets { + data_enc_packets: enc_packets, + edit_list_packet: edits, + }) } -} - -fn parse_edit_list_packet(packet: &[u8]) -> Result, Crypt4GHError> { - let nb_lengths: u32 = bincode::deserialize::(packet).map_err(|_| Crypt4GHError::NoEditListLength)?; - - log::info!("Edit list length: {}", nb_lengths); - log::info!("packet content length: {}", packet.len() - 4); - if ((packet.len() as u32) - 4) < (8 * nb_lengths) { - return Err(Crypt4GHError::InvalidEditList); + fn parse_enc_packet(packet: &[u8]) -> Result, Crypt4GHError> { + match packet[0..4] { + [0, 0, 0, 0] => Ok(packet[4..].to_vec()), + _ => Err(Crypt4GHError::UnsupportedEncryptionMethod( + bincode::deserialize::(&packet[0..4]).expect("Unable to deserialize bulk encryption method"), + )), + } } - (4..nb_lengths * 8) - .step_by(8) - .map(|i| bincode::deserialize::(&packet[i as usize..]).map_err(|_| Crypt4GHError::InvalidEditList)) - .collect() -} + fn parse_edit_list_packet(packet: &[u8]) -> Result, Crypt4GHError> { + let nb_lengths: u32 = bincode::deserialize::(packet).map_err(|_| Crypt4GHError::NoEditListLength)?; -/// Gets data packets and edit list packets from the encrypted packets. -/// -/// Decrypts the encrypted packets and partitions the encrypted packets in two groups, -/// the data packets and the edit list packets. Finally, it parses the packets. -pub fn deconstruct_header_body( - encrypted_packets: Vec>, - keys: &[KeyPairInfo], - sender_pubkey: &Option>, -) -> Result { - let (packets, _) = decrypt(encrypted_packets, keys, sender_pubkey); - - if packets.is_empty() { - return Err(Crypt4GHError::NoSupportedEncryptionMethod); - } + log::info!("Edit list length: {}", nb_lengths); + log::info!("packet content length: {}", packet.len() - 4); - let HeaderPackets { - data_enc_packets, - edit_list_packet, - } = partition_packets(packets)?; - - let session_keys = data_enc_packets - .into_iter() - .map(|d| parse_enc_packet(&d)) - .collect::, Crypt4GHError>>()?; - - let edit_list = match edit_list_packet { - Some(packet) => Some(parse_edit_list_packet(&packet)?), - None => None, - }; - - Ok(DecryptedHeaderPackets { - data_enc_packets: session_keys, - edit_list_packet: edit_list, - }) -} + if ((packet.len() as u32) - 4) < (8 * nb_lengths) { + return Err(Crypt4GHError::InvalidEditList); + } -/// Deserializes the data info from the header bytes. -/// -/// Reads the magic number, the version and the number of packets from the input bytes. -pub fn deserialize_header_info( - header: Bytes, - keys: Vec, - sender_pubkey: &Option> -) -> Result { - let header_info = - bincode::deserialize::(header.bytes()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; - - if &header_info.magic_number != MAGIC_NUMBER { - return Err(Crypt4GHError::MagicStringError); + (4..nb_lengths * 8) + .step_by(8) + .map(|i| bincode::deserialize::(&packet[i as usize..]).map_err(|_| Crypt4GHError::InvalidEditList)) + .collect() } - if header_info.version != VERSION { - return Err(Crypt4GHError::InvalidCrypt4GHVersion(header_info.version)); - } + /// Gets data packets and edit list packets from the encrypted packets. + /// + /// Decrypts the encrypted packets and partitions the encrypted packets in two groups, + /// the data packets and the edit list packets. Finally, it parses the packets. + pub fn deconstruct_header_body( + encrypted_packets: Vec>, + keys: &[KeyPairInfo], + sender_pubkey: &Option>, + ) -> Result { + let (packets, _) = decrypt(encrypted_packets, keys, sender_pubkey); + + if packets.is_empty() { + return Err(Crypt4GHError::NoSupportedEncryptionMethod); + } - Ok(header_info) -} + let HeaderPackets { + data_enc_packets, + edit_list_packet, + } = partition_packets(packets)?; -/// Reencrypts the header. -/// -/// Decrypts the header using the `keys` and then, encrypts the content again for every -/// key in `recipient_keys`. If trim is specified, the packets that cannot be decrypted are discarded. -pub fn reencrypt( - header_packets: Vec>, - keys: &[KeyPairInfo], - recipient_keys: &HashSet, - trim: bool, -) -> Result>, Crypt4GHError> { - log::info!("Reencrypting the header"); - - let (decrypted_packets, mut ignored_packets) = decrypt(header_packets, keys, &None); - - if decrypted_packets.is_empty() { - Err(Crypt4GHError::NoValidHeaderPacket) - } - else { - let mut packets: Vec> = decrypted_packets + let session_keys = data_enc_packets .into_iter() - .flat_map(|packet| encrypt(&packet, recipient_keys).unwrap()) - .collect(); + .map(|d| parse_enc_packet(&d)) + .collect::, Crypt4GHError>>()?; + + let edit_list = match edit_list_packet { + Some(packet) => Some(parse_edit_list_packet(&packet)?), + None => None, + }; + + Ok(DecryptedHeaderPackets { + data_enc_packets: session_keys, + edit_list_packet: edit_list, + }) + } - if !trim { - packets.append(&mut ignored_packets); + /// Deserializes the data info from the header bytes. + /// + /// Reads the magic number, the version and the number of packets from the input bytes. + pub fn deserialize_header_info( + header: Bytes, + keys: Vec, + sender_pubkey: &Option> + ) -> Result { + let header_info = + bincode::deserialize::(header.bytes()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; + + if &header_info.magic_number != MAGIC_NUMBER { + return Err(Crypt4GHError::MagicStringError); } - Ok(packets) - } -} + if header_info.version != VERSION { + return Err(Crypt4GHError::InvalidCrypt4GHVersion(header_info.version)); + } -/// Gets the packages to rearrange. -/// -/// Rearranges the edit list in accordance to the range. It returns the data packets -/// along with an oracle that decides if the next packet should be kept (starting by the first). -pub fn rearrange<'a>( - header_packets: Vec>, - keys: Vec, - range_start: usize, - range_span: Option, - sender_pubkey: &Option>, -) -> Result<(Vec>, impl Iterator + 'a), Crypt4GHError> { - if range_span <= Some(0) { - //assert!(span > 0, "Span should be greater than 0"); - return Err(Crypt4GHError::InvalidRangeSpan(range_span)); + Ok(header_info) } - log::info!("Rearranging the header"); - - log::debug!(" Start coordinate: {}", range_start); - range_span.map_or_else( - || { - log::debug!(" End coordinate: EOF"); - }, - |span| { - log::debug!(" End coordinate: {}", range_start + span); - }, - ); - log::debug!(" Segment size: {}", SEGMENT_SIZE); - - if range_start == 0 && range_span.is_none() { - return Err(Crypt4GHError::Done); - } + /// Reencrypts the header. + /// + /// Decrypts the header using the `keys` and then, encrypts the content again for every + /// key in `recipient_keys`. If trim is specified, the packets that cannot be decrypted are discarded. + pub fn reencrypt( + header_packets: Vec>, + keys: &[KeyPairInfo], + recipient_keys: &HashSet, + trim: bool, + ) -> Result>, Crypt4GHError> { + log::info!("Reencrypting the header"); + + let (decrypted_packets, mut ignored_packets) = decrypt(header_packets, keys, &None); + + if decrypted_packets.is_empty() { + Err(Crypt4GHError::NoValidHeaderPacket) + } + else { + let mut packets: Vec> = decrypted_packets + .into_iter() + .flat_map(|packet| encrypt(&packet, recipient_keys).unwrap()) + .collect(); - let (decrypted_packets, _) = decrypt(header_packets, &keys, sender_pubkey); + if !trim { + packets.append(&mut ignored_packets); + } - if decrypted_packets.is_empty() { - return Err(Crypt4GHError::NoValidHeaderPacket); + Ok(packets) + } } - let HeaderPackets { - data_enc_packets, - edit_list_packet, - } = partition_packets(decrypted_packets)?; + /// Gets the packages to rearrange. + /// + /// Rearranges the edit list in accordance to the range. It returns the data packets + /// along with an oracle that decides if the next packet should be kept (starting by the first). + pub fn rearrange<'a>( + header_packets: Vec>, + keys: Vec, + range_start: usize, + range_span: Option, + sender_pubkey: &Option>, + ) -> Result<(Vec>, impl Iterator + 'a), Crypt4GHError> { + if range_span <= Some(0) { + //assert!(span > 0, "Span should be greater than 0"); + return Err(Crypt4GHError::InvalidRangeSpan(range_span)); + } + + log::info!("Rearranging the header"); - if edit_list_packet.is_some() { - unimplemented!() - } + log::debug!(" Start coordinate: {}", range_start); + range_span.map_or_else( + || { + log::debug!(" End coordinate: EOF"); + }, + |span| { + log::debug!(" End coordinate: {}", range_start + span); + }, + ); + log::debug!(" Segment size: {}", SEGMENT_SIZE); + + if range_start == 0 && range_span.is_none() { + return Err(Crypt4GHError::Done); + } - log::info!("No edit list present: making one"); + let (decrypted_packets, _) = decrypt(header_packets, &keys, sender_pubkey); - let start_segment = range_start / SEGMENT_SIZE; - let start_offset = range_start % SEGMENT_SIZE; - let end_segment = range_span.map(|span| (range_start + span) / SEGMENT_SIZE); - let end_offset = range_span.map(|span| (range_start + span) % SEGMENT_SIZE); + if decrypted_packets.is_empty() { + return Err(Crypt4GHError::NoValidHeaderPacket); + } - log::debug!("Start segment: {} | Offset: {}", start_segment, start_offset); - log::debug!("End segment: {:?} | Offset: {:?}", end_segment, end_offset); + let HeaderPackets { + data_enc_packets, + edit_list_packet, + } = partition_packets(decrypted_packets)?; - let segment_oracle = (0..).map(move |count| { - if count < start_segment { - false + if edit_list_packet.is_some() { + unimplemented!() } - else { - match end_segment { - Some(end) => count < end || (count == end && end_offset.unwrap() > 0), - None => true, + + log::info!("No edit list present: making one"); + + let start_segment = range_start / SEGMENT_SIZE; + let start_offset = range_start % SEGMENT_SIZE; + let end_segment = range_span.map(|span| (range_start + span) / SEGMENT_SIZE); + let end_offset = range_span.map(|span| (range_start + span) % SEGMENT_SIZE); + + log::debug!("Start segment: {} | Offset: {}", start_segment, start_offset); + log::debug!("End segment: {:?} | Offset: {:?}", end_segment, end_offset); + + let segment_oracle = (0..).map(move |count| { + if count < start_segment { + false + } + else { + match end_segment { + Some(end) => count < end || (count == end && end_offset.unwrap() > 0), + None => true, + } } + }); + + let mut edit_list = vec![start_offset]; + if let Some(span) = range_span { + edit_list.push(span); } - }); - let mut edit_list = vec![start_offset]; - if let Some(span) = range_span { - edit_list.push(span); - } + log::debug!("New edit list: {:?}", edit_list); + let edit_packet = make_packet_data_edit_list(edit_list); - log::debug!("New edit list: {:?}", edit_list); - let edit_packet = make_packet_data_edit_list(edit_list); + log::info!("Reencrypting all packets"); - log::info!("Reencrypting all packets"); + let mut packets = data_enc_packets + .into_iter() + .map(|packet| vec![bincode::serialize(&HeaderPacketType::DataEnc).unwrap(), packet].concat()) + .collect::>>(); - let mut packets = data_enc_packets - .into_iter() - .map(|packet| vec![bincode::serialize(&HeaderPacketType::DataEnc).unwrap(), packet].concat()) - .collect::>>(); + packets.push(edit_packet); - packets.push(edit_packet); + let hash_keys = keys.into_iter().collect::>(); - let hash_keys = keys.into_iter().collect::>(); + let final_packets = packets + .into_iter() + .map(|packet| encrypt(&packet, &hash_keys).map(|encrypted_packets| encrypted_packets.concat())) + .collect::>, Crypt4GHError>>()?; - let final_packets = packets - .into_iter() - .map(|packet| encrypt(&packet, &hash_keys).map(|encrypted_packets| encrypted_packets.concat())) - .collect::>, Crypt4GHError>>()?; + Ok((final_packets, segment_oracle)) + } +} - Ok((final_packets, segment_oracle)) -} \ No newline at end of file From 54dd2ef56bd562b381e194befa3b5b1455bdf247 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 19 Feb 2024 13:56:08 +1100 Subject: [PATCH 18/30] Sorting through the functions that must be public for Header and which should not... also which of Header/HeaderPackets/EcnrytperHeaderPackets/EncryptedHeaderPacketBytes should hold which functions... [ci skip] --- src/decoder/mod.rs | 2 +- src/decrypter/header/packets.rs | 5 ++++- src/header.rs | 20 ++++++++++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index c98316a..34be387 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1,7 +1,7 @@ use std::io; use bytes::{Bytes, BytesMut}; -use crate::header::{Header, EncryptedHeaderPacketBytes}; +use crate::header::{EncryptedHeaderPacketBytes, Header, HeaderInfo}; use tokio_util::codec::Decoder; use crate::error::Crypt4GHError::{ diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs index 5e545dc..021ddbb 100644 --- a/src/decrypter/header/packets.rs +++ b/src/decrypter/header/packets.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; -use crate::header::{deserialize_header_info, DecryptedHeaderPackets}; +use crate::header::{DecryptedHeaderPackets, Header}; use pin_project_lite::pin_project; use tokio::task::{spawn_blocking, JoinHandle}; @@ -36,6 +36,9 @@ impl HeaderPacketsDecrypter { keys: Vec, sender_pubkey: Option, ) -> Result { + let header = Header::new_from_bytes(header_packets.as_slice()); + + Ok(deserialize_header_info( header_packets .into_iter() diff --git a/src/header.rs b/src/header.rs index adfe33b..f0487cb 100644 --- a/src/header.rs +++ b/src/header.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; use std::io::Read; +use std::mem::uninitialized; use bytes::Bytes; use aead::consts::U32; @@ -123,10 +124,16 @@ pub struct HeaderInfo { } impl Header { - pub fn new() { - + /// New empty header + pub fn new(header_bytes: Bytes) -> Self { + unimplemented!(); } + /// New header from Bytes + // pub fn new_from_bytes(self, header_bytes: Bytes) { + // unimplemented!(); + // } + /// Constructs an encrypted data packet pub fn make_packet_data_enc(encryption_method: usize, session_key: &[u8; 32]) -> Vec { vec![ @@ -203,7 +210,7 @@ impl Header { /// /// * `packet` is a vector of bytes of information to be encrypted /// * `keys` is a unique collection of keys with `key.method` == 0 - pub fn encrypt(packet: &[u8], keys: &HashSet) -> Result>, Crypt4GHError> { + pub fn encrypt(&mut self, packet: &[u8], keys: &HashSet) -> Result>, Crypt4GHError> { keys.iter() .filter(|key| key.method == 0) .map( @@ -218,7 +225,7 @@ impl Header { /// Serializes the header. /// /// Returns [ Magic "crypt4gh" + version + packet count + header packets... ] serialized. - pub fn serialize(packets: Vec>) -> Vec { + pub fn serialize(&mut self, packets: Vec>) -> Vec { log::info!("Serializing the header ({} packets)", packets.len()); vec![ MAGIC_NUMBER.to_vec(), @@ -232,7 +239,8 @@ impl Header { .concat() } - fn decrypt( + pub fn decrypt( + &mut self, encrypted_packets: Vec>, keys: &[KeyPairInfo], sender_pubkey: &Option>, @@ -410,7 +418,7 @@ impl Header { /// Deserializes the data info from the header bytes. /// /// Reads the magic number, the version and the number of packets from the input bytes. - pub fn deserialize_header_info( + pub fn deserialize(&self, header: Bytes, keys: Vec, sender_pubkey: &Option> From 0e685e9058a5b62c6ddc0765a4a5bce2d3ce2744 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 19 Feb 2024 16:14:13 +1100 Subject: [PATCH 19/30] Refactor the header structs so that it mirrors the Crypt4GH spec 1-1, much easier to follow [ci skip] --- src/header.rs | 171 +++++++++++++++++++++----------------------------- src/keys.rs | 16 +++-- 2 files changed, 81 insertions(+), 106 deletions(-) diff --git a/src/header.rs b/src/header.rs index f0487cb..2fc6783 100644 --- a/src/header.rs +++ b/src/header.rs @@ -1,136 +1,93 @@ use std::collections::HashSet; use std::io::Read; -use std::mem::uninitialized; use bytes::Bytes; use aead::consts::U32; use aead::generic_array::GenericArray; use chacha20poly1305::aead::Aead; use chacha20poly1305::aead::OsRng; +use chacha20poly1305::Nonce; use chacha20poly1305::{self, aead, ChaCha20Poly1305, KeyInit, AeadCore}; use crypto_kx::{SecretKey, PublicKey, Keypair}; +use curve25519_dalek::digest::Mac; use serde::{Deserialize, Serialize}; +use ssh_key::PrivateKey; use super::SEGMENT_SIZE; use crate::error::Crypt4GHError; +use crate::keys::EncryptionMethod; use crate::keys::KeyPair; use crate::keys::KeyPairInfo; + const MAGIC_NUMBER: &[u8; 8] = b"crypt4gh"; const VERSION: u32 = 1; #[derive(Serialize, Deserialize, PartialEq)] enum HeaderPacketType { - DataEnc = 0, // FIXME: C-style enums not needed here? Remove numbers. - EditList = 1, + DataEnc, + EditList +} + +enum HeaderPacketDataType { + Packet {DataEncryptionPacket: u8, EditListPacket: u8 } } pub struct Header { - header_info: HeaderInfo, - header_data: Bytes + magic: [u8; 8], + version: u8, + packet_count: u32, + header_packets: Vec } -pub struct HeaderPackets { - data_enc_packets: Vec>, - edit_list_packet: Option>, +pub struct HeaderPacket { + packet_length: u32, + encryption_method: EncryptionMethod, + writer_pubkey: PublicKey, + nonce: Nonce, + encrypted_packet_data: EncryptedPacketData, + mac: Bytes //dalek::Mac type might be more fitting } -#[derive(Debug, Default, Clone)] -pub struct EncryptedHeaderPacketBytes { - pub packet_length: Bytes, - pub header: Bytes +pub struct EncryptedPacketData { + packet_type: HeaderPacketType, + packet_data: HeaderPacketDataType } -/// Represents the encrypted header packet data, and the total size of all the header packets. -#[derive(Debug, Default)] -pub struct EncryptedHeaderPackets { - header_packets: Vec, - header_length: u64, +struct DataEncryptionPacket { + encryption_method: EncryptionMethod, + data_encryption_key: PrivateKey } -impl EncryptedHeaderPackets { - /// Create a new decrypted data block. - pub fn new(header_packets: Vec, size: u64) -> Self { - Self { - header_packets, - header_length: size, - } - } - - /// Get the header packet bytes - pub fn header_packets(&self) -> &Vec { - &self.header_packets - } - - /// Get the size of all the packets. - pub fn header_length(&self) -> u64 { - self.header_length - } - - /// Get the inner bytes and size. - pub fn into_inner(self) -> (Vec, u64) { - (self.header_packets, self.header_length) - } +struct EditListPacket { + number_lengths: Vec, + lengths: Vec } -/// Represents the bytes inside the `EncryptedHeaderPackets` -impl EncryptedHeaderPacketBytes { - /// Create header packet bytes. - pub fn new(packet_length: Bytes, header: Bytes) -> Self { - Self { - packet_length, - header, - } - } - - /// Get packet length bytes. - pub fn packet_length(&self) -> &Bytes { - &self.packet_length - } - - /// Get header bytes. - pub fn header(&self) -> &Bytes { - &self.header - } - - /// Get the owned packet length and header bytes. - pub fn into_inner(self) -> (Bytes, Bytes) { - (self.packet_length, self.header) +impl Header { + pub fn new() -> Self { + todo!() } - - /// Get the header bytes only. - pub fn into_header_bytes(self) -> Bytes { - self.header + + /// Get the header packet bytes + pub fn header_packets(&self) -> &Vec { + &self.header_packets } -} -/// Contains the parsed data of the packets -pub struct DecryptedHeaderPackets { - /// The packets that are coded as data - pub data_enc_packets: Vec>, - /// The packets that are an edit list - pub edit_list_packet: Option>, -} - -/// Contains the basic information of the header. -#[derive(Serialize, Deserialize, Debug)] -pub struct HeaderInfo { - /// A “magic” string for file type identification. It should be the ASCII representation of the string "crypt4gh". - pub magic_number: [u8; 8], - /// A version number (four-byte little-endian). The current version is 1. - pub version: u32, - /// The number of packets that the header contains. - pub packets_count: u32, -} + /// Get the size of all the packets. + pub fn header_length(&self) -> u64 { + self.header_length + } -impl Header { - /// New empty header - pub fn new(header_bytes: Bytes) -> Self { - unimplemented!(); + /// Get the inner bytes and size. + pub fn into_inner(self) -> (Vec, u64) { + (self.header_packets, self.header_length) } + // FIXME: implement default + /// New header from Bytes - // pub fn new_from_bytes(self, header_bytes: Bytes) { + // pub fn from(self, header_bytes: Bytes) { // unimplemented!(); // } @@ -210,7 +167,7 @@ impl Header { /// /// * `packet` is a vector of bytes of information to be encrypted /// * `keys` is a unique collection of keys with `key.method` == 0 - pub fn encrypt(&mut self, packet: &[u8], keys: &HashSet) -> Result>, Crypt4GHError> { + pub fn encrypt(&self, packet: &[u8], keys: &HashSet) -> Result>, Crypt4GHError> { keys.iter() .filter(|key| key.method == 0) .map( @@ -225,7 +182,7 @@ impl Header { /// Serializes the header. /// /// Returns [ Magic "crypt4gh" + version + packet count + header packets... ] serialized. - pub fn serialize(&mut self, packets: Vec>) -> Vec { + pub fn serialize(&self, packets: Vec>) -> Vec { log::info!("Serializing the header ({} packets)", packets.len()); vec![ MAGIC_NUMBER.to_vec(), @@ -387,7 +344,7 @@ impl Header { encrypted_packets: Vec>, keys: &[KeyPairInfo], sender_pubkey: &Option>, - ) -> Result { + ) -> Result, Crypt4GHError> { let (packets, _) = decrypt(encrypted_packets, keys, sender_pubkey); if packets.is_empty() { @@ -409,10 +366,11 @@ impl Header { None => None, }; - Ok(DecryptedHeaderPackets { - data_enc_packets: session_keys, - edit_list_packet: edit_list, - }) + todo!() + // Ok(Vec { + // data_enc_packets: session_keys, + // edit_list_packet: edit_list, + // }) } /// Deserializes the data info from the header bytes. @@ -422,9 +380,9 @@ impl Header { header: Bytes, keys: Vec, sender_pubkey: &Option> - ) -> Result { + ) -> Result { let header_info = - bincode::deserialize::(header.bytes()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; + bincode::deserialize::
(header.bytes()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; if &header_info.magic_number != MAGIC_NUMBER { return Err(Crypt4GHError::MagicStringError); @@ -446,7 +404,7 @@ impl Header { keys: &[KeyPairInfo], recipient_keys: &HashSet, trim: bool, - ) -> Result>, Crypt4GHError> { + ) -> Result { log::info!("Reencrypting the header"); let (decrypted_packets, mut ignored_packets) = decrypt(header_packets, keys, &None); @@ -566,3 +524,14 @@ impl Header { } } +impl Default for Header { + fn default() -> Self { + Self { + magic: MAGIC_NUMBER, + version: VERSION, + packet_count: 0, + header_packets: Vec::new(), + } + } +} + diff --git a/src/keys.rs b/src/keys.rs index 93a3c3c..4b59af3 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -6,16 +6,22 @@ const SSH_MAGIC_WORD: &[u8; 15] = b"openssh-key-v1\x00"; use crate::error::Crypt4GHError; +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub enum EncryptionMethod { + X25519Chacha20Poly305, + Aes256Gcm +} + #[derive(Debug, PartialEq, Eq, Hash, Clone)] /// Key information. pub struct KeyPairInfo { /// Method used for the key encryption. /// > Only method 0 is supported. - pub method: u8, + pub method: EncryptionMethod, /// Secret key of the encryptor / decryptor (your key). - pub privkey: Vec, + pub privkey: PrivateKey, /// Public key of the recipient (the key you want to encrypt for). - pub recipient_pubkey: Vec, + pub recipient_pubkey: PublicKey, } pub struct SessionKeys { @@ -23,13 +29,13 @@ pub struct SessionKeys { } /// Private keys are just bytes since it should support disparate formats, i.e: SSH and GA4GH -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Hash, Eq)] pub struct PrivateKey { pub bytes: Vec, } /// A wrapper around a vec of bytes that represent a public key. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Hash, Eq)] pub struct PublicKey { pub bytes: Vec, } From 1488a7750a85ff2830ce33cc7426c4a24ac68b13 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 19 Feb 2024 16:19:38 +1100 Subject: [PATCH 20/30] Vec instead of u8... see https://bcantrill.dtrace.org/2020/10/11/rust-after-the-honeymoon/ for context... why is u8 and not Vec for those data-bearing enums in point 6, @mmalenic? --- src/header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/header.rs b/src/header.rs index 2fc6783..a8bdf37 100644 --- a/src/header.rs +++ b/src/header.rs @@ -30,7 +30,7 @@ enum HeaderPacketType { } enum HeaderPacketDataType { - Packet {DataEncryptionPacket: u8, EditListPacket: u8 } + Packet {DataEncryptionPacket: Vec, EditListPacket: Vec } } pub struct Header { From 3db1a41e0caadc46f5ef2323ac8f2ece602607c0 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 19 Feb 2024 16:37:43 +1100 Subject: [PATCH 21/30] Corrections on data types gathered from the spec and annotated: sections from the spec mirroring the actual implementation and FIXMEs that should be considered --- src/decoder/mod.rs | 11 ++++------- src/decrypter/header/packets.rs | 14 +++++++++----- src/header.rs | 11 ++++++++++- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 34be387..77d6354 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1,14 +1,11 @@ use std::io; use bytes::{Bytes, BytesMut}; -use crate::header::{EncryptedHeaderPacketBytes, Header, HeaderInfo}; use tokio_util::codec::Decoder; -use crate::error::Crypt4GHError::{ +use crate::{error::Crypt4GHError::{ self, MaximumHeaderSize, NumericConversionError, SliceConversionError -}; -use crate::header::EncryptedHeaderPackets; - +}, header::HeaderPacket}; pub const ENCRYPTED_BLOCK_SIZE: usize = 65536; pub const NONCE_SIZE: usize = 12; // ChaCha20 IETF Nonce size pub const MAC_SIZE: usize = 16; @@ -32,10 +29,10 @@ const MAX_HEADER_SIZE: usize = 8 * 1024 * 1024; pub enum DecodedBlock { /// The magic string, version string and header packet count. /// Corresponds to `deconstruct_header_info`. - HeaderInfo(HeaderInfo), + HeaderInfo(Header), /// Header packets, both data encryption key packets and a data edit list packets. /// Corresponds to `deconstruct_header_body`. - HeaderPackets(EncryptedHeaderPackets), + HeaderPackets(HeaderPacket), /// The encrypted data blocks /// Corresponds to `body_decrypt`. DataBlock(Bytes), diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs index 021ddbb..ac81bbd 100644 --- a/src/decrypter/header/packets.rs +++ b/src/decrypter/header/packets.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; -use crate::header::{DecryptedHeaderPackets, Header}; +use crate::header::Header; use pin_project_lite::pin_project; use tokio::task::{spawn_blocking, JoinHandle}; @@ -14,10 +14,14 @@ pin_project! { #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct HeaderPacketsDecrypter { #[pin] - handle: JoinHandle> + handle: JoinHandle> } } + +/// FIXME: This should be probably moved to header.rs along with header as it only concerns Header ops? +/// Since packets are not data blocks I think that for clarity it does not deserve its own file, but +/// belongs to header.rs instead. impl HeaderPacketsDecrypter { pub fn new( header_packets: Vec, @@ -35,10 +39,10 @@ impl HeaderPacketsDecrypter { header_packets: Vec, keys: Vec, sender_pubkey: Option, - ) -> Result { + ) -> Result { let header = Header::new_from_bytes(header_packets.as_slice()); - + Ok(deserialize_header_info( header_packets .into_iter() @@ -51,7 +55,7 @@ impl HeaderPacketsDecrypter { } impl Future for HeaderPacketsDecrypter { - type Output = Result; + type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.project().handle.poll(cx).map_err(JoinHandleError)? diff --git a/src/header.rs b/src/header.rs index a8bdf37..c2db380 100644 --- a/src/header.rs +++ b/src/header.rs @@ -23,23 +23,29 @@ use crate::keys::KeyPairInfo; const MAGIC_NUMBER: &[u8; 8] = b"crypt4gh"; const VERSION: u32 = 1; +/// Structs below follow crypt4gh spec §2.2 +/// +/// Encodes actual encrypted data from a header packet or an edit list. #[derive(Serialize, Deserialize, PartialEq)] enum HeaderPacketType { DataEnc, EditList } +/// Data-bearing Header Packet data type as it can hold either depending on packet type enum HeaderPacketDataType { Packet {DataEncryptionPacket: Vec, EditListPacket: Vec } } +/// Header precedes data blocks and is described in crypt4gh spec §3.2 and §2.2 for a high level graphical representation pub struct Header { magic: [u8; 8], - version: u8, + version: u32, packet_count: u32, header_packets: Vec } +/// As described in crypt4gh spec §3.2.1 pub struct HeaderPacket { packet_length: u32, encryption_method: EncryptionMethod, @@ -54,16 +60,19 @@ pub struct EncryptedPacketData { packet_data: HeaderPacketDataType } +/// This packet contains the parameters needed to decrypt the data part of the file. As described in crypt4gh spec §3.2.3 struct DataEncryptionPacket { encryption_method: EncryptionMethod, data_encryption_key: PrivateKey } +/// This packet contains a list of edits that should be applied to the plain-text data following decryption. As described in crypt4gh spec §3.2.4 struct EditListPacket { number_lengths: Vec, lengths: Vec } +/// Implements all header-related operations described in crypt4gh spec §3.2 and onwards impl Header { pub fn new() -> Self { todo!() From ab23e6d0ed598905483af774dc79782068d299ad Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 5 Mar 2024 16:53:25 +1100 Subject: [PATCH 22/30] Introduce encrypted_data, move segments, fixing header function names reflect the builder pattern instead of hardcoding header_* and the like --- src/decrypter/header/packets.rs | 3 +- src/encrypted_data.rs | 16 +++++ src/header.rs | 101 ++++++++++++++++++++------------ src/lib.rs | 33 ++--------- src/reader/mod.rs | 2 +- 5 files changed, 86 insertions(+), 69 deletions(-) create mode 100644 src/encrypted_data.rs diff --git a/src/decrypter/header/packets.rs b/src/decrypter/header/packets.rs index ac81bbd..3631bc1 100644 --- a/src/decrypter/header/packets.rs +++ b/src/decrypter/header/packets.rs @@ -42,8 +42,7 @@ impl HeaderPacketsDecrypter { ) -> Result { let header = Header::new_from_bytes(header_packets.as_slice()); - - Ok(deserialize_header_info( + Ok(header.deserialize( header_packets .into_iter() .map(|bytes| bytes.to_vec()) diff --git a/src/encrypted_data.rs b/src/encrypted_data.rs new file mode 100644 index 0000000..6beed47 --- /dev/null +++ b/src/encrypted_data.rs @@ -0,0 +1,16 @@ +use crate::keys::EncryptionMethod; + +/// Size of the encrypted segments. +pub const SEGMENT_SIZE: usize = 65_536; +const CIPHER_DIFF: usize = 28; +const CIPHER_SEGMENT_SIZE: usize = SEGMENT_SIZE + CIPHER_DIFF; + +struct Segment { + pub data: Chacha20IetfPoly1305Segment +} + +struct Chacha20IetfPoly1305Segment { + nonce: u8, + encrypted_data: Vec, // FIXME: Specific Nonce type preferred in Rust, prefer not following the spec types here + mac: u8 // FIXME: Ditto above +} \ No newline at end of file diff --git a/src/header.rs b/src/header.rs index c2db380..e09b1cc 100644 --- a/src/header.rs +++ b/src/header.rs @@ -14,7 +14,7 @@ use curve25519_dalek::digest::Mac; use serde::{Deserialize, Serialize}; use ssh_key::PrivateKey; -use super::SEGMENT_SIZE; +use crate::encrypted_data::SEGMENT_SIZE; use crate::error::Crypt4GHError; use crate::keys::EncryptionMethod; use crate::keys::KeyPair; @@ -25,6 +25,15 @@ const VERSION: u32 = 1; /// Structs below follow crypt4gh spec §2.2 /// +/// Header precedes data blocks and is described in crypt4gh spec §3.2 and §2.2 for a high level graphical representation of +/// the file structure. +pub struct Header { + magic: [u8; 8], + version: u32, + count: u32, + packets: Vec +} + /// Encodes actual encrypted data from a header packet or an edit list. #[derive(Serialize, Deserialize, PartialEq)] enum HeaderPacketType { @@ -37,14 +46,6 @@ enum HeaderPacketDataType { Packet {DataEncryptionPacket: Vec, EditListPacket: Vec } } -/// Header precedes data blocks and is described in crypt4gh spec §3.2 and §2.2 for a high level graphical representation -pub struct Header { - magic: [u8; 8], - version: u32, - packet_count: u32, - header_packets: Vec -} - /// As described in crypt4gh spec §3.2.1 pub struct HeaderPacket { packet_length: u32, @@ -79,18 +80,18 @@ impl Header { } /// Get the header packet bytes - pub fn header_packets(&self) -> &Vec { - &self.header_packets + pub fn packets(&self) -> &Vec { + &self.packets } /// Get the size of all the packets. - pub fn header_length(&self) -> u64 { - self.header_length + pub fn length(&self) -> u64 { + self.length } /// Get the inner bytes and size. pub fn into_inner(self) -> (Vec, u64) { - (self.header_packets, self.header_length) + (self.packets, self.length) } // FIXME: implement default @@ -101,7 +102,7 @@ impl Header { // } /// Constructs an encrypted data packet - pub fn make_packet_data_enc(encryption_method: usize, session_key: &[u8; 32]) -> Vec { + pub fn make_data_enc_packet(encryption_method: usize, session_key: &[u8; 32]) -> Vec { vec![ bincode::serialize(&HeaderPacketType::DataEnc).expect("Unable to serialize packet type"), (encryption_method as u32).to_le_bytes().to_vec(), @@ -111,7 +112,7 @@ impl Header { } /// Constructs an edit list packet - pub fn make_packet_data_edit_list(edit_list: Vec) -> Vec { + pub fn make_data_edit_list(edit_list: Vec) -> Vec { vec![ bincode::serialize(&HeaderPacketType::EditList).unwrap(), (edit_list.len() as u32).to_le_bytes().to_vec(), @@ -205,6 +206,29 @@ impl Header { .concat() } + /// Deserializes the data info from the header bytes. + /// + /// Reads the magic number, the version and the number of packets from the input bytes. + pub fn deserialize(&self, + header: Bytes, + keys: Vec, + sender_pubkey: &Option> + ) -> Result { + let header_info = + bincode::deserialize::
(header.bytes()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; + + if &header_info.magic_number != MAGIC_NUMBER { + return Err(Crypt4GHError::MagicStringError); + } + + if header_info.version != VERSION { + return Err(Crypt4GHError::InvalidCrypt4GHVersion(header_info.version)); + } + + Ok(header_info) + } + + pub fn decrypt( &mut self, encrypted_packets: Vec>, @@ -382,27 +406,6 @@ impl Header { // }) } - /// Deserializes the data info from the header bytes. - /// - /// Reads the magic number, the version and the number of packets from the input bytes. - pub fn deserialize(&self, - header: Bytes, - keys: Vec, - sender_pubkey: &Option> - ) -> Result { - let header_info = - bincode::deserialize::
(header.bytes()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; - - if &header_info.magic_number != MAGIC_NUMBER { - return Err(Crypt4GHError::MagicStringError); - } - - if header_info.version != VERSION { - return Err(Crypt4GHError::InvalidCrypt4GHVersion(header_info.version)); - } - - Ok(header_info) - } /// Reencrypts the header. /// @@ -531,6 +534,30 @@ impl Header { Ok((final_packets, segment_oracle)) } + + /// Builds a header with a random session key + /// + /// Returns the encrypted header bytes + pub fn encrypt_header( + recipient_keys: &HashSet, + session_key: SessionKeys, + ) -> Result, Crypt4GHError> { + let encryption_method = 0; + + let session_key_or_new = session_key.map_or_else(|| { + let mut session_key = [0_u8; 32]; + let mut rnd = rand_chacha::ChaCha20Rng::from_entropy(); + + rnd.try_fill_bytes(&mut session_key).map_err(|_| Crypt4GHError::NoRandomNonce)?; // TODO: Custom error for this + + Ok::<_, Crypt4GHError>(session_key) + }, |value| { Ok(value)} )?; + + let header_content = header::make_packet_data_enc(encryption_method, &session_key_or_new); + let header_packets = header::encrypt(&header_content, recipient_keys)?; + let header_bytes = header::serialize(header_packets); + Ok(header_bytes) + } } impl Default for Header { diff --git a/src/lib.rs b/src/lib.rs index 8184356..261481a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ pub mod reader; pub mod util; pub mod header; pub mod keys; +pub mod encrypted_data; pub mod error; use bytes::Bytes; @@ -45,17 +46,14 @@ use chacha20poly1305::aead::Aead; use chacha20poly1305::{ self, ChaCha20Poly1305, Key, KeyInit, Nonce }; use crate::error::Crypt4GHError; +use crate::header::Header; use decrypter::data_block::{ DecryptedDataBlock, DecryptedBytes }; use keys::KeyPairInfo; -use header::{ HeaderInfo, deserialize_header_info }; +//use header::{ HeaderInfo, deserialize_header_info }; const CHUNK_SIZE: usize = 4096; -/// Size of the encrypted segments. -pub const SEGMENT_SIZE: usize = 65_536; -const CIPHER_DIFF: usize = 28; -const CIPHER_SEGMENT_SIZE: usize = SEGMENT_SIZE + CIPHER_DIFF; /// Write buffer wrapper. /// * offset: Start writing on position = `offset` @@ -212,29 +210,6 @@ impl<'a, W: Write> WriteInfo<'a, W> { // Ok(()) // } -/// Builds a header with a random session key -/// -/// Returns the encrypted header bytes -pub fn encrypt_header( - recipient_keys: &HashSet, - session_key: SessionKeys, -) -> Result, Crypt4GHError> { - let encryption_method = 0; - - let session_key_or_new = session_key.map_or_else(|| { - let mut session_key = [0_u8; 32]; - let mut rnd = rand_chacha::ChaCha20Rng::from_entropy(); - - rnd.try_fill_bytes(&mut session_key).map_err(|_| Crypt4GHError::NoRandomNonce)?; // TODO: Custom error for this - - Ok::<_, Crypt4GHError>(session_key) - }, |value| { Ok(value)} )?; - - let header_content = header::make_packet_data_enc(encryption_method, &session_key_or_new); - let header_packets = header::encrypt(&header_content, recipient_keys)?; - let header_bytes = header::serialize(header_packets); - Ok(header_bytes) -} /// Encrypts a segment. /// @@ -554,7 +529,7 @@ pub fn reencrypt( read_buffer .read_exact(&mut temp_buf) .map_err(|e| Crypt4GHError::ReadHeaderError(e.into()))?; - let header_info: HeaderInfo = deserialize_header_info((&temp_buf).to_vec())?; + let header = Header::from((&temp_buf).to_vec())?; // Calculate header packets let header_packets = (0..header_info.packets_count) diff --git a/src/reader/mod.rs b/src/reader/mod.rs index a0a99ce..d0fcd5a 100644 --- a/src/reader/mod.rs +++ b/src/reader/mod.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::{cmp, io}; -use crate::header::HeaderInfo; +use crate::decoder::DecodedBlock::HeaderInfo; use crate::keys::KeyPairInfo; use futures::ready; use futures::stream::TryBuffered; From 2d4be96f2e8426bb03709beb45a9522ad4b664ad Mon Sep 17 00:00:00 2001 From: Marko Malenic Date: Thu, 7 Mar 2024 15:39:19 +1100 Subject: [PATCH 23/30] refactor: review session --- src/{ => decryption}/decoder/mod.rs | 0 src/{ => decryption}/decrypter/builder.rs | 0 src/{ => decryption}/decrypter/data_block.rs | 0 src/{ => decryption}/decrypter/header/mod.rs | 0 .../decrypter/header/packets.rs | 0 src/{ => decryption}/decrypter/mod.rs | 0 src/decryption/mod.rs | 3 + src/{ => decryption}/reader/builder.rs | 0 src/{ => decryption}/reader/mod.rs | 0 src/{ => encryption}/encrypter/builder.rs | 0 src/{ => encryption}/encrypter/data_block.rs | 0 src/{ => encryption}/encrypter/header/mod.rs | 0 .../encrypter/header/packets.rs | 0 src/{ => encryption}/encrypter/mod.rs | 0 src/encryption/mod.rs | 1 + src/header.rs | 69 ++++++++++++------- 16 files changed, 50 insertions(+), 23 deletions(-) rename src/{ => decryption}/decoder/mod.rs (100%) rename src/{ => decryption}/decrypter/builder.rs (100%) rename src/{ => decryption}/decrypter/data_block.rs (100%) rename src/{ => decryption}/decrypter/header/mod.rs (100%) rename src/{ => decryption}/decrypter/header/packets.rs (100%) rename src/{ => decryption}/decrypter/mod.rs (100%) create mode 100644 src/decryption/mod.rs rename src/{ => decryption}/reader/builder.rs (100%) rename src/{ => decryption}/reader/mod.rs (100%) rename src/{ => encryption}/encrypter/builder.rs (100%) rename src/{ => encryption}/encrypter/data_block.rs (100%) rename src/{ => encryption}/encrypter/header/mod.rs (100%) rename src/{ => encryption}/encrypter/header/packets.rs (100%) rename src/{ => encryption}/encrypter/mod.rs (100%) create mode 100644 src/encryption/mod.rs diff --git a/src/decoder/mod.rs b/src/decryption/decoder/mod.rs similarity index 100% rename from src/decoder/mod.rs rename to src/decryption/decoder/mod.rs diff --git a/src/decrypter/builder.rs b/src/decryption/decrypter/builder.rs similarity index 100% rename from src/decrypter/builder.rs rename to src/decryption/decrypter/builder.rs diff --git a/src/decrypter/data_block.rs b/src/decryption/decrypter/data_block.rs similarity index 100% rename from src/decrypter/data_block.rs rename to src/decryption/decrypter/data_block.rs diff --git a/src/decrypter/header/mod.rs b/src/decryption/decrypter/header/mod.rs similarity index 100% rename from src/decrypter/header/mod.rs rename to src/decryption/decrypter/header/mod.rs diff --git a/src/decrypter/header/packets.rs b/src/decryption/decrypter/header/packets.rs similarity index 100% rename from src/decrypter/header/packets.rs rename to src/decryption/decrypter/header/packets.rs diff --git a/src/decrypter/mod.rs b/src/decryption/decrypter/mod.rs similarity index 100% rename from src/decrypter/mod.rs rename to src/decryption/decrypter/mod.rs diff --git a/src/decryption/mod.rs b/src/decryption/mod.rs new file mode 100644 index 0000000..3bc6282 --- /dev/null +++ b/src/decryption/mod.rs @@ -0,0 +1,3 @@ +pub mod reader; +pub mod decoder; +pub mod decrypter; \ No newline at end of file diff --git a/src/reader/builder.rs b/src/decryption/reader/builder.rs similarity index 100% rename from src/reader/builder.rs rename to src/decryption/reader/builder.rs diff --git a/src/reader/mod.rs b/src/decryption/reader/mod.rs similarity index 100% rename from src/reader/mod.rs rename to src/decryption/reader/mod.rs diff --git a/src/encrypter/builder.rs b/src/encryption/encrypter/builder.rs similarity index 100% rename from src/encrypter/builder.rs rename to src/encryption/encrypter/builder.rs diff --git a/src/encrypter/data_block.rs b/src/encryption/encrypter/data_block.rs similarity index 100% rename from src/encrypter/data_block.rs rename to src/encryption/encrypter/data_block.rs diff --git a/src/encrypter/header/mod.rs b/src/encryption/encrypter/header/mod.rs similarity index 100% rename from src/encrypter/header/mod.rs rename to src/encryption/encrypter/header/mod.rs diff --git a/src/encrypter/header/packets.rs b/src/encryption/encrypter/header/packets.rs similarity index 100% rename from src/encrypter/header/packets.rs rename to src/encryption/encrypter/header/packets.rs diff --git a/src/encrypter/mod.rs b/src/encryption/encrypter/mod.rs similarity index 100% rename from src/encrypter/mod.rs rename to src/encryption/encrypter/mod.rs diff --git a/src/encryption/mod.rs b/src/encryption/mod.rs new file mode 100644 index 0000000..8db6650 --- /dev/null +++ b/src/encryption/mod.rs @@ -0,0 +1 @@ +pub mod encrypter; \ No newline at end of file diff --git a/src/header.rs b/src/header.rs index e09b1cc..661ef16 100644 --- a/src/header.rs +++ b/src/header.rs @@ -23,27 +23,38 @@ use crate::keys::KeyPairInfo; const MAGIC_NUMBER: &[u8; 8] = b"crypt4gh"; const VERSION: u32 = 1; +pub struct Magic([u8; 8]); + /// Structs below follow crypt4gh spec §2.2 /// /// Header precedes data blocks and is described in crypt4gh spec §3.2 and §2.2 for a high level graphical representation of /// the file structure. pub struct Header { - magic: [u8; 8], + magic: Magic, version: u32, count: u32, packets: Vec } -/// Encodes actual encrypted data from a header packet or an edit list. -#[derive(Serialize, Deserialize, PartialEq)] -enum HeaderPacketType { - DataEnc, - EditList +pub enum EncryptedPacketData { + DataEncryptionKey(DataEncryptionKeyPacket), + EditList(EditListPacket) +} + +struct DataEncryptionKeyPacket { + encryption_method: u32, + data_encryption_key: Vec +} + +struct EditListPacket { + number_lengths: u32, + lengths: Vec } /// Data-bearing Header Packet data type as it can hold either depending on packet type enum HeaderPacketDataType { - Packet {DataEncryptionPacket: Vec, EditListPacket: Vec } + EditListPacket(Vec), + DataPacketEncrypted(Vec), } /// As described in crypt4gh spec §3.2.1 @@ -56,22 +67,34 @@ pub struct HeaderPacket { mac: Bytes //dalek::Mac type might be more fitting } -pub struct EncryptedPacketData { - packet_type: HeaderPacketType, - packet_data: HeaderPacketDataType -} - -/// This packet contains the parameters needed to decrypt the data part of the file. As described in crypt4gh spec §3.2.3 -struct DataEncryptionPacket { - encryption_method: EncryptionMethod, - data_encryption_key: PrivateKey -} - -/// This packet contains a list of edits that should be applied to the plain-text data following decryption. As described in crypt4gh spec §3.2.4 -struct EditListPacket { - number_lengths: Vec, - lengths: Vec -} +// /// Encodes actual encrypted data from a header packet or an edit list. +// #[derive(Serialize, Deserialize, PartialEq)] +// enum HeaderPacketType { +// DataEnc, +// EditList +// } +// +// /// Data-bearing Header Packet data type as it can hold either depending on packet type +// enum HeaderPacketDataType { +// Packet {DataEncryptionPacket: Vec, EditListPacket: Vec } +// } + +// pub struct EncryptedPacketData { +// packet_type: HeaderPacketType, +// packet_data: HeaderPacketDataType +// } + +// /// This packet contains the parameters needed to decrypt the data part of the file. As described in crypt4gh spec §3.2.3 +// struct DataEncryptionPacket { +// encryption_method: EncryptionMethod, +// data_encryption_key: PrivateKey +// } +// +// /// This packet contains a list of edits that should be applied to the plain-text data following decryption. As described in crypt4gh spec §3.2.4 +// struct EditListPacket { +// number_lengths: Vec, +// lengths: Vec +// } /// Implements all header-related operations described in crypt4gh spec §3.2 and onwards impl Header { From 73dbc9af35855dcfaa902267a3f33516b5bf0e11 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 15 Jul 2024 16:07:27 +1000 Subject: [PATCH 24/30] Bump up crate versions after hiatus... --- Cargo.lock | 477 ++++++++++++++++++++++++++++++++++++++++++++--------- Cargo.toml | 16 +- 2 files changed, 407 insertions(+), 86 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1265c45..6262b32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,33 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "aws-lc-rs" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a47f2fb521b70c11ce7369a6c5fa4bd6af7e5d62ec06303875bafe7c6ba245" +dependencies = [ + "aws-lc-sys", + "mirai-annotations", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2927c7af777b460b7ccd95f8b67acd7b4c04ec8896bf0c8e80ba30523cffc057" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", + "libc", + "paste", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -89,9 +116,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.21.2" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -119,11 +146,34 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.43", + "which", +] + [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" [[package]] name = "bitflags" @@ -133,9 +183,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blake2" @@ -232,9 +282,19 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -276,13 +336,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098" dependencies = [ - "bitflags 2.3.2", + "bitflags 2.6.0", "clap_derive", "clap_lex", "is-terminal", @@ -313,6 +384,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -370,7 +450,7 @@ dependencies = [ "ed25519_to_curve25519", "futures", "futures-util", - "itertools", + "itertools 0.13.0", "lazy_static", "log", "noodles", @@ -460,7 +540,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.43", ] [[package]] @@ -485,6 +565,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "ecdsa" version = "0.16.9" @@ -572,23 +658,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -617,6 +692,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures" version = "0.3.30" @@ -673,7 +754,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.43", ] [[package]] @@ -734,6 +815,12 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "group" version = "0.13.0" @@ -772,6 +859,15 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "humantime" version = "2.1.0" @@ -806,7 +902,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -817,8 +913,8 @@ checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi", "io-lifetimes", - "rustix", - "windows-sys", + "rustix 0.37.20", + "windows-sys 0.48.0", ] [[package]] @@ -830,6 +926,24 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -839,6 +953,12 @@ dependencies = [ "spin 0.5.2", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "lexical-core" version = "0.8.5" @@ -909,6 +1029,16 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libloading" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + [[package]] name = "libm" version = "0.2.8" @@ -921,6 +1051,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "log" version = "0.4.16" @@ -957,6 +1093,12 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -966,11 +1108,27 @@ dependencies = [ "adler", ] +[[package]] +name = "mirai-annotations" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "noodles" -version = "0.64.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa9a3104049a2a6b31b8b3cf414774832f28cc6fe3fb5fca21ed28e77c7f95f" +checksum = "81e0702ff73390d2b8f97751bc34cfedcd3f5d39b4e32875e4c64a32d8cc670b" dependencies = [ "noodles-bam", "noodles-bcf", @@ -979,6 +1137,7 @@ dependencies = [ "noodles-csi", "noodles-fasta", "noodles-fastq", + "noodles-gff", "noodles-sam", "noodles-tabix", "noodles-vcf", @@ -986,9 +1145,9 @@ dependencies = [ [[package]] name = "noodles-bam" -version = "0.56.0" +version = "0.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3189e8ecee801ab5c3f4ea9908c4196b429137d8d35d733f00f6681f9188be7" +checksum = "406d4768f21c73e3075c0c0d77a5b21bc8b8169c8f0963122607cc410427b727" dependencies = [ "bit-vec", "bstr", @@ -1005,9 +1164,9 @@ dependencies = [ [[package]] name = "noodles-bcf" -version = "0.46.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1561dbba3a09a61020b805a598b3d7c50841491c915523e0e4987f67286886f1" +checksum = "f1f217d811dde790866d3c4902ef713f9dc5c4b96e51935571ddf68399f97ad6" dependencies = [ "byteorder", "futures", @@ -1021,9 +1180,9 @@ dependencies = [ [[package]] name = "noodles-bgzf" -version = "0.26.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8970db2e84adb1007377dd3988258d7a64e3fc4c05602ebf94e1f8cba207c030" +checksum = "2b2fba0f4a64cc897d9396d730a0c444d148daed7de31ad5904ecc673178fc9d" dependencies = [ "byteorder", "bytes", @@ -1037,18 +1196,21 @@ dependencies = [ [[package]] name = "noodles-core" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7336c3be652de4e05444c9b12a32331beb5ba3316e8872d92bfdd8ef3b06c282" +checksum = "c5a8c6b020d1205abef2b0fab4463a6c5ecc3c8f4d561ca8b0d1a42323376200" +dependencies = [ + "bstr", +] [[package]] name = "noodles-cram" -version = "0.55.0" +version = "0.66.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79515cee0bc37187bd3baf02f2dc02db5ad91b006b7856ce1417053d69168924" +checksum = "8c7f58d900eb9fa1f0ef1a4834a6f71bfa792b25b2fa3b02e582239089907909" dependencies = [ "async-compression", - "bitflags 2.3.2", + "bitflags 2.6.0", "bstr", "byteorder", "bytes", @@ -1068,9 +1230,9 @@ dependencies = [ [[package]] name = "noodles-csi" -version = "0.30.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60dfe0919f7ecbd081a82eb1d32e8f89f9041932d035fe8309073c8c01277bf" +checksum = "e4bc8001c54f1d8e47e1ac6041a5f27edc99b68bacea3fade9c89059de285aea" dependencies = [ "bit-vec", "byteorder", @@ -1082,10 +1244,11 @@ dependencies = [ [[package]] name = "noodles-fasta" -version = "0.32.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebb3e83e0f112d3482f5234a1eb219081f12cc3aab38a9eba00ef1846b43b63b" +checksum = "d7a1662ac3ace299515c982a322e378bbeb4c1bd90fb098d823ef0f3a6abcc00" dependencies = [ + "bstr", "bytes", "memchr", "noodles-bgzf", @@ -1095,22 +1258,37 @@ dependencies = [ [[package]] name = "noodles-fastq" -version = "0.10.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03559005dc319f23454e0ae6804f72d27da2d4293c2dcc01ff7b0d8c5d59ab9f" +checksum = "c1edf1f924acddeee36304c444e242b9bda52ef9383dc2d7f008fca190753207" dependencies = [ "futures", "memchr", "tokio", ] +[[package]] +name = "noodles-gff" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adef59012090b5694b58cad0e4426cd18af404803f942d02e664af607d89ee28" +dependencies = [ + "futures", + "indexmap", + "noodles-bgzf", + "noodles-core", + "noodles-csi", + "percent-encoding", + "tokio", +] + [[package]] name = "noodles-sam" -version = "0.53.0" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f0d8e441368374f6e144989f823fd7c05e58cdaa3f97d22bb4d75b534327b87" +checksum = "b80efc627501962e2ff15411d1c011fa9cf3db1b47ddd13dceb1d1134068d5b7" dependencies = [ - "bitflags 2.3.2", + "bitflags 2.6.0", "bstr", "futures", "indexmap", @@ -1124,9 +1302,9 @@ dependencies = [ [[package]] name = "noodles-tabix" -version = "0.36.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1ab29335a68d0c2bdf41460a67714ca69e23a1cbeb950ac5c38a9afa446a62" +checksum = "545e16e229b7f8734b0a2a36bd4c98a5b70128663b16b5201ddadc0d09c28d4a" dependencies = [ "bit-vec", "byteorder", @@ -1139,9 +1317,9 @@ dependencies = [ [[package]] name = "noodles-vcf" -version = "0.49.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e1f2fa749afaccadc596ec55ccb7bdcd8101fa79f8382384223c0dbae3e245b" +checksum = "b6372f1df57c1826d083370b6eac586f331509feed15fd80dda306ef3e7ac68d" dependencies = [ "futures", "indexmap", @@ -1151,6 +1329,7 @@ dependencies = [ "noodles-csi", "noodles-tabix", "percent-encoding", + "pin-project-lite", "tokio", ] @@ -1288,6 +1467,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pbkdf2" version = "0.12.1" @@ -1385,6 +1570,16 @@ dependencies = [ "log", ] +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.43", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -1420,9 +1615,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1504,7 +1699,7 @@ dependencies = [ "libc", "spin 0.9.8", "untrusted", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1555,6 +1750,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1574,18 +1775,32 @@ dependencies = [ "errno", "io-lifetimes", "libc", - "linux-raw-sys", - "windows-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.22.2" +version = "0.23.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" dependencies = [ + "aws-lc-rs", "log", - "ring", + "once_cell", "rustls-pki-types", "rustls-webpki", "subtle", @@ -1594,16 +1809,17 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.2.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.102.2" +version = "0.102.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -1681,6 +1897,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -1801,9 +2023,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" dependencies = [ "proc-macro2", "quote", @@ -1821,9 +2043,9 @@ dependencies = [ [[package]] name = "testresult" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e045f5cf9ad69772c1c9652f5567a75df88bbb5a1310a64e53cab140c5c459" +checksum = "d72e255c0541f86589b0287139b70bd941a197ea4cea8fd8f87afe9c965a99e4" [[package]] name = "thiserror" @@ -1866,7 +2088,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.43", ] [[package]] @@ -1948,6 +2170,18 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.34", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1985,7 +2219,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -1994,13 +2237,29 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -2009,42 +2268,90 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "xz2" version = "0.1.7" @@ -2059,3 +2366,17 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] diff --git a/Cargo.toml b/Cargo.toml index 0cff51c..d26b949 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,10 +23,10 @@ path = "src/bin.rs" clap = { version = "4", features = ["derive", "env"] } regex = "1.5" rpassword = "7" -base64 = "0.21" +base64 = "0.22" lazy_static = "1.4" chacha20poly1305 = "0.10" -crypto_kx = { version = "0.2.1" } +crypto_kx = { version = "0.2" } scrypt = { version = "0.11" } bcrypt-pbkdf = { version = "0.10" } aes = { version = "0.8" } @@ -38,7 +38,7 @@ serde = { version = "1", features = ["derive"] } log = "0.4" pretty_env_logger = "0.5" thiserror = "1" -itertools = "0.12" +itertools = "0.13" rand = "0.8" rand_chacha = "0.3" ed25519_to_curve25519 = "0.2" @@ -46,7 +46,7 @@ ed25519_to_curve25519 = "0.2" curve25519-dalek = "4" ssh-key = { version = "0.6.4", features = ["ed25519"] } bytes = "1.5.0" -rustls = "0.22" +rustls = "0.23" tokio = { version = "1", features = [ "io-util", "test-util", "macros", "rt-multi-thread" ] } futures = "0.3" pin-project-lite = "0.2.13" @@ -54,10 +54,10 @@ tokio-util = { version = "0.7", features = ["codec"] } futures-util = "0.3.30" [dev-dependencies] -testresult = "0.3" -noodles-bam = "0.56" -noodles-sam = "0.53" -noodles = { version = "0.64", features = [ "sam", "bam", "async" ] } +testresult = "0.4" +noodles-bam = "0.65" +noodles-sam = "0.62" +noodles = { version = "0.78", features = [ "sam", "bam", "async" ] } [profile.release] lto = true From 5362810db2c3a78fdc8d6ab6b62081b6a46e348c Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 15 Jul 2024 16:16:19 +1000 Subject: [PATCH 25/30] Sea of red for the spec-based refactor, need to discuss design w/ @mmalenic --- src/decoder/mod.rs | 2 +- src/encrypted_data.rs | 4 ++++ src/header.rs | 18 +++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 77d6354..1d6973f 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -5,7 +5,7 @@ use tokio_util::codec::Decoder; use crate::{error::Crypt4GHError::{ self, MaximumHeaderSize, NumericConversionError, SliceConversionError -}, header::HeaderPacket}; +}, header::HeaderPacket, header::Header}; pub const ENCRYPTED_BLOCK_SIZE: usize = 65536; pub const NONCE_SIZE: usize = 12; // ChaCha20 IETF Nonce size pub const MAC_SIZE: usize = 16; diff --git a/src/encrypted_data.rs b/src/encrypted_data.rs index 6beed47..c8fb995 100644 --- a/src/encrypted_data.rs +++ b/src/encrypted_data.rs @@ -1,3 +1,5 @@ +/// Implementation of Crypt4GH spec "Encrypted Data" §3.4. + use crate::keys::EncryptionMethod; /// Size of the encrypted segments. @@ -5,6 +7,8 @@ pub const SEGMENT_SIZE: usize = 65_536; const CIPHER_DIFF: usize = 28; const CIPHER_SEGMENT_SIZE: usize = SEGMENT_SIZE + CIPHER_DIFF; + +// §3.4.2 Segmenting the input struct Segment { pub data: Chacha20IetfPoly1305Segment } diff --git a/src/header.rs b/src/header.rs index e09b1cc..73333d8 100644 --- a/src/header.rs +++ b/src/header.rs @@ -8,9 +8,8 @@ use chacha20poly1305::aead::Aead; use chacha20poly1305::aead::OsRng; use chacha20poly1305::Nonce; use chacha20poly1305::{self, aead, ChaCha20Poly1305, KeyInit, AeadCore}; -use crypto_kx::{SecretKey, PublicKey, Keypair}; +use crypto_kx::{SecretKey, Keypair}; -use curve25519_dalek::digest::Mac; use serde::{Deserialize, Serialize}; use ssh_key::PrivateKey; @@ -19,6 +18,7 @@ use crate::error::Crypt4GHError; use crate::keys::EncryptionMethod; use crate::keys::KeyPair; use crate::keys::KeyPairInfo; +use crate::keys::PublicKey; const MAGIC_NUMBER: &[u8; 8] = b"crypt4gh"; const VERSION: u32 = 1; @@ -27,6 +27,7 @@ const VERSION: u32 = 1; /// /// Header precedes data blocks and is described in crypt4gh spec §3.2 and §2.2 for a high level graphical representation of /// the file structure. +#[derive(Debug)] pub struct Header { magic: [u8; 8], version: u32, @@ -35,18 +36,20 @@ pub struct Header { } /// Encodes actual encrypted data from a header packet or an edit list. -#[derive(Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq)] enum HeaderPacketType { DataEnc, EditList } /// Data-bearing Header Packet data type as it can hold either depending on packet type +#[derive(Debug)] enum HeaderPacketDataType { Packet {DataEncryptionPacket: Vec, EditListPacket: Vec } } -/// As described in crypt4gh spec §3.2.1 +/// As described in crypt4gh spec §3.2.1 +#[derive(Debug)] pub struct HeaderPacket { packet_length: u32, encryption_method: EncryptionMethod, @@ -56,6 +59,7 @@ pub struct HeaderPacket { mac: Bytes //dalek::Mac type might be more fitting } +#[derive(Debug)] pub struct EncryptedPacketData { packet_type: HeaderPacketType, packet_data: HeaderPacketDataType @@ -86,12 +90,12 @@ impl Header { /// Get the size of all the packets. pub fn length(&self) -> u64 { - self.length + unimplemented!() } /// Get the inner bytes and size. pub fn into_inner(self) -> (Vec, u64) { - (self.packets, self.length) + unimplemented!() } // FIXME: implement default @@ -217,7 +221,7 @@ impl Header { let header_info = bincode::deserialize::
(header.bytes()).map_err(|e| Crypt4GHError::ReadHeaderError(e))?; - if &header_info.magic_number != MAGIC_NUMBER { + if &header_info.magic != MAGIC_NUMBER { return Err(Crypt4GHError::MagicStringError); } From 918a8c61f8771957ea68e994711d4a4077d294c0 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 22 Jul 2024 14:06:29 +1000 Subject: [PATCH 26/30] Refactor and flatten decrypt/encrypt modules. Finalise first draft on the direct spec-to-code struct approach (following the structs and their namings defined in the official Crypt4GH spec) --- .../decrypter => decrypt}/builder.rs | 10 +-- .../decrypter => decrypt}/data_block.rs | 4 +- .../decrypter => decrypt}/header/mod.rs | 8 +- .../decrypter => decrypt}/header/packets.rs | 0 src/{decryption/decrypter => decrypt}/mod.rs | 84 +++++++++---------- src/{decryption => decrypt}/reader/builder.rs | 6 +- .../mod.rs => decrypt/reader/decode.rs} | 0 src/{decryption => decrypt}/reader/mod.rs | 15 ++-- src/decryption/mod.rs | 3 - src/edit_lists.rs | 2 +- .../encrypter => encrypt}/builder.rs | 4 +- .../encrypter => encrypt}/data_block.rs | 0 src/{ => encrypt}/encrypted_data.rs | 0 .../encrypter => encrypt}/header/mod.rs | 10 +-- .../encrypter => encrypt}/header/packets.rs | 0 src/{encryption/encrypter => encrypt}/mod.rs | 12 +-- src/encryption/mod.rs | 1 - src/header.rs | 77 ++++++++--------- src/keys.rs | 2 +- src/lib.rs | 13 +-- src/util/mod.rs | 6 +- 21 files changed, 121 insertions(+), 136 deletions(-) rename src/{decryption/decrypter => decrypt}/builder.rs (92%) rename src/{decryption/decrypter => decrypt}/data_block.rs (97%) rename src/{decryption/decrypter => decrypt}/header/mod.rs (81%) rename src/{decryption/decrypter => decrypt}/header/packets.rs (100%) rename src/{decryption/decrypter => decrypt}/mod.rs (88%) rename src/{decryption => decrypt}/reader/builder.rs (94%) rename src/{decryption/decoder/mod.rs => decrypt/reader/decode.rs} (100%) rename src/{decryption => decrypt}/reader/mod.rs (94%) delete mode 100644 src/decryption/mod.rs rename src/{encryption/encrypter => encrypt}/builder.rs (97%) rename src/{encryption/encrypter => encrypt}/data_block.rs (100%) rename src/{ => encrypt}/encrypted_data.rs (100%) rename src/{encryption/encrypter => encrypt}/header/mod.rs (78%) rename src/{encryption/encrypter => encrypt}/header/packets.rs (100%) rename src/{encryption/encrypter => encrypt}/mod.rs (99%) delete mode 100644 src/encryption/mod.rs diff --git a/src/decryption/decrypter/builder.rs b/src/decrypt/builder.rs similarity index 92% rename from src/decryption/decrypter/builder.rs rename to src/decrypt/builder.rs index 8d15686..3751f84 100644 --- a/src/decryption/decrypter/builder.rs +++ b/src/decrypt/builder.rs @@ -3,7 +3,7 @@ use crate::keys::{KeyPair, KeyPairInfo}; use tokio::io::{AsyncRead, AsyncSeek}; use tokio_util::codec::FramedRead; -use crate::decrypter::DecrypterStream; +use crate::decrypt::DecryptStream; use crate::keys::PublicKey; /// An decrypter reader builder. @@ -49,18 +49,18 @@ impl Builder { } /// Build the decrypter. - pub fn build(self, inner: R, keys: Vec) -> DecrypterStream + pub fn build(self, inner: R, keys: Vec) -> DecryptStream where R: AsyncRead, { - DecrypterStream { + DecryptStream { inner: FramedRead::new(inner, Default::default()), header_packet_future: None, keys, sender_pubkey: self.sender_pubkey, session_keys: vec![], encrypted_header_packets: None, - edit_list_packet: DecrypterStream::<()>::create_internal_edit_list(self.edit_list), + edit_list_packet: DecryptStream::<()>::create_internal_edit_list(self.edit_list), header_info: None, header_length: None, current_block_size: None, @@ -79,7 +79,7 @@ impl Builder { self, inner: R, keys: Vec, - ) -> Result, Crypt4GHError> + ) -> Result, Crypt4GHError> where R: AsyncRead + AsyncSeek + Unpin, { diff --git a/src/decryption/decrypter/data_block.rs b/src/decrypt/data_block.rs similarity index 97% rename from src/decryption/decrypter/data_block.rs rename to src/decrypt/data_block.rs index bf289ef..042d93b 100644 --- a/src/decryption/decrypter/data_block.rs +++ b/src/decrypt/data_block.rs @@ -9,7 +9,7 @@ use crate::{body_decrypt, WriteInfo}; use pin_project_lite::pin_project; use tokio::task::JoinHandle; -use crate::decrypter::DecrypterStream; +use crate::decrypt::DecryptStream; use crate::error::Crypt4GHError::{self, JoinHandleError}; pin_project! { @@ -137,7 +137,7 @@ impl DataBlockDecrypter { let mut decrypted_bytes: Bytes = write_buf.into_inner().into(); let mut edited_bytes = Bytes::new(); - let edits = DecrypterStream::<()>::create_internal_edit_list(edit_list_packet) + let edits = DecryptStream::<()>::create_internal_edit_list(edit_list_packet) .unwrap_or(vec![(false, decrypted_bytes.len() as u64)]); if edits.iter().map(|(_, edit)| edit).sum::() > decrypted_bytes.len() as u64 { return Err(Crypt4GHError::InvalidEditList); diff --git a/src/decryption/decrypter/header/mod.rs b/src/decrypt/header/mod.rs similarity index 81% rename from src/decryption/decrypter/header/mod.rs rename to src/decrypt/header/mod.rs index 9f79dda..b9d4f39 100644 --- a/src/decryption/decrypter/header/mod.rs +++ b/src/decrypt/header/mod.rs @@ -4,7 +4,7 @@ use std::task::{Context, Poll}; use tokio::io::AsyncRead; -use crate::decrypter::DecrypterStream; +use crate::decrypt::DecryptStream; use crate::error::Crypt4GHError; pub mod packets; @@ -14,17 +14,17 @@ pub mod packets; /// the session keys. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct SessionKeysFuture<'a, R> { - handle: &'a mut DecrypterStream, + handle: &'a mut DecryptStream, } impl<'a, R> SessionKeysFuture<'a, R> { /// Create the future. - pub fn new(handle: &'a mut DecrypterStream) -> Self { + pub fn new(handle: &'a mut DecryptStream) -> Self { Self { handle } } /// Get the inner handle. - pub fn get_mut(&mut self) -> &mut DecrypterStream { + pub fn get_mut(&mut self) -> &mut DecryptStream { self.handle } } diff --git a/src/decryption/decrypter/header/packets.rs b/src/decrypt/header/packets.rs similarity index 100% rename from src/decryption/decrypter/header/packets.rs rename to src/decrypt/header/packets.rs diff --git a/src/decryption/decrypter/mod.rs b/src/decrypt/mod.rs similarity index 88% rename from src/decryption/decrypter/mod.rs rename to src/decrypt/mod.rs index 4369fec..be7efc7 100644 --- a/src/decryption/decrypter/mod.rs +++ b/src/decrypt/mod.rs @@ -1,6 +1,7 @@ pub mod builder; pub mod data_block; pub mod header; +pub mod reader; use std::cmp::min; use std::io::SeekFrom; @@ -8,7 +9,6 @@ use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; -use crate::header::{EncryptedHeaderPacketBytes, HeaderInfo}; use crate::keys::{KeyPair, KeyPairInfo}; use futures::ready; use futures::Stream; @@ -16,11 +16,9 @@ use pin_project_lite::pin_project; use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt}; use tokio_util::codec::FramedRead; -use crate::decoder::Block; -use crate::decoder::DecodedBlock; -use crate::decrypter::data_block::DataBlockDecrypter; -use crate::decrypter::header::packets::HeaderPacketsDecrypter; -use crate::decrypter::header::SessionKeysFuture; +use crate::decrypt::data_block::DataBlockDecrypter; +use crate::decrypt::header::packets::HeaderPacketsDecrypter; +use crate::decrypt::header::SessionKeysFuture; use crate::error::Crypt4GHError; use crate::{util, keys::PublicKey}; @@ -28,7 +26,7 @@ use futures::Future; pin_project! { /// A decrypter for an entire AsyncRead Crypt4GH file. - pub struct DecrypterStream { + pub struct DecryptStream { #[pin] inner: FramedRead, #[pin] @@ -370,39 +368,39 @@ where } } -// impl DecrypterStream -// where -// R: AsyncRead + AsyncSeek + Unpin + Send, -// { -// /// Seek to a position in the encrypted stream. -// pub async fn seek_encrypted(&mut self, position: SeekFrom) -> io::Result { -// // Make sure that session keys are polled. -// self.read_header().await?; - -// // First poll to the position specified. -// let seek = self.inner.get_mut().seek(position).await?; - -// // Then advance to the correct data block position. -// let advance = self.advance_encrypted(seek).await?; - -// // Then seek to the correct position. -// let seek = self.inner.get_mut().seek(SeekFrom::Start(advance)).await?; -// self.inner.read_buffer_mut().clear(); - -// Ok(seek) -// } - -// /// Seek to a position in the unencrypted stream. -// pub async fn seek_unencrypted(&mut self, position: u64) -> io::Result { -// // Make sure that session keys are polled. -// self.read_header().await?; - -// // Convert to an encrypted position and seek -// let position = self -// .to_encrypted(position) -// .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; - -// // Then do the seek. -// self.seek_encrypted(SeekFrom::Start(position)).await -// } -// } \ No newline at end of file +impl DecrypterStream +where + R: AsyncRead + AsyncSeek + Unpin + Send, +{ + /// Seek to a position in the encrypted stream. + pub async fn seek_encrypted(&mut self, position: SeekFrom) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // First poll to the position specified. + let seek = self.inner.get_mut().seek(position).await?; + + // Then advance to the correct data block position. + let advance = self.advance_encrypted(seek).await?; + + // Then seek to the correct position. + let seek = self.inner.get_mut().seek(SeekFrom::Start(advance)).await?; + self.inner.read_buffer_mut().clear(); + + Ok(seek) + } + + /// Seek to a position in the unencrypted stream. + pub async fn seek_unencrypted(&mut self, position: u64) -> io::Result { + // Make sure that session keys are polled. + self.read_header().await?; + + // Convert to an encrypted position and seek + let position = self + .to_encrypted(position) + .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; + + // Then do the seek. + self.seek_encrypted(SeekFrom::Start(position)).await + } +} \ No newline at end of file diff --git a/src/decryption/reader/builder.rs b/src/decrypt/reader/builder.rs similarity index 94% rename from src/decryption/reader/builder.rs rename to src/decrypt/reader/builder.rs index 250c912..556bf70 100644 --- a/src/decryption/reader/builder.rs +++ b/src/decrypt/reader/builder.rs @@ -5,8 +5,8 @@ use crate::keys::KeyPairInfo; use futures_util::TryStreamExt; use tokio::io::{AsyncRead, AsyncSeek}; -use crate::decrypter::builder::Builder as DecrypterBuilder; -use crate::decrypter::DecrypterStream; +use crate::decrypt::builder::Builder as DecrypterBuilder; +use crate::decrypt::DecryptStream; use crate::keys::PublicKey; use super::Reader; @@ -89,7 +89,7 @@ impl Builder { } /// Build the Crypt4GH reader with a decryper stream. - pub fn build_with_stream(self, stream: DecrypterStream) -> Reader + pub fn build_with_stream(self, stream: DecryptStream) -> Reader where R: AsyncRead, { diff --git a/src/decryption/decoder/mod.rs b/src/decrypt/reader/decode.rs similarity index 100% rename from src/decryption/decoder/mod.rs rename to src/decrypt/reader/decode.rs diff --git a/src/decryption/reader/mod.rs b/src/decrypt/reader/mod.rs similarity index 94% rename from src/decryption/reader/mod.rs rename to src/decrypt/reader/mod.rs index d0fcd5a..d7243c0 100644 --- a/src/decryption/reader/mod.rs +++ b/src/decrypt/reader/mod.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::{cmp, io}; -use crate::decoder::DecodedBlock::HeaderInfo; +use crate::decrypt::reader::decode::DecodedBlock::HeaderInfo; use crate::keys::KeyPairInfo; use futures::ready; use futures::stream::TryBuffered; @@ -11,21 +11,22 @@ use futures::Stream; use pin_project_lite::pin_project; use tokio::io::{AsyncBufRead, AsyncRead, AsyncSeek, ReadBuf}; -use crate::decoder::Block; +use crate::decrypt::reader::decode::Block; use crate::error::Crypt4GHError::{self, NumericConversionError}; -use crate::reader::builder::Builder; +use crate::decrypt::reader::builder::Builder; use crate::{DecryptedDataBlock, header::EncryptedHeaderPacketBytes}; -use super::decrypter::DecrypterStream; +use crate::decrypt::DecryptStream; pub mod builder; +pub(crate) mod decode; pin_project! { pub struct Reader where R: AsyncRead { #[pin] - stream: TryBuffered>, + stream: TryBuffered>, current_block: DecryptedDataBlock, // The current position in the decrypted buffer. buf_position: usize, @@ -116,11 +117,11 @@ where } } -impl From> for Reader +impl From> for Reader where R: AsyncRead, { - fn from(stream: DecrypterStream) -> Self { + fn from(stream: DecryptStream) -> Self { Builder::default().build_with_stream(stream) } } diff --git a/src/decryption/mod.rs b/src/decryption/mod.rs deleted file mode 100644 index 3bc6282..0000000 --- a/src/decryption/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod reader; -pub mod decoder; -pub mod decrypter; \ No newline at end of file diff --git a/src/edit_lists.rs b/src/edit_lists.rs index 6daa8ae..2b694e8 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -6,7 +6,7 @@ use crate::keys::PrivateKey; use tokio::io::AsyncRead; use crate::error::Crypt4GHError; -use crate::reader::Reader; +use crate::decrypt::reader::Reader; use crate::keys::PublicKey; /// Unencrypted byte range positions. Contains inclusive start values and exclusive end values. diff --git a/src/encryption/encrypter/builder.rs b/src/encrypt/builder.rs similarity index 97% rename from src/encryption/encrypter/builder.rs rename to src/encrypt/builder.rs index 4c41f2c..a8736cb 100644 --- a/src/encryption/encrypter/builder.rs +++ b/src/encrypt/builder.rs @@ -1,8 +1,8 @@ -use crypt4gh::Keys; +use crate::keys::Keys; use tokio::io::{AsyncRead, AsyncSeek}; use tokio_util::codec::FramedRead; -use crate::decrypter::DecrypterStream; +use crate::decrypt::DecryptStream; use crate::error::Result; use crate::PublicKey; diff --git a/src/encryption/encrypter/data_block.rs b/src/encrypt/data_block.rs similarity index 100% rename from src/encryption/encrypter/data_block.rs rename to src/encrypt/data_block.rs diff --git a/src/encrypted_data.rs b/src/encrypt/encrypted_data.rs similarity index 100% rename from src/encrypted_data.rs rename to src/encrypt/encrypted_data.rs diff --git a/src/encryption/encrypter/header/mod.rs b/src/encrypt/header/mod.rs similarity index 78% rename from src/encryption/encrypter/header/mod.rs rename to src/encrypt/header/mod.rs index f516309..a0f5d1f 100644 --- a/src/encryption/encrypter/header/mod.rs +++ b/src/encrypt/header/mod.rs @@ -4,8 +4,8 @@ use std::task::{Context, Poll}; use tokio::io::AsyncRead; -use crate::encrypter::EncrypterStream; -use crate::encrypter::Result; +use crate::encrypt::EncrypterStream; +use crate::encrypt::Result; pub mod packets; @@ -14,17 +14,17 @@ pub mod packets; /// the session keys. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct SessionKeysFuture<'a, R> { - handle: &'a mut EncrypterStream, + handle: &'a mut EncryptStream, } impl<'a, R> SessionKeysFuture<'a, R> { /// Create the future. - pub fn new(handle: &'a mut EncrypterStream) -> Self { + pub fn new(handle: &'a mut EncryptStream) -> Self { Self { handle } } /// Get the inner handle. - pub fn get_mut(&mut self) -> &mut EncrypterStream { + pub fn get_mut(&mut self) -> &mut EncryptStream { self.handle } } diff --git a/src/encryption/encrypter/header/packets.rs b/src/encrypt/header/packets.rs similarity index 100% rename from src/encryption/encrypter/header/packets.rs rename to src/encrypt/header/packets.rs diff --git a/src/encryption/encrypter/mod.rs b/src/encrypt/mod.rs similarity index 99% rename from src/encryption/encrypter/mod.rs rename to src/encrypt/mod.rs index be7545b..b79e2cd 100644 --- a/src/encryption/encrypter/mod.rs +++ b/src/encrypt/mod.rs @@ -7,7 +7,7 @@ use std::task::{Context, Poll}; use async_trait::async_trait; use bytes::Bytes; -use crypt4gh::header::HeaderInfo; +use crate::encrypt::header::HeaderInfo; use crypt4gh::Keys; use futures::ready; use futures::Stream; @@ -18,17 +18,17 @@ use tokio_util::codec::FramedRead; use crate::advance::Advance; use crate::decoder::Block; use crate::decoder::DecodedBlock; -use crate::decrypter::data_block::DataBlockDecrypter; -use crate::decrypter::header::packets::HeaderPacketsDecrypter; -use crate::decrypter::header::SessionKeysFuture; -use crate::error::Error::Crypt4GHError; -use crate::error::Result; +use crate::decrypt::data_block::DataBlockDecrypter; +use crate::decrypt::header::packets::HeaderPacketsDecrypter; +use crate::decrypt::header::SessionKeysFuture; +use crate::error::Crypt4GHError; use crate::EncryptedHeaderPacketBytes; use crate::{util, PublicKey}; pub mod builder; pub mod data_block; pub mod header; +pub mod encrypted_data; pin_project! { /// A decrypter for an entire AsyncRead Crypt4GH file. diff --git a/src/encryption/mod.rs b/src/encryption/mod.rs deleted file mode 100644 index 8db6650..0000000 --- a/src/encryption/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod encrypter; \ No newline at end of file diff --git a/src/header.rs b/src/header.rs index 7c3640f..5c8e5ff 100644 --- a/src/header.rs +++ b/src/header.rs @@ -12,11 +12,12 @@ use crypto_kx::{SecretKey, Keypair}; use serde::{Deserialize, Serialize}; -use crate::encrypted_data::SEGMENT_SIZE; +use crate::encrypt::encrypted_data::SEGMENT_SIZE; use crate::error::Crypt4GHError; use crate::keys::EncryptionMethod; use crate::keys::KeyPair; use crate::keys::KeyPairInfo; +use crate::keys::PrivateKey; use crate::keys::PublicKey; const MAGIC_NUMBER: &[u8; 8] = b"crypt4gh"; @@ -42,16 +43,19 @@ enum HeaderPacketType { DataEnc, EditList } -pub enum EncryptedPacketData { - DataEncryptionKey(DataEncryptionKeyPacket), - EditList(EditListPacket) -} +#[derive(Debug)] struct DataEncryptionKeyPacket { encryption_method: u32, data_encryption_key: Vec } +/// Crypt4gh spec §3.2.4 +/// +/// TODO: Enforce this: +/// +/// It is not permitted to have more than one edit list. If more than one edit list is present, the file SHOULD +/// be rejected. struct EditListPacket { number_lengths: u32, lengths: Vec @@ -64,50 +68,41 @@ enum HeaderPacketDataType { DataPacketEncrypted(Vec), } -/// As described in crypt4gh spec §3.2.1 +/// Crypt4gh spec §3.2.1 +/// +/// Conditional settings for writer_public_key/nonce/mac depending on +/// as described in the spec can be selected at runtime #[derive(Debug)] pub struct HeaderPacket { packet_length: u32, encryption_method: EncryptionMethod, - writer_pubkey: PublicKey, + writer_public_key: PublicKey, nonce: Nonce, - encrypted_packet_data: EncryptedPacketData, + encrypted_payload: EncryptedPacketData, mac: Bytes //dalek::Mac type might be more fitting + // TODO: MAC[16] for chacha20_ietf_poly1305 } -// #[derive(Debug)] -// pub struct EncryptedPacketData { -// packet_type: HeaderPacketType, -// packet_data: HeaderPacketDataType -// } -// /// Encodes actual encrypted data from a header packet or an edit list. -// #[derive(Serialize, Deserialize, PartialEq)] -// enum HeaderPacketType { -// DataEnc, -// EditList -// } -// -// /// Data-bearing Header Packet data type as it can hold either depending on packet type -// enum HeaderPacketDataType { -// Packet {DataEncryptionPacket: Vec, EditListPacket: Vec } -// } - -// pub struct EncryptedPacketData { -// packet_type: HeaderPacketType, -// packet_data: HeaderPacketDataType -// } - -// /// This packet contains the parameters needed to decrypt the data part of the file. As described in crypt4gh spec §3.2.3 -// struct DataEncryptionPacket { -// encryption_method: EncryptionMethod, -// data_encryption_key: PrivateKey -// } -// -// /// This packet contains a list of edits that should be applied to the plain-text data following decryption. As described in crypt4gh spec §3.2.4 -// struct EditListPacket { -// number_lengths: Vec, -// lengths: Vec -// } +/// Crypt4gh spec §3.2.2 +#[derive(Debug)] +pub struct EncryptedHeaderPacket { + packet_type: HeaderPacketType, + data_key: Bytes, // TODO: data_key[32] on the spec + // for chacha20_ietf_poly1305 + data_edit_list: EditListPacket, +} + +/// Crypt4gh spec §3.2.3 +/// +/// TODO: Make clear decision on how to enforce this: +/// +/// To allow parts of the data to be encrypted with different Kdata keys, more than one of this packet type may +/// be present. If there is more than one, the data encryption method MUST be the same for all of them to +/// prevent problems with random access in the encrypted file. +struct DataEncryptionPacket { + encryption_method: EncryptionMethod, + data_key: PrivateKey, +} /// Implements all header-related operations described in crypt4gh spec §3.2 and onwards impl Header { diff --git a/src/keys.rs b/src/keys.rs index 4b59af3..2ed875c 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -7,7 +7,7 @@ const SSH_MAGIC_WORD: &[u8; 15] = b"openssh-key-v1\x00"; use crate::error::Crypt4GHError; #[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum EncryptionMethod { +pub enum EncryptionMethod { // TODO: Spec says u32 for this enum, how to encode? X25519Chacha20Poly305, Aes256Gcm } diff --git a/src/lib.rs b/src/lib.rs index 261481a..5f88003 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,23 +21,18 @@ clippy::redundant_else )] -pub mod decoder; -pub mod decrypter; -//pub mod encrypter; +pub mod decrypt; +pub mod encrypt; pub mod edit_lists; -pub mod reader; pub mod util; pub mod header; pub mod keys; -pub mod encrypted_data; pub mod error; use bytes::Bytes; -use decrypter::DecrypterStream; +use crate::decrypt::DecrypterStream; use io::Cursor; use keys::SessionKeys; -use rand::{SeedableRng, RngCore}; -use rand_chacha; use std::collections::HashSet; use std::io::{self, Read, Write}; @@ -48,7 +43,7 @@ use chacha20poly1305::{ self, ChaCha20Poly1305, Key, KeyInit, Nonce }; use crate::error::Crypt4GHError; use crate::header::Header; -use decrypter::data_block::{ DecryptedDataBlock, DecryptedBytes }; +use crate::decrypt::data_block::{ DecryptedDataBlock, DecryptedBytes }; use keys::KeyPairInfo; //use header::{ HeaderInfo, deserialize_header_info }; diff --git a/src/util/mod.rs b/src/util/mod.rs index 8293d47..5e5e38f 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,8 +1,8 @@ use std::cmp::min; -use crate::decoder::Block; -use crate::error::Crypt4GHError; -use crate::keys::{KeyPair, PublicKey}; +use crate::decrypt::reader::decode::Block; +// use crate::error::Crypt4GHError; +// use crate::keys::{KeyPair, PublicKey}; fn to_current_data_block(pos: u64, header_len: u64) -> u64 { header_len + (pos / Block::encrypted_block_size()) * Block::standard_data_block_size() From ab792b549b76505e2bfd2defa8f88476c86f71b3 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Mon, 22 Jul 2024 14:20:55 +1000 Subject: [PATCH 27/30] No 'HeaderInfo' in the spec --- src/decrypt/mod.rs | 8 ++++---- src/decrypt/reader/decode.rs | 12 ++++++------ src/decrypt/reader/mod.rs | 4 ++-- src/edit_lists.rs | 4 ++-- src/encrypt/mod.rs | 10 +++++----- src/error.rs | 2 +- src/lib.rs | 6 +++--- tests/test_decoder.rs | 2 +- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/decrypt/mod.rs b/src/decrypt/mod.rs index be7efc7..ef9f674 100644 --- a/src/decrypt/mod.rs +++ b/src/decrypt/mod.rs @@ -34,7 +34,7 @@ pin_project! { keys: Vec, sender_pubkey: Option, encrypted_header_packets: Option>, - header_info: Option, + header_info: Option
, session_keys: Vec>, edit_list_packet: Option>, header_length: Option, @@ -145,7 +145,7 @@ where let mut this = self.as_mut().project(); match ready!(this.inner.poll_next(cx)) { Some(Ok(buf)) => match buf { - DecodedBlock::HeaderInfo(header_info) => { + DecodedBlock::Header(header_info) => { // Store the header info but otherwise ignore it and poll again. *this.header_info = Some(header_info); cx.waker().wake_by_ref(); @@ -286,7 +286,7 @@ impl DecrypterStream { } /// Get the header info. - pub fn header_info(&self) -> Option<&HeaderInfo> { + pub fn header_info(&self) -> Option<&Header> { self.header_info.as_ref() } @@ -348,7 +348,7 @@ where match ready!(item) { Some(Ok(buf)) => match buf { - DecodedBlock::HeaderInfo(_) | DecodedBlock::HeaderPackets(_) => { + DecodedBlock::Header(_) | DecodedBlock::HeaderPackets(_) => { // Session keys have already been read, so ignore the header info and header packets // and poll again cx.waker().wake_by_ref(); diff --git a/src/decrypt/reader/decode.rs b/src/decrypt/reader/decode.rs index 1d6973f..54ec2ff 100644 --- a/src/decrypt/reader/decode.rs +++ b/src/decrypt/reader/decode.rs @@ -29,7 +29,7 @@ const MAX_HEADER_SIZE: usize = 8 * 1024 * 1024; pub enum DecodedBlock { /// The magic string, version string and header packet count. /// Corresponds to `deconstruct_header_info`. - HeaderInfo(Header), + Header(Header), /// Header packets, both data encryption key packets and a data edit list packets. /// Corresponds to `deconstruct_header_body`. HeaderPackets(HeaderPacket), @@ -42,7 +42,7 @@ pub enum DecodedBlock { #[derive(Debug)] enum BlockState { /// Expecting header info. - HeaderInfo, + Header, /// Expecting header packets and the number of header packets left to decode. HeaderPackets(u32), /// Expecting a data block. @@ -58,7 +58,7 @@ pub struct Block { } impl Block { - fn get_header_info(src: &mut BytesMut) -> Result { + fn get_header_info(src: &mut BytesMut) -> Result { deserialize_header_info( src .split_to(HEADER_INFO_SIZE) @@ -84,7 +84,7 @@ impl Block { self.next_block = BlockState::HeaderPackets(header_info.packets_count); - Ok(Some(DecodedBlock::HeaderInfo(header_info))) + Ok(Some(DecodedBlock::Header(header_info))) } /// Decodes header packets, updates the state and returns a header packet block type. @@ -197,7 +197,7 @@ impl Block { impl Default for Block { fn default() -> Self { Self { - next_block: BlockState::HeaderInfo, + next_block: BlockState::Header, } } } @@ -208,7 +208,7 @@ impl Decoder for Block { fn decode(&mut self, src: &mut BytesMut) -> Result, Crypt4GHError> { match self.next_block { - BlockState::HeaderInfo => self.decode_header_info(src), + BlockState::Header => self.decode_header_info(src), BlockState::HeaderPackets(header_packets) => self.decode_header_packets(src, header_packets), BlockState::DataBlock => self.decode_data_block(src), BlockState::Eof => Ok(None), diff --git a/src/decrypt/reader/mod.rs b/src/decrypt/reader/mod.rs index d7243c0..8d82e7b 100644 --- a/src/decrypt/reader/mod.rs +++ b/src/decrypt/reader/mod.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::{cmp, io}; -use crate::decrypt::reader::decode::DecodedBlock::HeaderInfo; +use crate::decrypt::reader::decode::DecodedBlock::Header; use crate::keys::KeyPairInfo; use futures::ready; use futures::stream::TryBuffered; @@ -89,7 +89,7 @@ where } /// Get the header info. - pub fn header_info(&self) -> Option<&HeaderInfo> { + pub fn header_info(&self) -> Option<&Header> { self.stream.get_ref().header_info() } diff --git a/src/edit_lists.rs b/src/edit_lists.rs index 2b694e8..822a44f 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use crate::header::{encrypt, make_packet_data_edit_list, HeaderInfo}; +use crate::header::{encrypt, make_packet_data_edit_list, Header}; use crate::keys::KeyPairInfo; use crate::keys::PrivateKey; use tokio::io::AsyncRead; @@ -205,7 +205,7 @@ where self.reader.encrypted_header_packets(), ) { ( - HeaderInfo { + Header { magic_number: header_info.magic_number, version: header_info.version, packets_count: header_info.packets_count, diff --git a/src/encrypt/mod.rs b/src/encrypt/mod.rs index b79e2cd..d481801 100644 --- a/src/encrypt/mod.rs +++ b/src/encrypt/mod.rs @@ -7,7 +7,7 @@ use std::task::{Context, Poll}; use async_trait::async_trait; use bytes::Bytes; -use crate::encrypt::header::HeaderInfo; +use crate::encrypt::header::Header; use crypt4gh::Keys; use futures::ready; use futures::Stream; @@ -40,7 +40,7 @@ pin_project! { keys: Vec, sender_pubkey: Option, encrypted_header_packets: Option>, - header_info: Option, + header_info: Option
, session_keys: Vec>, edit_list_packet: Option>, header_length: Option, @@ -151,7 +151,7 @@ where let mut this = self.as_mut().project(); match ready!(this.inner.poll_next(cx)) { Some(Ok(buf)) => match buf { - DecodedBlock::HeaderInfo(header_info) => { + DecodedBlock::Header(header_info) => { // Store the header info but otherwise ignore it and poll again. *this.header_info = Some(header_info); cx.waker().wake_by_ref(); @@ -292,7 +292,7 @@ impl DecrypterStream { } /// Get the header info. - pub fn header_info(&self) -> Option<&HeaderInfo> { + pub fn header_info(&self) -> Option<&Header> { self.header_info.as_ref() } @@ -354,7 +354,7 @@ where match ready!(item) { Some(Ok(buf)) => match buf { - DecodedBlock::HeaderInfo(_) | DecodedBlock::HeaderPackets(_) => { + DecodedBlock::Header(_) | DecodedBlock::HeaderPackets(_) => { // Session keys have already been read, so ignore the header info and header packets // and poll again cx.waker().wake_by_ref(); diff --git a/src/error.rs b/src/error.rs index 6715363..0edb131 100644 --- a/src/error.rs +++ b/src/error.rs @@ -161,7 +161,7 @@ pub enum Crypt4GHError { #[error("converting between numeric types")] NumericConversionError, #[error("Decoding header info error")] - DecodingHeaderInfo, + DecodingHeader, #[error("Decoding header packet error")] DecodingHeaderPacket, #[error("join handle error: `{0}`")] diff --git a/src/lib.rs b/src/lib.rs index 5f88003..ad3a772 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ pub mod keys; pub mod error; use bytes::Bytes; -use crate::decrypt::DecrypterStream; +use crate::decrypt::DecryptStream; use io::Cursor; use keys::SessionKeys; @@ -45,7 +45,7 @@ use crate::header::Header; use crate::decrypt::data_block::{ DecryptedDataBlock, DecryptedBytes }; use keys::KeyPairInfo; -//use header::{ HeaderInfo, deserialize_header_info }; +//use header::{ Header, deserialize_header_info }; const CHUNK_SIZE: usize = 4096; @@ -584,7 +584,7 @@ pub fn rearrange( read_buffer .read_exact(&mut temp_buf) .map_err(|e| Crypt4GHError::ReadHeaderError(e.into()))?; - let header_info: HeaderInfo = deserialize_header_info((&temp_buf).to_vec())?; + let header_info: Header = deserialize_header_info((&temp_buf).to_vec())?; // Calculate header packets let header_packets = (0..header_info.packets_count) diff --git a/tests/test_decoder.rs b/tests/test_decoder.rs index b0c19a1..23e2806 100644 --- a/tests/test_decoder.rs +++ b/tests/test_decoder.rs @@ -19,7 +19,7 @@ pub(crate) mod tests { // Assert that the first block output is a header info with one packet. assert!( - matches!(header_info, DecodedBlock::HeaderInfo(header_info) if header_info.packets_count == 1) + matches!(header_info, DecodedBlock::Header(header_info) if header_info.packets_count == 1) ); } From 0b3f25b22966f8be9997b348d29cb431ed2f0f71 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Wed, 24 Jul 2024 14:21:57 +1000 Subject: [PATCH 28/30] More refactoring, a bit more focus on consolidating different header files and structures --- src/decrypt/header/mod.rs | 41 ------------ src/decrypt/header/packets.rs | 62 ------------------- src/decrypt/mod.rs | 1 + src/decrypt/reader/builder.rs | 3 +- src/header.rs | 113 +++++++++++++++++++++++++++++----- src/keys.rs | 30 +++------ 6 files changed, 106 insertions(+), 144 deletions(-) delete mode 100644 src/decrypt/header/mod.rs delete mode 100644 src/decrypt/header/packets.rs diff --git a/src/decrypt/header/mod.rs b/src/decrypt/header/mod.rs deleted file mode 100644 index b9d4f39..0000000 --- a/src/decrypt/header/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::future::Future; -use std::pin::Pin; -use std::task::{Context, Poll}; - -use tokio::io::AsyncRead; - -use crate::decrypt::DecryptStream; -use crate::error::Crypt4GHError; - -pub mod packets; - -/// A struct which will poll a decrypter stream until the session keys are found. -/// After polling the future, the underlying decrypter stream should have processed -/// the session keys. -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct SessionKeysFuture<'a, R> { - handle: &'a mut DecryptStream, -} - -impl<'a, R> SessionKeysFuture<'a, R> { - /// Create the future. - pub fn new(handle: &'a mut DecryptStream) -> Self { - Self { handle } - } - - /// Get the inner handle. - pub fn get_mut(&mut self) -> &mut DecryptStream { - self.handle - } -} - -impl<'a, R> Future for SessionKeysFuture<'a, R> -where - R: AsyncRead + Unpin, -{ - type Output = Result<(), Crypt4GHError>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.handle.poll_session_keys_unpin(cx) - } -} diff --git a/src/decrypt/header/packets.rs b/src/decrypt/header/packets.rs deleted file mode 100644 index 3631bc1..0000000 --- a/src/decrypt/header/packets.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::future::Future; -use std::pin::Pin; -use std::task::{Context, Poll}; - -use bytes::Bytes; -use crate::header::Header; -use pin_project_lite::pin_project; -use tokio::task::{spawn_blocking, JoinHandle}; - -use crate::error::Crypt4GHError::{self, JoinHandleError}; -use crate::keys::{KeyPairInfo, PublicKey}; - -pin_project! { - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct HeaderPacketsDecrypter { - #[pin] - handle: JoinHandle> - } -} - - -/// FIXME: This should be probably moved to header.rs along with header as it only concerns Header ops? -/// Since packets are not data blocks I think that for clarity it does not deserve its own file, but -/// belongs to header.rs instead. -impl HeaderPacketsDecrypter { - pub fn new( - header_packets: Vec, - keys: Vec, - sender_pubkey: Option, - ) -> Self { - Self { - handle: spawn_blocking(|| { - HeaderPacketsDecrypter::decrypt(header_packets, keys, sender_pubkey) - }), - } - } - - pub fn decrypt( - header_packets: Vec, - keys: Vec, - sender_pubkey: Option, - ) -> Result { - let header = Header::new_from_bytes(header_packets.as_slice()); - - Ok(header.deserialize( - header_packets - .into_iter() - .map(|bytes| bytes.to_vec()) - .collect(), - keys.as_slice(), - &sender_pubkey.map(|pubkey| pubkey.into_inner()) - )) - } -} - -impl Future for HeaderPacketsDecrypter { - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.project().handle.poll(cx).map_err(JoinHandleError)? - } -} \ No newline at end of file diff --git a/src/decrypt/mod.rs b/src/decrypt/mod.rs index ef9f674..4a3ba52 100644 --- a/src/decrypt/mod.rs +++ b/src/decrypt/mod.rs @@ -9,6 +9,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; +use reader::decode::Block; use crate::keys::{KeyPair, KeyPairInfo}; use futures::ready; use futures::Stream; diff --git a/src/decrypt/reader/builder.rs b/src/decrypt/reader/builder.rs index 556bf70..d9f8fd5 100644 --- a/src/decrypt/reader/builder.rs +++ b/src/decrypt/reader/builder.rs @@ -2,6 +2,7 @@ use std::thread; use crate::error::Crypt4GHError; use crate::keys::KeyPairInfo; +use futures::Stream; use futures_util::TryStreamExt; use tokio::io::{AsyncRead, AsyncSeek}; @@ -76,7 +77,7 @@ impl Builder { /// Build the reader and compute the stream length for seek operations. pub async fn build_with_stream_length(self, inner: R, keys: Vec) -> Result, Crypt4GHError> where - R: AsyncRead + AsyncSeek + Unpin, + R: AsyncRead + AsyncSeek + Unpin + Stream, { let stream_length = self.stream_length; let mut reader = self.build_with_reader(inner, keys); diff --git a/src/header.rs b/src/header.rs index 5c8e5ff..47a0385 100644 --- a/src/header.rs +++ b/src/header.rs @@ -12,13 +12,18 @@ use crypto_kx::{SecretKey, Keypair}; use serde::{Deserialize, Serialize}; +use crate::decrypt; +use crate::encrypt; use crate::encrypt::encrypted_data::SEGMENT_SIZE; +use crate::encrypt::header; use crate::error::Crypt4GHError; +use crate::keys; use crate::keys::EncryptionMethod; use crate::keys::KeyPair; use crate::keys::KeyPairInfo; use crate::keys::PrivateKey; use crate::keys::PublicKey; +use crate::keys::SessionKeys; const MAGIC_NUMBER: &[u8; 8] = b"crypt4gh"; const VERSION: u32 = 1; @@ -78,7 +83,7 @@ pub struct HeaderPacket { encryption_method: EncryptionMethod, writer_public_key: PublicKey, nonce: Nonce, - encrypted_payload: EncryptedPacketData, + encrypted_payload: Bytes, mac: Bytes //dalek::Mac type might be more fitting // TODO: MAC[16] for chacha20_ietf_poly1305 } @@ -104,6 +109,81 @@ struct DataEncryptionPacket { data_key: PrivateKey, } + +/// FIXME: (MOVED from packets.rs) This should be probably moved to header.rs along with header as it only concerns Header ops? +/// Since packets are not data blocks I think that for clarity it does not deserve its own file, but +/// belongs to header.rs instead. + +/// A struct which will poll a decrypter stream until the session keys are found. +/// After polling the future, the underlying decrypter stream should have processed +/// the session keys. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct SessionKeysFuture<'a, R> { + handle: &'a mut DecryptStream, +} + +impl<'a, R> SessionKeysFuture<'a, R> { + /// Create the future. + pub fn new(handle: &'a mut DecryptStream) -> Self { + Self { handle } + } + + /// Get the inner handle. + pub fn get_mut(&mut self) -> &mut DecryptStream { + self.handle + } +} + +impl<'a, R> Future for SessionKeysFuture<'a, R> +where + R: AsyncRead + Unpin, +{ + type Output = Result<(), Crypt4GHError>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.handle.poll_session_keys_unpin(cx) + } +} + +impl HeaderPacketsDecrypter { + pub fn new( + header_packets: Vec, + keys: Vec, + sender_pubkey: Option, + ) -> Self { + Self { + handle: spawn_blocking(|| { + HeaderPacketsDecrypter::decrypt(header_packets, keys, sender_pubkey) + }), + } + } + + pub fn decrypt( + header_packets: Vec, + keys: Vec, + sender_pubkey: Option, + ) -> Result { + let header = Header::new_from_bytes(header_packets.as_slice()); + + Ok(header.deserialize( + header_packets + .into_iter() + .map(|bytes| bytes.to_vec()) + .collect(), + keys.as_slice(), + &sender_pubkey.map(|pubkey| pubkey.into_inner()) + )) + } + } + + impl Future for HeaderPacketsDecrypter { + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().handle.poll(cx).map_err(JoinHandleError)? + } + } + /// Implements all header-related operations described in crypt4gh spec §3.2 and onwards impl Header { pub fn new() -> Self { @@ -212,7 +292,7 @@ impl Header { keys.iter() .filter(|key| key.method == 0) .map( - |key| match encrypt_x25519_chacha20_poly1305(packet, &key.privkey, &key.recipient_pubkey) { + |key| match Self::encrypt_x25519_chacha20_poly1305(packet, &key.privkey, &key.recipient_pubkey) { Ok(session_key) => Ok(vec![u32::from(key.method).to_le_bytes().to_vec(), session_key].concat()), Err(e) => Err(e), }, @@ -270,7 +350,7 @@ impl Header { let mut ignored_packets = Vec::new(); for packet in encrypted_packets { - match decrypt_packet(&packet, keys, sender_pubkey) { + match Self::decrypt_packet(&packet, keys, sender_pubkey) { Ok(decrypted_packet) => decrypted_packets.push(decrypted_packet), Err(e) => { log::warn!("Ignoring packet because: {}", e); @@ -295,7 +375,7 @@ impl Header { match packet_encryption_method { 0 => { - let plaintext_packet = decrypt_x25519_chacha20_poly1305(&packet[4..], &key.privkey, sender_pubkey); + let plaintext_packet = Self::decrypt_x25519_chacha20_poly1305(&packet[4..], &key.privkey, sender_pubkey); //log::debug!("Decrypting packet: {:?}\n into plaintext packet: {:?}\n", &packet[8..], &plaintext_packet); return plaintext_packet; }, @@ -348,7 +428,7 @@ impl Header { Ok(plaintext) } - fn partition_packets(packets: Vec>) -> Result { + fn partition_packets(packets: Vec>) -> Result, Crypt4GHError> { let mut enc_packets = Vec::new(); let mut edits = None; @@ -409,32 +489,31 @@ impl Header { keys: &[KeyPairInfo], sender_pubkey: &Option>, ) -> Result, Crypt4GHError> { - let (packets, _) = decrypt(encrypted_packets, keys, sender_pubkey); + let (packets, _) = decrypt(encrypted_packets, keys, sender_pubkey)?; if packets.is_empty() { return Err(Crypt4GHError::NoSupportedEncryptionMethod); } - let HeaderPackets { + let Vec { data_enc_packets, edit_list_packet, - } = partition_packets(packets)?; + } = Self::partition_packets(packets)?; let session_keys = data_enc_packets .into_iter() - .map(|d| parse_enc_packet(&d)) + .map(|d| Self::parse_enc_packet(&d)) .collect::, Crypt4GHError>>()?; let edit_list = match edit_list_packet { - Some(packet) => Some(parse_edit_list_packet(&packet)?), + Some(packet) => Some(Self::parse_edit_list_packet(&packet)?), None => None, }; - todo!() - // Ok(Vec { - // data_enc_packets: session_keys, - // edit_list_packet: edit_list, - // }) + Ok(Vec { + data_enc_packets: session_keys, + edit_list_packet: edit_list, + }) } @@ -450,7 +529,7 @@ impl Header { ) -> Result { log::info!("Reencrypting the header"); - let (decrypted_packets, mut ignored_packets) = decrypt(header_packets, keys, &None); + let (decrypted_packets, mut ignored_packets) = decrypt(header_packets, keys, &None)?; if decrypted_packets.is_empty() { Err(Crypt4GHError::NoValidHeaderPacket) @@ -502,7 +581,7 @@ impl Header { return Err(Crypt4GHError::Done); } - let (decrypted_packets, _) = decrypt(header_packets, &keys, sender_pubkey); + let (decrypted_packets, _) = decrypt(header_packets, &keys, sender_pubkey)?; if decrypted_packets.is_empty() { return Err(Crypt4GHError::NoValidHeaderPacket); diff --git a/src/keys.rs b/src/keys.rs index 2ed875c..cf57636 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -14,14 +14,14 @@ pub enum EncryptionMethod { // TODO: Spec says u32 for this enum, how to encode? #[derive(Debug, PartialEq, Eq, Hash, Clone)] /// Key information. -pub struct KeyPairInfo { +pub struct KeyPair { /// Method used for the key encryption. /// > Only method 0 is supported. pub method: EncryptionMethod, /// Secret key of the encryptor / decryptor (your key). - pub privkey: PrivateKey, + pub private_key: PrivateKey, /// Public key of the recipient (the key you want to encrypt for). - pub recipient_pubkey: PublicKey, + pub public_key: PublicKey, } pub struct SessionKeys { @@ -40,17 +40,12 @@ pub struct PublicKey { pub bytes: Vec, } -/// A key pair containing a public and private key. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct KeyPair { - private_key: PrivateKey, - public_key: PublicKey, -} impl KeyPair { /// Create a new key pair. - pub fn new(private_key: PrivateKey, public_key: PublicKey) -> Self { + pub fn new(method: EncryptionMethod, private_key: PrivateKey, public_key: PublicKey) -> Self { Self { + method, private_key, public_key, } @@ -97,23 +92,12 @@ impl PublicKey { /// Generate a private and public key pair. pub fn generate_key_pair() -> Result { - // Todo, very janky, avoid writing this to a file first. - //let temp_dir = TempDir::new().map_err(|err| Crypt4GHError::NoTempFiles(err.to_string()))?; - + let method = EncryptionMethod::X25519Chacha20Poly305(); let private_key = PrivateKey::new(); let public_key = PublicKey::new(); - // generate_keys( - // private_key.clone(), - // public_key.clone(), - // Ok("".to_string()), - // None, - // ); - - // let private_key = get_private_key(private_key, Ok("".to_string()))?; - // let public_key = get_public_key(public_key)?; - Ok(KeyPair::new( + method, private_key, public_key )) From 948033f5bff9a964a5cde95d684e0a316e03e201 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 26 Jul 2024 12:00:30 +1000 Subject: [PATCH 29/30] KeyPairInfo is no more, simplify to just KeyPair, consolidate different types of headers in toplevel headers.rs too --- src/decrypt/builder.rs | 17 +++++++++-------- src/decrypt/mod.rs | 12 +++++------- src/edit_lists.rs | 14 +++----------- src/encrypt/header/packets.rs | 16 ++++++---------- src/header.rs | 4 ---- 5 files changed, 23 insertions(+), 40 deletions(-) diff --git a/src/decrypt/builder.rs b/src/decrypt/builder.rs index 3751f84..ee7ea3c 100644 --- a/src/decrypt/builder.rs +++ b/src/decrypt/builder.rs @@ -1,5 +1,5 @@ use crate::error::Crypt4GHError; -use crate::keys::{KeyPair, KeyPairInfo}; +use crate::keys::KeyPair; use tokio::io::{AsyncRead, AsyncSeek}; use tokio_util::codec::FramedRead; @@ -49,7 +49,7 @@ impl Builder { } /// Build the decrypter. - pub fn build(self, inner: R, keys: Vec) -> DecryptStream + pub fn build(self, inner: R, keys: Vec) -> DecryptStream where R: AsyncRead, { @@ -78,17 +78,18 @@ impl Builder { pub async fn build_with_stream_length( self, inner: R, - keys: Vec, + keys: Vec, ) -> Result, Crypt4GHError> where R: AsyncRead + AsyncSeek + Unpin, { - let stream_length = self.stream_length; - let mut stream = self.build(inner, keys); + //let stream_length = self.stream_length; + let stream = self.build(inner, keys); - if stream_length.is_none() { - stream.recompute_stream_length().await?; - } + // FIXME: Why is calculating stream "length" necessary? + // if stream_length.is_none() { + // stream.recompute_stream_length().await?; + // } Ok(stream) } diff --git a/src/decrypt/mod.rs b/src/decrypt/mod.rs index 4a3ba52..67624d0 100644 --- a/src/decrypt/mod.rs +++ b/src/decrypt/mod.rs @@ -1,6 +1,5 @@ pub mod builder; pub mod data_block; -pub mod header; pub mod reader; use std::cmp::min; @@ -9,8 +8,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; -use reader::decode::Block; -use crate::keys::{KeyPair, KeyPairInfo}; +use reader::decode::{Block, DecodedBlock}; use futures::ready; use futures::Stream; use pin_project_lite::pin_project; @@ -18,9 +16,9 @@ use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt}; use tokio_util::codec::FramedRead; use crate::decrypt::data_block::DataBlockDecrypter; -use crate::decrypt::header::packets::HeaderPacketsDecrypter; -use crate::decrypt::header::SessionKeysFuture; use crate::error::Crypt4GHError; +use crate::header::Header; +use crate::keys::KeyPair; use crate::{util, keys::PublicKey}; use futures::Future; @@ -32,7 +30,7 @@ pin_project! { inner: FramedRead, #[pin] header_packet_future: Option, - keys: Vec, + keys: Vec, sender_pubkey: Option, encrypted_header_packets: Option>, header_info: Option
, @@ -44,7 +42,7 @@ pin_project! { } } -impl DecrypterStream +impl DecryptStream where R: AsyncRead, { diff --git a/src/edit_lists.rs b/src/edit_lists.rs index 822a44f..fa9bdf8 100644 --- a/src/edit_lists.rs +++ b/src/edit_lists.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; -use crate::header::{encrypt, make_packet_data_edit_list, Header}; -use crate::keys::KeyPairInfo; +use crate::keys::KeyPair; +use crate::header::Header; use crate::keys::PrivateKey; use tokio::io::AsyncRead; @@ -51,14 +51,6 @@ impl ClampedPosition { } } -/// Bytes representing a header packet with an edit list. -#[derive(Debug, Clone)] -pub struct Header { - header_info: Vec, - original_header: Vec, - edit_list_packet: Vec, -} - impl Header { pub fn new(header_info: Vec, original_header: Vec, edit_list_packet: Vec) -> Self { Self { @@ -125,7 +117,7 @@ where /// Encrypt the edit list packet. pub fn encrypt_edit_list(&self, edit_list_packet: Vec) -> Result, Crypt4GHError> { - let keys = KeyPairInfo { + let keys = KeyPair{ method: 0, privkey: self.private_key.clone().0, recipient_pubkey: self.recipient_public_key.clone().into_inner(), diff --git a/src/encrypt/header/packets.rs b/src/encrypt/header/packets.rs index 69ba5bc..cad60e0 100644 --- a/src/encrypt/header/packets.rs +++ b/src/encrypt/header/packets.rs @@ -3,27 +3,23 @@ use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; -use crypt4gh::header::{deconstruct_header_body, DecryptedHeaderPackets}; -use crypt4gh::Keys; +use crate::header::{deconstruct_header_body, DecryptedHeaderPackets}; +use crate::keys::{KeyPair, PublicKey}; use pin_project_lite::pin_project; use tokio::task::{spawn_blocking, JoinHandle}; -use crate::error::Error::JoinHandleError; -use crate::error::Result; -use crate::PublicKey; - pin_project! { #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct HeaderPacketsDecrypter { + pub struct HeaderPacketsDecrypt { #[pin] handle: JoinHandle> } } -impl HeaderPacketsDecrypter { +impl HeaderPacketsDecrypt { pub fn new( header_packets: Vec, - keys: Vec, + keys: KeyPair, sender_pubkey: Option, ) -> Self { Self { @@ -68,7 +64,7 @@ mod tests { let (recipient_private_key, sender_public_key, header_packets, _) = get_first_header_packet().await; - let data = HeaderPacketsDecrypter::new( + let data = HeaderPacketsDecrypt::new( header_packets, vec![recipient_private_key], Some(PublicKey::new(sender_public_key)), diff --git a/src/header.rs b/src/header.rs index 47a0385..30130d3 100644 --- a/src/header.rs +++ b/src/header.rs @@ -110,10 +110,6 @@ struct DataEncryptionPacket { } -/// FIXME: (MOVED from packets.rs) This should be probably moved to header.rs along with header as it only concerns Header ops? -/// Since packets are not data blocks I think that for clarity it does not deserve its own file, but -/// belongs to header.rs instead. - /// A struct which will poll a decrypter stream until the session keys are found. /// After polling the future, the underlying decrypter stream should have processed /// the session keys. From 48825613d584fd0e2a2407fd2b7990bda4dd42f9 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Fri, 26 Jul 2024 13:42:32 +1000 Subject: [PATCH 30/30] Remove all tests, too much noise and there's heavy API changes that will break most of them anyway. Will re-add them later --- src/bin.rs | 280 --------- src/cli.rs | 93 --- src/decrypt/reader/builder.rs | 18 +- src/decrypt/reader/decode.rs | 11 +- src/encrypt/data_block.rs | 42 +- src/encrypt/header/mod.rs | 12 +- src/encrypt/header/packets.rs | 41 +- src/encrypt/mod.rs | 908 +----------------------------- src/error.rs | 4 +- src/lib.rs | 2 +- tests/README.md | 49 -- tests/edit_list_gen.rs | 89 --- tests/test_common.rs | 256 --------- tests/test_data_block.rs | 40 -- tests/test_decoder.rs | 171 ------ tests/test_decrypter.rs | 879 ----------------------------- tests/test_edit_list.rs | 96 ---- tests/test_full_file.rs | 164 ------ tests/test_header.rs | 21 - tests/test_header_packets.rs | 0 tests/test_keygen.rs | 56 -- tests/test_keygen_length.rs | 48 -- tests/test_keys.rs | 54 -- tests/test_multiple_recipients.rs | 114 ---- tests/test_reader.rs | 520 ----------------- tests/test_segments.rs | 143 ----- tests/test_util.rs | 82 --- tests/testfiles/alice.pub | 3 - tests/testfiles/alice.sec | 3 - tests/testfiles/bob.pub | 3 - tests/testfiles/bob.sec | 3 - tests/testfiles/testfile.abbbc | 1 - tests/testfiles/testfile.abcd | 1 - 33 files changed, 46 insertions(+), 4161 deletions(-) delete mode 100644 src/bin.rs delete mode 100644 src/cli.rs delete mode 100644 tests/README.md delete mode 100644 tests/edit_list_gen.rs delete mode 100644 tests/test_common.rs delete mode 100644 tests/test_data_block.rs delete mode 100644 tests/test_decoder.rs delete mode 100644 tests/test_decrypter.rs delete mode 100644 tests/test_edit_list.rs delete mode 100644 tests/test_full_file.rs delete mode 100644 tests/test_header.rs delete mode 100644 tests/test_header_packets.rs delete mode 100644 tests/test_keygen.rs delete mode 100644 tests/test_keygen_length.rs delete mode 100644 tests/test_keys.rs delete mode 100644 tests/test_multiple_recipients.rs delete mode 100644 tests/test_reader.rs delete mode 100644 tests/test_segments.rs delete mode 100644 tests/test_util.rs delete mode 100644 tests/testfiles/alice.pub delete mode 100644 tests/testfiles/alice.sec delete mode 100644 tests/testfiles/bob.pub delete mode 100644 tests/testfiles/bob.sec delete mode 100644 tests/testfiles/testfile.abbbc delete mode 100644 tests/testfiles/testfile.abcd diff --git a/src/bin.rs b/src/bin.rs deleted file mode 100644 index d2fe831..0000000 --- a/src/bin.rs +++ /dev/null @@ -1,280 +0,0 @@ -#![allow( - clippy::missing_errors_doc, - clippy::missing_panics_doc, - clippy::module_name_repetitions, - clippy::must_use_candidate, - clippy::cast_possible_truncation, - clippy::similar_names, - clippy::implicit_hasher, - clippy::redundant_else -)] - -use std::collections::HashSet; -use std::fs::remove_file; -use std::io; -use std::io::stdin; -use std::path::{Path, PathBuf}; - -use clap::Parser; -use cli::{Args, Command}; -use crypt4gh::error::Crypt4GHError; -use crypt4gh::keys::{get_private_key, get_public_key}; -use crypt4gh::{self, keys, Keys}; -use regex::Regex; -use rpassword::prompt_password; - -mod cli; - -const PASSPHRASE: &str = "C4GH_PASSPHRASE"; - -fn parse_range(arg: Option) -> Result<(usize, Option), Crypt4GHError> { - match arg { - Some(range) => { - // Capture regex - let range_regex = Regex::new(r"(?P[\d]+)-?(?P[\d]+)?").expect("Bad range regex"); - - match range_regex.captures(&range) { - Some(matched_range) => { - // Get start - let range_start = matched_range - .name("start") - .ok_or(Crypt4GHError::ParseRangeError)? - .as_str() - .parse::() - .map_err(|_| Crypt4GHError::ParseRangeError)?; - - // Get span - let range_span = match matched_range.name("end") { - Some(end) => { - let range_end = end - .as_str() - .parse::() - .map_err(|_| Crypt4GHError::ParseRangeError)?; - - if range_start >= range_end { - return Err(Crypt4GHError::ParseRangeError); - } - - Some(range_end - range_start - 1) - }, - None => None, - }; - - Ok((range_start, range_span)) - }, - None => Err(Crypt4GHError::ParseRangeError), - } - }, - None => Ok((0, None)), - } -} - -fn retrieve_private_key(sk: Option, generate: bool) -> Result, Crypt4GHError> { - let seckey_path = sk; - - if generate && seckey_path.is_none() { - let skey = keys::generate_private_key()?; - log::info!("Generating Private Key: {:02x?}", skey); - Ok(skey) - } - else { - let path = seckey_path.expect("Unable to extract the secret key"); - if !path.is_file() { - return Err(Crypt4GHError::ReadSecretKeyFileError(path)); - } - - let passphrase: Result = match std::env::var(PASSPHRASE) { - Ok(_) => { - log::warn!("Warning: Using a passphrase in an environment variable is insecure"); - std::env::var(PASSPHRASE).map_err(|e| Crypt4GHError::NoPassphrase(e.into())) // TODO: Does this make sure it's set/unset? - }, - Err(_) => { - prompt_password(format!("Passphrase for {:?}: ", path)) - .map_err(|e| Crypt4GHError::NoPassphrase(e.into())) - }, - }; - - get_private_key(path.to_owned(), passphrase) - } -} - -fn build_recipients(recipient_pk: &[PathBuf], sk: &[u8]) -> Result, Crypt4GHError> { - if recipient_pk.is_empty() { - Err(Crypt4GHError::NoRecipients) - } - else { - recipient_pk - .iter() - .filter(|&pk| Path::new(pk).exists()) - .map(|pk| { - Ok(Keys { - method: 0, - privkey: sk.to_vec(), - recipient_pubkey: get_public_key(PathBuf::from(pk))?, - }) - }) - .collect() - } -} - -fn run_encrypt(sk: Option, recipient_pk: &[PathBuf], range: Option) -> Result<(), Crypt4GHError> { - let (range_start, range_span) = parse_range(range)?; - let seckey = retrieve_private_key(sk, true)?; - let recipient_keys = build_recipients(recipient_pk, &seckey)?; - - if recipient_keys.is_empty() { - return Err(Crypt4GHError::NoRecipients); - } - - crypt4gh::encrypt( - &recipient_keys, - &mut io::stdin(), - &mut io::stdout(), - range_start, - range_span, - ) -} - -fn run_decrypt(sk: Option, sender_pk: Option, range: Option) -> Result<(), Crypt4GHError> { - let sender_pubkey = match sender_pk { - Some(path) => Some(keys::get_public_key(path)?), - None => None, - }; - - let (range_start, range_span) = parse_range(range)?; - - let seckey = retrieve_private_key(sk, false)?; - - let keys = vec![Keys { - method: 0, - privkey: seckey, - recipient_pubkey: vec![], - }]; - - //log::debug!("run_decrypt()'s parameters: {:#?}, {}, {:#?}, {:#?}", &keys, range_start, range_span, &sender_pubkey ); - - crypt4gh::decrypt( - &keys, - &mut io::stdin(), - &mut io::stdout(), - range_start, - range_span, - &sender_pubkey, - ) -} - -fn run_rearrange(sk: Option, range: Option) -> Result<(), Crypt4GHError> { - let (range_start, range_span) = parse_range(range)?; - let seckey = retrieve_private_key(sk, false)?; - let pubkey = keys::get_public_key_from_private_key(&seckey)?; - - let keys = vec![Keys { - method: 0, - privkey: seckey, - recipient_pubkey: pubkey, - }]; - - crypt4gh::rearrange(keys, &mut io::stdin(), &mut io::stdout(), range_start, range_span) -} - -fn run_reencrypt(sk: Option, recipient_pk: &[PathBuf], trim: bool) -> Result<(), Crypt4GHError> { - let seckey = retrieve_private_key(sk, false)?; - let recipient_keys = build_recipients(recipient_pk, &seckey)?; - - if recipient_keys.is_empty() { - return Err(Crypt4GHError::NoRecipients); - } - - let keys = vec![Keys { - method: 0, - privkey: seckey, - recipient_pubkey: vec![], - }]; - - crypt4gh::reencrypt(&keys, &recipient_keys, &mut io::stdin(), &mut io::stdout(), trim) -} - -fn run_keygen(sk: PathBuf, pk: PathBuf, comment: Option, nocrypt: bool, force: bool) -> Result<(), Crypt4GHError> { - // Prepare key files - - let seckey = sk; - let pubkey = pk; - - for key in &[seckey.to_owned(), pubkey.to_owned()] { - // If key exists and it is a file - if key.is_file() { - // Force overwrite? - if !force { - eprint!("{} already exists. Do you want to overwrite it? (y/n): ", key.display()); - let mut input = String::new(); - stdin() - .read_line(&mut input) - .map_err(|e| Crypt4GHError::NotEnoughInput(1, e.into()))?; - if input.trim() != "y" { - log::info!("Ok. Exiting."); - return Ok(()); - } - } - remove_file(key).unwrap_or_else(|_| panic!("Unable to remove key file (ERROR = {:?})", key)); - } - } - - // Comment - let comment = comment; - let do_crypt = !nocrypt; - let seckey_display = PathBuf::from(&seckey); - - let passphrase = { - if do_crypt { - prompt_password(format!("Passphrase for {}: ", seckey_display.display())) - .map_err(|e| Crypt4GHError::NoPassphrase(e.into())) - - } else { - Ok(String::new()) - } - }; - - crypt4gh::keys::generate_keys(seckey, pubkey, passphrase, comment) -} - -fn run() -> Result<(), Crypt4GHError> { - let matches = Args::parse(); - - if std::env::var("RUST_LOG").is_err() { - if matches.verbose { - std::env::set_var("RUST_LOG", "trace"); - } - else { - std::env::set_var("RUST_LOG", "warn"); - } - } - - pretty_env_logger::init(); - - match matches.subcommand { - Command::Encrypt { - sk, - recipient_pk, - range, - } => run_encrypt(sk, &recipient_pk, range)?, - Command::Decrypt { sk, sender_pk, range } => run_decrypt(sk, sender_pk, range)?, - Command::Rearrange { sk, range } => run_rearrange(sk, range)?, - Command::Reencrypt { sk, recipient_pk, trim } => run_reencrypt(sk, &recipient_pk, trim)?, - Command::Keygen { - sk, - pk, - comment, - nocrypt, - force, - } => run_keygen(sk, pk, comment, nocrypt, force)?, - } - - Ok(()) -} - -fn main() { - if let Err(err) = run() { - log::error!("{}", err); - std::process::exit(1); - } -} diff --git a/src/cli.rs b/src/cli.rs deleted file mode 100644 index 0fd5782..0000000 --- a/src/cli.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::path::PathBuf; - -use clap::Subcommand; - -#[derive(Subcommand)] -pub enum Command { - /// Encrypts the input using your (optional) secret key and the public key of the recipient. - Encrypt { - /// Curve25519-based Private key - #[clap(long, env = "C4GH_SECRET_KEY")] - sk: Option, - - /// Recipient's Curve25519-based Public key - #[clap(long = "recipient_pk", num_args = 1..)] - recipient_pk: Vec, - - /// Byte-range either as or just (Start included, End excluded) - #[clap(long)] - range: Option, - }, - /// Decrypts the input using your secret key and the (optional) public key of the sender. - Decrypt { - /// Curve25519-based Private key - #[clap(long, env = "C4GH_SECRET_KEY")] - sk: Option, - - /// Peer's Curve25519-based Public key to verify provenance (akin to signature) - #[clap(long)] - sender_pk: Option, - - /// Byte-range either as or just (Start included, End excluded) - #[clap(long)] - range: Option, - }, - /// Rearranges the input according to the edit list packet. - Rearrange { - /// Curve25519-based Private key - #[clap(long, env = "C4GH_SECRET_KEY")] - sk: Option, - - /// Byte-range either as or just (Start included, End excluded) - #[clap(long)] - range: Option, - }, - /// Decrypts the input using your (optional) secret key and then it reencrypts it using the public key of the recipient. - Reencrypt { - /// Curve25519-based Private key - #[clap(long, env = "C4GH_SECRET_KEY")] - sk: Option, - - /// Recipient's Curve25519-based Public key - #[clap(long = "recipient_pk", num_args = 1..)] - recipient_pk: Vec, - - /// Keep only header packets that you can decrypt - #[clap(short, long)] - trim: bool, - }, - /// Utility to create Crypt4GH-formatted keys. - Keygen { - /// Curve25519-based Private key - #[clap(long, env, default_value = "~/.c4gh/key")] - sk: PathBuf, - - /// Curve25519-based Public key - #[clap(long, env, default_value = "~/.c4gh/key.pub")] - pk: PathBuf, - - /// Key's Comment - #[clap(short, long)] - comment: Option, - - /// Do not encrypt the private key. Otherwise it is encrypted in the Crypt4GH key format (See https://crypt4gh.readthedocs.io/en/latest/keys.html) - #[clap(long)] - nocrypt: bool, - - /// Overwrite the destination files - #[clap(short, long)] - force: bool, - }, -} - -/// Utility for the cryptographic GA4GH standard, reading from stdin and outputting to stdout. -#[derive(clap::Parser)] -#[clap(about, version, author)] -pub struct Args { - /// Sets the level of verbosity - #[clap(short, long)] - pub verbose: bool, - - #[clap(subcommand)] - pub subcommand: Command, -} diff --git a/src/decrypt/reader/builder.rs b/src/decrypt/reader/builder.rs index d9f8fd5..96be66e 100644 --- a/src/decrypt/reader/builder.rs +++ b/src/decrypt/reader/builder.rs @@ -1,14 +1,13 @@ use std::thread; use crate::error::Crypt4GHError; -use crate::keys::KeyPairInfo; use futures::Stream; use futures_util::TryStreamExt; use tokio::io::{AsyncRead, AsyncSeek}; use crate::decrypt::builder::Builder as DecrypterBuilder; use crate::decrypt::DecryptStream; -use crate::keys::PublicKey; +use crate::keys::{KeyPair, PublicKey}; use super::Reader; @@ -55,7 +54,7 @@ impl Builder { } /// Build the Crypt4GH reader. - pub fn build_with_reader(self, inner: R, keys: Vec) -> Reader + pub fn build_with_reader(self, inner: R, keys: Vec) -> Reader where R: AsyncRead, { @@ -75,16 +74,17 @@ impl Builder { } /// Build the reader and compute the stream length for seek operations. - pub async fn build_with_stream_length(self, inner: R, keys: Vec) -> Result, Crypt4GHError> + pub async fn build_with_stream_length(self, inner: R, keys: Vec) -> Result, Crypt4GHError> where R: AsyncRead + AsyncSeek + Unpin + Stream, { - let stream_length = self.stream_length; - let mut reader = self.build_with_reader(inner, keys); + //let stream_length = self.stream_length; + let reader = self.build_with_reader(inner, keys); - if stream_length.is_none() { - reader.stream.get_mut().recompute_stream_length().await?; - } + // FIXME: Why do we need to determine a stream length? + // if stream_length.is_none() { + // reader.stream.get_mut().recompute_stream_length().await?; + // } Ok(reader) } diff --git a/src/decrypt/reader/decode.rs b/src/decrypt/reader/decode.rs index 54ec2ff..75b52eb 100644 --- a/src/decrypt/reader/decode.rs +++ b/src/decrypt/reader/decode.rs @@ -4,7 +4,7 @@ use bytes::{Bytes, BytesMut}; use tokio_util::codec::Decoder; use crate::{error::Crypt4GHError::{ - self, MaximumHeaderSize, NumericConversionError, SliceConversionError + self, NumericConversionError, SliceConversionError }, header::HeaderPacket, header::Header}; pub const ENCRYPTED_BLOCK_SIZE: usize = 65536; pub const NONCE_SIZE: usize = 12; // ChaCha20 IETF Nonce size @@ -21,7 +21,8 @@ pub const HEADER_INFO_SIZE: usize = const HEADER_PACKET_LENGTH_SIZE: usize = 4; -/// Have some sort of maximum header size to prevent any overflows. +/// Maximum header size +/// FIXME: Does this comply with the spec? const MAX_HEADER_SIZE: usize = 8 * 1024 * 1024; /// The type that a block is decoded into. @@ -115,11 +116,7 @@ impl Block { // We have already taken 4 bytes out of the length. length -= HEADER_PACKET_LENGTH_SIZE; - // Have a maximum header size to prevent any overflows. - if length > MAX_HEADER_SIZE { - return Err(MaximumHeaderSize); - } - + // FIXME: Shouldn't those bytes be known at compile time? // Get enough bytes to read the entire header packet. if src.len() < length { src.reserve(length - src.len()); diff --git a/src/encrypt/data_block.rs b/src/encrypt/data_block.rs index e4eee3a..fa6633e 100644 --- a/src/encrypt/data_block.rs +++ b/src/encrypt/data_block.rs @@ -81,44 +81,4 @@ impl Future for DataBlockDecrypter { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.project().handle.poll(cx).map_err(JoinHandleError)? } -} - -#[cfg(test)] -mod tests { - use crate::decoder::tests::{assert_first_data_block, get_data_block}; - use crate::tests::get_original_file; - - use super::*; - - #[tokio::test] - async fn data_block_decrypter() { - let (header_packets, data_block) = get_data_block(0).await; - - let data = DataBlockDecrypter::new( - data_block, - header_packets.data_enc_packets, - header_packets.edit_list_packet, - ) - .await - .unwrap(); - - assert_first_data_block(data.bytes.to_vec()).await; - } - - #[tokio::test] - async fn data_block_decrypter_with_edit_list() { - let (header_packets, data_block) = get_data_block(0).await; - - let data = DataBlockDecrypter::new( - data_block, - header_packets.data_enc_packets, - Some(vec![0, 4668, 60868]), - ) - .await - .unwrap(); - - let original_bytes = get_original_file().await; - - assert_eq!(data.bytes.to_vec(), original_bytes[..4668]); - } -} +} \ No newline at end of file diff --git a/src/encrypt/header/mod.rs b/src/encrypt/header/mod.rs index a0f5d1f..18c5f03 100644 --- a/src/encrypt/header/mod.rs +++ b/src/encrypt/header/mod.rs @@ -4,8 +4,8 @@ use std::task::{Context, Poll}; use tokio::io::AsyncRead; -use crate::encrypt::EncrypterStream; -use crate::encrypt::Result; +use crate::error::Crypt4GHError; +use crate::encrypt::EncryptStream; pub mod packets; @@ -14,17 +14,17 @@ pub mod packets; /// the session keys. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct SessionKeysFuture<'a, R> { - handle: &'a mut EncryptStream, + handle: &'a mut EncryptStream, } impl<'a, R> SessionKeysFuture<'a, R> { /// Create the future. - pub fn new(handle: &'a mut EncryptStream) -> Self { + pub fn new(handle: &'a mut EncryptStream) -> Self { Self { handle } } /// Get the inner handle. - pub fn get_mut(&mut self) -> &mut EncryptStream { + pub fn get_mut(&mut self) -> &mut EncryptStream { self.handle } } @@ -33,7 +33,7 @@ impl<'a, R> Future for SessionKeysFuture<'a, R> where R: AsyncRead + Unpin, { - type Output = Result<()>; + type Output = Result<(), Crypt4GHError>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.handle.poll_session_keys_unpin(cx) diff --git a/src/encrypt/header/packets.rs b/src/encrypt/header/packets.rs index cad60e0..c677354 100644 --- a/src/encrypt/header/packets.rs +++ b/src/encrypt/header/packets.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use bytes::Bytes; -use crate::header::{deconstruct_header_body, DecryptedHeaderPackets}; +use crate::error::Crypt4GHError; use crate::keys::{KeyPair, PublicKey}; use pin_project_lite::pin_project; use tokio::task::{spawn_blocking, JoinHandle}; @@ -12,7 +12,7 @@ pin_project! { #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct HeaderPacketsDecrypt { #[pin] - handle: JoinHandle> + handle: JoinHandle> } } @@ -24,16 +24,16 @@ impl HeaderPacketsDecrypt { ) -> Self { Self { handle: spawn_blocking(|| { - HeaderPacketsDecrypter::decrypt(header_packets, keys, sender_pubkey) + HeaderPacketsDecrypt::decrypt(header_packets, keys, sender_pubkey) }), } } pub fn decrypt( header_packets: Vec, - keys: Vec, + keys: Vec, // FIXME: Not quite right sender_pubkey: Option, - ) -> Result { + ) -> Result { Ok(deconstruct_header_body( header_packets .into_iter() @@ -45,33 +45,10 @@ impl HeaderPacketsDecrypt { } } -impl Future for HeaderPacketsDecrypter { - type Output = Result; +impl Future for HeaderPacketsDecrypt { + type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.project().handle.poll(cx).map_err(JoinHandleError)? + self.project().handle.poll(cx).map_err(Crypt4GHError::JoinHandleError)? } -} - -#[cfg(test)] -mod tests { - use crate::decoder::tests::{assert_first_header_packet, get_first_header_packet}; - - use super::*; - - #[tokio::test] - async fn header_packet_decrypter() { - let (recipient_private_key, sender_public_key, header_packets, _) = - get_first_header_packet().await; - - let data = HeaderPacketsDecrypt::new( - header_packets, - vec![recipient_private_key], - Some(PublicKey::new(sender_public_key)), - ) - .await - .unwrap(); - - assert_first_header_packet(data); - } -} +} \ No newline at end of file diff --git a/src/encrypt/mod.rs b/src/encrypt/mod.rs index d481801..669be0b 100644 --- a/src/encrypt/mod.rs +++ b/src/encrypt/mod.rs @@ -8,8 +8,8 @@ use std::task::{Context, Poll}; use async_trait::async_trait; use bytes::Bytes; use crate::encrypt::header::Header; -use crypt4gh::Keys; -use futures::ready; +use crate::Keys; +use futures::{ready, TryFutureExt}; use futures::Stream; use pin_project_lite::pin_project; use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt}; @@ -107,7 +107,7 @@ where pub fn poll_data_block( mut self: Pin<&mut Self>, data_block: Bytes, - ) -> Poll>> { + ) -> Poll>> { let edit_list = self.as_mut().partition_edit_list(&data_block); let this = self.project(); @@ -180,19 +180,19 @@ where cx.waker().wake_by_ref(); Poll::Pending } - DecodedBlock::DataBlock(_) => Poll::Ready(Err(Crypt4GHError( + DecodedBlock::DataBlock(_) => Poll::Ready(Err(Crypt4GHError::NoKey( "data block reached without finding session keys".to_string(), ))), }, Some(Err(e)) => Poll::Ready(Err(e)), - None => Poll::Ready(Err(Crypt4GHError( + None => Poll::Ready(Err(Crypt4GHError::NoKey( "end of stream reached without finding session keys".to_string(), ))), } } /// Convenience for calling [`poll_session_keys`] on [`Unpin`] types. - pub fn poll_session_keys_unpin(&mut self, cx: &mut Context<'_>) -> Poll> + pub fn poll_session_keys_unpin(&mut self, cx: &mut Context<'_>) -> Poll> where Self: Unpin, { @@ -200,7 +200,7 @@ where } /// Poll the stream until the header has been read. - pub async fn read_header(&mut self) -> Result<()> + pub async fn read_header(&mut self) -> Result<(), Crypt4GHError> where R: Unpin, { @@ -321,7 +321,7 @@ where /// /// This can take up to 3 seek calls. If the size of the underlying buffer changes, this function /// should be called again, otherwise data block positions may not be valid. - pub async fn recompute_stream_length(&mut self) -> Result { + pub async fn recompute_stream_length(&mut self) -> Result { let inner = self.inner.get_mut(); let position = inner.seek(SeekFrom::Current(0)).await?; @@ -341,7 +341,7 @@ impl Stream for DecrypterStream where R: AsyncRead, { - type Item = Result; + type Item = Result; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { // When polling, we first need to process enough data to get the session keys. @@ -379,7 +379,7 @@ where R: AsyncRead + AsyncSeek + Unpin + Send, { /// Seek to a position in the encrypted stream. - pub async fn seek_encrypted(&mut self, position: SeekFrom) -> io::Result { + pub async fn seek_encrypted(&mut self, position: SeekFrom) -> Result { // Make sure that session keys are polled. self.read_header().await?; @@ -404,10 +404,10 @@ where // Convert to an encrypted position and seek let position = self .to_encrypted(position) - .ok_or_else(|| Crypt4GHError("Unable to convert to encrypted position.".to_string()))?; + .ok_or_else(|| Crypt4GHError::InvalidPosition("Unable to convert to encrypted position.".to_string()))?; // Then do the seek. - self.seek_encrypted(SeekFrom::Start(position)).await + self.seek_encrypted(SeekFrom::Start(position)).map_err(Crypt4GHError::IoError(())) } } @@ -444,886 +444,4 @@ where fn stream_length(&self) -> Option { self.stream_length } -} - -#[cfg(test)] -mod tests { - use bytes::BytesMut; - use futures_util::future::join_all; - use futures_util::StreamExt; - use tokio::fs::File; - - use htsget_test::http_tests::get_test_file; - - use crate::decoder::tests::assert_last_data_block; - use crate::decrypter::builder::Builder; - use crate::tests::get_original_file; - use htsget_test::crypt4gh::get_decryption_keys; - - use super::*; - - #[tokio::test] - async fn partition_edit_lists() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_edit_list(vec![60113, 100000, 65536]) - .build(src, vec![recipient_private_key]); - - assert_edit_list(&mut stream, Some(vec![60113, 5423]), vec![0; 65564]); - assert_edit_list(&mut stream, Some(vec![0, 65536]), vec![0; 65564]); - assert_edit_list(&mut stream, Some(vec![0, 29041, 36495]), vec![0; 65564]); - assert_edit_list(&mut stream, Some(vec![29041]), vec![0; 29041 + 12 + 16]); - } - - fn assert_edit_list( - stream: &mut DecrypterStream, - expected: Option>, - bytes: Vec, - ) { - let stream = Pin::new(stream); - let edit_list = stream.partition_edit_list(&Bytes::from(bytes)); - assert_eq!(edit_list, expected); - } - - #[tokio::test] - async fn decrypter_stream() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn get_header_length() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - assert!(stream.header_size().is_none()); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.header_size(), Some(124)); - } - - #[tokio::test] - async fn first_block_size() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - assert!(stream.current_block_size().is_none()); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.current_block_size(), Some(65564)); - } - - #[tokio::test] - async fn last_block_size() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - assert!(stream.current_block_size().is_none()); - - let mut stream = stream.skip(39); - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.get_ref().current_block_size(), Some(40923)); - } - - #[tokio::test] - async fn clamp_position_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.clamp_position(0), Some(124)); - assert_eq!(stream.clamp_position(124), Some(124)); - assert_eq!(stream.clamp_position(200), Some(124)); - } - - #[tokio::test] - async fn clamp_position_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.clamp_position(80000), Some(124 + 65564)); - } - - #[tokio::test] - async fn clamp_position_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.clamp_position(2598044), Some(2598043)); - } - - #[tokio::test] - async fn convert_position_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - let pos = stream.to_encrypted(0); - assert_eq!(pos, Some(124)); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); - - let pos = stream.to_encrypted(200); - assert_eq!(pos, Some(124 + 12 + 200)); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); - } - - #[tokio::test] - async fn convert_position_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - let pos = stream.to_encrypted(80000); - assert_eq!(pos, Some(124 + 65564 + 12 + (80000 - 65536))); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(124 + 65564)); - } - - #[tokio::test] - async fn convert_position_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - let _ = stream.next().await.unwrap().unwrap().await; - - let pos = stream.to_encrypted(2596800); - assert_eq!(pos, Some(2598043)); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(2598043)); - } - - #[tokio::test] - async fn seek_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::Start(80000)).await.unwrap(); - - assert_eq!(seek, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let seek = stream - .seek_encrypted(SeekFrom::Current(-20000)) - .await - .unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::End(-1000)).await.unwrap(); - - assert_eq!(seek, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let block = stream.next().await.unwrap().unwrap().await.unwrap(); - assert_last_data_block(block.bytes.to_vec()).await; - } - - #[tokio::test] - async fn seek_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn seek_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn advance_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(0).await.unwrap(); - - assert_eq!(advance, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(80000).await.unwrap(); - - assert_eq!(advance, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(2598042).await.unwrap(); - - assert_eq!(advance, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(2598044).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let advance = stream.advance_encrypted(2598044).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(0).await.unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_second_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(65537).await.unwrap(); - - assert_eq!(seek, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let seek = stream.seek_unencrypted(65535).await.unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(2596799).await.unwrap(); - - assert_eq!(seek, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let block = stream.next().await.unwrap().unwrap().await.unwrap(); - assert_last_data_block(block.bytes.to_vec()).await; - } - - #[tokio::test] - async fn seek_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(2596800).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn seek_past_end_stream_unencrypted_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let seek = stream.seek_unencrypted(2596800).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn advance_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(0).await.unwrap(); - - assert_eq!(advance, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_second_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(65537).await.unwrap(); - - assert_eq!(advance, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(2596799).await.unwrap(); - - assert_eq!(advance, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(2596800).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end_unencrypted_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let advance = stream.advance_unencrypted(2596800).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } -} +} \ No newline at end of file diff --git a/src/error.rs b/src/error.rs index 0edb131..82dcd3f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,7 +18,7 @@ pub enum Crypt4GHError { NoNonce, #[error("Unable to create random salt")] NoRandomSalt, - #[error("Unable to create session key")] + #[error("Unable to find or create session key")] NoKey, #[error("Unable to wrap key")] BadKey, @@ -32,6 +32,8 @@ pub enum Crypt4GHError { InvalidPEMHeaderOrFooter, #[error("Invalid SSH key format")] InvalidSSHKey, + #[error("Invalid position: {0:?}")] + InvalidPosition(String), #[error("Unable to wrap nonce")] UnableToWrapNonce, #[error("Could not decrypt block: {0:?}, {1:?}")] diff --git a/src/lib.rs b/src/lib.rs index ad3a772..02ee6d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,7 @@ use crate::error::Crypt4GHError; use crate::header::Header; use crate::decrypt::data_block::{ DecryptedDataBlock, DecryptedBytes }; -use keys::KeyPairInfo; +use crate::keys::KeyPair; //use header::{ Header, deserialize_header_info }; const CHUNK_SIZE: usize = 4096; diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index 12c0b35..0000000 --- a/tests/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Testing - -```sh -cargo test --release -- --test-threads 1 -``` - -## Crypt4GH testsuite - -We run the following tests: - -These tests treat the system as a black box, only checking the expected output for a given input. - -We use 2 users: Alice and Bob. - -### Full file Encryption/Decryption - -We use a `testfile` containing the sequence of letters `abcd`, where each letter is repeated 65536 times. - -- [x] Bob encrypts a 10MB file for Alice, and Alice decrypts it. Expected outcome: Alice reads the same content as Bob had. - -- [x] Bob encrypts the testfile for Alice, and Alice decrypts it. Expected outcome: Alice reads the same content as testfile. - -- [x] Bob encrypts the testfile for himself. Bob takes the resulting file and only changes the recipient to be Alice. Alice decrypts what she receives. Expected outcome: Alice reads the same content as testfile. - -### Segmenting an encrypted file - -We use the testfile and Bob encrypts it for himself. - -- [x] Bob encrypts only the "b"'s from the testfile for Alice, using the `--range` flag. Alice decrypts what she receives. Expected outcome: Alice reads 65536 "b"s. - -- [x] Bob rerranges the encrypted file using the `--range 65536-131073` flag, to only the "b"s. Bob takes the resulting file and only changes the recipient to be Alice. Alice decrypts what she receives. Expected outcome: Alice reads 65536 "b"s. - -- [x] Bob rerranges the encrypted file using the `--range 65535-131074` flag, for Alice, to match one "a", all the "b"s, and one "c". Expected outcome: Alice reads one "a", 65536 "b"s and one "c". - -- [x] Bob sends the secret message `Let's have beers in the sauna! or Dinner at 7pm?` to Alice. The message is buried in the middle of some random data. Alice decrypts what she receives. Expected outcome: Alice reads `Let's have beers in the sauna! or Dinner at 7pm?`. - -### Using SSH keys - -- [x] Bob encrypts a 10MB file for Alice, using his own SSH keypair, and Alice decrypts it, using her Crypt4GH keypair. Expected outcome: Alice reads the same content as Bob had. - -- [x] Bob encrypts a 10MB file for Alice, using his own Crypt4GH keypair, and Alice decrypts it, using her SSH keypair. Expected outcome: Alice reads the same content as testfile. - -- [x] Bob encrypts a 10MB file for Alice, and Alice decrypts it, both using their SSH keypair. Expected outcome: Alice reads the same content as testfile. - -### Multiple recipients - -- [x] Bob sends the testfile secretly to himself and Alice. Expected outcome: They both can read the same content as Bob had. - -- [x] Bob encrypts the testfile for himself and reencrypts it for himself and Alice. Expected outcome: They both can read the same content as Bob had. diff --git a/tests/edit_list_gen.rs b/tests/edit_list_gen.rs deleted file mode 100644 index 4d15bdb..0000000 --- a/tests/edit_list_gen.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![allow(clippy::missing_panics_doc)] - -use std::fs::File; -use std::io::Write; -use std::path::{Path, PathBuf}; - -use crypt4gh::error::Crypt4GHError; -use chacha20poly1305::{ self, Key, Nonce }; -use rand_chacha; -use rand::{Rng, SeedableRng}; - -pub fn generate(sk: &str, recipient_pk: &str, input: &str, outfile: &mut File, passphrase: &str) -> Result<(), Crypt4GHError> { - let mut rng = rand::thread_rng(); - - let parts = input.lines().collect::>(); - let skips = parts.iter().copied().map(|_| 50000); - - let mut message = Vec::new(); - let mut edits = Vec::new(); - - for (skip, part) in skips.into_iter().zip(parts.iter()) { - message.extend((0..skip).map(|_| rand::random::())); - message.extend(part.as_bytes().iter()); - edits.push(skip); - edits.push(part.len()); - } - - log::debug!("Edits: {:?}", edits); - - // Fetch the keys - - log::debug!("SK: {:?}", sk); - assert!(Path::new(sk).exists()); // TODO: Migrate to Crypt4GHError - log::debug!("Recipient PK: {:?}", recipient_pk); - assert!(Path::new(recipient_pk).exists(), "Edit list gen key not found"); // TODO: Migrate to Crypt4GHError - - let callback = Ok(passphrase.to_string()); - let seckey = crypt4gh::keys::get_private_key(PathBuf::from(sk), callback)?; - let recipient_pubkey = crypt4gh::keys::get_public_key(PathBuf::from(recipient_pk))?; - - log::debug!("Sec: {:?}\n with length: {:?}", seckey, seckey.len()); - log::debug!("Pub: {:?}\n with length: {:?}", recipient_pubkey, recipient_pubkey.len()); - - let keys = vec![crypt4gh::Keys { - method: 0, - privkey: seckey, - recipient_pubkey, - }] - .into_iter() - .collect(); - - // Prepare encryption engine - - let encryption_method = 0; // Only choice for this version - let session_key: [u8; 32] = rng.gen(); // We use one session key for all blocks - - // Output the header - - let packets = vec![ - crypt4gh::header::make_packet_data_enc(encryption_method, &session_key), - crypt4gh::header::make_packet_data_edit_list(edits), - ]; - - let header_packets: Vec> = packets - .into_iter() - .flat_map(|packet| crypt4gh::header::encrypt(&packet, &keys).unwrap()) - .collect(); - let mangled_header_packets = header_packets; - let mangled_header_packets = crypt4gh::header::serialize(mangled_header_packets); - outfile.write_all(&mangled_header_packets)?; - - log::debug!("header length: {}", mangled_header_packets.len()); - - // TODO: Perhaps migrate rest of this file to rnd instead of rng (crypto-safe PRNG?) - let mut rnd = rand_chacha::ChaCha20Rng::from_entropy(); - let mut random_buf = [0u8; 12]; - rnd.fill(&mut random_buf); - - // Output the message - for segment in message.chunks(crypt4gh::SEGMENT_SIZE) { - let nonce = Nonce::from_slice(&random_buf); - let key = Key::from_slice(&session_key); - - let encrypted_segment = crypt4gh::encrypt_segment(segment, *nonce, &key)?; - outfile.write_all(&encrypted_segment)?; - } - - Ok(()) -} diff --git a/tests/test_common.rs b/tests/test_common.rs deleted file mode 100644 index 5022dbb..0000000 --- a/tests/test_common.rs +++ /dev/null @@ -1,256 +0,0 @@ -#![allow(clippy::missing_panics_doc)] - -use std::env; -use std::ffi::OsStr; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; -use std::process::{Command, ExitStatus, Stdio}; - -pub const BOB_PASSPHRASE: &str = "bob"; -pub const BOB_PUBKEY: &str = "testfiles/bob.pub"; -pub const BOB_SECKEY: &str = "testfiles/bob.sec"; - -pub const BOB_SECKEY_SSH: &str = "bob.sshkey"; -pub const BOB_PUBKEY_SSH: &str = "bob.sshkey.pub"; - -pub const ALICE_PASSPHRASE: &str = "alice"; -pub const ALICE_PUBKEY: &str = "testfiles/alice.pub"; -pub const ALICE_SECKEY: &str = "testfiles/alice.sec"; - -pub const ALICE_SECKEY_SSH: &str = "alice.sshkey"; -pub const ALICE_PUBKEY_SSH: &str = "alice.sshkey.pub"; - -pub const TEMP_LOCATION: &str = "tests/tempfiles"; -pub const TESTFILE_ABCD: &str = "tests/testfiles/testfile.abcd"; -pub const TESTFILE_ABBBC: &str = "tests/testfiles/testfile.abbbc"; - -pub struct CommandUnderTest { - raw: Command, - stdin: Vec, - run: bool, - stdout: String, - stderr: String, -} - -impl CommandUnderTest { - #[must_use] - pub fn new() -> Self { - // To find the directory where the built binary is, we walk up the directory tree of the test binary until the - // parent is "target/". - let mut binary_path = env::current_exe().expect("need current binary path to find binary to test"); - loop { - { - let parent = binary_path.parent(); - assert!( - parent.is_some(), - "Failed to locate binary path from original path: {:?}", - env::current_exe() - ); - let parent = parent.unwrap(); - if parent.is_dir() && parent.file_name().unwrap() == "target" { - break; - } - } - binary_path.pop(); - } - - binary_path.push( - if cfg!(target_os = "windows") { - format!("{}.exe", env!("CARGO_BIN_EXE_crypt4gh")) - } - else { - env!("CARGO_BIN_EXE_crypt4gh").to_string() - }, - ); - - let mut cmd = Command::new(binary_path); - - let mut work_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - work_dir.push("tests"); - - cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).current_dir(work_dir); - - Self { - raw: cmd, - run: false, - stdin: Vec::new(), - stdout: String::new(), - stderr: String::new(), - } - } - - pub fn env(&mut self, key: &str, val: &str) -> &mut Self { - self.raw.env(key, val); - self - } - - pub fn same_envs(&mut self) -> &mut Self { - self.raw.envs(env::vars()); - self - } - - pub fn arg>(&mut self, arg: S) -> &mut Self { - self.raw.arg(arg); - self - } - - pub fn args(&mut self, args: I) -> &mut Self - where - I: IntoIterator, - S: AsRef, - { - self.raw.args(args); - self - } - - pub fn pipe_in(&mut self, filename: &str) -> &mut Self { - let file = File::open(filename).unwrap(); - self.raw.stdin(Stdio::from(file)); - self - } - - pub fn pipe_out(&mut self, filename: &str) -> &mut Self { - let file = File::create(filename).unwrap(); - self.raw.stdout(Stdio::from(file)); - self - } - - pub fn run(&mut self) -> ExitStatus { - let mut child = self.raw.spawn().expect("failed to run command"); - - if !self.stdin.is_empty() { - let stdin = child.stdin.as_mut().expect("failed to open stdin"); - stdin.write_all(&self.stdin).expect("failed to write to stdin"); - } - - let output = child - .wait_with_output() - .expect("failed waiting for command to complete"); - self.stdout = String::from_utf8(output.stdout).unwrap(); - self.stderr = String::from_utf8(output.stderr).unwrap(); - self.run = true; - output.status - } - - pub fn fails(&mut self) -> &mut Self { - assert!(!self.run().success(), "expected command to fail"); - self - } - - pub fn succeeds(&mut self) -> &mut Self { - let status = self.run(); - assert!( - status.success(), - "expected command to succeed, but it failed.\nexit code: {}\nstdout: {}\nstderr:{}\n", - status.code().unwrap(), - self.stdout, - self.stderr, - ); - self - } - - pub fn no_stdout(&mut self) -> &mut Self { - assert!(self.run, "command has not yet been run, use succeeds()/fails()"); - assert!(self.stdout.is_empty(), "expected no stdout, got {}", self.stdout); - self - } - - pub fn no_stderr(&mut self) -> &mut Self { - assert!(self.run, "command has not yet been run, use succeeds()/fails()"); - assert!(self.stderr.is_empty(), "expected no stderr, got {}", self.stderr); - self - } - - pub fn stdout_is(&mut self, expected: &str) -> &mut Self { - assert!(self.run, "command has not yet been run, use succeeds()/fails()"); - assert_eq!(&self.stdout[..], expected, "stdout does not match expected"); - self - } - - pub fn stderr_is(&mut self, expected: &str) -> &mut Self { - assert!(self.run, "command has not yet been run, use succeeds()/fails()"); - assert_eq!(&self.stderr[..], expected, "stderr does not match expected"); - self - } -} - -impl Default for CommandUnderTest { - fn default() -> Self { - Self::new() - } -} - -pub struct Cleanup; - -impl Drop for Cleanup { - fn drop(&mut self) { - eprintln!("DROP"); - remove_file(TEMP_LOCATION); - } -} - -impl Cleanup { - #[must_use] - pub fn new() -> Self { - eprintln!("Created!"); - Command::new("mkdir") - .arg(TEMP_LOCATION) - .stderr(Stdio::null()) - .spawn() - .unwrap() - .wait() - .unwrap(); - Self {} - } -} - -impl Default for Cleanup { - fn default() -> Self { - Self::new() - } -} - -pub fn echo(message: &str, filename: &str) { - let file = File::create(filename).unwrap(); - let status = Command::new("echo") - .arg("-n") - .arg(message) - .stderr(Stdio::null()) - .stdout(Stdio::from(file)) - .spawn() - .unwrap() - .wait() - .unwrap() - .code() - .unwrap(); - assert_eq!(status, 0); -} - -pub fn count_characters(filepath: &str, assert_size: usize) { - let wc = Command::new("wc") - .arg("-c") - .arg(filepath) - .stderr(Stdio::null()) - .output() - .unwrap(); - - let mut awk = Command::new("awk") - .arg("{ print $1 }") - .stdin(Stdio::piped()) - .stderr(Stdio::null()) - .stdout(Stdio::piped()) - .spawn() - .unwrap(); - - { - let awk_in = awk.stdin.as_mut().unwrap(); - awk_in.write_all(&wc.stdout).unwrap(); - } - - let result = awk.wait_with_output().unwrap(); - - assert!(result.status.success()); - let out = String::from_utf8(result.stdout).unwrap(); - assert_eq!(out.trim().parse::().unwrap(), assert_size); -} \ No newline at end of file diff --git a/tests/test_data_block.rs b/tests/test_data_block.rs deleted file mode 100644 index 1da3dd2..0000000 --- a/tests/test_data_block.rs +++ /dev/null @@ -1,40 +0,0 @@ -#[cfg(test)] -mod tests { - use crate::decoder::tests::{assert_first_data_block, get_data_block}; - //use crate::tests::get_original_file; - - use super::*; - - #[tokio::test] - async fn data_block_decrypter() { - let (header_packets, data_block) = get_data_block(0).await; - - let data = DataBlockDecrypter::new( - data_block, - header_packets.data_enc_packets, - header_packets.edit_list_packet, - ) - .await - .unwrap(); - - assert_first_data_block(data.bytes.to_vec()).await; - } - - #[tokio::test] - async fn data_block_decrypter_with_edit_list() { - let (header_packets, data_block) = get_data_block(0).await; - - let data = DataBlockDecrypter::new( - data_block, - header_packets.data_enc_packets, - Some(vec![0, 4668, 60868]), - ) - .await - .unwrap(); - - // FIXME: No "file" constructs in this crate! - //let original_bytes = get_original_file().await; - - //assert_eq!(data.bytes.to_vec(), original_bytes[..4668]); - } -} \ No newline at end of file diff --git a/tests/test_decoder.rs b/tests/test_decoder.rs deleted file mode 100644 index 23e2806..0000000 --- a/tests/test_decoder.rs +++ /dev/null @@ -1,171 +0,0 @@ -#[cfg(test)] -pub(crate) mod tests { - use std::io::Cursor; - - use crate::header::{deconstruct_header_body, DecryptedHeaderPackets}; - use crate::{body_decrypt, Keys, WriteInfo}; - use futures_util::stream::Skip; - use futures_util::StreamExt; - use tokio::io::AsyncReadExt; - use tokio_util::codec::FramedRead; - use super::*; - - #[tokio::test] - async fn decode_header_info() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let mut reader = FramedRead::new(src, Block::default()); - - let header_info = reader.next().await.unwrap().unwrap(); - - // Assert that the first block output is a header info with one packet. - assert!( - matches!(header_info, DecodedBlock::Header(header_info) if header_info.packets_count == 1) - ); - } - - #[tokio::test] - async fn decode_header_packets() { - let (recipient_private_key, sender_public_key, header_packet, _) = - get_first_header_packet().await; - let header = get_header_packets(recipient_private_key, sender_public_key, header_packet); - - assert_first_header_packet(header); - - // Todo handle case where there is more than one header packet. - } - - #[tokio::test] - async fn decode_data_block() { - let (header, data_block) = get_data_block(0).await; - - let read_buf = Cursor::new(data_block.to_vec()); - let mut write_buf = Cursor::new(vec![]); - let mut write_info = WriteInfo::new(0, None, &mut write_buf); - - body_decrypt(read_buf, &header.data_enc_packets, &mut write_info, 0).unwrap(); - - let decrypted_bytes = write_buf.into_inner(); - - assert_first_data_block(decrypted_bytes).await; - } - - #[tokio::test] - async fn decode_eof() { - let (header, data_block) = get_data_block(39).await; - - let read_buf = Cursor::new(data_block.to_vec()); - let mut write_buf = Cursor::new(vec![]); - let mut write_info = WriteInfo::new(0, None, &mut write_buf); - - body_decrypt(read_buf, &header.data_enc_packets, &mut write_info, 0).unwrap(); - - let decrypted_bytes = write_buf.into_inner(); - - assert_last_data_block(decrypted_bytes).await; - } - - /// Assert that the first header packet is a data encryption key packet. - pub(crate) fn assert_first_header_packet(header: DecryptedHeaderPackets) { - assert_eq!(header.data_enc_packets.len(), 1); - assert!(header.edit_list_packet.is_none()); - } - - /// Assert that the last data block is equal to the expected ending bytes of the original file. - pub(crate) async fn assert_last_data_block(decrypted_bytes: Vec) { - let mut original_file = get_test_file("bam/htsnexus_test_NA12878.bam").await; - let mut original_bytes = vec![]; - original_file - .read_to_end(&mut original_bytes) - .await - .unwrap(); - - assert_eq!( - decrypted_bytes, - original_bytes - .into_iter() - .rev() - .take(40895) - .rev() - .collect::>() - ); - } - - /// Assert that the first data block is equal to the first 64KiB of the original file. - pub(crate) async fn assert_first_data_block(decrypted_bytes: Vec) { - let original_bytes = get_original_file().await; - - assert_eq!(decrypted_bytes, original_bytes[..65536]); - } - - /// Get the first header packet from the test file. - pub(crate) async fn get_first_header_packet( - ) -> (Keys, Vec, Vec, Skip>) { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = FramedRead::new(src, Block::default()).skip(1); - - // The second block should contain a header packet. - let header_packets = reader.next().await.unwrap().unwrap(); - - let (header_packet, header_length) = - if let DecodedBlock::HeaderPackets(header_packets) = header_packets { - Some(header_packets) - } else { - None - } - .unwrap() - .into_inner(); - - assert_eq!(header_length, 108); - - ( - recipient_private_key, - sender_public_key, - header_packet - .into_iter() - .map(|packet| packet.into_header_bytes()) - .collect(), - reader, - ) - } - - /// Get the first data block from the test file. - pub(crate) async fn get_data_block(skip: usize) -> (DecryptedHeaderPackets, Bytes) { - let (recipient_private_key, sender_public_key, header_packets, reader) = - get_first_header_packet().await; - let header = get_header_packets(recipient_private_key, sender_public_key, header_packets); - - let data_block = reader.skip(skip).next().await.unwrap().unwrap(); - - let data_block = if let DecodedBlock::DataBlock(data_block) = data_block { - Some(data_block) - } else { - None - } - .unwrap(); - - (header, data_block) - } - - /// Get the header packets from a decoded block. - pub(crate) fn get_header_packets( - recipient_private_key: Keys, - sender_public_key: Vec, - header_packets: Vec, - ) -> DecryptedHeaderPackets { - // Assert the size of the header packet is correct. - assert_eq!(header_packets.len(), 1); - assert_eq!(header_packets.first().unwrap().len(), 104); - - deconstruct_header_body( - header_packets - .into_iter() - .map(|header_packet| header_packet.to_vec()) - .collect(), - &[recipient_private_key], - &Some(sender_public_key), - ) - .unwrap() - } -} \ No newline at end of file diff --git a/tests/test_decrypter.rs b/tests/test_decrypter.rs deleted file mode 100644 index f4e2d41..0000000 --- a/tests/test_decrypter.rs +++ /dev/null @@ -1,879 +0,0 @@ -// FIXME: Test suite highly dependent on fs and File(s), migrate to Bytes and/or Streams instead -#[cfg(test)] -mod tests { - use bytes::BytesMut; - use futures_util::future::join_all; - use futures_util::StreamExt; - // use tokio::fs::File; - - use crate::decoder::tests::assert_last_data_block; - use crate::decrypter::builder::Builder; - // use crate::tests::get_original_file; - - use super::*; - - #[tokio::test] - async fn partition_edit_lists() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_edit_list(vec![60113, 100000, 65536]) - .build(src, vec![recipient_private_key]); - - assert_edit_list(&mut stream, Some(vec![60113, 5423]), vec![0; 65564]); - assert_edit_list(&mut stream, Some(vec![0, 65536]), vec![0; 65564]); - assert_edit_list(&mut stream, Some(vec![0, 29041, 36495]), vec![0; 65564]); - assert_edit_list(&mut stream, Some(vec![29041]), vec![0; 29041 + 12 + 16]); - } - - fn assert_edit_list( - stream: &mut DecrypterStream, // FIXME: No files! - expected: Option>, - bytes: Vec, - ) { - let stream = Pin::new(stream); - let edit_list = stream.partition_edit_list(&Bytes::from(bytes)); - assert_eq!(edit_list, expected); - } - - #[tokio::test] - async fn decrypter_stream() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn get_header_length() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - assert!(stream.header_size().is_none()); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.header_size(), Some(124)); - } - - #[tokio::test] - async fn first_block_size() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - assert!(stream.current_block_size().is_none()); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.current_block_size(), Some(65564)); - } - - #[tokio::test] - async fn last_block_size() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - assert!(stream.current_block_size().is_none()); - - let mut stream = stream.skip(39); - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.get_ref().current_block_size(), Some(40923)); - } - - #[tokio::test] - async fn clamp_position_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.clamp_position(0), Some(124)); - assert_eq!(stream.clamp_position(124), Some(124)); - assert_eq!(stream.clamp_position(200), Some(124)); - } - - #[tokio::test] - async fn clamp_position_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.clamp_position(80000), Some(124 + 65564)); - } - - #[tokio::test] - async fn clamp_position_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - let _ = stream.next().await.unwrap().unwrap().await; - - assert_eq!(stream.clamp_position(2598044), Some(2598043)); - } - - #[tokio::test] - async fn convert_position_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - let pos = stream.to_encrypted(0); - assert_eq!(pos, Some(124)); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); - - let pos = stream.to_encrypted(200); - assert_eq!(pos, Some(124 + 12 + 200)); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(124)); - } - - #[tokio::test] - async fn convert_position_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let _ = stream.next().await.unwrap().unwrap().await; - - let pos = stream.to_encrypted(80000); - assert_eq!(pos, Some(124 + 65564 + 12 + (80000 - 65536))); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(124 + 65564)); - } - - #[tokio::test] - async fn convert_position_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - let _ = stream.next().await.unwrap().unwrap().await; - - let pos = stream.to_encrypted(2596800); - assert_eq!(pos, Some(2598043)); - assert_eq!(stream.clamp_position(pos.unwrap()), Some(2598043)); - } - - #[tokio::test] - async fn seek_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::Start(80000)).await.unwrap(); - - assert_eq!(seek, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let seek = stream - .seek_encrypted(SeekFrom::Current(-20000)) - .await - .unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::End(-1000)).await.unwrap(); - - assert_eq!(seek, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let block = stream.next().await.unwrap().unwrap().await.unwrap(); - assert_last_data_block(block.bytes.to_vec()).await; - } - - #[tokio::test] - async fn seek_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn seek_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let seek = stream.seek_encrypted(SeekFrom::End(80000)).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn advance_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(0).await.unwrap(); - - assert_eq!(advance, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_second_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(80000).await.unwrap(); - - assert_eq!(advance, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(2598042).await.unwrap(); - - assert_eq!(advance, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_encrypted(2598044).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let advance = stream.advance_encrypted(2598044).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(0).await.unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_second_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(65537).await.unwrap(); - - assert_eq!(seek, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let seek = stream.seek_unencrypted(65535).await.unwrap(); - - assert_eq!(seek, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn seek_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(2596799).await.unwrap(); - - assert_eq!(seek, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let block = stream.next().await.unwrap().unwrap().await.unwrap(); - assert_last_data_block(block.bytes.to_vec()).await; - } - - #[tokio::test] - async fn seek_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let seek = stream.seek_unencrypted(2596800).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn seek_past_end_stream_unencrypted_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let seek = stream.seek_unencrypted(2596800).await.unwrap(); - - assert_eq!(seek, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - assert!(stream.next().await.is_none()); - } - - #[tokio::test] - async fn advance_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(0).await.unwrap(); - - assert_eq!(advance, 124); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_second_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(65537).await.unwrap(); - - assert_eq!(advance, 124 + 65564); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(2596799).await.unwrap(); - - assert_eq!(advance, 2598043 - 40923); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let advance = stream.advance_unencrypted(2596800).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn advance_past_end_unencrypted_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut stream = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build(src, vec![recipient_private_key]); - - let advance = stream.advance_unencrypted(2596800).await.unwrap(); - - assert_eq!(advance, 2598043); - assert_eq!(stream.header_size(), Some(124)); - assert_eq!(stream.current_block_size(), None); - - let mut futures = vec![]; - while let Some(block) = stream.next().await { - futures.push(block.unwrap()); - } - - let decrypted_bytes = - join_all(futures) - .await - .into_iter() - .fold(BytesMut::new(), |mut acc, bytes| { - let (bytes, _) = bytes.unwrap().into_inner(); - acc.extend(bytes.0); - acc - }); - - // Assert that the decrypted bytes are equal to the original file bytes. - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } -} \ No newline at end of file diff --git a/tests/test_edit_list.rs b/tests/test_edit_list.rs deleted file mode 100644 index 41f4fa5..0000000 --- a/tests/test_edit_list.rs +++ /dev/null @@ -1,96 +0,0 @@ -#[cfg(test)] -mod tests { - // use htsget_test::crypt4gh::{get_decryption_keys, get_encryption_keys}; - // use htsget_test::http_tests::get_test_file; - - use crate::reader::builder::Builder; - - use super::*; - - #[tokio::test] - async fn test_append_edit_list() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (private_key_decrypt, public_key_decrypt) = get_decryption_keys().await; - let (private_key_encrypt, public_key_encrypt) = get_encryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(public_key_decrypt.clone())) - .with_stream_length(5485112) - .build_with_reader(src, vec![private_key_decrypt.clone()]); - reader.read_header().await.unwrap(); - - let expected_data_packets = reader.session_keys().to_vec(); - - let header = EditHeader::new( - &reader, - test_unencrypted_positions(), - test_clamped_positions(), - PrivateKey(private_key_encrypt.clone().privkey), - PublicKey { - bytes: public_key_encrypt.clone(), - }, - ) - .edit_list() - .unwrap() - .unwrap(); - - let header_slice = header.as_slice(); - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(public_key_decrypt)) - .with_stream_length(5485112) - .build_with_reader(header_slice.as_slice(), vec![private_key_decrypt]); - reader.read_header().await.unwrap(); - - let data_packets = reader.session_keys(); - assert_eq!(data_packets, expected_data_packets); - - let edit_lists = reader.edit_list_packet().unwrap(); - assert_eq!(edit_lists, expected_edit_list()); - } - - #[tokio::test] - async fn test_create_edit_list() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (private_key_decrypt, public_key_decrypt) = get_decryption_keys().await; - let (private_key_encrypt, public_key_encrypt) = get_encryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(public_key_decrypt.clone())) - .with_stream_length(5485112) - .build_with_reader(src, vec![private_key_decrypt.clone()]); - reader.read_header().await.unwrap(); - - let edit_list = EditHeader::new( - &reader, - test_unencrypted_positions(), - test_clamped_positions(), - PrivateKey(private_key_encrypt.clone().privkey), - PublicKey { - bytes: public_key_encrypt.clone(), - }, - ) - .create_edit_list(); - - assert_eq!(edit_list, expected_edit_list()); - } - - fn test_unencrypted_positions() -> Vec { - vec![ - UnencryptedPosition::new(0, 7853), - UnencryptedPosition::new(145110, 453039), - UnencryptedPosition::new(5485074, 5485112), - ] - } - - fn test_clamped_positions() -> Vec { - vec![ - ClampedPosition::new(0, 65536), - ClampedPosition::new(131072, 458752), - ClampedPosition::new(5439488, 5485112), - ] - } - - fn expected_edit_list() -> Vec { - vec![0, 7853, 71721, 307929, 51299, 38] - } -} \ No newline at end of file diff --git a/tests/test_full_file.rs b/tests/test_full_file.rs deleted file mode 100644 index 4ba4e88..0000000 --- a/tests/test_full_file.rs +++ /dev/null @@ -1,164 +0,0 @@ -mod test_common; - -pub use test_common::*; -use testresult::TestResult; - -#[test] -fn test_encrypt_decrypt_random() -> TestResult { - // Init - let init = Cleanup::new(); - - // Create random file - new_random_file(&temp_file("random.10MB"), 10); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(ALICE_PUBKEY) - .pipe_in(&temp_file("random.10MB")) - .pipe_out(&temp_file("random.10MB.c4gh")) - .succeeds(); - - // Decrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(ALICE_SECKEY) - .pipe_in(&temp_file("random.10MB.c4gh")) - .pipe_out(&temp_file("random.10MB.received")) - .succeeds(); - - // Compare - equal(&temp_file("random.10MB"), &temp_file("random.10MB.received")); - - // Cleanup - drop(init); - - Ok(()) -} - -#[test] -fn test_encrypt_decrypt_testfile() -> TestResult { - // Init - let init = Cleanup::new(); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(ALICE_PUBKEY) - .pipe_in(TESTFILE_ABCD) - .pipe_out(&temp_file("message.c4gh")) - .succeeds(); - - // Decrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(ALICE_SECKEY) - .pipe_in(&temp_file("message.c4gh")) - .pipe_out(&temp_file("message.received")) - .succeeds(); - - // Compare - equal(TESTFILE_ABCD, &temp_file("message.received")); - - // Cleanup - drop(init); - - Ok(()) -} - -#[test] -fn test_encrypt_then_reencrypt() -> TestResult { - // Init - let init = Cleanup::new(); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(BOB_PUBKEY) - .pipe_in(TESTFILE_ABCD) - .pipe_out(&temp_file("message.bob.c4gh")) - .succeeds(); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("reencrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(ALICE_PUBKEY) - .pipe_in(&temp_file("message.bob.c4gh")) - .pipe_out(&temp_file("message.c4gh")) - .succeeds(); - - // Decrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(ALICE_SECKEY) - .pipe_in(&temp_file("message.c4gh")) - .pipe_out(&temp_file("message.received")) - .succeeds(); - - // Compare - equal(TESTFILE_ABCD, &temp_file("message.received")); - - // Cleanup - drop(init); - - Ok(()) -} - -#[test] -fn test_encrypt_with_missing_key() -> TestResult { - // Init - let init = Cleanup::new(); - - // Create random file - new_random_file(&temp_file("random.10MB"), 10); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--recipient_pk") - .arg(ALICE_PUBKEY) - .pipe_in(&temp_file("random.10MB")) - .pipe_out(&temp_file("random.10MB.c4gh")) - .succeeds(); - - // Decrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(ALICE_SECKEY) - .pipe_in(&temp_file("random.10MB.c4gh")) - .pipe_out(&temp_file("random.10MB.received")) - .succeeds(); - - // Compare - equal(&temp_file("random.10MB"), &temp_file("random.10MB.received")); - - // Cleanup - drop(init); - - Ok(()) -} diff --git a/tests/test_header.rs b/tests/test_header.rs deleted file mode 100644 index 2e13195..0000000 --- a/tests/test_header.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn enum_serialization_0() { - assert_eq!( - bincode::serialize(&HeaderPacketType::DataEnc).unwrap(), - 0_u32.to_le_bytes() - ); - } - - #[test] - fn enum_serialization_1() { - assert_eq!( - bincode::serialize(&HeaderPacketType::EditList).unwrap(), - 1_u32.to_le_bytes() - ); - } -} \ No newline at end of file diff --git a/tests/test_header_packets.rs b/tests/test_header_packets.rs deleted file mode 100644 index e69de29..0000000 diff --git a/tests/test_keygen.rs b/tests/test_keygen.rs deleted file mode 100644 index dc0109d..0000000 --- a/tests/test_keygen.rs +++ /dev/null @@ -1,56 +0,0 @@ -mod test_common; - -use std::path::PathBuf; - -pub use test_common::*; -use testresult::TestResult; - -#[test] -fn test_keygen() -> TestResult { - // Init - let init = Cleanup::new(); - - let bob_pk_path = temp_file("bob.pub"); - let bob_sk_path = temp_file("bob.sec"); - let callback = Ok(BOB_PASSPHRASE.to_string()); - - crypt4gh::keys::generate_keys(PathBuf::from(&bob_sk_path), PathBuf::from(&bob_pk_path), callback, None) - .expect("Unable to generate Bob's keys"); - - let alice_pk_path = temp_file("alice.pub"); - let alice_sk_path = temp_file("alice.sec"); - let callback2 = Ok(ALICE_PASSPHRASE.to_string()); - - crypt4gh::keys::generate_keys(PathBuf::from(&alice_sk_path), PathBuf::from(&alice_pk_path), callback2, None) - .expect("Unable to generate Alice's keys"); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(strip_prefix("bob.sec")) - .arg("--recipient_pk") - .arg(strip_prefix("alice.pub")) - .pipe_in(TESTFILE_ABCD) - .pipe_out(&temp_file("message.c4gh")) - .succeeds(); - - // Decrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(strip_prefix("alice.sec")) - .pipe_in(&temp_file("message.c4gh")) - .pipe_out(&temp_file("message.received")) - .succeeds(); - - // Compare - equal(TESTFILE_ABCD, &temp_file("message.received")); - - // Cleanup - drop(init); - - Ok(()) -} diff --git a/tests/test_keygen_length.rs b/tests/test_keygen_length.rs deleted file mode 100644 index 9f66c3e..0000000 --- a/tests/test_keygen_length.rs +++ /dev/null @@ -1,48 +0,0 @@ -mod test_common; - -use std::path::PathBuf; - -pub use test_common::*; -use testresult::TestResult; - -#[test] -fn test_keygen_length_encrypted() -> TestResult { - // Init - let init = Cleanup::new(); - - let bob_pk_path = temp_file("bob.pub"); - let bob_sk_path = temp_file("bob.sec"); - let callback = Ok(BOB_PASSPHRASE.to_string()); - - crypt4gh::keys::generate_keys(PathBuf::from(&bob_sk_path), PathBuf::from(&bob_pk_path), callback, None) - .expect("Unable to generate Bob's keys"); - - count_characters(&temp_file("bob.pub"), 36 + 45 + 34); - count_characters(&temp_file("bob.sec"), 37 + 161 + 35); - - // Cleanup - drop(init); - - Ok(()) -} - -#[test] -fn test_keygen_length_not_encrypted() -> TestResult { - // Init - let init = Cleanup::new(); - - let alice_pk_path = temp_file("alice.pub"); - let alice_sk_path = temp_file("alice.sec"); - let callback = Ok("".to_string()); - - crypt4gh::keys::generate_keys(PathBuf::from(&alice_sk_path), PathBuf::from(&alice_pk_path), callback, None) - .expect("Unable to generate Bob's keys"); - - count_characters(&temp_file("alice.pub"), 36 + 45 + 34); - count_characters(&temp_file("alice.sec"), 37 + 73 + 35); - - // Cleanup - drop(init); - - Ok(()) -} diff --git a/tests/test_keys.rs b/tests/test_keys.rs deleted file mode 100644 index 74282f5..0000000 --- a/tests/test_keys.rs +++ /dev/null @@ -1,54 +0,0 @@ -mod test_common; - -use crypt4gh::{keys::get_private_key, Keys}; -use rand::Rng; -use rand_chacha::rand_core::OsRng; -use ssh_key::PrivateKey; -pub use test_common::*; -use testresult::TestResult; - -#[test] -fn encrypt_decrypt_ssh() -> TestResult { - // Init - let init = Cleanup::new(); - pretty_env_logger::init(); - let mut rng = rand::thread_rng(); - - // Generate 10MB of "cleartext" payload - let mut cleartext = vec![0u8; 10 * 1024 * 1024]; - rng.fill(&mut cleartext[..]); - - // Generate a random SSH key, no pubkey for sender and no range values - let private_key = PrivateKey::random(&mut OsRng, ssh_key::Algorithm::Ed25519)?; - let sender_pubkey = None; - let (range_start, range_span) = (0, None); - - let keys = vec![Keys { - method: 0, - privkey: private_key.to_bytes()?.to_vec(), - recipient_pubkey: vec![], - }]; - - // Encrypt - let cryptext = crypt4gh::encrypt( - &keys, - range_start, - range_span - ); - - // Decrypt - let plaintext = crypt4gh::decrypt( - &keys, - range_start, - range_span, - &sender_pubkey, - )?; - - // Compare - equal(&cleartext, &plaintext); - - // Cleanup - drop(init); - - Ok(()) -} \ No newline at end of file diff --git a/tests/test_multiple_recipients.rs b/tests/test_multiple_recipients.rs deleted file mode 100644 index 0bf6079..0000000 --- a/tests/test_multiple_recipients.rs +++ /dev/null @@ -1,114 +0,0 @@ -mod test_common; - -pub use test_common::*; -use testresult::TestResult; - -#[test] -fn send_to_bob_and_alice() -> TestResult { - // Init - let init = Cleanup::new(); - - // Create random file - new_random_file(&temp_file("random.10MB"), 10); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(BOB_PUBKEY) - .arg(ALICE_PUBKEY) - .pipe_in(&temp_file("random.10MB")) - .pipe_out(&temp_file("random.10MB.c4gh")) - .succeeds(); - - // Alice decrypts - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(ALICE_SECKEY) - .pipe_in(&temp_file("random.10MB.c4gh")) - .pipe_out(&temp_file("random.10MB.received")) - .succeeds(); - - // Bob decrypts - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .pipe_in(&temp_file("random.10MB.c4gh")) - .pipe_out(&temp_file("random.10MB.received")) - .succeeds(); - - // Compare - equal(&temp_file("random.10MB"), &temp_file("random.10MB.received")); - - // Cleanup - drop(init); - - Ok(()) -} - -#[test] -fn reencrypt_to_bob_and_alice() -> TestResult { - // Init - let init = Cleanup::new(); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(BOB_PUBKEY) - .pipe_in(TESTFILE_ABCD) - .pipe_out(&temp_file("message.bob.c4gh")) - .succeeds(); - - // Reencrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("reencrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(BOB_PUBKEY) - .arg(ALICE_PUBKEY) - .pipe_in(&temp_file("message.bob.c4gh")) - .pipe_out(&temp_file("message.c4gh")) - .succeeds(); - - // Alice decrypts - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(ALICE_SECKEY) - .pipe_in(&temp_file("message.c4gh")) - .pipe_out(&temp_file("message.alice.received")) - .succeeds(); - - // Bob decrypts - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .pipe_in(&temp_file("message.c4gh")) - .pipe_out(&temp_file("message.bob.received")) - .succeeds(); - - // Compare - equal(TESTFILE_ABCD, &temp_file("message.alice.received")); - equal(TESTFILE_ABCD, &temp_file("message.bob.received")); - - // Cleanup - drop(init); - - Ok(()) -} diff --git a/tests/test_reader.rs b/tests/test_reader.rs deleted file mode 100644 index 0138be5..0000000 --- a/tests/test_reader.rs +++ /dev/null @@ -1,520 +0,0 @@ -#[cfg(test)] -mod tests { - use std::io::SeekFrom; - - use futures_util::TryStreamExt; - use noodles::bam::AsyncReader; - use noodles::sam::Header; - use tokio::io::AsyncReadExt; - - use crate::reader::builder::Builder; - use crate::keys::PublicKey; - - #[tokio::test] - async fn reader() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let mut decrypted_bytes = vec![]; - reader.read_to_end(&mut decrypted_bytes).await.unwrap(); - - let original_bytes = get_original_file().await; - assert_eq!(decrypted_bytes, original_bytes); - } - - #[tokio::test] - async fn reader_with_noodles() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - let mut reader = AsyncReader::new(reader); - - let original_file = get_test_file("bam/htsnexus_test_NA12878.bam").await; - let mut original_reader = AsyncReader::new(original_file); - - let header: Header = reader.read_header().await.unwrap().parse().unwrap(); - let reference_sequences = reader.read_reference_sequences().await.unwrap(); - - let original_header: Header = original_reader - .read_header() - .await - .unwrap() - .parse() - .unwrap(); - let original_reference_sequences = original_reader.read_reference_sequences().await.unwrap(); - - assert_eq!(header, original_header); - assert_eq!(reference_sequences, original_reference_sequences); - - let mut stream = original_reader.records(&original_header); - let mut original_records = vec![]; - while let Some(record) = stream.try_next().await.unwrap() { - original_records.push(record); - } - - let mut stream = reader.records(&header); - let mut records = vec![]; - while let Some(record) = stream.try_next().await.unwrap() { - records.push(record); - } - - assert_eq!(records, original_records); - } - - #[tokio::test] - async fn first_current_block_position() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the current block should not be known. - assert_eq!(reader.current_block_position(), None); - - // Read the first byte of the decrypted data. - let mut buf = [0u8; 1]; - reader.read_exact(&mut buf).await.unwrap(); - - // Now the current position should be at the end of the header. - assert_eq!(reader.current_block_position(), Some(124)); - } - - #[tokio::test] - async fn first_next_block_position() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the next block should not be known. - assert_eq!(reader.next_block_position(), None); - - // Read the first byte of the decrypted data. - let mut buf = [0u8; 1]; - reader.read_exact(&mut buf).await.unwrap(); - - // Now the next position should be at the second data block. - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn last_current_block_position() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the current block should not be known. - assert_eq!(reader.current_block_position(), None); - - // Read the whole file. - let mut decrypted_bytes = vec![]; - reader.read_to_end(&mut decrypted_bytes).await.unwrap(); - - // Now the current position should be at the last data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - } - - #[tokio::test] - async fn last_next_block_position() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the next block should not be known. - assert_eq!(reader.next_block_position(), None); - - // Read the whole file. - let mut decrypted_bytes = vec![]; - reader.read_to_end(&mut decrypted_bytes).await.unwrap(); - - // Now the next position should be the size of the file. - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_encrypted(SeekFrom::Start(0)).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(124)); - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn seek_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader - .seek_encrypted(SeekFrom::Start(2598042)) - .await - .unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader - .seek_encrypted(SeekFrom::Start(2598044)) - .await - .unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build_with_reader(src, vec![recipient_private_key]); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader - .seek_encrypted(SeekFrom::Start(2598044)) - .await - .unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_first_data_block() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_encrypted(0).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(124)); - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn advance_to_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_encrypted(2598042).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_past_end() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_encrypted(2598044).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_past_end_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build_with_reader(src, vec![recipient_private_key]); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_encrypted(2598044).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_unencrypted(0).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(124)); - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn seek_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_unencrypted(2596799).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_unencrypted(2596800).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn seek_past_end_unencrypted_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build_with_reader(src, vec![recipient_private_key]); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.seek_unencrypted(2596800).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_first_data_block_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_unencrypted(0).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(124)); - assert_eq!(reader.next_block_position(), Some(124 + 65564)); - } - - #[tokio::test] - async fn advance_to_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_unencrypted(2596799).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043 - 40923)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_past_end_unencrypted() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .build_with_stream_length(src, vec![recipient_private_key]) - .await - .unwrap(); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_unencrypted(2596800).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } - - #[tokio::test] - async fn advance_past_end_unencrypted_stream_length_override() { - let src = get_test_file("crypt4gh/htsnexus_test_NA12878.bam.c4gh").await; - let (recipient_private_key, sender_public_key) = get_decryption_keys().await; - - let mut reader = Builder::default() - .with_sender_pubkey(PublicKey::new(sender_public_key)) - .with_stream_length(2598043) - .build_with_reader(src, vec![recipient_private_key]); - - // Before anything is read the block positions should not be known. - assert_eq!(reader.current_block_position(), None); - assert_eq!(reader.next_block_position(), None); - - reader.advance_unencrypted(2596800).await.unwrap(); - - // Now the positions should be at the first data block. - assert_eq!(reader.current_block_position(), Some(2598043)); - assert_eq!(reader.next_block_position(), Some(2598043)); - } -} \ No newline at end of file diff --git a/tests/test_segments.rs b/tests/test_segments.rs deleted file mode 100644 index 3716512..0000000 --- a/tests/test_segments.rs +++ /dev/null @@ -1,143 +0,0 @@ -mod test_common; - -pub use test_common::*; -use testresult::TestResult; - -#[test] -fn test_send_all_b() -> TestResult { - // Init - let init = Cleanup::new(); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(ALICE_PUBKEY) - .arg("--range") - .arg("65536-131073") - .pipe_in(TESTFILE_ABCD) - .pipe_out(&temp_file("message.b.c4gh")) - .succeeds(); - - // Decrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(ALICE_SECKEY) - .pipe_in(&temp_file("message.b.c4gh")) - .pipe_out(&temp_file("message.b.received")) - .succeeds(); - - // Count - count_characters(&temp_file("message.b.received"), 65536); - - // All Bs - grep(&temp_file("message.b.received"), "b"); - - // Cleanup - drop(init); - - Ok(()) -} - -#[test] -fn test_send_one_a_all_b_one_c() -> TestResult { - // Init - let init = Cleanup::new(); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(ALICE_PUBKEY) - .arg("--range") - .arg("65535-131074") - .pipe_in(TESTFILE_ABCD) - .pipe_out(&temp_file("message.abbbc.c4gh")) - .succeeds(); - - // Decrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(ALICE_SECKEY) - .pipe_in(&temp_file("message.abbbc.c4gh")) - .pipe_out(&temp_file("message.abbbc.received")) - .succeeds(); - - // Compare - equal(TESTFILE_ABBBC, &temp_file("message.abbbc.received")); - - // Cleanup - drop(init); - - Ok(()) -} - -#[test] -fn test_rearrange_one_a_all_b_one_c() -> TestResult { - // Init - let init = Cleanup::new(); - - // Encrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("encrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(BOB_PUBKEY) - .pipe_in(TESTFILE_ABCD) - .pipe_out(&temp_file("message.bob.c4gh")) - .succeeds(); - - // Rearrange - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("rearrange") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--range") - .arg("65535-131074") - .pipe_in(&temp_file("message.bob.c4gh")) - .pipe_out(&temp_file("message.bob.abbbc.c4gh")) - .succeeds(); - - // Reencrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", BOB_PASSPHRASE) - .arg("reencrypt") - .arg("--sk") - .arg(BOB_SECKEY) - .arg("--recipient_pk") - .arg(ALICE_PUBKEY) - .pipe_in(&temp_file("message.bob.abbbc.c4gh")) - .pipe_out(&temp_file("message.abbbc.c4gh")) - .succeeds(); - - // Decrypt - CommandUnderTest::new() - .env("C4GH_PASSPHRASE", ALICE_PASSPHRASE) - .arg("decrypt") - .arg("--sk") - .arg(ALICE_SECKEY) - .pipe_in(&temp_file("message.abbbc.c4gh")) - .pipe_out(&temp_file("message.abbbc.received")) - .succeeds(); - - // Compare - equal(TESTFILE_ABBBC, &temp_file("message.abbbc.received")); - - // Cleanup - drop(init); - - Ok(()) -} diff --git a/tests/test_util.rs b/tests/test_util.rs deleted file mode 100644 index ae30827..0000000 --- a/tests/test_util.rs +++ /dev/null @@ -1,82 +0,0 @@ -#[cfg(test)] -mod tests { - use crate::util::{unencrypted_clamp, unencrypted_to_data_block, unencrypted_to_next_data_block}; - - use super::*; - - #[test] - fn test_to_encrypted() { - let pos = 80000; - let expected = 120 + 65536 + 12 + 16; - let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(100000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_to_encrypted_file_size() { - let pos = 110000; - let expected = 60148; - let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(60000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_to_encrypted_pos_greater_than_file_size() { - let pos = 110000; - let expected = 120 + 65536 + 12 + 16; - let result = unencrypted_to_data_block(pos, 120, to_encrypted_file_size(100000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_next_data_block() { - let pos = 100000; - let expected = 120 + (65536 + 12 + 16) * 2; - let result = unencrypted_to_next_data_block(pos, 120, to_encrypted_file_size(150000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_next_data_block_file_size() { - let pos = 110000; - let expected = 100176; - let result = unencrypted_to_next_data_block(pos, 120, to_encrypted_file_size(100000, 120)); - assert_eq!(result, expected); - } - - #[test] - fn test_unencrypted_clamp() { - let pos = 0; - let expected = 0; - let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - - let pos = 145110; - let expected = 131072; - let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - - let pos = 5485074; - let expected = 5439488; - let result = unencrypted_clamp(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - } - - #[test] - fn test_unencrypted_clamp_next() { - let pos = 7853; - let expected = 65536; - let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - - let pos = 453039; - let expected = 458752; - let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - - let pos = 5485112; - let expected = 5485112; - let result = unencrypted_clamp_next(pos, to_encrypted_file_size(5485112, 0)); - assert_eq!(result, expected); - } -} \ No newline at end of file diff --git a/tests/testfiles/alice.pub b/tests/testfiles/alice.pub deleted file mode 100644 index 0dfe3c2..0000000 --- a/tests/testfiles/alice.pub +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN CRYPT4GH PUBLIC KEY----- -oyERnWAhzV4MAh9XIk0xD4C+nNp2tpLUiWtQoVS/xB4= ------END CRYPT4GH PUBLIC KEY----- diff --git a/tests/testfiles/alice.sec b/tests/testfiles/alice.sec deleted file mode 100644 index 3e9f752..0000000 --- a/tests/testfiles/alice.sec +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -YzRnaC12MQAGYmNyeXB0ABQAAABk8Kn90WJVzJBevxN4980aWwARY2hhY2hhMjBfcG9seTEzMDUAPBdXfpV1zOcMg5EJRlGNpKZXT4PXM2iraMGCyomRQqWaH5iBGmJXU/JROPsyoX5nqmNo8oxANvgDi1hqZQ== ------END ENCRYPTED PRIVATE KEY----- diff --git a/tests/testfiles/bob.pub b/tests/testfiles/bob.pub deleted file mode 100644 index 0951cc9..0000000 --- a/tests/testfiles/bob.pub +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN CRYPT4GH PUBLIC KEY----- -JXGe7vpNZpWEhsxrIE/h83xst7sQ+2INpaoiGjtLIDg= ------END CRYPT4GH PUBLIC KEY----- diff --git a/tests/testfiles/bob.sec b/tests/testfiles/bob.sec deleted file mode 100644 index e6d0106..0000000 --- a/tests/testfiles/bob.sec +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -YzRnaC12MQAGYmNyeXB0ABQAAABkb1LLjyLNrcL4IgMD+NuDDQARY2hhY2hhMjBfcG9seTEzMDUAPFfaFm7bJc+pr6IRezakf5AsP7HTZnVfhSBt7XIKQcJBJY/yrPSfLxLvPMY4Edu4r0hyJTX2CNqR7wmwYg== ------END ENCRYPTED PRIVATE KEY----- diff --git a/tests/testfiles/testfile.abbbc b/tests/testfiles/testfile.abbbc deleted file mode 100644 index 9037c30..0000000 --- a/tests/testfiles/testfile.abbbc +++ /dev/null @@ -1 +0,0 @@ -abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc \ No newline at end of file diff --git a/tests/testfiles/testfile.abcd b/tests/testfiles/testfile.abcd deleted file mode 100644 index a2d9df0..0000000 --- a/tests/testfiles/testfile.abcd +++ /dev/null @@ -1 +0,0 @@ -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd \ No newline at end of file