Skip to content

Commit

Permalink
crypto: poseidon2: Define huff structure and implement simple sbox (#3)
Browse files Browse the repository at this point in the history
* forge install: foundry-huff

* crypto: poseidon2: roundUtils: Define huff structure and add sbox
  • Loading branch information
joeykraut authored Jan 25, 2025
1 parent f2ae760 commit 9b851fa
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 61 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: true

name: Foundry project
name: Foundry checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -41,5 +41,5 @@ jobs:

- name: Run Forge tests
run: |
forge test -vvv
forge test --ffi -vvv
id: test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Workspace
.vscode

# Compiler files
cache/
out/
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/foundry-huff"]
path = lib/foundry-huff
url = https://github.com/huff-language/foundry-huff
5 changes: 3 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[profile.default]
solc_version = "0.8.20"
evm_version = "cancun"
src = "src"
out = "out"
libs = ["lib"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
remappings = ["forge-std/=lib/forge-std/src/"]
1 change: 1 addition & 0 deletions lib/foundry-huff
Submodule foundry-huff added at 7d1ce1
5 changes: 5 additions & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src/
foundry-huff/=lib/foundry-huff/src/
solidity-stringutils/=lib/foundry-huff/lib/solidity-stringutils/
stringutils/=lib/foundry-huff/lib/solidity-stringutils/
19 changes: 0 additions & 19 deletions script/Counter.s.sol

This file was deleted.

14 changes: 0 additions & 14 deletions src/Counter.sol

This file was deleted.

9 changes: 9 additions & 0 deletions src/crypto/poseidon2/main.huff
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/// @title Poseidon2
/// @author @joeykraut
/// @notice A Poseidon2 implementation in Huff. See https://eprint.iacr.org/2023/323
/// for more details. Inspired by https://github.com/zemse/poseidon2-evm/tree/main

#define macro MAIN() = takes(0) returns(0) {
}


30 changes: 30 additions & 0 deletions src/crypto/poseidon2/roundUtils.huff
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/// Helpers for Poseidon2 round functions

/// @dev The scalar field modulus of BN254
#define constant PRIME = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001

/// @dev Push the prime onto the stack
#define macro PUSH_PRIME() = {
[PRIME]
}

/// @dev Apply the sbox function to the element on top of the stack,
/// which is replaced by its fifth power mod p
/// I.e. transforms the stack [x, ...] -> [x^5 mod p, ...]
#define macro SBOX() = takes(2) returns(1) {
// Takes [x, PRIME]
// Prelude: setup primes on the stack in the order they'll be used
dup2 dup1 // [PRIME, PRIME, x, PRIME]
dup3 // [x, PRIME, PRIME, x, PRIME]
dup1 // [x, x, PRIME, PRIME, x, PRIME]

// Compute x^2 (mod p)
mulmod // [x^2 mod p, PRIME, x, PRIME]

// Compute x^4 (mod p)
dup1 // [x^2 mod p, x^2 mod p, PRIME, x, PRIME]
mulmod // [x^4 mod p, x, PRIME]

// Compute x^5 (mod p)
mulmod // [x^5 mod p]
}
24 changes: 0 additions & 24 deletions test/Counter.t.sol

This file was deleted.

35 changes: 35 additions & 0 deletions test/Poseidon.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {Test} from "forge-std/Test.sol";
import {console} from "forge-std/console.sol";
import {HuffDeployer} from "foundry-huff/HuffDeployer.sol";

contract PoseidonTest is Test {
/// @dev The Poseidon main contract
PoseidonSuite public poseidonSuite;

/// @dev The BN254 field modulus from roundUtils.huff
uint256 PRIME = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001;

/// @dev Deploy the PoseidonSuite contract
function setUp() public {
poseidonSuite = PoseidonSuite(HuffDeployer.deploy("../test/huff/testPoseidonUtils"));
}

/// @dev Test the sbox function applied to a single input
function testSboxSingle() public {
uint256 testValue = vm.randomUint();
uint256 result = poseidonSuite.testSboxSingle(testValue);

// Calculate expected x^5 mod p
uint256 x2 = mulmod(testValue, testValue, PRIME);
uint256 x4 = mulmod(x2, x2, PRIME);
uint256 expected = mulmod(testValue, x4, PRIME);
assertEq(result, expected, "Expected result to match x^5 mod p");
}
}

interface PoseidonSuite {
function testSboxSingle(uint256) external returns (uint256);
}
36 changes: 36 additions & 0 deletions test/huff/testPoseidonUtils.huff
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/// @title Test Poseidon Utils
/// @author @joeykraut
/// @notice Test the utils for the Poseidon2 permutation

#include "../../src/crypto/poseidon2/roundUtils.huff"

/// @dev Test the sbox function applied to a single input
#define function testSboxSingle(uint256) nonpayable returns(uint256)

/// @dev Entrypoint to the poseidon test suite
#define macro MAIN() = takes(0) returns(0) {
// Get the function selector
0x0 calldataload 0xe0 shr // [SELECTOR]
__FUNC_SIG(testSboxSingle) eq testSboxSingle jumpi

// Revert if the function selector is not valid
0x1 0x0 mstore
0x1 0x0 revert

testSboxSingle:
TEST_SBOX_SINGLE()
}

/// @notice Test the sbox function applied to a single input
#define macro TEST_SBOX_SINGLE() = takes(0) returns(0) {
// Get the input from calldata
PUSH_PRIME()
0x04 calldataload

// Call the sbox function
SBOX()

// Return the result
0x00 mstore
0x20 0x00 return
}

0 comments on commit 9b851fa

Please sign in to comment.