@@ -204,7 +204,18 @@ object Scripts {
204204 */
205205 def witnessAnchor (localSig : ByteVector64 , anchorScript : ByteVector ): ScriptWitness = ScriptWitness (der(localSig) :: anchorScript :: Nil )
206206
207- def htlcOffered (keys : CommitmentPublicKeys , paymentHash : ByteVector32 , commitmentFormat : CommitmentFormat ): Seq [ScriptElt ] = {
207+ case class RipemdOfPaymentHash (ripemdHash : ByteVector ) {
208+ require(ripemdHash.size == 20 )
209+ }
210+
211+ object RipemdOfPaymentHash {
212+ def apply (paymentHash : ByteVector32 ): RipemdOfPaymentHash = RipemdOfPaymentHash (Crypto .ripemd160(paymentHash))
213+
214+ // this value cannot be generated with a real payment hash
215+ val empty : RipemdOfPaymentHash = RipemdOfPaymentHash (ByteVector .fill(20 )(0 ))
216+ }
217+
218+ def htlcOffered (keys : CommitmentPublicKeys , paymentHash : RipemdOfPaymentHash , commitmentFormat : CommitmentFormat ): Seq [ScriptElt ] = {
208219 val addCsvDelay = commitmentFormat match {
209220 case DefaultCommitmentFormat => false
210221 case _ : AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => true
@@ -220,7 +231,7 @@ object Scripts {
220231 // To me via HTLC-timeout transaction (timelocked).
221232 OP_DROP :: OP_2 :: OP_SWAP :: OP_PUSHDATA (keys.localHtlcPublicKey) :: OP_2 :: OP_CHECKMULTISIG ::
222233 OP_ELSE ::
223- OP_HASH160 :: OP_PUSHDATA (Crypto .ripemd160( paymentHash) ) :: OP_EQUALVERIFY ::
234+ OP_HASH160 :: OP_PUSHDATA (paymentHash.ripemdHash ) :: OP_EQUALVERIFY ::
224235 OP_CHECKSIG ::
225236 OP_ENDIF ::
226237 (if (addCsvDelay) {
@@ -232,6 +243,46 @@ object Scripts {
232243 // @formatter:on
233244 }
234245
246+ def htlcOffered (keys : CommitmentPublicKeys , paymentHash : ByteVector32 , commitmentFormat : CommitmentFormat ): Seq [ScriptElt ] =
247+ htlcOffered(keys, RipemdOfPaymentHash (paymentHash), commitmentFormat)
248+
249+ // @formatter::off
250+ def extractHtlcInfoFromHtlcOfferedScript (script : Seq [ScriptElt ]): Option [RipemdOfPaymentHash ] = script match {
251+ case OP_DUP :: OP_HASH160 :: OP_PUSHDATA (_, _) :: OP_EQUAL ::
252+ OP_IF ::
253+ OP_CHECKSIG ::
254+ OP_ELSE ::
255+ OP_PUSHDATA (_, _) :: OP_SWAP :: OP_SIZE :: OP_PUSHDATA (_, _) :: OP_EQUAL ::
256+ OP_NOTIF ::
257+ // To me via HTLC-timeout transaction (timelocked).
258+ OP_DROP :: OP_2 :: OP_SWAP :: OP_PUSHDATA (_, _) :: OP_2 :: OP_CHECKMULTISIG ::
259+ OP_ELSE ::
260+ OP_HASH160 :: OP_PUSHDATA (ripemdOfPaymentHash, _) :: OP_EQUALVERIFY :: OP_CHECKSIG ::
261+ OP_ENDIF ::
262+ OP_ENDIF :: Nil if ripemdOfPaymentHash.size == 20 => {
263+ Some (RipemdOfPaymentHash (ripemdOfPaymentHash))
264+ }
265+ case OP_DUP :: OP_HASH160 :: OP_PUSHDATA (_, _) :: OP_EQUAL ::
266+ OP_IF ::
267+ OP_CHECKSIG ::
268+ OP_ELSE ::
269+ OP_PUSHDATA (_, _) :: OP_SWAP :: OP_SIZE :: OP_PUSHDATA (_, _) :: OP_EQUAL ::
270+ OP_NOTIF ::
271+ // To me via HTLC-timeout transaction (timelocked).
272+ OP_DROP :: OP_2 :: OP_SWAP :: OP_PUSHDATA (_, _) :: OP_2 :: OP_CHECKMULTISIG ::
273+ OP_ELSE ::
274+ OP_HASH160 :: OP_PUSHDATA (ripemdOfPaymentHash, _) :: OP_EQUALVERIFY :: OP_CHECKSIG ::
275+ OP_ENDIF ::
276+ OP_1 :: OP_CHECKSEQUENCEVERIFY :: OP_DROP ::
277+ OP_ENDIF :: Nil if ripemdOfPaymentHash.size == 20 => {
278+ Some (RipemdOfPaymentHash (ripemdOfPaymentHash))
279+ }
280+ case _ => None
281+ }
282+ // @formatter::on
283+
284+ def extractHtlcInfoFromHtlcOfferedScript (script : ByteVector ): Option [RipemdOfPaymentHash ] = extractHtlcInfoFromHtlcOfferedScript(Script .parse(script))
285+
235286 /**
236287 * This is the witness script of the 2nd-stage HTLC Success transaction (consumes htlcOffered script from commit tx)
237288 */
@@ -261,7 +312,7 @@ object Scripts {
261312 /** Extract payment preimages from a (potentially batched) claim HTLC transaction's witnesses. */
262313 def extractPreimagesFromClaimHtlcSuccess (tx : Transaction ): Set [ByteVector32 ] = tx.txIn.map(_.witness).collect(extractPreimageFromClaimHtlcSuccess).toSet
263314
264- def htlcReceived (keys : CommitmentPublicKeys , paymentHash : ByteVector32 , lockTime : CltvExpiry , commitmentFormat : CommitmentFormat ): Seq [ScriptElt ] = {
315+ def htlcReceived (keys : CommitmentPublicKeys , paymentHash : RipemdOfPaymentHash , lockTime : CltvExpiry , commitmentFormat : CommitmentFormat ): Seq [ScriptElt ] = {
265316 val addCsvDelay = commitmentFormat match {
266317 case DefaultCommitmentFormat => false
267318 case _ : AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => true
@@ -275,7 +326,7 @@ object Scripts {
275326 OP_PUSHDATA (keys.remoteHtlcPublicKey) :: OP_SWAP :: OP_SIZE :: encodeNumber(32 ) :: OP_EQUAL ::
276327 OP_IF ::
277328 // To me via HTLC-success transaction.
278- OP_HASH160 :: OP_PUSHDATA (Crypto .ripemd160( paymentHash) ) :: OP_EQUALVERIFY ::
329+ OP_HASH160 :: OP_PUSHDATA (paymentHash.ripemdHash ) :: OP_EQUALVERIFY ::
279330 OP_2 :: OP_SWAP :: OP_PUSHDATA (keys.localHtlcPublicKey) :: OP_2 :: OP_CHECKMULTISIG ::
280331 OP_ELSE ::
281332 // To you after timeout.
@@ -291,6 +342,48 @@ object Scripts {
291342 // @formatter:on
292343 }
293344
345+ // @formatter:off
346+ def extractHtlcInfoFromHtlcReceived (script : Seq [ScriptElt ]): Option [(RipemdOfPaymentHash , CltvExpiry )] = script match {
347+ case OP_DUP :: OP_HASH160 :: OP_PUSHDATA (_, _) :: OP_EQUAL ::
348+ OP_IF ::
349+ OP_CHECKSIG ::
350+ OP_ELSE ::
351+ OP_PUSHDATA (_, _) :: OP_SWAP :: OP_SIZE :: OP_PUSHDATA (_, _) :: OP_EQUAL ::
352+ OP_IF ::
353+ // To me via HTLC-success transaction.
354+ OP_HASH160 :: OP_PUSHDATA (ripemdHash, _) :: OP_EQUALVERIFY ::
355+ OP_2 :: OP_SWAP :: OP_PUSHDATA (_, _) :: OP_2 :: OP_CHECKMULTISIG ::
356+ OP_ELSE ::
357+ // To you after timeout.
358+ OP_DROP :: OP_PUSHDATA (rawExpiry, _) :: OP_CHECKLOCKTIMEVERIFY :: OP_DROP ::
359+ OP_CHECKSIG ::
360+ OP_ENDIF ::
361+ OP_1 :: OP_CHECKSEQUENCEVERIFY :: OP_DROP ::
362+ OP_ENDIF :: Nil if ripemdHash.size == 20 => Some (RipemdOfPaymentHash (ripemdHash), CltvExpiry (Script .decodeNumber(rawExpiry, false )))
363+ case OP_DUP :: OP_HASH160 :: OP_PUSHDATA (_, _) :: OP_EQUAL ::
364+ OP_IF ::
365+ OP_CHECKSIG ::
366+ OP_ELSE ::
367+ OP_PUSHDATA (_, _) :: OP_SWAP :: OP_SIZE :: OP_PUSHDATA (_, _) :: OP_EQUAL ::
368+ OP_IF ::
369+ // To me via HTLC-success transaction.
370+ OP_HASH160 :: OP_PUSHDATA (ripemdHash, _) :: OP_EQUALVERIFY ::
371+ OP_2 :: OP_SWAP :: OP_PUSHDATA (_, _) :: OP_2 :: OP_CHECKMULTISIG ::
372+ OP_ELSE ::
373+ // To you after timeout.
374+ OP_DROP :: OP_PUSHDATA (rawExpiry, _) :: OP_CHECKLOCKTIMEVERIFY :: OP_DROP ::
375+ OP_CHECKSIG ::
376+ OP_ENDIF ::
377+ OP_ENDIF :: Nil if ripemdHash.size == 20 => Some (RipemdOfPaymentHash (ripemdHash), CltvExpiry (Script .decodeNumber(rawExpiry, false )))
378+ case _ => None
379+ }
380+ // @formatter:on
381+
382+ def extractHtlcInfoFromHtlcReceived (script : ByteVector ): Option [(RipemdOfPaymentHash , CltvExpiry )] = extractHtlcInfoFromHtlcReceived(Script .parse(script))
383+
384+ def htlcReceived (keys : CommitmentPublicKeys , paymentHash : ByteVector32 , lockTime : CltvExpiry , commitmentFormat : CommitmentFormat ): Seq [ScriptElt ] =
385+ htlcReceived(keys, RipemdOfPaymentHash (paymentHash), lockTime, commitmentFormat)
386+
294387 /**
295388 * This is the witness script of the 2nd-stage HTLC Timeout transaction (consumes htlcOffered script from commit tx)
296389 */
@@ -445,10 +538,10 @@ object Scripts {
445538 *
446539 * @return a script used to create a "spend offered HTLC" leaf in a script tree
447540 */
448- private def offeredHtlcSuccess (keys : CommitmentPublicKeys , paymentHash : ByteVector32 ): Seq [ScriptElt ] = {
541+ private def offeredHtlcSuccess (keys : CommitmentPublicKeys , paymentHash : RipemdOfPaymentHash ): Seq [ScriptElt ] = {
449542 // @formatter:off
450543 OP_SIZE :: encodeNumber(32 ) :: OP_EQUALVERIFY ::
451- OP_HASH160 :: OP_PUSHDATA (Crypto .ripemd160( paymentHash) ) :: OP_EQUALVERIFY ::
544+ OP_HASH160 :: OP_PUSHDATA (paymentHash.ripemdHash ) :: OP_EQUALVERIFY ::
452545 OP_PUSHDATA (keys.remoteHtlcPublicKey.xOnly) :: OP_CHECKSIGVERIFY ::
453546 OP_1 :: OP_CHECKSEQUENCEVERIFY :: Nil
454547 // @formatter:on
@@ -457,13 +550,15 @@ object Scripts {
457550 /**
458551 * Script tree used for offered HTLCs.
459552 */
460- def offeredHtlcScriptTree (keys : CommitmentPublicKeys , paymentHash : ByteVector32 ): ScriptTree .Branch = {
553+ def offeredHtlcScriptTree (keys : CommitmentPublicKeys , paymentHash : RipemdOfPaymentHash ): ScriptTree .Branch = {
461554 new ScriptTree .Branch (
462555 new ScriptTree .Leaf (offeredHtlcTimeout(keys)),
463556 new ScriptTree .Leaf (offeredHtlcSuccess(keys, paymentHash)),
464557 )
465558 }
466559
560+ def offeredHtlcScriptTree (keys : CommitmentPublicKeys , paymentHash : ByteVector32 ): ScriptTree .Branch = offeredHtlcScriptTree(keys, RipemdOfPaymentHash (paymentHash))
561+
467562 /**
468563 * Script used for offered HTLCs.
469564 */
@@ -491,10 +586,10 @@ object Scripts {
491586 *
492587 * miniscript: and_v(v:hash160(H),and_v(v:pk(local_key),pk(remote_key)))
493588 */
494- private def receivedHtlcSuccess (keys : CommitmentPublicKeys , paymentHash : ByteVector32 ): Seq [ScriptElt ] = {
589+ private def receivedHtlcSuccess (keys : CommitmentPublicKeys , paymentHash : RipemdOfPaymentHash ): Seq [ScriptElt ] = {
495590 // @formatter:off
496591 OP_SIZE :: encodeNumber(32 ) :: OP_EQUALVERIFY ::
497- OP_HASH160 :: OP_PUSHDATA (Crypto .ripemd160( paymentHash) ) :: OP_EQUALVERIFY ::
592+ OP_HASH160 :: OP_PUSHDATA (paymentHash.ripemdHash ) :: OP_EQUALVERIFY ::
498593 OP_PUSHDATA (keys.localHtlcPublicKey.xOnly) :: OP_CHECKSIGVERIFY ::
499594 OP_PUSHDATA (keys.remoteHtlcPublicKey.xOnly) :: OP_CHECKSIG :: Nil
500595 // @formatter:on
@@ -503,13 +598,16 @@ object Scripts {
503598 /**
504599 * Script tree used for received HTLCs.
505600 */
506- def receivedHtlcScriptTree (keys : CommitmentPublicKeys , paymentHash : ByteVector32 , expiry : CltvExpiry ): ScriptTree .Branch = {
601+ def receivedHtlcScriptTree (keys : CommitmentPublicKeys , paymentHash : RipemdOfPaymentHash , expiry : CltvExpiry ): ScriptTree .Branch = {
507602 new ScriptTree .Branch (
508603 new ScriptTree .Leaf (receivedHtlcTimeout(keys, expiry)),
509604 new ScriptTree .Leaf (receivedHtlcSuccess(keys, paymentHash)),
510605 )
511606 }
512607
608+ def receivedHtlcScriptTree (keys : CommitmentPublicKeys , paymentHash : ByteVector32 , expiry : CltvExpiry ): ScriptTree .Branch =
609+ receivedHtlcScriptTree(keys, RipemdOfPaymentHash (paymentHash), expiry)
610+
513611 /**
514612 * Script used for received HTLCs.
515613 */
0 commit comments