# PoC

What will all this look like in the first version?

Description of initial PoC version that will be deployed to testnet only.

### Id and secrets <a href="#pdf-page-hry3fqldkhqwfukb7hwt-id-and-secrets" id="pdf-page-hry3fqldkhqwfukb7hwt-id-and-secrets"></a>

In order to deposit any funds to the Shielder some on-chain transaction must be sent. Thus we assume that a user already has some native account with a corresponding private key (essentially, some 32 random bytes). For the sake of simplicity, we use this key as the user ID in the Shielder system. Note that there are no checks performed relating to the corresponding on-chain account - essentially, you can use arbitrary 32 bytes.

All other (operational) secrets, namely nullifiers and trapdoors, are generated as the Keccak256 hash of `id || nonce || label`, where:

* `id` is the private key, as stated above
* `nonce` is the counter of how many Shielder operations have been already done using `id`
* `label` is a byte string, either `b"nullifier"` or `b"trapdoor"`

### Account <a href="#pdf-page-hry3fqldkhqwfukb7hwt-account" id="pdf-page-hry3fqldkhqwfukb7hwt-account"></a>

In the PoC version, for the sake of simplicity, we only allow for shielding native AZERO tokens. Therefore, the only information (apart from operational secrets) kept in a note is the current shielded AZERO balance.

### Recovery and account tracking <a href="#pdf-page-hry3fqldkhqwfukb7hwt-recovery-and-account-tracking" id="pdf-page-hry3fqldkhqwfukb7hwt-recovery-and-account-tracking"></a>

If you lose your shielded state (e.g., due to losing your device or accidentally deleting the state file), you can still recover your funds as long as you have your ID.

All Shielder transactions share a common property - every such action *invalidates some nullifier*. For deposits and withdrawals we just publish the hash of the nullifier of our current note. For the new-account action, we publish the hash of our ID, which can be seen as a special *pre-nullifier*. Shielder contract maintains a registry of all used (hashes of) nullifiers to prevent double spending or creating multiple accounts for the same ID. This is implemented as a mapping from a used nullifier hash to a block number when it was published.

Thanks to this design we can easily derive a recovery procedure as follows. Starting with a nonce 0, we repeatedly ask the contract whether a corresponding nullifier has already been spent, and if so, we can fetch the proper block, find our transaction and update the local state.

This also helps with account tracking. Since a user can interact with the Shielder from many different devices, we must always ensure, that the local state is up-to-date. Therefore, anytime our app is turned on, we check if the nullifier for the current note has been already spent. If so, then we just have to fetch latest transactions and update the state.

### Relations <a href="#pdf-page-hry3fqldkhqwfukb7hwt-relations" id="pdf-page-hry3fqldkhqwfukb7hwt-relations"></a>

#### Preliminaries / Recap <a href="#pdf-page-hry3fqldkhqwfukb7hwt-preliminaries-recap" id="pdf-page-hry3fqldkhqwfukb7hwt-preliminaries-recap"></a>

`Scalar` is a type for some fixed finite field elements.

`hash` function is a hashing function from a sequence of `Scalar` elements into a single `Scalar` value.

`AMOUNT_BOUND` is some limit on the amounts handled by the Shielder, so that arithmetic operations do not overflow in the field. E.g. 2^128

`MERKLE_HEIGHT` is the height of the Merkle tree kept in the contract.

`MERKLE_ARITY` is the arity of the Merkle tree kept in the contract.

#### New Account <a href="#pdf-page-hry3fqldkhqwfukb7hwt-new-account" id="pdf-page-hry3fqldkhqwfukb7hwt-new-account"></a>

```rust
relation PoC::NewAccount

inputs:
    - h_note:          Scalar
    - h_id:            Scalar
    - initial_deposit: Scalar

witnesses:
    - id:        Scalar
    - nullifier: Scalar
    - trapdoor:  Scalar

assumptions:
    - initial_deposit <= AMOUNT_BOUND

constraints:
    // id is correctly exposed as a public input
    - h_id = hash(id)
    // note is well-formed
    - h_note = hash(id, nullifier, trapdoor, hash(initial_deposit))
    
suggestions:
    - nullifier = hash(id, 0, 0)
    - trapdoor  = hash(id, 0, 1)
```

<figure><img src="https://open.gitbook.com/~gitbook/image?url=https%3A%2F%2F1927958252-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FjxGnEsASyxizmuYQHzry%252Fuploads%252FHIt1skIB5detXl55RhLu%252Fnew-account.svg%3Falt%3Dmedia%26token%3D938127a1-be84-47dd-9fc7-4507d85ebf48&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=b9e1e093&#x26;sv=2" alt=""><figcaption></figcaption></figure>

