Repository navigation
System XLS: Reproducible Release Attestations #659
dangell7
started this conversation in
XLS Proposals
Replies: 1 comment 1 reply
|
The SHA256 hashes are specified in the release blogs, e.g. https://xrpl.org/blog/2026/xrpld-3.4.1#install--upgrade Is that insufficient? |
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Reproducible Release Attestations
1. Abstract
An operator installing an xrpld package today trusts whoever built and served it. This XLS removes
that trust in three parts. First, a release MUST build byte-for-byte reproducibly from its public
commit. Second, rebuilders who reproduce a release attest the hash of its
SHA256SUMSon the XRPLedger, each as a
Credentialit issues to itself, and accreditors such as XRPLF vouch for whichaccounts are rebuilders with a
Credentialissued to each. Third, before a package is installed,the operator's running node checks it against the rebuilders or accreditors the operator trusts and
a threshold the operator sets, the way a node already trusts a UNL and a quorum. No amendment is
required:
Credentialsis enabled on Mainnet.2. Motivation
The only checks available to an operator today are the package repository's GPG signature and the
hashes published in release posts. Both come from the party that built the binary, so both prove
who shipped it, not what source it came from. A compromised CI runner, signing key, package host or
CDN can ship a binary that passes both.
Release 3.4.1 shows both the gap and how close xrpld already is.
xrpld_3.4.1-1was built from acommit in a private repository: the binary embeds the source path
/__w/xrpld-private/xrpld-private/. Operators upgraded with no way to check it against any source.xrpld_3.4.1-2was later built from public tag3.4.1. The two commits differ only in one CIworkflow line, yet the two binaries differ, because the build path and the commit hash are compiled
into the bytes. Rebuilding each commit in CI's container image at CI's checkout path reproduces each
shipped package byte for byte, debug symbols included. So the build is already deterministic. What
stops an operator verifying it is that one commit was never published and that the bytes depend on
where the source was checked out.
Discussion #235 proposed having xrpld
verify its own binary hash at startup against operator-configured signatures. This XLS keeps its
central idea, signatures from parties the operator chooses, and changes where verification runs and
where signatures live (Section 4).
3. Specification
The key words MUST, MUST NOT, SHOULD and MAY are to be interpreted as described in RFC 2119 and
RFC 8174.
3.1. Terms
XRPLF/ripplednaming the exact commit a release is built from..deb,.rpm, debug-symbol package,container image manifest, the
flake.lockandconan.lockused, and the list of Conanpackage revisions used.
SHA256SUMS: the release's list of artifact hashes (Section 3.3).every artifact with the published one, and attests only on an exact match.
SHA256SUMShash for a tag (Section 3.4).(Section 3.6).
3.2. Reproducible builds
For every release tag:
time, the directory the source is checked out to, and the directory the dependency cache lives
in.
cache. Compilers MUST be given
-ffile-prefix-mapfor each, covering__FILE__, assertionstrings and debug information (
DW_AT_comp_dir). This applies to dependency builds too:prebuilt Conan libraries in 3.4.1 carry 534
/root/.conan2/p/paths. The link MUST NOT writean rpath that a later step removes, since
patchelf --remove-rpathleaves the string in.dynstr.SOURCE_DATE_EPOCH, set to the commit time of therelease tag.
flake.lock, container imagesby
@sha256digest, and Conan recipes by a committedconan.lock. A Conan 2 lockfile recordsrecipe revisions only, so each release MUST also publish the package revisions it used.
used in the official build. A rebuilder MUST be able to reproduce a release without downloading
any prebuilt binary from an XRPLF-operated server.
BuildInfo) MUST be the release tag's commit. Arelease built from a commit outside the public repository MUST have that same commit object
published to
XRPLF/rippledat disclosure (Section 3.10). A different commit is notsufficient, even with identical compiled source.
written to the changelog, MUST be published with the release.
CI MUST build every release tag twice, in different directories, and fail if any artifact differs.
CI SHOULD run the same check on every merge to the default branch, so a regression is caught before
a release depends on it.
3.3.
SHA256SUMSSHA256SUMSis UTF-8 text with LF line endings. It has one line per artifact,<sha256 as 64 lowercase hex> <file name>(two spaces), sorted by file name, with no othercontent. It is attached to the GitHub release of the tag.
A signature that a package format embeds, such as an RPM header signature, MUST be published
separately as an artifact of its own, so that every rebuilder can apply it to its own unsigned
build and reproduce the signed package byte for byte. For such a package,
SHA256SUMSlists threeartifacts: the unsigned package, under its file name with
.unsignedappended; the publishedsignature; and the signed package, under its file name.
3.4. Attestation
A rebuilder attests a release by submitting, from its own account:
TransactionTypeCredentialCreateAccountSubjectlsfAcceptedat creation)CredentialTypexrpld/release-attestation/v1/<tag>, at most 64 bytes, so<tag>is at most 35 bytes of[A-Za-z0-9._+-]URISHA256SUMS, exactly 64 bytesExpirationbefore building.
SHA256SUMSof the artifacts it built itself. For a package with anembedded signature (Section 3.3), it builds the unsigned package and applies the published
signature, and both its unsigned hash and its signed hash MUST match the published lines. When
its
SHA256SUMSdiffers from the published one, the attestation is a dissent, and the rebuilderSHOULD publish its
SHA256SUMSand adiffoscopereport at itsDomain.each
flake.lock.tecDUPLICATE).CredentialDelete(Subject,IssuerandCredentialTypeas above) only to correct its own error, with a public statement at itsDomain, or after the tag reaches end of life.key or
SignerListheld on hardware.Domain, and that domain'sxrp-ledger.tomlSHOULD listthe account, so operators can tie the account to an organisation.
An attestation is a claim, not a proof that the work was done. Anyone can create one; verifiers
ignore attestations from accounts outside the operator's trust policy (Section 3.6).
3.5. Accreditation
An accreditor vouches that an account belongs to a vetted rebuilder by submitting, from its own
account:
TransactionTypeCredentialCreateAccountSubjectCredentialTypexrpld/rebuilder/v1ExpirationURICredentialAcceptbefore verifiers count it.CredentialDelete. The issuer may delete a credential it issuedat any time.
stays with the party that built them.
SignerListwhose keysare held by different people on hardware, so one stolen key cannot accredit an account.
3.6. Trust policy
A trust policy has six parts:
rebuilders: rebuilder accounts the operator trusts directly, without an accreditor.accreditors: accounts whosexrpld/rebuilder/v1credentials make other accounts eligiblerebuilders.
accreditor_quorum: how many listed accreditors must accredit an account (default 1).min_accreditation_age: how many ledgers must have passed since the accreditation was lastmodified, read from its
PreviousTxnLgrSeq(default 0). A delay gives watchers time to see anew accreditation before it counts.
threshold: how many eligible rebuilders must attest the same hash.max_dissent: how many eligible rebuilders may attest a different hash (default 0).An account is an eligible rebuilder if it is listed in
rebuilders, or if it holds anaccepted, unexpired accreditation from at least
accreditor_quorumlisted accreditors, each atleast
min_accreditation_ageledgers old. Attestations from any other account are ignored.The operator configures a default policy in a file, referenced from
xrpld.cfgby[rebuilders_file]in the same way as[validators_file]:operator explicitly allows it.
accreditor_quorumMUST be between 1 and the number of distinct accreditors.shipped default MUST list at least two independent accreditors with
accreditor_quorumof atleast 2,
min_accreditation_ageof at least 172800 ledgers (about seven days at 3.5 seconds perledger), and a threshold of at least 2.
verify_releaseMAY pass a policy in the request, which replaces the configured onefor that call.
3.7. Verification
Given a tag, the
SHA256SUMScontent and a package's sha256, a verifier MUST:more than one server MUST require all of them to report the same hash for that ledger index.
accreditor's
account_objectsof typecredential, followingmarkerto the end, and keepcredentials with that
Issuer,CredentialTypexrpld/rebuilder/v1,lsfAcceptedset, noExpirationearlier than the ledger's close time, andPreviousTxnLgrSeqat leastmin_accreditation_ageledgers before it.ledger_entryfor the credential keyed by(
Subject=Issuer= rebuilder,CredentialTypeas in Section 3.4).entryNotFoundmeans noattestation. Any other error fails verification.
lsfAcceptedis clear,Expirationis present, orURIisnot 64 lowercase hex characters. A malformed credential counts as disagreement.
thresholdeligible rebuilders. Fail unless there isexactly one; it is the attested hash.
max_dissenteligible rebuilders attest anything else, malformedattestations included.
SHA256SUMSis not the attested hash.SHA256SUMS.xrpld MUST provide an admin RPC,
verify_release, that runs these steps against the node's ownvalidated ledger:
{ "method": "verify_release", "params": [{ "tag": "3.4.1", "sha256sums": "<SHA256SUMS content>", "package_sha256": "<64 hex>", "policy": { "rebuilders": ["rXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"], "accreditors": ["rAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"], "accreditor_quorum": 1, "min_accreditation_age": 172800, "threshold": 2, "max_dissent": 0 } }] }policyis optional; without it the configured policy applies. The RPC returnsstatussuccesswithverifiedtrueorfalse,ledger_index,ledger_hash, the policy used, arebuildersarray (account, why it is eligible, attested hash or null, ledger entry index), andreasonwhenverifiedisfalse. The node MUST log every result, with the tag, package hash,ledger index and hash, and each eligible rebuilder's attestation and entry index, so the record
outlives any later deletion.
The official
.deband.rpmpackages SHOULD run verification before replacing the binary(
preinst,%pre). They SHOULD call the installed node'sverify_releasewhen the node isrunning and has a validated ledger. Otherwise they SHOULD fall back to two or more public servers
operated by different parties, pinned as in step 1. When a trust policy is configured and
verification fails, the package SHOULD refuse to install unless the operator sets
XRPLD_SKIP_RELEASE_VERIFY=1. When no policy is configured, it SHOULD warn. Packages SHOULD alsorefuse to replace the installed release with an older one unless the operator sets
XRPLD_ALLOW_DOWNGRADE=1.3.8. CI provenance
The official release workflow SHOULD publish a build provenance attestation (for example
actions/attest-build-provenance, recorded in Sigstore's public transparency log) for everyartifact, naming the workflow, the commit and the runner. Verifiers SHOULD report whether one
exists for the package and MUST NOT count it towards the threshold. It does not prove the source
matches the bytes. It records what CI claims to have run, in a log XRPLF does not control, which
helps diagnose a disagreement between CI and a rebuilder.
3.9. Release gate
A release MUST NOT be promoted to the stable package channel until at least two accredited
rebuilders outside XRPLF, and no fewer than the shipped default policy's threshold, have attested
it with the same hash as the published
SHA256SUMS.3.10. Releases with withheld source
When a security fix ships before its source is public:
match before release. Each submits its attestation when the binary ships.
XRPLF/rippledand tagged, so anyone canrebuild the binary they already run.
the binary ships.
4. Rationale
at startup. A tampered binary simply skips that check, and anyone who can replace the binary can
edit the config. Here, the node already installed checks the next package before it is installed.
Trust carries forward from a binary the operator has already accepted.
Without reproducibility, a signature says only "I trust this binary". With it, a signature says
"this source produced these bytes", a public and permanent claim that anyone can falsify by
rebuilding the tag.
that the account's key holder made the claim. So the question of whom to trust is answered
separately, by accreditation, which is what a
Credentialfrom one party to another is for.If XRPLF issued the attestations itself, it would become the single party whose key
compromise passes any package, which is the trust this XLS removes. Accreditation keeps XRPLF's
role to vouching for people, the way a validator list publisher vouches for validators. An
operator who trusts no accreditor lists rebuilders directly.
guix.sigs) is controlled by its administrators, who can rewrite history. Ledger state isreplicated, validated by the operator's own UNL, and readable from the operator's own node.
tecDUPLICATE),a direct key lookup with no pagination, and fixed fields with no payload to parse.
SignerListlets the account's quorum, not the operator, decidewho attests.
artifact, which is the trust this XLS removes, so it cannot decide a verification. It is still
an independent public record of CI's claim (Section 3.8).
signed each of the last three releases in the
guix.sigsrepository, and binaries ship onlyafter six match. This XLS keeps that release gate and its two-stage hashes for signed outputs,
and adds what Bitcoin does not have: attestation records on a ledger, with on-ledger revocation
and expiry, vetting of who counts, and a check at install.
Ethereum clients and Solana validators have no independent rebuilds; their defence against one bad
binary is a second client implementation, which XRPL does not have.
requirements and a release process.
5. Backwards Compatibility
None. Nodes without the RPC are unaffected. Operators without a trust policy get a warning, not a
refusal.
6. Test Plan
independent servers, covers:
SHA256SUMS, an unlisted package, a threshold too high and threshold 0 all fail;tecDUPLICATE;requiring two accreditors, a minimum accreditation age, an expired accreditation and a
revoked accreditation each shrink the eligible set as specified;
max_dissent0 fails,max_dissent1 passes, and two hashesthat both reach the threshold fail.
outside XRPLF reproduce a release tag.
verify_releasecover each step of Section 3.7.7. Security Considerations
SignerListmax_dissentto 1CredentialCreateandCredentialDeletetransactions stay on full-history serversSHA256SUMS. Packages refuse to downgrade unless the operator overridesLedgerMaster.cpp)SetRegularKeyorSignerListSet. A compromised rebuilder is revoked by its accreditorsAppendix
Appendix A: FAQ
A.1: Who are the rebuilders?
Any party that runs the build on its own infrastructure. Accreditors SHOULD accredit parties that
are independent of XRPLF and of each other, in different organisations and jurisdictions and on
different infrastructure. Each operator decides which accreditors and rebuilders to trust.
All reactions