tsslib 0.2.4

Easy-to-use threshold signature schemes (FROST, ML-DSA, DKLs23) — wire- and save-data-compatible with the Go tss-lib.
Documentation
name: Go/Rust interop (ecdsatss)

# Validates that the Rust `ecdsatss` (GG18/GG20) port stays compatible with the
# Go `tss-lib/ecdsatss` reference: fixtures (Paillier/ZK-proof vectors and a real
# 2-party keygen result) are regenerated FROM the Go implementation on each run,
# then the Rust tests consume them — proving the migration path (export a key from
# Go, load it in Rust, and sign).
#
# The Go reference is consumed as a normal published module
# (github.com/KarpelesLab/tss-lib/v2, pinned in fixtures-gen/go.mod); no sibling
# checkout is needed. Bump that version to test against a newer Go release.

on:
  push:
    branches: [master]
    paths:
      - "src/ecdsatss/**"
      - "src/eddsatss/**"
      - "src/dklstss/**"
      - "src/frosttss/**"
      - "fixtures-gen/**"
      - ".github/workflows/interop.yml"
      - "Cargo.toml"
  pull_request:
    paths:
      - "src/ecdsatss/**"
      - "src/eddsatss/**"
      - "src/dklstss/**"
      - "src/frosttss/**"
      - "fixtures-gen/**"
      - ".github/workflows/interop.yml"
      - "Cargo.toml"
  workflow_dispatch:

permissions:
  contents: read

env:
  CARGO_TERM_COLOR: always
  # purecrypto is a git dependency; fetch it via the git CLI for reliable
  # anonymous HTTPS cloning of the public repo.
  CARGO_NET_GIT_FETCH_WITH_CLI: "true"

jobs:
  interop:
    name: Go fixtures -> Rust verify + sign
    runs-on: ubuntu-latest
    timeout-minutes: 40
    steps:
      - uses: actions/checkout@v6

      - name: Install Go
        uses: actions/setup-go@v5
        with:
          go-version: "1.25"

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Rust build
        uses: Swatinem/rust-cache@v2

      # Regenerate every fixture from the pinned Go release (fixtures-gen/go.mod) —
      # including a real in-process 2-party (t=1) Go keygen — overwriting the
      # committed copy.
      - name: Generate fixtures from Go
        working-directory: fixtures-gen
        run: |
          # Emits gg18.json (ecdsatss, to stdout) and, as a side effect,
          # ../src/eddsatss/testdata/eddsa.json (a real 2-party Go EdDSA keygen).
          go run . > ../src/ecdsatss/testdata/gg18.json
          echo "gg18.json:  $(wc -c < ../src/ecdsatss/testdata/gg18.json) bytes"
          echo "eddsa.json: $(wc -c < ../src/eddsatss/testdata/eddsa.json) bytes"
          echo "dkls.json:  $(wc -c < ../src/dklstss/testdata/dkls.json) bytes"
          echo "frost.json: $(wc -c < ../src/frosttss/testdata/frost.json) bytes"

      # Fast Go->Rust proof interop: the Rust verifiers must accept Go-emitted
      # Paillier, DLN, fac, and mod proofs, and load a Go-marshaled Key.
      - name: Rust verifies Go proof + key vectors (ecdsatss)
        run: "cargo test --features ecdsatss ecdsatss:: -- --nocapture"

      # End-to-end migration path: load the REAL Go-generated keys and produce a
      # standard ECDSA signature that verifies under the group public key.
      - name: Rust signs with real Go keys (ecdsatss)
        run: cargo test --features ecdsatss go_keys_sign_and_verify -- --ignored --nocapture

      # eddsatss: load the REAL Go-generated EdDSA keys and produce a standard
      # Ed25519 signature (all eddsatss tests are fast — no safe primes).
      - name: Rust loads Go keys + signs (eddsatss)
        run: "cargo test --features eddsatss eddsatss:: -- --nocapture"

      # dklstss (DKLs23): load a REAL Go-saved key (v4 format incl. structured
      # OT-extension state) and produce an ECDSA signature.
      - name: Rust loads Go keys + signs (dklstss)
        run: "cargo test --features dklstss dklstss::serialize -- --nocapture"

      # frosttss (FROST-Ed25519): load real Go-generated keys, round-trip the
      # save format, and reconstruct the group key from the shares.
      - name: Rust loads + round-trips Go keys (frosttss)
        run: "cargo test --features frosttss frosttss::key -- --nocapture"

      # Surface the regenerated fixture's shape (informational — fixtures use
      # fresh randomness so values differ run-to-run; this just confirms the Go
      # generator still emits every section the Rust tests expect).
      - name: Report regenerated fixture shape
        if: always()
        run: |
          jq 'keys' src/ecdsatss/testdata/gg18.json
          jq '.signing_keys | length' src/ecdsatss/testdata/gg18.json