Skip to content

Commit 25d2cfb

Browse files
authored
Merge pull request #540 from o1-labs/300-tuto5
Verify Tutorial 5: Common Types and Functions
2 parents d9a3e11 + 8487c69 commit 25d2cfb

File tree

1 file changed

+61
-49
lines changed

1 file changed

+61
-49
lines changed

docs/zkapps/tutorials/05-common-types-and-functions.mdx

Lines changed: 61 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: 'Tutorial 5: Common Types and Functions'
33
hide_title: true
44
sidebar_label: 'Tutorial 5: Common Types and Functions'
5-
description: Higher-order types are built from Fields and are useful for your development. Learn how to create custom types.
5+
description: Higher-order types are built from Fields. Create custom types to build your own strings. Create compound data types with the Struct.
66
keywords:
77
- smart contracts
88
- zkapps
@@ -14,6 +14,10 @@ keywords:
1414
- zk
1515
- blockchain
1616
- mina
17+
- custom types
18+
- basic types
19+
- circuits
20+
- struct
1721
---
1822

1923
import ResponsiveVideo from '@site/src/components/common/ResponsiveVideo';
@@ -24,35 +28,36 @@ zkApp programmability is not yet available on the Mina Mainnet. You can get star
2428

2529
:::
2630

27-
:::note
2831

29-
This tutorial was last tested with [SnarkyJS](https://www.npmjs.com/package/snarkyjs) 0.8.0.
32+
# Tutorial 5: Common Types and Functions
3033

31-
:::
34+
In previous tutorials, you learned how to deploy smart contracts to the network interact with them from a React UI and NodeJS.
3235

33-
# Tutorial 5: Common Types and Functions
36+
In this tutorial, you learn about types you can use when building with SnarkyJS. Earlier tutorials mostly use the `Field` type. SnarkyJS provides other higher-order types built from Fields that are useful for zkApp development and expand the possibilities for more applications.
3437

35-
In previous tutorials, we've seen how to deploy smart contracts to the network, and we've interacted with them from both a React UI and NodeJS.
38+
All types are defined in the [SnarkyJS / Modules / Types](/zkapps/snarkyjs-reference/modules/Types) API reference documentation.
3639

37-
In this tutorial, we will talk about more types that are useful when building with SnarkyJS, so you can build more applications. So far, we've mostly been using the `Field` type. SnarkyJS provides other higher-order types built from Fields, that will be useful for your development.
40+
The [example project](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src) includes a [main.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/main.ts) file that shows all of the concepts presented in this tutorial, along with smart contracts showing more advanced usage of some of the concepts, particularly Merkle Trees.
3841

39-
You can find all of these on the [SnarkyJS Reference page](../snarkyjs-reference), for their full API documentation.
42+
## Prerequisites
4043

41-
There is also a project [here](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src), with a [main.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/main.ts) demoing the concepts presented in this tutorial, along with smart contracts showing more advanced usage of some of the concepts, particularly Merkle Trees.
44+
This tutorial has been verified with [Mina zkApp CLI](https://github.com/o1-labs/zkapp-cli) version `0.11.0` and [SnarkyJS](https://www.npmjs.com/package/snarkyjs) `0.12.1`.
45+
46+
Ensure your environment meets the [Prerequisites](/zkapps/tutorials#prerequisites) for zkApp Developer Tutorials.
4247

4348
## Basic Types
4449

45-
To start, we'll discuss 5 basic types derived from the Fields:
50+
Five basic types are derived from Fields:
4651

4752
- [Bool](../snarkyjs-reference/classes/Bool)
4853
- [UInt32](../snarkyjs-reference/classes/UInt32)
4954
- [UInt64](../snarkyjs-reference/classes/UInt64)
5055
- [Int64](../snarkyjs-reference/classes/Int64)
5156
- [Character](../snarkyjs-reference/classes/Character)
5257

53-
These each have their usual programming language semantics.
58+
Each type has the usual programming language semantics.
5459

55-
For example, we can have the following code:
60+
For example, the following code:
5661

5762
```ts
5863
const num1 = UInt32.from(40);
@@ -84,7 +89,7 @@ console.log(`char1 === char2: ${char1EqualsChar2.toString()}`);
8489
console.log(`Fields in char1: ${char1.toFields().length}`);
8590
```
8691

87-
And when run it'll print to the console:
92+
This result prints to the console when the code is run:
8893

8994
```
9095
num1 === num2: true
@@ -98,20 +103,20 @@ Fields in char1: 1
98103

99104
## More Advanced Types
100105

101-
4 more advanced types are:
106+
Four advanced types are:
102107

103108
- [CircuitString](../snarkyjs-reference/classes/CircuitString)
104109
- [PrivateKey](../snarkyjs-reference/classes/PrivateKey)
105110
- [PublicKey](../snarkyjs-reference/classes/Types.PublicKey)
106111
- [Signature](../snarkyjs-reference/classes/Signature)
107112

108-
All arguments passed into smart contracts need to be arguments SnarkyJS can understand. This means that we can't just pass normal strings - we need to pass in strings that have been wrapped to be compatible with circuits, which is what `Struct` accomplishes.
113+
All arguments passed into smart contracts must be arguments SnarkyJS can consume. You cannot pass normal strings. Instead, you must pass in strings that are wrapped to be compatible with circuits. This is accomplished with `Struct`.
109114

110-
One special thing to note, is that the default `CircuitString` has a max length of 128 characters. This is because, under the hood, SnarkyJS types have to be fixed length. However, the `CircuitString` API abstracts this away and can be used like a dynamic length string, with the only caveat being the max length.
115+
The default `CircuitString` has a maximum length of 128 characters because SnarkyJS types must be fixed length. However, the `CircuitString` API abstracts this restriction away and can be used like a dynamic length string with the maximum length caveat.
111116

112-
We'll see in the following section how to create custom types, where you could for example build your own strings, modified to whatever length you would like.
117+
You can create custom types to build your own strings, modified to whatever length you want.
113118

114-
A brief example of using these:
119+
A brief example of custom types:
115120

116121
```ts
117122
const str1 = CircuitString.fromString('abc..xyz');
@@ -156,19 +161,21 @@ signature verified for data2: true
156161
Fields in signature: 256
157162
```
158163

159-
Small but important note: Make sure that you never use the private key above (or any private key that's publicly accessible) in a real application!
164+
Observe and follow best practices for your key security. Make sure that you never use the private key in this example output, or any private key that's publicly accessible, in a real application.
160165

161-
If you're curious why there are 255 Fields in a private key and 256 in a signature - the reason for this is cryptographic in nature: Elliptic curve scalars are most efficiently represented in a SNARK as an array of bits, and the bit length of these scalars happens to be 255.
166+
There are 255 Fields in a private key and 256 Fields in a signature. If you are curious about the reason for this, the answer is cryptographic in nature: Elliptic curve scalars are most efficiently represented in a SNARK as an array of bits, and the bit length of these scalars is 255.
162167

163168
## Struct
164169

165-
A special type is [Struct](../snarkyjs-reference#struct), which lets you create your own compound data types.
170+
You can create your own compound data types with the special [Struct](../snarkyjs-reference#struct) type.
171+
172+
Define a Struct as one or more data types that SnarkyJS understands. For example, Field, higher-order types built into SnarkyJS based on Field, or other Struct types defined by you. You can also define methods on your Struct to act upon this data type.
166173

167-
Your Struct can be defined as one or more data types that SnarkyJS understands, i.e. Field, higher-order types built into SnarkyJS based on Field, or other Struct types defined by you. You can also define methods on your Struct to act upon this data type, if desired, but doing so is optional.
174+
The following example demonstrates how to use `Struct` to implement a `Point` structure and an array of points of length 8 structure.
168175

169-
See the following for an example of how to use `Struct`, implementing a `Point` structure, and an array of points of length 8 structure.
176+
In SnarkyJS, programs are compiled into fixed-sized circuits. This means that data structures it consumes must also be a fixed size.
170177

171-
SnarkyJS compiles programs into fixed sized circuits. This means that data structures it consumes must also be a fixed size, and is why we declare the array in `Points8` structure to be a static size of 8 in the example below.
178+
To meet the fixed-size requirement, this code declares the array in `Points8` structure to be a static size of 8.
172179

173180
```ts
174181
class Point extends Struct({ x: Field, y: Field }) {
@@ -196,23 +203,24 @@ const points8: Points8 = { points };
196203
console.log(`points8 JSON: ${JSON.stringify(points8)}`);
197204
```
198205

199-
Which prints the following to the console:
206+
The console output:
200207

201208
```
202209
pointSum Fields: 11,6
203210
points8 Fields: {"points":[{"x":"0","y":"0"},{"x":"1","y":"10"},{"x":"2","y":"20"},{"x":"3","y":"30"},{"x":"4","y":"40"},{"x":"5","y":"50"},{"x":"6","y":"60"},{"x":"7","y":"70"}]}
204211
```
205212

206-
## Control flow
213+
## Control Flow
207214

208-
There are two functions which help do control flow within SnarkyJS:
215+
Two functions help do control flow in SnarkyJS:
209216

210217
- [Provable.if](../snarkyjs-reference/classes/Circuit#if)
211-
- [Provable.switch](../snarkyjs-reference/classes/Circuit#switch)
218+
Similar to a ternary in JavaScript
212219

213-
`Provable.if` is similar to a ternary in JavaScript. `Provable.switch` is similar to a switch case statement in JavaScript.
220+
- [Provable.switch](../snarkyjs-reference/classes/Circuit#switch)
221+
Similar to a switch case statement in JavaScript
214222

215-
With these, you can write conditionals inside SnarkyJS.
223+
You can write conditionals inside SnarkyJS with these functions.
216224

217225
For example:
218226

@@ -263,30 +271,30 @@ inputSumAbs: 5
263271
largest: 22
264272
```
265273

266-
Note that when using `Provable.if`, like in a JS ternary, both branches are executed. Unlike normal programming, because SnarkyJS under the hood is creating a zk circuit, there is no primitive for if statements where only one branch is executed.
274+
Both branches are executed when using `Provable.if`, like in a JavaScript ternary. Because SnarkyJS is creating a zk circuit, there is no primitive for `if` statements where only one branch is executed.
267275

268276
## Assertions and Constraints
269277

270278
SnarkyJS functions are compiled to generate circuits.
271279

272-
When a transaction is proven in SnarkyJS, SnarkyJS is proving that the program logic is computed according to the written program, and all assertions are holding true.
280+
When a transaction is proven in SnarkyJS, the proof is that the program logic is computed according to the written program, and all assertions are holding true.
273281

274-
We've seen assertions already, with `a.assertEquals(b)`, which we've often used. There is also `.assertTrue()` available on the Bool class.
282+
In previous tutorials, you learned `a.assertEquals(b)`. The `.assertTrue()` is available on the Bool class.
275283

276-
Circuits in SnarkyJS currently have a fixed maximum size. Each operation performed in a function counts towards this maximum size. This maximum size is currently equivalent to the following:
284+
Circuits in SnarkyJS have a fixed maximum size. Each operation performed in a function counts towards this maximum size. This maximum size is equivalent to:
277285

278286
- about 5,200 hashes on two fields
279287
- about 2,600 hashes on four fields
280288
- about `2^17` field multiplies
281289
- about `2^17` field additions
282290

283-
If a program is too large to fit into these constraints, it can be broken up into multiple recursive proof verifications. See more on how to do this in the section [here](../snarkyjs/recursion).
291+
If a program is too large to fit into these constraints, it can be broken up into multiple recursive proof verifications. See [Recursion](../snarkyjs/recursion).
284292

285293
## Merkle Trees
286294

287-
Lastly, let's go over an example using [merkle trees](../snarkyjs-reference/classes/MerkleTree). Merkle trees are very powerful, since they let us manage large amounts of data within a circuit. In the [project corresponding to this tutorial](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src), you can find a full reference for the example here. The contract can be found in [BasicMerkleTreeContract.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/BasicMerkleTreeContract.ts), and the example can be found in a section of [main.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/main.ts).
295+
You can use [Merkle trees](../snarkyjs-reference/classes/MerkleTree) to manage large amounts of data within a circuit. The power of Merkle trees is demonstrated in the [05-common-types-and-functions/src](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src) reference project for this tutorial. See the [BasicMerkleTreeContract.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/BasicMerkleTreeContract.ts) contract and [main.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/main.ts) that demonstrates how contracts interact with Merkle trees and how to construct them.
288296

289-
Start off by importing `MerkleTree`:
297+
The first step is to import `MerkleTree`:
290298

291299
```ts
292300
import {
@@ -296,18 +304,20 @@ import {
296304
} from 'snarkyjs'
297305
```
298306

299-
Merkle Trees can be created in your application like so:
307+
To create Merkle trees in your application:
300308

301309
```ts
302310
const height = 20;
303311
const tree = new MerkleTree(height);
304312
```
305313

306-
The height variable determines how many leaves are available to your application. A height of 20 for example will lead to a tree with `2^(20-1)`, or 524,288 leaves.
314+
The height variable determines how many leaves are available to the application. For example, a height of 20 leads to a tree with `2^(20-1)`, or 524,288 leaves.
307315

308-
Merkle trees in smart contracts are stored as the hash of the merkle tree's root. Smart contract methods which update the merkle root can take a "witness" of the change as an argument, which represents the merkle path to the data for which inclusion is being proved.
316+
Merkle trees in smart contracts are stored as the hash of the Merkle tree's root. Smart contract methods that update the Merkle root can take a _witness_ of the change as an argument. The [MerkleMapWitness](/zkapps/snarkyjs-reference/classes/MerkleMapWitness) represents the Merkle path to the data for which inclusion is being proved.
309317

310-
Here is a simple example of a contract that stores the root of a merkle tree, where each leaf stores a number, and the smart contract has an `update` function that adds a number to the leaf. As an example of putting a condition on a leaf update, the `update` function checks that the number added was less than 10.
318+
A contract stores the root of a Merkle tree, where each leaf stores a number, and the smart contract has an `update` function that adds a number to the leaf.
319+
320+
For example, to put a condition on a leaf update, the `update` function checks that the number added was less than 10:
311321

312322
```ts
313323
...
@@ -341,7 +351,7 @@ Here is a simple example of a contract that stores the root of a merkle tree, wh
341351
}
342352
```
343353

344-
And code to interact with it:
354+
The code to interact with the smart contract:
345355

346356
```ts
347357
// initialize the zkapp
@@ -401,13 +411,15 @@ console.log(
401411
);
402412
```
403413

404-
While in this example leaves are fields, you can put more variables in a leaf by instead hashing an array of fields, and setting a leaf to that.
414+
In this example, leaves are fields. However, you can put more variables in a leaf by hashing an array of fields and setting a leaf to that hash.
415+
416+
This complete example is in the [project directory](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src).
405417

406-
You can find this complete example in the [project directory](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src), as well as a more advanced example `LedgerContract`, which implements a basic ledger of tokens, including checks that the sender has signed their transaction and that the amount the sender has sent matches the amount the receiver receives.
418+
A more advanced example `LedgerContract` implements a basic ledger of tokens, including checks that the sender has signed their transaction and that the amount the sender has sent matches the amount the receiver receives.
407419

408420
## Merkle Map
409421

410-
Lastly, let's go over an example using [merkle maps](../snarkyjs-reference/classes/MerkleMap). These allow us to implement key value stores.
422+
See the API reference documentation for the [MerkleMap](../snarkyjs-reference/classes/MerkleMap) class you can use to implement key-value stores.
411423

412424
The API for Merkle Maps is similar to Merkle Trees, just instead of using an index to set a leaf, one uses a key:
413425

@@ -462,7 +474,7 @@ It can be used inside smart contracts with a witness, similar to merkle trees
462474
}
463475
```
464476

465-
With (abbreviated) code to interact with it, similar to the merkle tree example above:
477+
With (abbreviated) code to interact with it, similar to the Merkle tree example above:
466478

467479
```ts
468480
const map = new MerkleMap();
@@ -487,16 +499,16 @@ const txn1 = await Mina.transaction(deployerAccount, () => {
487499
...
488500
```
489501

490-
MerkleMaps can be used to implement many useful patterns. For example:
502+
You use [MerkleMaps](/zkapps/snarkyjs-reference/classes/MerkleMap) to implement many useful patterns. For example:
491503

492504
- A key value store from public keys to booleans, of token accounts to whether they've participated in a voted yet.
493505
- A nullifier that privately tracks if an input was used, without revealing it.
494506

495507
## Conclusion
496508

497-
Congrats! We have finished reviewing more common types and functions in SnarkyJS. With this, you should now be capable of writing many advanced smart contracts and zkApps.
509+
Congratulations! You have finished reviewing more common types and functions in SnarkyJS. With this, you should now be capable of writing many advanced smart contracts and zkApps.
498510

499-
Checkout [Tutorial 6](offchain-storage) to learn how to use off-chain storage, to use more data from your zkApp.
511+
To use more data from your zkApp, check out [Tutorial 6](offchain-storage) to learn how to use off-chain storage.
500512

501513
## Other Resources
502514

0 commit comments

Comments
 (0)