BP-WG / bp-core

BP Core Lib: consensus data structures and client-side-validation library for bitcoin protocol
Apache License 2.0
22 stars 20 forks source link

TapLeafHash error? #77

Closed EthanShang8989 closed 6 months ago

EthanShang8989 commented 7 months ago
impl TapLeafHash {
    pub fn with_leaf_script(leaf_script: &LeafScript) -> Self {
        let mut engine = Sha256::from_tag(MIDSTATE_TAPLEAF);
        engine.input_raw(&[leaf_script.version.to_consensus_u8()]);
        engine.input_with_len::<U32>(leaf_script.script.as_slice());
        Self(engine.finish().into())
    }

    pub fn with_tap_script(tap_script: &TapScript) -> Self {
        let mut engine = Sha256::from_tag(MIDSTATE_TAPLEAF);
        engine.input_raw(&[TAPROOT_LEAF_TAPSCRIPT]);
        engine.input_with_len::<U32>(tap_script.as_slice());
        Self(engine.finish().into())
    }
}

The function with_leaf_script directly uses a slice of the script as part of constructing the hash. However, according to BIP341, it is required to use the script encoded with CompactSize before including it in the hash. The actual difference is that the length prefix is missing, which results in a different value for the Merkle tree root compared to the standard approach.

//[80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 106, 33, 242, 163, 220, 185, 239, 79, 165, 64, 83, 110, 199, 176, 31, 215, 84, 134, 136, 166, 12, 144, 195, 241, 128, 12, 14, 18, 218, 137, 128, 240, 96, 251, 0]
//[64, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 106, 33, 242, 163, 220, 185, 239, 79, 165, 64, 83, 110, 199, 176, 31, 215, 84, 134, 136, 166, 12, 144, 195, 241, 128, 12, 14, 18, 218, 137, 128, 240, 96, 251, 0]

https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs

#[test]
fn test_hash() {
    const MIDSTATE_TAPLEAF: [u8; 7] = *b"TapLeaf";
    let script_vec = vec![
        80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
        80, 80, 80, 80, 80, 80, 106, 33, 242, 163, 220, 185, 239, 79, 165, 64, 83, 110, 199, 176,
        31, 215, 84, 134, 136, 166, 12, 144, 195, 241, 128, 12, 14, 18, 218, 137, 128, 240, 96,
        251, 0,
    ];
    let mut bp_script_encode: Vec<u8> = vec![];
    let mut bdk_script_encode: Vec<u8> = vec![];
    ////////////////////////////////////////bp/////////////////////////////////////////////////
    let bp_script = bp::ScriptBytes::try_from(script_vec.clone()).unwrap();
    let _ = bp::ConsensusEncode::consensus_encode(&bp_script, &mut bp_script_encode);
    let mut engine = Sha256::from_tag(MIDSTATE_TAPLEAF);
    engine.input_raw(&[LeafVer::TapScript.to_consensus_u8()]);

    //The hash values of these three are different.
    // engine.input_with_len::<U32>(&bp_script_encode);
    // engine.input_with_len::<U32>(bp_script.as_slice());
    engine.input_raw(&bp_script_encode);

    let bp_result = engine.finish().to_lower_hex_string();
    println!("bp_script_encode{:?}", bp_script_encode);
    println!("bp_result: {:#?} \n", bp_result);
    ////////////////////////////////////////bdk/////////////////////////////////////////////////
    let mut eng = bdk_chain::bitcoin::taproot::TapLeafHash::engine();
    let ver = bdk_chain::bitcoin::taproot::LeafVersion::TapScript;
    let bdk_script = bdk_chain::bitcoin::Script::from_bytes(&script_vec);
    ver.to_consensus()
        .consensus_encode(&mut eng)
        .expect("engines don't error");
    bdk_script
        .consensus_encode(&mut eng)
        .expect("engines don't error");
    let bdk_hash_result = bdk_chain::bitcoin::taproot::TapLeafHash::from_engine(eng);
    let _ = bdk_script.consensus_encode(&mut bdk_script_encode);
    println!("bdk_script_encode{:?}", bdk_script_encode);
    println!("bdk_hash_result to hex: {:#?}", bdk_hash_result.to_hex());
    assert_eq!(bdk_hash_result.to_hex(), bp_result);
}
dr-orlovsky commented 7 months ago

Thank you for discovering this. Will fix ASAP