Skip to content

Conversation

@arshbot
Copy link
Contributor

@arshbot arshbot commented Mar 28, 2022

In this commit we add the version 3 htlc, which is implemented with
taproot script spending the two payment paths: the claim path case, and
the timeout case.

Pull Request Checklist

  • Update release_notes.md if your PR contains major features, breaking changes or bugfixes

@arshbot arshbot requested review from bhandras and carlaKC March 28, 2022 20:26
@arshbot
Copy link
Contributor Author

arshbot commented Mar 28, 2022

The internalPubKey bytes are set to a dummy variable for the time being, however we should have a dynamic way of generating keys which neither the client nor the server are aware of.

Used something like the below to attempt to accomplish this but some feedback would be appreciated.

	increment := func(seedPhrase []byte, i int) []byte {
		// Increment the origin of the hash using the mapping candidateSed :=
		// h(i || seedPhrase).
		shaStream := sha256.New()

		var iterationBytes [8]byte
		binary.BigEndian.PutUint64(iterationBytes[:], uint64(i))
		shaStream.Write(iterationBytes[:])

		shaStream.Write(seedPhrase)

		seedHash := shaStream.Sum(nil)

		return seedHash[:]
	}

	var i int
	for {
		// At the start of the iteration, we'll try with a counter
		// offset of 0, each time we fail to find a proper point, we'll
		// increment this by one.
		candidateSeed := increment(randomPub, i)

		fmt.Printf("iteration_num=%v, candidate=%x\n", i, candidateSeed[:])

		var pubBytes [33]byte
		pubBytes[0] = 0x02
		copy(pubBytes[1:], candidateSeed[:])

		// Try to see if this point when intercepted as an x coordinate
		// is actually found on the curve.
		candidatePoint, err := btcec.ParsePubKey(pubBytes[:])
		if err == nil {
			fmt.Printf("Global param generated: %x\n",
				candidatePoint.SerializeCompressed())
			break
		}

		fmt.Printf("not a quadratic residue: %v\n", err)

		i++
	}

@arshbot arshbot force-pushed the HtlcV3-taproot-base branch 4 times, most recently from 8765ba2 to 83f8a76 Compare March 28, 2022 20:37
swap/htlc.go Outdated
// - witness_script_length: 1 byte
// - witness_script: len(script) bytes
// - control_block_length: 1 byte
// - control_block: 4129 bytes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you get 4129 for control block?

Copy link
Contributor Author

@arshbot arshbot Mar 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BIP 341:

the last stack element is called the control block c, and must have length 33 + 32m, for a value of m that is an integer between 0 and 128[6], inclusive.

33 + (32 * 128) = 4129

alternatively could be len(genControlBytes)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be based on the worst-case size of our control block so that we can get as close to accurate as possible.

Copy link
Member

@bhandras bhandras Apr 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Carla, since our taptree is shallow, our control block is also small compared to the worst theoretical case, so we should calculate the max for our case imo. (Even though we don't use this function).

Edit: we should actually also use these functions in our test cases as a sanity check (once the control block sizes are adjusted)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set to our worst case, which is 65 bytes - please confirm

swap/htlc.go Outdated
Comment on lines 563 to 564
TaprootKey *secp.PublicKey
InternalPubKey *secp.PublicKey
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[32] byte?

Copy link
Contributor Author

@arshbot arshbot Mar 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storing as byte slice adds a lot of conversions all over the place, but better here than throughout the codebase. Storing as array will only add another conversion without reason imo.

(also, I think secp.PublicKey are 33 bytes when compressed)

@arshbot arshbot force-pushed the HtlcV3-taproot-base branch 3 times, most recently from 3b3df7b to 5a31825 Compare March 29, 2022 15:15
@arshbot arshbot requested a review from carlaKC March 29, 2022 15:15
swap/htlc.go Outdated
func newHTLCScriptV3(cltvExpiry int32, receiverHtlcKey, senderHtlcKey [33]byte,
swapHash lntypes.Hash) (*HtlcScriptV3, error) {

_, receiverPubKey := btcec.PrivKeyFromBytes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pubkey from privkeyfrombytes?

receiverPubkey, err:= btcec.ParsePubkey(receiverHtlcKey[:])
copy(schnorrReceiverKey, schnorr.SerializePubkey(receiverPubkey)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From NewHtlc:

// NewHtlc returns a new instance. For V1 and V2 scripts, receiver and sender
// keys are expected to be in ecdsa compressed format. For V3 scripts, keys are
// expected to be raw private key bytes.

This was feedback I received from laolu and oli in regards to dealing with the serializeLoopContract issue which requires the keys stored to be 33 bytes (which ecdsa compressed are), however schnorr keys are 32 bytes, which throws the serializer off. To mitigate this issue, we store raw private key bytes in the LoopContract in memory and feed those raw bytes to NewHtlc only in the htlcv3 case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we just store [33]byte then schnorr.SerializePubkey when we need to use the key in a HtlcV3 context?

Do you have a link to that convo so I can understand the context of that discussion?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took that approach, addressed

swap/htlc.go Outdated
// - witness_script_length: 1 byte
// - witness_script: len(script) bytes
// - control_block_length: 1 byte
// - control_block: 4129 bytes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be based on the worst-case size of our control block so that we can get as close to accurate as possible.

swap/htlc.go Outdated
func newHTLCScriptV3(cltvExpiry int32, receiverHtlcKey, senderHtlcKey [33]byte,
swapHash lntypes.Hash) (*HtlcScriptV3, error) {

_, receiverPubKey := btcec.PrivKeyFromBytes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we just store [33]byte then schnorr.SerializePubkey when we need to use the key in a HtlcV3 context?

Do you have a link to that convo so I can understand the context of that discussion?

@lightninglabs-deploy
Copy link

@bhandras: review reminder
@arshbot, remember to re-request review from reviewers when ready

Copy link
Member

@bhandras bhandras left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR, almost there just a few comments remain.

swap/htlc.go Outdated
// - witness_script_length: 1 byte
// - witness_script: len(script) bytes
// - control_block_length: 1 byte
// - control_block: 4129 bytes
Copy link
Member

@bhandras bhandras Apr 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Carla, since our taptree is shallow, our control block is also small compared to the worst theoretical case, so we should calculate the max for our case imo. (Even though we don't use this function).

Edit: we should actually also use these functions in our test cases as a sanity check (once the control block sizes are adjusted)

)

sig := signTx(
tx, senderPrivKey, txscript.NewBaseTapLeaf(trHtlc.ClaimScript),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The testcase descriptions and the actual testcases are inverted.

@bhandras bhandras requested a review from guggero April 8, 2022 10:39
@yyforyongyu yyforyongyu self-requested a review April 11, 2022 14:11
@arshbot arshbot force-pushed the HtlcV3-taproot-base branch 2 times, most recently from 2a2d675 to 06fd791 Compare April 12, 2022 20:24
Copy link
Contributor Author

@arshbot arshbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the requested changes! Ready for another pass

swap/htlc.go Outdated
func newHTLCScriptV3(cltvExpiry int32, receiverHtlcKey, senderHtlcKey [33]byte,
swapHash lntypes.Hash) (*HtlcScriptV3, error) {

_, receiverPubKey := btcec.PrivKeyFromBytes(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took that approach, addressed

swap/htlc.go Outdated
// - witness_script_length: 1 byte
// - witness_script: len(script) bytes
// - control_block_length: 1 byte
// - control_block: 4129 bytes
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set to our worst case, which is 65 bytes - please confirm

@arshbot arshbot requested a review from bhandras April 12, 2022 20:26
Copy link
Contributor

@guggero guggero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks way better now, but still a lot of nits. We want to be extra careful, explicit and verbose with anything that touches on-chain scripts.

preimage := [32]byte{1, 2, 3}
p := lntypes.Preimage(preimage)
hashedPreimage := sha256.Sum256(p[:])
value := int64(800_000 - 500) // TODO(guggero): Calculate actual fee.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fee calculation is now available in lnd master.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed fee because previous tests don't include and it's a distraction from what this is testing

@arshbot arshbot force-pushed the HtlcV3-taproot-base branch from 06fd791 to fcc1c35 Compare April 13, 2022 16:22
@arshbot arshbot requested a review from guggero April 13, 2022 16:23
@arshbot
Copy link
Contributor Author

arshbot commented Apr 13, 2022

Addressed all nits, left a clarifying question! @bhandras @guggero PTAL!!

@arshbot arshbot force-pushed the HtlcV3-taproot-base branch 2 times, most recently from b8dff91 to abce7d1 Compare April 14, 2022 16:41
@arshbot arshbot requested a review from bhandras April 14, 2022 16:42
Copy link
Member

@bhandras bhandras left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried to find everything, hopefully we're now just one round away from being ready.

swap/htlc.go Outdated

switch outputType {
case HtlcNP2WSH:
pkScript, err := input.WitnessScriptHash(htlc.Script())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pkScript inside the case will shadow the pkScript declared outside. A way to fix it is to declare the error as well. Example: https://go.dev/play/p/3RXcMVh162P

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, done. Since err is already declared earlier, the redeclaration shouldn't be necessary

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still wrong?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edit: I see you fixed it in the other commit. Please fix it in this commit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Is still wrong in the first commit.

@arshbot arshbot force-pushed the HtlcV3-taproot-base branch 2 times, most recently from bcfb001 to b3e4f68 Compare April 18, 2022 18:49
@arshbot arshbot requested a review from bhandras April 18, 2022 18:49
@arshbot
Copy link
Contributor Author

arshbot commented Apr 19, 2022

@bhandras PTAL!

@arshbot
Copy link
Contributor Author

arshbot commented Apr 19, 2022

@guggero I think is ready for another pass from you as well! PTAL!

@arshbot arshbot force-pushed the HtlcV3-taproot-base branch from b3e4f68 to 2135bcd Compare April 19, 2022 14:17
Copy link
Member

@bhandras bhandras left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost ready :)

swap/htlc.go Outdated

switch outputType {
case HtlcNP2WSH:
pkScript, err := input.WitnessScriptHash(htlc.Script())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edit: I see you fixed it in the other commit. Please fix it in this commit.

@arshbot arshbot force-pushed the HtlcV3-taproot-base branch from 2135bcd to 0f75c9b Compare April 19, 2022 23:11
@arshbot arshbot requested a review from bhandras April 19, 2022 23:12
Copy link
Member

@bhandras bhandras left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the aliasing issue (#473 (review)) in the first commit, other than that LGTM 🎉

arshbot added 2 commits April 20, 2022 10:52
In this commit we add the version 3 htlc, which is implemented with
taproot script spending the two payment paths: the claim path case, and
the timeout case.
@arshbot arshbot force-pushed the HtlcV3-taproot-base branch from 0f75c9b to 173c213 Compare April 20, 2022 14:53
@arshbot arshbot merged commit 5446a1f into lightninglabs:master Apr 20, 2022
@bhandras
Copy link
Member

Uhm, these PRs need two approvals..

This was referenced Apr 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants