Function: canonicalizeForSigning()
canonicalizeForSigning(
info):string
Produces the exact byte string that is Ed25519-signed at publish time and verified at update time.
Only integrity- and rollout-critical fields are covered:
version— prevents version downgrade/substitutionstagingPercentage— prevents tampering with staged-rollout gatingminimumSystemVersion— prevents bypassing or forging the OS-version gate (its absence is signed too, so one cannot be added after the fact)- each file's
url,sha512,size— the artifact identity + integrity hash the updater enforces - each NSIS web-installer package's arch key and
path,sha512,size,blockMapSize,isAdminRightsRequired(WindowsUpdateInfo.packages, keyed by arch) — the payload the web installer downloads and verifies
Cosmetic/operational fields (releaseDate, releaseNotes, releaseName) are intentionally excluded so
they can be edited post-signing without invalidating the signature. The signature/signatures fields are
not part of the payload either, so signatures can be added or removed independently of one another. The
deprecated top-level path/sha512 mirror of files[0] is not signed; instead the verifier refuses a
signed manifest without a non-empty files list (see validateSignedManifestShape), so the updater
never falls back to those legacy fields for a verified manifest.
Wire format (EBUM1): one record per line, label: followed by tab-separated fields, e.g.
EBUM1
version:"1.2.3"
staging:25
minimumSystemVersion:"10.0.19041"
file:"App-1.2.3.exe"<TAB>"<sha512>"<TAB>8123456
package:"x64"<TAB>"App-1.2.3-x64.nsis.7z"<TAB>"<sha512>"<TAB>5000<TAB>120<TAB>1
Every value goes through encodeField (JSON-quoted strings, bare numbers, empty for absent), which is
what makes the encoding injective: a value can never contain an unescaped newline or tab, so no choice of
field values in one manifest can reproduce the record structure of another (e.g. an empty files list plus
a minimumSystemVersion that spells out the original file: lines). The format is deterministic regardless
of object key order or YAML formatting: file records are sorted, package records are sorted, and a version
prefix anchors the scheme. Both the signer (build) and verifier (runtime) MUST call this identical function —
it is a wire contract — and both operate on the manifest exactly as written to latest*.yml: the signer runs
on the final UpdateInfo right before serialization, the verifier on the parsed manifest before the provider
resolves files[].url / packages[arch].path against the feed base URL. This function never throws; shape
problems are reported by validateSignedManifestShape instead.
Parameters
info
Returns
string