Skip to content

nixprotocol/poseidon2-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

poseidon2-go

Pure-Go implementation of the Poseidon2 hash function over the BN254 scalar field.

This is the first standalone Poseidon2 implementation in Go. It produces identical outputs to Noir's standard library (Barretenberg), @zkpassport/poseidon2, and poseidon2-evm.

Parameters

Parameter Value
Field BN254 Fr (p = 21888...95617)
State width (t) 4
Full rounds (rf) 8 (4 + 4)
Partial rounds (rp) 56
S-box x^5
Rate 3
Capacity 1

Installation

go get github.com/nixprotocol/poseidon2-go

Usage

package main

import (
    "fmt"

    "github.com/consensys/gnark-crypto/ecc/bn254/fr"
    poseidon2 "github.com/nixprotocol/poseidon2-go"
)

func main() {
    // Hash two field elements (Merkle tree node, commitment, etc.)
    var a, b fr.Element
    a.SetUint64(1)
    b.SetUint64(2)
    digest := poseidon2.Hash2(a, b)
    fmt.Printf("Hash2(1, 2) = %s\n", digest.String())

    // Hash arbitrary number of field elements
    inputs := []fr.Element{a, b}
    digest = poseidon2.Hash(inputs)

    // Get 32-byte output
    bytes := poseidon2.HashToBytes(inputs)
    fmt.Printf("bytes = %x\n", bytes)
}

API

// Hash computes Poseidon2 sponge hash over arbitrary-length inputs.
func Hash(inputs []fr.Element) fr.Element

// Hash2 hashes exactly 2 field elements.
func Hash2(a, b fr.Element) fr.Element

// HashToBytes computes Hash and returns the result as 32 bytes (big-endian).
func HashToBytes(inputs []fr.Element) [32]byte

// Permute applies the raw Poseidon2 permutation on a 4-element state.
func Permute(s *[4]fr.Element)

Field Range

All inputs and outputs are BN254 scalar field elements, valid in the range [0, p) where:

p = 21888242871839275222246405745257275088548364400416034343698204186575808495617

This is approximately 254 bits (not a full 256-bit integer range). Values set via SetBytes() or SetBigInt() that exceed p are automatically reduced modulo p by gnark-crypto. This is standard behavior across all Poseidon2 implementations in every ZK ecosystem (Noir, Solidity, Rust, TypeScript).

Sponge Construction

The sponge uses the FieldSponge mode matching Noir/Barretenberg:

  • IV: len(inputs) << 64, placed in state[3] (capacity element)
  • Absorption: into state[0..2] (rate = 3), permuting when full
  • Squeeze: state[0] after final permutation
  • No padding marker (fixed-length mode)

Cross-Implementation Compatibility

All test vectors are verified against:

  • Noir stdlib (Barretenberg) - Aztec's ZK prover
  • @zkpassport/poseidon2 - TypeScript reference
  • Poseidon2.sol - Ethereum Solidity implementation

Round Constants

Round constants are sourced from poseidon2-evm, which uses the same constants as Aztec's Barretenberg prover. These are the standard BN254 Poseidon2 constants used across the ZK ecosystem.

Dependencies

Only one external dependency:

Benchmarks

Run benchmarks:

go test -bench=. -benchmem

License

Apache 2.0 - See LICENSE.

Author

NixProtocol (GitHub)

About

Pure-Go Poseidon2 hash over BN254. First standalone Go implementation. Matches Noir stdlib, Barretenberg, and poseidon2-evm.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages