Fix ComputeTapTweak span aliasing causing all-zero output key on .NET 10 ARM64#1300
Merged
NicolasDorier merged 1 commit intoMay 11, 2026
Merged
Conversation
….NET 10 ARM64 ComputeTapTweak reused the same Span<byte> tweak32 for WriteToSpan serialization (input), SHA256.Write (hash input), and GetHash (output). On .NET 10 ARM64 (Android), the JIT miscompiles this aliasing pattern, causing AddTweak to receive a corrupted tweak and return an all-zero ECXOnlyPubKey. Fix: use a separate stackalloc byte[32] buffer for serialization, keeping tweak32 exclusively for the GetHash output. Add regression test that verifies a known BIP341 test vector produces the expected non-zero output key.
Contributor
Author
|
Hi @NicolasDorier |
Collaborator
|
wtf, this is the second time in dotnet I see something like this. |
Collaborator
|
@dangershony can you also report this to dotnet team? to me it seems like a dotnet bug, and I suspect I am using the same pattern at other places. |
Collaborator
|
bumped 10.0.4 |
Collaborator
|
For record, this bug seems similar to me to dotnet/runtime#122237 It would be nice if you could make a small repro for them and open an issue. |
Contributor
Author
|
Thanks mate issue opened |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
TaprootFullPubKey.ComputeTapTweakreuses the sameSpan<byte> tweak32for:WriteToSpan(serializing the internal pubkey)SHA256.Write(feeding the hash)merkleRoot.ToBytes(serializing the merkle root)SHA256.GetHash(writing the hash output)On .NET 10 ARM64 (Android), the JIT miscompiles this span aliasing pattern. The result is that
AddTweakreceives a corrupted tweak value and returns an all-zeroECXOnlyPubKey, producing invalid P2TR output scripts.Root Cause
The .NET 10 ARM64 JIT appears to optimize away or reorder memory operations when the same
Span<byte>is used as both input and output across multiple method calls within the same scope. This is a JIT codegen bug — the C# code is semantically correct (each use oftweak32is sequential and non-overlapping), but the generated native code does not preserve the correct memory ordering.Fix
Use a separate
stackalloc byte[32]buffer (buf) for the serialization writes (WriteToSpan,ToBytes), keepingtweak32exclusively for the finalGetHashoutput. This eliminates the aliasing pattern that triggers the JIT bug.Impact
GetTaprootFullPubKey()orTaprootFullPubKey.Create()— produces all-zero output keys, leading to funds sent to unspendable addressesTesting
ComputeTapTweak_DoesNotProduceAllZeroOutputKeyusing BIP341 test vectorRelated
160f198ba0f7dacbc097d6a61703b3121af38b7362d17b063cd9152f74012598(signet, funds sent to all-zero P2TR)