diff --git a/Cargo.toml b/Cargo.toml index 764ef1adb..a538d4d42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,6 +66,11 @@ required-features = ["std", "base64"] name = "big" required-features = ["std", "base64", "compiler"] +[[example]] +name = "taptree_of_horror" +path = "examples/taptree_of_horror/taptree_of_horror.rs" +required-features = ["compiler"] + [workspace] members = ["fuzz"] exclude = ["embedded", "bitcoind-tests"] diff --git a/examples/taptree_of_horror/README.md b/examples/taptree_of_horror/README.md new file mode 100644 index 000000000..506d615a4 --- /dev/null +++ b/examples/taptree_of_horror/README.md @@ -0,0 +1,20 @@ +# Taptree of Horror Example + +### Running this example: +- `cargo run --example taptree_of_horror --features "compiler"` + +### Originally based on the TABConf 6, CTB. +The challenge can be found here: +- https://tabctb.com/six +- https://tabctb.com/six/thebeginning/thetree/grim/iacceptyourterms.html + +### This example demonstrates: +- Providing multiple extended private key (xpriv) descriptors for sample personas. +- Creating a policy using logical 'and/or' conditions with preimages and signatures and timelocks. +- Structuring a Taproot tree (taptree) with an internal key into logical branches and leaves based on the policy. +- Implementing nine complex tapleaves within the taptree. +- Building a spending transaction that signs and satisfies one of the tapleaves using signatures, preimages and a timelock. + +### Helpful Graphic to visualize using Excalidraw +![taptree_of_horror](./taptree_of_horror.png) + diff --git a/examples/taptree_of_horror/helper_fns.rs b/examples/taptree_of_horror/helper_fns.rs new file mode 100644 index 000000000..d0ca62dad --- /dev/null +++ b/examples/taptree_of_horror/helper_fns.rs @@ -0,0 +1,59 @@ +use std::str::FromStr; + +use bitcoin::bip32::{DerivationPath, Xpriv}; +use bitcoin::hashes::{ripemd160, sha256, Hash}; +use miniscript::descriptor::DescriptorSecretKey; +use miniscript::ToPublicKey; +use secp256k1::Secp256k1; + +use crate::KEYS_PER_PERSONA; + +pub fn produce_grim_hash(secret: &str) -> (sha256::Hash, ripemd160::Hash) { + let mut hash_holder = sha256::Hash::hash(secret.as_bytes()); + for _i in 0..5 { + hash_holder = sha256::Hash::hash(hash_holder.as_byte_array()); + //println!("{} hash: {}", i, hash_holder); + } + + let ripemd_160_final = ripemd160::Hash::hash(hash_holder.as_byte_array()); + (hash_holder, ripemd_160_final) +} + +pub fn produce_kelly_hash(secret: &str) -> (sha256::Hash, sha256::Hash) { + let prepreimage = secret.as_bytes(); + let preimage_256_hash = sha256::Hash::hash(prepreimage); + let result256_final = sha256::Hash::hash(&preimage_256_hash.to_byte_array()); + (preimage_256_hash, result256_final) +} + +pub fn produce_key_pairs( + desc: DescriptorSecretKey, + secp: &Secp256k1, + derivation_without_index: &str, + _alias: &str, +) -> (Vec, Vec) { + let mut pks = Vec::new(); + let mut prvs = Vec::new(); + + let xprv = match &desc { + DescriptorSecretKey::XPrv(xpriv) => xpriv, + _ => panic!("not an xpriv"), + }; + + for i in 0..KEYS_PER_PERSONA { + let pk = desc + .to_public(secp) + .unwrap() + .at_derivation_index(i.try_into().unwrap()) + .unwrap() + .to_public_key(); + + let derivation_with_index = format!("{}/{}", derivation_without_index, i); + let derivation_path = DerivationPath::from_str(&derivation_with_index).unwrap(); + let derived_xpriv: Xpriv = xprv.xkey.derive_priv(secp, &derivation_path).unwrap(); + + pks.push(pk); + prvs.push(derived_xpriv); + } + (pks, prvs) +} diff --git a/examples/taptree_of_horror/taptree_of_horror.excalidraw b/examples/taptree_of_horror/taptree_of_horror.excalidraw new file mode 100644 index 000000000..192f9eb2c --- /dev/null +++ b/examples/taptree_of_horror/taptree_of_horror.excalidraw @@ -0,0 +1,2602 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "ellipse", + "version": 2692, + "versionNonce": 1273399365, + "index": "a0", + "isDeleted": false, + "id": "GndOEcsuqlogN1UcnadVX", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dotted", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 208.4102320023012, + "y": -709.2168669525936, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 209.47745849070802, + "height": 199.18174923961917, + "seed": 1306491013, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "m81hu3nIIMkXG2LjoHMmW" + }, + { + "id": "EgPd-FPgebvosI3czaK01", + "type": "arrow" + }, + { + "id": "VtHSD4EKn3K0OiK3PYcUK", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 3695, + "versionNonce": 2002191019, + "index": "a1", + "isDeleted": false, + "id": "m81hu3nIIMkXG2LjoHMmW", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 255.6656205454036, + "y": -643.1473751207507, + "strokeColor": "#e9ecef", + "backgroundColor": "#ffc9c9", + "width": 114.84375, + "height": 67.2, + "seed": 2059935717, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974524, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "Tweaked\nPubkey", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "GndOEcsuqlogN1UcnadVX", + "originalText": "Tweaked Pubkey", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "ellipse", + "version": 2593, + "versionNonce": 215431077, + "index": "a2", + "isDeleted": false, + "id": "-Cidda3DazDNLK0_Sd7pZ", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dotted", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 238.54589044894237, + "y": -474.6836531471308, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 151.07973831598636, + "height": 141.75534587692505, + "seed": 115661637, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "IeP9dh3q0ryg71N2dzX6O" + }, + { + "id": "urfueZsZkcMv9Lbm609tu", + "type": "arrow" + }, + { + "id": "VtHSD4EKn3K0OiK3PYcUK", + "type": "arrow" + }, + { + "id": "RG7h_aUNwQcNgAHGXKT68", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 2734, + "versionNonce": 2119660875, + "index": "a3", + "isDeleted": false, + "id": "IeP9dh3q0ryg71N2dzX6O", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 281.030380875374, + "y": -420.7240633781774, + "strokeColor": "#e9ecef", + "backgroundColor": "#ffc9c9", + "width": 66.28125, + "height": 33.6, + "seed": 445852325, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974524, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "MAST", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "-Cidda3DazDNLK0_Sd7pZ", + "originalText": "MAST", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 3212, + "versionNonce": 2126183173, + "index": "a4", + "isDeleted": false, + "id": "7Hj1luhAphC8npbws5IAP", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dotted", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -83.22700581782556, + "y": -448.54582089444557, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 219.18110402097952, + "height": 85.78000786121443, + "seed": 1988136453, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "oEsje763sCNmxQVyDfaeu" + }, + { + "id": "EgPd-FPgebvosI3czaK01", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 3324, + "versionNonce": 1039176683, + "index": "a5", + "isDeleted": false, + "id": "oEsje763sCNmxQVyDfaeu", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -72.5866491198358, + "y": -422.45581696383834, + "strokeColor": "#e9ecef", + "backgroundColor": "#b2f2bb", + "width": 197.900390625, + "height": 33.6, + "seed": 1772782949, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974524, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "internal key", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "7Hj1luhAphC8npbws5IAP", + "originalText": "internal key", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 4034, + "versionNonce": 974082661, + "index": "a6", + "isDeleted": false, + "id": "pulcCCcFMj7eXPO9nxIBh", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -304.20177730797514, + "y": -284.71993963660225, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 392.82373498030887, + "height": 185.3504062594211, + "seed": 123637957, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "qO3G04ebCAVeJJImyiLAh" + }, + { + "id": "urfueZsZkcMv9Lbm609tu", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 4307, + "versionNonce": 1982652043, + "index": "a7", + "isDeleted": false, + "id": "qO3G04ebCAVeJJImyiLAh", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -230.8367848178207, + "y": -264.0447365068917, + "strokeColor": "#e9ecef", + "backgroundColor": "#99e9f2", + "width": 246.09375, + "height": 144, + "seed": 490352677, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974525, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "thresh 10/10 \na,b,c,d,e,f,h,i,j,l\nand\nthresh 3/3 \ns256(k), r160(g),\nafter(oct_23_morning)", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "pulcCCcFMj7eXPO9nxIBh", + "originalText": "thresh 10/10 \na,b,c,d,e,f,h,i,j,l\nand\nthresh 3/3 \ns256(k), r160(g), after(oct_23_morning)", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 5343, + "versionNonce": 1805761989, + "index": "a8", + "isDeleted": false, + "id": "kNBgATjr-iJJJFZRgnYoN", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -553.0309892600926, + "y": 147.22797670293494, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 391.48379206337756, + "height": 201.7077229710872, + "seed": 1764418437, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "dupy4rdH_1zRka8o_cGT7" + }, + { + "id": "21UC2uoycgnGjouAikaty", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 5441, + "versionNonce": 29807915, + "index": "a9", + "isDeleted": false, + "id": "dupy4rdH_1zRka8o_cGT7", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -480.33596822840383, + "y": 176.08183818847854, + "strokeColor": "#e9ecef", + "backgroundColor": "#99e9f2", + "width": 246.09375, + "height": 144, + "seed": 258878181, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974525, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "thresh 8/9 \na,b,c,e,f,h,i,j,l\nand\nthresh 3/3 \nd, s256(k),\nafter(oct_24_evening)", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "kNBgATjr-iJJJFZRgnYoN", + "originalText": "thresh 8/9 \na,b,c,e,f,h,i,j,l\nand\nthresh 3/3 \nd, s256(k), after(oct_24_evening)", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 4843, + "versionNonce": 1250934053, + "index": "aA", + "isDeleted": false, + "id": "bLV0XU6dZVYsVeGHZf9cv", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 359.4166225314948, + "y": 695.0065747025692, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 388.6894334865265, + "height": 217.74074458257027, + "seed": 1351714373, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "qe79ig9V6YaWiz2Df4pQm" + }, + { + "id": "f2tME6oYIWtL37q0oVsdt", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 5022, + "versionNonce": 2684875, + "index": "aB", + "isDeleted": false, + "id": "qe79ig9V6YaWiz2Df4pQm", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 407.27696427475803, + "y": 743.8769469938543, + "strokeColor": "#e9ecef", + "backgroundColor": "#99e9f2", + "width": 292.96875, + "height": 120, + "seed": 2138207653, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974525, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "thresh 9/12\na,b,c,d,e,f,h,i,j,l,s1,s2\nand\nthresh 2/2 s256(k),\nafter(oct_25_afternoon)", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "bLV0XU6dZVYsVeGHZf9cv", + "originalText": "thresh 9/12 a,b,c,d,e,f,h,i,j,l,s1,s2\nand\nthresh 2/2 s256(k), after(oct_25_afternoon)", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 4732, + "versionNonce": 1313263749, + "index": "aC", + "isDeleted": false, + "id": "ZTAH5ww7UCc4y6yLN7drt", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 756.5781194882948, + "y": 694.1265426547307, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 377.3483883841334, + "height": 212.06497069870056, + "seed": 926841093, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "hxMiuuWJaIgWye-AEJikj" + }, + { + "id": "65L5hfrRqPt4dVTJ5_Wwd", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 4959, + "versionNonce": 1064158827, + "index": "aD", + "isDeleted": false, + "id": "hxMiuuWJaIgWye-AEJikj", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 798.7679386803615, + "y": 752.1590280040809, + "strokeColor": "#e9ecef", + "backgroundColor": "#99e9f2", + "width": 292.96875, + "height": 96, + "seed": 1366495333, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974525, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "thresh 10/12\na,b,c,d,e,f,h,i,j,l,s1,s2\nand\nafter(oct_26_morning)", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ZTAH5ww7UCc4y6yLN7drt", + "originalText": "thresh 10/12 a,b,c,d,e,f,h,i,j,l,s1,s2\nand\nafter(oct_26_morning)", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 7144, + "versionNonce": 612661221, + "index": "aE", + "isDeleted": false, + "id": "5MGv1HzNoNX-0RrauWLZu", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -344.9948272132315, + "y": 690.4389376692989, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 350.0389322994304, + "height": 222.9029292832944, + "seed": 467516357, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "VDWKnVn-l9cZZ1gyo-Bek" + }, + { + "id": "1PWGzYTTw4yXaQ3I-rxI6", + "type": "arrow" + }, + { + "id": "DOqBDv-zff6uTvcAxzfjK", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 7219, + "versionNonce": 1717551371, + "index": "aF", + "isDeleted": false, + "id": "VDWKnVn-l9cZZ1gyo-Bek", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -310.6003610635163, + "y": 741.8904023109461, + "strokeColor": "#e9ecef", + "backgroundColor": "#99e9f2", + "width": 281.25, + "height": 120, + "seed": 1318845221, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974525, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "thresh 6/8 \na,b,c,e,f,h,i,l\nand\nthresh 4/4 d,j, s256(k),\nafter(oct_25_afternoon)", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "5MGv1HzNoNX-0RrauWLZu", + "originalText": "thresh 6/8 \na,b,c,e,f,h,i,l\nand\nthresh 4/4 d,j, s256(k),\nafter(oct_25_afternoon)", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 5527, + "versionNonce": 1733702469, + "index": "aG", + "isDeleted": false, + "id": "ZSTVjoa0ysJsriRSBcYzX", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -153.93222113798765, + "y": 147.2351112564893, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 408.8961274837388, + "height": 202, + "seed": 1109085829, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "-bwZDFJg-pt1eBl3qIvQn" + }, + { + "id": "1PWGzYTTw4yXaQ3I-rxI6", + "type": "arrow" + }, + { + "id": "mwiusPzAAWQEB20BXWwxc", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 5696, + "versionNonce": 1585014699, + "index": "aH", + "isDeleted": false, + "id": "-bwZDFJg-pt1eBl3qIvQn", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -72.53103239611826, + "y": 152.2351112564893, + "strokeColor": "#e9ecef", + "backgroundColor": "#99e9f2", + "width": 246.09375, + "height": 192, + "seed": 1696151013, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974525, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "thresh 4/8 \na,b,c,e,f,h,i,l\nand\nthresh 4/4 \nj, d, r160(g),\nafter(oct_24_evening)\nand \n(s1 or s2)", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ZSTVjoa0ysJsriRSBcYzX", + "originalText": "thresh 4/8 \na,b,c,e,f,h,i,l\nand\nthresh 4/4 \nj, d, r160(g), after(oct_24_evening)\nand \n(s1 or s2)", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 6619, + "versionNonce": 320438949, + "index": "aI", + "isDeleted": false, + "id": "2h3JbkXgMQ7MMRFZPTzRi", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 837.318407530769, + "y": 414.962066381926, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 301.23755653870825, + "height": 220.94554924242397, + "seed": 1923297605, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "mGUhyrKdwt8cLOD8DrLjY" + }, + { + "id": "21jZrZAH_TT7hcgDWqFEv", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 6709, + "versionNonce": 2112174667, + "index": "aJ", + "isDeleted": false, + "id": "mGUhyrKdwt8cLOD8DrLjY", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 853.1715608001232, + "y": 453.434841003138, + "strokeColor": "#e9ecef", + "backgroundColor": "#99e9f2", + "width": 269.53125, + "height": 144, + "seed": 1746321573, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974526, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "thresh 4/8\na,b,c,e,f,h,i,l\nand\nthresh 5/5 \ns2, j, d, r160(g),\nafter(oct_25_afternoon)", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "2h3JbkXgMQ7MMRFZPTzRi", + "originalText": "thresh 4/8 a,b,c,e,f,h,i,l\nand\nthresh 5/5 \ns2, j, d, r160(g), after(oct_25_afternoon)", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 6230, + "versionNonce": 1014752773, + "index": "aK", + "isDeleted": false, + "id": "fm-NYTJKLK7LsjWREcm9w", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1146.8818419361342, + "y": 412.89269516878903, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 285.50070982395846, + "height": 226, + "seed": 992044037, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "__QI2iSNzNDeK5MMEoyTT" + }, + { + "id": "uOY77vAQT2DAkvrTp2drq", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 6412, + "versionNonce": 1176578251, + "index": "aL", + "isDeleted": false, + "id": "__QI2iSNzNDeK5MMEoyTT", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1154.8665718481134, + "y": 453.89269516878903, + "strokeColor": "#e9ecef", + "backgroundColor": "#99e9f2", + "width": 269.53125, + "height": 144, + "seed": 1338022757, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "thresh 4/8\na,b,c,e,f,h,i,l\nand\nthresh 5/5 \ns1, j, d, r160(g),\nafter(oct_25_afternoon)", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fm-NYTJKLK7LsjWREcm9w", + "originalText": "thresh 4/8 a,b,c,e,f,h,i,l\nand\nthresh 5/5 \ns1, j, d, r160(g), after(oct_25_afternoon)", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "ellipse", + "version": 4414, + "versionNonce": 108715365, + "index": "aM", + "isDeleted": false, + "id": "v2lIJCoAEdlxeXX5yQOwb", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0.08073325539026932, + "x": 303.9086383200156, + "y": -222.45983936196626, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 40.4601478630984, + "height": 38.64854104631888, + "seed": 776070853, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "urfueZsZkcMv9Lbm609tu", + "type": "arrow" + }, + { + "id": "ljZjSBKW4sMKCKI9ODFIF", + "type": "arrow" + }, + { + "id": "_YbHoe6YDYLMQXEn8cd5-", + "type": "arrow" + }, + { + "id": "RG7h_aUNwQcNgAHGXKT68", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 5458, + "versionNonce": 1496831851, + "index": "aN", + "isDeleted": false, + "id": "B93pVpAwiGgM8jjzoKukj", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1116.737833074345, + "y": 246.30352578450857, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 40.4601478630984, + "height": 38.64854104631888, + "seed": 2034419237, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "uOY77vAQT2DAkvrTp2drq", + "type": "arrow" + }, + { + "id": "21jZrZAH_TT7hcgDWqFEv", + "type": "arrow" + }, + { + "id": "Bqa_eZMJs2TQyA79SXRox", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 5429, + "versionNonce": 1482942661, + "index": "aO", + "isDeleted": false, + "id": "FYxVNvpFVhTleRqN0ET5E", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -99.09039345210476, + "y": 20.642348841470266, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 40.4601478630984, + "height": 38.64854104631888, + "seed": 598784389, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "_YbHoe6YDYLMQXEn8cd5-", + "type": "arrow" + }, + { + "id": "21UC2uoycgnGjouAikaty", + "type": "arrow" + }, + { + "id": "mwiusPzAAWQEB20BXWwxc", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 5593, + "versionNonce": 1052750347, + "index": "aP", + "isDeleted": false, + "id": "SnZBQtynkH6LccjyHpQx3", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 742.3028140928291, + "y": 13.61507942134267, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 40.4601478630984, + "height": 38.64854104631888, + "seed": 1724465381, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "ljZjSBKW4sMKCKI9ODFIF", + "type": "arrow" + }, + { + "id": "XQe06-YXd7ExM7ijS1N6I", + "type": "arrow" + }, + { + "id": "Bqa_eZMJs2TQyA79SXRox", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 6025, + "versionNonce": 1406437413, + "index": "aQ", + "isDeleted": false, + "id": "nAwkj_TTi9IRl0XcJFWlt", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 335.6564278842525, + "y": 248.65585152508174, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 40.4601478630984, + "height": 38.64854104631888, + "seed": 2014960709, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "32LitBboppxtzZ05wxaRr", + "type": "arrow" + }, + { + "id": "1PWGzYTTw4yXaQ3I-rxI6", + "type": "arrow" + }, + { + "id": "XQe06-YXd7ExM7ijS1N6I", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 4446, + "versionNonce": 1739798699, + "index": "aR", + "isDeleted": false, + "id": "EgPd-FPgebvosI3czaK01", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 232.94608171072832, + "y": -541.8937934437126, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 177.38347962135595, + "height": 92.34797254926707, + "seed": 2139098021, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "GndOEcsuqlogN1UcnadVX", + "focus": -0.22879401895928267, + "gap": 2.473373925378283, + "fixedPoint": null + }, + "endBinding": { + "elementId": "7Hj1luhAphC8npbws5IAP", + "focus": -0.2870465208281284, + "gap": 1, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -177.38347962135595, + 92.34797254926707 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 4372, + "versionNonce": 179977093, + "index": "aS", + "isDeleted": false, + "id": "VtHSD4EKn3K0OiK3PYcUK", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 311.050584088116, + "y": -476.03521510733844, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 0.06628362956325873, + "height": 33.018480132871446, + "seed": 1294552837, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "-Cidda3DazDNLK0_Sd7pZ", + "focus": -0.042099198497008015, + "gap": 1.4078135805500551, + "fixedPoint": null + }, + "endBinding": { + "elementId": "GndOEcsuqlogN1UcnadVX", + "focus": 0.01747390172673689, + "gap": 1, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 0.06628362956325873, + -33.018480132871446 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 10744, + "versionNonce": 1102900043, + "index": "aT", + "isDeleted": false, + "id": "f2tME6oYIWtL37q0oVsdt", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 559.3363785843067, + "y": 694.0065747025692, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 163.70545131418476, + "height": 134.14998733712218, + "seed": 1335043685, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "bLV0XU6dZVYsVeGHZf9cv", + "focus": -0.39272979559648463, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "S_Q991PeqdSevng9uouUz", + "focus": -0.038152973939790946, + "gap": 2.36345185004026, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 163.70545131418476, + -134.14998733712218 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 12666, + "versionNonce": 1968341733, + "index": "aU", + "isDeleted": false, + "id": "32LitBboppxtzZ05wxaRr", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 724.5590184129396, + "y": 530.3361428939324, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 349.10992980222727, + "height": 250.008319804625, + "seed": 1233850821, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "S_Q991PeqdSevng9uouUz", + "focus": 0.1669413464963727, + "gap": 1.4785627279888693, + "fixedPoint": null + }, + "endBinding": { + "elementId": "nAwkj_TTi9IRl0XcJFWlt", + "focus": -0.06880083360064951, + "gap": 3.171991125616305, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -349.10992980222727, + -250.008319804625 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 12936, + "versionNonce": 557271531, + "index": "aV", + "isDeleted": false, + "id": "1PWGzYTTw4yXaQ3I-rxI6", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 31.721850910325884, + "y": 523.2428057461138, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 305.7690627629454, + "height": 243.22706198761625, + "seed": 1211011365, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "IFUk60wMBxA51iwG6OQqb", + "focus": -0.20974289035952742, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "nAwkj_TTi9IRl0XcJFWlt", + "focus": 0.10328475833615307, + "gap": 2.036058195085218, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 305.7690627629454, + -243.22706198761625 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 11512, + "versionNonce": 673898053, + "index": "aW", + "isDeleted": false, + "id": "uOY77vAQT2DAkvrTp2drq", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1293.2805639217004, + "y": 410.95966939654954, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 141.6606265632654, + "height": 125.88014274822308, + "seed": 1491805317, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "fm-NYTJKLK7LsjWREcm9w", + "focus": 0.49270680490401136, + "gap": 1.933025772239489, + "fixedPoint": null + }, + "endBinding": { + "elementId": "B93pVpAwiGgM8jjzoKukj", + "focus": 0.20539131292931936, + "gap": 4.7111016841606315, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -141.6606265632654, + -125.88014274822308 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 11434, + "versionNonce": 1798100107, + "index": "aX", + "isDeleted": false, + "id": "21jZrZAH_TT7hcgDWqFEv", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 979.42686047405, + "y": 412.58505730185425, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 147.73583273445183, + "height": 125.80253108871057, + "seed": 2138983397, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "2h3JbkXgMQ7MMRFZPTzRi", + "focus": -0.5030642138306205, + "gap": 2.37700908007173, + "fixedPoint": null + }, + "endBinding": { + "elementId": "B93pVpAwiGgM8jjzoKukj", + "focus": -0.4940982058898614, + "gap": 3.8391421727988586, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 147.73583273445183, + -125.80253108871057 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 10541, + "versionNonce": 1243663781, + "index": "aY", + "isDeleted": false, + "id": "21UC2uoycgnGjouAikaty", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -337.6374401355206, + "y": 146.0416760897433, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 239.78864713821167, + "height": 95.56135423888009, + "seed": 1811253061, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "kNBgATjr-iJJJFZRgnYoN", + "focus": -0.5267119485740405, + "gap": 1.186300613191182, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FYxVNvpFVhTleRqN0ET5E", + "focus": -0.15738580455621068, + "gap": 1.697472602908359, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 239.78864713821167, + -95.56135423888009 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 10361, + "versionNonce": 2136476459, + "index": "aZ", + "isDeleted": false, + "id": "mwiusPzAAWQEB20BXWwxc", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 51.174730225746316, + "y": 141.41500591669774, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 111.72174036411889, + "height": 91.1670148828398, + "seed": 1890473637, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "ZSTVjoa0ysJsriRSBcYzX", + "focus": 0.40083784607213824, + "gap": 5.820105339791553, + "fixedPoint": null + }, + "endBinding": { + "elementId": "FYxVNvpFVhTleRqN0ET5E", + "focus": -0.18345644314476317, + "gap": 1, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -111.72174036411889, + -91.1670148828398 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 9944, + "versionNonce": 1247924485, + "index": "aa", + "isDeleted": false, + "id": "ljZjSBKW4sMKCKI9ODFIF", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 744.2692173284631, + "y": 22.577370886223434, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 400.96364272535357, + "height": 213.6945919079999, + "seed": 945175045, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "SnZBQtynkH6LccjyHpQx3", + "focus": 0.028393633841551483, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "v2lIJCoAEdlxeXX5yQOwb", + "focus": 0.08173562160790569, + "gap": 2.5947467209904858, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -400.96364272535357, + -213.6945919079999 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 9455, + "versionNonce": 1646489035, + "index": "ab", + "isDeleted": false, + "id": "_YbHoe6YDYLMQXEn8cd5-", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -60.50748843470137, + "y": 28.60588959969482, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 363.5049643559905, + "height": 221.1626085150674, + "seed": 1005236581, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "FYxVNvpFVhTleRqN0ET5E", + "focus": -0.00849170109271466, + "gap": 1.616777484406395, + "fixedPoint": null + }, + "endBinding": { + "elementId": "v2lIJCoAEdlxeXX5yQOwb", + "focus": 0.09933736947085296, + "gap": 3.6632198493235357, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 363.5049643559905, + -221.1626085150674 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 11365, + "versionNonce": 1449879653, + "index": "ac", + "isDeleted": false, + "id": "XQe06-YXd7ExM7ijS1N6I", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 371.69296296727407, + "y": 249.98375110025245, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 373.8722220523123, + "height": 203.78001122393835, + "seed": 2025405637, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "nAwkj_TTi9IRl0XcJFWlt", + "focus": -0.4216411359110048, + "gap": 4.245238385321986, + "fixedPoint": null + }, + "endBinding": { + "elementId": "SnZBQtynkH6LccjyHpQx3", + "focus": -0.1805084277254035, + "gap": 1.6638546991132728, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 373.8722220523123, + -203.78001122393835 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 10910, + "versionNonce": 648641643, + "index": "ad", + "isDeleted": false, + "id": "65L5hfrRqPt4dVTJ5_Wwd", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 919.9125373311872, + "y": 693.1265426547307, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 166.4074844092247, + "height": 132.08768467670507, + "seed": 1717525541, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "ZTAH5ww7UCc4y6yLN7drt", + "focus": 0.339799084361474, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "S_Q991PeqdSevng9uouUz", + "focus": 0.19388880862827196, + "gap": 1.2767711428052948, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -166.4074844092247, + -132.08768467670507 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 5788, + "versionNonce": 269161413, + "index": "ae", + "isDeleted": false, + "id": "urfueZsZkcMv9Lbm609tu", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -27.043547391251195, + "y": -285.71993963660225, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 271.73992112572887, + "height": 87.57340174461979, + "seed": 751472517, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "pulcCCcFMj7eXPO9nxIBh", + "focus": -0.4337498892123899, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "-Cidda3DazDNLK0_Sd7pZ", + "focus": -0.13679725735460757, + "gap": 1.0787348208211682, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 271.73992112572887, + -87.57340174461979 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 6224, + "versionNonce": 414496523, + "index": "af", + "isDeleted": false, + "id": "RG7h_aUNwQcNgAHGXKT68", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 321.509113240787, + "y": -223.32638702602435, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 2.561994606610824, + "height": 107.22724973166669, + "seed": 439899877, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "v2lIJCoAEdlxeXX5yQOwb", + "focus": -0.10615828713796777, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "-Cidda3DazDNLK0_Sd7pZ", + "focus": -0.04117494231308823, + "gap": 2.5171308182720367, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -2.561994606610824, + -107.22724973166669 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 10850, + "versionNonce": 56513317, + "index": "ag", + "isDeleted": false, + "id": "Bqa_eZMJs2TQyA79SXRox", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1117.5083538453073, + "y": 254.6224747895585, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 338.49019881832646, + "height": 208.53048840765587, + "seed": 1496724037, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "B93pVpAwiGgM8jjzoKukj", + "focus": -0.042746659529295045, + "gap": 2.3554067898219735, + "fixedPoint": null + }, + "endBinding": { + "elementId": "SnZBQtynkH6LccjyHpQx3", + "focus": 0.1303223156910213, + "gap": 1.2252229460940285, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -338.49019881832646, + -208.53048840765587 + ] + ], + "elbowed": false + }, + { + "type": "ellipse", + "version": 6938, + "versionNonce": 650091947, + "index": "ah", + "isDeleted": false, + "id": "S_Q991PeqdSevng9uouUz", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 719.4901465063595, + "y": 525.901214876727, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 40.4601478630984, + "height": 38.64854104631888, + "seed": 1721868709, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "f2tME6oYIWtL37q0oVsdt", + "type": "arrow" + }, + { + "id": "32LitBboppxtzZ05wxaRr", + "type": "arrow" + }, + { + "id": "65L5hfrRqPt4dVTJ5_Wwd", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 7554, + "versionNonce": 1557309061, + "index": "ai", + "isDeleted": false, + "id": "IFUk60wMBxA51iwG6OQqb", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -1.8002840567169187, + "y": 519.7663060928026, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 40.4601478630984, + "height": 38.64854104631888, + "seed": 1202201861, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "1PWGzYTTw4yXaQ3I-rxI6", + "type": "arrow" + }, + { + "id": "DOqBDv-zff6uTvcAxzfjK", + "type": "arrow" + }, + { + "id": "QOAFW1FVnNNFJCPpD_9-w", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 11860, + "versionNonce": 200585291, + "index": "aj", + "isDeleted": false, + "id": "DOqBDv-zff6uTvcAxzfjK", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -160.8054001647506, + "y": 687.7146069916489, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 159.41234633760178, + "height": 133.57277814318877, + "seed": 2143763557, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "5MGv1HzNoNX-0RrauWLZu", + "focus": -0.41259811147281256, + "gap": 2.7243306776499594, + "fixedPoint": null + }, + "endBinding": { + "elementId": "IFUk60wMBxA51iwG6OQqb", + "focus": 0.06169709778677002, + "gap": 5.001249321508315, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 159.41234633760178, + -133.57277814318877 + ] + ], + "elbowed": false + }, + { + "type": "arrow", + "version": 12491, + "versionNonce": 1596296677, + "index": "ak", + "isDeleted": false, + "id": "QOAFW1FVnNNFJCPpD_9-w", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 177.87620851284737, + "y": 688.0995551275755, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 147.6624678420303, + "height": 132.10303172196564, + "seed": 1187801029, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "startBinding": { + "elementId": "9ozuQcAm-5fmSR2vOJdkw", + "focus": 0.4298532710881462, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "IFUk60wMBxA51iwG6OQqb", + "focus": 0.2403567865177893, + "gap": 1, + "fixedPoint": null + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -147.6624678420303, + -132.10303172196564 + ] + ], + "elbowed": false + }, + { + "type": "rectangle", + "version": 7779, + "versionNonce": 976121579, + "index": "al", + "isDeleted": false, + "id": "9ozuQcAm-5fmSR2vOJdkw", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 21.599787523198756, + "y": 689.0995551275755, + "strokeColor": "#e9ecef", + "backgroundColor": "#343a40", + "width": 318.4094398731536, + "height": 220.4461851635856, + "seed": 2127898405, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "gp15-boeCj8mVpmS6Mcxp" + }, + { + "id": "QOAFW1FVnNNFJCPpD_9-w", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 7913, + "versionNonce": 1904064747, + "index": "am", + "isDeleted": false, + "id": "gp15-boeCj8mVpmS6Mcxp", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 46.03888245977555, + "y": 763.3226477093683, + "strokeColor": "#e9ecef", + "backgroundColor": "#99e9f2", + "width": 269.53125, + "height": 72, + "seed": 1783560837, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974526, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "thresh 14/14\na,b,c,d,e,f,h,i,j,l,s1,\ns256(k), r160(g)", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "9ozuQcAm-5fmSR2vOJdkw", + "originalText": "thresh 14/14 a,b,c,d,e,f,h,i,j,l,s1, s256(k), r160(g)", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "text", + "version": 358, + "versionNonce": 66541963, + "index": "an", + "isDeleted": false, + "id": "7P0GFNmp_KR23VpBgOFlU", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -104.95006727833606, + "y": -321.26636271364487, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 16.40625, + "height": 33.6, + "seed": 569860581, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "0", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "0", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "text", + "version": 638, + "versionNonce": 1559042213, + "index": "ao", + "isDeleted": false, + "id": "P3p_35ZOqNcMkT0QL2BLk", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -357.31254277773405, + "y": 87.71282145573332, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 16.70703125, + "height": 33.6, + "seed": 1255923013, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "21UC2uoycgnGjouAikaty", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "1", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "1", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "text", + "version": 107, + "versionNonce": 109703211, + "index": "ap", + "isDeleted": false, + "id": "o77hIwHqVaw25aZB1y_Sz", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 78.6434442728023, + "y": 104.29375669913406, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 16.70703125, + "height": 33.6, + "seed": 207219877, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "mwiusPzAAWQEB20BXWwxc", + "type": "arrow" + } + ], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "2", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "2", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "text", + "version": 220, + "versionNonce": 1936505861, + "index": "aq", + "isDeleted": false, + "id": "L23NyrFv9BQeHx4bRjG_3", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 944.8745875404311, + "y": 373.15695151394175, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 16.43359375, + "height": 33.6, + "seed": 1176440837, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "6", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "6", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "text", + "version": 295, + "versionNonce": 1406186187, + "index": "ar", + "isDeleted": false, + "id": "1RAXw-XMJalhCT4PIg-zj", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1311.6784944876927, + "y": 364.48367093229353, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 17.30859375, + "height": 33.6, + "seed": 103335781, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "7", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "7", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "text", + "version": 317, + "versionNonce": 350286693, + "index": "as", + "isDeleted": false, + "id": "_koPm53cJR4ZyRRc4yQB8", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": -200.7715746264439, + "y": 642.1987138701334, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 16.40625, + "height": 33.6, + "seed": 1053070021, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "3", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "3", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "text", + "version": 373, + "versionNonce": 1550197099, + "index": "at", + "isDeleted": false, + "id": "l-t6sj1HQgGqSOR3_dW8V", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 204.471371169122, + "y": 637.8280607142833, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 16.40625, + "height": 33.6, + "seed": 1016066597, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "8", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "8", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "text", + "version": 451, + "versionNonce": 496451269, + "index": "au", + "isDeleted": false, + "id": "8yFv2T31BqQ--pmODH65u", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 512.5343929264673, + "y": 646.2122319432101, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 16.40625, + "height": 33.6, + "seed": 1551394181, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "4", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "4", + "autoResize": true, + "lineHeight": 1.2 + }, + { + "type": "text", + "version": 530, + "versionNonce": 429177867, + "index": "av", + "isDeleted": false, + "id": "Cse67_giObt4V1kwptfcj", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 943.2052898865404, + "y": 656.8667619126272, + "strokeColor": "#fd7e14", + "backgroundColor": "#343a40", + "width": 16.76171875, + "height": 33.6, + "seed": 29060325, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1730739974522, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 3, + "text": "5", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "5", + "autoResize": true, + "lineHeight": 1.2 + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/examples/taptree_of_horror/taptree_of_horror.png b/examples/taptree_of_horror/taptree_of_horror.png new file mode 100644 index 000000000..32ff4f5c7 Binary files /dev/null and b/examples/taptree_of_horror/taptree_of_horror.png differ diff --git a/examples/taptree_of_horror/taptree_of_horror.rs b/examples/taptree_of_horror/taptree_of_horror.rs new file mode 100644 index 000000000..45f569756 --- /dev/null +++ b/examples/taptree_of_horror/taptree_of_horror.rs @@ -0,0 +1,283 @@ +use std::str::FromStr; + +use bitcoin::absolute::LockTime; +use bitcoin::consensus::encode::serialize; +use bitcoin::hashes::Hash; +use bitcoin::hex::{Case, DisplayHex}; +use bitcoin::transaction::Version; +use bitcoin::{Address, Amount, Network, Psbt, PublicKey, Sequence, TxIn, TxOut}; +use helper_fns::{produce_grim_hash, produce_kelly_hash, produce_key_pairs}; +use miniscript::descriptor::DescriptorSecretKey; +use miniscript::policy::Concrete; +use miniscript::psbt::PsbtExt; +use miniscript::{Descriptor, DescriptorPublicKey}; +mod helper_fns; + +pub const KEYS_PER_PERSONA: usize = 9; + +fn main() { + let secp: &secp256k1::Secp256k1 = &secp256k1::Secp256k1::new(); + + // ====== 1. Setup Hardcoded Values for all of the Personas ====== + + // Define derivation paths that will be used + let normal_path = "86'/1'/0'/0"; + let unhardened_path = "86/1/0/0"; + let weird_path = "69'/420'/999999999'/8008135'"; + + // Hard coded regtest tprvs that will be used. + let internal = format!("tprv8ZgxMBicQKsPfBJTWzMTQfRzcE3HCNKg6TUBpGBfigcFbqTXNBw6SuGPqBpD6D9pjLLASwq8bE7oZXCtMFPDKRizLy14xNqw4uz1zwrfo2c/{normal_path}/*"); + let alice = format!("tprv8ZgxMBicQKsPeZjVFDhZR5wjfCvFNev9qKGPDPC77p5cAEgEMUCR8Cecaf8pYfY7NTz8QcjVnP8uR8NedPz8o7iG7qWgnFMyQy9BAhMVZgb/{normal_path}/*"); + let bob = format!("tprv8ZgxMBicQKsPeHy2kPPVzYpbUqwTVBjSthMJUcGyqUiXk8eZTQ6xrJKEmdX8NYJKLLGCHGjuByqz2ahJXp52E8zCUV7njziJzwN7V7zfrKZ/{normal_path}/*"); + let charlie = format!("tprv8ZgxMBicQKsPdYaiWLUQCprj7Ej9Ka5GEq6giWHgTnbJvdLWnSuYnsF5sonVh6iy2HzvfkfxRDAmWEXNo3SJWTHCXM6XuxVZvqxtEyjdC29/{normal_path}/*"); + let dave = format!("tprv8ZgxMBicQKsPfCRUoMSWthoE8aJKr7De5YkxS1y55PuiSoi5ACyYUbas8Kv4vVtDzhKnBgY7cVSuogg2QLqtFcSZVv4ZTeBEzkzSnF9cSUT/{weird_path}/*"); + let eve = format!("tprv8ZgxMBicQKsPdYD5umCPZeh6tMqKfQATctqJbycgJ5N1rrJ15cHMgxds5iYENHZHmkMiXccAqUFx2k3ZNwU9qxPMjrKvTbCtgLFxk7mjMWD/{normal_path}/*"); + let frank = format!("tprv8ZgxMBicQKsPemyPyxqZ85T1UjpToCbLQ7uSn4JpbtwMBCodjvrLbgjBZeGgT4tMHdHCqyieDwCNzE7RrtRMVCQjPKQbGJzrg5vfn4eT7og/{normal_path}/*"); + let heather = format!("tprv8ZgxMBicQKsPefp99xLkwnQbU9LEEb8v4Aig3o4hwnjbaYotixkbJv3Ssmog68ptHij2LgExefNU96DYJKtFbDazTr1jm48twYhQLG775qw/{normal_path}/*"); + let ian = format!("tprv8ZgxMBicQKsPfGsuwfAdg3xPP452wreLk7ZEgusb8zdMqh1fyKGKnzFbxyxeHY3qhg8ESDRp5F6RgWiQGcvkmLyERcMys5V8DuT4gvxMDmS/{unhardened_path}/*"); + let judy = format!("tprv8ZgxMBicQKsPcz4VcN87e2e9k1LHDBLLajbVSAKAedpm1qakjtRT5xrdnmsQARWAfwg3REr6sNd5YHeWuWkHVvyey3rYmq9xYorMvwY3XAB/{normal_path}/*"); + let liam = format!("tprv8ZgxMBicQKsPcycCJ2v7B1utZrhWJNdQTBm7m9eR6iX1D9a9YvjbCNeT6dTEdMh4JziVCHD4YHQ7AXkZNMLfaBVf3CCiVWQLxwdU2SnrPcT/{normal_path}/*"); + let s_backup_1 = format!("tprv8ZgxMBicQKsPetPYYt5GUtNmQPChghNDBLbgJXz3cTZopeDrxHMendLpujaBHMPX3dXLZcv2NkgAvxMeuf1jWBU3iYxdeJAhktdeM9cKcYF/{normal_path}/*"); + let x_backup_2 = format!("tprv8ZgxMBicQKsPdf55kYg8pVPrUaW3VLZyt8XwxwrvSPkpskxDah1mAWypsTTZJeomWPrGf4e5RyT4zVzENHrwAsXxJP2EPYbfrYLRVFC1rLb/{normal_path}/*"); + + // define DescriptorSecretKeys + let internal_desc_secret = DescriptorSecretKey::from_str(&internal).unwrap(); + let a_descriptor_desc_secret = DescriptorSecretKey::from_str(&alice).unwrap(); + let b_descriptor_desc_secret = DescriptorSecretKey::from_str(&bob).unwrap(); + let c_descriptor_desc_secret = DescriptorSecretKey::from_str(&charlie).unwrap(); + let d_descriptor_desc_secret = DescriptorSecretKey::from_str(&dave).unwrap(); + let e_descriptor_desc_secret = DescriptorSecretKey::from_str(&eve).unwrap(); + let f_descriptor_desc_secret = DescriptorSecretKey::from_str(&frank).unwrap(); + let h_descriptor_desc_secret = DescriptorSecretKey::from_str(&heather).unwrap(); + let i_descriptor_desc_secret = DescriptorSecretKey::from_str(&ian).unwrap(); + let j_descriptor_desc_secret = DescriptorSecretKey::from_str(&judy).unwrap(); + let l_descriptor_desc_secret = DescriptorSecretKey::from_str(&liam).unwrap(); + let s_descriptor_desc_secret = DescriptorSecretKey::from_str(&s_backup_1).unwrap(); + let x_descriptor_desc_secret = DescriptorSecretKey::from_str(&x_backup_2).unwrap(); + let grim = produce_grim_hash("sovereignty through knowledge"); + let kelly = produce_kelly_hash("the ultimate pre-preimage"); + + // ====== 2. Derive Keys, Preimages, Hashes, and Timelocks for Policy and Signing ====== + + let internal_xpub: miniscript::DescriptorPublicKey = + internal_desc_secret.to_public(secp).unwrap(); + + // example of how defining the internal xpriv that can be used for signing. + // let internal_xpriv: DescriptorXKey = match internal_desc_secret { + // miniscript::descriptor::DescriptorSecretKey::XPrv(x) => Some(x.clone()), + // _ => None, + // } + // .unwrap(); + + let (a_pks, a_prvs) = produce_key_pairs(a_descriptor_desc_secret, secp, normal_path, "alice"); + let (b_pks, b_prvs) = produce_key_pairs(b_descriptor_desc_secret, secp, normal_path, "bob"); + let (c_pks, c_prvs) = produce_key_pairs(c_descriptor_desc_secret, secp, normal_path, "charlie"); + let (d_pks, d_prvs) = produce_key_pairs(d_descriptor_desc_secret, secp, weird_path, "dave"); + let (e_pks, e_prvs) = produce_key_pairs(e_descriptor_desc_secret, secp, normal_path, "eve"); + let (f_pks, f_prvs) = produce_key_pairs(f_descriptor_desc_secret, secp, normal_path, "frank"); + let (h_pks, h_prvs) = produce_key_pairs(h_descriptor_desc_secret, secp, normal_path, "heather"); + let (i_pks, i_prvs) = produce_key_pairs(i_descriptor_desc_secret, secp, unhardened_path, "ian"); + let (j_pks, j_prvs) = produce_key_pairs(j_descriptor_desc_secret, secp, normal_path, "judy"); + let (l_pks, l_prvs) = produce_key_pairs(l_descriptor_desc_secret, secp, normal_path, "liam"); + let (s_pks, _s_prvs) = + produce_key_pairs(s_descriptor_desc_secret, secp, normal_path, "s_backup1"); + let (x_pks, _x_prvs) = + produce_key_pairs(x_descriptor_desc_secret, secp, normal_path, "x_backup2"); + + // For this example we are grabbing the 9 keys for each persona + let [a0, a1, a2, a3, a4, a5, a6, a7, a8]: [PublicKey; KEYS_PER_PERSONA] = + a_pks[..].try_into().unwrap(); + let [b0, b1, b2, b3, b4, b5, b6, b7, b8]: [PublicKey; KEYS_PER_PERSONA] = + b_pks[..].try_into().unwrap(); + let [c0, c1, c2, c3, c4, c5, c6, c7, c8]: [PublicKey; KEYS_PER_PERSONA] = + c_pks[..].try_into().unwrap(); + let [d0, d1, d2, d3, d4, d5, d6, d7, d8]: [PublicKey; KEYS_PER_PERSONA] = + d_pks[..].try_into().unwrap(); + let [e0, e1, e2, e3, e4, e5, e6, e7, e8]: [PublicKey; KEYS_PER_PERSONA] = + e_pks[..].try_into().unwrap(); + let [f0, f1, f2, f3, f4, f5, f6, f7, f8]: [PublicKey; KEYS_PER_PERSONA] = + f_pks[..].try_into().unwrap(); + let [h0, h1, h2, h3, h4, h5, h6, h7, h8]: [PublicKey; KEYS_PER_PERSONA] = + h_pks[..].try_into().unwrap(); + let [i0, i1, i2, i3, i4, i5, i6, i7, i8]: [PublicKey; KEYS_PER_PERSONA] = + i_pks[..].try_into().unwrap(); + let [j0, j1, j2, j3, j4, j5, j6, j7, j8]: [PublicKey; KEYS_PER_PERSONA] = + j_pks[..].try_into().unwrap(); + let [l0, l1, l2, l3, l4, l5, l6, l7, l8]: [PublicKey; KEYS_PER_PERSONA] = + l_pks[..].try_into().unwrap(); + let [_s0, _s1, s2, _s3, s4, s5, _s6, s7, s8]: [PublicKey; KEYS_PER_PERSONA] = + s_pks[..].try_into().unwrap(); + let [_x0, _x1, x2, _x3, x4, x5, x6, _x7, x8]: [PublicKey; KEYS_PER_PERSONA] = + x_pks[..].try_into().unwrap(); + + // Hashes that will also be used in the policy. + let g = grim.1; + let k = kelly.1; + // Absolute timelocks that were used at TABConf 6, The event took place Oct 23-26 and more spending paths for the puzzle became available during the conference. + let oct_23_morning: u32 = 1729692000; // Oct 23, 10:00 AM EST + let oct_24_evening: u32 = 1729819800; // Oct 24, 09:30 PM EST + let oct_25_afternoon: u32 = 1729877400; // Oct 25, 01:30 PM EST + let oct_26_morning: u32 = 1729942200; // Oct 26, 07:30 AM EST + + // ====== 3. Create Taptree Policy and Descriptor ====== + + let pol_str = format!( + "or( + pk({internal_xpub}), + or( + and( + thresh(10, pk({a0}), pk({b0}), pk({c0}), pk({d0}), pk({e0}), pk({f0}), pk({h0}), pk({i0}), pk({j0}), pk({l0})), + thresh(3, sha256({k}), ripemd160({g}), after({oct_23_morning})) + ), + or( + or( + and( + thresh(8, pk({a1}), pk({b1}), pk({c1}), pk({e1}), pk({f1}), pk({h1}), pk({i1}), pk({j1}), pk({l1})), + thresh(3, pk({d1}), sha256({k}), after({oct_24_evening})) + ), + and( + thresh(4, pk({a2}), pk({b2}), pk({c2}), pk({e2}), pk({f2}), pk({h2}), pk({i2}), pk({l2})), + and( + thresh(4, pk({d2}), pk({j2}), ripemd160({g}), after({oct_24_evening})), + or(pk({s2}), pk({x2})) + ) + ) + ), + or( + or( + or( + and( + thresh(6, pk({a3}), pk({b3}), pk({c3}), pk({e3}), pk({f3}), pk({h3}), pk({i3}), pk({l3})), + thresh(4, pk({d3}), pk({j3}), sha256({k}), after({oct_25_afternoon})) + ), + thresh(14, pk({a8}), pk({b8}), pk({c8}), pk({d8}), pk({e8}), pk({f8}), pk({h8}), pk({i8}), pk({j8}), pk({l8}), pk({s8}), pk({x8}), sha256({k}), ripemd160({g})) + ), + or( + and( + thresh(9, pk({a4}), pk({b4}), pk({c4}), pk({d4}), pk({e4}), pk({f4}), pk({h4}), pk({i4}), pk({j4}), pk({l4}), pk({s4}), pk({x4})), + thresh(2, sha256({k}), after({oct_26_morning})) + ), + and( + thresh(10, pk({a5}), pk({b5}), pk({c5}), pk({d5}), pk({e5}), pk({f5}), pk({h5}), pk({i5}), pk({j5}), pk({l5}), pk({s5}), pk({x5})), + after({oct_26_morning}) + ) + ) + ), + or( + and( + thresh(4, pk({a6}), pk({b6}), pk({c6}), pk({e6}), pk({f6}), pk({h6}), pk({i6}), pk({l6})), + thresh(5, pk({d6}), pk({x6}), pk({j6}), ripemd160({g}), after({oct_25_afternoon})) + ), + and( + thresh(4, pk({a7}), pk({b7}), pk({c7}), pk({e7}), pk({f7}), pk({h7}), pk({i7}), pk({l7})), + thresh(5, pk({d7}), pk({s7}), pk({j7}), ripemd160({g}), after({oct_25_afternoon})) + ) + ) + ) + ) + ) + + )" + ) + .replace(&[' ', '\n', '\t'][..], ""); + + // make sure policy doesn't have any issues + let pol = Concrete::::from_str(&pol_str).unwrap(); + let policy_desc: Descriptor = pol.compile_tr(None).unwrap(); + + // Now, using this public descriptor create the script address + let derived_descriptor = policy_desc.at_derivation_index(0).unwrap(); + let _script_address = derived_descriptor.address(Network::Regtest).unwrap(); + println!("the receiving address of this script is: {}", _script_address); + println!("\ndescriptor is: {}\n", policy_desc); + + // We assert internal key is the one used in the descriptor + match &policy_desc { + Descriptor::Tr(tr) => { + // println!("internal: {}, eve: {}", tr.internal_key(), eve_xpub); + assert!(tr.internal_key() == &internal_xpub); + } + _ => panic!("internal spending path is not correct"), + } + + // ====== 4. Construct an Unsigned Transaction from the Tapscript ====== + + let secp: &secp256k1::Secp256k1 = &secp256k1::Secp256k1::new(); + + let tx_in = TxIn { + previous_output: bitcoin::OutPoint { + txid: "8888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffff" + .parse() + .unwrap(), + vout: 0, + }, + sequence: Sequence(0), + // sequence: Sequence(40), + ..Default::default() + }; + + let prev_amount = Amount::from_sat(100_000_000); + let witness_utxo = + TxOut { value: prev_amount, script_pubkey: derived_descriptor.clone().script_pubkey() }; + + let destination_address = + Address::from_str("bcrt1p2tl8zasepqe3j6m7hx4tdmqzndddr5wa9ugglpdzgenjwv42rkws66dk5a") + .unwrap(); + let destination_output: TxOut = TxOut { + value: bitcoin::Amount::from_sat(99_999_000), + script_pubkey: destination_address.assume_checked().script_pubkey(), + }; + + let time = oct_23_morning; + + let unsigned_tx = bitcoin::Transaction { + version: Version::TWO, + lock_time: LockTime::from_time(time).unwrap(), + input: vec![tx_in], + output: vec![destination_output], + }; + + let unsigned_tx_test_string = serialize(&unsigned_tx).to_hex_string(Case::Lower); + assert!(unsigned_tx_test_string == "0200000001ffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa99999999888888880000000000000000000118ddf5050000000022512052fe7176190833196b7eb9aab6ec029b5ad1d1dd2f108f85a246672732aa1d9d60011967"); + + let mut psbt = Psbt::from_unsigned_tx(unsigned_tx).unwrap(); + psbt.inputs[0].witness_utxo = Some(witness_utxo); + + // Tell Psbt about the descriptor so it can sign with it + psbt.update_input_with_descriptor(0, &derived_descriptor) + .unwrap(); + + // ====== 5. Sign and Create a Spending Transaction ====== + + // this is how you would sign for an internal key spend + //let _res = psbt.sign(&intneral_xpriv.xkey, secp).unwrap(); + + // how you would sign using the leaf that uses index 0 keys + let _res = psbt.sign(&a_prvs[0], secp).unwrap(); + let _res = psbt.sign(&b_prvs[0], secp).unwrap(); + let _res = psbt.sign(&c_prvs[0], secp).unwrap(); + let _res = psbt.sign(&d_prvs[0], secp).unwrap(); + let _res = psbt.sign(&e_prvs[0], secp).unwrap(); + let _res = psbt.sign(&f_prvs[0], secp).unwrap(); + let _res = psbt.sign(&h_prvs[0], secp).unwrap(); + let _res = psbt.sign(&i_prvs[0], secp).unwrap(); + let _res = psbt.sign(&j_prvs[0], secp).unwrap(); + let _res = psbt.sign(&l_prvs[0], secp).unwrap(); + + psbt.inputs[0] + .sha256_preimages + .insert(kelly.1, kelly.0.to_byte_array().to_vec()); + + psbt.inputs[0] + .ripemd160_preimages + .insert(grim.1, grim.0.to_byte_array().to_vec()); + + // Finalize PSBT now that we have all the required signatures and hash preimages. + psbt.finalize_mut(secp).unwrap(); + + // Now extract the tx + let signed_tx = psbt.extract_tx().unwrap(); + let raw_tx = bitcoin::consensus::encode::serialize(&signed_tx).to_hex_string(Case::Lower); + + assert!(raw_tx == "02000000000101ffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa99999999888888880000000000000000000118ddf5050000000022512052fe7176190833196b7eb9aab6ec029b5ad1d1dd2f108f85a246672732aa1d9d0e209250ecce1169d94cf17baaecddcef779ff1b0d07d347d24afcd5b2231f95a500209562ef4e826d891eaa72f2cee753b80a3f7f6b5aed07b850227e83546fa6185740a5da084901627205e860d6530ff5ff580fc3841b779ad8535ffd7b466664aa0280c218aa05a1054c73b1f717b6c5badf70e71e5091b4b34e25ec3584243fd0604032a0bad48af9b3263d331ba2c789a931af81755c67dfefab28f8e40658545e6659eeb93d2c501ac79914ca82f4dbdcd669d34c7de73b4c243400926cffeb42b640015f5b58eb820676382521bb38b9d0c16d40c6a1b710242232d3d8276145aee859667d3caf9b72acecbfa3be33ce7afb9bda70b19451c58550bb1076125463c240ba0ba063d92ef71a35a1bdbd41b165d71825d6b5d9555781a3a6c35aba5864c82c4e53a7656458dc8bd586a6de749b6ab59cbb5ec4e2264a185ef7b79db3ea9c408176c65f6486f5c9a7d466fe86dfed7d55f8fc480b5843414696842f1efc689e74fce36a0b318535ef86864d8f83ac4bb60085c2b45c0547b9657def51b52b8e40b5f95b03c77b685314848a292d05bf350cdad506bcb2601b634779e956235aef3bade98a812f046d47060fbf9965ac0ef016e6ef09540c1c7d5b2fe447192cbd405ea9e1a58685ef958db8aa529d3fbfcc1182e252a35715bf9b2c35a30c73e718a65e8a8c0141eaac72af71a1dd7f19c53aaead75ae5b963a4eee5d1228c389844094a38c8574e6089c33d2c37d6f889adb671ef09a188e91cf032e97a3e25e9636901096e1cc92d17fbf4c581e5a1915de53f807f3198f4a2b829fc3a4479f6bb54017e68b70fd9e5c94c6f99abf284f5da42365a2e5fd4f0971bf5cb68aea3408c0d05ace043c15e70958c73f7455db3a22e3e5fb0240749a9dc52aa66a554fb06b40c478230871c12b60bc7cae151e411aa779780a8e6a7afd57aa763185809259fc7853f65e712d1ef178d4750f66e1b6db3cae7efcec5308b815b39fe8498f404afd9c0120fe88003d0bcb15d1628edff84046255758baf205d42ce460b6fb4595b983f2ecad20eecd6dba68fd0ec5d4baa0052db8084cb15a55503b78cfee5ef31c35cd98d846ad20529c1e24d86bf35b35133a81bf1e8c21759f3a83cfb38f18eae1d5b8292ff4bead2083835dbe036944f18783e0a525babe23965a2b4fdeca2d2d84997fc6ff0fb06aad204aeb360d05ad743b838ad27c56b78f08668aeba77f2f1fc439ac80f970e57328ad2062c4d094ce7a28414102bacccb06947053e07e4da53ad96e5724565f09436dfcad20f6e5c74176d69d44a97220a694237d8e719fae4a029942aadb28a9b491b40e31ad20dc7ea580c6887971614260d91069c4d398cc80ecc6cbb4ab59099e110ad3bb8bad2059fa3dfd7286d59f9b3853fb0cdd13c4760508f672435be40057b9e02eb937bdad20aa90f13a1c98abc5620d3f379d20b8c28ddf8f46772a0d0af6b7deb7bf3a1ee1ad82012088a8202db9cdb5e102541f19b455fa798e0cb009f5faa6358b9d3507858caf797bca418882012088a6148d60757ec290d055be92da400cff617b0423cb14880460011967b141c1259b7a61aa66c551a6cd35ccc35e9e011ecbbddbbb673acba71e2e4cc11e8883326f8afc8b0ef3f1cc0428893a40e48b9419807a4fd8f8673b62840ef216d5f660011967"); +} diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 63e16579e..80226f73a 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -691,13 +691,10 @@ fn insert_elem( // Check whether the new element is worse than any existing element. If there // is an element which is a subtype of the current element and has better // cost, don't consider this element. - let is_worse = map - .iter() - .map(|(existing_key, existing_elem)| { - let existing_elem_cost = existing_elem.cost_1d(sat_prob, dissat_prob); - existing_key.is_subtype(elem_key) && existing_elem_cost <= elem_cost - }) - .any(|x| x); + let is_worse = map.iter().any(|(existing_key, existing_elem)| { + let existing_elem_cost = existing_elem.cost_1d(sat_prob, dissat_prob); + existing_key.is_subtype(elem_key) && existing_elem_cost <= elem_cost + }); if !is_worse { // If the element is not worse any element in the map, remove elements // whose subtype is the current element and have worse cost.