Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: hardware wallet transactions #98

Merged
merged 17 commits into from
Feb 11, 2024
Merged

Conversation

SWvheerden
Copy link
Contributor

Description

Intial draft for hardware wallet transactions.

Motivation and Context

How Has This Been Tested?

src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
@AaronFeickert
Copy link
Contributor

What should be the relationship between this RFC and the existing RFC-0204 (which discusses interactive and "legacy" one-sided outputs) and RFC-0203 (which discusses stealth one-sided outputs)?

### Receiving one-sided-stealth
`TODO`

### Output recovery
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps worth noting that this process only works for interactive outputs.

For legacy one-sided outputs, the helper can watch for A in scripts (as you note elsewhere), but since it can't complete the DHKE required to decrypt the commitment opening, it can't assert the output is valid and must send it to the signer to be checked.

For stealth one-sided outputs, the helper can't do anything except send such outputs to the signer to be checked.

Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not ideal, but it's not terrible if the helper can at least make a note of all the places `` is found and then batch requests to signer when it's available. The UX would be "42 transactions received. Synch with your device to update the balance".

The synching would be pretty quick then.

That said, I think we'll hone in on a solution where we needn't go down this road.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, for legacy one-sided it's mostly a UX issue, and somewhat a "wait for the signer" issue. For stealth one-sided it's an entirely different problem that does not scale.

Copy link
Collaborator

@CjS77 CjS77 left a comment

Choose a reason for hiding this comment

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

I like it. Some discussion points and clarifying questions.

src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
\end{aligned}
$$

The blinding factor (\\( k_i \\) ) is used as a random nonce when creating the script key. This means the helper can create the public key without the signer present, and the signer can then at a later stage create the private key from the nonce. The key pair (\\( a, A \\) ) is the master key pair from the signer. The private key (\\( a \\) ) is kept secret by the signer at all times.
Copy link
Collaborator

Choose a reason for hiding this comment

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

When you say "master key pair", does this mean that the same a is used for every transaction?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, it would be.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, it needs to be for the helper to calculate the Public receive address.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there any benefit in doing addition instead of DH?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's faster, and there's no need to do ECDH for this use case.

src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
### Receiving one-sided-stealth
`TODO`

### Output recovery
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not ideal, but it's not terrible if the helper can at least make a note of all the places `` is found and then batch requests to signer when it's available. The UX would be "42 transactions received. Synch with your device to update the balance".

The synching would be pretty quick then.

That said, I think we'll hone in on a solution where we needn't go down this road.

### Process Overview
By splitting the ownership of the [UTXO]'s secret by assigning knowledge of only the script key (\\( k_s \\) ) to the signer, we can lift much of the heavy cryptography like bulletproof creation to the helper device by exposing (\\( k_i \\) ) to it. By looking at how [one-sided-stealth] transactions are created, we can construct the script key in such a way that the helper can calculate the public script key, but cannot calculate the private script key.

All [UTXO]s created will be created with a script `PushPubkey(K_S)`. The key (\\( k_s \\) ) is created as follows:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I gather, from the discussion below, that you mean to say that we must update the protocol to deprecate the current NOP default script so that there's always a script key present?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, only change the default behaviour in the default implementation.
The No-Op script is still useful to have.
Currently, we use No-Op in all default interactive transactions. that's all I propose we change


### Output recovery
When creating outputs the wallet encrypts the blinding factor (\\k_i \\) and value \\( v \\) with (\\( k_H \\) ).
Because the key (\\( k_H \\) ) is calculated from the seed phrase of the signer, this will be the same each time. The helper can try to decrypt each scanned output, when it is successful it knows it has found its own output.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are a and k_H the same thing?

Copy link
Contributor

Choose a reason for hiding this comment

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

No, k_H is a fixed helper key derived from a that's used for encrypting commitment openings. The signer provides it once to the helper, who can then use it for AEAD operations.


### Output recovery
When creating outputs the wallet encrypts the blinding factor (\\k_i \\) and value \\( v \\) with (\\( k_H \\) ).
Because the key (\\( k_H \\) ) is calculated from the seed phrase of the signer, this will be the same each time. The helper can try to decrypt each scanned output, when it is successful it knows it has found its own output.
Copy link
Collaborator

Choose a reason for hiding this comment

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

So it's a bit worrying to use the same key every time from a security perspective.

Could we perhaps use a strategy similar to the one in BIP-32 for deriving an infinite number of A' from a single parent private key (signer) or the parent public key (helper)?

Copy link
Contributor

Choose a reason for hiding this comment

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

There's no security problem here. Encrypted openings use an extended nonce whose entire purpose is to allow for safe key reuse with random nonce sampling. And this key reuse allows for super-fast interactive output scanning during recovery.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, the wallet public key A doesn't play any role in AEAD decryption during recovery. It only comes into play when testing for offset script public keys, and in that case, there's already a hash-based offset applied that masks the fixed A.

Copy link
Collaborator

@CjS77 CjS77 left a comment

Choose a reason for hiding this comment

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

I like it. Some discussion points and clarifying questions.

@CjS77 CjS77 changed the title feat: HW transactions feat: hardware wallet transactions May 19, 2023
SWvheerden and others added 2 commits May 22, 2023 10:15
Co-authored-by: Cayle Sharrock <CjS77@users.noreply.github.com>
Co-authored-by: Cayle Sharrock <CjS77@users.noreply.github.com>
Copy link
Collaborator

@stringhandler stringhandler left a comment

Choose a reason for hiding this comment

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

I think it's worth adding a section on generic TariScripts that are not one-sided, e.g. HTLC

src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved

## Background

Vanilla [Mimblewimble] only has a single secret per [UTXO], the blinding factor (\\( k_i \\) ), the Tari protocol extends the [Mimblewimble] protocol to include scripting in the form of [TariScript]. This adds a second secret per [UTXO] called the script_key (\\( k_s \\) ). In practical terms this means that while vanilla [Mimblewimble] only requires that a wallet wishing to spend an [UTXO], prove knowledge of (\\( k_i \\) ) by producing the kernel signature, this is not sufficient for Tari. A Tari wallet must also prove knowledge of the script key (\\( k_s \\) ), by producing the script signature.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this true even for Nop scripts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Practically No, Technically yes.
A No-Op script that just contains the No-Op operation accepts any input.

So from the wallet submitting the tx, it can submit any Public key as input, and it's still valid. But it still needs to prove it knows the secret key of that public key.

But from the prover side, aka base_node, it just runs, the script and verifies the signature, thus proving knowledge of the script key k_S. How the key was calculated from the script the Base_node does not care.


To properly implement hardware wallets we need the following requirements to be met:
* No UTXO can be spent without a user physically approving the transaction on the hardware wallet.
* Users need to verify transaction properties when signing for transactions.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you referring to the display of the transaction on the HW wallet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes

src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
\end{aligned}
$$

The blinding factor (\\( k_i \\) ) is used as a random nonce when creating the script key. This means the helper can create the public key without the signer present, and the signer can then at a later stage create the private key from the nonce. The key pair (\\( a, A \\) ) is the master key pair from the signer. The private key (\\( a \\) ) is kept secret by the signer at all times.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there any benefit in doing addition instead of DH?

src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_LedgerTransactions.md Outdated Show resolved Hide resolved

### Receiving normal one-sided transaction
This can be done by the helper asking the signer for a public key. And advertising this public key as the destination public key for a 1-sided transaction.
The helper can scan the blockchain for this public key.
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens to the wallet's Tari Address? Is this not related?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently, the wallet calculates the Public script key for the script from the wallet's Tari Address. The only reason that is used is that it's an easily known key that the wallet has the secret key to. So we use that key in place of the TariAddress

The helper can scan the blockchain for this public key.

### Receiving one-sided-stealth
`TODO`
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just adding a marker here. DNM until resolved

Copy link
Collaborator

Choose a reason for hiding this comment

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

As far as I see it, this is no different from normal (public) one-sided transactions

SWvheerden and others added 5 commits May 22, 2023 11:51
Co-authored-by: stringhandler <stringhandler@gmail.com>
Co-authored-by: stringhandler <stringhandler@gmail.com>
Co-authored-by: stringhandler <stringhandler@gmail.com>
Co-authored-by: stringhandler <stringhandler@gmail.com>
* Helper: This entity is the program that helps the signer construct the transaction, send it over the network and scan the network, aka wallet.

### Process Overview
By splitting the ownership of the [UTXO]'s secret by assigning knowledge of only the script key (\\( k_s \\) ) to the signer, we can lift much of the heavy cryptography like bulletproof creation to the helper device by exposing (\\( k_i \\) ) to it. By looking at how [one-sided-stealth] transactions are created, we can construct the script key in such a way that the helper can calculate the public script key, but cannot calculate the private script key.
Copy link
Contributor

Choose a reason for hiding this comment

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

Some context on what a UTXO's "secret" is could be helpful here. Really it's two secret values: the commitment mask and the script private key. (The value is private too, but can be easily brute forced and therefore not as relevant.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is discussed two paragraphs up?

Copy link
Contributor

@AaronFeickert AaronFeickert left a comment

Choose a reason for hiding this comment

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

There are a few spots where the math-mode separators are written incorrectly, meaning not all math renders properly.

src/RFC-0205_HardwareTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_HardwareTransactions.md Outdated Show resolved Hide resolved
src/RFC-0205_HardwareTransactions.md Outdated Show resolved Hide resolved
Co-authored-by: Brian Pearce <brianp@users.noreply.github.com>
add mention of provider requirements
@CjS77 CjS77 merged commit 584e997 into tari-project:main Feb 11, 2024
2 checks passed
@SWvheerden SWvheerden deleted the sw_ledger branch April 22, 2024 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants