예제 #1
0
        private void RecoverSeedPowerOf2Callback(RecoverSeedEventArgs args)
        {
            if (args.EventType == RecoverSeedEventType.SeedDiscovered)
            {
                args.Seed = PreviousState(args.Seed ^ _Multiplier) ^ _Multiplier;
            }

            this._OriginalCallback(args);
        }
예제 #2
0
        private void RecoverSeedCallback(RecoverSeedEventArgs args)
        {
            if (args.EventType == RecoverSeedEventType.SeedDiscovered)
            {
                args.Seed = PreviousState(unchecked ((uint)args.Seed));
            }

            this._OriginalCallback(args);
        }
예제 #3
0
        /// <summary>
        /// Discovers the seed or seeds that produce the supplied PRNG output sequence.
        /// </summary>
        /// <param name="seedStart">The first seed value to test.</param>
        /// <param name="seedEnd">The last seed value that could be tested.</param>
        /// <param name="seedIncrement">A positive integer specifying the interval at which to test seeds.
        /// A value of 1 tests each seed serially, a value of 2 tests every other seed, and so on.</param>
        /// <param name="output">A sequence containing one or more PRNG output values (modulo <paramref name="limit"/>)
        /// and any number of instances of <paramref name="wildcard"/>.</param>
        /// <param name="limit">The lowest positive integer greater than the maximum allowed output value, or 0 if no limit was imposed on the output.</param>
        /// <param name="wildcard">A number which will match any PRNG output value when encountered in <paramref name="output"/>.</param>
        /// <param name="callback">A method to invoke with seed discovery or progress notifications.</param>
        /// <param name="progressInterval">The number of seeds to test between progress notifications, or 0 to not receive progress notifications.</param>
        /// <returns>true if seed discovery completed (even if no seed was discovered), or false if the callback canceled discovery or an error occurred.</returns>
        /// <remarks>If progress notifications are requested, <paramref name="callback"/> will be invoked for a final progress notification event before true is returned.</remarks>
        protected virtual bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (seedStart > seedEnd || seedIncrement == 0)
                return false;

            if (callback == null)
                progressInterval = 0;

            ulong totalcount = unchecked((seedEnd - seedStart) / seedIncrement + 1);  // count = 0 (2**64) if minimum seed = 0, maxseed = 2**64 - 1, and seedIncrement = 1
            ulong totalcountdown = totalcount;

            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            ulong seed = seedStart;

            do
            {
                ulong countdown = ((totalcountdown < progressInterval || progressInterval == 0) ? totalcountdown : progressInterval);
                totalcountdown = unchecked(totalcountdown - countdown);  // allow integer underflow so that 0 == 2**64

                do
                {
                    this.Seed(seed);

                    int i;

                    if (limit != 0)
                    {
                        for (i = 0; i < output.Length; i++)
                        {
                            if (this.Next(limit) != output[i] && output[i] != wildcard)
                                break;
                        }
                    }
                    else
                    {
                        for (i = 0; i < output.Length; i++)
                        {
                            if (this.Next() != output[i] && output[i] != wildcard)
                                break;
                        }
                    }

                    if (i == output.Length)  // invoke callback for seed discovery notification
                    {
                        args.EventType = RecoverSeedEventType.SeedDiscovered;
                        args.Seed = seed;
                        args.CurrentAttempts = (totalcount - totalcountdown - countdown);
                        args.TotalAttempts = totalcount;

                        callback(args);

                        if (args.Cancel)
                            return false;
                    }

                    seed += seedIncrement;
                }
                while (unchecked(--countdown) != 0);  // allow integer underflow here, so that 0 is equivalent to 2**64

                if (progressInterval != 0)  // invoke callback for progress notification
                {
                    args.EventType = RecoverSeedEventType.ProgressNotification;
                    args.Seed = seed;
                    args.CurrentAttempts = (totalcount - totalcountdown - countdown);
                    args.TotalAttempts = totalcount;

                    callback(args);

                    if (args.Cancel)
                        return false;
                }
            }
            while (totalcountdown != 0);

            return true;
        }
예제 #4
0
        private void RecoverSeedCallback(RecoverSeedEventArgs args)
        {
            if (args.EventType == RecoverSeedEventType.SeedDiscovered)
                args.Seed = PreviousState(unchecked((uint)args.Seed));

            this._OriginalCallback(args);
        }
예제 #5
0
        private void RecoverSeedPowerOf2Callback(RecoverSeedEventArgs args)
        {
            if (args.EventType == RecoverSeedEventType.SeedDiscovered)
                args.Seed = PreviousState(args.Seed ^ _Multiplier) ^ _Multiplier;

            this._OriginalCallback(args);
        }
예제 #6
0
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (output.Length < 2 || output[0] > (ulong.MaxValue / _OutputDivisor) || output[0] == wildcard || limit == 0 || limit > _OutputDivisor)
                return base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval);

            if (seedStart > seedEnd || seedIncrement == 0)
                return false;

            if (unchecked(limit & (limit - 1)) == 0)  // special handling for power-of-two limits
            {
                return this.RecoverSeedPowerOf2(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval);
            }

            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix middle portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                ulong seedtopincr = (uint)limit * _DiscardDivisorForMod;

                // Modulus is a power of 2, so GCD(limit, Modulus) is greatest power-of-two factor of limit
                ulong subgenoutputmask = ((uint)limit ^ ((uint)limit - 1)) >> 1;

                // fix bottom portion by brute-forcing subgenerator
                ulong subseed, subseedend;
                for (subseed = (output[0] & subgenoutputmask) * _DiscardDivisorForMod, subseedend = subseed + _DiscardDivisorForMod - 1; subseed != subseedend; subseed++)
                {
                    if (subgenoutputmask != 0)  // if limit is odd, we can't check this subgenerator seed against LSB(s) of output; we must test all possibilities below
                    {
                        this._LcgState = subseed;  // don't use Seed() because it XORs by _Multiplier

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                           if ((this.Next(limit) & subgenoutputmask) != (suboutput[i] & subgenoutputmask) && suboutput[i] != wildcard)
                                break;
                        }

                        if (i < suboutput.Length)
                            continue;
                    }

                    // MSB(s) of subseed will contain LSB(s) of output[0], so | instead of + to keep duplicate bit(s) from interfering
                    for (ulong seed = (output[0] * _DiscardDivisorForMod) | subseed; seed <= seedEnd; seed += seedtopincr)
                    {
                        this._LcgState = seed;  // don't use Seed() because it XORs by _Multiplier

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                            if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                                break;
                        }

                        if (i == suboutput.Length)  // invoke callback for seed discovery notification
                        {
                            args.EventType = RecoverSeedEventType.SeedDiscovered;
                            args.Seed = (PreviousState(seed) ^ _Multiplier);
                            // TO-DO TODO: estimate progress/total somehow?
                            args.CurrentAttempts = 0;
                            args.TotalAttempts = 0;

                            callback(args);

                            if (args.Cancel)
                                return false;
                        }
                    } //for(seed<=seedEnd)
                } //for(subseed<subgensize)
            } //unchecked

            return true;
        }
예제 #7
0
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (output.Length < 2 || output[0] > (ulong.MaxValue / _OutputDivisor) || output[0] == wildcard || limit == 0 || limit > _OutputDivisor)
                return base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval);

            if (seedStart > seedEnd || seedIncrement == 0)
                return false;

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix top portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                ulong rangestart = ((_OutputDivisor * output[0]) + (uint)limit - 1) / (uint)limit;  // add (limit - 1) to round up, to make sure 'rangestart' will produce output[0]
                rangestart *= _DiscardDivisor;

                ulong rangeend = (((_OutputDivisor * (output[0] + 1)) + (uint)limit - 1) / (uint)limit) - 1;  // lowest seed that produces (output[0] + 1), then - 1
                rangeend = (rangeend * _DiscardDivisor) + (_DiscardDivisor - 1);

                if (rangestart <= seedStart)
                {
                    rangestart = seedStart;
                }
                else if (seedIncrement > 1)
                {
                    ulong incroffset = (rangestart - seedStart) % seedIncrement;
                    if (incroffset != 0)
                        rangestart += (seedIncrement - incroffset);  // advance to the next multiple of 'seedIncrement' (relative to 'seedStart')
                }

                if (rangeend > seedEnd)
                    rangeend = seedEnd;

                ulong output1 = ((output.Length > 2) ? output[1] : wildcard);

                uint blocksize = (uint)(_Modulus / ((ulong)_Multiplier * limit));
                if (blocksize < 2) output1 = wildcard;  // don't attempt improved attack if block size is too small

                if (output1 == wildcard || seedIncrement != 1)
                {
                    this._OriginalCallback = callback;
                    return base.RecoverSeed(rangestart, rangeend, seedIncrement, suboutput, limit, wildcard, this.RecoverSeedCallback, progressInterval);
                }

                // otherwise, use second output to skip blocks of candidate states

                RecoverSeedEventArgs args = new RecoverSeedEventArgs();

                uint offset = NextFromState((uint)rangestart, (uint)limit);  // determine how far off current output is from second output
                offset = (uint)output1 + ((output1 < offset) ? (uint)limit : 0) - offset;

                if (offset >= 2)  // skip ahead conservatively to vicinity of a block of consecutive states that will produce 'output1'
                    rangestart += (offset - 1) * blocksize;

                while (NextFromState((uint)rangestart, (uint)limit) != output1)  // TO-DO TODO: binary seek, starting at +'blocksize'
                    rangestart++;

                uint blockstart = (uint)rangestart;
                uint blockend;

                for (; ; )
                {
                    blockend = blockstart + blocksize;  // [blockstart..blockend] is (blocksize + 1) states, to accommodate rounding variations
                    if (blockend >= rangeend) blockend = (uint)rangeend;

                    for (uint state = blockstart; ; state++)
                    {
                        this.Seed(state);

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                            if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                                break;
                        }

                        if (i == suboutput.Length)  // invoke callback for seed discovery notification
                        {
                            args.EventType = RecoverSeedEventType.SeedDiscovered;
                            args.Seed = PreviousState(state);
                            // TO-DO TODO: estimate progress/total somehow?
                            args.CurrentAttempts = 0;
                            args.TotalAttempts = 0;

                            callback(args);

                            if (args.Cancel)
                                return false;
                        }

                        if (state == blockend)  // check only after body of loop so that 'blockend' will get tested
                            break;
                    } //for(state)

                    blockstart += ((uint)limit * blocksize);
                    if (blockstart >= rangeend)
                        break;
                    // 'blockend' will be set at the top of the loop body

                    while (NextFromState(blockstart, (uint)limit) != output1)  // TO-DO TODO: binary seek?
                        blockstart++;
                } //for(;;)
            } //unchecked

            return true;
        }
예제 #8
0
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (output.Length < 2 || output[0] >= limit || output[0] == wildcard || limit == 0 || limit > _Modulus || seedIncrement != 1)
                return base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval);

            if (seedStart < this.MinimumSeed)
                seedStart = this.MinimumSeed;

            if (seedEnd > this.MaximumSeed)
                seedEnd = this.MaximumSeed;

            if (seedStart > seedEnd)
                return false;

            ulong output1 = ((output.Length > 2) ? output[1] : wildcard);

            uint blocksize = (uint)(_Modulus / ((ulong)_Multiplier1 * limit));
            if (blocksize < 2) output1 = wildcard;  // don't attempt improved attack if block size is too small

            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix bottom portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                // 2147483589.46728 rounded down is 2147483589 and rounded up is 2147483590; rounding outward ensures we won't exclude a viable candidate state
                uint difflo = (uint)(((2147483589 * output[0]) + limit - 1) / limit);  // add (limit - 1) to round up, to make sure 'difflo' will (almost always) produce output[0]
                uint diffhi = (uint)(((2147483590 * (output[0] + 1)) + limit - 1) / limit) - 1;  // lowest difference that produces (output[0] + 1), then - 1

                for (uint state0 = 1; state0 < _Modulus; state0++)
                {
                    uint state1start = (state0 + _Modulus - diffhi);  // State1 such that (State0 - State1) == diffhi; subtract 'diffhi' to get State1 lower bound
                    if (state1start >= _Modulus)  // _Modulus rather than _Modulus1 because difference is computed modulo _Modulus
                        state1start -= _Modulus;
                    if (state1start == 0 || state1start >= _Modulus1)
                        state1start = 1;  // skip impossible state1 values

                    if (output1 != wildcard)
                    {
                        uint offset = NextFromStates(state0, state1start, (uint)limit);  // determine how far off current output is from second output
                        offset = offset + ((offset < output1) ? (uint)limit : 0) - (uint)output1;  // compute (offset - output1) because State1 is subtracted from State0

                        if (offset >= 2)  // skip ahead very conservatively to vicinity of a block of consecutive states that will produce 'output1'
                            state1start += (offset - 1) * blocksize - (_Modulus - _Modulus1 + 1);  // don't let skipped states cause us to miss any viable candidates

                        while (NextFromStates(state0, state1start, (uint)limit) != output1)  // TO-DO TODO: binary seek, starting at +'blocksize'
                            state1start++;
                    }

                    uint state1end = (state0 + _Modulus - difflo);  // State1 such that (State0 - State1) == difflo; subtract 'difflo' to get State1 upper bound
                    if (state1end >= _Modulus)
                        state1end -= _Modulus;
                    if (state1end == 0 || state1end >= _Modulus1)
                        state1end = (_Modulus1 - 1);  // stop short of impossible State1 values

                    uint state1blockstart = state1start;
                    uint state1blockend;

                    for (; ; )  // blocks
                    {
                        if (output1 != wildcard)
                        {
                            state1blockend = state1blockstart + blocksize;  // [state1blockstart..state1blockend] is (blocksize + 1) states, to accommodate rounding variations
                            if (state1blockend >= _Modulus)
                                state1blockend -= _Modulus;
                            if (state1blockend == 0 || state1blockend >= _Modulus1)
                                state1blockend = (_Modulus1 - 1);  // stop short of impossible State1 values
                        }
                        else
                        {
                            state1blockstart = state1start;
                            state1blockend = state1end;
                        }

                        for (; ; )  // pieces
                        {
                            // brute-force State1 in two passes if its range wraps around, so that we don't have to check for zero or _Modulus1 after each increment
                            uint state1piecestart = state1blockstart;
                            uint state1pieceend = ((state1blockstart < state1blockend) ? state1blockend : (_Modulus1 - 1));

                            for (uint state1 = state1piecestart; ; state1++)
                            {
                                this._State0 = state0;  // faster than converting states to seed and seed to states via Seed()
                                this._State1 = state1;

                                int i;
                                for (i = 0; i < suboutput.Length; i++)
                                {
                                    if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                                        break;
                                }

                                if (i == suboutput.Length)  // invoke callback for seed discovery notification
                                {
                                    uint prevstate0 = (uint)(((ulong)state0 * _Multiplier0Inverse) % _Modulus);
                                    uint prevstate1 = (uint)(((ulong)state1 * _Multiplier1Inverse) % _Modulus1);

                                    args.EventType = RecoverSeedEventType.SeedDiscovered;
                                    args.Seed = SeedFromStates(prevstate0, prevstate1);
                                    // TO-DO TODO: estimate progress/total somehow?  would be easy if not for skipped State1 candidates
                                    args.CurrentAttempts = 0;
                                    args.TotalAttempts = 0;

                                    callback(args);

                                    if (args.Cancel)
                                        return false;
                                }

                                if (state1 == state1pieceend)  // check only after body of loop so that 'state1pieceend' will get tested
                                    break;
                            } //for(state1)

                            if (state1blockstart > state1blockend)
                                state1blockstart = 1;  // now brute-force the second (post-zero) piece
                            else break;
                        } //for(pieces)

                        if (output1 != wildcard)
                        {
                            if (state1blockstart <= state1end && state1blockend >= state1end)
                                break;

                            state1blockstart = state1blockend + ((uint)(limit - 1) * blocksize);  // skip ahead by a conservative underestimate
                            if (state1blockend <= state1end && state1blockstart >= state1end)
                                break;
                            // 'state1blockend' will be set at the top of the loop body

                            while (NextFromStates(state0, state1blockstart, (uint)limit) != output1)  // TO-DO TODO: binary seek?
                                state1blockstart++;
                        }
                        else break;
                    } //for(blocks)
                } //for(state0)
            } //unchecked

            return true;
        }
예제 #9
0
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (output.Length < 2 || output[0] > (ulong.MaxValue / _OutputDivisor) || output[0] == wildcard || limit == 0 || limit > _OutputDivisor)
            {
                return(base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval));
            }

            if (seedStart > seedEnd || seedIncrement == 0)
            {
                return(false);
            }

            if (unchecked (limit & (limit - 1)) == 0)  // special handling for power-of-two limits
            {
                return(this.RecoverSeedPowerOf2(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval));
            }

            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix middle portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                ulong seedtopincr = (uint)limit * _DiscardDivisorForMod;

                // Modulus is a power of 2, so GCD(limit, Modulus) is greatest power-of-two factor of limit
                ulong subgenoutputmask = ((uint)limit ^ ((uint)limit - 1)) >> 1;

                // fix bottom portion by brute-forcing subgenerator
                ulong subseed, subseedend;
                for (subseed = (output[0] & subgenoutputmask) * _DiscardDivisorForMod, subseedend = subseed + _DiscardDivisorForMod - 1; subseed != subseedend; subseed++)
                {
                    if (subgenoutputmask != 0)    // if limit is odd, we can't check this subgenerator seed against LSB(s) of output; we must test all possibilities below
                    {
                        this._LcgState = subseed; // don't use Seed() because it XORs by _Multiplier

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                            if ((this.Next(limit) & subgenoutputmask) != (suboutput[i] & subgenoutputmask) && suboutput[i] != wildcard)
                            {
                                break;
                            }
                        }

                        if (i < suboutput.Length)
                        {
                            continue;
                        }
                    }

                    // MSB(s) of subseed will contain LSB(s) of output[0], so | instead of + to keep duplicate bit(s) from interfering
                    for (ulong seed = (output[0] * _DiscardDivisorForMod) | subseed; seed <= seedEnd; seed += seedtopincr)
                    {
                        this._LcgState = seed;  // don't use Seed() because it XORs by _Multiplier

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                            if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                            {
                                break;
                            }
                        }

                        if (i == suboutput.Length)  // invoke callback for seed discovery notification
                        {
                            args.EventType = RecoverSeedEventType.SeedDiscovered;
                            args.Seed      = (PreviousState(seed) ^ _Multiplier);
                            // TO-DO TODO: estimate progress/total somehow?
                            args.CurrentAttempts = 0;
                            args.TotalAttempts   = 0;

                            callback(args);

                            if (args.Cancel)
                            {
                                return(false);
                            }
                        }
                    } //for(seed<=seedEnd)
                }     //for(subseed<subgensize)
            }         //unchecked

            return(true);
        } //PrngJava.RecoverSeed
