Skip to content

Reject self ContextExtension keys >= 0x80 (JVM context-construction parity)#906

Open
mwaddip wants to merge 1 commit into
ergoplatform:developfrom
mwaddip:fix/context-extension-key-domain
Open

Reject self ContextExtension keys >= 0x80 (JVM context-construction parity)#906
mwaddip wants to merge 1 commit into
ergoplatform:developfrom
mwaddip:fix/context-extension-key-domain

Conversation

@mwaddip

@mwaddip mwaddip commented Jun 13, 2026

Copy link
Copy Markdown

ContextExtension keys are a signed Byte JVM-side. ErgoLikeContext.toSigmaContext builds the context vars as new Array(maxKey+1) indexed by the signed key (ErgoLikeContext.scala:140-146), so a self-box extension with a key >= 0x80 crashes context construction (NegativeArraySize / AIOOBE) before any bytecode — the spend never validates, on key PRESENCE.

sigma-rust stores extension keys as unsigned u8 and resolves them lazily at GetVar, so it would otherwise ACCEPT a >= 0x80 key where the JVM rejects — a consensus fork on the attacker-supplied spending extension. Reject any self-extension key outside 0..=127 at the reduction boundary. The per-input getVarFromInput path (id masked & 0xff) is untouched, and a GetVar of an absent >= 0x80 id still resolves to None.

ContextExtension keys are a signed Byte JVM-side. ErgoLikeContext
.toSigmaContext builds the contextVars as new Array(maxKey+1) indexed by
the signed key (ErgoLikeContext.scala:140-146), so a self-box extension
carrying a key >= 0x80 (signed-negative) crashes context construction
(NegativeArraySizeException / ArrayIndexOutOfBoundsException) BEFORE any
bytecode runs — the spend never validates. The crash is on the key's
PRESENCE, independent of whether the script reads it.

sigma-rust stores extension keys as unsigned u8 and resolves them lazily
at GetVar, so it would otherwise ACCEPT a >= 0x80 key where the JVM
rejects — a consensus fork on the attacker-supplied spending extension
(the node feeds the spending input's extension into ctx.extension before
reduce_to_crypto). Reject any self-extension key outside 0..=127 at the
reduction boundary, mirroring the construction-time crash as a clean
rejection. This is the top-level self extension only; the per-input
getVarFromInput path masks the id with & 0xff by design and is untouched,
and a GetVar of a >= 0x80 id with the key absent still resolves to None.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants