From a21f7d5a46048cd29c9bc36a930ba5bd8f70a009 Mon Sep 17 00:00:00 2001 From: Parthasarathy Ramanujam <1627026+ch4r10t33r@users.noreply.github.com> Date: Tue, 14 Oct 2025 08:20:54 +0100 Subject: [PATCH] feat: Add semantic versioning and proper export of koalabear fields (#3) * fix: Made Poseidon2KoalaBera const as public and added semantic versioning * fix: Exported the koalabear16 module properly from root.zig * fix: corrected lint errors * fix: corrected error in ci workflow * fix: Corrected the GH workflow to release a verion on the release branch --- .github/workflows/auto-release.yml | 160 +++++++++++++++++++++++++++++ .github/workflows/ci.yml | 2 +- README.md | 50 ++++++++- VERSION | 2 + build.zig | 18 +--- build.zig.zon | 18 ++++ src/instances/koalabear16.zig | 2 +- src/root.zig | 14 +++ 8 files changed, 249 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/auto-release.yml create mode 100644 VERSION create mode 100644 build.zig.zon create mode 100644 src/root.zig diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml new file mode 100644 index 0000000..b8cc4e4 --- /dev/null +++ b/.github/workflows/auto-release.yml @@ -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 "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 968aeba..073bc8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/README.md b/README.md index 75278b1..fb0ac34 100644 --- a/README.md +++ b/README.md @@ -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/.tar.gz", - .hash = "", + .url = "https://github.com/blockblaz/zig-poseidon/archive/v0.2.0.tar.gz", + .hash = "122...", // Get hash by running: zig fetch --save }, }, ``` +**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 @@ -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 diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..5faa42c --- /dev/null +++ b/VERSION @@ -0,0 +1,2 @@ +0.2.0 + diff --git a/build.zig b/build.zig index 8982419..8a5fd05 100644 --- a/build.zig +++ b/build.zig @@ -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(.{ diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..f93c982 --- /dev/null +++ b/build.zig.zon @@ -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", + }, +} + diff --git a/src/instances/koalabear16.zig b/src/instances/koalabear16.zig index 75b9e47..72633b9 100644 --- a/src/instances/koalabear16.zig +++ b/src/instances/koalabear16.zig @@ -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, diff --git a/src/root.zig b/src/root.zig new file mode 100644 index 0000000..ea2a826 --- /dev/null +++ b/src/root.zig @@ -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()); +}