Skip to content

Commit

Permalink
Merge pull request #784 from o1-labs/feature/ecdsa-keccak-overview
Browse files Browse the repository at this point in the history
Keccak overview
  • Loading branch information
barriebyron authored Dec 15, 2023
2 parents 483ec87 + d2c09bc commit 9206173
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 0 deletions.
167 changes: 167 additions & 0 deletions docs/zkapps/o1js/keccak.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
title: Keccak
hide_title: true
description: A comprehensive guide on how to use Keccak-based hashes in o1js.
keywords:
- keccak
- sha3
- hash
- ethereum
- mina blockchain
- blockchain technology
- data structures
---

:::info

Please note that zkApp programmability is not yet available on Mina Mainnet, but zkApps can now be deployed to Berkeley Testnet.

:::

# Keccak (SHA-3)

Keccak is a flexible cryptographic hash function that provides more security than traditional SHA hash algorithms.

## What is Keccak?

Developed by a team of cryptographers from Belgium, Keccak was the winning submission for the National Institute of Standards and Technology (NIST) SHA-3 competition. Keccak was standardized as SHA-3. Keccak is used in many different applications, including Ethereum.

Specifically, Keccak is used in the Ethereum ecosystem to hash addresses, transactions, and blocks. It is also used to hash the state trie, the data structure that stores the state of the Ethereum blockchain.
Because of the common usage of Keccak in Ethereum, it is a key component of o1js that you can use to verify Ethereum transactions and blocks in o1js.

## Keccak and Poseidon

As an o1js developer, you are likely familar with the [Poseidon](https://o1-labs.github.io/proof-systems/specs/poseidon.html) zero knowledge native hash function. Poseidon operates over the native [Pallas base field](https://electriccoin.co/blog/the-pasta-curves-for-halo-2-and-beyond/) and uses parameters generated specifically for Mina which makes Poseidon the most efficient hash function available in o1js.

In contrast, Keccak is a hash function that requires binary arithmetic. It operates over binary data and is not native to most zero knowledge proofs. For this reason, Keccak is not as efficient as Poseidon, but it is still very useful for verifying Ethereum transactions and blocks.
So, when you choose what hash function to use, it is important to consider the use case and the data that needs to be hashed.

## Basic usage

Keccak is available in the following configurations that are available under the `Hash` namespace in o1js:

- `Hash.SHA3_256`: NIST SHA3 hash function with output size of 256 bits.
- `Hash.SHA3_385`: NIST SHA3 hash function with output size of 384 bits.
- `Hash.SHA3_512`: NIST SHA3 hash function with output size of 512 bits.
- `Hash.Keccak256`: pre-NIST Keccak hash function with output size of 256 bits. _This configuration used to hash blocks, transactions, and more in Ethereum._
- `Hash.Keccak384`: pre-NIST Keccak hash function with output size of 384 bits.
- `Hash.Keccak512`: pre-NIST Keccak hash function with output size of 512 bits.

Because Keccak operates over binary data instead of native Field elements like Poseidon, o1js uses the `Bytes` type. `Bytes` is a fixed-length array of bytes that can be used to represent binary data.
Under the hood, `Bytes` is represented as an array of `UInt8` elements.

In order to use `Bytes`, you need to extend the `Bytes` class and specify the length of bytes:

```ts
// This creates a Bytes class that represents 16 bytes
class Bytes16 extends Bytes(16) {}
```

To initiate your `Bytes16` class with a value, you can use `from`, `fromHex`, or `fromString`.

```ts
// `.from` accepts an array of `number`, `bigint`, `UInt8` elements or a `Uint8Array` or `Bytes`
let bytes = Bytes16.from(new Array(16).fill(0));

// converts a hex string to bytes
bytes = Bytes16.fromHex('646f67');

// converts a string to bytes
bytes = Bytes16.fromString('dog');

// print the contents of `bytes` to the console
bytes.bytes.forEach((b) => console.log(b.toBigInt()));
// [100n, 111n, 103n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n]
```

:::note
If the input array is smaller than the length of the `Bytes` class, it will be padded with zeros.
:::

You can also convert a `Bytes` object back to a hex string using `toHex`.

```ts
class Bytes3 extends Bytes(3) {}

let bytes = Bytes3.fromHex('646f67');
let hex = bytes.toHex();
console.log('hex', hex);
// 646f67
```

Now that you know how to use `Bytes` as input, you can use it to hash data using Keccak:

```ts
// define a preimage
let preimage = 'The quick brown fox jumps over the lazy dog';

// create a Bytes class that represents 43 bytes
class Bytes43 extends Bytes(43) {}

// convert the preimage to bytes
let preimageBytes = Bytes43.fromString(preimage);

// hash the preimage
let hash = Hash.SHA3_256.hash(preimageBytes);

console.log(hash.toHex());
//69070dda01975c8c120c3aada1b282394e7f032fa9cf32f4cb2259a0897dfc04
```

See the o1js repository for an [example](https://github.com/o1-labs/o1js/tree/main/src/examples/zkapps/hashing) of how to use Keccak.

### Bytes - API reference

```ts
// creates a Bytes class that represents n bytes (n is 32 in this example)
let n = 32;
class BytesN extends Bytes(n) {}

// initiate an instance from a hex string
let bytes = BytesN.fromHex('646f67');

// initiate an instance from a string
bytes = BytesN.fromString('dog');

// initiate an instance from an array of numbers
bytes = BytesN.from([100, 111, 103]);

// initiate an instance from an array of bigints
bytes = BytesN.from([100n, 111n, 103n]);

// initiate an instance from an array of UInt8 elements
bytes = BytesN.from([UInt8(100), UInt8(111), UInt8(103)]);

// initiate an instance from a Uint8Array
bytes = BytesN.from(new Uint8Array([100, 111, 103]));

// initiate an instance from another Bytes instance
bytes = BytesN.from(BytesN.fromHex('646f67'));

// convert the bytes to a hex string
const hex = bytes.toHex();
```

### Keccak - API reference

```ts
// https://keccak.team/keccak.html hash function, pre-NIST specification
// hash bytes using Keccak256 with output size of 256 bits, mainly used in Ethereum
Hash.Keccak256.hash(bytes);

// hash bytes using Keccak384 with output size of 384 bits
Hash.Keccak384.hash(bytes);

// hash bytes using Keccak512 with output size of 512 bits
Keccak.Keccak512.hash(bytes);

// https://csrc.nist.gov/pubs/fips/202/final hash function, official NIST specification
// hash bytes using SHA3_256 with output size of 256 bits
Hash.SHA3_256.hash(bytes);

// hash bytes using SHA3_384 with output size of 384 bits
Hash.SHA3_384.hash(bytes);

// hash bytes using SHA3_512 with output size of 512 bits
Hash.SHA3_512.hash(bytes);
```
1 change: 1 addition & 0 deletions sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ module.exports = {
'zkapps/o1js/merkle-tree',
'zkapps/o1js/permissions',
'zkapps/o1js/time-locked-accounts',
'zkapps/o1js/keccak',
],
},
{
Expand Down

2 comments on commit 9206173

@vercel
Copy link

@vercel vercel bot commented on 9206173 Dec 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs2 – ./

docs2-git-main-minadocs.vercel.app
docs2-minadocs.vercel.app
docs.minaprotocol.com

@vercel
Copy link

@vercel vercel bot commented on 9206173 Dec 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

07-oracles – ./examples/zkapps/07-oracles/oracle

07-oracles-minadocs.vercel.app
07-oracles-git-main-minadocs.vercel.app
07-oracles.vercel.app

Please sign in to comment.