-
Notifications
You must be signed in to change notification settings - Fork 34
EIP-41 Stealth address standard #87
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
Open
ross-weir
wants to merge
5
commits into
ergoplatform:master
Choose a base branch
from
ross-weir:eip41/stealthaddresses
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| # EIP-41 Stealth Address Standard | ||
|
|
||
| * Author: ross-weir | ||
| * Status: Proposed | ||
| * Created: 16-Dec-2022 | ||
| * Last edited: 17-Dec-2022 | ||
| * License: CC0 | ||
| * Forking: not needed | ||
|
|
||
| ## Motivation | ||
|
|
||
| This specification defines a standardized way of implementing and interacting with stealth addresses on the Ergo blockchain. | ||
|
|
||
| Stealth addresses enable recipients of a payment to remain anonymous when receiving funds thus providing financial privacy should an actor desire it. | ||
|
|
||
| ## Scenario | ||
|
|
||
| An actor, `Receiver`, wishes to receive a stealth payment so they generate a public address and share it. | ||
|
|
||
| An actor, `Sender`, wishes to make a stealth payment to `Receiver` so they create a box protected by a "one-time-secret" generated from the `Receiver`s public address. Due to the method of generation this box will be spendable by `Receiver` and cannot be linked to the `Receiver`s public address they shared. | ||
|
|
||
| ## Stealth address specification | ||
|
|
||
| The implemention suggested in this EIP was posted by `scalahub` in a thread on `ergoforum.org` [[1]](#1) and is outlined below. | ||
|
|
||
| **Script protecting stealth boxes:** | ||
|
|
||
| ```scala | ||
| { | ||
| // ===== Contract Information ===== // | ||
| // Name: EIP-0041 Stealth address contract | ||
| // Version: 1.0.0 | ||
| val gr = SELF.R4[GroupElement].get | ||
| val gy = SELF.R5[GroupElement].get | ||
| val ur = SELF.R6[GroupElement].get | ||
| val uy = SELF.R7[GroupElement].get | ||
|
|
||
| proveDHTuple(gr,gy,ur,uy) | ||
| } | ||
| ``` | ||
|
|
||
| **Script ErgoTree:** | ||
|
|
||
| ``` | ||
| 1000cee4c6a70407e4c6a70507e4c6a70607e4c6a70707 | ||
| ``` | ||
|
|
||
| **Generation of stealth box registers [[5]](#5):** | ||
|
|
||
| ```typescript | ||
| const g = new EC("secp256k1").g; // group element generator | ||
| const u = receiverPublicAddress; | ||
| const r = BigInt(rand(32)); | ||
| const y = BigInt(rand(32)); | ||
| const gr = g.mul(r); // gr = g^r = R4 | ||
| const gy = g.mul(y); // gy = g^y = R5 | ||
| const ur = u.mul(r); // ur = u^r = R6 | ||
| const uy = u.mul(y); // uy = u^y = R7 | ||
| ``` | ||
|
|
||
| **Box register declarations:** | ||
|
|
||
| - Register `R4` | ||
| - Type: `SConstant[SGroupElement]` | ||
| - Value: gr = g^r | ||
| - Register `R5` | ||
| - Type: `SConstant[SGroupElement]` | ||
| - Value: gy = g^y | ||
| - Register `R6` | ||
| - Type: `SConstant[SGroupElement]` | ||
| - Value: ur = u^r | ||
| - Register `R7` | ||
| - Type: `SConstant[SGroupElement]` | ||
| - Value: uy = u^y | ||
|
|
||
| > 📝 As discussed in the `ergoforum` discussion [[1]](#1) this register declaration is larger in size than that originally proposed by `kushti` but possesses the useful property that it could look like a legitimate use-case. | ||
|
|
||
| ## `Receiver`s public address and wallets | ||
ross-weir marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Leaning on deterministically generated wallet addresses [[6]](#6) enables stealth boxes to be retreived following a fresh wallet restore but raises a problem. When a user shares such a public address and wishes to receive stealth payments how do wallets determine they are requesting a stealth payment - the address will appear to be a regular P2PK address. | ||
|
|
||
| Requiring `Sender` to manually perform special actions when sending a stealth payment in their wallet introduces the possibility of (in addition to other issues): | ||
|
|
||
| 1. `Sender` uses a regular payment exposing a transaction that `Receiver` wanted to remain private | ||
| 2. Introduces friction when making payments, possiblily reducing conversions | ||
| 3. Less user friendly, `Sender` as a non-technical user might not know about stealth payments | ||
|
|
||
| Ideally when `Sender` is creating a stealth transaction in their wallet the UX flow should remain the same as a regular transaction, the fact that the `Receiver` is requesting a stealth payment should be opaque to the `Sender` when making the payment. To achieve this we could encode a "payment type" in the public address so wallets can detect the `Receiver` is requesting a specific type of payment and construct the transaction accordingly, similar to network and address type prefixes but only for supporting wallets. | ||
|
|
||
| This could extend in the future to more non-interactive custom payment types, not just stealth payments. | ||
|
|
||
| **Encoding** | ||
ross-weir marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Encoding of the public key to include custom payment requests could be implemented as follows: | ||
|
|
||
| | Field | Type | Description | | ||
| |-------------------|----------|--------------------------------------------------------------------------| | ||
| | Magic Byte Prefix | byte | Magic byte indiciating `Receiver` is requesting a custom transaction | | ||
| | Custom Tx Type | byte | Enum defining the type of custom transaction `Receiver` is requesting | | ||
| | Network Address | byte[] | Standard network encoded p2pk address | | ||
|
|
||
| **Constructing the public address for a `Receiver` requesting a stealth payment** | ||
|
|
||
| ```ts | ||
| enum CustomTxType { | ||
| Stealth = 0x0, | ||
| // More in future? | ||
| } | ||
|
|
||
| const magicBytePrefix = 0xCE // arbitrarily chosen for now | ||
| const customTxType = CustomTxType.Stealth | ||
| const publicShareableAddress = [magicBytePrefix, customTxType] + normalP2PKNetworkAddress | ||
|
|
||
| // publicShareableAddress is shared to social media, etc to receive payments | ||
| ``` | ||
|
|
||
| **Possible wallet implementation** | ||
|
|
||
| As mentioned previously, when `Sender` is making a payment to `Receiver` ideally their user journey would remain the same with the wallet handling the custom transaction type. | ||
|
|
||
| `Sender` inputs `Receiver`s public address encoded as above and a wallet might handle it in the following manner: | ||
|
|
||
| ```ts | ||
| enum CustomTxType { | ||
| Stealth = 0x0 | ||
| } | ||
|
|
||
| const magicBytePrefix = 0xCE | ||
| const receiverPublicAddress = new UInt8([/** receivers pub key **/]) | ||
|
|
||
| if (receiverPublicAddress[0] === magicBytePrefix) { | ||
| const customTxType = receiverPublicAddress[1] as CustomTxType | ||
| const networkEncodedPubKey = receiverPublicAddress.slice(2) | ||
|
|
||
| handleCustomTx(customTxType, networkEncodedPubKey) | ||
| } else { | ||
| handleNormalTx(receiverPublicAddress) // handle making payment as normal | ||
| } | ||
| ``` | ||
|
|
||
| ## References | ||
|
|
||
| - <a id="1">[1]</a> [Stealth Address Contract (ergoforum)](https://www.ergoforum.org/t/stealth-address-contract/255) | ||
| - <a id="2">[2]</a> [ErgoScript by example](https://github.com/ergoplatform/ergoscript-by-example/blob/main/stealthAddress.md) | ||
| - <a id="3">[3]</a> [Stealth-doc (ERGOHACK III aragogi)](https://github.com/aragogi/Stealth-doc) | ||
| - <a id="4">[4]</a> [Ethereum (EIP-5564)](https://eips.ethereum.org/EIPS/eip-5564#:~:text=A%20Stealth%20address%20is%20generated,compute%20the%20matching%20private%20key.) | ||
| - <a id="5">[5]</a> [TypeScript stealth address example](https://github.com/ross-weir/ergo-stealth-address-example/blob/main/index.ts) | ||
| - <a id="6">[6]</a> [Ergo (EIP-0003)](eip-0003.md) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.