# Tutorial 2: Private Inputs and Hash Functions

> Guided steps to learn about private inputs, hash functions, and adding a second value as an input.

Canonical URL: https://docs.minaprotocol.com/zkapps/tutorials/private-inputs-hash-functions

In the [Hello World](hello-world) tutorial, you built a basic zkApp smart contract with o1js with a single state variable that could be updated if you knew the square of that number.

In this tutorial, you learn about private inputs and hash functions.

With a zkApp, a smart contract user's local device generates one or more zero knowledge proofs, which are then verified by the Mina network. Each method in a o1js smart contract corresponds to constructing a proof.

All inputs to a smart contract are private by default. Inputs are never seen by the blockchain unless you store those values as on-chain state in the zkApp account.

In this tutorial, you build a smart contract with a piece of private state that can be modified if a user knows the private state.

## Prerequisites

This tutorial has been tested with [o1js](https://www.npmjs.com/package/o1js) version `3.0.0` and [zkApp CLI](https://www.npmjs.com/package/zkapp-cli) version `0.23.0`. o1js 3.0.0 requires Node.js `22.19.5` or later.

Ensure your environment meets the [Prerequisites](/zkapps/tutorials#prerequisites) for zkApp Developer Tutorials.

## Create a project

1. Create or change to a directory where you have write privileges.

1. Create a project by using the `zk project` command:

  ```sh
  $ zk project 02-private-inputs-and-hash-functions --ui none
  ```

  The `zk project` command can also scaffold a UI for your project. This tutorial does not use a UI, so the `--ui none` option skips it. If you do not give the `--ui` option, the command asks you to select a UI type. Select `none`.

  The expected output is:

  ```sh
  ✔ Initialize Git repo
  ✔ Set up project
  ✔ Set project name
  ✔ NPM install
  ✔ NPM build contract
  ✔ Git init commit

  Success!

  Next steps:
    cd 02-private-inputs-and-hash-functions
    git remote add origin <your-repo-url>
    git push -u origin main
  ```

  The `zk project` command creates the `02-private-inputs-and-hash-functions` directory that contains the scaffolding for your project, including tools such as the Prettier code formatting tool and the ESLint static code analysis tool. The `npm test` script uses the Node.js built-in test runner.

1. The zkApp CLI `0.23.0` creates a project for o1js 2. To use o1js 3.0.0, the same as the [example project](https://github.com/MinaProtocol/docs2/tree/main/examples/zkapps/02-private-inputs-and-hash-functions), open `package.json` and change the `o1js` entry in `peerDependencies` from `"^2.*"` to `"^3.0.0"`. Then install it:

  ```sh
  $ cd 02-private-inputs-and-hash-functions
  $ npm install
  ```

1. List the contents of the `02-private-inputs-and-hash-functions` directory:

  ```sh
  $ ls
  ```

  The output shows these results:

  ```sh
  LICENSE
  README.md
  babel.config.cjs
  build
  cache
  config.json
  node_modules
  package-lock.json
  package.json
  scripts
  src
  tsconfig.json
  ```

For this tutorial, you run commands from the root of the `02-private-inputs-and-hash-functions` directory as you work in the `src` directory on files that contain the TypeScript code for the smart contract.

Each time you make updates, then build or deploy, the TypeScript code is compiled into JavaScript in the `build` directory.

### Prepare the project

Start by deleting the default files that come with the new project.

1. To delete the default generated files:

  ```sh
  $ rm src/Add.ts
  $ rm src/Add.test.ts
  $ rm src/AddZkProgram.ts
  $ rm src/interact.ts
  ```

1. Now, create the new files for your project:

  ```sh
  $ zk file src/IncrementSecret
  $ touch src/main.ts
  ```

    - The `zk file` command created the `src/IncrementSecret.ts` file and the `src/IncrementSecret.test.ts` test file.
    - This tutorial does not walk you through writing tests, so you use the `main.ts` file as a script to interact with the smart contract and observe how it works. The finished example project has a test suite; see [Test it](#test-it).

1. Now, open `src/index.ts` in a text editor and change it to look like:

  ```ts title="src/index.ts"
  import { IncrementSecret } from './IncrementSecret.js';

  export { IncrementSecret };
  ```

  The `src/index.ts` file contains all of the exports you want to make available for consumption from outside your smart contract project, such as from a UI.

### Copy the example files

This tutorial relies on the completed code in the [02-private-inputs-and-hash-functions/src/](https://github.com/MinaProtocol/docs2/tree/main/examples/zkapps/02-private-inputs-and-hash-functions/src) example files.

1. First, open the [IncrementSecret.ts](https://github.com/MinaProtocol/docs2/blob/main/examples/zkapps/02-private-inputs-and-hash-functions/src/IncrementSecret.ts) example file.

1. Copy the entire contents of the file into your smart contract in the `IncrementSecret.ts` file.

1. Next, open the [main.ts](https://github.com/MinaProtocol/docs2/blob/main/examples/zkapps/02-private-inputs-and-hash-functions/src/main.ts) example file.

1. Copy the entire contents of the file into your smart contract in the `main.ts` file.

Now you are ready to review the imports in the smart contract.

## Write the smart contract

Now we'll build the smart contract for our application.

### Imports

The `import` statement in the `IncrementSecret.ts` file brings in other packages and dependencies to use in your smart contract.

:::info

All functions used inside a smart contract must operate on o1js compatible data types: `Field` types and other types built on top of `Field` types.

:::

```ts title="src/IncrementSecret.ts"
import { Field, SmartContract, state, State, method, Poseidon } from 'o1js';
```

### Exports

The smart contract called `IncrementSecret` has one element of on-chain state named `x` of type `Field` as defined by following code:

```ts title="src/IncrementSecret.ts"
export class IncrementSecret extends SmartContract {
  @state(Field) x = State<Field>();
```

This code adds the basic structure for the smart contract. You are familiar with the import and export code from [Tutorial 01: Hello World](hello-world).

### Initial State

The `initState()` method is intended to run once to set up the initial state on the zkApp account.

```ts title="src/IncrementSecret.ts"
@method async initState(salt: Field, firstSecret: Field) {
  this.x.set(Poseidon.hash([salt, firstSecret]));
}
```

The `initState()` method accepts your secret and adds a `salt` value.

These inputs to the `initState()` method are private to whoever initializes the contract. The zkApp account on the chain does not reveal what the values `firstSecret` or `salt` actually are.

### Update the State

This method updates the state:

```ts title="src/IncrementSecret.ts"
  @method async incrementSecret(salt: Field, secret: Field) {
    const x = this.x.get();
    this.x.requireEquals(x);

    Poseidon.hash([salt, secret]).assertEquals(x);
    this.x.set(Poseidon.hash([salt, secret.add(1)]));
  }
}
```

Mina uses the Poseidon hash function that is optimized for fast performance inside zero knowledge proof systems. The Poseidon hash function takes in an array of Fields and returns a single Field as output. For more about hash functions in o1js, see [Hashing](https://docs.o1labs.org/o1js/basic-types/hashing) in the o1js documentation.

This smart contract uses a secret number and the second Field, `salt`.

The `incrementSecret()` method checks that the hash of the salt and the secret is equal to the current state `x`:

- If this is the case, add `1` to the secret and set `x` to the hash of the salt and this new secret.
- o1js creates a proof of this fact and a JSON description of the state updates to be made on the zkApp account, such as to store the new hash value.
- Together, this forms a transaction that can be sent to the Mina network to update the zkApp account.

Because zkApp smart contracts are run off chain, your salt and secret remain private and are never transmitted anywhere.

Only the result, updating `x` on-chain state to `hash([ salt, secret + 1])` is revealed. Because the salt and secret can't be deduced from their hash, they remain private.

### About the `salt` argument

Cryptographic salt adds an additional layer of security to a smart contract. The extra `salt` argument prevents a possible attack on the smart contract. If you just use `secret`, the contract is vulnerable to discovery by an attacker. An attacker could try hashing likely secrets and then check if the hash matches the hash stored in the smart contract. If the hash were to match, then the attacker knows they have discovered the secret. This scenario is particularly concerning if the secret is likely to be within a particular subset of possible values, say between 1 and 10,000. In that case, with just 10,000 hashes, the attacker could discover the secret.

Adding salt as a second input to the contract code makes it harder for an attacker to reverse engineer the code and gain access to the contract. Salt makes the contract more secure and helps protect the data stored within it. For optimal security, the salt is known only to you and is typically random.

## Main

The `src/main.ts` file is similar to the Hello World tutorial. For a full version,  see [main.ts](https://github.com/MinaProtocol/docs2/blob/main/examples/zkapps/02-private-inputs-and-hash-functions/src/main.ts).

For this tutorial, the key parts to discuss are initializing our contract and using the poseidon hash.

The salt is a random `Field`:

```ts title="src/main.ts"
const salt = Field.random();
```

The smart contract initialization this time is:

```ts title="src/main.ts"
const deployTxn = await Mina.transaction(deployerAccount, async () => {
  // 1 Mina fee is required to create a new account for the zkApp
  // This line means the deployer account will pay the fee for any account created in this transaction
  AccountUpdate.fundNewAccount(deployerAccount);
  await zkAppInstance.deploy();
  await zkAppInstance.initState(salt, Field(750));
});
await deployTxn.prove();
await deployTxn.sign([deployerKey, zkAppPrivateKey]).send();
```

Note that the `initState()` method accepts the salt and the secret. In this case, the secret is the number `750`.

This code creates a user transaction to update the on-chain state:

```ts title="src/main.ts"
const txn1 = await Mina.transaction(senderAccount, async () => {
  await zkAppInstance.incrementSecret(salt, Field(750));
});
await txn1.prove();
await txn1.sign([senderKey]).send();
```

Call the zkApp smart contract with both the salt and the secret (the number `750`).

Because zkApp smart contracts are executed locally, neither the secret nor the salt are part of the transaction.

Instead, the transaction includes only the proof that the update was called in such a way that all assertions passed and an update to the on-chain state `x` where the hash value is stored. After the transaction is processed by the Mina network, `x` is the value of `Poseidon.hash([ salt, Field(750).add(1) ])`. The underlying salt and secret are not revealed.

Try running `main`:

```sh
$ npm run build && node build/src/main.js
```

The output looks something like this:

```text
state after init: 23550325085366129189717132755196644361022196796445325283916855715034087760727
state after txn1: 3862582281777914218165481333613805684592130064784051986586001318806512141915
```

The `state` strings are different because `Field.random()` generates the salt.

## Test it

The two `state` lines that `main` prints are hashes, and they are different on
each run. You cannot check them by reading them. A test suite can. The example
project in this repository carries one:

```sh
cd examples/zkapps/02-private-inputs-and-hash-functions
npm install
npm test
```

It asserts what this page claims:

- After `initState()`, `x` is `Poseidon.hash([ salt, Field(750) ])`, not `750`
  and not the salt.
- After `incrementSecret(salt, Field(750))`, `x` is
  `Poseidon.hash([ salt, Field(750).add(1) ])`.
- The transaction contains the new value of `x`, but not the salt.
- A wrong secret is **rejected**, and so is the right secret with a wrong
  salt. The state does not change.
- After an increment, the secret is `751`. The old secret `750` is rejected.

The rejections are the point of the contract. A contract that accepted any
secret would still print two hashes and still look like it worked.

## Conclusion

Congratulations! You built a smart contract that uses privacy and hash functions.

To deploy zkApps to a live network, see [Tutorial 3: Deploy to a Live Network](deploying-to-a-network).
