Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions .github/workflows/auto-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
name: Auto Release on Release Branch

on:
pull_request:
types: [closed]
branches:
- release

permissions:
contents: write

jobs:
auto-release:
# Only run if PR was merged to release branch (not just closed)
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for versioning

- name: Setup Zig
uses: goto-bus-stop/setup-zig@v2
with:
version: 0.14.1

- name: Read VERSION file
id: get_version
run: |
VERSION=$(cat VERSION)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "tag=v$VERSION" >> $GITHUB_OUTPUT

- name: Check if tag exists
id: check_tag
run: |
if git rev-parse "v${{ steps.get_version.outputs.version }}" >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "⚠️ Tag v${{ steps.get_version.outputs.version }} already exists"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "✅ Tag v${{ steps.get_version.outputs.version }} does not exist"
fi

- name: Run tests
if: steps.check_tag.outputs.exists == 'false'
run: zig build test

- name: Build library
if: steps.check_tag.outputs.exists == 'false'
run: zig build

- name: Update build.zig.zon version
if: steps.check_tag.outputs.exists == 'false'
run: |
VERSION="${{ steps.get_version.outputs.version }}"
sed -i "s/\.version = \".*\"/\.version = \"$VERSION\"/" build.zig.zon

- name: Generate changelog
if: steps.check_tag.outputs.exists == 'false'
id: changelog
run: |
VERSION="${{ steps.get_version.outputs.version }}"

# Get previous tag
PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")

if [ -z "$PREV_TAG" ]; then
echo "## 🎉 Initial Release" > CHANGELOG.md
echo "" >> CHANGELOG.md
echo "First release of zig-poseidon - A Zig implementation of Poseidon2 hash function." >> CHANGELOG.md
echo "" >> CHANGELOG.md
echo "### Features" >> CHANGELOG.md
echo "- BabyBear field (p = 2³¹ - 2²⁷ + 1) for Ethereum Lean chain" >> CHANGELOG.md
echo "- KoalaBear field (p = 2³¹ - 2²⁴ + 1) for plonky3 and Rust hash-sig compatibility" >> CHANGELOG.md
echo "- Generic Montgomery form implementation" >> CHANGELOG.md
echo "- Compression mode for Merkle Trees" >> CHANGELOG.md
echo "- Comprehensive test suite" >> CHANGELOG.md
else
echo "## Changes since $PREV_TAG" > CHANGELOG.md
echo "" >> CHANGELOG.md
git log "$PREV_TAG"..HEAD --pretty=format:"- %s (%h)" >> CHANGELOG.md
fi

cat CHANGELOG.md

- name: Create Git tag
if: steps.check_tag.outputs.exists == 'false'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "${{ steps.get_version.outputs.tag }}" -m "Release ${{ steps.get_version.outputs.tag }}"
git push origin "${{ steps.get_version.outputs.tag }}"

- name: Create GitHub Release
if: steps.check_tag.outputs.exists == 'false'
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.get_version.outputs.tag }}
name: Release ${{ steps.get_version.outputs.tag }}
body_path: CHANGELOG.md
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Calculate tarball hash
if: steps.check_tag.outputs.exists == 'false'
id: tarball_hash
run: |
VERSION="${{ steps.get_version.outputs.version }}"
TARBALL_URL="https://github.com/${{ github.repository }}/archive/v${VERSION}.tar.gz"

# Download and calculate hash
curl -L "$TARBALL_URL" -o release.tar.gz
HASH=$(zig fetch release.tar.gz 2>&1 | grep -o '12[0-9a-f]*' || echo "")

if [ -z "$HASH" ]; then
echo "⚠️ Could not calculate hash automatically"
echo "📦 Users can get the hash by running:"
echo " zig fetch --save $TARBALL_URL"
else
echo "hash=$HASH" >> $GITHUB_OUTPUT
echo "📦 Tarball hash: $HASH"
fi

- name: Post release information
if: steps.check_tag.outputs.exists == 'false'
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🎉 Release ${{ steps.get_version.outputs.tag }} created successfully!"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "📦 To use this release in your project's build.zig.zon:"
echo ""
echo ".dependencies = .{"
echo " .poseidon = .{"
echo " .url = \"https://github.com/${{ github.repository }}/archive/${{ steps.get_version.outputs.tag }}.tar.gz\","
echo " .hash = \"${{ steps.tarball_hash.outputs.hash }}\","
echo " },"
echo "},"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