#### Deposit <a href="#pdf-page-hry3fqldkhqwfukb7hwt-deposit" id="pdf-page-hry3fqldkhqwfukb7hwt-deposit"></a>

```rust
relation PoC::Deposit

inputs:
    - merkle_root:     Scalar
    - h_nullifier_old: Scalar
    - h_note_new:      Scalar
    - value:           Scalar

witnesses:
    - id:                  Scalar
    - nullifier_old:       Scalar
    - trapdoor_old:        Scalar
    - account_balance_old: Scalar
    - merkle_path:         [[Scalar; MERKLE_ARITY]; MERKLE_HEIGHT]
    - nullifier_new:       Scalar
    - trapdoor_new:        Scalar

assumptions:
    - value <= AMOUNT_BOUND
    - account_balance_old <= AMOUNT_BOUND

constraints:
    // new value satisfies the bound
    - account_balance_old + value <= AMOUNT_BOUND
    // old nullifier is correctly exposed as a public input
    - h_nullifier_old = hash(nullifier_old)
    // new note is well-formed
    - h_note_new = hash(id, nullifier_new, trapdoor_new, hash(account_balance_old + value))
    // membership proof is valid
    - merkle_path is a valid path to merkle_root
    // membership proof relates to the old note
    - hash(id, nullifier_old, trapdoor_old, account_balance_old) is belongs to the first layer of merkle_path
    

suggestions:
    - nullifier_old = hash(id, n, 0)
    - nullifier_new = hash(id, n+1, 0)
    - trapdoor_old = hash(id, n, 1)
    - trapdoor_new = hash(id, n+1, 1)
```

<figure><img src="https://open.gitbook.com/~gitbook/image?url=https%3A%2F%2F1927958252-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FjxGnEsASyxizmuYQHzry%252Fuploads%252FajJNkqmodCpQJiTS5sAh%252Fdeposit.svg%3Falt%3Dmedia%26token%3D7aac2d5b-26ce-4852-8138-46f70d401ec6&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=4c9711f8&#x26;sv=2" alt=""><figcaption></figcaption></figure>

#### Withdraw <a href="#pdf-page-hry3fqldkhqwfukb7hwt-withdraw" id="pdf-page-hry3fqldkhqwfukb7hwt-withdraw"></a>

```rust
relation PoC::Withdraw

inputs:
    - merkle_root:        Scalar
    - h_nullifier_old:    Scalar
    - h_note_new:         Scalar
    - value:              Scalar
    - relayer:            Scalar
    - fee:                Scalar
    - withdrawal_address: Scalar

witnesses:
    - id:                  Scalar
    - nullifier_old:       Scalar
    - trapdoor_old:        Scalar
    - account_balance_old: Scalar
    - merkle_path:         [[Scalar; MERKLE_ARITY]; MERKLE_HEIGHT]
    - nullifier_new:       Scalar
    - trapdoor_new:        Scalar

assumptions:
    - value <= AMOUNT_BOUND
    - fee <= AMOUNT_BOUND
    - account_balance_old <= AMOUNT_BOUND

constraints:
    // new value satisfies the bound
    - account_balance_old >= value + fee
    // old nullifier is correctly exposed as a public input
    - h_nullifier_old = hash(nullifier_old)
    // new note is well-formed
    - h_note_new = hash(id, nullifier_new, trapdoor_new, hash(account_balance_old - value - fee))
    // membership proof is valid
    - merkle_path is a valid path to merkle_root
    // membership proof relates to the old note
    - hash(id, nullifier_old, trapdoor_old, account_balance_old) is belongs to the first layer of merkle_path
    

suggestions:
    - nullifier_old = hash(id, n, 0)
    - nullifier_new = hash(id, n+1, 0)
    - trapdoor_old = hash(id, n, 1)
    - trapdoor_new = hash(id, n+1, 1)
```

<br>

<figure><img src="https://open.gitbook.com/~gitbook/image?url=https%3A%2F%2F1927958252-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FjxGnEsASyxizmuYQHzry%252Fuploads%252FpOQy5vkMrb5NcrUTnJnu%252Fwithdraw.svg%3Falt%3Dmedia%26token%3D842345aa-0a38-4242-879a-c567c7e797d7&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=9b6c68b7&#x26;sv=2" alt=""><figcaption></figcaption></figure>
