Skip to content

Conversation

ChrisMcKee
Copy link

Changes FixedTimeEquals to use XOR instead of SUB.

XOR directly expresses the statement "are these bytes different"; the use of subtraction changes that to "what is the difference between these bytes".
The agreed implementation for constant-time security is to avoid arithmetic that may introduce timing variations between platform/processor/compiler. XOR operations a ^ b produces a non-zero result, only when bits differ, and benefits from being its own inverse without requiring extra-information like carry bits or sign bits. XOR is cheaper at a CPU level (realitically not a huge factor unless your on certain low speed asics) though I mention this more for fun than "this would have a huge impact on perf"; Theoretically that difference can matter in side-channel-attacks that utilise differential power analysis; but again not the biggest driver for change vs consistency and agreed approach.

BenchmarkDotNet v0.15.2, Windows 11 (10.0.26100.4946/24H2/2024Update/HudsonValley)
AMD Ryzen 9 9900X 4.40GHz, 1 CPU, 24 logical and 12 physical cores
.NET SDK 9.0.304
  [Host]     : .NET 9.0.8 (9.0.825.36511), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
  DefaultJob : .NET 9.0.8 (9.0.825.36511), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Method Mean BranchInstructions/Op Code Size
XOR_WithVariance 3,396.70 ns 8,335 377 B
FixedTimeEquals_WithVariance 3,337.46 ns 8,338 381 B
XOR_ExtremeValues 3,474.97 ns 11,403 339 B
FixedTimeEquals_ExtremeValues 3,385.70 ns 11,418 343 B
XOR_RealisticShaValues 88.68 ns 237 275 B
FixedTimeEquals_RealisticShaValues 87.80 ns 237 279 B

@Copilot Copilot AI review requested due to automatic review settings September 8, 2025 21:16
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves the constant-time equality implementation by replacing subtraction with XOR operations in the FixedTimeEquals method. The change enhances security consistency with industry standards and provides better protection against timing-based side-channel attacks.

Key Changes

  • Replaces subtraction operation (left[i] - right[i]) with XOR operation (left[i] ^ right[i])
  • Renames the accumulator variable from accum to diff to better reflect its purpose
  • Updates loop variable declaration to use var instead of explicit type


for (int i = 0; i < length; i++)
int diff = 0;
for (var i = 0; i < length; i++)
Copy link
Preview

Copilot AI Sep 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use explicit type int instead of var for the loop variable to maintain consistency with the existing codebase style. The variable length is already declared as int on line 49.

Copilot generated this review using guidance from repository custom instructions.

@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Sep 8, 2025
XOR directly expresses the statement "are these bytes different"; the use of subtraction changes that to "what is the difference between these bytes"
The agreed implementation for constant-time security is to avoid arithmetic that may introduce timing variations between platform/processor/compiler.
XOR operations `a ^ b` produces a non-zero result only when bits differ.
XOR also benefits from being its own inverse without requiring extra information like carry bits or sign bits, and though somewhat irrelevant with built in overflow checks, doesn't carry any risk.
XOR is theoretically cheaper at a CPU level; though I mention this more for fun than "this would have a huge impact on perf"; Theoretically that can matter in side-channel-attacks that utilise differential power analysis.

* Consistent with:
  * Windows SymCrypt https://github.com/microsoft/SymCrypt/blob/6d019cefafb3fefe3c53b0de3bba6f8c86e2d48a/lib/equal.c
  * GoLang std FIPS140 https://cs.opensource.google/go/go/+/master:src/crypto/internal/fips140/subtle/constant_time.go;l=72?q=ConstantTimeEq&ss=go%2Fgo
  * JDK https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.base/share/classes/java/security/MessageDigest.java#L473C1-L486C6
  * Rust https://github.com/cesarb/constant_time_eq/blob/main/src/generic.rs#L158
  * OpenBSD https://sources.debian.org/src/openssh/1%3A10.0p1-6/openbsd-compat/timingsafe_bcmp.c/#L30
@bartonjs
Copy link
Member

bartonjs commented Sep 8, 2025

"Why?"

When we originally added this to .NET Framework, we observed that the XOR based approach actually had a timing bias in it (either A XOR A was faster than A XOR (anything not A), or 0 XOR 0 was faster than other things, I don't remember), and we didn't observe the bias with SUB.

We don't want a change here "just because".

@bartonjs bartonjs added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Sep 8, 2025
@ChrisMcKee
Copy link
Author

Didn't think I worded it as 'just because'; xor in time-constant comparison, as per the links, is the standard approach. There was nothing to say why this deviates or why, for instance, this deviates in yet another way.

Thanks for your time anyway.

@bartonjs
Copy link
Member

bartonjs commented Sep 8, 2025

"Because other people do it a different way" is sort of "just because". Maybe a different question would be "what motivated you to make the change?" and/or "what motivated you to look at this code?"

@ChrisMcKee ChrisMcKee closed this Sep 8, 2025
@ChrisMcKee ChrisMcKee deleted the fixed-time-equality branch September 8, 2025 22:28
@ChrisMcKee
Copy link
Author

ChrisMcKee commented Sep 8, 2025

I was working on similar functionality in another library and remembered the extensions had been added to the runtime, which led me to this source, the identity source, and wondering why they all differed from what I considered the standard implementation (ignoring the .net specifics like read-only spans).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Security community-contribution Indicates that the PR has been added by a community member NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants