Skip to content

Commit

Permalink
Merge pull request #14 from logical-mechanism/code-review-01
Browse files Browse the repository at this point in the history
Code review 01
  • Loading branch information
logicalmechanism authored Nov 23, 2024
2 parents b78f2c0 + 64d7db1 commit 6991ec7
Show file tree
Hide file tree
Showing 14 changed files with 133 additions and 93 deletions.
46 changes: 23 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Seedelf - A Cardano Stealth Wallet

**Seedelf** is a Cardano stealth wallet that hides the receiver and spender with Schnorr proofs using the BLS12-381 curve.
**Seedelf** is a stealth wallet that hides the receiver and spender with Schnorr proofs using the BLS12-381 curve.

## What is a Seedelf token?

Expand Down Expand Up @@ -50,17 +50,17 @@ Below is a quick overview of how the wallet contract works.

`Generator`: An element of the curve that will produce more elements of the curve with scaler multiplication.

`G1`: The base g1 generator.
`G1`: The base $\mathbb{G}_{1}$ generator from BLS12-381.

`Public Key`: The public key element of the curve, this information is known publicly.
`Public Value`: The public value element of the curve, this information is known publicly.

`Registry`: The datum consisting the generator and the public key.
`Register`: The datum consisting the generator and the public value.

`Re-Randomizing`: The construction of a new registry from an existing and valid registry.
`Re-Randomizing`: The construction of a new register from an existing register.

### Spendability

The registry contains the generator and the public key for some UTxO.
The register contains the generator and the public key for some UTxO.

```rust
pub type Register {
Expand Down Expand Up @@ -94,13 +94,13 @@ $$

A register defines a public address used to produce a private address. A user wishing to create a stealth address for another user will find a public address and re-randomize the register as the new datum of a future UTxO.

A user selects a random integer, $d$, and constructs a new registry.
A user selects a random integer, $d$, and constructs a new register.

$$
(g, u) \rightarrow (g^{d}, u^{d})
$$

From the outside viewer, the new registry appears random and can not be inverted back into the public registry because we assume the Elliptic Curve Decisional-Diffie-Hellman (ECDDH) problem is hard. The scalar multiplication of the registry maintains spendability while providing privacy about who owns the UTxO.
From the outside viewer, the new register appears random and can not be inverted back into the public register because we assume the Elliptic Curve Decisional-Diffie-Hellman (ECDDH) problem is hard. The scalar multiplication of the register maintains spendability while providing privacy about who owns the UTxO.

#### Re-Randomization Spendability Proof

Expand Down Expand Up @@ -136,23 +136,23 @@ The proof of re-randomization reduces to proving the original Schnorr proof.

### Finding Spendable UTxOs From The Set

In the contract, there will be many UTxOs with unique registries. A user can always find their UTxOs by searching the UTxO set at the contract address and finding all the registries that satisfy $(\alpha, \beta) \rightarrow \alpha^{x} = \beta$ for the user's secret $x$.
In the contract, there will be many UTxOs with unique registers. A user can always find their UTxOs by searching the UTxO set at the contract address and finding all the registers that satisfy $(\alpha, \beta) \rightarrow \alpha^{x} = \beta$ for the user's secret $x$.

### Wallet Limitations

The wallet is just a smart contract. It is bound by the cpu and memory units of the underlying blockchain, meaning that a UTxO can only hold so many tokens before it becomes unspendable due to space and time limitations. In this implementation, the value is not hidden nor mixed in any way, shape, or fashion. This contract is equivalent to generating addresses using a hierarchical deterministic wallet, but instead of keeping the root key private and generating the address when asked, it is now public via a datum, and address generation is the sender's duty and not the receiver's.

Sending funds requires a correct and equal $d$ value applied to both elements of the registry. Incorrectly applied $d$ values will result in a stuck UTxO inside the contract as seen in the example below.
Sending funds requires a correct and equal $d$ value applied to both elements of the register. Incorrectly applied $d$ values will result in a stuck UTxO inside the contract as seen in the example below.

$$
(g, u) \rightarrow (g^{d}, u^{d'}) \quad \text{where } d \neq d'
$$

This registry would become unspendable, resulting in lost funds for both Bob and Alice.
This register would become unspendable, resulting in lost funds for both Bob and Alice.

### De-Anonymizing Attacks

Three attacks are known to break the privacy of this wallet. The first attack comes from picking a bad $d$ value. A small $d$ value may be able to be brute-forced. The brute-force attack is circumvented by selecting a $d$ value on the order of $2^{254}$. The second attack comes from not properly destroying the $d$ value information after the transaction. The $d$ value is considered toxic waste in this context. If the $d$ values are known for some users then it becomes trivial to backtrack the registry into the original form thus losing all privacy. The third attack is tainted collateral UTxOs. On the Cardano blockchain, a collateral must be put into a transaction to be taken if the transaction fails when being placed into the block. The collateral has to be on a payment credential which means that the collateral UTxO by definition isn't anonymous and ownership it is known the entire time. This means that an outside user could track a wallet by simply watching which collaterals were used.
Three attacks are known to break the privacy of this wallet. The first attack comes from picking a bad $d$ value. A small $d$ value may be able to be brute-forced. The brute-force attack is circumvented by selecting a $d$ value on the order of $2^{254}$. The second attack comes from not properly destroying the $d$ value information after the transaction. The $d$ value is considered toxic waste in this context. If the $d$ values are known for some users then it becomes trivial to invert the register into the original form thus losing all privacy. The third attack is tainted collateral UTxOs. On the Cardano blockchain, a collateral must be put into a transaction to be taken if the transaction fails when being placed into the block. The collateral has to be on a payment credential which means that the collateral UTxO by definition isn't anonymous and the ownership is known the entire time. This means that an outside user could track a user's actions by simply watching which collaterals were used during transactions.

Privacy is preserved as long as $d$ is large and destroyed after use and the collateral used in the transaction is unconnectable to the original owner. This type of wallet can not be staked.

Expand All @@ -162,14 +162,14 @@ The happy paths follow Alice and Bob as they interact with their seedelf wallets

### Creating A seedelf

A seedelf will be saved locally inside a file. This file is a simple way to store the secret value $x$ and the original registry values.
A seedelf will be saved locally inside a file. This file is a simple way to store the secret value $x$ and the original register values.

An example seedelf file is shown below.
```json
{
"a": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb",
"b": "a2e4786cbc52f9e2f5266ed7fcabe88e01ba92e652c8be79b994c522724bba015ccdd038f42aa03f907a0f6ffe16fc4c",
"secret": 6626762640525735488664943722689229887125200532629070040776184331198666927087
"a": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb",
"b": "8912c5a3e0a3f6dfeee8ab7e1559ad2ff40c4caf32c952593a1ab8863662c26e795176b3bb8930c58f566c53a885452c",
"secret": 50932149572198509980040270467982453407914038612833920156636550490899997953674
}
```

Expand All @@ -184,30 +184,30 @@ Removing funds is a simple process. Given a secret value $x$, search the UTxO se
/// computed using the Fiat-Shamir heuristic. The vkh is used as a one time
/// pad for the proof to prevent rollback attacks.
///
pub type WalletRedeemer {
pub type Proof {
// this is z = r + c * x as a bytearray
z_b: ByteArray,
// this is the g^r compressed G1Element
g_r_b: ByteArray,
// one time use signature
sig: VerificationKeyHash,
vkh: VerificationKeyHash,
}
```

These ZK element combined with a registry is the only required knowledge to spend a UTxO. The spent UTxOs can be sent to any non-seedelf wallet or can be recombined into a new UTxO inside the seedelf wallet with a new re-randomzied registry.
These ZK element combined with a register is the only required knowledge to spend a UTxO. The spent UTxOs can be sent to any non-seedelf wallet or can be recombined into a new UTxO inside the seedelf wallet with a new re-randomzied register. A random key signature is required to create a one-time pad for the proof as funds could be respendable without it due to the transaction being dropped during a rollback event and a user being able to pick off the proof and resubmit. This is completely circumvented by having a random key sign the transaction and using that verification key hash inside of the Fiat-Shamir transform.

### Sending Funds

Sending funds works very similarly to removing funds but the funds are sent to a new re-randomized regsitry given by finding the registry on some other seedelf token. This act perserves privacy. An outside user should only see random UTxOs being collected and sent to a new random registry. The link between Alice and Bob should remain hidden.
Sending funds works very similarly to removing funds but the funds are sent to a new re-randomized register given by finding the register on some other seedelf token. This act perserves privacy. An outside user should only see random UTxOs being collected and sent to a new random register. The link between Alice and Bob should remain hidden.

### Non-Mixablility

Spendability is always in the hands of the original owner. If two UTxOs are being spent then it is safe to assume it is the same owner because if two different users spent UTxOs together inside of a single transaction then there would be no way to ensure funds are not lost or stolen by one of the parties. If Alice and Bob are working together then either Alice or Bob has the chance of losing funds. Inside of real mixers the chance of losing funds does not exist as the spendability is arbitrary thus ensuring the mixing probably exists. This is not the case inside the seedelf wallet.
Spendability is always in the hands of the original owner. If two UTxOs are being spent then it is safe to assume it is the same owner because if two different users spent UTxOs together inside of a single transaction then there would be no way to ensure funds are not lost or stolen by one of the parties. If Alice and Bob are working together then either Alice or Bob has the chance of losing funds. Inside of real mixers the chance of losing funds does not exist as the spendability is arbitrary thus ensuring the mixing probably exists. This is not the case inside the seedelf wallet. This wallet is purely just for stealth not for mixing.

## Defeating The Collateral Problem

TODO
- TODO

## The Seedelf Application

TODO
- TODO
27 changes: 14 additions & 13 deletions complete_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ rm hashes/* || true
rm -fr build/ || true

# compile the scripts with aiken build
echo -e "\033[1;34m\nCompiling Contracts \033[0m"
echo -e "\033[1;34m\nCompiling...\033[0m"

# remove all traces
aiken build --trace-level silent --trace-filter user-defined
Expand All @@ -22,27 +22,28 @@ aiken build --trace-level silent --trace-filter user-defined
# aiken build --trace-level verbose --trace-filter all

# some random string to make the contracts unique
ran="acab"
ran_cbor=$(python3 -c "import cbor2;encoded = cbor2.dumps(bytes.fromhex('${ran}'));print(encoded.hex())")
rand=$(head /dev/urandom | tr -dc a-f0-9 | head -c 16)
rand_cbor=$(python3 -c "import cbor2; print(cbor2.dumps(bytes.fromhex('${rand}')).hex())")
echo "Random Seed:" ${rand}

# build and apply parameters to each contract
echo -e "\033[1;37m\nBuilding Wallet Contract \033[0m"
aiken blueprint apply -o plutus.json -m wallet "${ran_cbor}"
echo -e "\033[1;37m\nBuilding Wallet Contract\033[0m"
aiken blueprint apply -o plutus.json -m wallet "${rand_cbor}"
aiken blueprint convert -m wallet > contracts/wallet_contract.plutus
cardano-cli conway transaction policyid --script-file contracts/wallet_contract.plutus > hashes/wallet.hash
echo -e "\033[1;33m Wallet Contract Hash: $(cat hashes/wallet.hash) \033[0m"
echo -e "\033[1;33m Wallet Contract Hash: $(cat hashes/wallet.hash)\033[0m"

echo -e "\033[1;37m\nBuilding Seedelf Contract \033[0m"
aiken blueprint apply -o plutus.json -m seedelf "${ran_cbor}"
echo -e "\033[1;37m\nBuilding Seedelf Contract\033[0m"
aiken blueprint apply -o plutus.json -m seedelf "${rand_cbor}"
aiken blueprint convert -m seedelf > contracts/seedelf_contract.plutus
cardano-cli conway transaction policyid --script-file contracts/seedelf_contract.plutus > hashes/seedelf.hash
echo -e "\033[1;33m Seedelf Contract Hash: $(cat hashes/seedelf.hash) \033[0m"
echo -e "\033[1;33m Seedelf Contract Hash: $(cat hashes/seedelf.hash)\033[0m"

echo -e "\033[1;37m\nBuilding Always False Contract \033[0m"
aiken blueprint apply -o plutus.json -m always_false "${ran_cbor}"
echo -e "\033[1;37m\nBuilding Always False Contract\033[0m"
aiken blueprint apply -o plutus.json -m always_false "${rand_cbor}"
aiken blueprint convert -m always_false > contracts/always_false_contract.plutus
cardano-cli conway transaction policyid --script-file contracts/always_false_contract.plutus > hashes/always_false.hash
echo -e "\033[1;33m Always False Contract Hash: $(cat hashes/always_false.hash) \033[0m"
echo -e "\033[1;33m Always False Contract Hash: $(cat hashes/always_false.hash)\033[0m"

# end of build
echo -e "\033[1;32m\nCompiling Complete! \033[0m"
echo -e "\033[1;32m\nComplete!\033[0m"
2 changes: 1 addition & 1 deletion contracts/always_false_contract.plutus
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"type": "PlutusScriptV3",
"description": "Generated by Aiken",
"cborHex": "583d583b010100332323232225333003323232323263009300a0033008002300700230070013004375400229309b2b2b9a5573cae855d126010342acab0001"
"cborHex": "58435841010100332323232225333003323232323263009300a0033008002300700230070013004375400229309b2b2b9a5573cae855d1260109489f758fe61354a4490001"
}
2 changes: 1 addition & 1 deletion contracts/seedelf_contract.plutus
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"type": "PlutusScriptV3",
"description": "Generated by Aiken",
"cborHex": "59024959024601010033232323232323223225333004323232323253330093370e900018051baa00113232323322533300e533300e00214a22002266601ca66601c004200229412825114a06464a66602260280042646464a66602266e3c020dd7180b0020a99980899b8f3337189000240100049101045eed0e1f0013370e90008008a5014a06eb4c054c058008dd7180a000980a0008b1bac30120013001375660226024602460246024601c6ea8018c8c8c8c94ccc04cc0580084c8c8c8c8c94ccc054cdc3a4000602c6ea80044c8c8c8c94ccc064cdc400124100082a66603266e3c04002054ccc064cdc7800803899b87480080185280a5014a06466600266e28cdc52441045eed0e1f0033300100f48001201c337160046eb8c00cc06cdd51801980d9baa00448001203e22233371800466e00cdc0800801240040066eb4c070c074c064dd51800980c9baa0022301c001301a301737540022ca66602e00e2980103d87a800013374a90001980c180c803a5eb80dd6980c180c8019bae3017002375c602c004602c0022c6eb0c050004c00cdd59809980a180a180a180a0011bac3012001300e375400c4646600200200444a666022002297ae01323332223233001001003225333017001100313233019374e660326ea4018cc064c058004cc064c05c0052f5c066006006603600460320026eb8c040004dd5980880099801801980a80118098009bae003375c601c60166ea800458c034c03800cc030008c02c008c02c004c018dd50008a4c26cac6eb80055cd2ab9d5573caae7d5d02ba157449810342acab0001"
"cborHex": "59024b590248010100332323232323232225333003323232323253330083370e900018049baa00113232323322533300d533300d00214a22002266601aa66601a004200229412825114a06464a66602060260042646464a66602066e3c020dd7180a8020a99980819b8f3337189000240100049101045eed0e1f0013370e90008008a5014a06eb4c050c054008dd7180980098098008b1bac30110013001375660206022602260226022601a6ea8018c8c8c8c94ccc048c0540084c8c8c8c8c94ccc050cdc3a4000602a6ea80044c8c8c8c94ccc060cdc400124100082a66603066e3c04002054ccc060cdc7800803899b87480080185280a5014a06466600266e28cdc52441045eed0e1f0033300100f48001201c337160046eb8c00cc068dd51801980d1baa00448001203e22233371800466e00cdc0800801240040066eb4c06cc070c060dd51800980c1baa0022301b0013019301637540022ca66602c00e2980103d87a800013374a90001980b980c003a5eb80dd6980b980c0019bae3016002375c602a004602a0022c6eb0c04c004c00cdd5980918099809980998098011bac3011001300d375400c4646600200200444a666020002297ae01323332223233001001003225333016001100313233018374e660306ea4018cc060c054004cc060c0580052f5c066006006603400460300026eb8c03c004dd5980800099801801980a00118090009bae003375c601a60146ea800458c030c03400cc02c008c028008c028004c014dd50008a4c26cacae6955ceaab9e5573eae815d0aba24c0109489f758fe61354a4490001"
}
2 changes: 1 addition & 1 deletion contracts/wallet_contract.plutus
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"type": "PlutusScriptV3",
"description": "Generated by Aiken",
"cborHex": "5902775902740101003323232323232323223225333004323232323253330093370e900118051baa001132332253323300d3001300e375400426464a66666602c0042a66601e600660206ea80084c94ccc04c0040084c94cccccc06000400c00c00c00c4c8c94ccc0580040144c94cccccc06c0040180180180184c94ccc060c06c00c54ccc054c024c058dd50070991919191919299980f1810801099299980e1919199999911111192999812980c98131baa001132325333027301b30283754002266ee4008cddb1bbb005337706eb4c0b0c0a4dd50009bbb007163008379066e28cdc519b8a007004006003337706eb4c0a8c09cdd50009bbb00616300600323253330205333020337129000000899b880014820a02020383ffffffffef7f97fefe0693ef3aaa02efa21222c39e660ea77f3aa69a77b6f838528099ba548000cc090dd4000a5eb805300103d87a800033794944004dd7180098101baa011375c600460406ea8044dd7180098101baa017375c600460406ea805cdd7180198101baa0172302300123022302300113322323300100100322533302300114a026644a66604466e3c0080145288998020020009bae302500130260013758604260446044604460446044604460446044603c6ea8058dd71800980f1baa01514a046042604460440022c6eb8c07c004c07c008dd7180e800980e8011bae301b0013017375401c2c00e6eb8004c060004c06000cdd7000980a80098089baa00200100100100100114a26024601e6ea8008dc3a40002944c03c004c03cc040004c02cdd50008b1806980700198060011805801180580098031baa00114984d958dd7000ab9a5573aaae7955cfaba05742ae895d226010342acab0001"
"cborHex": "59027959027601010033232323232323232225333003323232323253330083370e900118049baa001132332253323300c3001300d375400c2646464646464a66602a60300042a666024600e60266ea80204c8c94cccccc06c00854ccc050c024c054dd5001099299980c000801099299999980e80080180180180189919299980d8008028992999999810000803003003003099299980e9810001899299980d9919199999911111192999812180c98129baa001132325333026301b30273754002266ee4008cddb1bbb005337706eb4c0acc0a0dd50009bbb007163008379066e28cdc519b8a007004006003337706eb4c0a4c098dd50009bbb006163006003232533301f533301f337129000000899b880014820a02020383ffffffffef7f97fefe0693ef3aaa02efa21222c39e660ea77f3aa69a77b6f838528099ba548000cc08cdd4000a5eb805300103d87a800033794944004dd71800980f9baa00b375c6004603e6ea802cdd71800980f9baa017375c6004603e6ea805cdd71801980f9baa0172302200123021302200113322323300100100322533302200114a026644a66604266e3c0080145288998020020009bae302400130250013758604060426042604260426042604260426042603a6ea8058dd71800980e9baa01514a0460406042604200200e6eb8004c074004c07400cdd7000980d000980b1baa00200100100100100114a2602e60286ea80205288b1bae30160013016002375c602800260280046eb8c048004c038dd50031b874800058c038004c038c03c004c028dd50008b1806180680198058011805001180500098029baa00114984d9595cd2ab9d5573caae7d5d02ba15744ae91300109489f758fe61354a4490001"
}
2 changes: 1 addition & 1 deletion hashes/always_false.hash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0ef52e89a1b563fc09ad23f250fb18bc1a7d00fc5f3c521916a1718d
fd80f72ab30b506e1fc7a7dd20ef820ca67105cd93f18f2292437217
2 changes: 1 addition & 1 deletion hashes/seedelf.hash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
466d8ded60a4b3da10b3e14cb1ccf7c0e9ccb10e2c606ccd9dfae58f
88176fa1b636ef39dd71d83b17fa487942492bb3af99fd375ec71847
2 changes: 1 addition & 1 deletion hashes/wallet.hash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2bee66335d6ccf52fa1775b49dd50f9f3b3345b6cc337e5d4fba7a03
32f95ddceffb5d3c27cfb88be8c8c5e7861234f6db313ef4df785a49
Loading

0 comments on commit 6991ec7

Please sign in to comment.