예제 #10
0
        /// <summary>
        /// Discovers the seed or seeds that produce the supplied PRNG output sequence.
        /// </summary>
        /// <param name="seedStart">The first seed value to test.</param>
        /// <param name="seedEnd">The last seed value that could be tested.</param>
        /// <param name="seedIncrement">A positive integer specifying the interval at which to test seeds.
        /// A value of 1 tests each seed serially, a value of 2 tests every other seed, and so on.</param>
        /// <param name="output">A sequence containing one or more PRNG output values (modulo <paramref name="limit"/>)
        /// and any number of instances of <paramref name="wildcard"/>.</param>
        /// <param name="limit">The lowest positive integer greater than the maximum allowed output value, or 0 if no limit was imposed on the output.</param>
        /// <param name="wildcard">A number which will match any PRNG output value when encountered in <paramref name="output"/>.</param>
        /// <param name="callback">A method to invoke with seed discovery or progress notifications.</param>
        /// <param name="progressInterval">The number of seeds to test between progress notifications, or 0 to not receive progress notifications.</param>
        /// <returns>true if seed discovery completed (even if no seed was discovered), or false if the callback canceled discovery or an error occurred.</returns>
        /// <remarks>If progress notifications are requested, <paramref name="callback"/> will be invoked for a final progress notification event before true is returned.</remarks>
        protected virtual bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (seedStart > seedEnd || seedIncrement == 0)
            {
                return(false);
            }

            if (callback == null)
            {
                progressInterval = 0;
            }

            ulong totalcount     = unchecked ((seedEnd - seedStart) / seedIncrement + 1); // count = 0 (2**64) if minimum seed = 0, maxseed = 2**64 - 1, and seedIncrement = 1
            ulong totalcountdown = totalcount;

            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            ulong seed = seedStart;

            do
            {
                ulong countdown = ((totalcountdown < progressInterval || progressInterval == 0) ? totalcountdown : progressInterval);
                totalcountdown = unchecked (totalcountdown - countdown);  // allow integer underflow so that 0 == 2**64

                do
                {
                    this.Seed(seed);

                    int i;

                    if (limit != 0)
                    {
                        for (i = 0; i < output.Length; i++)
                        {
                            if (this.Next(limit) != output[i] && output[i] != wildcard)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        for (i = 0; i < output.Length; i++)
                        {
                            if (this.Next() != output[i] && output[i] != wildcard)
                            {
                                break;
                            }
                        }
                    }

                    if (i == output.Length)  // invoke callback for seed discovery notification
                    {
                        args.EventType       = RecoverSeedEventType.SeedDiscovered;
                        args.Seed            = seed;
                        args.CurrentAttempts = (totalcount - totalcountdown - countdown);
                        args.TotalAttempts   = totalcount;

                        callback(args);

                        if (args.Cancel)
                        {
                            return(false);
                        }
                    }

                    seed += seedIncrement;
                }while (unchecked (--countdown) != 0); // allow integer underflow here, so that 0 is equivalent to 2**64

                if (progressInterval != 0)             // invoke callback for progress notification
                {
                    args.EventType       = RecoverSeedEventType.ProgressNotification;
                    args.Seed            = seed;
                    args.CurrentAttempts = (totalcount - totalcountdown - countdown);
                    args.TotalAttempts   = totalcount;

                    callback(args);

                    if (args.Cancel)
                    {
                        return(false);
                    }
                }
            }while (totalcountdown != 0);

            return(true);
        } //PrngBase.RecoverSeed(ulong,ulong,ulong,ulong[],ulong,ulong,RecoverSeedCallback,ulong)
예제 #11
0
파일: PrngV8.cs 프로젝트: JarLob/Prangster
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            /// TO-DO TODO: make this more accurate in general, account for off-by-one (esp. in output[0] position), etc.

            if (output.Length < 2 || output[0] > uint.MaxValue || output[0] == wildcard || limit == 0 || limit > (ulong)uint.MaxValue + 1 || seedIncrement != 1)
            {
                return(base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval));
            }

            if (seedStart > seedEnd)
            {
                return(false);
            }

            if (callback == null)
            {
                progressInterval = 0;
            }

            ulong output1 = ((output.Length > 2) ? output[1] : wildcard);

            uint blocksize = (uint)(0x100000000 / ((ulong)0x10000 * limit));

            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix middle portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                // lowstart..lowend define the range of values that the low 18 bits of State0 could have taken after producing the observed output[0]
                uint lowstart = (uint)((output[0] * 0x100000000 + (limit - 1)) / limit) >> 14;
                uint lowend   = (uint)((((output[0] + 1) * 0x100000000 + (limit - 1)) / limit) - 1) >> 14;

                ulong totalcount     = (ulong)(lowend - lowstart) * (((ulong)_Multiplier0 / 4) + 1);
                ulong totalcountdown = totalcount;

                ulong countdown = ((totalcountdown < progressInterval || progressInterval == 0) ? totalcountdown : progressInterval);

                int skip = (output1 == wildcard) ? -1 : 0;
                if (blocksize < 2)
                {
                    skip = -1;                 // don't attempt improved attack if block size is too small
                }
                for (uint statelow = lowstart; statelow < lowend; statelow++)
                {
                    ulong rangestart = ((ulong)statelow << 32) | 1;
                    ulong rangeend   = rangestart + (((ulong)_Multiplier0 / 4) << 50);

                    for (ulong seed = rangestart; seed <= rangeend;)
                    {
                        uint rounds = (uint)(((rangeend - seed) >> 50) + 1);
                        if (rounds > countdown)
                        {
                            rounds = (uint)countdown;
                        }

                        uint roundnum = 0;

                        if (skip > 0)
                        {
                            if ((uint)skip >= rounds)
                            {
                                seed    += 0x4000000000000 * (ulong)rounds;
                                skip    -= (int)(rounds - roundnum);
                                roundnum = rounds;
                            }
                            else
                            {
                                roundnum = (uint)skip;
                                seed    += 0x4000000000000 * (ulong)(uint)skip;
                                skip     = 0;
                            }
                        }

                        // we have the low 18 bits of State0 confined to a range, but we still need to brute-force the top 14 bits (up to Multiplier0 / 4)
                        for (; roundnum < rounds; seed += 0x4000000000000, roundnum++)
                        {
                            this.Seed(seed);

                            uint o1test = (uint)this.Next(limit);
                            if (o1test != output1 && output1 != wildcard)
                            {
                                if (skip == 0)
                                {
                                    uint diff = ((uint)output1 + (uint)limit - o1test) % (uint)limit;
                                    if (diff > 1)
                                    {
                                        skip = (int)((diff - 1) * blocksize);

                                        if ((uint)skip >= (rounds - roundnum))
                                        {
                                            seed    += 0x4000000000000 * (ulong)(rounds - roundnum);
                                            skip    -= (int)(rounds - roundnum);
                                            roundnum = rounds;
                                            break;
                                        }

                                        roundnum += (uint)(skip - 1);
                                        seed     += 0x4000000000000 * (ulong)(uint)(skip - 1);
                                        skip      = 0;
                                    }
                                }
                                continue;
                            }
                            else if (skip > 0)
                            {
                                skip = 0;
                            }

                            int i;
                            for (i = 1; i < suboutput.Length; i++)
                            {
                                if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                                {
                                    break;
                                }
                            }

                            if (i >= suboutput.Length)  // invoke callback for seed discovery notification
                            {
                                args.EventType       = RecoverSeedEventType.SeedDiscovered;
                                args.Seed            = unchecked (((ulong)PreviousState0((uint)(seed >> 32)) << 32) | PreviousState1((uint)seed));
                                args.CurrentAttempts = (totalcount - totalcountdown + roundnum);
                                args.TotalAttempts   = totalcount;

                                callback(args);

                                if (args.Cancel)
                                {
                                    return(false);
                                }
                            }
                        } //for(roundnum<rounds)

                        totalcountdown -= rounds;
                        countdown      -= rounds;

                        if (countdown == 0 && progressInterval != 0)
                        {
                            args.EventType       = RecoverSeedEventType.ProgressNotification;
                            args.Seed            = seed;
                            args.CurrentAttempts = (totalcount - totalcountdown);
                            args.TotalAttempts   = totalcount;

                            callback(args);

                            if (args.Cancel)
                            {
                                return(false);
                            }

                            countdown = ((totalcountdown < progressInterval) ? totalcountdown : progressInterval);
                        }
                    } //for(seed<=rangeend)
                }     //for(statelow<lowend)
            }         //unchecked

            return(true);
        } //PrngV8.RecoverSeed
예제 #12
0
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (output.Length < 2 || output[0] > (ulong.MaxValue / _OutputDivisor) || output[0] == wildcard || limit == 0 || limit > _OutputDivisor)
            {
                return(base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval));
            }

            if (seedStart > seedEnd || seedIncrement == 0)
            {
                return(false);
            }

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix top portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                ulong rangestart = ((_OutputDivisor * output[0]) + (uint)limit - 1) / (uint)limit;  // add (limit - 1) to round up, to make sure 'rangestart' will produce output[0]
                rangestart *= _DiscardDivisor;

                ulong rangeend = (((_OutputDivisor * (output[0] + 1)) + (uint)limit - 1) / (uint)limit) - 1;  // lowest seed that produces (output[0] + 1), then - 1
                rangeend = (rangeend * _DiscardDivisor) + (_DiscardDivisor - 1);

                if (rangestart <= seedStart)
                {
                    rangestart = seedStart;
                }
                else if (seedIncrement > 1)
                {
                    ulong incroffset = (rangestart - seedStart) % seedIncrement;
                    if (incroffset != 0)
                    {
                        rangestart += (seedIncrement - incroffset);  // advance to the next multiple of 'seedIncrement' (relative to 'seedStart')
                    }
                }

                if (rangeend > seedEnd)
                {
                    rangeend = seedEnd;
                }

                ulong output1 = ((output.Length > 2) ? output[1] : wildcard);

                uint blocksize = (uint)(_Modulus / ((ulong)_Multiplier * limit));
                if (blocksize < 2)
                {
                    output1 = wildcard;                 // don't attempt improved attack if block size is too small
                }
                if (output1 == wildcard || seedIncrement != 1)
                {
                    this._OriginalCallback = callback;
                    return(base.RecoverSeed(rangestart, rangeend, seedIncrement, suboutput, limit, wildcard, this.RecoverSeedCallback, progressInterval));
                }

                // otherwise, use second output to skip blocks of candidate states

                RecoverSeedEventArgs args = new RecoverSeedEventArgs();

                uint offset = NextFromState((uint)rangestart, (uint)limit);  // determine how far off current output is from second output
                offset = (uint)output1 + ((output1 < offset) ? (uint)limit : 0) - offset;

                if (offset >= 2)  // skip ahead conservatively to vicinity of a block of consecutive states that will produce 'output1'
                {
                    rangestart += (offset - 1) * blocksize;
                }

                while (NextFromState((uint)rangestart, (uint)limit) != output1)  // TO-DO TODO: binary seek, starting at +'blocksize'
                {
                    rangestart++;
                }

                uint blockstart = (uint)rangestart;
                uint blockend;

                for (; ;)
                {
                    blockend = blockstart + blocksize;  // [blockstart..blockend] is (blocksize + 1) states, to accommodate rounding variations
                    if (blockend >= rangeend)
                    {
                        blockend = (uint)rangeend;
                    }

                    for (uint state = blockstart; ; state++)
                    {
                        this.Seed(state);

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                            if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                            {
                                break;
                            }
                        }

                        if (i == suboutput.Length)  // invoke callback for seed discovery notification
                        {
                            args.EventType = RecoverSeedEventType.SeedDiscovered;
                            args.Seed      = PreviousState(state);
                            // TO-DO TODO: estimate progress/total somehow?
                            args.CurrentAttempts = 0;
                            args.TotalAttempts   = 0;

                            callback(args);

                            if (args.Cancel)
                            {
                                return(false);
                            }
                        }

                        if (state == blockend)  // check only after body of loop so that 'blockend' will get tested
                        {
                            break;
                        }
                    } //for(state)

                    blockstart += ((uint)limit * blocksize);
                    if (blockstart >= rangeend)
                    {
                        break;
                    }
                    // 'blockend' will be set at the top of the loop body

                    while (NextFromState(blockstart, (uint)limit) != output1)  // TO-DO TODO: binary seek?
                    {
                        blockstart++;
                    }
                } //for(;;)
            }     //unchecked

            return(true);
        } //PrngMsvcrtMul.RecoverSeed
예제 #13
0
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            /// TO-DO TODO: make this more accurate in general, account for off-by-one (esp. in output[0] position), etc.

            if (output.Length < 2 || output[0] > uint.MaxValue || output[0] == wildcard || limit == 0 || limit > (ulong)uint.MaxValue + 1 || seedIncrement != 1)
                return base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval);

            if (seedStart > seedEnd)
                return false;

            if (callback == null)
                progressInterval = 0;

            ulong output1 = ((output.Length > 2) ? output[1] : wildcard);

            uint blocksize = (uint)(0x100000000 / ((ulong)0x10000 * limit));

            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix middle portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                // lowstart..lowend define the range of values that the low 18 bits of State0 could have taken after producing the observed output[0]
                uint lowstart = (uint)((output[0] * 0x100000000 + (limit - 1)) / limit) >> 14;
                uint lowend = (uint)((((output[0] + 1) * 0x100000000 + (limit - 1)) / limit) - 1) >> 14;

                ulong totalcount = (ulong)(lowend - lowstart) * (((ulong)_Multiplier0 / 4) + 1);
                ulong totalcountdown = totalcount;

                ulong countdown = ((totalcountdown < progressInterval || progressInterval == 0) ? totalcountdown : progressInterval);

                int skip = (output1 == wildcard) ? -1 : 0;
                if (blocksize < 2) skip = -1;  // don't attempt improved attack if block size is too small

                for (uint statelow = lowstart; statelow < lowend; statelow++)
                {
                    ulong rangestart = ((ulong)statelow << 32) | 1;
                    ulong rangeend = rangestart + (((ulong)_Multiplier0 / 4) << 50);

                    for (ulong seed = rangestart; seed <= rangeend; )
                    {
                        uint rounds = (uint)(((rangeend - seed) >> 50) + 1);
                        if (rounds > countdown) rounds = (uint)countdown;

                        uint roundnum = 0;

                        if (skip > 0)
                        {
                            if ((uint)skip >= rounds)
                            {
                                seed += 0x4000000000000 * (ulong)rounds;
                                skip -= (int)(rounds - roundnum);
                                roundnum = rounds;
                            }
                            else
                            {
                                roundnum = (uint)skip;
                                seed += 0x4000000000000 * (ulong)(uint)skip;
                                skip = 0;
                            }
                        }

                        // we have the low 18 bits of State0 confined to a range, but we still need to brute-force the top 14 bits (up to Multiplier0 / 4)
                        for (; roundnum < rounds; seed += 0x4000000000000, roundnum++)
                        {
                            this.Seed(seed);

                            uint o1test = (uint)this.Next(limit);
                            if (o1test != output1 && output1 != wildcard)
                            {
                                if (skip == 0)
                                {
                                    uint diff = ((uint)output1 + (uint)limit - o1test) % (uint)limit;
                                    if (diff > 1)
                                    {
                                        skip = (int)((diff - 1) * blocksize);

                                        if ((uint)skip >= (rounds - roundnum))
                                        {
                                            seed += 0x4000000000000 * (ulong)(rounds - roundnum);
                                            skip -= (int)(rounds - roundnum);
                                            roundnum = rounds;
                                            break;
                                        }

                                        roundnum += (uint)(skip - 1);
                                        seed += 0x4000000000000 * (ulong)(uint)(skip - 1);
                                        skip = 0;
                                    }
                                }
                                continue;
                            }
                            else if (skip > 0) skip = 0;

                            int i;
                            for (i = 1; i < suboutput.Length; i++)
                            {
                                if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                                    break;
                            }

                            if (i >= suboutput.Length)  // invoke callback for seed discovery notification
                            {
                                args.EventType = RecoverSeedEventType.SeedDiscovered;
                                args.Seed = unchecked(((ulong)PreviousState0((uint)(seed >> 32)) << 32) | PreviousState1((uint)seed));
                                args.CurrentAttempts = (totalcount - totalcountdown + roundnum);
                                args.TotalAttempts = totalcount;

                                callback(args);

                                if (args.Cancel)
                                    return false;
                            }
                        } //for(roundnum<rounds)

                        totalcountdown -= rounds;
                        countdown -= rounds;

                        if (countdown == 0 && progressInterval != 0)
                        {
                            args.EventType = RecoverSeedEventType.ProgressNotification;
                            args.Seed = seed;
                            args.CurrentAttempts = (totalcount - totalcountdown);
                            args.TotalAttempts = totalcount;

                            callback(args);

                            if (args.Cancel)
                                return false;

                            countdown = ((totalcountdown < progressInterval) ? totalcountdown : progressInterval);
                        }
                    } //for(seed<=rangeend)
                } //for(statelow<lowend)
            } //unchecked

            return true;
        }
