Nim / C implementations of arithmetic hash functions over the Goldilocks field

Experimental implementation of arithmetic hash functions (like for example Poseidon2) specialized to the Goldilocks field p = 2^64 - 2^32 + 1. Mostly uses C implementations internally.

Hash functions supported

[x] Poseidon2 (t=12) [ ] Monolith (t=12) [ ] Tip4' (t=12) [ ] Tip5 (t=16)

The Poseidon2 implementation is compatible with Horizen Lab's one at 4. The Monolith implementation is compatible with 6.

Installation

Use the Nimble package manager to add goldilocks_hash to an existing project. Add the following to its .nimble file:

requires "goldilocks_hash >= 0.0.1 & < 1.0.0"

Conventions

Hash digests consist of 4 field elements (approximately 256 bits).

When constructing binary Merkle trees, we similarly work on units of 4 field elements. We use a custom ``safe'' Merkle tree building convention, which ensures that different inputs can never produce the same Merkle root (except with negligible probability).

When hashing bytes, first we pad the byte sequence to a multiple of 31 bytes using the 10* padding strategy, and then we convert each 31 byte piece into 4 field elements by using the lowest 62 bits. We do this for two reasons: 1) to be a drop-in replacement for the BN254 implementation which also takes 31 bytes at a time; and 2) because hashing 31/62 bytes with one permutation is almost 11% more efficient than using only 28/56 bytes at a time.

When hashing field elements, similarly we pad using the 10* strategy. Domain separation ensures that using different sponge rates, or different types of input don't produce the same hash.

Usage

Hashing bytes into with the sponge construction:

import goldilocks_hash/poseidon2

let input = [1'u8, 2'u8, 3'u8]                 # some bytes that you want to hash
let digest: Digest = Sponge.digest(input) 

Converting a hash digest (4 field elements) into bytes:

let output: array[32, byte] = digest.toBytes

Combining field elements, useful for constructing a binary Merkle tree:

let left  = Sponge.digest( [1'u8, 2'u8, 3'u8] )
let right = Sponge.digest( [4'u8, 5'u8, 6'u8] )
let combination = compress(left, right)

Building Merkle trees:

let input: seq[Digest] = ...
let digest: F = Merkle.digest(input) 
Description
Arithmetic hash functions (Poseidon2 etc) over the Goldilocks field
Readme
Languages
Nim 92.2%
Haskell 4.4%
C 2.2%
C++ 0.7%
POV-Ray SDL 0.5%