- name: Skip release (tag exists)
if: steps.check_tag.outputs.exists == 'true'
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "⚠️ Skipping release - tag ${{ steps.get_version.outputs.tag }} already exists"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "To create a new release:"
echo "1. Update the VERSION file with a new version number"
echo "2. Commit the change"
echo "3. Create and merge a PR"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
zig-version: 0.14.0

- name: Lint
run: zig fmt --check src/*.zig
run: zig fmt --check src/

test:
runs-on: ubuntu-latest
Expand Down
50 changes: 48 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,19 @@ Add `zig-poseidon` as a dependency in your `build.zig.zon`:
```zig
.dependencies = .{
.poseidon = .{
.url = "https://github.com/jsign/zig-poseidon/archive/<commit-hash>.tar.gz",
.hash = "<hash>",
.url = "https://github.com/blockblaz/zig-poseidon/archive/v0.2.0.tar.gz",
.hash = "122...", // Get hash by running: zig fetch --save <url>
},
},
```

**Get the correct hash:**
```bash
zig fetch --save https://github.com/blockblaz/zig-poseidon/archive/v0.2.0.tar.gz
```

**Latest version:** See [Releases](https://github.com/blockblaz/zig-poseidon/releases) for the most recent version.

## Usage

### Using BabyBear16
Expand Down Expand Up @@ -150,6 +157,45 @@ Both implementations include tests ensuring the naive and optimized (Montgomery)
- Add benchmarks and performance optimizations
- Add more S-Box degrees as needed

## Versioning and Releases

This project follows [Semantic Versioning](https://semver.org/).

**Current version:** `0.2.0`

### Release Process

Releases are automatically created when Pull Requests from `main` are merged to the `release` branch:

1. Develop and merge features to `main` branch
2. When ready to release, update the `VERSION` file on `main`
3. Create a PR from `main` to `release` branch
4. After merge to `release`, the workflow automatically:
- Creates a Git tag (e.g., `v0.2.0`)
- Generates a changelog
- Creates a GitHub Release
- Calculates the tarball hash for dependencies

**Why a release branch?**
- ✅ Control when releases happen
- ✅ Not every feature triggers a release
- ✅ Batch multiple features into one release

See [RELEASING.md](RELEASING.md) for detailed release instructions.

### Using Specific Versions

Always pin to a specific version in your `build.zig.zon`:

```zig
.poseidon = .{
.url = "https://github.com/blockblaz/zig-poseidon/archive/v0.2.0.tar.gz",
.hash = "122...", // specific hash for v0.2.0
},
```

**Find releases:** [GitHub Releases](https://github.com/blockblaz/zig-poseidon/releases)

## License

MIT
Expand Down
2 changes: 2 additions & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
0.2.0

18 changes: 5 additions & 13 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,11 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

// Generic Poseidon2 module
_ = b.addModule("poseidon2", .{
.root_source_file = b.path("src/poseidon2/poseidon2.zig"),
});

// BabyBear16 instance
_ = b.addModule("babybear16", .{
.root_source_file = b.path("src/instances/babybear16.zig"),
});

// KoalaBear16 instance (compatible with Rust hash-sig)
_ = b.addModule("koalabear16", .{
.root_source_file = b.path("src/instances/koalabear16.zig"),
// Main module - exports everything
_ = b.addModule("poseidon", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});

const lib = b.addStaticLibrary(.{
Expand Down
18 changes: 18 additions & 0 deletions build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.{
.name = .zig_poseidon,
.version = "0.2.0",
.fingerprint = 0x4cb45c65d8967708,
.minimum_zig_version = "0.14.0",

.dependencies = .{},

.paths = .{
"build.zig",
"build.zig.zon",
"src",
"README.md",
"LICENSE",
"VERSION",
},
}

2 changes: 1 addition & 1 deletion src/instances/koalabear16.zig
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const DIAGONAL = [WIDTH]u32{
parseHex("7fffff7f"), // -1/2^24
};

const Poseidon2KoalaBear = poseidon2.Poseidon2(
pub const Poseidon2KoalaBear = poseidon2.Poseidon2(
koalabear,
WIDTH,
INTERNAL_ROUNDS,
Expand Down
14 changes: 14 additions & 0 deletions src/root.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Root module for zig-poseidon
// Re-exports all components

pub const babybear16 = @import("instances/babybear16.zig");
pub const koalabear16 = @import("instances/koalabear16.zig");
pub const poseidon2 = @import("poseidon2/poseidon2.zig");

// Convenience type exports
pub const Poseidon2BabyBear = babybear16.Poseidon2BabyBear;
pub const Poseidon2KoalaBear = koalabear16.Poseidon2KoalaBear;

test {
@import("std").testing.refAllDecls(@This());
}
Loading