예제 #14
0
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (output.Length < 2 || output[0] >= limit || output[0] == wildcard || limit == 0 || limit > _Modulus || seedIncrement != 1)
            {
                return(base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval));
            }

            if (seedStart < this.MinimumSeed)
            {
                seedStart = this.MinimumSeed;
            }

            if (seedEnd > this.MaximumSeed)
            {
                seedEnd = this.MaximumSeed;
            }

            if (seedStart > seedEnd)
            {
                return(false);
            }

            ulong output1 = ((output.Length > 2) ? output[1] : wildcard);

            uint blocksize = (uint)(_Modulus / ((ulong)_Multiplier1 * limit));

            if (blocksize < 2)
            {
                output1 = wildcard;                 // don't attempt improved attack if block size is too small
            }
            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix bottom portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                // 2147483589.46728 rounded down is 2147483589 and rounded up is 2147483590; rounding outward ensures we won't exclude a viable candidate state
                uint difflo = (uint)(((2147483589 * output[0]) + limit - 1) / limit);           // add (limit - 1) to round up, to make sure 'difflo' will (almost always) produce output[0]
                uint diffhi = (uint)(((2147483590 * (output[0] + 1)) + limit - 1) / limit) - 1; // lowest difference that produces (output[0] + 1), then - 1

                for (uint state0 = 1; state0 < _Modulus; state0++)
                {
                    uint state1start = (state0 + _Modulus - diffhi); // State1 such that (State0 - State1) == diffhi; subtract 'diffhi' to get State1 lower bound
                    if (state1start >= _Modulus)                     // _Modulus rather than _Modulus1 because difference is computed modulo _Modulus
                    {
                        state1start -= _Modulus;
                    }
                    if (state1start == 0 || state1start >= _Modulus1)
                    {
                        state1start = 1;  // skip impossible state1 values
                    }
                    if (output1 != wildcard)
                    {
                        uint offset = NextFromStates(state0, state1start, (uint)limit);           // determine how far off current output is from second output
                        offset = offset + ((offset < output1) ? (uint)limit : 0) - (uint)output1; // compute (offset - output1) because State1 is subtracted from State0

                        if (offset >= 2)                                                          // skip ahead very conservatively to vicinity of a block of consecutive states that will produce 'output1'
                        {
                            state1start += (offset - 1) * blocksize - (_Modulus - _Modulus1 + 1); // don't let skipped states cause us to miss any viable candidates
                        }
                        while (NextFromStates(state0, state1start, (uint)limit) != output1)       // TO-DO TODO: binary seek, starting at +'blocksize'
                        {
                            state1start++;
                        }
                    }

                    uint state1end = (state0 + _Modulus - difflo);  // State1 such that (State0 - State1) == difflo; subtract 'difflo' to get State1 upper bound
                    if (state1end >= _Modulus)
                    {
                        state1end -= _Modulus;
                    }
                    if (state1end == 0 || state1end >= _Modulus1)
                    {
                        state1end = (_Modulus1 - 1);  // stop short of impossible State1 values
                    }
                    uint state1blockstart = state1start;
                    uint state1blockend;

                    for (; ;)   // blocks
                    {
                        if (output1 != wildcard)
                        {
                            state1blockend = state1blockstart + blocksize;  // [state1blockstart..state1blockend] is (blocksize + 1) states, to accommodate rounding variations
                            if (state1blockend >= _Modulus)
                            {
                                state1blockend -= _Modulus;
                            }
                            if (state1blockend == 0 || state1blockend >= _Modulus1)
                            {
                                state1blockend = (_Modulus1 - 1);  // stop short of impossible State1 values
                            }
                        }
                        else
                        {
                            state1blockstart = state1start;
                            state1blockend   = state1end;
                        }

                        for (; ;)   // pieces
                        {
                            // brute-force State1 in two passes if its range wraps around, so that we don't have to check for zero or _Modulus1 after each increment
                            uint state1piecestart = state1blockstart;
                            uint state1pieceend   = ((state1blockstart < state1blockend) ? state1blockend : (_Modulus1 - 1));

                            for (uint state1 = state1piecestart; ; state1++)
                            {
                                this._State0 = state0;  // faster than converting states to seed and seed to states via Seed()
                                this._State1 = state1;

                                int i;
                                for (i = 0; i < suboutput.Length; i++)
                                {
                                    if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                                    {
                                        break;
                                    }
                                }

                                if (i == suboutput.Length)  // invoke callback for seed discovery notification
                                {
                                    uint prevstate0 = (uint)(((ulong)state0 * _Multiplier0Inverse) % _Modulus);
                                    uint prevstate1 = (uint)(((ulong)state1 * _Multiplier1Inverse) % _Modulus1);

                                    args.EventType = RecoverSeedEventType.SeedDiscovered;
                                    args.Seed      = SeedFromStates(prevstate0, prevstate1);
                                    // TO-DO TODO: estimate progress/total somehow?  would be easy if not for skipped State1 candidates
                                    args.CurrentAttempts = 0;
                                    args.TotalAttempts   = 0;

                                    callback(args);

                                    if (args.Cancel)
                                    {
                                        return(false);
                                    }
                                }

                                if (state1 == state1pieceend)  // check only after body of loop so that 'state1pieceend' will get tested
                                {
                                    break;
                                }
                            } //for(state1)

                            if (state1blockstart > state1blockend)
                            {
                                state1blockstart = 1;  // now brute-force the second (post-zero) piece
                            }
                            else
                            {
                                break;
                            }
                        } //for(pieces)

                        if (output1 != wildcard)
                        {
                            if (state1blockstart <= state1end && state1blockend >= state1end)
                            {
                                break;
                            }

                            state1blockstart = state1blockend + ((uint)(limit - 1) * blocksize);  // skip ahead by a conservative underestimate
                            if (state1blockend <= state1end && state1blockstart >= state1end)
                            {
                                break;
                            }
                            // 'state1blockend' will be set at the top of the loop body

                            while (NextFromStates(state0, state1blockstart, (uint)limit) != output1)  // TO-DO TODO: binary seek?
                            {
                                state1blockstart++;
                            }
                        }
                        else
                        {
                            break;
                        }
                    } //for(blocks)
                }     //for(state0)
            }         //unchecked

            return(true);
        } //PrngMssql.RecoverSeed
예제 #15
0
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (output.Length < 2 || output[0] >= _OutputDivisor || output[0] == wildcard || seedStart != this.MinimumSeed || seedIncrement != 1 || limit == 0 || limit > _OutputDivisor)
            {
                return(base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval));
            }

            if (seedStart > seedEnd || seedIncrement == 0)
            {
                return(false);
            }

            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix middle portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                uint seedtopincr = (uint)limit * _DiscardDivisor;

                // Modulus is a power of 2, so GCD(limit, Modulus) is greatest power-of-two factor of limit
                uint subgenoutputmask = ((uint)limit ^ ((uint)limit - 1)) >> 1;
                uint subgensize       = (subgenoutputmask + 1) * _DiscardDivisor; // GCD(limit, Modulus) * DiscardDivisor

                // fix bottom portion by brute-forcing subgenerator
                uint subseed;
                for (subseed = 0; subseed < subgensize; subseed++)
                {
                    if (subgenoutputmask != 0)  // if limit is odd, we can't check this subgenerator seed against LSB(s) of output; we must test all possibilities below
                    {
                        this.Seed(subseed);

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                            // we can do Next() instead of Next(limit) for speed, since either way the remainder modulo power-of-two is preserved
                            if ((this.Next(limit) & subgenoutputmask) != (suboutput[i] & subgenoutputmask) && suboutput[i] != wildcard)
                            {
                                break;
                            }
                        }

                        if (i < suboutput.Length)
                        {
                            continue;
                        }
                    }

                    // MSB(s) of subseed will contain LSB(s) of output[0], so | instead of + to keep duplicate bit(s) from interfering
                    for (uint seed = ((uint)output[0] * _DiscardDivisor) | subseed; seed <= seedEnd; seed += seedtopincr)
                    {
                        this.Seed(seed);

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                            if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                            {
                                break;
                            }
                        }

                        if (i == suboutput.Length)  // invoke callback for seed discovery notification
                        {
                            args.EventType = RecoverSeedEventType.SeedDiscovered;
                            args.Seed      = PreviousState(seed);
                            // TO-DO TODO: estimate progress/total somehow?
                            args.CurrentAttempts = 0;
                            args.TotalAttempts   = 0;

                            callback(args);

                            if (args.Cancel)
                            {
                                return(false);
                            }
                        }
                    } //for(seed<=seedEnd)
                }     //for(subseed<subgensize)
            }         //unchecked

            return(true);
        } //PrngMsvcrt.RecoverSeed
예제 #16
0
        protected override bool RecoverSeed(ulong seedStart, ulong seedEnd, ulong seedIncrement, ulong[] output, ulong limit, ulong wildcard, RecoverSeedCallback callback, ulong progressInterval)
        {
            if (output.Length < 2 || output[0] >= _OutputDivisor || output[0] == wildcard || seedStart != this.MinimumSeed || seedIncrement != 1 || limit == 0 || limit > _OutputDivisor)
                return base.RecoverSeed(seedStart, seedEnd, seedIncrement, output, limit, wildcard, callback, progressInterval);

            if (seedStart > seedEnd || seedIncrement == 0)
                return false;

            RecoverSeedEventArgs args = new RecoverSeedEventArgs();

            unchecked  // disable arithmetic checks for performance
            {
                // operate on output suffix of length N - 1 so we can fix middle portion of seed to output[0]
                ulong[] suboutput = new ulong[output.Length - 1];
                Array.Copy(output, 1, suboutput, 0, output.Length - 1);

                uint seedtopincr = (uint)limit * _DiscardDivisor;

                // Modulus is a power of 2, so GCD(limit, Modulus) is greatest power-of-two factor of limit
                uint subgenoutputmask = ((uint)limit ^ ((uint)limit - 1)) >> 1;
                uint subgensize = (subgenoutputmask + 1) * _DiscardDivisor;  // GCD(limit, Modulus) * DiscardDivisor

                // fix bottom portion by brute-forcing subgenerator
                uint subseed;
                for (subseed = 0; subseed < subgensize; subseed++)
                {
                    if (subgenoutputmask != 0)  // if limit is odd, we can't check this subgenerator seed against LSB(s) of output; we must test all possibilities below
                    {
                        this.Seed(subseed);

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                            // we can do Next() instead of Next(limit) for speed, since either way the remainder modulo power-of-two is preserved
                            if ((this.Next(limit) & subgenoutputmask) != (suboutput[i] & subgenoutputmask) && suboutput[i] != wildcard)
                                break;
                        }

                        if (i < suboutput.Length)
                            continue;
                    }

                    // MSB(s) of subseed will contain LSB(s) of output[0], so | instead of + to keep duplicate bit(s) from interfering
                    for (uint seed = ((uint)output[0] * _DiscardDivisor) | subseed; seed <= seedEnd; seed += seedtopincr)
                    {
                        this.Seed(seed);

                        int i;
                        for (i = 0; i < suboutput.Length; i++)
                        {
                            if (this.Next(limit) != suboutput[i] && suboutput[i] != wildcard)
                                break;
                        }

                        if (i == suboutput.Length)  // invoke callback for seed discovery notification
                        {
                            args.EventType = RecoverSeedEventType.SeedDiscovered;
                            args.Seed = PreviousState(seed);
                            // TO-DO TODO: estimate progress/total somehow?
                            args.CurrentAttempts = 0;
                            args.TotalAttempts = 0;

                            callback(args);

                            if (args.Cancel)
                                return false;
                        }
                    } //for(seed<=seedEnd)
                } //for(subseed<subgensize)
            } //unchecked

            return true;
        }