Skip to main content

Ledger v8.1.2 release notes

For the complete documentation index, see llms.txt
  • Version: v8.1.2
  • Date: August 24, 2026

High-level summary

Ledger 8.1.2 is a security patch. It fixes multiple encoding strictness issues that could have led to security issues down the line, hardening low-level deserialization so that non-canonical encodings and values violating their type's invariant are rejected rather than decoded. The release was delivered to mainnet nodes prior to this public release.

All version bumps are patch-level so that the release reads as one, even where an individual change carries wider semver implications, and internal dependency requirements are pinned to the new exact versions so that consumers cannot resolve past the fix.

Audience

This release note is most relevant for:

  • Node developers.

Summary of updates

  • Security: hardening of low-level deserialization across serialize, base-crypto, storage, onchain-state, onchain-vm, and transient-crypto. Encodings that are not canonical, and values violating their type's invariant, are now rejected rather than decoded. This narrows what deserializes: an 8.1.2 node rejects data an 8.1.1 node accepts. See the per-crate changelogs for the individual rules.
  • Fix: DustParameters::time_to_cap guards against a zero generation_decay_rate instead of dividing by zero.
  • Fix: Dust seq increments saturate.
  • Fix: Zswap binding randomness extraction no longer panics on a proof preimage with no witness to extract from.
  • Fix: delta accumulation in normalize_deltas saturates.
  • Fix: contract call cost accounting counts public inputs via ContractCall::public_inputs_len, with saturating arithmetic, rather than materializing the inputs to take their length.

New features

No new features in this release.

New features requiring configuration updates

None in this release.

Deprecations

None in this release.


Breaking changes or required actions

The security changes are breaking only for an environment containing maliciously formed transactions: encodings that previously decoded despite being non-canonical no longer do.


Bug fixes and quality improvements

ComponentDescription
serializeHashMap and HashSet deserialization requires a normalized encoding (sorted, no duplicate keys); the non-canonical encodings that previously decoded to the same value are rejected.
serializeNon-canonical ScaleBigInt encodings, which use the 4-byte form for a value that fits a smaller form, are rejected.
serializeBox<T> deserialization counts against the recursion depth budget.
serializeVec::with_bounded_capacity no longer divides by zero for zero-sized types.
serializeserialized_size for HashMap and HashSet accounts for the actual width of the length prefix.
base-cryptoNon-canonical Value and ValueAtom encodings are rejected: a singleton value encoded in the multi-entry form, and an atom that fits the single-byte form encoded as multiple bytes.
base-cryptoAlignedValue deserialization rejects a value that does not fit its declared alignment.
base-cryptoDuration::from_hours saturates instead of overflowing.
storageMerklePatriciaTrie deserialization enforces full structural canonicity rather than annotation consistency alone; a trie whose structure is not uniquely determined by its contents no longer decodes.
storageAn Extension node whose declared nibble length disagrees with the length of its encoded path is rejected.
storageMultiSet rejects zero-count entries.
storageTimeFilterMap rejects an encoding whose set and time-map representations disagree.
storageNibble-encoded keys reject trailing bytes left over after decoding.
onchain-runtimeOp deserialization rejects operands outside their legal encoding bound: dup, swap, and ins with n >= 16, and idx with a path length outside 1..=16.
onchain-runtimeserde StateValue deserialization enforces the type's invariant.
onchain-runtimeTaking the type of an array with more than 16 entries is a type error instead of producing an out-of-range tag byte.
onchain-runtimeThe Merkle tree bound checks in idx and ins no longer overflow for large tree heights.
transient-cryptoVerifierKey serialization is independent of whether the key has been initialized; initializing in place no longer changes what the key serializes to.
transient-cryptoA verifier key with trailing bytes after the encoded key is rejected, so two encodings cannot map to the same key.
ledgerDustParameters::time_to_cap guards against a zero generation_decay_rate instead of dividing by zero.
ledgerDust seq increments saturate.
ledgerContract call cost accounting counts public inputs via ContractCall::public_inputs_len, with saturating arithmetic, rather than materializing the inputs to take their length.
zswapBinding randomness extraction no longer panics on a proof preimage with no witness to extract from.
zswapDelta accumulation in normalize_deltas saturates.
coin-structure, storage-core, zkirPull in the hardened serialize, base-crypto, storage-core, and transient-crypto deserialization.

Known issues

No new known issues in this release.