# Code signing and notarisation for MoonBite releases Status: playbook, 2026-10-10. Companion to `deploy/RELEASE-SIGNING.md` (the minisign machinery already wired into the publish scripts), `docs/AV-FALSE-POSITIVE-PLAYBOOK.md` (what to do when scanners flag the miner), `docs/REPRODUCIBLE-BUILDS.md`, `release/miner/ANTIVIRUS.md`, and the verifier scripts `scripts/release/verify-release.sh` / `scripts/release/Verify-Release.ps1`. MoonBite Labs publishes a CPU RandomX miner, a node (`moonbited`) and a desktop wallet. The operator is pseudonymous. Every platform's "trusted publisher" system ties trust to a verified legal identity, so this document separates **what a pseudonymous publisher can do today** from **what needs a legal entity**, with the current rules and prices cited. This is factual background, not legal or tax advice. Forming an entity has jurisdiction-specific consequences; check them before acting. --- ## 1. Windows: Authenticode ### 1.1 What Authenticode buys and what it does not A signed PE file lets Windows show a **publisher name** instead of "Unknown publisher", and lets SmartScreen attach reputation to the certificate instead of to each file hash. It does **not** make a file trusted on day one, and it does **not** stop antivirus engines classifying a miner as `PUA` / `CoinMiner` (see the AV playbook). Microsoft's own guidance, updated May 2026: - SmartScreen evaluates two signals: publisher reputation (is it signed, by a known certificate?) and file-hash reputation (has this exact file been downloaded without signs of malice?). "Even when signed, a newly created binary could still show a SmartScreen warning until its hash or publisher certificate accumulates sufficient evidence of positive reputation." - Unsigned files start from zero reputation on every release. Signed files let reputation carry across versions "signed using the same publisher identity". - **EV certificates no longer bypass SmartScreen.** Microsoft: "Paying a premium for EV solely to avoid SmartScreen warnings is no longer justified." - There is "no need (or mechanism) to manually submit a file for SmartScreen reputation review for consumer endpoints. Reputation builds organically through download volume" - "several weeks and hundreds of clean installs". - Do not sign PUA-like software: the certificate "may develop negative reputation". For a miner this is a real risk, which is why build hygiene (no persistence, no silent install, clear UI) matters before signing. Source: https://learn.microsoft.com/en-us/windows/apps/package-and-deploy/smartscreen-reputation ### 1.2 Certificate routes and their identity requirements | Route | Identity required | Key storage | Cost (indicative, 2026) | Pseudonymous operator? | |---|---|---|---|---| | OV code-signing cert from a public CA (Sectigo, DigiCert, SSL.com, Certum, GlobalSign) | Organisation validation: registered legal entity, verifiable address and phone; some CAs sell OV to **individuals** against a government photo ID (name appears as publisher) | Since **1 June 2023** the CA/Browser Forum requires the private key on FIPS 140-2 L2 / CC EAL4+ hardware (USB token or cloud HSM) for **both OV and EV** | roughly USD 65-440 per year depending on CA; token or cloud-HSM fee often extra | No. Publisher field = legal name of entity or person | | EV code-signing cert | Stricter organisation vetting (legal existence, operational history, signed agreement); not issued to individuals | Hardware as above | typically USD 250-700 per year | No. And no SmartScreen head-start any more | | Azure **Artifact Signing** (renamed from Trusted Signing, Jan 2026) | Microsoft identity validation. Public Trust certs: organisations in US, Canada, EU, UK, Australia, New Zealand, Japan, South Korea, Singapore, Switzerland, Norway, Israel; **individual developers only in US or Canada**, validated via government photo ID + selfie (AU10TIX / Entra Verified ID) with legal name and address taken from the Azure billing account. During the 2025 preview Microsoft additionally required "3 years or more of verifiable history" for organisations; the current quickstart no longer states that, but expect public-record checks (business registration, domain invoice) | Cloud HSM, keys never leave Azure; short-lived certs; integrates with signtool and GitHub Actions | from USD 9.99 per month (Basic) | No. Certificate subject is the validated legal name | | **SignPath Foundation** (free OSS signing) | No personal ID check in the usual CA sense, but: OSI licence with no commercial dual-licensing, team must own and maintain the repo, MFA for all members, defined author/reviewer/approver roles, manual approval per release, an initial "project reputation and control" check, and SignPath "decides whether to accept or reject". **Publisher name on the certificate is "SignPath Foundation", not the project.** Terms exclude malware and "potentially unwanted programs"; cryptominers are not named, but a miner is commonly classified as PUA, so acceptance is uncertain | SignPath HSM | free | **Partly.** Maintainer need not disclose a legal name, but acceptance for a miner is not assured; apply at https://signpath.org/apply.html | | Self-signed certificate | none | any | free | Yes, but Microsoft: "Same behavior as no signature". Useless for trust | | Microsoft Store | Partner Center account (individual or company; identity and payment verification) | Microsoft re-signs | USD 19 individual / 99 company one-off (historic figures; check Partner Center) | No for pseudonymity; and a background CPU miner is unlikely to pass Store policy | Sources: - CA/B Forum June 2023 key-protection change: https://venafi.com/blog/new-ca-b-forum-requirements-for-code-signing-start-in-june-will-you-be-ready and https://www.encryptionconsulting.com/understanding-the-ca-browser-forum-code-signing-requirements/ - Azure Artifact Signing quickstart (eligibility note, individual validation flow): https://learn.microsoft.com/en-us/azure/trusted-signing/quickstart (canonical: https://learn.microsoft.com/en-us/azure/artifact-signing/quickstart) - April 2025 restriction announcement (3-year history): https://techcommunity.microsoft.com/blog/microsoftsecurityandcompliance/-/4273554 - Artifact Signing pricing: https://azure.microsoft.com/pricing/details/artifact-signing/ - SignPath Foundation terms: https://signpath.org/terms - Indicative OV pricing (reseller pages, verify before buying): https://sslinsights.com/digicert-vs-sectigo-code-signing/ and https://gabrielmoraru.com/obtaining-cheap-ev-ov-certificates-singing-your-application/ ### 1.3 Practical reading for MoonBite Nothing on Windows gives a pseudonymous publisher a trusted-publisher string. The realistic Windows options are, in order: 1. Ship unsigned but **verifiable** (SHA-256 + minisign + GitHub attestation, section 4), be explicit on the download page that SmartScreen will say "Unknown publisher", and let hash reputation build per release. 2. Apply to **SignPath Foundation**. If accepted, Windows shows "SignPath Foundation" as publisher and reputation accrues to that certificate. Be candid in the application that the product is a CPU miner that only runs when the user starts it, with no persistence. 3. Form an entity (section 5) and use **Azure Artifact Signing** (cheapest managed route, no hardware token) or an OV certificate from a public CA. --- ## 2. macOS: Developer ID and notarisation - Since macOS 10.15, software distributed outside the App Store must be signed with a **Developer ID Application** certificate and **notarised** or Gatekeeper blocks it with "cannot be opened because the developer cannot be verified". Users can bypass this (right-click Open, or `xattr -dr com.apple.quarantine`, which `/mine` already documents), but every bypass is friction and a support cost. - Developer ID certificates come only from the **Apple Developer Program**, USD 99 per year. Enrolment is as an **individual** (government photo ID verification, legal name becomes the signing identity) or as an **organisation** (must be a legal entity - "DBAs, fictitious businesses, trade names, and branches are not accepted" - with a **D-U-N-S number** registered to that entity, and the enroller must have authority to bind it). Forum reports through 2026 show individual ID verification can stall for weeks. - Notarisation itself is automated: `xcrun notarytool submit --apple-id ... --team-id ... --password ` (or an App Store Connect API key for CI), then `xcrun stapler staple`. Hardened Runtime and a secure timestamp are required. Notarisation is a malware scan, not a review; a CPU miner is not automatically rejected, but Apple can revoke a Developer ID later. - The name on the certificate is the enrolled legal name or organisation. There is no anonymous Developer ID. Sources: - Apple enrolment (individual vs organisation): https://developer.apple.com/support/compare-memberships/ - D-U-N-S requirement: https://developer.apple.com/support/D-U-N-S/ - Notarisation requirements and tooling (third-party summary): https://www.electron.build/docs/notarization - Whether CLI tools need notarising (background): https://eclecticlight.co/2023/02/17/should-apps-and-command-tools-be-notarized/ Practical reading: macOS signing requires either the operator's real name or an entity. Until one exists, ship macOS tarballs unsigned, keep the quarantine-removal instructions, and make the SHA-256 / minisign check the primary trust step. --- ## 3. Linux Linux has no platform gatekeeper. Trust comes from: - **Checksums + a detached signature.** MoonBite uses **minisign** (Ed25519, single small key, no web of trust). GPG is the distro convention but has a larger key-management surface; minisign is what `deploy/publish-node-binaries.sh` already calls. Runbook in section 6. - **Sigstore / cosign keyless** signing: `cosign sign-blob --bundle .sigstore.json ` binds the artefact to an OIDC identity (for GitHub Actions, the workflow identity `https://moonbite.org/git/moonbite-network.yml@refs/tags/`), recorded in the public Rekor transparency log. Verification must pin the identity: `cosign verify-blob --bundle .sigstore.json --certificate-identity --certificate-oidc-issuer https://token.actions.githubusercontent.com `. - **GitHub artifact attestations**: `actions/attest-build-provenance` in the release workflow produces a SLSA provenance attestation stored by GitHub; anyone verifies with `gh attestation verify --repo moonbitecoin/moonbite-network` (`--owner moonbitecoin` is looser; `--repo` is preferred). This proves "built by this repository's CI from this commit", which is exactly the claim a pseudonymous project can make honestly. - **Reproducible builds** (`docs/REPRODUCIBLE-BUILDS.md`): anyone rebuilding the tagged commit gets the same hash, so independent parties can confirm the release without trusting the signer at all. Sources: - `gh attestation verify` manual: https://cli.github.com/manual/gh_attestation_verify - cosign keyless concepts and pinning (beginner guide): https://code.mendhak.com/understanding-sigstore-cosign-as-a-beginner/ - minisign: https://jedisct1.github.io/minisign/ --- ## 4. Decision matrix for a pseudonymous operator | Capability | Possible today without a legal identity | Requires a legal entity (or real-name individual enrolment) | |---|---|---| | SHA-256 manifest for every release (`SHA256SUMS.txt`) | Yes | - | | minisign signature on the manifest (`SHA256SUMS.txt.minisig`), public key published in repo, site and DNS | Yes | - | | GitHub build-provenance attestation + `gh attestation verify` | Yes (needs the release built in GitHub Actions, not on a laptop) | - | | Sigstore cosign keyless bundle per artefact | Yes (identity = the CI workflow, not a person) | - | | Reproducible build instructions and third-party rebuild confirmations | Yes | - | | VirusTotal pre-scan + vendor false-positive submissions (AV playbook) | Yes (submissions accept any contact email) | - | | Windows publisher name instead of "Unknown publisher" | Only via SignPath Foundation (publisher shows "SignPath Foundation"; acceptance for a miner not assured) | OV cert or Azure Artifact Signing in the entity's name | | SmartScreen reputation carrying across releases | No (unsigned: resets per hash) | Yes, once signed consistently | | macOS Developer ID + notarisation (no Gatekeeper warning) | No | Yes: Apple Developer Program, USD 99/yr, individual (real name) or organisation (D-U-N-S) | | Microsoft Store / Mac App Store listing | No | Yes, and Store policy may still reject a miner | ### 4.1 Entity routes commonly used by small software publishers Factual summary only; costs and disclosure rules change and differ by jurisdiction. The point of an entity here is that the **entity** is the publisher of record on the certificate, while the operator's name appears only in registry filings (public in some jurisdictions, private or agent-shielded in others). - **US single-member LLC** (commonly Wyoming, New Mexico, Delaware). Formation roughly USD 50-300 plus a registered agent (roughly USD 50-150/yr). Some states do not publish member names; a registered agent provides the public address. An EIN is free from the IRS. Needed for: OV cert, Azure Artifact Signing (US-based organisation; new entities may face the "verifiable history" bar), Apple organisation enrolment (needs a D-U-N-S number, free from Dun and Bradstreet, up to 5 business days). - **UK Ltd**: Companies House incorporation GBP 50; director names and a service address are public; a correspondence address can be used instead of home. Eligible for Azure Artifact Signing (UK is listed) and OV certs. - **EU single-member company** (for example Estonian OU via e-Residency): EU is in the Artifact Signing list; registry data is public. - Beneficial-ownership reporting regimes (US CTA as currently applied, UK PSC register, EU UBO registers) may require filing the owner's identity with the state even where the public registry does not show it. The cheapest working stack once an entity exists is: entity + domain in the entity's name + Azure Artifact Signing (USD 9.99/mo, no token) for Windows, and Apple Developer Program (USD 99/yr) for macOS. Total under USD 300/yr before formation costs. --- ## 5. What MoonBite does now (policy) 1. Every release is built by GitHub Actions from a signed tag, with `actions/attest-build-provenance` enabled. 2. Every release ships `SHA256SUMS.txt` and `SHA256SUMS.txt.minisig`. 3. The minisign public key is published in three independent places (section 6.5). 4. The download pages state plainly that Windows and macOS builds are unsigned, what the OS will say, and how to verify instead. 5. The wallet never bundles the miner; the website never mines in the browser. This keeps the wallet's own reputation clean and gives AV vendors a narrow, honest story for the miner. 6. If SignPath Foundation accepts the project, Windows miner and wallet builds are signed there. If an entity is formed later, switch to Artifact Signing and Developer ID and announce the publisher name on the site and in an ADR. --- ## 6. Runbooks All commands are POSIX shell; on Windows use Git Bash or WSL. The key file names match `deploy/RELEASE-SIGNING.md` and `deploy/publish-node-binaries.sh`. ### 6.1 Generate the minisign key (offline, air-gapped, two copies) Do this once, on a machine that is not connected to any network and will not be again until the key material is off it. 1. Prepare the offline machine: a live Linux USB (for example Tails or a plain Debian live image) on a laptop with Wi-Fi disabled in firmware or the card removed; no Ethernet cable. Bring `minisign` in as a static binary you verified on an online machine (`sha256sum` against the project release page https://github.com/jedisct1/minisign/releases) on a freshly formatted USB stick. 2. Generate: ```sh mkdir -p /tmp/mb-key && cd /tmp/mb-key minisign -G -p moonbite-release.pub -s moonbite-release.key # choose a long passphrase; it is what protects the key at rest cat moonbite-release.pub # untrusted comment: minisign public key XXXXXXXXXXXXXXXX # RWQ... <- this line is the public key ``` 3. Record the **key ID** (the hex after "public key") and the full `RWQ...` line by hand on paper. Also sign a test file and verify it before leaving the room: ```sh echo moonbite > t && minisign -Sm t -s moonbite-release.key && minisign -Vm t -p moonbite-release.pub ``` 4. Make **two** copies of `moonbite-release.key` on two separate, new, encrypted USB sticks (LUKS or VeraCrypt, different passphrase from the key passphrase). Label them A and B. Store them in two different physical locations. Store the passphrases separately from the sticks (paper in a sealed envelope, or a password manager that is itself backed up offline). 5. Copy only `moonbite-release.pub` to the online world. Wipe `/tmp/mb-key` (live images lose it on reboot; reboot anyway). Never let `moonbite-release.key` touch a networked disk, a cloud sync folder, a screenshot, or a chat. 6. Confirm `*.key` is git-ignored: `git check-ignore -v moonbite-release.key`. For day-to-day signing, you may keep **one** working copy of the key on an encrypted volume on the release machine (the signing step in `deploy/publish-node-binaries.sh` expects it there). If that machine is ever suspected compromised, rotate (6.4). ### 6.2 Sign a release Prerequisites: the GitHub Actions release workflow has produced the artefacts and attestations; you have downloaded them to a clean directory. ```sh cd release-vX.Y.Z/ # 1. Independent re-hash. Must match what CI printed in the workflow log. sha256sum moonbite-miner-*.tar.gz moonbite-miner-*.zip moonbite-wallet*.exe > SHA256SUMS.txt diff <(sort SHA256SUMS.txt) <(sort SHA256SUMS.ci.txt) # CI's copy; must be empty # 2. Provenance check before you put your signature on it. for f in moonbite-miner-*.tar.gz moonbite-miner-*.zip moonbite-wallet*.exe; do gh attestation verify "$f" --repo moonbitecoin/moonbite-network || exit 1 done # 3. Sign the manifest (trusted comment is signed; include version and date). minisign -Sm SHA256SUMS.txt -s /path/to/moonbite-release.key \ -t "MoonBite release vX.Y.Z $(date -u +%F) https://moonbite.org/mine" # 4. Verify with the PUBLISHED key, not the local file. curl -fsSL https://moonbite.org/.well-known/moonbite-release.pub -o pub.verify minisign -Vm SHA256SUMS.txt -p pub.verify # 5. Attach to the GitHub release and stage on the site. gh release upload vX.Y.Z SHA256SUMS.txt SHA256SUMS.txt.minisig ``` Then run `scripts/release/verify-release.sh vX.Y.Z` (and `Verify-Release.ps1` on a Windows VM) exactly as a user would, from a machine that never saw the private key. Only after that passes do the download buttons on `/mine` and `/get-wallet` go live (`build-windows-bundle.py --stage` refuses to stage an unsigned bundle once a key is configured). ### 6.3 Verify (what users run) ```sh # Linux / macOS sha256sum -c SHA256SUMS.txt --ignore-missing # shasum -a 256 -c on macOS minisign -Vm SHA256SUMS.txt -P 'RWQ...' # public key from the site, repo and DNS gh attestation verify moonbite-miner-linux-x86_64.tar.gz --repo moonbitecoin/moonbite-network ``` ```powershell # Windows Get-FileHash .\moonbite-miner-windows-x86_64.zip -Algorithm SHA256 minisign -Vm SHA256SUMS.txt -P 'RWQ...' gh attestation verify .\moonbite-miner-windows-x86_64.zip --repo moonbitecoin/moonbite-network ``` ### 6.4 Rotate the key minisign has no revocation. Rotation is announcement plus overlap. 1. Generate the new key with the 6.1 ceremony. Note the new key ID. 2. Sign a **rotation statement** `KEY-ROTATION-.txt` ("MoonBite release key is retired as of ; new key is `RWQ...`; reason: scheduled / suspected compromise") with **both** keys (two `.minisig` files) if the old key is still trusted, or with the new key only if it is not. Commit it to the repo, attach it to a GitHub release, and link it from `/mine`. 3. Update the public key in all three publication places (6.5) in one change, and in `deploy/moonbite-release.pub` and the `RELEASE_PUBKEY=` line in `deploy/setup-seed2.sh` (grep `RELEASE_PUBKEY`). 4. Re-sign the current release's `SHA256SUMS.txt` with the new key so the latest download verifies against the current key. 5. On compromise: additionally post on every channel the project uses, open a GitHub Security Advisory, and treat every artefact signed after the suspected compromise date as untrusted until rebuilt and re-signed. 6. Destroy the old key (both sticks) only after the overlap period (suggest 90 days) so historic releases can still be cross-checked. ### 6.5 Publish the public key in three places Users should be able to fetch the key from three independent trust roots and compare. Publish the identical `RWQ...` line: 1. **Repository**: `deploy/moonbite-release.pub` and the top-level `README.md` under "Verify a download", at https://moonbite.org/git/moonbite-network/file/deploy/moonbite-release.pub.html. Commit with a signed git tag so the history is auditable. 2. **Website**: served as a plain text file at `https://moonbite.org/.well-known/moonbite-release.pub` (static file; add to `static/` or nginx) and printed inline on `/mine` in the "Antivirus warnings and how to verify" section. 3. **DNS TXT**: a record on the project domain, for example ``` _moonbite-release.moonbite.org. TXT "v=minisign1; keyid=; key=RWQ..." ``` Check with `dig +short TXT _moonbite-release.moonbite.org`. Enable DNSSEC on the zone if the registrar supports it so the record itself is signed. Mention the key fingerprint (key ID) in release notes and in the signed trusted comment so a user who already has one copy can cross-check the others. --- ## 7. Open items for the operator - Decide whether to apply to SignPath Foundation (free, no real name on the certificate, acceptance uncertain for a miner). - Decide whether and where to form an entity; until then macOS and Windows stay unsigned and the site says so. - Complete the key ceremony in 6.1 (the placeholder in `deploy/moonbite-release.pub` is still `REPLACE_ME`). - Add the `.well-known` static file and the DNS TXT record.