@@ -386,6 +386,20 @@ public object Script {
386386 @JvmStatic
387387 public fun isPay2wsh (script : ByteArray ): Boolean = isPay2wsh(parse(script))
388388
389+ @JvmStatic
390+ public fun isPay2tr (script : List <ScriptElt >): Boolean {
391+ return when {
392+ script.size == 2 && script[0 ] == OP_1 && script[1 ].isPush(32 ) -> true
393+ else -> false
394+ }
395+ }
396+
397+ @JvmStatic
398+ public fun isPay2tr (script : ByteArray ): Boolean = isPay2tr(parse(script))
399+
400+ @JvmStatic
401+ public fun isPay2tr (script : ByteVector ): Boolean = isPay2tr(script.toByteArray())
402+
389403 /* *
390404 * @param pubKeyHash public key hash
391405 * @return a pay-to-public-key-hash script
@@ -404,47 +418,41 @@ public object Script {
404418 public fun pay2pkh (pubKey : PublicKey ): List <ScriptElt > = pay2pkh(pubKey.hash160())
405419
406420 /* *
407- *
408421 * @param script bitcoin script
409422 * @return a pay-to-script script
410423 */
411424 @JvmStatic
412425 public fun pay2sh (script : List <ScriptElt >): List <ScriptElt > = pay2sh(write(script))
413426
414427 /* *
415- *
416428 * @param script bitcoin script
417429 * @return a pay-to-script script
418430 */
419431 @JvmStatic
420432 public fun pay2sh (script : ByteArray ): List <ScriptElt > = listOf (OP_HASH160 , OP_PUSHDATA (Crypto .hash160(script)), OP_EQUAL )
421433
422434 /* *
423- *
424435 * @param script bitcoin script
425436 * @return a pay-to-witness-script script
426437 */
427438 @JvmStatic
428439 public fun pay2wsh (script : List <ScriptElt >): List <ScriptElt > = pay2wsh(write(script))
429440
430441 /* *
431- *
432442 * @param script bitcoin script
433443 * @return a pay-to-witness-script script
434444 */
435445 @JvmStatic
436446 public fun pay2wsh (script : ByteArray ): List <ScriptElt > = listOf (OP_0 , OP_PUSHDATA (Crypto .sha256(script)))
437447
438448 /* *
439- *
440449 * @param script bitcoin script
441450 * @return a pay-to-witness-script script
442451 */
443452 @JvmStatic
444453 public fun pay2wsh (script : ByteVector ): List <ScriptElt > = pay2wsh(script.toByteArray())
445454
446455 /* *
447- *
448456 * @param pubKeyHash public key hash
449457 * @return a pay-to-witness-public-key-hash script
450458 */
@@ -455,20 +463,12 @@ public object Script {
455463 }
456464
457465 /* *
458- *
459466 * @param pubKey public key
460467 * @return a pay-to-witness-public-key-hash script
461468 */
462469 @JvmStatic
463470 public fun pay2wpkh (pubKey : PublicKey ): List <ScriptElt > = pay2wpkh(pubKey.hash160())
464471
465- /* *
466- * @param pubkey x-only public key
467- * @return a pay-to-taproot script
468- */
469- @JvmStatic
470- public fun pay2tr (pubkey : XonlyPublicKey ): List <ScriptElt > = listOf (OP_1 , OP_PUSHDATA (pubkey.value))
471-
472472 /* *
473473 * @param pubKey public key
474474 * @param sig signature matching the public key
@@ -477,6 +477,47 @@ public object Script {
477477 @JvmStatic
478478 public fun witnessPay2wpkh (pubKey : PublicKey , sig : ByteVector ): ScriptWitness = ScriptWitness (listOf (sig, pubKey.value))
479479
480+ /* *
481+ * @param outputKey public key exposed by the taproot script (tweaked based on the tapscripts).
482+ * @return a pay-to-taproot script.
483+ */
484+ @JvmStatic
485+ public fun pay2tr (outputKey : XonlyPublicKey ): List <ScriptElt > = listOf (OP_1 , OP_PUSHDATA (outputKey.value))
486+
487+ /* *
488+ * @param internalKey internal public key that will be tweaked with the [scripts] provided.
489+ * @param scripts optional spending scripts that can be used instead of key-path spending.
490+ * @return the script and the tweak that must be applied to the private key for [internalKey] when signing.
491+ */
492+ @JvmStatic
493+ public fun pay2tr (internalKey : XonlyPublicKey , scripts : ScriptTree ? ): List <ScriptElt > {
494+ val tweak = when (scripts) {
495+ null -> Crypto .TaprootTweak .NoScriptTweak
496+ else -> Crypto .TaprootTweak .ScriptTweak (scripts.hash())
497+ }
498+ val (publicKey, _) = internalKey.outputKey(tweak)
499+ return pay2tr(publicKey)
500+ }
501+
502+ /* * NB: callers must ensure that they use the correct [Crypto.TaprootTweak] when generating their signature. */
503+ @JvmStatic
504+ public fun witnessKeyPathPay2tr (sig : ByteVector64 , sighash : Int = SigHash .SIGHASH_DEFAULT ): ScriptWitness = when (sighash) {
505+ SigHash .SIGHASH_DEFAULT -> ScriptWitness (listOf (sig))
506+ else -> ScriptWitness (listOf (sig.concat(sighash.toByte())))
507+ }
508+
509+ /* *
510+ * @param internalKey taproot internal public key.
511+ * @param script script that is spent (must exist in the [scriptTree]).
512+ * @param witness witness for the spent [script].
513+ * @param scriptTree tapscript tree.
514+ */
515+ @JvmStatic
516+ public fun witnessScriptPathPay2tr (internalKey : XonlyPublicKey , script : ScriptTree .Leaf , witness : ScriptWitness , scriptTree : ScriptTree ): ScriptWitness {
517+ val controlBlock = ControlBlock .build(internalKey, scriptTree, script)
518+ return ScriptWitness (witness.stack + script.script + controlBlock)
519+ }
520+
480521 public fun removeSignature (script : List <ScriptElt >, signature : ByteVector ): List <ScriptElt > {
481522 val toRemove = OP_PUSHDATA (signature)
482523 return script.filterNot { it == toRemove }
@@ -622,7 +663,7 @@ public object Script {
622663 */
623664 @JvmStatic
624665 public fun build (internalPubKey : XonlyPublicKey , scriptTree : ScriptTree , spendingScript : ScriptTree .Leaf ): ByteVector {
625- val (_, parity) = internalPubKey.outputKey(Crypto . TaprootTweak . ScriptTweak ( scriptTree.hash()) )
666+ val (_, parity) = internalPubKey.outputKey(scriptTree)
626667 val controlByte = (spendingScript.leafVersion + (if (parity) 1 else 0 )).toByte()
627668 // NB: the spending script is included in a separate witness element, so we remove it from the control block.
628669 val merkleProof = scriptTree.merkleProof(spendingScript.id).tail()
@@ -689,7 +730,16 @@ public object Script {
689730 pubKey.size == 32 && sigBytes.isEmpty() -> false
690731 pubKey.size == 32 -> {
691732 val sighashType = sigHashType(sigBytes)
692- val hash = Transaction .hashForSigningSchnorr(context.tx, context.inputIndex, context.prevouts, sighashType, signatureVersion, this .context.executionData)
733+ val hash = Transaction .hashForSigningSchnorr(
734+ context.tx,
735+ context.inputIndex,
736+ context.prevouts,
737+ sighashType,
738+ signatureVersion,
739+ context.executionData.tapleafHash,
740+ context.executionData.annex,
741+ context.executionData.codeSeparatorPos
742+ )
693743 val result = Secp256k1 .verifySchnorr(sigBytes.take(64 ).toByteArray(), hash.toByteArray(), pubKey)
694744 require(result) { " Invalid Schnorr signature" }
695745 result
@@ -1364,7 +1414,16 @@ public object Script {
13641414 val sig = stack.first()
13651415 val pub = XonlyPublicKey (program.byteVector32())
13661416 val hashType = sigHashType(sig)
1367- val hash = Transaction .hashForSigningSchnorr(context.tx, context.inputIndex, context.prevouts, hashType, SigVersion .SIGVERSION_TAPROOT , context.executionData)
1417+ val hash = Transaction .hashForSigningSchnorr(
1418+ context.tx,
1419+ context.inputIndex,
1420+ context.prevouts,
1421+ hashType,
1422+ SigVersion .SIGVERSION_TAPROOT ,
1423+ context.executionData.tapleafHash,
1424+ context.executionData.annex,
1425+ context.executionData.codeSeparatorPos
1426+ )
13681427 require(Secp256k1 .verifySchnorr(sig.take(64 ).toByteArray(), hash.toByteArray(), pub.value.toByteArray())) { " invalid Schnorr signature " }
13691428 return
13701429 } else {
0 commit comments