diff --git a/Cargo-recent.lock b/Cargo-recent.lock index ae7b3d61..e00cf714 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -25,12 +25,11 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "base58ck" -version = "0.1.0" +version = "0.1.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +checksum = "365c0acd5b2e8dd0111a46c4faea83fb3cfb6e39a49a7c73a06e090db7b2eff0" dependencies = [ - "bitcoin-internals 0.3.0", - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.14.101", ] [[package]] @@ -59,17 +58,17 @@ checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" [[package]] name = "bitcoin" -version = "0.32.8" +version = "0.32.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" +checksum = "bb0ce8bd5baaa0d303a19915a6d93afed161f528654e42da2a7a97d05c59499a" dependencies = [ "base58ck", "base64 0.21.7", "bech32", - "bitcoin-internals 0.3.0", + "bitcoin-consensus-encoding", "bitcoin-io", "bitcoin-units", - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.14.101", "hex-conservative 0.2.2", "hex_lit", "secp256k1", @@ -78,19 +77,12 @@ dependencies = [ [[package]] name = "bitcoin-consensus-encoding" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207311705279250ba465076a1bac4b1ac982855fff73fc5f67e22158ac58cdc9" -dependencies = [ - "bitcoin-internals 0.6.0", -] - -[[package]] -name = "bitcoin-internals" -version = "0.3.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" +checksum = "6712f9c6fd6785b3b270884e57c441c403dc5d7e19ca45368c97c7a1de3000ec" dependencies = [ + "bitcoin-internals", + "hex-conservative 1.2.0", "serde", ] @@ -102,9 +94,12 @@ checksum = "d573f4cf32996a8dce612e4348cece65a241f1882ed594047c9ba348e8869fa5" [[package]] name = "bitcoin-io" -version = "0.1.4" +version = "0.1.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" +checksum = "bb5de036369d1ac59d3c1819ebc4d850f89466f5401c571a285b6ed564a4cb78" +dependencies = [ + "bitcoin-consensus-encoding", +] [[package]] name = "bitcoin-private" @@ -114,19 +109,19 @@ checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" [[package]] name = "bitcoin-units" -version = "0.1.2" +version = "0.1.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +checksum = "9cb95693f371d089a4b5b6fc41c6f3ea6e01ee8c15388335dfac8ea685173b51" dependencies = [ - "bitcoin-internals 0.3.0", + "bitcoin-consensus-encoding", "serde", ] [[package]] name = "bitcoin_hashes" -version = "0.14.1" +version = "0.14.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +checksum = "bca4c7abb40c8817d77403c880988cfd484f23ab2365726afb2f798363e2c4a2" dependencies = [ "bitcoin-io", "hex-conservative 0.2.2", @@ -135,13 +130,14 @@ dependencies = [ [[package]] name = "bitcoin_hashes" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a67800fcf7f3ca52f7796d4466948a424326b225950c79d1e76d0458760bb25d" +checksum = "5304e53726dbe5f93141535e102ed97b5bf4714fbecefdda8f9fb98d7fdaff0e" dependencies = [ "bitcoin-consensus-encoding", - "bitcoin-internals 0.6.0", + "bitcoin-internals", "hex-conservative 1.2.0", + "serde", ] [[package]] @@ -176,12 +172,16 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "elements" -version = "0.25.3" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c63a04238f4b7f3564fe9705921452c2900efd00982545e5c634fac9024fe2" +checksum = "34e00f7ddcd826d2f4c9bd72d79a6b6991a0ac4286e7e2b2ff8eecd130549073" dependencies = [ "bech32", "bitcoin", + "bitcoin-consensus-encoding", + "bitcoin-internals", + "bitcoin_hashes 1.2.0", + "hex-conservative 1.2.0", "secp256k1-zkp", "serde", ] @@ -485,7 +485,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.14.101", "rand", "secp256k1-sys", "serde", @@ -601,7 +601,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75c8fb4a18e63fbce4cf16026c36a6c38066e4f4a09ce5e81be817d0e36d8f8" dependencies = [ - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.14.101", "byteorder", "getrandom 0.2.16", "hex-conservative 0.1.2", @@ -615,7 +615,7 @@ name = "simplicity-lang" version = "0.8.0" dependencies = [ "bitcoin", - "bitcoin_hashes 1.1.0", + "bitcoin_hashes 1.2.0", "byteorder", "elements", "getrandom 0.2.16", @@ -634,7 +634,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd2cc5d458a8032d328ea85e824f54f61664ab84c3d42b3b7f8804fb9b81572" dependencies = [ - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.14.101", "cc", ] @@ -642,7 +642,7 @@ dependencies = [ name = "simplicity-sys" version = "0.7.0" dependencies = [ - "bitcoin_hashes 1.1.0", + "bitcoin_hashes 1.2.0", "cc", ] diff --git a/Cargo.toml b/Cargo.toml index 8055aa8f..54a1061f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,9 +26,9 @@ path = "src/lib.rs" bitcoin = { version = "0.32.0", optional = true } bitcoin-miniscript = { package = "miniscript", version = "12.0.0" } byteorder = "1.3" -elements = { version = "0.25.3", optional = true, default-features = false } +elements = { version = "0.27.0", optional = true, default-features = false } ghost-cell = { version = "0.2.6", default-features = false } -hashes = { package = "bitcoin_hashes", version = "1.1.0" } +hashes = { package = "bitcoin_hashes", version = "1.2.0" } hex = { package = "hex-conservative", version = "1.2.0" } logos = { version = "0.15", optional = true } simplicity-sys = { version = "0.7.0", path = "./simplicity-sys" } diff --git a/fuzz/fuzz_lib/program.rs b/fuzz/fuzz_lib/program.rs index ae39baf9..6745baf4 100644 --- a/fuzz/fuzz_lib/program.rs +++ b/fuzz/fuzz_lib/program.rs @@ -4,8 +4,7 @@ use std::sync::Arc; use super::Extractor; use simplicity::node::{ - CoreConstructible as _, DisconnectConstructible as _, JetConstructible as _, - WitnessConstructible as _, + CoreConstructible as _, DisconnectConstructible as _, WitnessConstructible as _, }; use simplicity::types; use simplicity::{jet::Core, Cmr, ConstructNode, FailEntropy}; diff --git a/jets-bench/src/data_structures.rs b/jets-bench/src/data_structures.rs index bcb2ad4a..2eacd32d 100644 --- a/jets-bench/src/data_structures.rs +++ b/jets-bench/src/data_structures.rs @@ -4,10 +4,7 @@ use bitcoin::secp256k1; use elements::Txid; use rand::{thread_rng, RngCore}; -use simplicity::{ - bitcoin, elements, elements::hashes::Hash as _, types::Final, BitIter, EarlyEndOfStreamError, - Value, -}; +use simplicity::{bitcoin, elements, types::Final, BitIter, EarlyEndOfStreamError, Value}; /// Engine to compute SHA256 hash function. /// We can't use hashes::sha256::HashEngine because it does not accept @@ -182,7 +179,7 @@ impl SimplicityEncode for elements::confidential::Asset { match self { elements::confidential::Asset::Explicit(a) => { let left = Final::product(Final::u1(), Final::u256()); - Value::right(left, Value::u256(a.into_inner().to_byte_array())) + Value::right(left, Value::u256(a.to_byte_array())) } elements::confidential::Asset::Confidential(gen) => { let ser = gen.serialize(); @@ -324,7 +321,7 @@ impl BenchSample for elements::confidential::Asset { let mut rng = rand::thread_rng(); let mut asset = [0u8; 32]; rng.fill_bytes(&mut asset); - let asset = elements::AssetId::from_slice(&asset).unwrap(); + let asset = elements::AssetId::from_byte_array(asset); elements::confidential::Asset::Explicit(asset) } else { let asset_str = "0abb0d5d5843b9378c7f245fd7329d6fcef6926554f0c95f7cf0316239178f743c"; diff --git a/jets-bench/src/env.rs b/jets-bench/src/env.rs index 21cf158c..b55c2ed6 100644 --- a/jets-bench/src/env.rs +++ b/jets-bench/src/env.rs @@ -1,7 +1,6 @@ use elements::locktime::LockTime; use elements::taproot::ControlBlock; use elements::{BlockHash, Transaction}; -use simplicity::elements::hashes::Hash; use simplicity::jet::elements::{ElementsEnv, ElementsUtxo}; use simplicity::Cmr; use simplicity::{bitcoin, elements}; @@ -190,7 +189,7 @@ fn env_with_spent_utxos( Cmr::from_byte_array([0xab; 32]), // dummy values ControlBlock::from_slice(&ctrl_blk).unwrap(), annex, - BlockHash::all_zeros(), // Dummy genesis hash + BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, // Dummy genesis hash ) } @@ -206,7 +205,7 @@ fn null_env() -> ElementsEnv> { pub(super) mod txout_utils { use bitcoin::key::XOnlyPublicKey; - use elements::hex::FromHex; + use elements::hex; use elements::{confidential, encode::deserialize, schnorr::TapTweak, AssetId, Transaction}; use simplicity::{bitcoin, elements}; @@ -218,7 +217,7 @@ pub(super) mod txout_utils { let asset = rand::random::<[u8; 32]>(); elements::TxOut { value: confidential::Value::Explicit(v), - asset: confidential::Asset::Explicit(AssetId::from_slice(&asset).unwrap()), + asset: confidential::Asset::Explicit(AssetId::from_byte_array(asset)), nonce: confidential::Nonce::Null, script_pubkey: Default::default(), witness: Default::default(), @@ -233,13 +232,13 @@ pub(super) mod txout_utils { let v = rand::random::() % 21_000_000; let asset = rand::random::<[u8; 32]>(); let xpk = "21ddd128bfa066994cb4be6880f0589075996203d8a7e88f136eec662b8912b8"; - let xpk = Vec::::from_hex(xpk).unwrap(); + let xpk = hex::decode_to_vec(xpk).unwrap(); let output_key = XOnlyPublicKey::from_slice(&xpk) .unwrap() .dangerous_assume_tweaked(); elements::TxOut { value: confidential::Value::Explicit(v), - asset: confidential::Asset::Explicit(AssetId::from_slice(&asset).unwrap()), + asset: confidential::Asset::Explicit(AssetId::from_byte_array(asset)), nonce: confidential::Nonce::Null, script_pubkey: elements::Script::new_v1_p2tr_tweaked(output_key), witness: elements::TxOutWitness::default(), @@ -247,20 +246,19 @@ pub(super) mod txout_utils { } pub(super) fn confidential() -> elements::TxOut { - let tx_bytes = Vec::::from_hex(CONF_TX_BYTES).unwrap(); + let tx_bytes = hex::decode_to_vec(CONF_TX_BYTES).unwrap(); let mut tx: Transaction = deserialize(&tx_bytes).unwrap(); tx.output.swap_remove(0) } } pub(super) mod txin_utils { use elements::{ - confidential, encode::deserialize, hex::FromHex, AssetIssuance, OutPoint, Script, Sequence, + confidential, encode::deserialize, hex, AssetIssuance, OutPoint, Script, Sequence, TxInWitness, Txid, }; use simplicity::{elements, jet::elements::ElementsUtxo}; use super::txout_utils; - use super::Hash; const PEGIN_TX_BYTES: &str = "0200000001013fe9fcf1d5eae66a152efa45ad32baa5eed3cf11ab5e04edde650313b58ed8c90000004000ffffffff0201f80bb0038f482243202f0b2dcf88d9b4e7f930a48a3fcdc003af76b1f9d60e63010000000005f5c88c001976a914d7cc0ea6d5e53af78c7802101519cc100692668e88ac01f80bb0038f482243202f0b2dcf88d9b4e7f930a48a3fcdc003af76b1f9d60e63010000000000001874000000000000000002473044022048cf10f12a31cb0ec36ba3a6f79fad7e0dea3f1aa790a5aed02f8e8455c8cb1502201a2624089ce70c893dfd07a156ba91223edd5680cbd93d3336285ceefcb3dc1401210205914becd15ac5d2f72ad0aa42e84349c825a544d8c16e78ecc21534ef561fd4060800e1f5050000000020f80bb0038f482243202f0b2dcf88d9b4e7f930a48a3fcdc003af76b1f9d60e632006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f1600141ab7f5995cf0dfcb90cbb02b63397e5326eae6febe020000000113244fa59fcb407124038ff9121ed546f6dc217571cb366a50d3193f2c80298c0000000049483045022100d1e212715d2dcbc1c66d76f43d9f326f54ff339b565c68f046ed74040730433b02201d9ccbad57566100a06b4be47a4c777cbd7c99e0a08e17f7bf10458117426cd801feffffff0200e1f5050000000017a914774b87be1ef871d82a01edbb89a70bf4bb59310387a88c8b44000000001976a914b14b7395623921dbbce438f4fc1fc8f1a495affa88acf4010000b700000020a060086af92ac34dbbc8bd89bbbe03ef7e0016930f7fdc806ff15d163b5fda5e32105949c748222d3e1c5b6e0a4d47f8de45b25d63f145c4056682a7b15cc3da56a2815bffff7f20000000000300000003946c969d81a3b0ca473ab54c11fa665234d6ce1ad09e87a1dbc56eb6de4002b83fe9fcf1d5eae66a152efa45ad32baa5eed3cf11ab5e04edde650313b58ed8c9fccdc0d07eaf48f928fecfc07707b95769704d25f855529711ed6450cc9b3c95010b00000000"; const ISSUANCE_TX_BYTES: &str = "020000000101975891c8466c3eed75f817e16867e4004786afe652c833db38a6d8ff37626ea10000008000fdffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000846378d77e3e759fd90a42a99cf4b95e8819db99d424ce3fd0352ec16ca9115a5093b64687ef20c5c3da2d2695c42aecd775d700d2ddb9a903a3eac8d661b503070040aba8ea89e00fbd0e14bcbeec94b883ac4fba0dafd5e795658bc1d184ad80c625809da1bff65d7958239c186b5dd8ef23606903bf1f5961893b3e3d7dd44902e4ea302f8fceaa7a53a51a24cfb9666f2d798224a5a84b60d26483a9da385362b87300616001455c29f7cf389e353362116c2ee374857c013129e0a3a07091f4e203f46aaa44d17824ba311243ed38a70fb9b393bde312d5b4460c208fcaab83caf46df2ee16c162094809fb9dce4b642224da210702be1b04deb94c70381d9c59df43aa717e026743f9c54c2048756eddb6d5992a56627102194852f9b160014feff6610a74105b33e4e8d2cac73f3d05c944d270bcdadac9b7bf23a96bdbb9f488bf7909f76d7ff997a5551a38778a7e7aa5f8b540889d6c664ee5d6a106dadb07a987843fc2fb965f356821a59db1dc1f7e1aa839f03fbd0226d70bba5a6fc866d4c980b677cd9112e98aaadfc671ff7e39e49a748ab160014b6d0f377bd2d2dc48ebb374b7107a15d4395ff8101230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b2010000000000000251000065000000fd46104033a1497f00233f81f0687170526b203c1d6f34ef9c7d73bd2ccafc3d7de5fa4e69ccd7bf27571e7b49803282a8dd2fe98845efbfcd2d28de571a1d2c077228effcc0ce338457ab6f3d15ea7fbbdff8024ceefc72eb9345d272a3650b6ad1220a173cc7ad90c7b6d108bc5bf20e8613ee76b8f2280f55dccaf5e0adb7eb50753288693ea99417bc7588db0f4ff798a503885da8ab6ae3be8b628ba48c7a4c80a6067017705486e7c06ec509557f7d75e2e75db784a1293f847a5940e725d86a505f720ce43c27df97ea2fc05e003cc74c924fbe8513454ccf6fc54e73987a59f48297175e81fd8ccae89bcad6006501c6126bb94ae7bbea35f1e996107015eaf7bc4e046bbfff3d324afc1f8a764f91f0775aac6c328a9ee2c28c74673e62a0ed7ad630738329be8d586bda0e6224f42a9d7c4b4dbfe505ce513e9bd2d2f78a7c3977d74ffc5790dc50f913c80e8b1f23e6b236c790a9578e956b039ee8940bcb3f7d87c8da028dd60b078130c52d553d63ec02689a62c4d0f365dc53cf406b6ed3ee3eb60a280776452712635788f6583e875c598ab9ca6a96a2b68e99853abcbc1ba113bed2fbf05fb63c5fef34ab38e10f426309fc0891bbbadc44979409712a3ce7cf01a31985eeac0f4dbe00a57a20ef9f766025102b1428cd8adcfa63a7ffa25f89c2ba8e6b92cfe660135f1714179d455f014a9875005afa019a434d285927dae2e285bdf82721d65d2f095fdbe83cd861497e4875a69961cd44b6895485ce325c074f69ccb60c8831a7437ab08f9d6da84f40f65d5a63b409631d0a65eb5285c0f4837ff71f2a7391f51d10865731bcab4943bbfa3feec2433640329753a134a9035caeb9bca8287c5bd723252c8f6849b80e89f9355200de5548f081a36c5a1cc579be24b8b563aa4025c005cedfc1bb540fa8792749b971835edc741fbd211fb45ed6df5094714a8ba30f3895a8e2a4314d944d00791a19f4f811bd7d67a83df31614b43f13c59ef1d20e28d589a505a1acd37a4ff78e9af2d132063af9f5fd7d9fb3cd6bf9f3dc73cd4cb3479f7c36c23135d8c962fb531d16ed8fb4055151c6216cf53bbf1cf65ee63d9bf85bb74bfae527022619c4f0d9e8d3339bde33bb789bd25bee0241acd1527283f1cd58b7bec00b6f30931024e30c18469002e825bf6d10240b0163585cdff2845a077681996558fd63f1f7c373b54af1c2da61bb015ff70895e1072136d3b603d329c428871750858a70a222ad73560bc73e5ad24f541fc4a32f734a2dc722f24579b505158f39bee0cfc4c9890245c2defb368b6d6644a2579ff4a23082e686c94bcfc4097589efeda5810c363acd8290ee29ee76baecb178a228de614388b79283df07396195c4d2d3aadb7ac3f68cab163c8a1157e5ce4c3502cba9032918bc259434c4b12cbf77d08beb6cab6e19ac3c7d2d82a6b792a0c1de08540ada9c45dfab36b4c71419d54f25959d7c95e2c0301982caddd0fd0f9ac45dfb1cbf9a6cbb3111f7e5a9e8a29870c1029cc0d74df8f8a852dca511aeee22c471b09d8cf18eb85dddf9273c5024de0d0d617f3609d6e09a2d0f2951ae35d07f5f27cd47f217a939d56aae2c8ee2d95836bbdaa5c816082fe2bbb1f5c7a114e1b45ddd448c3ad19cdd7ed04a087ba00524ed8e16f295b4ec28f5ba5e0077d3d0ef30e718ce5a1d9c8430631baefcc9c26551d26f42ab64041129304eb4d76720d94adf9f2cece3627b2833335dce5f562ae2169ef44f12ca36a26d45195847b8eda8836177025bc66aa4f103d662ba1de526db5c7ad2899bd9e22245445022a156a2b47022853ca473588172efdcb8e61c8d20962a8c92d3a86e83050ed75d6a152915eb0e1051800b79d15b473899f4fbd3d47d6e7e72982d6c7adce00e51f0b1033bd1112091418ef979b4aa7f4c942b31ecc5bc9cbddeb3812906a172fbcfe085eafb901140710cea913779510648a79fab4917f96efc5e7f28b0fd2c813805760d657a089a015f6368f2b471539c8ca2b33c4800a6a201a21daf09a194e1962196716e0a645c72dd1168dead6b64b0ef16ef4b73dcb2b56d517c082f218db141059cc7d52d5e5e0832f13030be8e3b36605f9f9749fbb1b1b4805a5720763ae406b32498f1aab809088489a6b71e2274ec26c4964f2e3bb32063013868a030af901e8afb5f563e3a690726b7afd3761ab9cb3abaa4849355d0183dfc66d8e8bace12e739c9a9ae1efa0d9d8f58df3352e7f8c1e24e2a0f71c861ec09428bbe837145ec1b50426c24725bdd025da913b689ede4c8d57c8cda6a48a5b246b0ae57e4dce9cd2cfd0604b217f806650ac957aa01aa9f37e601bf1fbe36e0b3359a4b7477fb4e59c48481797694b5ef3b51ccb7a69910617988bf1b5dae18ff0686d722fcef097d55ec74932643a285242243a96288525dbaab523d55ab28aa0b6df74c4bb2d90042c952c5412d379357c81fa1618e3cbc855132e0e63242fcc2cdcd1d96663ab8f112424f7deb4aa6a01976d4d8c9e82303b3323bf1a77a9392b8141aba33df3a02f3423d50136a65aafa4b993a36ebe4e1ade2f3c8cb70bdd35b4787180cfe14ce82e81f60aea09c052f74a41045eee52844cb50e257dad50ca3e8f3631f82366252cd4dfef33e6106edee6764d25d0a0cf8c9d8dc0b126064d2efec032890724e40ceb350a4d5df729bb22a878fce0b4e698b16c251db70a49f1275ed28a7e678f2ffad0047a118d7f8202f417ba2436b285cbbd0f1c2710f08d73b31e54ad9e1164c6fc1ba1a5c9666b001f5d8b7d03e97a48d338890b41b2968c65859e18907a08e7f96da368f2143f63d09c0948e6e7a3b41210fe7ab7a48668339d0f5e4d4de1b8c0cef095b228dcaaa0ef8c6fc1d8d65cda7e9e81137aa8d0595b53c6bd9f831debee20784e790af3676039b7f4486e28ea28edb66dfdcaaa62f286099bbb62066023278de78030c30a7bc33f5ee2d2fee4705eeebf1768c7ee1b15dca01eb82f818589ba2362feee455c568f38c306d964987e29cd50408c73d171f93c4bb1e4937bbd786d567bd3dd488a440cf95fcc1a54d6e0b35173421daa01512f970e89738251fb75701c5c849720290e49f124fe3c4e2885b23b055b1cf6b7ea10a07614e9f2eba7bc953158e11130167fd2081a09381329449e2f17fe7403db46b0ce380fe846cda85e4c085fc0dfd8a86d4aaa4fd6c1b2804b13c70a4a858180ff1450a4c11aa576327f78e74c3dccbb27d178ef09575c4879e84d49b41caa3b3dd282f1b464d0df4bc01565123ead10bdb9273544b058032807482774fd9e705187bc6a4927dc29a23a8d6e5d7c7b54432546d5a2f341b2d90ab6866d9177f7f8d601083a53444b16b1e9ef4ff24954f4a3bc5fa25af61ce9a5c1ee2e507eb4f4022b4c0bea888491b1201477eeae5ae432a262b8c9da98283b895f484dd911a7c503a258e9b4ea01f07ec66fce68be4372d87b304d7840362064b7443ec227df0d25ad6e695f800be0bff81cb68d8f05c89318561209f6e36952cc30c0a2f3b66855b63d388d55a44013096f2bf8941804cb202685deb23ad0fdb92de3a780051fe5f644483db93c95fbff0a30e0d1b1a476f1161953835665c761b7190b1520b5880896e0c51ae6e3090fab2554ad56dcf0d8311b0256a5a4561460b01741e843d4b0c26abfbabc519dc2141d3aacb6ae7713cf2c95803904ace06f667d114193e655e1ff0ce724441cedfd21ca3268cd2f586eeb150c08c55540e3c621e77986c4fd07d5a586a787fdb976a1549d982c2620dbaff166949c99f5d52664fb350025976d1f78d00994442df6d552cbc567f0d9d7b4d391876bbcc3b9e61f2f764b2464066f3a491042f7376ce4f28e63e6d5d395e5ef6c529d6eb3a792ffd5ea1016fbae24188d96bac0a9c40a3c024a4432a27145d72d0f9c91f373ad0fafb7c4503d3668ebf8c090a805a98d272c6f24ca0f8c98f03f3c9d33f38c92200d4e9a3d8fe2034c195779c2fb261e57b1a067f177af54f2ad7fc49154582a70f7da33500a849212717756f06e53bdcecd41b75faf63afcad04118a3ef956d72643b7d9737107354a3dd3b24f456aa4ab45f00b4a8d2a7617a9bc9dc2afca3c2e478ebde4634a73d1b6b61c99a14bd4b962bb3e3fdd9a00ab928e1a8fc1dcdd0a4ac463ba693ecd9d1ba40199c8f423ecdce7f05f928f5aab1baebbf3c0fa17b114aa12bb3c6ebc7da0b113e3e2886dc092b787a738fa1906c63c815c2ae6d51e97bd44fed8f1b83f5c4f9141971e6947c88490f67637c03cd7e354f74fab3494f40c869a57f67b6525501cf19ee9ae93430b29cc680c8b31dc8e8950a06c43e821ab86f16d275a219e49f9cf94016b7c08c8ceb161c52e8bca8f8044669a96c160c1e38c7e65afa862264ec168dc6d4a6a9d70625341ea83daeb15b93fd20d449157271e01cd591f4ddb9ad8b4bed1e1402cf9ca6964653288c78d673803df2505c680c840ea6fb7411f1cf229184f1331b8c8ed82d1ec7d35a8c4de9fa04b6283eb67fc4a164c122506921e49f9b6726b97168b53b3dac93f302e79dd260723dd077716083060cf2e363361fbba6d8b86723c64382d59fe20920e9d5aa133021a6709901b535c63c4795845c78a7e647e39340dc6b74d3e7341c49bd8af57c9abb2261a328f33122026043e4f32b7ebecca9d9250f186e81906143f409ef36c8865577e797e7d57381a0fe633df73b59544c16ed8b8f852f3e033da0ade4412a4d1ce584b47abf8ac4ac604a90a0f316b621c87ef7200bc10df3221533e1e54a6bde13c549c95f8060b4149d351ee10e33217470125bbb4bf327bfd5d151458dc249aa4b57f14979fd53b09ec2d01b9358739fbe44e7ba4c54a9e6bd483801605cd33dfa84e7dee0bfc30d4b4e2b0c45355e13a92f9c588725829de2e9efc0adfd807c3f8a32b623548785d07d3520f0933e5d5a280efc6724e03dad47013bf54338ef4956c9be1b09681429f9cda18a11df04ac0ed66f28d2f3722aec5fc0f169055e9f5357d15fa6d53edc35dcc5dde72ca418c618994a5e8cac6c2a115e87b27d2d3af81654c23d476f49b606144814cb36ca892b0e0d4673a2091c4f948079eca42f66e000432255da0c99cae1542acf0836398e067b8d13b9e1e9a149bdda367bd65f88af269078ac8cdf79a2b303287ceaac470b050b6884a44c86ccf413e50fecedffd864c16b18bf3c59cc9c0e2c3a84a37f7dc1bb53729f306f40827d30eef367ad5217a5c5f987da8003b08d55b90014cd828fed7beb4c4afe6bca378aae72f8c4c3eeabe1c1b7edb44f1ce8abce27c16154ea58015fcf9ca99200005729abd67473540c4c9f20d1d0875697dcf01b2cfe61aa729a9f90475bbb720e413794df4079bf3199ab1a071ee448dbef39a9d1e2c7462cb6a56d558389244b4542f913325dcc0c2517dfaea6cb67a1e5ee8e9e7f4b4b343b33588c28f6cf82be5aca0c0b51dc7c461dd05ccb9766814a17d0e491a61b87bf134002441fc1c4f3b060df87b065f75f30121545755397015f0c4b8c7cf855defc20af97349281147ce557e40d292b36950d58692162dac1993c0ca4fa61fafdc1baa39e50302666546a8c3f74c2e0b53b3f0b9307dae1834a284aa6a2f811af925037a7a69a0585689d31777cccabb18b7e3f5fb5644339fd998d3a3886e3e1bd5f85fcc39f8e5d14005292c275076636179c93c8b2593661f7ece42551ccc1e43fd78a0331001b7b3b9a7dcdf40ff398a43e07be40ec2946f994fe8647f854b86f8c4fd735dea6cdbe7ee962fe76b788f3405392e747293043c0938545f1d78c00c1cb84991752936fc6f0a72e861f032253c6ba214fd46104033d2543400eebc89cff38ea74f8b07f174b6917951751737e2a917818fffe7172adda4808ad17522f3d76e16489d4b4098b049353c053a7eba7fc13f9129fe41c6c2301782bf9a1ad16f22b7308e97ed7a2f29f5f948a13be4117dcbdf069210d93d508fd03bbf6430f4f788a097f573a34f430304d3518c5e2b1669f23a3d7597a502da41a2f92aaef8922d8603cc0455691cc59d28a004ad2f9385253874c2073d0e2575c48a8c8ed8a273bc2de878e217be56d318821c4205c784b838c6b030ce821246ac7b8876376ac0131735b66d616bf6c89b1f183ba62d53913be941462d67adadbc9f546be9099e895b839875952e2845bf468326b8802d44931d7fa81a1b7a048da7065538c6700c68213f16060bdf5c0ee5cf25066e0a739f0816d551d404e00b632a1f76b254ff8e93e24f45e6ac9f7c62486cdab28131fc9f77aa440295460b38379d347718daa871929743a8b5f19237b6e58c1cfa5645559fe31b99ae317de28d8b7fb5e32aa9f163a8479635e5ff564280ca7dae3ae355fb2319c624f01e6ff1a3c5f6e98dcf5d58c943a49b49e2d10c6b6d7cf355397bcdf3cf9be84e7eb3353f7bfea193f1b6b22309838b081fe37609daf49ac30a8d0929c189ef58148d92cdc584bf9ae21b13e7998d7258811a22738f4cdb7de66967411dffbaeff7947ed330a20f9de0ff91cd2d282153fce0d29637c7c064416611b13ac77585d03cc8862b8a93ddf03c1efc52b49417ac9571312f6d216f74815800ed6827bcec56b0ee6f55ec8e4b8737ddcab9a8e966b7a64fc1adc3eb04e8aeb44ab5633f12f57dbad58d121997621c3fd3a750d78f4a9e581a0c468eed32f8e2d340c76f5604c2e4a9787a153c51588d518ae7f5f3b4d7b072b4a953c594a261870dfeecec4c3865f98a890312f3e6d0ebbceae695f415ae93e18eacb14616f40d69bde463bc2190bd6a73174c26f838b49ac8286544b2a31d8dadd6e8164b823436490bc1d6790de250e7b80de847a856a5bfcacd44c172672d52fb2c8e6e04972596105d3372ab4e9d68845843d457d4d54b21fe2f4e4d117f5fa2ec13d671d9cefaf00fc5d61c3e9b5b565ef84afa535008115f8e6d8b8fb8ad2744a337b967054c6c45da0a6f820bb02f07d51b7ff10820421db70ef08c24d9d913deca3ddd1aa2659cd1d349a9606b35de2735e058ce86d0fd2ccf147867aa9f9c236bb32d82c4bec7d8e77a159d5057650ebb161ef1940d8e64fe4b6fad3bff7621848d3e8401cd5ab25a910352aea58e06c4549d2b7907011e02b1ba94774a4a66b24466f641d376976db27bd23ce682fc4341f5d449d13b9d8fc2f9a67db302083a53bfc79ba2e607cede1c2cf95d1e529262cf48908c889944c4db1b5e8555d86effacb882d148993a1fe91f567b14b43424515aa75852a50f73fbc5751e11c2467e695bb3ccc95f77e11ee44d7c57927a255caf5a5d7365af8af604a097097855d4627b44855549566e00fb530f52e15c1365ba86aa7d60f1ef9929b2fd0ce8526bb7adbeadbba9ed7e9ee60a11cd3952b2b142b3c348d5fb7c1e9a1a7cfc8c75937563097ff18bcfc00cf7bafce608a7caef0f18210ea76d30be1c866697771de2027f4c5dcc15e68342c7b413438939db39677838867379bf6c85c684dc72d00e4a7e15ae21ab863f0901309a673d85563feccc8a5e489bd7ee96ff697f7308a97ca31d71e8db533feb347881d7891f9e82b15a2a0fd725e523b41d67fba6292d177599c7ef1f0860f341d7002dc4566c72e3862abe80711acacfcf8162fd3d6485063a53d73acd54588aca581f1cd846565b0216e871cb65fa6d77cfb46445dd843df7c7ae759951fefaeef9a4301223e296cdf5ec4a6730580a51ce69ae044abe974bad7273534f4b2f668a3a7c978508fe9b9058668e56f6dac062e78205229a831feb67327c12e1a0166e34dba6cef41a72af91ee00c270f1b1abd6aa80116d2f76e6861aae614e7d2a70bc0045dd5005acea24baecd3be3cb6b5fd4dc8e15e396568842ab82e638edc93438050fd7966217c5a523942d2f6bd52a9f414493748c0c26069b30c8b2ee1d2ed5748bd2b79071ec7c53789096ba2e78dc19d4a904bb73e85c18cba02139c429a6f634ca6688034655deacfc4881fe2ab2f9b2d192102ac72084a33cd1525f4e99e52e18e9a7a70fd139e6ffdbd18e9f9f69bd88ca6c51b5f8c164704cd5d5fe9ffd1da9f66ff0b956953f5443cf3b2673718b6e159961e8fd39ff5de5a5bccf92dbb5fc61f58a7e6ca4e5377771ba062faa584965e136af0395ceab6ee5a92b97ddc6935fb14e77f63226a473e7026f62956262d21328fd6a3540415efb91513938c4dd48fa8fd39aa5752591aeecf183c49a3802dbeec2b6acfe2f2b541dbd0957899eac632d053ead0bd0dd743a2f768afbb8e2498763544c6b84972a0a5c809c68db911228f4a5c7bee0ffe26f841e0357117940117299ada73759495898253da36357e0233ef46f36bbde01a0829acb0134653e653aa714708cea625d2b664818a34e96a90fc2c26b6891654ee3afa0156b18fbf336d28bc6f29c8075ac0327f20a9b263a6c821d292de100cb211678874f29aa7c94fe9aa33158d6408e370b23b8b24b5d952fc75a1f3d45624d11d07a262d09aedf64fec483c1663ffe6efbf45afb69b5cff2cbf373ea078cc268965c8754247042acda43d49ab34ac9d8d55023a76d42ae858731cceab3c324a935df0f226b1f4bd1b15843ad68ceaf81a630871d57663dfa60bda287e88a3e36906895213edc1a387c3306d139555679e40abe5ec9bb7af1e1eca841d1e58dbb84282aa4f79f2c7e27a5c8da392930be19ed9bc14abb2b032eca39f6a6b4dd63eea4917d8e3f10c1a24f02ee43b5e61bcda2351f5a9525e50e99244947c8a8b7e36b0ef6a9b5c81d7a463aa8f899f91286e59b5accfde4d60fa0dffdaeea610ebf420042210ea39e841c9369761633a2d91ecd2db4d9b5f6ba3c0234acf6482133ae1dedec1311f66e9b2c596ea7348d2a97f69d3c8f6ed24791a7099e7ca434561cac27bc923398a3791509002ca65e90a363cd24ca901171073fde0ca56cb5a3c30d79730f001f6742fc60d65fe92a9c0ac21c7316b048c8e912a8a15f1258c94b6f70b964e7761e5d66e3a197e36b1d9e7cf0199282cfd8ab6fb08fb6fc416bb5fdc27e90df8f19da219600b3c534eaf857dca7d81ba0e6d39fe200b79580a4d50d7049647c95293bf7da983507844bb0ae18970354124834f2a84fc7a3a6c0d73528465bde9f919ab23e7557e023c9576efd95cb547c0f8eaedbdf889c10c2fb006b1c283c26f7103189a0a7411f5ba4ac1bc1adb8a481c82c470af023cd0198258c02abe70f6a7d3d88ad1db0140f553855fd3ce0c20a1ba30cd2dc66fae3b1a2374f6b70a72b84224e03d3a7d368bd265009a94f49a0e9d4fe9008b2183bb51e3ea4b2ec2eac830f617606403226a88e4ca85ba83f634d5953b3507eb6c9c0085d13cd6deb27beab2e18f0568a506da251d4a2eb0e4e57eb3aa28ae0831ee55bd17814b0231e0d6642540e73f8e56f016f1e9465123f27ed192b1e6fcb84f8cf03dfc0cf107fe3bf68700173c614f5ec79c8a513fb332df753e14d9de20514002dc34d845d78c1d9facef86f9e19717d505b2d00aaf90da2ed5a60d032ea41b893208a838633f084e940bd228a96e6c4af51d320070e096541551149b3a764407ad92b9331eb82ee66e26e49da13e1d433483b5c4edf3fdfdb780f7b76a7bcb467fcdb5db6a9b0e63eb390c780a850c2c9f1d3683ef9ca949c03c6851f04602ace98ae57abcc2d99f330a369c4bd2b4adb13f70d0f421a8e386b572f33d16e70f46891f33c9f978280dcaf5b28a7e98b5022ff33517fc1ebe69fe7846f48fcb3d8c9c3790787d740c4cb42369f52b18c420f76c0046eb3da8b4999b28d6be977a33502608937036a0a770feecba941c08703eb5c3c6adc91e7c7cfb7475e3bff85075aa41f39dcb2813675e13516c0e2c13a5cc1ed685e00f7d8ebb6f0fd5a2d174df43f7d0601f39694df34d7287dbfef1de686277d6d0506c59f73a4792a15b49f4916f0b051f9da8a14ece65871f2dc653b7d5902ee0ba771985d9f0432db9fc22bf468567f4c2e19ac23a2692ad8e155d433f53aec7294c01c9cf7172715391b2c0b53986c6e06f77959780dc0ee0c4b6f2f6fa1753d8582f2bb14f260f34f33df6ddee30c8dc823f7be6c40d0df760590a9445f7ab0cf5d5a3f33e0967bb023e205f7737d390d0ed6c52d22726aded20d3d31928810463bd511b1ee3f6ae11337712fdb8a8869337b4b8819098b8c1b725127c8bc48646634f31ce0487bde029e6960dca8d27d67473a9308a47d1ef35519ac9fa56eb93d840bc5fbdef88f6017c38849fbec727ba4da247a3c560a08776efa9a3743ddd18e9a535d60d74aeb5c0092aa15728cae216fe4eddfc4b99024732eff574d7eec2199a2bdcf9843d61a01bbddcc283e9fd9283ed91e92af964d84e5102470ee5061f66d132602158481362fea94ab9c4dd19c1287d8a38d8722d6f9f5f0a0573bf0f623cc5f2992f881e5101e436b2724b1d671152fbfb38caaf67cf25d5c304cf72b14da11a15c47aa008969a616e67643f5491605971c9e3e2a4f179b7e59df1c0f031903d486e0fafe65e69a2f5c934bc8badad20619c13a1eb9214e989d3a34c562d654a5235fe87469f2400920fff5e0e4c8e5b3e3fa928289ad378bb674e03e9249b7632253278c9fa1a240a2a2e33efa823e538ad267e980fb453037d5e109184515d0486fd2e8474c8219d093f2ce316f5af0e04a8c63005d5f7dd86c152d77557c38c1ae1d168ea06f1d9514091072a917d966ea0d931a559208221ce4b0fac75980b87948f1ad561570cccd0daf0828cacddac0805ab0e5a13df399b61a5e9de6c49adf65dcbe20c2f81ebd4fa4039e80d0727a14e6e0b0d3b800c47ffe37468d21e84e3977dcd64d3cb41cc30007d0cc574f1d3e600acc0c9b8e1f9095e4889ba5905da0af2d97cb68f0c1143cdb3db961d11ddd6971812cc9204f801a7ff5a448c0c9e86a122026d4ea74d0b2def69b056757f7d7910981927ab0cdb3820edb735c170e7379146edde11bbb4964e27aaa72b9c977431a540784df74d9cc601d2a447ab6837d3798fb49497d5931b74aba2a563928daf05c4b95a4a1cf25c38e8a6d7e17bf36e0c621b9351bc8e009cb848c827b4526f0edfbdeadb3d734f78f00fc03570b83f7d5840fbaf905af3b54313055d95e4d697f53e9b61479eb8c428f87a10423fc862266cce54350e81a94cadab7d2f70c67225363a8e63cd002c92b769c4fd30737d444a3c1e897e367ee423b74841bfe50360a49efd0c256731975d9a38d04fa57454a25520ea4f56c1ed65683e6d012b8c8ebc3237c56c54556b3f8ca63f5c766364ed4794a2b15e8b70cdf67d552ed4fd8ef0ac159e3354efb440f323da3d1595707c49924dc0dcb06a9128a7e0524a5fd6b6510dfe539bea327f9745aef775da6ee55455505dd8ac5a2959ed411fda0daea56d25dbc9c7d3a67761cc3ea2e6c65e600e4db7890bc43b4cee6db84e3bdbe9b4c2d7c1e0af8abbb62f8fafacec372a5a30fc935a73904dba6a6e29e5582b1089af5cfe5e98a8591d2a282c4c5c8a52f2701e16278e659c00160ee1d0863905991dac6b290ea877cdf531db4fcb8fd7a2b0826e57601d65f9b4a895ba5869e45678e66dec8654049ab9743ddd9341138eaaf98713b4006b283134ec2a6cf4b12c624a4c620ac77561cead9a5c11a7d5b4b0ae3f92f72a4f3baf13eb4253498d6df7128cf935b075bec291800247304402200279ca59f49ab840062e5d5d3e1448ebbd381ca68ce2c0ce3cf0cdeb5357302302204c6b09eaafad7a019fdace6cab0335cfa1114f026b8ab91a9d11c8888b4e99b201210356f8a8c1cefde4ccee408bcfdf092f7f811da92e4f99d99231b3a5d8c58a490a00830300072589ea79c4dd0b6d3b2aa0c1ac0768a29a6b7a2e78127b2d8ca9c039506b28a3457584b47a73efb3375fe373e21e8395d4c1783d30193e571057dfc6ad94d7eeff5085548b88a7155b56e33b8fe545281765a07217094da53d1688992b1a98396a0451494e974da12ea68ad1a0a372ae160eae0f425ae227ecaa27aba4547f73fd4e10603300000000000000016fb32b0047f0087d30de68fc697678c7f4a95254a2004925e057185ff09d3b7f60b0d7f9af606b1846239a35843c6e6e221eaa9aefc0ff8b33a1b9a10855a59136d84c20cf675d6cffbb62999e452037baa143650e18e81733205817a8420440eea5490608b149366eeb4d1790e9199a04a39d0cae86ad4c5e250fac55f6953a489484938dc7521351a9c1775a658ead3404618ea8f724df382e94358c7ef3e669d9affbd0a2d6b79a6740464940eeba629a7bf7950a049366755b88dd9b2856a937ecb30b063238bf7e694ca78bf56e6e967bb820b340945b34c5d1bc55a60e5905d8c6ece19fab342cb977397a38d983b387ba6f1c846247b81e0d34e1589dc89617fb315eff0f4841898d28bd324db24056b6d5311d41bdff31ff881ac3b08d690a67481ee7bf77dc8f220d33dc1497b080b13a5c8660dd63951a76a1835bbf63505ca76d3d3c15ab4415097787b0571c0967db45556322a54aa0a9b8c5eb9007d92924c193796a3fed9debd71f67c6781a39e198ab227b7a060821dafc703f2abed6aae8103742128f087303107e1ddcedd96acf844b1b26cd795d13ef7cf0f184bc8cebaea710fc0bc0f258500df2c82249975e83a4f53dd74f4d1f692cfc49e5ff3ed5563110079df9f073db12fef044ba5fd1d76d4ed90f3c9f1901e4e57c63e6296c9f7aa36ea95941a6b01d7de20048714bb68964077e520f2d557246b92f3d567ffd4685187709e44d3f66a96cd05bec08f8667d6e29109a8240877b42031e56f213524ff6d881385da86e85765d20b2ad132ae191b5e8bec738df5c533c20fbcfbbeab8f0b5aebccaaab1a6df234a05bca892c048367f07e1747d4deef8536c19d2bf0c4574106bbc4bdedb30606f35559ddfff29ac65517477f69b75f6e6bfbb878129b684d25c3634e907cdc04afa579a815994ef6838348e155ef1dce5c4eae478bc2954e2b45ce5d63cdee731f398b98a8628f317fa1bb7602ce13506d84fc8e8852315df692bd0b6545a8d7884930a06d23be3d31b72878045d83018e7e6cdd437bc241dca6b53f4c9635eebe5bbc610da87d68d91eaab2c82f216049a49dc5e087fdea5c9f7890e05fb20f0f93ce8a008874d25bf377e52a346277069097046d27f8929c320ae1934cc5707eb0146fb73f98af7de49a234a17f371c14f778ba90308b7ace650cd667324b42ca790599d02579a38b64d5840aac48d0fe5b56a77e1fa6d034624da585a766a685c9fe2d1a4dc65d64588ee30d950643224acc1744b46a13687078d2354d68771825acf6f57317959b0c296af72499b1da75054f076135a59126d974ad6ef25764d122d35bd96ac0c4fe9cc47631eda9027bee307a74997b9bbe07a2da7c29b69de863149130be9deb5b9784cf603d0fea396fc5556a36b36a5b6951da1c289e6fd595943d258c8bc58541fdded69e7d97eb90eeab944804cb4262dd87fed48ee071c2fbf5a3df015d0fbe54a80dbc7d4d350aed97e91e2f000abfb8002feac203ec5ffcaa7033ba9b1a82a4edb37706db47199e3855f993ab02b6c8501e9a1215565bfd0194655fd98edd33282c7150a2f9369e46e31724c12b870223b0c9678f04a5f951860018ac96928b5d9c18ff1e06205e27e9bb15576a1a651ead62b7b8ab11057b352e1385c60478c369e34c320fa1b36e856a1f302f1da053d4b220fcbed9be7642319024bc712f082a5517d9f6dfa0c2d85af3d8660cd06e71e9de67053cda59926d9e0845d30939e7aecab1dd26f186239b8392500821d4c8dec5a8d0123cea75354a7dfbaa5ebcc9d75c9a307d633e4aae4ecca0a6216c1509dca5b052644dba73a0244e29f5e95ad2c09d313f607ca6ef424fb74481d4427ecd9b04afd563f46136cf2c6bc596a13ada2564c52450dd9b451da52cc1d82002ee68acb1caa38cdc2fd629e10264e908645eb859173b698918ca8dfa2e3a9350fc0545cae228890316c82f491c281d15bdecf2bcde89e9ac435239eaea24a8cddd08aac147633e822f2c57aae5f59ae901042cc15b045a58d78099da9031528e8182ee93433e4183c969cdef637d421c0fea042c1da85f5f338ea9be23c84f0f53456a695ae5db2d54d2e70e5579a6b81d1d3f5e63de0c746b0361d713d2d1e83118eacc7032bbd31c2ea26bb5d55fc47d7b56033a68c567cbfcf8856a7cfe0d37c59f660ba3226d409205a73b5a7b86a1bd6384e93e1486c33540f2e2e29551294be97204cd85f29d38ff11fb1d3dd34edb1bf7eb9e05c5b20318dab896a5134dadcdd197c74f94c0110a8349bf29fe246a0fd54063603de7a67333ea3830779a8d9bb6f41a82ede66103859a25c9116193c95d4e6a9029bf3e301f1b77c5f31d7c78ba43f34ea027ecd7063919ca1ae583d135c008edba60b020804571e33b9ada9b9072b339400d356a54fa3f4000ab7cbb8337400d2d9f130755d87a8b62a91e1fe95a0999f24b56d89a5ad291b0ee96aecc43b08aade1223cf1cc231bd2a18aa175dfc7064692bde34b0f3b6c55e2d27cbf58554484649f1dc52db19bdf284ba1dea6802a0808d87584a3ed0902988b5d1761234ae091ffd917385ffd419224d29f0d8393acfece765eeebc62406edc65c54ccc38bd118f7203e5bb12d2dd21024b34984731f2fccef7d9e292d18c6651d30b7fe47dec4c643c252c2186bc0ddb095c4f96a7ef7d7d73b0e3a55feab61ac088e03fc5d79b0cd44f538c0750aa592b4f9ec5f2f35446c6c4263c292a3ee1486ef7665569d36eaa9bf52b5ebf394facff338923e5f2a802272cf866a59d325f6893c913c55fa215533add8cedf52a1d79098e3c29d4a54929e762d6eb9f23d7dbb69187ba5c11f441575e603858f6729895ce534ac0261f5f88eefc4e3145a93b960030dfa4a5a8a5e287e932ed2375fb29b66d6b563432692d052a43f6caec6c9be33b6cad83e354225a232d056a614031923f67a0322d9c261a4a730a1427e0537749cf4fe20844674b456eee877070aeb10dc5d424f4f1b3d0fe42ef68ec48ed4ab6b2bd4eb52fa868d510badd443a7b22f5c370864fbf279774d26c6314903c2b3517276477db9a4db8f6514b38eb5e2bd5153b73288a0bdf17bafef3a9067216ce5939f5eedaa3dfe8f3a9a0f10b0933af5b37da4542e1323c22e00fcb9ca2f12b6a644cb6709cf491abfc86f8e842ca568de096e36714e2e043f10b039c62822714fdc65818293c44f03c984546f6c20177f212dd8485c20d07f809748a9f93b666daa2999f044016065afe45a9a8e865379489c1e7daeff03ffdb0b9cda86d913e764676112320cedf6455c2c9aea0df7b90c6462001f4cf02e4dba3afc85f283ea1fd69a8a73a9c85ff54ef7e12515f531a9ed0cfb10fa747cc4131737cd106ecfeda49ca336f9ba8636769f41922dc277b5ae95b01bbc15c36c2d93301e4d87279723c6ac79800f6a9a0533e99b3ce272694d4c6df941389bedf36fc7c8aee32ff954705f96b64ee524b7178af060d8113340b142325581839bf29d02144bbabf4cfaa1f6e178412098e2c175b5132dca9288ea1ceeb4517d78883e432e0cede03a59a6260abb55a1a2410b74f1adcb9730d377448cf8fb57d5c00de0b4000c54fe7ff516694e46e6c2b9b4efd5ad11862f368d29b05d0ad9a8b7891715259f00643060d5b348bd5c355fe294971590ff4c03d1513d4cc91fe5bc32b9531560ca50292cb340a1a3a5d7d5b6591a4e6db94b4807b4d33772304ef838912a142206491d7f3ef8c8a2932ef3c04ca2fc19e726a10ed8dcfcd0a2ec81a049afd6aa24ed7a0df80c809a6f5963e93da0e231b748d0099e12c2ce8e0754eb3d006cfcc381ee495234aec6568c978d7e8f44d6644c4638ce425ed3800c3f445ec7fa85adcb23cf78a18fbb5deaa20b47c12896377d032a67056ea192b187ec4a44c16cd7b728941a087a45f9915668a7ce2f120aff50660d66c8477591a4d2f9a79f39f40401342a5aae0ff8253ac62c9d46b09b458f20069f9170c1aa3ccaee649a3fb37f7de2cec2b7c82a07bdc707580a3371b2387c5e110eb9c945d7013cadd7580f3b0590777e7af620b7e0bbe389b70eee42cde184413cd3530083f612069796c9fb81fbcfcd69de104e8de56afb2fb4998b94100b53aad94f2cfd6bfa3f7d0158d549907c9a07b45a22b1a4a190bfd4c9b67132dfe5e5e5a00d37ddd80f96c1506da71baa95082c2b85e0d354ebff3a329868bc5840b17cb8fc4ddcbfd195e447c17d76632dfaaf6b02c5981f88572791f32810c8272408ca9c12ab24952fa50c5efe817fb21d204d59eeaa8d8282f787a92d1cd27ddc7abf8ccb530dd51f9337fcbef197823ef11a23c76e121079bdfa523eb6cfe78e2e8cec31846c5920dcf6700bb3875b0c9fbac31a6e6a1551205e539d39e0f333197131340d9d74c5b343450f4e0dc756d3dadf1b2d25c1d60f244ce0923682b96de22be8e1fbd6e762cb89bda68c597baf8c6c814f760050381041ddcde5f52dac92dfb3b229491712cb1ac7365dbd1bb62f91b6d124ba65fc8d83b532c8d98d96a2e131b8fb943335cf83a2de63e17888557be979c05c6f05550a49abe1a9b00cb77b756dd16a8edae167f38ae784f816c6d8b05edb9db093e5359963a927370b78f14bca2f472a2974b10a37ef0a78cb78754dcb5ec8f59d5e2f33523aab33abbeaea56a5c688e498fee42d202b0c1f08332077ff5360c189c5d30c4384cc8776bf30a67636c711a1396d7f139c57b2cc365d156898979f9a38a2c02b601ca5448e7a7c2981df170219f5a4550ded4ab499f4ae1e47da52b6c1ea441466b6824cde0e2a53bfd6fc636274760b102edf719473eeb4b68e70097d80e739f8f2e1e284228f731db44d327a52efe258f78795b2257dc3478e0a1732e741c0f68074a5520ce4cfaebcee260538bf4954e669cd17887bb25929330b4b2ceb750d64da0cd6ffa5171c4ffc104ceae609fe777b99908e4f46169144c07c5250fc4fdb051ba5335297357039e5957e77b177b974892b19e27f4b7a5e2522429451f84a2b5b2931fb4d5a47319e1df8434caf337784e6d33783a634d9d4a4ac27bdd96ab4684dbf29d0612a1419ce54db6e4af8209ca7da98b18a1eedfa2473653ffdfbf1472229fcf4c528a99995d48003c85511c87957a862b5308b9d2977ecc82b03ea381336fcae95e9c5ffb60b0b487f4f1c212f7f11265d928d095a16a638faa646ef3969c7cfc2d082ddeea9facd508f2773787508e45a969972fe54576120a834b2d553659efd9d9f605aee04c2a36c12b82a13a97fdc2af4211c87585b0378ec2c0cabd769479bf653bedd83c6796ad4c878114dae20affa06fa66daf9cc0e658dbe87cf51637bdb332e6e231ec30b371297d0c7a73d128f4f909175613243973298cb852b008e117ba7d41e71cdd1e24c3d4f6675a26ac8ae67fd8e7e5945853c11a153842196cebf9c791370556e5f3a72deb5685af7aa52ded66bb4760f3bcee98d1a1750426151d7346a9eff2dddb9b7b3736ac0bd0a590e7af4b25ed7fc3b52a5b52c915a3584e1b2383cdbfd8138dd545abc2734864fce88ef2cf12cabe5eea478095ffcc10fc512adeef7d9e8e27d26adef3e48de380e5b851d2b9cc1a8b2f08081308383f71cc61166efe9c9a139a662b94154ae757cc37225521d5f29d27347606fd2698ab7ff3f2497ef1c8efec0ad281f0932f36a8518ab40b946746c5661aeca2ac446064a7c823b5791f2687fbcca8fd2ce95e4994de25a8fba056ac2d5bb8e5a6f5b312c0893c8a7bcae58dcc967f3917dc3c97b3b7ff9653fdf087ed66b847731656e56f83829b0f20ae395d6b4a7587dc796603620553f7dca83030007025608a8da0159d01ce5cc0f7c8f453c62ef23ba5cac9e87d63d854abe7282c506e5eb6dd22d8168ed895e19432694f3f19f0ecce079a1cf1daa0b7e17a193c90d4fb0a155818e1d6fcfa08ed64e17bfb2573a3fb74a4a1b9210d3bd1034f7ba01079fe75b5448b77807a19f418cc560290c9f9ba4b670a9941d5134ece76c9afd4e10603300000000000000018a6bce01807c9bdd76cc5033fcdc479c5044a055e47db9d282b018dfa90f76d01b9fb00e4081f09465fa45160873ca33bdda257bfb2337278edcd9f6abaa88994ff9a932176975d5f971b6a699ecb55231d2e90f7f8a4b1c29fc8062c17de71f5e6d2489be1dd5b8ed07cbd8f5bdacebfe98569f88510cf266dc9fb9139d654f03efecc270ec323ae588076a64de344f1eb1def577664ba6dd07b1856b68deb5b32d4335e25ea784441dc70039e8fed8e56d9ccfc79c79614a79639f27ffa9497abede452de0cae56414662e511f0c01a938e99e88f5e0a7bce74530b4cfdd5b2b4994941cd7d83739f223ec0f18ed192a7d4730725b2c123682af22b9a1f0aee048fa8610fd813705757070838f826c37911f60a2f132f00910fea698e1f0ed735d7c75772c40a76d0af7f349df5974f95147fe8ea1cea847557889efdc3e836abaa04da71be14cba79ec7ed106c35622312994638863c263482e8291ec65a0d9e5c194c1780781c782684fa3f153823013df06f44ab05e0ea00f396053e3dd784819bd0a616eeb6e4ac8a11a5cab14ef40151fee4d7459dec2caa90e22dd2e2e01c082ababf8024a6553bf0e6d085a65948ab12598ffb1ac59c1df05df073fbd015337355db33701847c803318dd348356a657ed1a50344bada887b2559a6ac186883f5cfb2c28239ba699f9747a967b03e8866dabb72cfadfcb3fbb4c800bf3535c22b1d62a372de4113a2e2b90e85f7515ce84eb0152320c176679ce330c8fcaf17e90b62253a139871e1450822fae80af81fd1bd9dad1b7038db01aa6045a8db0102d7155a5ac6f72bb2afa06950d03ed94c79cb14594f6a01eb4f2b42d8b314306b1166a236f239ab47eac097e4c09126730476133b1d45e046ab098a8ae7a43e6014f284dbd83f1596db401452282471848937668b8392a38f961f88618d7aa9f39c07cece10a9bca1ca9749603a7f49791f553199dfa74e6796412c1e6a2b36f26c9030f513418171700ef7b8839c0381ab346950d5eba26a9d7b5ee4044bc594ec05aa8dc8158304fee3db3aaf0266f64d454e3fb0f5adce7d3501b743d85ffe4e889f0c33ffcaca5fab156e2d3c8f1b64f2c41c556d5a7842ce91c826592506c2d66522e9962bf9122262447105eab88e85cc2184ed0b829cdd9b3acdb9e3a59504a9d03afd81f96bd395861c6979f7e0a1fcb392b347599e34786f9a3998d28d945b23860011610a853237a0b6f249df2d99058b83e4defbc06d9df3bec802b41a2fec1b8510f912cfc67c5cc6c35150fa3d08348b5e4bc6da099fe70c737cd8b1c65ae44633e167c9005593081dc8d136799bcf64d416d0820b36b3c49ad61145585a4e3255a11ef4717e844ec52a40b6277499e5d4079de077985d5cab312e2d886fd2c44d7c0934e308e2b04e0c73fca15e764ee4fab3a24451328b5eada8f9cc79c8607d0831e6cf0d98e819ab89450f991a327d957ba2c01f5d9e5496fe09a173103db2ddbd46ac2368f6c1b37d8f5d6c5b0fb13e44a704f2b105a10bdcab372f47c7f316a3e3509a6cac2aa876c3ba96400ec9afe3e39fbb8cb04dec8cc586c62cf2f6f55fb373f5c59776ad1339f83e0d2d8c5c5ec5730c6258f5d7a3c475e295fc42d3cdb1ed8cee098fe576ad58b5777bafe0bbcac85b5a165589519e66c7306db586f23ca3a2fe5861b71303a3a7b27fac2863bb497f2e56e13478c027d8d0c4ee23b2114d0aab5e055361a06127780214c9ea4d7c5faf76a22e957eed5d9b23bdd9f433e05d6dd1ff19497040c7142b2a47b2427b844352ee0d16bb7f48441f13ed04e10a1f5573294b2dfaa0615c218b32da91d4c3ccbf6e2fb11123555d7c8ae790f0f3bbf219b077da42fba400bfa7c4700039cf7ab83ff4c8f2f78b118a8c8419468d46db65d3cba24ad78482366492a300057181d85997980d07de9607bdc78fdfbbd81bfd7fd38b384b001fba13fbb49bf0754620c781fdb2a7d9ecc949c0dfb31ad72d80669ba9eed13b650f7e9b24439a36fd01ced68f0b9e7786ecc285898cbd9c1d8e16a56a64f22b0fdc238e65d7868e382feeccebdd8ac0f3f07cf7c1498cc579ed7902fd69dba058376297773c853150110b557439a197d354e3cd619df5c58de5318795444356be6d647d56fc9b86a859cc7a759d54210f36c9baa0c2b71f1209d465cd44367ad10f1790de61c7cd0f4d1bc819d750324b15ee03d0d0ed62849796f1bf7e28c76bde2180482ea242a906ac21b87c8cd2a8482d8522cd2eccfe259b14cbeabfb814886effeffe3dc2fab36cf01d87759119dcb0617d18b4751f9e34456acbad90f090c799741189404b4e41568e63f3362f1806e31c5b46fab80e4c88b74fd812fce26fd8be6854568587d7ad4fa48ce23d30dde3aaee41dcd80a52a4aeccc5b831c79588c0640b2e72f6a16066f972bb4328771884b75615ac67752eec45cb09c00535a88fcd04a77ee26fadea9f468a1e3830a6d867236a0dfb3110a039d5367439fe4bdfef0ec654b74ffce087dab53a3c73dfd78de16a5b484aff9b0d87146fdefb708f2af7136ed72850377c6c62281201e6c8b3dd66fcb5ad08b5a1b7def79f9b57a069f44ea38f7512c34d19561e9fa787d2b556d2ff9d80ee4b48d13e350f567c162469fb55bc46b41326b5e2a881fcaa3e46bb1e25eda14e41042346c8c803104f4bf7cfc8b8d3066cda088b515deaab5117b280ed6dbb65b32c464f11c95bcdf33e5fdbc08e770037c45e5ecf66c5be861be4c57fb139588da85db47580d097bd3b566280092d1318c2cb9ef4ce36f9dc5209b51137008ea5d232be54f0dcdf37054e02b082d1f4bb6c3c70b2055465f3809566db0a7bf125c35744b600cc688cc20d2cbe891d91f9b94eec38194902910330009498fda15e39502917580e586223c165cd7fc3605b741aedf4bad4c4d3e6b775da1f14920ae9f1ca16be31eb3b98be97d8948fcd1acdd4d4d640d0e9ff1e25776df6442f85e0246a94c87f07c3e46f850c0010b0c441500393c738db192ad528fdf30738ade085f7fe1aa64ff04fb6d2abb661dc7358706a51e274e76effeaf590533d8871090393acfd805398f90272c9f009da27e9eb4b3f2320ea0a86316539fd39a8b94405f63dc74b47caab38f2a72737dddd45b63e608ce86b4e4e552714bef18b0407fd419f3d9ed7449300f44db5557587d862c16da8104d59d1f36e866bcf159e58f57dc4aae09790e16e4759c44d1817298aac924f78d2ff908e41be664cbf7388c1091dceff0b7451d416f6fc2c86eaaa7cda17f88ef8a3e0e38375a587b16b1bf94e554d9b377cff05f58f6b4c409ee659583e487a9a07a19a4d5f3ea66d44cbc6bda11d95c64c9d0bfb2683775da890d12a8101563ef4a0675f8b45963ea601cf4e0d8eb30ccdea3232d16ec4259b08f3f81624085d09f1e22f30bcfcd39e707d1bec0de5680ae6d62366e4615d462a5ec1bf3c5979dd141f29dccb581549f3c6da3d79e9f93b86dd0c0a00c0ae72a469921e851a87f7b09224e2bb7c76563eb5941b75c9b9ebaf997c0ff02db8f7ec630fe9b9d729a1eb13e625186d24ebe8fc8928d535222db7e86e33abcb8184d674aee60a2368753751deef6cfe58a65db1a782beee3e88390b4ac94c4085f6a27b3c6f4ec6000d4bec14d2ee68e58f409547e983e55fcf6f1b7dee0c03f8ded9abdfeee3a615fa9ff40e5ccc1f96a69b29f6c74d463a84b7326fb572adce7449c513b5570ced7c282d542be281f883878b677ac1a3c2ad30e22001cef97c8c30ab7c2e15d8e620cbb321f8bdf3c935a437981f9095f209e06859c15fb91ddb0c961a320e20b9427c767566fdb8b07b34178887ad189ef2637075c9eed26e3433e2eb93f138baae55224ff443109a873c2a92d2da937cc4ca46e2787027418e8df16a8ff164e1c527c4fb2abbbb53f96649ce18178b24a98f8c6f843ac7c1b9e651383eab7fc50af9534a5337ccf152fc26d1351b2d90ac78775ceb8cef457413c9916094f907e968ee54206c595104bae164f6e84ce9391d3f091d5da0adbfa4c32e705a5528dcfa57ed9e3e41525589385b799518caae2ec3c4b3b3adb8077df13e44b90d7dc47b9920555e7e6d419326b5fe1c806f0c174d0db1cf3cbae91fda2639996a965682eab241eb6e82412d7ff2debc030520859b474d65cc9d9ca7a7bdfbe64a0f288b866e42114cd62080b0b539de61a43b3ad0cb5c768b2fdc36757464af8f25bf2d5bfd8ce8b029b62f39434f80df63acebc7f3b3ed313d4face94be2386d4893cb672b35c9e346de162a4d11a13e3e711b1973ee43f57d82f86a043e9d5ab36024328593e67c8dba959e2c4c64d5be48bcdbc4b75d43ac919b6d768294ab3818fd2aea1cbb5f378c97a13f0b162cf6d7f3745baef6862f74d8631cb1f7181029df2b6c6ddff97fbd240a0ecd3593e8ff286c83221813ec4346915a8a9ba2025e7bb545a5372be950b59f4ce665b2e2188a5db21e52f33e89e197a5ca8d0f8fc1921f291650edf4561fecc0e0c802cb917a94d881b7b6b86f65634502b0f5893dd339ba1e2160b7ff2a28d68d25f53e2f1001e7331238b7b75f70322bd5debffb27a84823a57a1a8b36562b7726313ee770d21da76ac1d0731297cf0d73fbbd7a111a965f56446174d5118eb1f122b77ca04b910e268b0420b95b9dd43f083559cc608909ca31fad8ba978b211a7a583198465a344ceb5cccfc68c5cee065f69b692e49d01a9d91f29148fda8e767f605d8a361f27b6cd43f5d1c0ccace1fc84e510e75d580f3340a5296ad09d67ea96ff117283cf15e5ee7f5fc38ed9c390322718fcd6367a1c5bb3414492cd74acab5ea9dbfb168ad45860bb17c0f9a62cd0d7776934c2a4b26368fba0e668de85d6749c05bc061bb2d98d4f87f7adebb8b5045d572f70ec5baaa4b7b61abb42fe5d01cdba6c32e3599f9393011bdff7a3eb0e2f240b00f67422657f67ff5a74f0c6232d9092fa7da5429565649911081d7b0079835b6a11623559b3069a8f6e5c00ed39f9957b277c57f9354103fb2daff8363c8f5651c6f79c1b6b369ffacfb61fe71f8e866d10c3960b8ae7980312a84fecdb98ae9b6d2705292677a4f184294136095f6266f84ef5327565f349fb6109e8773b7054adfde3833dc994d674bb3b7c13867fcc3420000ef3c7be5ca8fd361384fb1aa04f2a08909ed6c20a86ce9743a38f3d90fe08f88b13dc3fa4b5a373f7951742cecb957e9bf9cedf23d13052222b9b577da222287b2e9712d91a6529e9c846682e4ed7a64be6ea235cb1688b20bafa35302d60a6122a57d735e85f8c483b938d6b933e0e29e52ae9da9dc4e9e4c33990c7cb3cb0eb1f876bd75447759921e99144559c511e51c7cac3bd2bd8e523d15e1b01a11c7f6fac154966e11632cd8bed9bfb9030ae5eb1784ccf20b3bf47c20fd4085d902db751a011928cf117463b7a1334000bd1ae68c2b467d5b998bf1be6f119454f07cc651f6264ff0843e18fd6c4e7c9875fcb4870dc1f11fd39e415b4893f81c180de2d09e4941d942c27cc7b17b1a33242a380b18cae7bd67ea49f7d71f28c7592bae562be8281a0e4bbc9e5f35e44db07c34ca1fc72d3c5cce645afd998edcf42d907b8e7cd140f7a83d4c5782a08cb2e37dd4c9f5cddcaadc2051f852ad8f2fef5b2d3161c2d24e709065db507e6d5f680b9075255a977cc092f3f893c70e39649a842c4ca491ad6a7b282470c28f43879b2204f2cf6e48c744759374657112ea1923289615d2e3e2df6f65578663d4196a59b72dfa98f306e23eaa86b786167dd701eee22a2068115002666e5d4b7686dd5b7951b3795c0b4c6c15290e083030007299c63a202890a17310328540685462ae2007e103086580efa3f1087466958e771ed3b44fd53012ede8c2380ac27ea211e392c2d42aee83aa3984550ced069f6cbf14bdd7410ee4211d61c94c156e7183370dccf7964552ec081c5d34fc304fb3c90a77933d0379b37c11292988866102e7c62c0ed6543d8ba47a13526ed6776fd4e1060330000000000000001944f1e003fe134b5ee3189d6eee87d81b57a1dd8d05d96d2659fc3b1d79d135b194870e79922d1a1c3956cc0d541bbcba70a80bd66818ad8da670562f7550f8acd03257acca9d4dea7d903039507c7a79e5bab415295938dcdd4abafa2c60c3f9b569c0f69d71c286da31da1732f2a5f07615456f83462bd5d52efaaaeeb7c9e4f569bc73df90782a0533d8832753856abee377a322a00c06942ee2ed98368afaa12ab2708cd6afed4aceb52bf68bb80053d9e9190d6ffc0ec355e715fd1c7616d806bd2d0c4319eac7cc33e3fbad9f49afc9c350d6f46ad8cd20cc99a7f304b5a9862b934dcc464b0167ce9424f22edeab320d7afd7a63591d079153df40cd63753e45babb4a14ad9610c79634280a4cf12310aca855beb9bab0691f7e3f3ea928af82fe79c61bf8f1fea647ae9215769e52f204aee66711ce76782aa929e8f5dffb2a3b053895b5c703a2741bd7a33940d6ea68034125e62a1ae0148a98ae2758b53d340756c01ed40b00225eb040dcb339689e7bd3c9f7b49f63035726ec276137f6f114162b9b7c777b7d76c33e74f360a77ad9e70dd77e68ffa7cd368a4e2a709b647f45d1352be8e866a4c10e57e7cd2c99dd1902cf69030aa67ef92ed13e6cc65fa448f348e6c1488d1a559de2daf1f44392771ac574b910595236e7d47c59187592f22ba4720552e47f708e6969c7f3930f6990300224f76416fc17c3a2b362526a2fdcab96d97de78e8a6a308283e467df0d8fca3ba7a097f8bb57eabc3185d70590a10ef8f22f0e98bdc2bec07d4cd4b32e836f14ff4ef94583c18b9d496c35c10ebbc948541eee1a2e574cc271606a3afce260bbc930d2dcb9dfcc0cdb0b11764302d770f3315b0cbb89d60c244ff442b20114432837943d29cc7b57d62927be6e180a2e9fcaad5e512b116f4810b2edf539bacc88d929d6e9e467b8929221d1d94f270d55b26f7d1ef3bde741941941d09f5368d295bd0b7bc26a5a17f7d05e8f111615cc9c9268e62c7d6afce346bd90e7df5d5c5e3c35e35ac58f2e4fbd27df087d2ea563d523229c35065c8fc2f45fe559f3ba015a2ad1e25dff624b3e276e3a26f1c79839a46db1eb568f3a7bd1cba3e70154d3f841f83f3c5311c30d84f0271c3cc6ac30b76d03fdc8a35219db36e610c521794921c21f2677c31c7f62441a3ff4c3ae51f84bf8751896b0ff2ba358a5b682f6b7c82427cc8f237476cf2f33ec253ca282f0e76813b5c39d4d39daf39470a2fe5d7536597ed1f3e5eacccd12d026c6eddae22cc2f824463e409fec56fd2e8a37a45bf3dd5925522cdb5b2be245b329bb906a327a7af9f76ba39abf2d968946cd0811f79492f1137596307afefb7f2e236260f94e3af0a0ee3a2d70b4d4fdf4e43f0cf9db48547bd3c1f0025e2ef7df60bb7106a4f6f7d6a0918ed7c205c9af79dcdfa7604eebbc1c4dd4027fd591afb34ee90796daca1d31f3300ba3d9afa3425ea51003e1b807a6b87533772e83ea6da9f6af8959cd87d1706c6afd98bd287a5b15ec3adb39edee929094a8e8d1193f4c857c023082925019adb6ee174066db2efe400b6d2dcce7ed95f277358fb7a5147408cf1b5e57b3b70c0ce0aeab5f1dc076dda4e3506d74270e6e177614c925d16c9987338da03c8eee837370120d5c3b9db22be11fb6629ee3a3707d9beb266440d093b016f431e12f8e538ec150624389a2445df96e8a555ecf74d6539f094de7297323c0923deecab854201d2199074442b8f13f56f16bed0927cd6f7bb0377ded7a9af040f7b9751c92d631073d659526c72188adf502d7802cb0182c4eb0f3bc0d85f0dc888a1ec4db0ab1d92f5d32b1206106bbe73bdb1c6aea7b0982b03df95cb3392ca24e046aef46afa0eeac40c8d333bb6eab09360a7d0a3c4d9b5e14ed06cb4bbaaf2918ea03b6dec268b4a326ed0063189196e08eeb5ef3013d64faacd12b5244bb927f5fd597565cfc0ea7882b03204b29e7457774745b83f29c4251859215af276aae1e6359659748df526840216efb41ca896491585a430c565fd86b1af9fdac03a7f5d91c9f2ec7b7d8788c416655a3ee3dc7c94fc1624f49e101ec6106b19a6552d9b0a69993aa9b22f550b0ca684ee54c5067c5e5e8e66ec76ce11776966a4857a4a4481ea153ef69c0006393395615d279867620c2a83941bc7117b3a0bbdf9c59aec020ad8472eea1ec2adb957d8f6d06128039846e7987d60b520f95ca54ac3a14114dd8c553aab25e04597ce8aca711cb9917748d0e58497fe3d248d15852da7a532b103d258d91ad24768d7f99f5d4914e5eb08c5c69ec1f0708376ad457734d22d23f2197f2c4bb7326a2af2cc1be87ed78f6aea444638ece8e4371fa6b3ca26d48082c0296dde972d9b613ead8d4a7f13916a093bd99bad57ec024004373232c191a36cbf24145c3d07e3155ef18aee937c0eb2893bff4132ebcf219de041cf0487ad3343b6fdb69bb4a53b96a6ebc6e30a16c95d7f33aff690882031877f7b0b856198d11965b3b1741b4f77dd80f11edc65c495ab032fd8a71566d5d2e5ff9fcb6fff5c82e695223ed373de3783bfd72f833ec2589e32fdb94ed7705b072d2c06bcbd6b6c26f39cec98d851fa4cf2182559699c652dad7ecfa9f92cdcbe3a2ef28b0a45573cbb0a23d983581f6ec4755dd6c6aef0ac2df82c3dd90eb29d14bbfcc7a70743a5d4f8ca94b848084933767f943a97df3ab7514e12c90ce2de7502a9687577e4fed24f252353836f98a3e7b25378f8d2d64089b7224f320817d0ca455e9a025e4b1c8953951346ded61f8b010c6fcef02ca767a116bb8cd17df58a69e9554051324c66699f3dc51895ac262cf9f40e3db2ce425374b87e262210f1945c8ab6aeb774c6d29fb299e91221b6086e74bd5064e7d4f6edde94e52f789ac9252943dd26a470c8911ba10e00faca77a707ad00b17c865fabb4ac1292c767d7862b0f88fd10a706fb7f25273dd23a47190f7583aac30f56903a6af2a53c1147d3d25c567e6cd8d1b7e66f6c79c2213530d78a3a580864a9a88b9f0639cf3f7fbeaea83ca5f5620c37ecdec12c48a5cf453a618960a458e460b3cec42612f891526dc8ccdd2126c3d3361a440e630f1e28e29911de43a516e2ff68013469ba8da4987e75510238a57c4fe2dba2d27baca30167b4004f7d16ae51e892b786d1d1ce49004b86a03ad1642f880a40ac723388f8cd6a7fafa5d24ae8f890c36e2b3090923a135bcd1a63e71933579278b51d17b2032f9b6064538029c14de6e371c5078caa81b1d4bb1264a24ccdea14963c755f6f59894e476b105cd1503c30c42f7439bc38f0a942d4d548eeed23f3f6b0437a3549e8c037cf8b02a2bae9a17e0a625c8ee15e662c8ff2471fe6a096093566b0b6070eef04fae4debf0cbcba425620b29988ffc99403b633bbabf642ab6ba50b4839682e0aca599bcfe6b9d8ab25ffe176f1d03cc3f1c019656a860764131d2b856ebf9c147b57a2f639a387817ea3fd26bed54d26131c68cb78c1bf013ee974d2a98e21a5d17b52ab3662043d268df9fc3df15f1d310bfe4b1c6e6cdb8cad182c5bdaeb130301a47a3405b3d68067821817668d6c31247a2ef709e10b0c650390a029fcf6f49f6f61435adade4a23e067fbab9fee9b41e844f93369ef4bf125a2612ecece8337d5c367a727bb393f56629b1f1835ab8c82197de24b4442697d43013fd056b12d7f798e567711134dd17010afa691b76a382f030491622a8ec99108bf1a63a4d16cdb051ffd304b4841e32aca8cf788a2a228c2332d62d70fa5648db427cd46ff6b25c9eeb4b6cec66ceb8e1f6c1014be5b8b4cb995288e4ef833edfc65d0e921831e6a7116318b644a67e406c823bd4bf565842ec98c65846cb79fd4e3f641a56a3f1607da4a5369fa8665bac3dbf60c60db1e82f15fd6de7333d0c1e6ec39d18ea197ccfefbb465c9576e7a621e9de1005c7d057c0054f5235c2a9f9b861e66a852edde3051bb2e3d9a9bd94f5cee2586ef178ff8e6453766f13e4189a953d2a07fad8ce2798a5e4804cde19729835d458b79632db9ef793b19264167cdc8a45771b24ee882a07531e59f529ac965fddff28548a5616beee0fe568c60f0154e30ba6dba2f4ffdacf3c7e865c38eb8128a1d0a33d3db35d1dbd4abb2a6137f4ff5146ef8743e974b8e39ea2af18e59e79f7d8f19d9fd55f207ae08f634103c7ba3d0e51e815870c4f2201c48ee932b855b6ec5d0620670b35d933886d7c5bd340a8be97da01155ce4f9f9cc3a3348d6069e76f86a6b24293c47f0d7a5103ecb5046c2ac806b66142e330856bbf0b2f13b6c5fc61919df8af8bf4cefeda6575b98aa1258e38768110fc8c70df44c1af37c8a37a25a349836e0b03f0b44b5e7351aef29eaae8046a3053acdeea934e4c9c19c23b72d40b8ef2a5e1145fe30437aa98075036d8789f1d118278822ad95463f310d181a1ad307a5574a2755ed1f897ae80034374d621c3239fe99567f33e9276401a60be33b25fbc9b567f0d4dda1b5a1895f6d7da6298612693ccfd8a5c6fd70605571d07080ad946c6cc4a23fbb951b572ca4495dc341f02d34e4c65cd55e91e20cb9e9236cb291d31bf065edf734761666ed1635d9a3a966c05ef84187bc48c78e4cf3ccf25815028e80f5dc4837e52fdf8b7bb508e1c89701e49ab92a2a7bf296e63f3ba1cd254c9fd0d46f03b3ee0e7d8474bd1bede4047080f704e6a97c90714fd7cf8c2b26031f83bf712a42fbb4fbece25e068fdaf9d9884481bf52e36bd0354b01e9d2c42bcc1f4cf3714b3e10ffacb25d179bd85abb48b4ec52903dab11cf70a493d5110bf9d8b1732d3112b0e3de13b3f2c99a484b7c1d6e889537e96d3528dd3ed5315fafceed1e9cd7cfe145ac07c2a09258cebbb81e4462e9edc53e3ddfd411b95c70cf7ebbe1e09598d2b18f573c3dfad52731b663aaeab850bee6ff9a874f00429779a87049a2845b68106db1d1f0ad17747661ffa8f9c4dc8144ba641c3196312538418f53ca44594afd0c6341c407e4049a6c14c8fac8b3a952c7eb1508288d7e3bbc37ef9b3dc8ab9b856ec80c8a06a3f1da9f8190f8b1d64f628305f9365962690e74162e6e50d916c6792b0f4a6423a05efcc3ad63e3e6acc389859322313c7268bbeac37ea629b6b4353aa48f7ea52055ab45ee5953194ce2b0ddb0054943cb5d02fb7c2ca1740f8101539be45eadad4c048dff9aac92ecff51d5a2f9e853527e000646e4d282df506f96c39b3cfa5ee49bd15efad63e7c20e84e55a3f108626f7a40546fd00dfc84b927b9893717e12c4af7c018c2fed42c9b75d3c2aa8fe381a45cfc7c7ac9291d748ea47019b7e0413dee6bda9e6ee79d045b598484c4e3fcae27242e4d4dc05376b73b0f762566b5f6f82aaf787f2e5a5bedf498f0bc1cb358fe1e2e2792e66c1c45e1b0d246ebfe1dd2d828409e1ecd1655d3d67ec2743e83e3d03f25c98a94d6f4c2c35c3c27a11b23847d508782b66738cb7a2bae10be75bb5baee38f9735a6f35a900e10f047b87b288b10e0ed365a736cf14db7fecfcb2ae3328066f38c9c3ce3666cea772c7dfc3f8f809482b8db6f9f6f890530d5be63a8cb0a666fe9170cb8cf5135ecd99b96fcc9066a6ce63bb68eb15cfcd105b30251b09dca1f6f515d322c0055b1087c21d1628368a6eecb5eefccd57a851629e47a4817b18f5af59f8050e91751b6c9d114b668fd69ad29ac8e465c40810bb5204d7cb3ac5641b9acf7741ba6d321c6934b71d37a454698b3b6652e3f5d3d2b5c2be02c38d44150ac2714d9631dc1f32a6dffe0757c51c1ec009b1aba29f0375eceffae3f5fd585e18d7e332b45e0f627864160000"; @@ -304,13 +302,13 @@ pub(super) mod txin_utils { /// native bitcoin asset. /// Returns the txin and the spending utxo pub(super) fn pegin() -> (elements::TxIn, ElementsUtxo) { - let tx_bytes = Vec::::from_hex(PEGIN_TX_BYTES).unwrap(); + let tx_bytes = hex::decode_to_vec(PEGIN_TX_BYTES).unwrap(); let mut tx: elements::Transaction = deserialize(&tx_bytes).unwrap(); let txin = tx.input.swap_remove(0); assert!(txin.is_pegin); let pegin_data = txin.pegin_data().expect("Is pegin"); let bitcoin_utxo = ElementsUtxo { - asset: confidential::Asset::Explicit(pegin_data.asset), + asset: confidential::Asset::Explicit(pegin_data.asset_id), value: confidential::Value::Explicit(pegin_data.value), script_pubkey: Script::new(), // Actually generated from a tweak of claim script and signing scripts }; @@ -319,7 +317,7 @@ pub(super) mod txin_utils { /// Input with issuance as well as re-issuance pub(super) fn issuance() -> (elements::TxIn, ElementsUtxo) { - let tx_bytes = Vec::::from_hex(ISSUANCE_TX_BYTES).unwrap(); + let tx_bytes = hex::decode_to_vec(ISSUANCE_TX_BYTES).unwrap(); let mut tx: elements::Transaction = deserialize(&tx_bytes).unwrap(); let txin = tx.input.swap_remove(0); assert!(txin.has_issuance()); diff --git a/jets-bench/src/input.rs b/jets-bench/src/input.rs index 2226706c..184ab09f 100644 --- a/jets-bench/src/input.rs +++ b/jets-bench/src/input.rs @@ -306,8 +306,6 @@ impl FlatValue { ); unsafe { - use simplicity::elements::hashes::Hash as _; - let mut dst_inner = [UWORD::from(0u8); MAX_VALUE_BYTES / mem::size_of::()]; let mut src_inner = [UWORD::from(0u8); MAX_VALUE_BYTES / mem::size_of::()]; @@ -347,7 +345,7 @@ impl FlatValue { simplicity::Cmr::unit(), simplicity::elements::taproot::ControlBlock::from_slice(&ctrl_blk).unwrap(), None, - simplicity::elements::BlockHash::all_zeros(), + simplicity::elements::BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, ); // We can assert this because in our sampling code jets should never diff --git a/simplicity-sys/Cargo.toml b/simplicity-sys/Cargo.toml index 6b49d5bd..96c3bbf4 100644 --- a/simplicity-sys/Cargo.toml +++ b/simplicity-sys/Cargo.toml @@ -15,7 +15,7 @@ links = "rustsimplicity_0_7" cc = "1.0.83" [dependencies] -hashes = { package = "bitcoin_hashes", version = "1.1.0" } +hashes = { package = "bitcoin_hashes", version = "1.2.0" } [features] test-utils = [] diff --git a/src/bit_encoding/decode.rs b/src/bit_encoding/decode.rs index 92f63afe..2d57c085 100644 --- a/src/bit_encoding/decode.rs +++ b/src/bit_encoding/decode.rs @@ -9,8 +9,7 @@ use crate::dag::{Dag, DagLike, InternalSharing}; use crate::jet::Jet; use crate::merkle::cmr::Cmr; use crate::node::{ - ConstructNode, CoreConstructible, DisconnectConstructible, JetConstructible, - WitnessConstructible, + ConstructNode, CoreConstructible, DisconnectConstructible, WitnessConstructible, }; use crate::types; use crate::value::Word; diff --git a/src/bit_machine/mod.rs b/src/bit_machine/mod.rs index 06d62e4d..d2f8751c 100644 --- a/src/bit_machine/mod.rs +++ b/src/bit_machine/mod.rs @@ -731,7 +731,7 @@ mod tests { #[test] fn crash_regression2() { - use crate::node::{CoreConstructible as _, JetConstructible as _}; + use crate::node::CoreConstructible as _; type Node<'brand> = Arc>; diff --git a/src/jet/elements/c_env.rs b/src/jet/elements/c_env.rs index fc1b534c..25483f60 100644 --- a/src/jet/elements/c_env.rs +++ b/src/jet/elements/c_env.rs @@ -4,15 +4,9 @@ //! use bitcoin::taproot::TAPROOT_ANNEX_PREFIX; -use elements::hashes::Hash as _; use std::os::raw::c_uchar; -use elements::{ - confidential, - encode::serialize, - secp256k1_zkp::{RangeProof, SurjectionProof}, - taproot::ControlBlock, -}; +use elements::{confidential, encode::serialize, taproot::ControlBlock}; use simplicity_sys::c_jets::c_env::elements as c_elements; use crate::merkle::cmr::Cmr; @@ -81,8 +75,8 @@ fn new_raw_input<'raw>( pegin: inp_data.genesis_hash.as_ref(), issuance: if inp.has_issuance() { c_elements::CRawInputIssuance { - blinding_nonce: Some(inp.asset_issuance.asset_blinding_nonce.as_ref()), - asset_entropy: Some(&inp.asset_issuance.asset_entropy), + blinding_nonce: Some(inp.asset_issuance.asset_blinding_nonce.as_byte_array()), + asset_entropy: Some(inp.asset_issuance.asset_entropy.as_byte_array()), amount: value_ptr(inp.asset_issuance.amount, &inp_data.issuance_amount), inflation_keys: value_ptr( inp.asset_issuance.inflation_keys, @@ -108,6 +102,8 @@ fn new_raw_input<'raw>( } fn new_tx_data(tx: &elements::Transaction, in_utxos: &[ElementsUtxo]) -> RawTransactionData { + use bitcoin::hashes::Hash as _; + let mut tx_data = RawTransactionData { inputs: Vec::with_capacity(tx.input.len()), outputs: Vec::with_capacity(tx.output.len()), @@ -120,10 +116,8 @@ fn new_tx_data(tx: &elements::Transaction, in_utxos: &[ElementsUtxo]) -> RawTran .map(|x| x.genesis_hash.to_raw_hash().to_byte_array()), issuance_amount: serialize(&inp.asset_issuance.amount), issuance_inflation_keys: serialize(&inp.asset_issuance.inflation_keys), - amount_range_proof: serialize_rangeproof(&inp.witness.amount_rangeproof), - inflation_keys_range_proof: serialize_rangeproof( - &inp.witness.inflation_keys_rangeproof, - ), + amount_range_proof: inp.witness.amount_rangeproof.to_vec(), + inflation_keys_range_proof: inp.witness.inflation_keys_rangeproof.to_vec(), asset: asset_array(&in_utxo.asset), value: serialize(&in_utxo.value), }; @@ -134,8 +128,8 @@ fn new_tx_data(tx: &elements::Transaction, in_utxos: &[ElementsUtxo]) -> RawTran asset: asset_array(&out.asset), value: serialize(&out.value), nonce: nonce_array(&out.nonce), - surjection_proof: serialize_surjection_proof(&out.witness.surjection_proof), - range_proof: serialize_rangeproof(&out.witness.rangeproof), + surjection_proof: out.witness.surjection_proof.to_vec(), + range_proof: out.witness.rangeproof.to_vec(), }; tx_data.outputs.push(out_data); } @@ -177,7 +171,7 @@ pub(super) fn new_tx( } let c_raw_tx = c_elements::CRawTransaction { - txid: txid.as_raw_hash().as_byte_array(), + txid: txid.as_byte_array(), inputs: raw_inputs.as_ptr(), outputs: raw_outputs.as_ptr(), n_inputs: raw_inputs.len().try_into().expect("sane length"), @@ -262,20 +256,6 @@ fn value_ptr(value: confidential::Value, data: &[u8]) -> *const c_uchar { } } -fn serialize_rangeproof(rangeproof: &Option>) -> Vec { - rangeproof - .as_ref() - .map(|x| x.serialize()) - .unwrap_or_default() -} - -fn serialize_surjection_proof(surjection_proof: &Option>) -> Vec { - surjection_proof - .as_ref() - .map(|x| x.serialize()) - .unwrap_or_default() -} - /// If the last item in the witness stack is an annex, return the data following the 0x50 byte. fn get_annex(in_witness: &elements::TxInWitness) -> Option<&[u8]> { let last_item = in_witness.script_witness.last()?; diff --git a/src/jet/elements/environment.rs b/src/jet/elements/environment.rs index fb5db4ca..202582c4 100644 --- a/src/jet/elements/environment.rs +++ b/src/jet/elements/environment.rs @@ -118,7 +118,6 @@ impl ElementsEnv> { /// Return a dummy Elements environment with given locktime pub fn dummy_with(lock_time: elements::LockTime, sequence: elements::Sequence) -> Self { - use elements::hashes::Hash as _; use elements::AssetIssuance; let ctrl_blk: [u8; 33] = [ @@ -151,7 +150,7 @@ impl ElementsEnv> { Cmr::from_byte_array([0; 32]), ControlBlock::from_slice(&ctrl_blk).unwrap(), None, - elements::BlockHash::all_zeros(), + elements::BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, ) } } diff --git a/src/jet/elements/tests.rs b/src/jet/elements/tests.rs index 936f3084..5430733b 100644 --- a/src/jet/elements/tests.rs +++ b/src/jet/elements/tests.rs @@ -4,16 +4,14 @@ use std::sync::Arc; use crate::jet::elements::{ElementsEnv, ElementsUtxo}; use crate::jet::Elements; -use crate::node::{ConstructNode, JetConstructible}; +use crate::node::{ConstructNode, CoreConstructible as _}; use crate::types; use crate::{BitMachine, Cmr, Value}; -use elements::hashes::sha256::Midstate; -use elements::hashes::Hash as _; -use elements::secp256k1_zkp::Tweak; use elements::taproot::ControlBlock; use elements::{ - confidential, AssetId, AssetIssuance, BlockHash, OutPoint, Sequence, Transaction, TxIn, - TxInWitness, TxOut, TxOutWitness, + confidential, AssetBlindingNonce, AssetEntropy, AssetId, AssetIssuance, BlockHash, OutPoint, + PeginWitness, RangeProof, Sequence, SurjectionProof, Transaction, TxIn, TxInWitness, TxOut, + TxOutWitness, Witness, }; #[test] @@ -33,8 +31,7 @@ fn test_ffi_env() { 0x33, 0x2f, 0xb7, 0x1d, 0xda, 0x90, 0xff, 0x4b, 0xef, 0x53, 0x70, 0xf2, 0x52, 0x26, 0xd3, 0xbc, 0x09, 0xfc, ]; - let asset = - confidential::Asset::Explicit(AssetId::from_inner(Midstate::from_byte_array(asset))); + let asset = confidential::Asset::Explicit(AssetId::from_byte_array(asset)); let tx = Transaction { version: 2, lock_time: elements::LockTime::from_consensus(100), @@ -47,17 +44,17 @@ fn test_ffi_env() { is_pegin: false, // perhaps make this an option in elements upstream? asset_issuance: AssetIssuance { - asset_blinding_nonce: Tweak::from_inner([0; 32]).expect("tweak from inner"), - asset_entropy: [0; 32], + asset_blinding_nonce: AssetBlindingNonce::NEW_ISSUANCE, + asset_entropy: AssetEntropy::NEW_ISSUANCE, amount: confidential::Value::Null, inflation_keys: confidential::Value::Null, }, script_sig: elements::Script::new(), witness: TxInWitness { - amount_rangeproof: None, - inflation_keys_rangeproof: None, - script_witness: vec![ctrl_blk.to_vec()], - pegin_witness: vec![], + amount_rangeproof: RangeProof::EMPTY, + inflation_keys_rangeproof: RangeProof::EMPTY, + script_witness: Witness::from(vec![ctrl_blk.to_vec()]), + pegin_witness: PeginWitness::EMPTY, }, }], output: vec![ @@ -67,8 +64,8 @@ fn test_ffi_env() { nonce: confidential::Nonce::Null, script_pubkey: hex_script("1976a91448633e2c0ee9495dd3f9c43732c47f4702a362c888ac"), witness: TxOutWitness { - surjection_proof: None, - rangeproof: None, + surjection_proof: SurjectionProof::EMPTY, + rangeproof: RangeProof::EMPTY, }, }, TxOut { @@ -77,8 +74,8 @@ fn test_ffi_env() { nonce: confidential::Nonce::Null, script_pubkey: elements::Script::new(), witness: TxOutWitness { - surjection_proof: None, - rangeproof: None, + surjection_proof: SurjectionProof::EMPTY, + rangeproof: RangeProof::EMPTY, }, }, ], @@ -97,7 +94,7 @@ fn test_ffi_env() { script_cmr, ctrl_block, None, - BlockHash::all_zeros(), + BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, ); types::Context::with_context(|ctx| { diff --git a/src/jet/mod.rs b/src/jet/mod.rs index a412aaf8..93732d69 100644 --- a/src/jet/mod.rs +++ b/src/jet/mod.rs @@ -181,7 +181,7 @@ impl Hash for Box { #[cfg(test)] mod tests { use crate::jet::{Core, CoreEnv}; - use crate::node::{ConstructNode, CoreConstructible, JetConstructible}; + use crate::node::{ConstructNode, CoreConstructible as _}; use crate::types; use crate::value::Word; use crate::{BitMachine, Value}; diff --git a/src/merkle/amr.rs b/src/merkle/amr.rs index 2d07538d..21dbeb15 100644 --- a/src/merkle/amr.rs +++ b/src/merkle/amr.rs @@ -301,7 +301,7 @@ mod tests { use super::*; use crate::jet::Core; - use crate::node::{ConstructNode, JetConstructible}; + use crate::node::{ConstructNode, CoreConstructible as _}; use crate::types; use std::sync::Arc; diff --git a/src/merkle/cmr.rs b/src/merkle/cmr.rs index 08f08f12..653940ed 100644 --- a/src/merkle/cmr.rs +++ b/src/merkle/cmr.rs @@ -1,9 +1,7 @@ // SPDX-License-Identifier: CC0-1.0 use crate::jet::Jet; -use crate::node::{ - CoreConstructible, DisconnectConstructible, JetConstructible, WitnessConstructible, -}; +use crate::node::{CoreConstructible, DisconnectConstructible, WitnessConstructible}; use crate::types::{self, Error}; use crate::value::Word; use crate::{FailEntropy, Tmr}; @@ -356,6 +354,13 @@ impl<'brand> CoreConstructible<'brand> for ConstructibleCmr<'brand> { } } + fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self { + ConstructibleCmr { + cmr: jet.cmr(), + inference_context: inference_context.shallow_clone(), + } + } + fn inference_context(&self) -> &types::Context<'brand> { &self.inference_context } @@ -383,15 +388,6 @@ impl<'brand, W> WitnessConstructible<'brand, W> for ConstructibleCmr<'brand> { } } -impl<'brand> JetConstructible<'brand> for ConstructibleCmr<'brand> { - fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self { - ConstructibleCmr { - cmr: jet.cmr(), - inference_context: inference_context.shallow_clone(), - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 5481fded..5a87bdcf 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -101,6 +101,18 @@ fn compact_value(value: &Value) -> [u8; 32] { .0 } +/// Helper function to concatenate two 32-byte arrays into one 64-byte one. +#[inline] +fn concat>(mr1: MR, mr2: MR) -> [u8; 64] { + core::array::from_fn(|i| { + if i < 32 { + mr1.as_ref()[i] + } else { + mr2.as_ref()[i - 32] + } + }) +} + const fn bip340_iv(tag: &[u8]) -> sha256::Midstate { sha256::Midstate::hash_tag(tag) } diff --git a/src/merkle/tmr.rs b/src/merkle/tmr.rs index 28e40a76..481f2e90 100644 --- a/src/merkle/tmr.rs +++ b/src/merkle/tmr.rs @@ -363,13 +363,41 @@ impl Tmr { /// The TMR for the sum of two types, whose TMRs are given pub fn sum(tmr1: Tmr, tmr2: Tmr) -> Tmr { - Self::SUM_IV.zz_update_2x32(tmr1, tmr2).into_merkle_root() + Self::SUM_IV + .update_64(&super::concat(tmr1, tmr2)) + .into_merkle_root() + } + + /// The TMR for the sum of two types, whose TMRs are given + /// + /// This function is slow but can be used in a const context. If you do not + /// need to run in a const context, use [`Self::sum`] instead. + pub const fn sum_unoptimized(tmr1: Tmr, tmr2: Tmr) -> Tmr { + Self::from_byte_array( + Self::SUM_IV + .update_2x32_unoptimized(tmr1.as_byte_array(), tmr2.as_byte_array()) + .to_parts() + .0, + ) } /// The TMR for the product of two types, whose TMRs are given pub fn product(tmr1: Tmr, tmr2: Tmr) -> Tmr { Self::PROD_IV.zz_update_2x32(tmr1, tmr2).into_merkle_root() } + + /// The TMR for the product of two types, whose TMRs are given + /// + /// This function is slow but can be used in a const context. If you do not + /// need to run in a const context, use [`Self::product`] instead. + pub const fn product_unoptimized(tmr1: Tmr, tmr2: Tmr) -> Tmr { + Self::from_byte_array( + Self::PROD_IV + .update_2x32_unoptimized(tmr1.as_byte_array(), tmr2.as_byte_array()) + .to_parts() + .0, + ) + } } #[cfg(test)] @@ -439,6 +467,20 @@ mod tests { }); } + #[test] + fn direct_constructors() { + let unit = Tmr::unit(); + let bit1 = Tmr::sum(unit, unit); + let bit2 = Tmr::sum_unoptimized(unit, unit); + assert_eq!(bit1, bit2); + assert_eq!(bit1, Tmr::TWO_TWO_N[0]); + + let dbit1 = Tmr::product(bit1, bit1); + let dbit2 = Tmr::product_unoptimized(bit1, bit1); + assert_eq!(dbit1, dbit2); + assert_eq!(dbit1, Tmr::TWO_TWO_N[1]); + } + #[test] fn const_buffer8() { use std::sync::Arc; diff --git a/src/node/construct.rs b/src/node/construct.rs index 72568cc1..ad3eff45 100644 --- a/src/node/construct.rs +++ b/src/node/construct.rs @@ -13,7 +13,7 @@ use super::{ Commit, CommitData, CommitNode, Converter, Inner, Marker, NoDisconnect, NoWitness, Node, Redeem, RedeemData, }; -use super::{CoreConstructible, DisconnectConstructible, JetConstructible, WitnessConstructible}; +use super::{CoreConstructible, DisconnectConstructible, WitnessConstructible}; /// ID used to share [`ConstructNode`]s. /// @@ -360,6 +360,12 @@ impl<'brand> CoreConstructible<'brand> for ConstructData<'brand> { } } + fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self { + ConstructData { + arrow: Arrow::jet(inference_context, jet), + } + } + fn inference_context(&self) -> &types::Context<'brand> { self.arrow.inference_context() } @@ -387,14 +393,6 @@ impl<'brand> WitnessConstructible<'brand, Option> for ConstructData<'bran } } -impl<'brand> JetConstructible<'brand> for ConstructData<'brand> { - fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self { - ConstructData { - arrow: Arrow::jet(inference_context, jet), - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/node/hiding.rs b/src/node/hiding.rs index a891824e..2e7bc57c 100644 --- a/src/node/hiding.rs +++ b/src/node/hiding.rs @@ -1,7 +1,5 @@ use crate::jet::Jet; -use crate::node::{ - CoreConstructible, DisconnectConstructible, JetConstructible, WitnessConstructible, -}; +use crate::node::{CoreConstructible, DisconnectConstructible, WitnessConstructible}; use crate::types::{Context, Error}; use crate::{Cmr, FailEntropy, HasCmr, Word}; @@ -212,18 +210,13 @@ impl<'brand, N: CoreConstructible<'brand> + HasCmr> CoreConstructible<'brand> N::const_word(inference_context, word).into() } - fn inference_context(&self) -> &Context<'brand> { - &self.ctx - } -} - -impl<'brand, N> JetConstructible<'brand> for Hiding<'brand, N> -where - N: JetConstructible<'brand> + CoreConstructible<'brand>, -{ fn jet(inference_context: &Context<'brand>, jet: &dyn Jet) -> Self { N::jet(inference_context, jet).into() } + + fn inference_context(&self) -> &Context<'brand> { + &self.ctx + } } impl<'brand, X, N> DisconnectConstructible<'brand, Option> for Hiding<'brand, N> diff --git a/src/node/mod.rs b/src/node/mod.rs index 3f3c91bc..7f6ac600 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -90,6 +90,14 @@ pub use hiding::Hiding; pub use inner::Inner; pub use redeem::{Redeem, RedeemData, RedeemNode}; +/// Lots of existing code imports [`JetConstructible`] just to get the `jet` method. +/// Almost all such code also imports [`CoreConstructible`], which now gives them +/// this method, so this code will continue to work as long as there is something +/// called [`JetConstructible`] to import. +#[doc(hidden)] +#[deprecated(note = "subsumed by CoreConstructible")] +pub enum JetConstructible {} + // This trait should only be implemented on empty types, so we can demand // every trait bound under the sun. Doing so will make #[derive]s easier // for downstream users. @@ -129,8 +137,7 @@ impl From for Option { } pub trait Constructible<'brand, X, W>: - JetConstructible<'brand> - + DisconnectConstructible<'brand, X> + DisconnectConstructible<'brand, X> + WitnessConstructible<'brand, W> + CoreConstructible<'brand> + Sized @@ -162,7 +169,6 @@ pub trait Constructible<'brand, X, W>: impl<'brand, X, W, T> Constructible<'brand, X, W> for T where T: DisconnectConstructible<'brand, X> - + JetConstructible<'brand> + WitnessConstructible<'brand, W> + CoreConstructible<'brand> + Sized @@ -183,6 +189,7 @@ pub trait CoreConstructible<'brand>: Sized { fn pair(left: &Self, right: &Self) -> Result; fn fail(inference_context: &types::Context<'brand>, entropy: FailEntropy) -> Self; fn const_word(inference_context: &types::Context<'brand>, word: Word) -> Self; + fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self; /// Accessor for the type inference context used to create the object. fn inference_context(&self) -> &types::Context<'brand>; @@ -344,10 +351,6 @@ pub trait DisconnectConstructible<'brand, X>: Sized { fn disconnect(left: &Self, right: &X) -> Result; } -pub trait JetConstructible<'brand>: Sized { - fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self; -} - pub trait WitnessConstructible<'brand, W>: Sized { fn witness(inference_context: &types::Context<'brand>, witness: W) -> Self; } @@ -539,6 +542,14 @@ where }) } + fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self { + Arc::new(Node { + cmr: Cmr::jet(jet), + data: N::CachedData::jet(inference_context, jet), + inner: Inner::Jet(jet.dyn_clone()), + }) + } + fn inference_context(&self) -> &types::Context<'brand> { self.data.inference_context() } @@ -572,20 +583,6 @@ where } } -impl<'brand, N> JetConstructible<'brand> for Arc> -where - N: Marker, - N::CachedData: JetConstructible<'brand>, -{ - fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self { - Arc::new(Node { - cmr: Cmr::jet(jet), - data: N::CachedData::jet(inference_context, jet), - inner: Inner::Jet(jet.dyn_clone()), - }) - } -} - impl Node { /// Accessor for the node's "inner value", i.e. its combinator pub fn inner(&self) -> &Inner>, N::Disconnect, N::Witness> { diff --git a/src/policy/ast.rs b/src/policy/ast.rs index 846ebc92..31de9c36 100644 --- a/src/policy/ast.rs +++ b/src/policy/ast.rs @@ -12,8 +12,8 @@ use std::convert::TryFrom; use std::sync::Arc; use std::{fmt, iter, mem}; -use crate::node::{ConstructNode, CoreConstructible, JetConstructible, WitnessConstructible}; -use crate::policy::serialize::{self, AssemblyConstructible}; +use crate::node::{ConstructNode, CoreConstructible, WitnessConstructible}; +use crate::policy::serialize; use crate::{types, Value}; use crate::{Cmr, CommitNode, FailEntropy}; use crate::{SimplicityKey, ToXOnlyPubkey, Translator}; @@ -50,68 +50,56 @@ pub enum Policy { }, /// Satisfy exactly `k` of the given sub-policies Threshold(usize, Vec>), - /// Satisfy the program with the given CMR - Assembly(Cmr), } impl Policy { /// Serializes the policy as a Simplicity fragment, with all witness nodes unpopulated. - fn serialize_no_witness<'brand, N>( - &self, - inference_context: &types::Context<'brand>, - ) -> Option + fn serialize_no_witness<'brand, N>(&self, inference_context: &types::Context<'brand>) -> N where - N: CoreConstructible<'brand> - + JetConstructible<'brand> - + WitnessConstructible<'brand, Option> - + AssemblyConstructible<'brand>, + N: CoreConstructible<'brand> + WitnessConstructible<'brand, Option>, { match *self { - Policy::Unsatisfiable(entropy) => { - Some(serialize::unsatisfiable(inference_context, entropy)) - } - Policy::Trivial => Some(serialize::trivial(inference_context)), - Policy::After(n) => Some(serialize::after(inference_context, n)), - Policy::Older(n) => Some(serialize::older(inference_context, n)), - Policy::Key(ref key) => Some(serialize::key(inference_context, key, None)), + Policy::Unsatisfiable(entropy) => serialize::unsatisfiable(inference_context, entropy), + Policy::Trivial => serialize::trivial(inference_context), + Policy::After(n) => serialize::after(inference_context, n), + Policy::Older(n) => serialize::older(inference_context, n), + Policy::Key(ref key) => serialize::key(inference_context, key, None), Policy::Sha256(ref hash) => { - Some(serialize::sha256::(inference_context, hash, None)) + serialize::sha256::(inference_context, hash, None) } Policy::And { ref left, ref right, } => { - let left = left.serialize_no_witness(inference_context)?; - let right = right.serialize_no_witness(inference_context)?; - Some(serialize::and(&left, &right)) + let left = left.serialize_no_witness(inference_context); + let right = right.serialize_no_witness(inference_context); + serialize::and(&left, &right) } Policy::Or { ref left, ref right, } => { - let left = left.serialize_no_witness(inference_context)?; - let right = right.serialize_no_witness(inference_context)?; - Some(serialize::or(&left, &right, None)) + let left = left.serialize_no_witness(inference_context); + let right = right.serialize_no_witness(inference_context); + serialize::or(&left, &right, None) } Policy::Threshold(k, ref subs) => { let k = u32::try_from(k).expect("can have k at most 2^32 in a threshold"); let subs = subs .iter() .map(|sub| sub.serialize_no_witness(inference_context)) - .collect::>>()?; + .collect::>(); let wits = iter::repeat(None).take(subs.len()).collect::>(); - Some(serialize::threshold(k, &subs, &wits)) + serialize::threshold(k, &subs, &wits) } - Policy::Assembly(cmr) => N::assembly(inference_context, cmr), } } /// Return the program commitment of the policy. - pub fn commit(&self) -> Option> { + pub fn commit(&self) -> Arc { types::Context::with_context(|ctx| { - let construct: Arc = self.serialize_no_witness(&ctx)?; - let commit = construct.finalize_types().expect("policy has sound types"); - Some(commit) + let construct: Arc = self.serialize_no_witness(&ctx); + construct.finalize_types().expect("policy has sound types") }) } @@ -119,7 +107,6 @@ impl Policy { pub fn cmr(&self) -> Cmr { types::Context::with_context(|ctx| { self.serialize_no_witness::(&ctx) - .expect("CMR is defined for asm fragment") .cmr }) } @@ -159,7 +146,6 @@ impl Policy { left: Arc::new(left.translate(translator)?), right: Arc::new(right.translate(translator)?), }), - Policy::Assembly(cmr) => Ok(Policy::Assembly(cmr)), } } @@ -268,7 +254,6 @@ impl fmt::Debug for Policy { } f.write_str(")") } - Policy::Assembly(cmr) => write!(f, "asm({})", cmr), } } } diff --git a/src/policy/satisfy.rs b/src/policy/satisfy.rs index c9f3710c..da7c866c 100644 --- a/src/policy/satisfy.rs +++ b/src/policy/satisfy.rs @@ -8,7 +8,6 @@ use crate::{Cmr, Policy, Value}; use elements::bitcoin; use elements::locktime::Height; -use elements::taproot::TapLeafHash; use crate::jet::elements::ElementsEnv; use std::convert::TryFrom; @@ -23,8 +22,9 @@ pub type Preimage32 = [u8; 32]; /// on every query. Users are expected to override the methods that they /// have data for. pub trait Satisfier<'brand, Pk: ToXOnlyPubkey> { - /// Given a public key, look up a Schnorr signature with that key. - fn lookup_tap_leaf_script_sig(&self, _: &Pk, _: &TapLeafHash) -> Option { + /// Given the external Taproot public key, look up a Schnorr signature (for the sighash_all + /// sighash mode for the program's Tapbranch) with that key. + fn lookup_signature(&self, _: &Pk) -> Option { None } @@ -152,10 +152,8 @@ impl Policy { } Policy::Trivial => super::serialize::trivial(inference_context), Policy::Key(ref key) => { - use elements::hashes::Hash as _; - let signature = satisfier - .lookup_tap_leaf_script_sig(key, &TapLeafHash::all_zeros()) + .lookup_signature(key) .map(|sig| sig.sig.serialize()) .map(Value::u512); ok_if( @@ -259,10 +257,6 @@ impl Policy { super::serialize::threshold(k, &subs_res, &witness_bits), ) } - Policy::Assembly(cmr) => match satisfier.lookup_asm_program(cmr) { - Some(program) => Hiding::from(program), - None => Hiding::hidden(cmr, inference_context.shallow_clone()), - }, }; Ok(node) } @@ -294,12 +288,10 @@ mod tests { use crate::bit_encoding::BitCollector; use crate::dag::{DagLike, NoSharing}; use crate::jet::elements::ElementsEnv; - use crate::jet::Elements; - use crate::node::{CoreConstructible, JetConstructible, SimpleFinalizer, WitnessConstructible}; - use crate::policy::serialize; + use crate::node::SimpleFinalizer; use crate::{BitMachine, FailEntropy, SimplicityKey}; + use elements::bitcoin::hashes::{sha256, Hash}; use elements::bitcoin::key::{Keypair, XOnlyPublicKey}; - use elements::hashes::{sha256, Hash}; use elements::secp256k1_zkp; use std::collections::HashMap; use std::sync::Arc; @@ -318,11 +310,7 @@ mod tests { &self.context } - fn lookup_tap_leaf_script_sig( - &self, - pk: &Pk, - _: &TapLeafHash, - ) -> Option { + fn lookup_signature(&self, pk: &Pk) -> Option { self.signatures.get(pk).copied() } @@ -413,7 +401,7 @@ mod tests { assert!(policy.satisfy(&satisfier, &env).is_err()); - let commit = policy.commit().expect("no asm"); + let commit = policy.commit(); let program = commit .finalize(&mut SimpleFinalizer::new(std::iter::empty())) .expect("finalize"); @@ -727,99 +715,4 @@ mod tests { } }); } - - #[test] - fn satisfy_asm() { - types::Context::with_context(|ctx| { - let env = ElementsEnv::dummy(); - let mut satisfier = get_satisfier(ctx, &env); - - let mut assert_branch = |witness0: Value, witness1: Value| { - let ctx = &satisfier.context; - let asm_program = serialize::verify_bexp( - &Arc::::pair( - &Arc::::witness(ctx, Some(witness0.clone())), - &Arc::::witness(ctx, Some(witness1.clone())), - ) - .expect("sound types"), - &Arc::::jet(ctx, &Elements::Eq8), - ); - let cmr = asm_program.cmr(); - satisfier.assembly.insert(cmr, asm_program); - - let policy = Policy::Assembly(cmr); - let result = policy.satisfy(&satisfier, &env); - - if witness0 == witness1 { - let program = result.expect("policy should be satisfiable"); - let witness = to_witness(&program); - - assert_eq!(2, witness.len()); - assert_eq!(&witness0, witness[0]); - assert_eq!(&witness1, witness[1]); - - execute_successful(program, &env); - } else { - assert!(matches!(result, Err(SatisfierError::AssemblyFailed(..)))); - } - }; - - for a in 0..2 { - for b in 0..2 { - assert_branch(Value::u8(a), Value::u8(b)) - } - } - }); - } - - #[test] - #[ignore] - fn satisfy_asm_and_older() { - types::Context::with_context(|ctx| { - let env = ElementsEnv::dummy_with( - elements::LockTime::ZERO, - elements::Sequence::from_consensus(42), - ); - let mut satisfier = get_satisfier(ctx, &env); - - let mut assert_branch = |witness0: Value, witness1: Value| { - let ctx = &satisfier.context; - let asm_program = serialize::verify_bexp( - &Arc::::pair( - &Arc::::witness(ctx, Some(witness0.clone())), - &Arc::::witness(ctx, Some(witness1.clone())), - ) - .expect("sound types"), - &Arc::::jet(ctx, &Elements::Eq8), - ); - let cmr = asm_program.cmr(); - satisfier.assembly.insert(cmr, asm_program); - - let policy = Policy::And { - left: Arc::new(Policy::Assembly(cmr)), - right: Arc::new(Policy::Older(41)), - }; - let result = policy.satisfy(&satisfier, &env); - - if witness0 == witness1 { - let program = result.expect("policy should be satisfiable"); - let witness = to_witness(&program); - - assert_eq!(2, witness.len()); - assert_eq!(&witness0, witness[0]); - assert_eq!(&witness1, witness[1]); - - execute_successful(program, &env); - } else { - assert!(matches!(result, Err(SatisfierError::AssemblyFailed(..)))); - } - }; - - for a in 0..2 { - for b in 0..2 { - assert_branch(Value::u8(a), Value::u8(b)) - } - } - }); - } } diff --git a/src/policy/serialize.rs b/src/policy/serialize.rs index ea623760..b56ca453 100644 --- a/src/policy/serialize.rs +++ b/src/policy/serialize.rs @@ -3,38 +3,13 @@ //! Serialization of Policy as Simplicity use crate::jet::Elements; -use crate::merkle::cmr::ConstructibleCmr; -use crate::node::{CoreConstructible, JetConstructible, WitnessConstructible}; +use crate::node::{CoreConstructible, WitnessConstructible}; use crate::types; use crate::FailEntropy; -use crate::{Cmr, ConstructNode, ToXOnlyPubkey}; +use crate::ToXOnlyPubkey; use crate::value::Word; use std::convert::TryFrom; -use std::sync::Arc; - -/// Constructors for the assembly fragment. -pub trait AssemblyConstructible<'brand>: Sized { - /// Construct the assembly fragment with the given CMR. - /// - /// The construction fails if the CMR alone is not enough information to construct the object. - fn assembly(inference_context: &types::Context<'brand>, cmr: Cmr) -> Option; -} - -impl<'brand> AssemblyConstructible<'brand> for ConstructibleCmr<'brand> { - fn assembly(inference_context: &types::Context<'brand>, cmr: Cmr) -> Option { - Some(ConstructibleCmr { - cmr, - inference_context: inference_context.shallow_clone(), - }) - } -} - -impl<'brand> AssemblyConstructible<'brand> for Arc> { - fn assembly(_: &types::Context, _cmr: Cmr) -> Option { - None - } -} pub fn unsatisfiable<'brand, N>( inference_context: &types::Context<'brand>, @@ -56,7 +31,7 @@ where pub fn key<'brand, Pk, N, W>(inference_context: &types::Context<'brand>, key: &Pk, witness: W) -> N where Pk: ToXOnlyPubkey, - N: CoreConstructible<'brand> + JetConstructible<'brand> + WitnessConstructible<'brand, W>, + N: CoreConstructible<'brand> + WitnessConstructible<'brand, W>, { let key_value = Word::u256(key.to_x_only_pubkey().serialize()); let const_key = N::const_word(inference_context, key_value); @@ -71,7 +46,7 @@ where pub fn after<'brand, N>(inference_context: &types::Context<'brand>, n: u32) -> N where - N: CoreConstructible<'brand> + JetConstructible<'brand>, + N: CoreConstructible<'brand>, { let n_value = Word::u32(n); let const_n = N::const_word(inference_context, n_value); @@ -82,7 +57,7 @@ where pub fn older<'brand, N>(inference_context: &types::Context<'brand>, n: u16) -> N where - N: CoreConstructible<'brand> + JetConstructible<'brand>, + N: CoreConstructible<'brand>, { let n_value = Word::u16(n); let const_n = N::const_word(inference_context, n_value); @@ -96,7 +71,7 @@ where pub fn compute_sha256<'brand, N>(witness256: &N) -> N where - N: CoreConstructible<'brand> + JetConstructible<'brand>, + N: CoreConstructible<'brand>, { let ctx = N::jet(witness256.inference_context(), &Elements::Sha256Ctx8Init); let pair_ctx_witness = N::pair(&ctx, witness256).expect("consistent types"); @@ -111,7 +86,7 @@ where pub fn verify_bexp<'brand, N>(input: &N, bexp: &N) -> N where - N: CoreConstructible<'brand> + JetConstructible<'brand>, + N: CoreConstructible<'brand>, { assert_eq!( input.inference_context(), @@ -130,7 +105,7 @@ pub fn sha256<'brand, Pk, N, W>( ) -> N where Pk: ToXOnlyPubkey, - N: CoreConstructible<'brand> + JetConstructible<'brand> + WitnessConstructible<'brand, W>, + N: CoreConstructible<'brand> + WitnessConstructible<'brand, W>, { use bitcoin_miniscript::bitcoin::hashes::Hash as _; @@ -210,7 +185,7 @@ where /// add(sum, summand): 1 → 2^32 pub fn thresh_add<'brand, N>(sum: &N, summand: &N) -> N where - N: CoreConstructible<'brand> + JetConstructible<'brand>, + N: CoreConstructible<'brand>, { assert_eq!( sum.inference_context(), @@ -237,7 +212,7 @@ where /// verify(sum): 1 → 1 pub fn thresh_verify<'brand, N>(sum: &N, k: u32) -> N where - N: CoreConstructible<'brand> + JetConstructible<'brand>, + N: CoreConstructible<'brand>, { // 1 → 2^32 let const_k = N::const_word(sum.inference_context(), Word::u32(k)); @@ -252,7 +227,7 @@ where pub fn threshold<'brand, N, W>(k: u32, subs: &[N], witness_bits: &[W]) -> N where - N: CoreConstructible<'brand> + JetConstructible<'brand> + WitnessConstructible<'brand, W>, + N: CoreConstructible<'brand> + WitnessConstructible<'brand, W>, W: Clone, { let n = u32::try_from(subs.len()).expect("can have at most 2^32 children in a threshold"); @@ -283,7 +258,7 @@ mod tests { fn compile( policy: Policy, ) -> (Arc, ElementsEnv>) { - let commit = policy.commit().expect("no asm"); + let commit = policy.commit(); let env = ElementsEnv::dummy(); (commit, env) @@ -331,7 +306,7 @@ mod tests { let signature = keypair.sign_schnorr(message); let (xonly, _) = keypair.x_only_public_key(); - let commit = Policy::Key(xonly).commit().expect("no asm"); + let commit = Policy::Key(xonly).commit(); assert!(execute_successful( &commit, @@ -346,19 +321,13 @@ mod tests { let env = ElementsEnv::dummy_with(elements::LockTime::Blocks(height), elements::Sequence::ZERO); - let commit = Policy::::After(41) - .commit() - .expect("no asm"); + let commit = Policy::::After(41).commit(); assert!(execute_successful(&commit, vec![], &env)); - let commit = Policy::::After(42) - .commit() - .expect("no asm"); + let commit = Policy::::After(42).commit(); assert!(execute_successful(&commit, vec![], &env)); - let commit = Policy::::After(43) - .commit() - .expect("no asm"); + let commit = Policy::::After(43).commit(); assert!(!execute_successful(&commit, vec![], &env)); } @@ -369,19 +338,13 @@ mod tests { elements::Sequence::from_consensus(42), ); - let commit = Policy::::Older(41) - .commit() - .expect("no asm"); + let commit = Policy::::Older(41).commit(); assert!(execute_successful(&commit, vec![], &env)); - let commit = Policy::::Older(42) - .commit() - .expect("no asm"); + let commit = Policy::::Older(42).commit(); assert!(execute_successful(&commit, vec![], &env)); - let commit = Policy::::Older(43) - .commit() - .expect("no asm"); + let commit = Policy::::Older(43).commit(); assert!(!execute_successful(&commit, vec![], &env)); } diff --git a/src/types/arrow.rs b/src/types/arrow.rs index 09005e22..a9df5c42 100644 --- a/src/types/arrow.rs +++ b/src/types/arrow.rs @@ -15,10 +15,7 @@ use std::fmt; use std::sync::Arc; use crate::jet::Jet; -use crate::node::{ - CoreConstructible, DisconnectConstructible, JetConstructible, NoDisconnect, - WitnessConstructible, -}; +use crate::node::{CoreConstructible, DisconnectConstructible, NoDisconnect, WitnessConstructible}; use crate::types::{Context, Error, Final, Type}; use crate::value::Word; @@ -319,6 +316,16 @@ impl<'brand> CoreConstructible<'brand> for Arrow<'brand> { } } + fn jet(inference_context: &Context<'brand>, jet: &dyn Jet) -> Self { + inference_context.check_jet(jet); + + Arrow { + source: jet.source_ty().to_type(inference_context), + target: jet.target_ty().to_type(inference_context), + inference_context: inference_context.shallow_clone(), + } + } + fn inference_context(&self) -> &Context<'brand> { &self.inference_context } @@ -354,18 +361,6 @@ impl<'brand> DisconnectConstructible<'brand, Option<&Arrow<'brand>>> for Arrow<' } } -impl<'brand> JetConstructible<'brand> for Arrow<'brand> { - fn jet(inference_context: &Context<'brand>, jet: &dyn Jet) -> Self { - inference_context.check_jet(jet); - - Arrow { - source: jet.source_ty().to_type(inference_context), - target: jet.target_ty().to_type(inference_context), - inference_context: inference_context.shallow_clone(), - } - } -} - impl<'brand, W> WitnessConstructible<'brand, W> for Arrow<'brand> { fn witness(inference_context: &Context<'brand>, _: W) -> Self { Arrow { diff --git a/src/types/mod.rs b/src/types/mod.rs index 5b1bd299..bef9550e 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -416,8 +416,7 @@ mod tests { use super::*; use crate::jet::Core; - use crate::node::JetConstructible; - use crate::node::{ConstructNode, CoreConstructible}; + use crate::node::{ConstructNode, CoreConstructible as _}; #[test] fn inference_failure() {