-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Fix bug of FastReducer used in BigInteger.ModPow #53945
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Tagging subscribers to this area: @tannergooding, @pgovind Issue DetailsThere is a bug in the current implementation of
When these conditions are met, the size of the buffers q1 and q2 used in the algorithm becomes insufficient, causing a assertion error on BigIntegerCalculator.FastReducer.cs#L77 in debug build, or IndexOutOfRangeException on BigIntegerCalculator.PowMod.cs#L401 in Release build. FastReducer is used only in BigInteger.ModPow, but the specific condition cause above error. Following code is one of the example. BigInteger.ModPow(BigInteger.One << 1008, 2, BigInteger.One << 992); This PR fixes this bug by changing the allocated size of the buffer. The validity of the change is explained below. ExplanationUnless otherwise stated, all variables are non-negative and division is defined as truncated division. Before we begin, we will define a few constants and functions.
First, we will look at the implementation of the constructor.
Note: The variable The above corresponds to the following code. Lines 26 to 43 in 949fef4
Next, we will look at the implementation of the Reduce function.
The above corresponds to the following code. Lines 45 to 66 in 949fef4
Here, we will think about upper bound of Same as Now we have shown the upper bound of
|
There is one additional bug in the current BigInteger.ModPow(BigInteger.One << 1008, 2, (BigInteger.One << 992) + 1); The above commit adds a test that covers this case and fixes the bug. Below is an explanation of the cause and fix for this bug. ExplanationIn this explanation, the symbols used in the above explanation are reused.
The above corresponds to the following code. Lines 63 to 65 in 949fef4
Lines 112 to 146 in 949fef4
The reason we divide by
The Furthermore, since |
I accidentally deleted the forked repository, so I'll close this one and repost it. I apologize for the inconvenience caused by this. |
There is a bug in the current implementation of
FastReducer
that causes a runtime error when certain conditions described below are met.base^{modulus.Length-1}
.When these conditions are met, the size of the buffers q1 and q2 used in the algorithm becomes insufficient, causing a assertion error on BigIntegerCalculator.FastReducer.cs#L77 in debug build, or
IndexOutOfRangeException
on BigIntegerCalculator.PowMod.cs#L401 in Release build.FastReducer
is used only inBigInteger.ModPow
, but the specific condition cause above error. Following code is one of the example.This PR fixes this bug by changing the allocated size of the buffer. The validity of the change is explained below.
Edit: After submitting this PR, I found a bug that is related but has a different cause, so I will fix that as well. See the below comments for details.
Explanation
Unless otherwise stated, all variables are non-negative and division is defined as truncated division.
Before we begin, we will define a few constants and functions.
First, we will look at the algorithm of the constructor.
Note: The variable
k
is implicitly defined and does not appear in the actual code.The above corresponds to the following code.
runtime/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigIntegerCalculator.FastReducer.cs
Lines 26 to 43 in 949fef4
Next, we will look at the algorithm of the Reduce function.
The above corresponds to the following code.
runtime/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigIntegerCalculator.FastReducer.cs
Lines 45 to 66 in 949fef4
Here, we will think about upper bound of
ActualLength(q1)
.Since upper bound of
V
isbase^(2k)
, upper bound ofV / base^(k-1)
isbase^(k+1)
.Since modulus should not be 0,
r
andmu
can't be 0. Somu
is less thanbase^(muLength)
.It is easy to show that an upper bound on the values of both
V
andmu
can be achieved.From these facts, we can see that the upper bound of
q1
isbase^(muLength + k + 1)
.Same as
q1
, we can see that upper bound ofq2
isbase^(muLength + k)
Now we have shown the upper bound of
q1
andq2
. From these, we can see that the upper bound of length of the buffer required forq1
andq2
is:ActualLength(q1) ≦ muLength + k + 1
,ActualLength(q2) ≦ muLength + k
.